/* ============================================================
   Klog 样式 5/5 · 视图层（历史追加区）
   装：各业务视图自己的皮肤——习惯 / 打卡热力 / 统计 / 记账 / 搜索 / 回收站 /
       个人中心 pfg / 抽屉与滚轮 / 小部件 等，按时间线一路追加至今。
   ⚠ 本片大量规则是对 01-04 的定向覆盖，必须最后加载。
   ⚠ 已知病灶：历史上每加一个页面就往这里续一段带自己类名的样式，从不复用
     03 的组件层，导致同一视觉模式被复制几十遍。新增视图样式前，先跑
     node dev/lab/css-bloat-gate.cjs 看有没有可复用的现成类。
   ─── 1008 拆分头结束 ─── */
/* ============================================================
   阶段一增强：今日一言 / 快捷操作 / 数据洞察 / 分类
   （.ov-hero / .ov-quote* 基线已随「概览 · 今日时间线 v1.0」迁移到文件末尾，
     .ov-quick 横滑胶囊轨已随 1010 hero 信息重排撤除，此处只保留仍被空态使用的 .empty .btn）
   ============================================================ */
.empty .btn { display: inline-flex; align-items: center; gap: var(--sp-1); }
.empty .btn span { margin: 0; }

/* 0927：概览「本周」卡撤除，.insight-* 与 .ov-dist-*（分类分布条）随之退场。
   下面的 .ov-bars 一族仍被统计页「完成趋势」（原名产出趋势）复用，别当死样式清掉。 */
.ov-bars { flex: 1; display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-1); padding-top: var(--sp-1); }
.ov-bar-col { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: var(--sp-1); min-width: 0; }
.ov-bar-n { font-size: var(--fs-micro); color: var(--text-4); height: 15px; line-height: 15px; font-variant-numeric: tabular-nums; }
.ov-bar { width: 58%; max-width: 22px; min-height: 3px; border-radius: var(--r-1); background: color-mix(in srgb, var(--primary) 34%, transparent); }
.ov-bar-col.is-today .ov-bar { background: var(--primary); }
.ov-bar-l { font-size: var(--fs-micro); color: var(--text-4); }
.ov-bar-col.is-today .ov-bar-l { color: var(--primary); font-weight: var(--fw-medium); }

.cat-dot { display: inline-block; width: 9px; height: 9px; border-radius: var(--r-circle); flex-shrink: 0; vertical-align: -1px; }
/* 已归档区：习惯行用行内色点区分（待办无颜色，只有标题） */
.trash-title .cat-dot { margin-right: var(--sp-1); }

.cat-filter { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2); margin: 0 0 var(--sp-4); }
.cat-filter .chip { height: 30px; }
.cat-filter > * { flex-shrink: 0; } /* 移动端横向滚动布局下禁止 chips 被压缩折行 */
.cat-filter .chip .cat-dot { margin-left: 2px; }
.chip { white-space: nowrap; }

.todo-meta { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-1); margin-top: 3px; }
.todo-cat { display: inline-flex; align-items: center; gap: var(--sp-1); height: 19px; padding: 0 var(--sp-2); border: 1px solid var(--border); border-radius: var(--radius-pill); font-size: var(--fs-micro); color: var(--text-3); background: var(--bg-card); }
.todo-cat .cat-dot { width: 7px; height: 7px; }
.todo-desc { font-size: var(--fs-micro); color: var(--text-4); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; }

.field-hint { margin-top: var(--sp-1); font-size: var(--fs-micro); color: var(--text-4); line-height: 1.6; }

/* 空态（友好文案 + 引导按钮） */
.empty .empty-ico { margin-bottom: 0; }
.empty-text { font-size: var(--fs-body); color: var(--text-3); margin: var(--sp-3) 0 var(--sp-3); line-height: 1.6; }

/* 分类管理弹窗 */
.cat-palette { display: flex; flex-wrap: wrap; gap: var(--sp-2); position: relative; }
.cat-swatch { width: 24px; height: 24px; border-radius: var(--r-2); border: none; cursor: pointer; transition: transform var(--d-med) var(--ease-spring); }
/* hover 缩放只给真鼠标（触屏统一走下面的按压即时态）——
   触屏上 tap 会粘住 :hover，原先那下「黑色再点会跳」其实是它：已选中的走早退、
   DOM 没重建、粘住的 1.12 放了一下；其余颜色一点就被重绘换新节点，所以没份。 */
@media (hover: hover) {
  .cat-swatch:hover { transform: scale(1.12); }
}
/* 按下缩小、松手回弹（1015 站主定）：按下走自己的快过渡（.1s 缩到 .9），
   松手 :active 摘掉、交还基线那条 .32s 弹簧——cubic-bezier 的 1.56 过冲就是「一点弹性」。
   两个旋钮：按下深度 .9；回弹劲度 = --ease-spring 的 1.56（越大越弹）。 */
.cat-swatch:active { transform: scale(.9); transition: transform var(--d-micro) ease-out; }
.cat-swatch.is-sel { box-shadow: 0 0 0 2px var(--bg-card), 0 0 0 4px var(--primary); }
/* 头像底色「自动」档：不指定固定色 = 回退按名字哈希上色。虚线圈 + 字母 A 明示
   「这是一模式、不是一个颜色」，与实色预设块一眼可分；选中时让位给上面的 .is-sel 主色环。 */
.cat-swatch-auto {
  background: var(--bg-page); color: var(--text-3);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: calc(12px * var(--fs-scale)); font-weight: var(--fw-semibold);
  box-shadow: inset 0 0 0 1px var(--border);
}
/* 自定义颜色入口：虚线圈 + 加号（与「新增」同语言）；取到颜色后填色并显示勾。
   虚线圈画在 ::before 上、不再用 border——border 参与盒模型，而色板「一行铺满」那一档
   （.cat-palette.is-fit）里 flex 分给每枚的是内容盒、边框另加在外面，于是「+」永远比
   同排预设枚宽 2~3px，一行看着就不齐（390 实测 29.11 对 30，对照实验：抹掉边框即齐）。
   挪到 inset:0 的绝对定位伪元素上，圈仍压在盒子边缘、与 border 版逐像素同形，
   但所有色块的盒模型从此完全相同。position:relative 必须自己带上：
   基础档的 .cat-swatch 不带定位，桌面端这枚会挂到 .cat-palette 那一层去。 */
.cat-swatch-custom {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  background: transparent; color: var(--text-4);
  border: none;
  transition: transform var(--d-fast) var(--ease-float), color var(--transition-fast), background var(--d-base) linear;
}
.cat-swatch-custom::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  border: 1.5px dashed var(--border-strong);
  transition: border-color var(--transition-fast);
}
.cat-swatch-custom svg { width: 13px; height: 13px; display: block; }
@media (hover: hover) { .cat-swatch-custom:hover { color: var(--text-1); } }
@media (hover: hover) { .cat-swatch-custom:hover::before { border-color: var(--text-4); } }
.cat-swatch-custom.is-filled::before { border-color: transparent; }
.cat-custom-hex {
  align-self: center; margin-left: 2px;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--fs-micro); color: var(--text-4); letter-spacing: .02em;
}
/* ≤768 手机端样式 → 06-mobile.css */

/* ---- 自建取色抽屉（.wp-mask / .wp-sheet 外壳，黑白语言里只让颜色有彩色） ---- */
.cp-stage {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3); margin-bottom: var(--sp-4);
  background: var(--bg-soft); border: 1px solid var(--border); border-radius: var(--r-3);
}
.cp-chip {
  flex: none; width: 46px; height: 46px; border-radius: var(--r-3);
  display: flex; align-items: center; justify-content: center;
  background: #5DCAA5; color: var(--white); /* 底色=取色初值（JS 开面板即运行时改写）；白勾＝取色器功能色豁免 */
  box-shadow: inset 0 0 0 1px rgba(17, 17, 17, .08);
  transition: background var(--d-fast) linear, color var(--d-fast) linear;
}
.cp-chip .habit-check { width: 20px; height: 20px; }
.cp-stage-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.cp-stage-txt b { font-size: var(--fs-body); font-weight: var(--fw-semibold); color: var(--text-1); }
.cp-stage-txt em { font-style: normal; font-size: var(--fs-micro); color: var(--text-4); line-height: 1.5; }
.cp-ramp { flex: none; display: flex; gap: var(--sp-1); }
.cp-ramp i {
  width: 26px; height: 26px; border-radius: var(--r-2);
  display: flex; align-items: center; justify-content: center;
  font-style: normal; font-family: var(--font-mono); font-size: var(--fs-10); line-height: 1;
  transition: background var(--d-fast) linear, color var(--d-fast) linear;
}
.cp-sv {
  position: relative; height: 150px; border-radius: var(--r-3);
  /* 取色器饱和/明度平面：这里的纯黑/纯白是 HSL 功能色（V=0 必须是绝对黑，否则选不出暗色、
     S=0 必须绝对白），不是 UI 表面色——是「全站禁可见纯黑」红线的登记豁免之一（另两类是
     mask-image 通道端点与 rgba(0,0,0,α) 半透明遮罩）。改近黑会让取色失真，勿动。 */
  background:
    linear-gradient(to top, #000000, rgba(0, 0, 0, 0)),
    linear-gradient(to right, #ffffff, rgba(255, 255, 255, 0)),
    hsl(calc(var(--cp-h, 210) * 1deg), 100%, 50%);
  box-shadow: inset 0 0 0 1px var(--border);
  touch-action: none; cursor: crosshair;
}
.cp-hue {
  position: relative; height: 26px; margin-top: var(--sp-3); border-radius: var(--radius-pill);
  background: linear-gradient(90deg, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00);
  box-shadow: inset 0 0 0 1px var(--border);
  touch-action: none; cursor: ew-resize;
}
.cp-thumb {
  position: absolute; width: 22px; height: 22px; border-radius: var(--r-pill);
  border: 2px solid var(--white); background: transparent; pointer-events: none; /* 取色器把手白环＝功能色豁免（DESIGN_SYSTEM §1） */
  box-shadow: 0 0 0 1px rgba(17, 17, 17, .3), 0 2px 6px rgba(17, 17, 17, .3);
  transform: translate(-50%, -50%);
  transition: transform var(--d-fast) var(--ease-float);
}
.cp-sv .cp-thumb {
  left: calc(var(--cp-s, 0) * 100%);
  top: calc((1 - var(--cp-v, 1)) * 100%);
  background: hsl(calc(var(--cp-h, 210) * 1deg), calc(var(--cp-s, 0) * 100%), calc(var(--cp-v, 1) * 50%));
}
.cp-hue .cp-thumb { top: 50%; left: calc(var(--cp-h, 0) * 100% / 360); background: hsl(calc(var(--cp-h, 0) * 1deg), 100%, 50%); }
.cp-sv.is-drag .cp-thumb, .cp-hue.is-drag .cp-thumb { transform: translate(-50%, -50%) scale(1.16); }
.cp-sv:focus-visible, .cp-hue:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }
/* 色值井（1029 换新款）：旧版是「色值」两个字 + 一整条 form-input 大灰框，那是站内很早以前的
   表单长相（标签单占一列、框子跟正文表单同款）。现在走现行井语言——井里住一枚实时上色的
   色块，HEX 是井内的等宽读数；标签不再单占一列（读屏仍吃 input 的 aria-label）。
   非习惯场景（人物头像底色）里「本周热力档位」那一块不渲染，这枚小色块就是唯一的实时预览。
   三态与站内输入井同源：静息 --fld-fill → 聚焦整井主描边 + --focus-glow 柔光。 */
.cp-hex-well {
  display: flex; align-items: center; gap: var(--sp-3);
  margin-top: var(--sp-4); height: 44px; padding: 0 var(--sp-3);
  background: var(--fld-fill); border: 1px solid transparent; border-radius: var(--fld-r);
  transition: background var(--d-fast) linear, border-color var(--d-fast) linear, box-shadow var(--d-fast) linear;
}
.cp-hex-well:focus-within { background: var(--bg-card); border-color: var(--primary); box-shadow: var(--focus-glow); }
.cp-hex-dot {
  flex: none; width: 22px; height: 22px; border-radius: var(--r-2);
  background: #5DCAA5; color: var(--white); /* 底色=取色初值（JS 开面板即改写），与 .cp-chip 同属取色器材质豁免 */
  box-shadow: inset 0 0 0 1px rgba(17, 17, 17, .08);
  transition: background var(--d-fast) linear;
}
.cp-hex {
  flex: 1; min-width: 0; height: 100%; padding: 0; border: none; background: none; outline: none;
  font-family: var(--font-mono); font-size: calc(15px * var(--fs-scale)); letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-1); caret-color: var(--primary);
}
.cp-sheet .wp-foot { margin-top: var(--sp-6); }
/* 桌面端「居中对话框」形态见文件末尾的 .wp-mask.cp-mask 块：
   必须排在 .wp-sheet 基础规则之后并带上 .wp-mask 前缀，否则会被同特异性的 width:100% / 24px 顶圆角反压 *//* (1008 死规则清理) *//* (1008 死规则清理) *//* (1008 死规则清理) */
.cat-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 2px; border-bottom: 1px solid var(--border); }
.cat-row:last-child { border-bottom: none; }/* (1008 死规则清理) *//* (1008 死规则清理) *//* (1008 死规则清理) */
/* flex: none 是补的一笔真 bug（真机截图）：28×28 的图标钮在手机行里是唯一可被压缩的
   弹性项——信息区是 flex:1 1 0%（basis 0 不参与收缩）、角色胶囊写了 flex-shrink:0，
   于是内容最长的那一行（「当前」标签那行）把额度钮挤成 0 宽，整列看着缺一格。
   图标钮在任何一行里都不该被压，所以收在基类上，不给用户页开特例。 */
.cat-act { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; flex: none; border: none; border-radius: var(--radius-btn); background: transparent; color: var(--text-3); cursor: pointer; }
.cat-act svg { width: 14px; height: 14px; }
@media (hover: hover) { .cat-act:hover { background: var(--bg-hover); color: var(--text-1); } }
@media (hover: hover) { .cat-act-del:hover { color: var(--status-bad); } }
.cat-row-empty { padding: var(--sp-3) 2px; text-align: center; font-size: var(--fs-caption); color: var(--text-4); }

/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   阶段二：子任务 / 重复 / Markdown / 置顶 / 习惯打卡
   ============================================================ */
/* .av-colors-k：头像底色那一行的行首（1029 搬进头像抽屉后它住在抽屉里，不是一张表单，
   用 div 而不是 label——label 得指向一个控件，这里是一组色块按钮）。
   副说明的字号/墨色必须与表单里的 label .opt 同一把尺，所以并进同一条规则，不再抄一遍。 */
label .opt, .av-colors-k .opt { color: var(--text-4); font-size: var(--fs-micro); font-weight: 400; }

/* 子任务编辑器 */
.sub-editor { display: flex; flex-direction: column; gap: var(--sp-1); margin-bottom: var(--sp-1); }
.sub-row {
  display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-1) var(--sp-2);
  border: 1px solid var(--border); border-radius: var(--radius-btn); background: var(--bg-card);
  transition: transform var(--d-base) var(--ease-float); /* 拖动让位补间（§4.3b 四口同一套） */
}
.sub-row.is-done .sub-title { color: var(--text-4); text-decoration: line-through; }
.sub-check { flex-shrink: 0; }
.sub-title { flex: 1; min-width: 0; font-size: var(--fs-caption); color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sub-del { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border: none; border-radius: var(--radius-btn); background: transparent; color: var(--text-4); cursor: pointer; }
.sub-del svg { width: 13px; height: 13px; }
@media (hover: hover) { .sub-del:hover { background: var(--bg-hover); color: var(--status-bad); } }
.sub-add { display: flex; gap: var(--sp-2); }
.sub-add .form-input { flex: 1; }
.sub-add .btn { flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; width: 40px; padding: 0; }
.sub-add .btn svg { width: 15px; height: 15px; }

/* 待办行徽标：子任务进度 / 重复 */
.todo-flag {
  display: inline-flex; align-items: center; gap: var(--sp-1); height: 19px; padding: 0 var(--sp-2);
  border-radius: var(--radius-pill); background: var(--bg-soft); color: var(--text-3);
  font-size: var(--fs-micro); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.todo-flag svg { width: 11px; height: 11px; }
.todo-flag-rep { color: var(--text-3); }

/* 重复规则：每周几 / 每月几号 */
.wd-row { display: flex; gap: var(--sp-1); margin-top: var(--sp-1); }
.wd-btn {
  flex: 1; height: 30px; border: 1px solid var(--border); border-radius: var(--radius-btn);
  background: var(--bg-card); color: var(--text-3); font-size: var(--fs-caption); cursor: pointer;
  transition: border-color var(--transition-fast), color var(--transition-fast), background var(--transition-fast);
}
@media (hover: hover) { .wd-btn:hover { border-color: var(--border-strong); color: var(--text-1); } }
.wd-btn.active { border-color: var(--primary); color: var(--text-1); font-weight: var(--fw-medium); background: color-mix(in srgb, var(--primary) 8%, transparent); }
.dom-row { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-1); font-size: var(--fs-caption); color: var(--text-3); }
.dom-row .form-input { width: 84px; }

/* Markdown 编辑 / 预览 */
.md-field-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); margin-bottom: var(--sp-1); }
/* 「内容」这行标题包在 .md-field-head 里（同一行还要放格式条/预览分段），
   `.field > label` 打不到它——1104 前它一直在吃正文默认字，是第六档。
   字形已并进 03 的字段标题唯一档（那条选择器列表里有 .md-field-head > label），
   这里不再重复声明；fgPaintIcons 认它，图标仍挂在这一行。 */
/* 备忘表单的紧凑分段（复用 .seg 组件，选中态 = 主色填充） */
.md-seg button { height: 28px; padding: 0 var(--sp-3); font-size: var(--fs-micro); }
/* 备忘快捷格式条：仅手机端（JS 门控 wbCoarse）。内嵌进弹窗 flex 布局，
   贴在底部按钮栏上方——键盘顶起时视口收缩、弹窗变矮，工具栏自然落到键盘正上方。 */
.md-fmt-slot { flex: 0 0 auto; display: flex; justify-content: center; padding: var(--sp-2) var(--sp-3); }
.md-fmt-slot[hidden] { display: none; }
.md-fmt-bar {
  display: flex; align-items: center; gap: 2px; padding: var(--sp-1);
  max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--r-3);
  box-shadow: var(--shadow-float);
  animation: mdFmtIn var(--d-base) var(--ease-enter);
}
.md-fmt-bar::-webkit-scrollbar { display: none; }
@keyframes mdFmtIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.md-fmt-bar .mdb {
  min-width: 42px; height: 42px; padding: 0; flex: none;
  border: none; background: transparent; color: var(--text-2);
  border-radius: var(--r-2); cursor: pointer; -webkit-tap-highlight-color: transparent;
  font-size: calc(17px * var(--fs-scale)); line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--transition-fast), color var(--transition-fast), transform var(--d-micro) ease;
}
.md-fmt-bar .mdb:active { background: var(--bg-hover); color: var(--text-1); transform: scale(.9); }
.md-fmt-bar .mdb b { font-weight: 700; }
.md-fmt-bar .mdb i { font-style: italic; font-family: Georgia, 'Times New Roman', serif; }
.md-fmt-bar .mdb u { text-decoration: underline; text-underline-offset: 2px; }
.md-fmt-bar .mdb s { text-decoration: line-through; }
/* 内联格式与标题之间的发丝分隔线 */
.md-fmt-bar .mdb-div { width: 1px; height: 22px; flex: none; margin: 0 var(--sp-1); background: var(--border); }
/* 标题按钮：更紧凑，字号阶梯暗示层级 */
.md-fmt-bar .mdb-h { min-width: 38px; font-weight: 600; letter-spacing: .2px; }
.md-fmt-bar .mdb-h[data-h="1"] { font-size: calc(16px * var(--fs-scale)); }
.md-fmt-bar .mdb-h[data-h="2"] { font-size: calc(15px * var(--fs-scale)); }
.md-fmt-bar .mdb-h[data-h="3"] { font-size: calc(14px * var(--fs-scale)); }
.md-fmt-bar .mdb-h[data-h="4"] { font-size: calc(13px * var(--fs-scale)); }
@media (prefers-reduced-motion: reduce) {
  .md-fmt-bar { animation: none; }
}
.md-body {
  border: 1px solid var(--border); border-radius: var(--radius-btn);
  background: var(--bg-card); padding: var(--sp-2) var(--sp-3);
  font-size: var(--fs-caption); color: var(--text-2); line-height: 1.7; overflow: auto;
  min-height: 140px; max-height: 320px;
}
.md-body h1, .md-body h2, .md-body h3, .md-body h4 { color: var(--text-1); margin: var(--sp-3) 0 var(--sp-1); line-height: 1.4; }
.md-body h1 { font-size: calc(17px * var(--fs-scale)); } .md-body h2 { font-size: calc(15px * var(--fs-scale)); } .md-body h3 { font-size: calc(14px * var(--fs-scale)); } .md-body h4 { font-size: calc(13px * var(--fs-scale)); }
.md-body p { margin: var(--sp-1) 0; }
.md-body ul, .md-body ol { margin: var(--sp-1) 0; padding-left: 1.4em; }
.md-body li { margin: 2px 0; }
.md-body code { font-family: var(--font-mono); font-size: var(--fs-micro); background: var(--bg-soft); border-radius: var(--r-1); padding: 1px var(--sp-1); }
.md-body pre { background: var(--bg-soft); border-radius: var(--radius-btn); padding: var(--sp-2) var(--sp-3); overflow: auto; margin: var(--sp-2) 0; }
.md-body pre code { background: transparent; padding: 0; }
.md-body blockquote { margin: var(--sp-2) 0; padding: var(--sp-1) var(--sp-3); border-left: 3px solid var(--border-strong); color: var(--text-3); }
.md-body a { color: var(--primary); }
.md-body img { max-width: 100%; border-radius: var(--radius-btn); }
.md-body hr { border: none; border-top: 1px solid var(--border); margin: var(--sp-3) 0; }
.md-body table { border-collapse: collapse; margin: var(--sp-2) 0; }
.md-body th, .md-body td { border: 1px solid var(--border); padding: var(--sp-1) var(--sp-2); font-size: var(--fs-caption); }
.md-empty-hint { color: var(--text-disabled); font-size: var(--fs-caption); }
/* 标题字形吃 03 的字段标题唯一档（.check-line 整行就是标题，已列进那条选择器列表） */
.check-line { display: flex; align-items: center; gap: var(--sp-2); cursor: pointer; margin: var(--sp-1) 0 2px; }
.check-line input { accent-color: var(--primary); }

/* 备忘 · 档案移出备忘后的一行交代（2.49 M0-a）。
   数字不单独设字族：--font-sans 栈首的 KlogNum 已认领 0-9，裸文本里的数字自动等宽。
   不设 display，所以 hidden 属性吃 UA 的 [hidden]{display:none}，不另开一条死规则。 */
.memo-card-hint { margin: var(--sp-2) 2px 0; text-align: center; font-size: var(--fs-caption); color: var(--text-4); }

/* 备忘置顶 */
.memo-card.is-pinned { border-color: color-mix(in srgb, var(--primary) 45%, var(--border)); }
.memo-pin {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 26px; height: 26px; border: none; border-radius: var(--radius-btn);
  background: transparent; color: var(--text-4); cursor: pointer;
  transition: color var(--transition-fast), background var(--transition-fast), transform var(--d-fast) var(--ease-float);
}
.memo-pin svg { width: 14px; height: 14px; }
@media (hover: hover) { .memo-pin:hover { background: var(--bg-hover); color: var(--text-1); transform: rotate(-12deg); } }
.memo-pin.on { color: var(--primary); }
.memo-pin.on svg { fill: color-mix(in srgb, var(--primary) 18%, transparent); }

/* 标签管理 */

/* 习惯打卡 */
.habit-today-panel { margin-bottom: var(--sp-4); }
.habit-today-panel .panel-head .t-micro { font-size: var(--fs-micro); color: var(--text-4); }
/* 完成度提示（2026-10-03 方案 B）：卡头两行制——标题行 + 分段进度条行。
   一段 = 一个习惯，打卡点亮纯黑（你点名的黑进度条；习惯色只留在色点/热力图，
   1003 真机反馈「颜色一多就花」后收色），右侧挂 N/M 计数；
   习惯数为 0 时整行 hidden（JS 控制），不再出现「0/0」噪声 */
.panel-head .ph-title { display: inline-flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.habit-today-panel .panel-head { flex-direction: column; align-items: stretch; gap: var(--sp-3); }
.hb-head-top { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); min-width: 0; }
.hb-head-bar { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.hb-head-bar[hidden] { display: none; }
.hb-segbar { flex: 1; display: flex; gap: var(--sp-1); min-width: 0; }
.hb-seg { flex: 1 1 0; min-width: 0; height: 6px; border-radius: var(--radius-pill); background: var(--bg-count); }
.hb-seg.on { background: var(--primary); }
.hb-segnum { flex: none; display: flex; align-items: baseline; gap: 2px; font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--text-4); font-size: var(--fs-12); line-height: 1; }
.hb-segnum b { font-size: var(--fs-num-sm); font-weight: var(--fw-bold); color: var(--text-1); }
.hb-segnum i { font-style: normal; }
.habit-today-row {
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-4);
  border-bottom: 1px solid var(--border); font-size: var(--fs-caption); color: var(--text-2);
}
.habit-today-row:last-child { border-bottom: none; }
.habit-today-row .row-title { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.streak-mark { font-size: var(--fs-micro); color: var(--text-4); flex-shrink: 0; }
/* 主胶囊两态（2026-10-03）：未打卡 = 黑实底「打卡」；已打卡 = 淡墨底 + 墨色字。
   全部从 --text-1 / --bg-card 派生 → 亮暗主题自适应；习惯色只留在色点与热力图，
   行内不再复涂（1003 用户反馈「颜色一多就花」后收色）。触屏 hover 复位段只需还原变量 */
.habit-toggle-btn {
  --hb-bg: var(--primary);
  --hb-fg: var(--on-primary);
  flex-shrink: 0; height: 30px; padding: 0 var(--sp-3); border-radius: var(--radius-pill);
  border: none; background: var(--hb-bg); color: var(--hb-fg);
  font-size: var(--fs-caption); font-weight: var(--fw-semibold); cursor: pointer;
  transition: all var(--transition-fast);
}
@media (hover: hover) { .habit-toggle-btn:hover { background: var(--primary-hover); color: var(--on-primary); } }
.habit-toggle-btn.on {
  --hb-bg: color-mix(in srgb, var(--text-1) 7%, var(--bg-card));
  --hb-fg: var(--text-1);
  display: inline-flex; align-items: center; gap: var(--sp-1);
}
@media (hover: hover) {
.habit-toggle-btn.on:hover {
  --hb-bg: color-mix(in srgb, var(--text-1) 11%, var(--bg-card));
}
}
.habit-check { width: 14px; height: 14px; display: block; }
.habit-toggle-btn:active { transform: scale(.96); }

.habit-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: var(--card-gap); }
.habit-card {
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-card);
  padding: var(--sp-3) var(--sp-4); box-shadow: var(--shadow-card); min-width: 0;
  transition: border-color var(--transition-fast), transform var(--d-base) var(--ease-float), box-shadow var(--d-base) var(--ease-float);
}
@media (hover: hover) { .habit-card:hover { border-color: var(--border-strong); transform: translateY(-2px); box-shadow: var(--shadow-hover); } }
.habit-name { flex: 1; min-width: 0; font-size: var(--fs-body); font-weight: var(--fw-semibold); color: var(--text-1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 1021 站主令：连续/本月两枚数据进标题行贴右缘（卡上编辑/停用钮已撤，.habit-ops 随删）。
   align-self: flex-end 让 12px 小字的盒底与 16px 标题盒底齐平（色点仍垂直居中）；
   flex-shrink:0 + nowrap 保住数值不被长标题挤断行——挤名字（名字本来就有省略号）。 */
.habit-meta { display: flex; gap: var(--sp-3); align-self: flex-end; flex-shrink: 0; font-size: var(--fs-caption); color: var(--text-4); white-space: nowrap; }
.habit-meta b { color: var(--text-1); font-variant-numeric: tabular-nums; }

/* ---- 打卡热力（本周 7 格 + 详情弹窗周/月/年） ---- */
.hm-cell {
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-1); background: var(--hm-0); color: var(--hm-ink-0);
  box-shadow: inset 0 0 0 1px var(--hm-line);
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--fs-11); line-height: 1; font-weight: var(--fw-medium);
}
.hm-l0 { background: var(--hm-0); color: var(--hm-ink-0); }
/* 1~3 档由「习惯自己的颜色」派生：JS 把亮/暗两套档位与墨色写在 .hb-heat / .hm-panel 的 style 上，
   取不到变量时回落品牌绿 token（如站外预览、旧数据） */
.hm-l1 { background: var(--hm-a, var(--hm-1)); color: var(--hm-ka, var(--hm-ink-1)); box-shadow: none; }
.hm-l2 { background: var(--hm-b, var(--hm-2)); color: var(--hm-kb, var(--hm-ink-2)); box-shadow: none; }
.hm-l3 { background: var(--hm-c, var(--hm-3)); color: var(--hm-kc, var(--hm-ink-3)); box-shadow: none; }
[data-theme="dark"] .hm-l1 { background: var(--hm-ad, var(--hm-1)); color: var(--hm-kad, var(--hm-ink-1)); }
[data-theme="dark"] .hm-l2 { background: var(--hm-bd, var(--hm-2)); color: var(--hm-kbd, var(--hm-ink-2)); }
[data-theme="dark"] .hm-l3 { background: var(--hm-cd, var(--hm-3)); color: var(--hm-kcd, var(--hm-ink-3)); }
.hm-cell.is-today { box-shadow: 0 0 0 1.5px var(--primary); }
.hm-cell.is-future { background: transparent; box-shadow: inset 0 0 0 1px var(--border); color: var(--text-disabled); }
.hm-cell.is-pad { background: transparent; box-shadow: none; }
.hm-dot { width: 3px; height: 3px; border-radius: var(--r-circle); background: var(--text-disabled); display: block; }
/* 周视图格子里的次数：包一层 .hm-v 便于原位改写，外观完全继承格子 */
.hm-v { font: inherit; line-height: 1; display: inline-block; }

/* 卡片内：只给本周 7 格 */
.hb-heat { margin-top: var(--sp-3); }
.hb-heat-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-2); }
.hb-heat-title { font-size: var(--fs-micro); letter-spacing: .08em; color: var(--text-4); }
.hb-heat-sum { font-size: var(--fs-micro); color: var(--text-4); font-variant-numeric: tabular-nums; white-space: nowrap; }
.hb-heat-sum b { color: var(--text-1); font-weight: var(--fw-semibold); }
.hm-week { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--sp-1); }
.hm-col { display: flex; flex-direction: column; align-items: center; gap: var(--sp-1); min-width: 0; }
.hm-col em { font-style: normal; font-size: var(--fs-10); line-height: 1; color: var(--text-4); }
.hm-col:has(.is-future) em { color: var(--text-disabled); }
.hm-sq { width: 100%; max-width: 34px; aspect-ratio: 1 / 1; }
.hm-sq-lg { max-width: 46px; font-size: calc(13px * var(--fs-scale)); }
.hm-sq-lg .hm-dot { width: 4px; height: 4px; }

/* 详情弹窗里的热力面板 */
.hm-panel {
  margin-top: var(--sp-3); padding: var(--sp-3);
  background: var(--bg-soft); border: 1px solid var(--border); border-radius: var(--radius-lg);
}
.hm-seg { width: 100%; }
.hm-seg .hm-tab { flex: 1; font-family: var(--font-mono); }
.hm-nav { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-3); }
.hm-range {
  flex: 1; min-width: 0; display: flex; align-items: center; justify-content: center; gap: var(--sp-1);
  /* 1004：放不下时让尾巴那枚「返回 / 本周」整枚退到第二行，日期一行都不许断——
     与 .st-range 同一排法，两族共用一套行为，别一处包一处不包 */
  flex-wrap: wrap; row-gap: 2px;
  font-size: var(--fs-caption); font-weight: var(--fw-semibold); color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
/* 日期本体（.hm-range 是 flex 容器，匿名文本项 CSS 选不中，必须包成真元素才管得住）：
   与统计页 .st-range-t 同一条——nowrap，宁可徽章退行也不把「8/16」拆成两截 */
.hm-range-t { white-space: nowrap; }
/* 当期徽章（本周/本月/今年/本期）：全站统一黑色主胶囊（黑底白字），
   与「返回」徽章同 padding / 字号 → 同尺寸档；心情、习惯、统计三处共用 */
.hm-cur {
  font-style: normal; padding: var(--sp-1) var(--sp-3); border-radius: var(--radius-pill);
  background: var(--primary); color: var(--on-primary);
  font-size: var(--fs-micro); font-weight: var(--fw-medium); letter-spacing: .02em; line-height: 1;
}
/* 返回徽章（回到本周/本月/今年/本期）：灰色系胶囊，与黑色当期徽章成对（一黑一灰、同尺寸）。
   视觉是小胶囊，热区靠 ::after 外扩补回 ≥38px（同站内图标钮手法） */
.hm-back {
  position: relative; border: none; cursor: pointer;
  background: var(--bg-count); color: var(--text-2);
  padding: var(--sp-1) var(--sp-3); border-radius: var(--radius-pill);
  font-size: var(--fs-micro); font-weight: var(--fw-medium); letter-spacing: .02em; line-height: 1;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.hm-back::after { content: ''; position: absolute; inset: -10px -6px; }
/* 两枚胶囊都不许被压扁：它们住在 .hm-range / .st-range 这只 flex 容器尾巴上，
   默认 flex-shrink:1 会先把「返回」挤瘦再换行——1004 要的正好相反（日期优先，徽章退行） */
.hm-cur, .hm-back { flex: none; }
@media (hover: hover) { .hm-back:hover { background: var(--bg-count-active); color: var(--text-1); } }
.dp-nav[disabled] { opacity: .35; cursor: default; pointer-events: none; }
.hm-summ { margin: var(--sp-2) 0; text-align: center; font-size: var(--fs-micro); color: var(--text-4); font-variant-numeric: tabular-nums; }
.hm-summ b { color: var(--text-2); font-weight: var(--fw-medium); }
/* 月视图：桌面把 7 列收到 336px 居中（格约 44px），一屏看完整月，不必滚动弹窗 */
.hm-wkrow { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--sp-1); max-width: 336px; margin: 0 auto var(--sp-1); }
.hm-wkrow span { text-align: center; font-size: var(--fs-10); line-height: 1; color: var(--text-4); }
.hm-grid7 { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--sp-1); max-width: 336px; margin: 0 auto; }
.hm-day { width: 100%; aspect-ratio: 1 / 1; font-size: var(--fs-12); }
.hm-year { display: flex; align-items: flex-start; gap: var(--sp-1); margin-top: 2px; }
.hm-ylab { display: grid; grid-template-rows: repeat(7, 12px); gap: 3px; padding-top: var(--sp-4); flex: none; }
.hm-ylab span { font-size: var(--fs-9); line-height: 12px; color: var(--text-4); }
.hm-year-scroll {
  flex: 1; min-width: 0; overflow-x: auto; overscroll-behavior: contain;
  padding-bottom: var(--sp-1); -webkit-overflow-scrolling: touch; scrollbar-width: thin;
}
.hm-year-inner { display: inline-block; min-width: max-content; }
.hm-year-scroll::-webkit-scrollbar { height: 6px; }
.hm-year-scroll::-webkit-scrollbar-button { display: none; }
.hm-year-scroll::-webkit-scrollbar-track { background: transparent; }
.hm-year-scroll::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: var(--r-1); }
@media (hover: hover) { .hm-year-scroll:hover::-webkit-scrollbar-thumb { background: var(--text-disabled); } }
.hm-mlab { display: flex; gap: 3px; height: 15px; }
.hm-mlab i {
  flex: none; width: 12px; font-style: normal; font-size: var(--fs-9); line-height: 15px;
  color: var(--text-4); font-family: var(--font-mono); text-align: left;
}
.hm-ygrid { display: grid; grid-template-rows: repeat(7, 12px); grid-auto-flow: column; grid-auto-columns: 12px; gap: 3px; }
.hm-dot-c { width: 12px; height: 12px; border-radius: var(--r-1); }
.hm-legend {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-3);
  margin-top: var(--sp-3); padding-top: var(--sp-2); border-top: 1px solid var(--border);
  font-size: var(--fs-micro); color: var(--text-4);
}
.hm-lg-item { display: inline-flex; align-items: center; gap: var(--sp-1); }
.hm-legend .hm-cell { width: 12px; height: 12px; }

/* 面板过渡：切视图上移淡入、翻页按方向滑入（方向可感知），打卡只做今日格脉冲 */
@keyframes hmInUp   { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes hmInLeft { from { opacity: 0; transform: translateX(18px); } to { opacity: 1; transform: none; } }
@keyframes hmInRight{ from { opacity: 0; transform: translateX(-18px); } to { opacity: 1; transform: none; } }
@keyframes hmPulse  { 0% { transform: scale(1); } 40% { transform: scale(1.14); } 100% { transform: scale(1); } }
.hm-in-up    { animation: hmInUp   var(--d-toast) var(--ease-enter); }
.hm-in-left  { animation: hmInLeft var(--d-toast) var(--ease-enter); }
.hm-in-right { animation: hmInRight var(--d-toast) var(--ease-enter); }
.hm-body.hm-in-left .hm-week > .hm-col,
.hm-body.hm-in-right .hm-week > .hm-col,
.hm-body.hm-in-up .hm-week > .hm-col { animation: hmInUp var(--d-push) var(--ease-enter) backwards; }
.hm-body .hm-week > .hm-col:nth-child(2) { animation-delay: .022s; }
.hm-body .hm-week > .hm-col:nth-child(3) { animation-delay: .044s; }
.hm-body .hm-week > .hm-col:nth-child(4) { animation-delay: .066s; }
.hm-body .hm-week > .hm-col:nth-child(5) { animation-delay: .088s; }
.hm-body .hm-week > .hm-col:nth-child(6) { animation-delay: var(--d-micro); }
.hm-body .hm-week > .hm-col:nth-child(7) { animation-delay: var(--d-micro); }
.hm-cell.hm-pulse { animation: hmPulse var(--d-enter) var(--ease-float); }
/* 区间标题与统计行只做透明度：它们和网格是相邻块级元素，
   带 translateY 的入场会在动画起点压住今日格顶部那圈 1.5px 黑环（看着像被裁掉一下） */
@keyframes hmFade { from { opacity: 0; } to { opacity: 1; } }
.hm-swap.hm-in-up, .hm-swap.hm-in-left, .hm-swap.hm-in-right { animation-name: hmFade; animation-duration: var(--d-modal); }
@media (prefers-reduced-motion: reduce) {
  .hm-in-up, .hm-in-left, .hm-in-right, .hm-cell.hm-pulse,
  .hm-body .hm-week > .hm-col { animation: none; }
}

/* 多次打卡控件：勾选钮带当日次数，前面挂「减一次」小钮 */
.hb-ctl { display: inline-flex; align-items: center; gap: var(--sp-1); flex-shrink: 0; }
.hb-times { min-width: 7px; font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--fs-caption); font-weight: var(--fw-semibold); color: inherit; }
/* 「减一次」幽灵圆钮（2026-10-03）：去掉描边、退成浅灰底，热区仍由 ≤768 档放到 38px */
.hb-minus {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 26px; height: 26px; padding: 0; border-radius: var(--radius-pill);
  border: none; background: var(--bg-muted); color: var(--text-3); cursor: pointer;
  transition: all var(--transition-fast);
}
.hb-minus svg { width: 12px; height: 12px; display: block; }
@media (hover: hover) { .hb-minus:hover { background: var(--bg-hover); color: var(--text-1); } }
.hb-minus:active { transform: scale(.92); }

/* 今日行拖动手柄（2026-10-03）：子任务编辑器 .sub-handle 同款语言——
   可见六点提手、touch-action:none 保证指针拖动在触屏上可靠；
   拖起行 z-index 抬一层 + 容器禁选中，行 :active 沉底在拖拽期关闭防闪 */
.hb-grip {
  flex: 0 0 22px; width: 22px; height: 36px; margin-left: -6px; padding: 0;
  border: none; background: transparent;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--text-4); opacity: .55; cursor: grab;
  touch-action: none; -webkit-user-select: none; user-select: none;
}
.hb-grip svg, .mg-grip svg { width: 14px; height: 14px; }
@media (hover: hover) { .hb-grip:hover, .mg-grip:hover { opacity: .85; } }
.hb-grip:active, .habit-today-row.is-dragging .hb-grip { cursor: grabbing; opacity: 1; }
/* 拖动排序三段（1105 站主点名，四个面同一套参数，见 DESIGN_SYSTEM §4.3b）：
   ① 拖起 = 轻微抬高（浮起阴影 + 卡面，JS 另给 scale(1.015)）
   ② 经过 = 让出空位（行基础条的 transform 补间滑开，此前是瞬跳）
   ③ 松手 = 落进空位（摘掉容器 is-dragging-mode＝补间回来了、浮起还挂在行上，
      JS 把被拖行补到整行格点，动画跑完才落库重渲——重渲后 DOM 序 == 屏上序，不闪回）
   「跟手禁补间」由容器态类压，不给落位另开一份浮起声明（那会被 bloat-gate 记成逐字重复）。 */
.habit-today-row { transition: transform var(--d-base) var(--ease-float); }
.habit-today-row.is-dragging {
  position: relative; z-index: 3;
  background: var(--bg-card); border-bottom-color: transparent;
  border-radius: var(--r-3); box-shadow: var(--shadow-float);
}
.is-dragging-mode .habit-today-row.is-dragging { transition: none; } /* 拖起那行必须逐帧跟手 */
#habitTodayList.is-dragging-mode { user-select: none; -webkit-user-select: none; }
#habitTodayList.is-dragging-mode .habit-today-row:active { background: transparent; }

/* 长按主钮 = 取消今天：按住过程中缓慢压下一档并转危险色，
   过渡 380ms 略短于 500ms 触发点，松手前就能看出「再按下去要取消了」 */
.habit-toggle-btn, .hb-minus {
  -webkit-touch-callout: none; -webkit-user-select: none; user-select: none;
  touch-action: manipulation;
}
.habit-toggle-btn.on.is-holding {
  border-color: var(--status-bad); color: var(--status-bad); background: var(--tag-bad-bg);
  transform: scale(.93);
  transition: transform var(--d-enter) var(--ease-float), color var(--d-modal) ease, background var(--d-modal) ease, border-color var(--d-modal) ease;
}

/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   阶段三：日记 / 回收站 / 数据与提醒
   ============================================================ */
.mood-chip {
  display: inline-flex; align-items: center; gap: var(--sp-1); height: 22px; padding: 0 var(--sp-2);
  border-radius: var(--radius-pill); background: var(--bg-soft);
  font-size: var(--fs-micro); color: var(--text-2);
}
/* 心情选择（.mood-seg）：1003 起并入 seg-slide v2 分段体系——结构 .seg.seg-slide.mood-seg，
   皮肤全在文件末尾「心情分段」块（与待办状态筛选同源，只多胶囊圆角）。此处不再有独立皮肤。 */
.field-diary-head { align-items: flex-end; }
.field-diary-head .field-grow { flex: 1; min-width: 0; }
.ov-diary-cta { margin-top: var(--sp-1); display: flex; align-items: center; gap: var(--sp-2); }/* (1008 死规则清理) *//* (1008 死规则清理) */
.diary-bring .btn-link { font-size: var(--fs-caption); }

.diary-list { display: flex; flex-direction: column; gap: var(--card-gap); }
/* 本月心情带（1003）：月度心情小结轻条——材质与 .diary-card 同源（白卡描边投影），
   左「N 月 · N 篇」右四色堆叠条（MOODS 顺序 好→糟，零档自然收 0 宽），下一行小结文案；
   本月 0 篇整条 hidden，不占位。 */
.mood-band {
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-card);
  box-shadow: var(--shadow-card); padding: var(--sp-3) var(--sp-4); margin-bottom: var(--card-gap);
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
/* 行卡规矩：按下只沉底色不缩放 */
.mood-band:active { background: var(--bg-hover); }
.mood-band-go { flex-shrink: 0; display: inline-flex; color: var(--text-4); }
.mood-band-go svg { width: 14px; height: 14px; }
.mood-band-title { font-size: var(--fs-body); font-weight: var(--fw-semibold); color: var(--text-1); flex-shrink: 0; white-space: nowrap; }
.mood-band-track { flex: 1; min-width: 0; height: 8px; display: flex; gap: 2px; border-radius: var(--radius-pill); overflow: hidden; background: var(--bg-muted); }
.mood-band-seg { flex-basis: 0; min-width: 0; }
.mood-band-note { margin-top: var(--sp-1); font-size: var(--fs-micro); color: var(--text-4); }
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   心情热力页（1003）：壳=dd-modal 灰底画布 + hm-modal 桌面 560 宽；
   网格/星期表头/翻页/图例/方向入场全借打卡热力 .hm-* 与 .dp-nav，此处只补：
   ① 大格（月/周）淡彩底——心情色 20% 调和白卡（暗色 30% 调和暗底），数字一律深墨，
     治「全饱和大色块发花」；② 年视图小点面积小，维持本色保住全年扫读；
   ③ 小结行=文字+比例条的横向排布；④ 图例色点直接实色（打卡图例是档位灰绿）。
   ============================================================ */
.moodhm-modal .hm-cell.mh-has { cursor: pointer; }
.moodhm-modal .hm-sq.mh-has, .moodhm-modal .hm-day.mh-has {
  background: color-mix(in srgb, var(--mood) var(--mw, 20%), var(--bg-card)); color: var(--text-2);
}
[data-theme="dark"] .moodhm-modal .hm-sq.mh-has, [data-theme="dark"] .moodhm-modal .hm-day.mh-has {
  background: color-mix(in srgb, var(--mood) var(--mwd, 30%), var(--bg-card)); color: rgba(255, 255, 255, .92); /* 1025：原硬编 #15171B 与 --bg-card 暗档 Δ4，归单源 */
}
.moodhm-modal .hm-dot-c.mh-has { background: var(--mood); }
/* 「本月/今年」当期胶囊：打卡热力给的是习惯色浅档（绿系），心情页里绿色=很好，
   换中性灰避免与心情四色打架 */
/* 时间文本包进白卡（心情 + 习惯两张热力面板共用 .hm-modal）：白底描边 + 微影；
   圆角与两侧 dp-nav 一致（--radius-btn）；高度对齐翻页钮（桌面 26 / ≤768 38） */
.hm-modal .hm-range {
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-btn);
  box-shadow: var(--shadow-sm); min-height: 26px; padding: 0 var(--sp-3);
}
/* ≤768 手机端样式 → 06-mobile.css */
.moodhm-sumtxt { flex: 1; min-width: 0; }
.moodhm-sumtrack { flex: 0 0 120px; height: 8px; }
.diary-card {
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-card);
  box-shadow: var(--shadow-card); padding: var(--sp-3) var(--sp-4); cursor: pointer;
  transition: border-color var(--transition-fast), transform var(--d-base) var(--ease-float), box-shadow var(--d-base) var(--ease-float);
}
@media (hover: hover) { .diary-card:hover { border-color: var(--border-strong); transform: translateY(-2px); box-shadow: var(--shadow-hover); } }
.diary-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-2); }
.diary-date { display: flex; align-items: baseline; gap: var(--sp-2); }
.diary-date b { font-size: var(--fs-body); color: var(--text-1); }
.diary-date span { font-size: var(--fs-micro); color: var(--text-4); }
.diary-body { display: flex; flex-direction: column; gap: var(--sp-1); }
.diary-sec { display: flex; gap: var(--sp-3); font-size: var(--fs-caption); line-height: 1.7; }
.diary-k { flex-shrink: 0; color: var(--text-4); width: 76px; }
.diary-v { color: var(--text-2); min-width: 0; word-break: break-word; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; white-space: pre-wrap; }
.diary-v.muted { color: var(--text-disabled); }

/* 回收站 */
.trash-rows { display: flex; flex-direction: column; max-height: 320px; overflow: auto; }
.trash-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 2px; border-bottom: 1px solid var(--border); }
.trash-row:last-child { border-bottom: none; }
.trash-title { flex: 1; min-width: 0; font-size: var(--fs-caption); color: var(--text-1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.trash-time { font-size: var(--fs-micro); color: var(--text-4); font-family: var(--font-mono); flex-shrink: 0; }

/* 个人中心：数据与提醒 */

/* 1030 清死样式：「可点击 KPI 卡」那一节（.summary-card[data-goto] 三态 + .kpi-grid 的窄屏
   覆盖）随类名一起退役——两个类名在 index.php / assets/*.js / api / lib 里 0 命中。 */
.md-warn { margin: 0 0 var(--sp-2); padding: var(--sp-1) var(--sp-2); border-radius: var(--radius-btn); background: color-mix(in srgb, var(--warning) 14%, transparent); color: var(--text-2); font-size: var(--fs-micro); }

/* ============================================================
   日历头部改版：左「年 月 ▾」下拉 + 右 ‹ › 切月
   ============================================================ */
.dp-head { justify-content: space-between; }
.dp-head-navs { display: flex; align-items: center; gap: 3px; }
.dp-ym { font-size: var(--fs-caption); font-weight: var(--fw-semibold); color: var(--text-1); }

/* ============================================================
   日历下钻动画（Win11 式）：下钻放大入场 / 返回收拢入场
   ============================================================ */
.dp-years, .dp-months, .dp-grid { transform-origin: 50% 40%; }
.dp-zoom-in  { animation: dpZoomIn  var(--d-modal) var(--ease-float); }
.dp-zoom-out { animation: dpZoomOut var(--d-modal) var(--ease-float); }
@keyframes dpZoomIn  { from { opacity: 0; transform: scale(.72); } to { opacity: 1; transform: scale(1); } }
@keyframes dpZoomOut { from { opacity: 0; transform: scale(1.12); } to { opacity: 1; transform: scale(1); } }
@media (prefers-reduced-motion: reduce) {
  .dp-zoom-in, .dp-zoom-out { animation: none; }
}
/* 修复：全局 svg display:block 导致 dp-tl 内箭头折行 */
.dp-tl { display: inline-flex; align-items: center; }

/* 两列格里的 label（优先级/截止时间等）：字形与下间距都在 03 的字段标题唯一档里
   （`.field > label, .field-row > div > label`），此处不再另写一遍。 */
/* 无子任务时列表容器不占位，避免 label 到输入行间距偏大 */
.sub-editor:empty { display: none; }

/* ============================================================
   打卡状态切换过渡：勾/文字弹性入场 + 连续天数淡入
   ============================================================ */
@keyframes btnPop {
  0% { transform: scale(.88); opacity: .4; }
  70% { transform: scale(1.03); }
  100% { transform: scale(1); opacity: 1; }
}
.btn-pop { animation: btnPop var(--d-modal) var(--ease-float); }
@keyframes fadeSoft { from { opacity: 0; } to { opacity: 1; } }
.fade-in { animation: fadeSoft var(--d-push) ease-out; }
@media (prefers-reduced-motion: reduce) {
  .btn-pop, .fade-in { animation: none; }
}

/* ============================================================
   详情弹窗（点击卡片/行 = 查看，编辑走表单）
   —— 旧扁平详情结构（detail-hero/detail-title/detail-desc/detail-count/detail-kv）
      已随 dd-modal 语言收口全部删除，详情语言只剩 .dd-* 一套。
   ============================================================ */
#dt-subs .sub-row { cursor: pointer; }
#dt-subs .sub-row .dt-sub-check { accent-color: var(--primary); width: 15px; height: 15px; flex-shrink: 0; margin: 0; }

/* 弹窗链切换（编辑/新增表单、删除确认）：移动端新内容自顶部推入
   —— 实现在文件末尾「手机端全局 UI/UX 优化 v1.0 · 6」，
   须排在 cascade 等 ≤768 规则之后才能覆盖它们 */

/* ============================================================
   移动端动效优化：退出柔和化 + 弹窗内容级联 + 列表 stagger
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */
/* 待办表格行递进（沿用 tbody-enter 触发，全端生效） */
.tbody-enter tr:nth-child(2) { animation-delay: .03s; }
.tbody-enter tr:nth-child(3) { animation-delay: .06s; }
.tbody-enter tr:nth-child(4) { animation-delay: .09s; }
.tbody-enter tr:nth-child(5) { animation-delay: var(--d-micro); }
.tbody-enter tr:nth-child(6) { animation-delay: var(--d-fast); }
.tbody-enter tr:nth-child(7) { animation-delay: var(--d-base); }
.tbody-enter tr:nth-child(n + 8) { animation: none; }   /* 同上：桌面待办表格第 8 行起直接落终态 */

@media (prefers-reduced-motion: reduce) {
  .modal-card.cascade .modal-body > *,
  .list-cascade > *,
  .content > .view.is-slide-out-l,
  .content > .view.is-slide-in-r,
  .content > .view.is-slide-out-r,
  .content > .view.is-slide-in-l,
  .header-txt.is-swap,
  .tbody-enter tr { animation: none !important; }
}

/* ============================================================
   移动端弹窗链：离场内容淡出（卡片背景常驻，无空白帧）
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */
@media (prefers-reduced-motion: reduce) {
  .modal-card .modal-body, .modal-card .modal-foot { transition: none; }
  .modal-card.leaving .modal-body, .modal-card.leaving .modal-foot { opacity: 0; }
}



/* ============================================================
   用户管理页 + 角色徽章（Ultra / Max / Pro / Free，仅标识）
   1017 方案 E：五档统一构造——淡底 bg@16% + 同色相加深 1px 内描边 bg@38%，扁平无投影。
   描边走 inset box-shadow 而不是 border：桌面档只有 16px 高，加实 border 会吃掉
   内容区 2px 让字顶边，也会撑动下面那条「抽屉等宽列」的基线。
   层级另靠文字前的递增徽记（Free 无 → Pro 点 → Max 星 → Ultra 冠），
   徽记由 app.js roleMarkHtml 出、吃 currentColor 与该行文字同色。
   ============================================================ */
.role-badge {
  display: inline-flex; align-items: center; gap: var(--sp-1); height: 16px; padding: 0 var(--sp-1);
  /* 1018 站主令：全站角色徽章统一为图3那种全圆胶囊——基类圆角从方角档 --radius-btn(r-1) 改成 --radius-pill，
     桌面 / 账户卡 / 详情行 / 顶栏 / 抽屉 / 手机列表一并跟手机档一致（这是把上一版「桌面保持方角」的取舍反转）。 */
  border-radius: var(--radius-pill); font-size: var(--fs-10); font-weight: var(--fw-semibold);
  letter-spacing: .02em; vertical-align: middle; margin-left: var(--sp-1);
}
/* 档位徽记：11px 为桌面基准，≤768 与 ≥1025 两档跟着放大（见本文件下方两处媒体查询） */
.role-badge .rb-mark { display: inline-flex; width: 11px; height: 11px; flex: none; }
.role-badge .rb-mark svg { width: 100%; height: 100%; display: block; }
/* 三档彩色共用同一条构造，只差两枚局部令牌——层级由「色相 + 徽记」承担，不靠各写一遍样式 */
.role-badge.role-ultra, .role-badge.role-max, .role-badge.role-pro {
  background: color-mix(in srgb, var(--rb-bg) 16%, transparent);
  color: var(--rb-fg);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--rb-bg) 38%, transparent);
}
.role-badge.role-ultra { --rb-bg: var(--role-ultra-bg); --rb-fg: var(--role-ultra-fg); }
.role-badge.role-max   { --rb-bg: var(--role-max-bg);   --rb-fg: var(--role-max-fg); }
.role-badge.role-pro   { --rb-bg: var(--role-pro-bg);   --rb-fg: var(--role-pro-fg); }
/* Free 走中性灰，不吃档位色板；描边用 border-strong 与其余三档同份量（原来是无边，站主点名「都加上描边」） */
.role-badge.role-free { background: var(--bg-soft); color: var(--text-4); box-shadow: inset 0 0 0 1px var(--border-strong); }
/* 暗档 Free：--text-4 压在 --bg-soft 上实测只有 4.33:1，够不到 AA（1017 徽章台子量出来的）。
   与 04-shell 里 .role-badge.role-local 暗档同一手——中性字提到 --text-3（约 8.4:1）。
   明档不动：那边 --text-4 过 4.5，且刻意比三档彩色淡一档是层级表达的一部分。 */
[data-theme="dark"] .role-badge.role-free { color: var(--text-3); }

.users-rows { display: flex; flex-direction: column; gap: var(--card-gap); }
.user-row {
  display: flex; align-items: center; gap: var(--sp-3);
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-card);
  box-shadow: var(--shadow-card); padding: var(--sp-3) var(--sp-4);
}
.user-row-avatar {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 36px; height: 36px; border-radius: var(--radius-btn);
  background: color-mix(in srgb, var(--primary) 12%, transparent); color: var(--primary);
  font-size: var(--fs-body); font-weight: var(--fw-semibold);
}
.user-row-info { flex: 1; min-width: 0; }
.user-row-name { display: flex; align-items: center; font-size: var(--fs-body); font-weight: var(--fw-semibold); color: var(--text-1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-row-name .tag { margin-left: var(--sp-2); }
.user-row-name .role-badge { margin-left: var(--sp-1); }
.user-row-sub { margin-top: 2px; font-size: var(--fs-micro); color: var(--text-4); }
.users-denied {
  padding: var(--sp-8) var(--sp-4); text-align: center; border: 1px dashed var(--border);
  border-radius: var(--radius-card); color: var(--text-4); font-size: var(--fs-caption);
}
/* 手机端角色胶囊：与 .role-badge 共用色板（元素带双类），只放大形与热区；
   复合选择器压过 ≤768 的 .role-badge 单类档（同元素双类必须写复合，后代选择器不生效） */
.u-role-pill.role-badge {
  position: relative; flex-shrink: 0; border: 0; cursor: pointer;
  height: 30px; padding: 0 var(--sp-3); border-radius: var(--radius-pill);
  font-size: var(--fs-12); font-weight: var(--fw-semibold);
  transition: transform var(--d-micro) ease, filter var(--transition-fast);
}
.u-role-pill.role-badge::after { content: ""; position: absolute; inset: -5px; } /* 视觉 30px，热区 40px */
.u-role-pill.role-badge:active { transform: scale(.94); filter: brightness(.92); }
.u-role-pill.role-badge .rb-mark { width: 13px; height: 13px; } /* 胶囊 30px 高、字 fs-12，徽记同档放大 */
/* 角色抽屉只有 4 行：刻意不带 .tf-list 类——wireSheetGrab 的选择器链认不到列表，
   抽屉就按内容高度收起（同登录抽屉的无列表形态），不会被两档锁拉到 2/3 屏留大片空白；
   把手下拉关闭 / 上滑橡皮筋照常 */
.u-role-list { display: flex; flex-direction: column; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.u-role-list .tf-row { padding: var(--sp-4); }
/* 徽章定宽成等宽列，后面的角色说明文字左对齐到同一条基线。
   1017 方案 E 给每枚徽章前加了徽记（图标 11px + 间距 4px），52px 装不下「◆ Ultra」，
   故放宽到 68px——Free 没有徽记，靠 min-width + justify-content:center 仍与其余三行同宽同基线。 */
.u-role-list .tf-row .role-badge { margin-left: 0; min-width: 68px; justify-content: center; height: 22px; padding: 0 var(--sp-2); font-size: var(--fs-12); flex: none; }
.u-role-note { font-size: var(--fs-micro); color: var(--text-4); line-height: 1.7; padding: 0 2px calc(var(--sp-1) + var(--sab, 0px)); }
/* 用户管理行内的「每日额度」钮：壳整个借 .cat-act（与铅笔/删除同族，≤768 自动放大到 40 热区）。
   开了小灶的在右上角点一颗实心点——它不占宽度（手机端那一行只有头像｜信息｜三颗钮的余量），
   又能一眼看出「这个人是被单独开过档的」；具体数值点开看，不铺开成第四列文字。 */
.u-cap { position: relative; }
.u-cap.has-cap::after { content: ""; position: absolute; top: 2px; right: 2px; width: 6px; height: 6px;
  border-radius: var(--r-circle); background: var(--primary); }
/* 桌面副行才写数值：手机端 .user-row-sub 没有 nowrap，多写一段字就把整行顶成两行 */
.u-cap-note { color: var(--text-3); }
/* 额度小灶页（用户管理 → 那颗额度钮）：卡片分组照站主 1007 参考稿，
   方言全部用站内表单那一套——输入行走 .fg-row + .form-input（不是记一笔那只金额大账盒）、
   快捷档借 .lg-pays/.lg-pay、两枚标借 .hm-cur/.hm-back、撤掉借标准 .btn.btn-sm.btn-danger。
   这里只补把它们串起来的骨架，不新造视觉语言。 */
/* 手写 .fg-card 也要用 hidden 属性开关（撤掉那张卡）：媒体查询里 .fg-card 是 display:block，
   会压掉 UA 的 [hidden]{display:none}——与 .st-navbtn 那颗出票钮同一类坑，不点名就收不回。 */
.fg-card[hidden] { display: none; }
.cap-bar { margin-top: var(--sp-3); }
.cap-tags { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-top: var(--sp-3); }
/* 表单行里裸放的按钮要贴右缘：.fg-row 的标题是定宽列（flex:0 0 auto），
   只有 .form-input / .select-wrap 一族才 flex:1 顶到右边（同记一笔 .lg-dir 那一招）。 */
.fg-card .fg-row > .btn { margin-left: auto; }
/* 「撤掉」这颗借一句话那颗黑胶囊（.nl-act + .nl-act-btn 的材质），但 .nl-act 是为「悬浮」写的，
   搬进卡片行要连带治它三条：① 桌面那条 `@media(min-width:769px){.nl-act{display:none}}`
   会把这颗钮整颗藏掉（只给 .nl-sheet 留活口）；② 浮入动画 nlFloatIn 在常驻行里是多余的跳动；
   ③ 它是 span，不吃上面那条 `> .btn` 的贴右规则。
   ★ 必须写复合选择器 .nl-act.cap-pill（0,2,0）：媒体查询不加特异性，
     单写 .cap-pill 会与那条桌面规则同分、按先后裁决，早晚被 display:none 盖掉。 */
.fg-card .fg-row > .cap-pill { margin-left: auto; }
.nl-act.cap-pill { display: inline-flex; animation: none; }
.cap-val { flex: none; margin-left: auto; font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: calc(16px * var(--fs-scale)); font-weight: var(--fw-semibold); color: var(--text-1); }
.cap-note { margin-top: var(--sp-2); font-size: var(--fs-micro); color: var(--text-4); line-height: 1.6; }
/* 1018 站主续：要在手机端列表随时看每人今日额度（今用/余），撤销此前「手机端隐藏 u-cap-note」那条
   （旧顾虑是怕顶两行，但注记在昵称下方的小字副行里，长了自然换到副行第二行，不动卡片主体那单行 头像｜昵称｜胶囊）。 */

/* ≤768 手机端样式 → 06-mobile.css */

/* ---- 用户管理页内检索与统计（1011）-------------------------------------
   三块全借现成外壳，本段只补它们凑进同一页缺的那点几何：
   ① 搜索框 = .search-field 药丸（搜索体系 v2 定「抽屉与桌面页内框共用一只框」），
      基座里它是 inline-flex + min(320px,100%)，页内要通栏所以放宽成 100%；
   ② 总数 = .st-hero-n（统计页那只大数字，同档字号），装进 .panel 卡；
   ③ 角色筛选 = .cat-filter + .chip（待办/备忘/纪念日同一排分类芯片），人数走 .chip-cnt。
   顺序账：以下全是单类，写在 33 行 .cat-filter 与 03 组件 61 行 .search-field 之后才压得住；
   ≤768 的 .cat-filter 横滑轨（161）与 .cat-filter .chip 38 高（2153）本段都不覆盖，照吃。
   桌面整行可点，光标给到 pointer（手机端按下反馈已有 .user-row:active 那一档）。 */
.us-tools { margin-bottom: var(--module-gap); }
.us-search { width: 100%; margin-bottom: var(--card-gap); }
.us-stat { padding: var(--sp-4) var(--sp-4) var(--sp-3); }
.us-stat .us-filter { margin: var(--sp-3) 0 0; } /* .cat-filter 默认那 20 底距是给页外用的，卡里只留上距 */
/* 两排筛选（角色 / 邮箱）之间也吃这一条 12px——站内「同组筛选相互间收进 card-gap」的既有节奏，
   所以不需要第二排单独开规则（分段器那版留下的 .us-mail-seg 随真机反馈撤掉）。 */
/* 0 人档：整颗降一档灰度。hover 复位并成一条写（拆成两条会与 .wd-btn:hover 那组逐字撞车，
   撞进 bloat-gate 的重复组；合一条还顺手把 :hover 的特异性抬到 4 类，压得住 .chip:hover） */
.us-stat .chip[disabled], .us-stat .chip[disabled]:hover {
  opacity: .45; border-color: var(--border); color: var(--text-3); cursor: default;
}
.user-row { cursor: pointer; }
/* 详情页头像：借 .user-row-avatar 那只材质，只在 hero 里放大一档。
   并排那一行不新造 flex——套既有的 .dd-hero-head；只把自己那两行的竖排留白收掉
   （挂在 .us-d-id 上而不是 .dd-hero-head 上：个人中心那页也在用后者，别连坐）。 */
.us-d-av { width: 46px; height: 46px; font-size: calc(18px * var(--fs-scale)); }
.us-d-id .dd-hero-name { margin-top: 0; }
.us-d-id .dd-hero-date { margin-top: 3px; }
/* 双类压 .dd-v（那条在 2296 行、比我靠后，单类写过去颜色被它吃回去） */
.dd-v.us-d-none { color: var(--text-disabled); }

/* ---- 停用（封号）· 详情页动作行（2.09）-------------------------------
   停用页整屏借的就是详情那一套（.dd-hero / .dd-group / .dd-hero-name），
   本段只补它独有的四样：禁行标记、解封时间那一句、管理员备注的原样呈现、底部一句去处说明。
    1018 站主令：连「删除账号」这行也不涂红了（红太突兀），站内唯一的 dd-danger 使用者已去类，
    这条报警色皮肤随其规则一并撤除；危险度回归文案「连同名下数据一并删除」+ confirmDeleteUser 二次确认。 */
.susp-mark {
  display: inline-flex; width: 44px; height: 44px; border-radius: var(--r-circle);
  background: var(--tag-bad-bg); color: var(--tag-bad-fg); align-items: center; justify-content: center;
}
.susp-mark svg { width: 24px; height: 24px; }
/* 备注是管理员写给人家看的一句原话：不截断、不折行成省略号，pre-wrap 让他自己换的行也算数 */
.susp-note {
  padding: var(--sp-3) var(--sp-4); font-size: calc(15px * var(--fs-scale));
  color: var(--text-2); line-height: 1.6; white-space: pre-wrap; word-break: break-word;
}
.susp-tip { margin-top: var(--sp-3); padding: 0 var(--sp-1); font-size: var(--fs-micro); color: var(--text-4); line-height: 1.6; }
.susp-hint { font-style: normal; font-weight: 400; font-size: var(--fs-micro); color: var(--text-4); margin-left: var(--sp-1); }
/* 折叠态只留一行入口：那句说明跟着输入框一起收，
   否则「保存后该账号需用新密码重新登录」会孤零零挂在入口行底下，读起来像已经展开了 */
.desc-field.is-collapsed > .field-hint { display: none; }

/* 侧栏用户名行：徽章跟随名字右侧（flex 对齐 + 溢出保护） */
.user-name { display: flex; align-items: center; gap: var(--sp-1); min-width: 0; }
.user-name .role-badge { margin-left: 0; flex-shrink: 0; }
.user-name { overflow: hidden; }
.user-name > :first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ============================================================
   自定义下拉（用户管理角色选择）：展开列表主题化
   ============================================================ */
.dd { position: relative; width: 96px; flex-shrink: 0; }
.dd-toggle {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-1); cursor: pointer; text-align: left;
}
.dd-toggle svg { width: 12px; height: 12px; color: var(--text-4); flex-shrink: 0; transition: transform var(--d-fast) var(--ease-float); }
.dd.open .dd-toggle svg { transform: rotate(180deg); }
.dd-menu {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 40;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-btn);
  box-shadow: var(--shadow-hover); padding: var(--sp-1); display: flex; flex-direction: column; gap: 2px;
  animation: ddIn var(--d-fast) var(--ease-enter);
}
@keyframes ddIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }
.dd-item {
  display: flex; align-items: center; justify-content: space-between;
  border: none; background: transparent; border-radius: calc(var(--radius-btn) - 2px);
  padding: var(--sp-1) var(--sp-2); font-size: var(--fs-caption); color: var(--text-2); cursor: pointer; text-align: left;
  transition: background var(--transition-fast), color var(--transition-fast);
}
@media (hover: hover) { .dd-item:hover { background: var(--bg-hover); color: var(--text-1); } }
.dd-item.is-sel { color: var(--primary); font-weight: var(--fw-medium); }
/* ≤768 手机端样式 → 06-mobile.css */
@media (prefers-reduced-motion: reduce) {
  .dd-menu { animation: none; }
}

/* hidden 属性全局兜底：任何自定义 display 的元素，hidden 时必须真正隐藏
   （.dd-menu 的 display:flex 覆盖过 hidden 默认样式 → 菜单常开） */
[hidden] { display: none !important; }

/* Ultra（创始人）：1017 权限徽章重设计（方案 E）——旧「双金渐变 + 内描边」撤掉，
   Ultra 并入本文件上方那条与 Max/Pro 共用的淡底+同色描边构造（只绑 --role-ultra-bg/fg）。
   顶配身份改由「金色相 + 一枚皇冠」承担，不再靠材质化装饰（那做法在同族里像穿了礼服）。
   故此处不再单独给 .role-badge.role-ultra 写样式。 */


/* ============================================================
   移动端 tabbar 布局（显式 margin 版）：dock 滑动动画可过渡
   胶囊宽度恒定 = 容器宽 - --dock-r（那 70px 是留给圆形加号的席位），两态差别只剩
   「本视图有没有加号」：有 → margin-left:0 左贴；没有 → 平移到正中。
   居中量由 --dock-r 算出（r/2），≤380 档只换这一个令牌——历史上 70/62 与 35/31
   各写两份，改一处忘一处就出过「dock 右移 66px、贴死屏幕右边」的实测 bug。
   两态都显式 transform:none：只留 margin-left 一位移源。
   0925 备忘：试过「概览+统计两席 / 收窄居中」的双形态（含逐帧跟手形变），手机上
   反而丢了直达五个模块那一排，已回退；那版源码存 E:\Klog\backups\20260925-dock-dual-shipped。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* 周岁 / 周年徽章：主色淡底，区别于普通 tag */
.years-tag {
  /* 与英雄区「类型」胶囊（.dd-mood）同一套语言：等高描边胶囊、成对出现不再突兀。
     告别旧 .tag 的小方角矮片，改用胶囊圆角 + bg-card 干净底 + text-3 弱一档。 */
  height: 24px; padding: 0 var(--sp-2);
  border-radius: var(--radius-pill);
  background: var(--bg-card);
  border: 1px solid var(--border);
  color: var(--text-3);
  font-weight: var(--fw-medium);
  letter-spacing: .02em;
}

/* 类型 / 分类筛选浮层共用的 tf-row 列表（复用 .wp-mask/.wp-sheet 抽屉骨架） */
.tf-list {
  display: flex; flex-direction: column; gap: var(--sp-2);
  max-height: 52vh; overflow-y: auto; margin-bottom: var(--sp-4);
}
.tf-row {
  position: relative; /* 行内绝对定位件的地基（1020 曾钉 .tf-bar 卡底缘，1025 撤条后仍留作通用地基） */
  display: flex; align-items: center; gap: var(--sp-3); width: 100%;
  padding: var(--sp-3) var(--sp-4); border: 1px solid var(--border); border-radius: var(--r-3);
  background: var(--bg-card); color: var(--text-1); font-size: calc(15px * var(--fs-scale)); text-align: left;
  cursor: pointer; transition: background var(--d-fast), border-color var(--d-fast);
}
@media (hover: hover) { .tf-row:hover { background: var(--bg-hover); } }
.tf-row.is-sel { border-color: var(--primary); background: var(--bg-hover); }
.tf-dot { width: 12px; height: 12px; border-radius: var(--r-circle); flex-shrink: 0; }
.tf-dot-all { background: transparent; box-shadow: inset 0 0 0 1.5px var(--text-4); }
.tf-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tf-cnt { font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--text-4); font-size: calc(13px * var(--fs-scale)); }
.tf-check { color: var(--primary); display: inline-flex; }
.tf-check svg { width: 18px; height: 18px; }
/* 分类抽屉行名下的「共 N 件 · 已完成 d」小字。
   .tf-sub 生产里从无定义（排序抽屉那行的 sub 一直没样式、挤成同行尾巴）——这里补上
   块级小字档，同时服务分类抽屉、排序抽屉与 1025 合并抽屉的当前档说明三处，不另开第二个类。
   1025（站主点名「每个分类下面那根进度条不好看」）：卡底那根 .tf-bar 完成度条连同
   为它加的 9px 底内距一并撤掉——主读数已换成未完成数，比例不需要图形再讲一遍，
   行收回单行节奏。 */
.tf-sub { display: block; font-size: var(--fs-micro); color: var(--text-4); }

/* 类型管理：内置类型（生日 / 纪念日）只读行 + 内置小标 */
.mg-row-builtin { cursor: default; }
.mg-row-builtin:hover { background: transparent; }
.mg-builtin-tag { margin-left: auto; }

/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   小票机：机身（白卡，站内灰底白卡语言）+ 纸（吐纸动画）+ 小票盒
   拟物只保留「出纸口 + 白纸滑出」的骨架，材质全部走令牌：
   机身=白卡描边，屏幕=浅灰内衬，主操作=小面积黑胶囊，出纸口=浅灰凹槽。
   ============================================================ */
.rm-tabs { margin-bottom: var(--sp-3); } /* 视觉由 .seg 分段组件承担 */
/* 票种开关（日志票 / 账本月票）：seg-slide 通栏两段，摆在机身之上、机器之前 */
.rm-mode { display: flex; width: 100%; margin-bottom: var(--sp-3); }

.rm-machine {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--r-4); padding: var(--sp-4) var(--sp-4) 0;
  box-shadow: var(--shadow-card);
  position: relative; overflow: hidden;
}
.rm-brand { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--sp-3); }
.rm-logo { color: var(--text-1); font-weight: var(--fw-bold); font-size: var(--fs-body); letter-spacing: .04em; }
.rm-screen {
  background: var(--bg-page); border: 1px solid var(--border);
  border-radius: var(--r-3); padding: var(--sp-3) var(--sp-4); min-height: 96px;
  display: flex; flex-direction: column; justify-content: center; gap: var(--sp-2);
}
.rm-date-line { display: flex; align-items: baseline; gap: var(--sp-3); }
.rm-date-line b { color: var(--text-1); font-size: var(--fs-h3, 17px); font-weight: var(--fw-bold); }
.rm-date-line span { color: var(--text-4); font-size: var(--fs-caption); }
.rm-state { display: flex; align-items: center; gap: var(--sp-2); color: var(--text-3); font-size: var(--fs-caption); }
.rm-dot { width: 8px; height: 8px; border-radius: var(--r-circle); background: var(--text-4); flex-shrink: 0; }
.rm-dot-busy { background: var(--rm-dot-busy); animation: rmPulse 1s ease-in-out infinite; }
.rm-dot-done { background: var(--rm-dot-done); }
@keyframes rmPulse { 50% { opacity: .3; } }

.rm-actions { padding: var(--sp-3) 0; display: flex; justify-content: flex-end; }
.rm-actions .btn { background: var(--primary); border-color: transparent; color: var(--on-primary); }
@media (hover: hover) { .rm-actions .btn:hover { background: var(--primary-hover); } }
.rm-slot { height: 10px; background: var(--bg-muted); border-radius: var(--r-2) var(--r-2) 0 0; margin: 0 -18px; box-shadow: inset 0 2px 4px rgba(17,17,17,.10); }



.rm-paper-ops { display: flex; justify-content: center; padding: var(--sp-2) 0 0; }

/* 小票盒：存根墙——每条存档是一张撕下来的白纸票根（直边顶、锯齿撕边底，与小票 canvas 的撕边同构），
   墨色与小票印刷同源（#111/#9a9a9a），纸质细节=打孔虚线分界 + 等宽字打印时间 + 右下角 NO. 微缩票号；
   整行点按查看，右上角小圆钮删除 */
.rm-box-list { display: flex; flex-direction: column; gap: var(--sp-4); max-width: 400px; margin: 0 auto; padding: 2px 2px var(--sp-3); }
.rm-box-row {
  position: relative; display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-3) var(--sp-4) var(--sp-4); background: var(--white); border-radius: var(--r-1); /* 小票纸面＝固定白纸材质（§1 材质豁免：机身翻面、纸不翻），
    故纸上墨色 #111/#9a9a9a/#b9b9b9 为材质固定色，勿改 --text-*/--primary（暗档会翻出「黑纸上白字」事故） */
  box-shadow: 0 1px 1px rgba(17,17,17,.05), 0 8px 18px -10px rgba(17,17,17,.22);
  cursor: pointer; user-select: none; -webkit-user-select: none;
  transition: transform var(--d-base) var(--ease-float), box-shadow var(--d-base) ease;
  animation: rmBoxIn var(--d-enter) var(--ease-enter) backwards;
}
@media (hover: hover) { .rm-box-row:hover { transform: translateY(-2px); box-shadow: 0 1px 1px rgba(17,17,17,.05), 0 12px 26px -10px rgba(17,17,17,.28); } }
.rm-box-row:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }
/* 锯齿撕边：纸色朝下三角铺满行底 */
.rm-box-row::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -5px; height: 6px;
  background: conic-gradient(from -45deg at 50% 100%, #fff 90deg, transparent 0) 0 0 / 12px 6px repeat-x;
}
@keyframes rmBoxIn { from { opacity: 0; transform: translateY(12px) scale(.985); } }
.rm-box-row:nth-child(2) { animation-delay: .04s; }
.rm-box-row:nth-child(3) { animation-delay: .08s; }
.rm-box-row:nth-child(4) { animation-delay: var(--d-micro); }
.rm-box-row:nth-child(5) { animation-delay: var(--d-fast); }
.rm-box-row:nth-child(6) { animation-delay: var(--d-base); }
.rm-box-row:nth-child(7) { animation-delay: var(--d-modal); }
.rm-box-row:nth-child(n+8) { animation-delay: var(--d-toast); }
.rm-box-day { flex: 0 0 auto; min-width: 46px; text-align: center; }
.rm-box-day b {
  display: block; font-size: calc(27px * var(--fs-scale)); line-height: 1.05; font-weight: 800; color: #111;
  font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}
.rm-box-day span { display: block; margin-top: 3px; font-size: var(--fs-11); color: #9a9a9a; letter-spacing: .05em; white-space: nowrap; }
/* 打孔虚线：存根与票体的分界 */
.rm-box-info {
  flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px;
  border-left: 1px dashed rgba(17,17,17,.20); padding-left: var(--sp-3);
}
.rm-box-date { font-size: calc(15px * var(--fs-scale)); font-weight: 600; color: #111; }
.rm-box-sub {
  font-size: var(--fs-12); color: #9a9a9a; letter-spacing: .01em;
  font-family: ui-monospace, "SF Mono", Consolas, monospace;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rm-box-del {
  flex: 0 0 auto; width: 38px; height: 38px; border: none; border-radius: var(--r-circle);
  background: transparent; color: #b9b9b9; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--d-base) ease, color var(--d-base) ease;
}
.rm-box-del svg { width: 17px; height: 17px; }
@media (hover: hover) { .rm-box-del:hover { background: rgba(17,17,17,.06); color: var(--status-bad); } }
/* 右下角微缩票号：像存根上印的小字 */
.rm-box-no {
  position: absolute; right: 15px; bottom: 5px; pointer-events: none;
  font-family: ui-monospace, "SF Mono", Consolas, monospace;
  font-size: var(--fs-9); letter-spacing: .12em; color: rgba(17,17,17,.30);
}
.rm-box-empty {
  text-align: center; padding: var(--sp-8) var(--sp-4); margin: var(--sp-1) 2px;
  border: 1.5px dashed var(--border-strong); border-radius: var(--r-3); color: var(--text-4);
}
.rm-box-empty svg { width: 34px; height: 34px; display: block; margin: 0 auto var(--sp-3); opacity: .85; }
.rm-box-empty p { margin: 0; font-size: var(--fs-caption); font-weight: var(--fw-medium); color: var(--text-3); }
.rm-box-empty span { display: block; margin-top: var(--sp-1); font-size: var(--fs-micro); color: var(--text-4); }
@media (prefers-reduced-motion: reduce) { .rm-box-row { animation: none; } }


/* ============================================================
   出纸机制：overflow 裁剪窗（静止、透明）——整卷纸藏于出纸口内，
   打印时整张纸（含投影）分段下移 translateY(-100% → 0)，从出纸口滑出。
   窗口自身不做任何动画，纸的外观全部跟纸走，避免"纸先出现、内容再动"的割裂感
   ============================================================ */
/* 高度：移动端随 ≤768 的 .modal-card 规则全屏；桌面在下方媒体块定高 82vh */
.rm-modal .modal-body { flex: 1; overflow-y: auto; background: var(--rm-well); }
.rm-machine {
  max-width: 340px; margin: 0 auto;
  background: linear-gradient(180deg, var(--bg-card) 0%, color-mix(in srgb, var(--bg-card) 95%, #111111 5%) 100%);
  border: 1px solid var(--border);
  border-radius: var(--r-4); padding: var(--sp-4) var(--sp-4) var(--sp-3);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.9),
    inset 0 -1px 0 rgba(17,17,17,.04),
    0 1px 1px rgba(17,17,17,.05),
    0 3px 6px rgba(17,17,17,.07),
    0 12px 24px -8px rgba(17,17,17,.16);
  position: relative; z-index: 2;
}
.rm-brand { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--sp-3); }
.rm-screen { background: var(--bg-page); border-color: var(--border); border-radius: var(--r-3); padding: var(--sp-3) var(--sp-4); }
.rm-screen .rm-actions { padding: var(--sp-3) 0 0; }
/* 出纸口：机身底部一道内凹的深色「狭缝」，与纸同宽，纸从缝里往下滑出 */
.rm-slot {
  height: 5px; margin: var(--sp-3) 0 0; border-radius: var(--r-1);
  background: linear-gradient(180deg, #26262b, #5b5b63);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.55), 0 1px 0 rgba(255,255,255,.6);
}
/* 机身「打印 ID 昵称」设置：与屏幕同语言的浅灰内衬控制卡（图标 + 文案 + 加大开关），
   不再是「左字右开关」的裸行，读作打印机面板上的一枚开关 */
.rm-nick-row {
  display: flex; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-3); padding: var(--sp-2) var(--sp-3);
  background: var(--bg-page); border: 1px solid var(--border); border-radius: var(--r-3);
  font-size: calc(15px * var(--fs-scale)); color: var(--text-1);
  cursor: pointer; user-select: none; -webkit-user-select: none;
}
.rm-nick-ico { display: inline-flex; color: var(--text-3); flex-shrink: 0; }
.rm-nick-ico svg { width: 16px; height: 16px; }
.rm-nick-txt { flex: 1; font-weight: var(--fw-medium); letter-spacing: .01em; }
.rm-nick-row .status-switch { width: 34px; height: 18px; }
.rm-nick-row .status-switch .switch-slider::before { width: 14px; height: 14px; left: 2px; top: 2px; }
.rm-nick-row .status-switch input:checked + .switch-slider::before { transform: translateX(16px); }
/* 裁剪窗口（静止、透明）：顶部对齐出纸口狭缝下沿，整卷纸藏于缝内，打印时从缝里往下滑出。
   负 margin 让窗口上移压住机身底部，消除机身与纸之间的缝隙，纸看起来是「从缝里吐出来」。
   z-index 高于机身，使滑出的纸盖在机身下唇之上（纸搭在前缘，更像真实出纸）。
   左右内距比机身多 4px（20 vs 16）→ 纸比出纸口略窄，缝两端各探出纸面约 3px，像纸从稍宽的缝里出来。 */
.rm-paper-win { max-width: 340px; margin: -13px auto 0; overflow: hidden; padding: 0 var(--sp-4) 30px; position: relative; z-index: 3; }
.rm-paper { margin: 0; }
/* 纸的外观：投影必须跟着纸的轮廓走——box-shadow 按矩形边框投影，会在撕边下方压出一条
   直边暗带、把齿轮齿吃掉一半，所以这里用 drop-shadow（按 alpha 轮廓，齿尖才有纸感）。
   顶边方角贴缝、底边由画布自己挖齿，故不铺白底、不留底部圆角。 */
.rm-paper canvas {
  display: block; width: 100%;
  filter: drop-shadow(0 4px 6px rgba(17,17,17,.16));
}

/* 小票盒「查看」：全屏纯小票查看器（body 级独立浮层，叠在小票机之上、关闭回到小票盒，不顶掉弹窗） */
.rm-view-mask {
  position: fixed; inset: 0; z-index: 9000;
  background: rgba(12,12,14,.74);
  opacity: 0; transition: opacity var(--d-modal) ease;
}
.rm-view-mask.is-open { opacity: 1; }
.rm-view { position: absolute; inset: 0; display: flex; flex-direction: column; }
.rm-view-bar {
  flex: 0 0 auto; display: flex; align-items: center; gap: var(--sp-2);
  padding: calc(var(--sp-2) + var(--sat)) var(--sp-3) var(--sp-2);
}
.rm-view-title {
  flex: 1; text-align: center; font-size: calc(15px * var(--fs-scale)); font-weight: 600;
  letter-spacing: .01em; color: rgba(255,255,255,.92);
}
.rm-view-x, .rm-view-save {
  width: 38px; height: 38px; flex: 0 0 auto; border: none; border-radius: var(--r-circle);
  background: rgba(255,255,255,.14); color: #fff; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--d-base) ease;
}
@media (hover: hover) { .rm-view-x:hover, .rm-view-save:hover { background: rgba(255,255,255,.26); } }
.rm-view-x:active, .rm-view-save:active { background: rgba(255,255,255,.34); }
.rm-view-x svg, .rm-view-save svg { width: 20px; height: 20px; }
.rm-view-scroll {
  flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch;
  display: flex; justify-content: center; align-items: flex-start;
  padding: var(--sp-1) var(--sp-6) calc(30px + var(--sab));
}
/* 查看器里的纸：白面由画布自己承担（底边是挖空的齿轮撕边），容器只留顶部圆角与投影。
   同样用 drop-shadow 让投影跟轮廓走，否则矩形 box-shadow 会从齿缝透出来、压出一条直边暗线 */
.rm-view-paper {
  width: 100%; max-width: 320px; background: transparent; border-radius: var(--r-2) var(--r-2) 0 0; overflow: hidden;
  filter: drop-shadow(0 14px 26px rgba(0,0,0,.42));
}
.rm-view-paper canvas { display: block; width: 100%; }

/* 小票机日期控件：极简日历图标（白卡机身上浅灰底圆角钮；选中日期由机身屏展示，点按开日历）。
   enhanceDates 注入的 dp-display 承载点击与可达性（文字 font-size:0 隐藏、保留朗读），
   date-ico 提供图标并铺满整个按钮 */
.rm-cal {
  position: relative; width: 36px; height: 36px; padding: 0;
  border-radius: var(--r-2); background: var(--bg-muted);
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--transition-fast);
}
@media (hover: hover) { .rm-cal:hover { background: var(--border); } }
.rm-cal .date-wrap { position: absolute; inset: 0; } /* 流内无内容会塌缩，强制铺满按钮作为定位参照 */
.rm-cal .dp-display {
  position: absolute; inset: 0; width: 100%; height: 100%; padding: 0;
  border: none; background: transparent; font-size: 0; line-height: 0;
}
.rm-cal .date-ico {
  inset: 0; width: 100%; height: 100%; right: auto; top: auto; transform: none;
  color: var(--text-2); border-radius: var(--r-2);
}
@media (hover: hover) { .rm-cal .date-ico:hover { background: transparent; color: var(--text-1); } }
/* 保存按钮：简约圆形下载图标，紧跟纸底 */
.rm-save-btn {
  width: 42px; height: 42px; border-radius: var(--r-circle);
  border: 1px solid var(--border); background: var(--bg-card); color: var(--text-2);
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  transition: color var(--transition-fast), border-color var(--transition-fast), transform var(--d-fast) var(--ease-float);
}
.rm-save-btn svg { width: 18px; height: 18px; }
@media (hover: hover) { .rm-save-btn:hover { color: var(--primary); border-color: var(--primary); transform: translateY(-2px); } }
.rm-save-btn:active { transform: scale(.92); }

/* 小票机弹窗：桌面宽一点 + 定高 82vh；移动端随全局弹窗全屏 */
@media (min-width: 769px) { .modal-card.rm-modal { max-width: 560px; height: 82vh; } }

/* ============================================================
   键盘跳转链接：视觉隐藏，获得焦点时从顶部滑入
   ============================================================ */
.skip-link {
  position: fixed; top: -48px; left: 16px; z-index: 300;
  padding: var(--sp-2) var(--sp-4); border-radius: 0 0 var(--r-2) var(--r-2);
  background: var(--primary); color: var(--on-primary);
  font-size: var(--fs-caption); text-decoration: none;
  transition: top var(--transition-fast);
}
.skip-link:focus-visible { top: 0; }

/* 长列表渲染优化：屏外卡片跳过渲染（滚动到即恢复，auto 记住上次高度）
   覆盖 备忘/纪念/习惯/回顾 四类卡片列表（备忘实际类名是 .card-grid，
   此前写成 .memo-grid 一直是死选择器） */
.date-list > *, .habit-grid > *, .diary-list > *, .card-grid > * {
  content-visibility: auto;
  contain-intrinsic-size: auto 120px;
}

/* 个人中心内嵌管理区块：导出 / 导入按钮横排 */

/* ===================== 个人中心 pf-* 区块体系 =====================
   布局：账户卡 → 我的概览 KPI → 数据统计 → 数据管理 → 偏好设置 → 账户安全 → 危险操作
   颜色 / 圆角 / 字号 / 动效全部走全站设计令牌，暗色主题自动适配 */

/* 账户卡 */
.pf-account {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--bg-soft); border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
/* 登录态账户卡整卡可点击进入编辑资料（右箭头为视觉引导） */
.pf-account-click { cursor: pointer; }
/* 账户卡 + 云端同步状态行：单容器连体（一卡两段，内部分隔线），消除拼接割裂感。
   overflow 与 .pfg-card 同一条规矩：底部那段是通栏色带，圆角由卡壳统一裁，
   色带自己不再补圆角。 */
.pf-idcard {
  background: var(--bg-soft); border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition: border-color var(--transition-fast);
}
@media (hover: hover) { .pf-idcard:has(.pf-account-click:hover) { border-color: var(--border-strong); } }
.pf-idcard .pf-account { background: transparent; border: 0; border-radius: 0; }
/* 云端同步状态行：容器内第二段，上边框即内部分隔线。
   底色与 AI 连接卡那条铭牌带（.ai-conn-foot）同档 --bg-soft——
   「白卡 + 底部浅灰信息带」是站内一处语言，两处各染一套就成了两个家族（1003） */
.pf-sync-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--border); background: var(--bg-soft);
  font-size: var(--fs-body); color: var(--text-2);
}
.pf-sync-ok { display: inline-flex; align-items: center; gap: var(--sp-1); color: var(--tag-good-fg); flex: none;
  transition: color var(--transition-fast); }
.pf-sync-ok svg { width: 14px; height: 14px; }
/* 2.34：这句从写死换成读出来的（复用站内 tag 那两档色，不另配色板）。
   「正在同步」不转圈——这一行只有 14px，转起来是装饰不是信息，文案已经说了在动。
   未登录时右侧压根不摆徽章：没有云端可说，再染一档灰只是多一条规则。 */
.pf-sync-ok.is-warn { color: var(--tag-bad-fg); }
.pf-sync-ok.is-busy { color: var(--text-3); }

/* ---- 本机与云端（2.34 个人中心二级页）----
   行壳直接复用 .pfg-row（行高 / 分隔线 / 图标档 / 热区都在里面），这里只补差异那一小块；
   读不到云端就一句正文灰 + 一颗「再读一次」，不另立红字类（这不是校验失败）。
   勾选行借 .sd-item 自己一层，不硬套 .pfg-row——它没有箭头、右侧是勾而不是跳转。 */
.sd-load { padding: var(--sp-4) 2px; font-size: var(--fs-body); color: var(--text-3); }
.sd-load + .btn-link { margin-top: var(--sp-2); }
.sd-row { min-height: 52px; }
/* 两行堆叠用块级子元素，不另开一条 flex 列——那与时间线的 .tl-main 逐字同体，
   等于把同一份声明抄第二遍（bloat-gate 的逐字重复组会凭空多一组） */
.sd-t { flex: 1; min-width: 0; }
.sd-t b { display: block; font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--text-1); }
.sd-t-2 { display: block; margin-top: 2px; font-size: var(--fs-12); color: var(--text-3); font-variant-numeric: tabular-nums; }
.sd-tag { flex: none; font-size: var(--fs-12); color: var(--text-3); }
.sd-tag.is-gain { color: var(--tag-good-fg); }
.sd-tag.is-up { color: var(--text-2); }
.sd-list { padding: 2px 0 var(--sp-2); border-bottom: 1px solid var(--border); }
.sd-item {
  display: flex; align-items: center; gap: var(--sp-3); min-height: 38px;      /* 站内手机端触控地板 */
  padding: 0 2px; font-size: var(--fs-body); color: var(--text-2); cursor: pointer;
}
.sd-item input { flex: none; width: 18px; height: 18px; accent-color: var(--text-1); }
.sd-item-t { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sd-item.is-on .sd-item-t { color: var(--text-1); }
.sd-empty { padding: var(--sp-2) 2px var(--sp-3); font-size: var(--fs-12); color: var(--text-hint); }
.sd-foot { margin-top: var(--sp-3); font-size: var(--fs-12); line-height: 1.5; color: var(--text-3); }
.sd-foot b { font-weight: var(--fw-semibold); color: var(--text-1); font-variant-numeric: tabular-nums; }
.pf-account-main { flex: 1; min-width: 0; }
.pf-name { display: flex; align-items: center; font-size: var(--fs-h2); font-weight: 600; color: var(--text-1); line-height: 1.3; }
.pf-name .role-badge { flex: none; }
.pf-sub {
  margin-top: 3px; display: flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap;
  font-size: var(--fs-caption); color: var(--text-4);
}

/* 图标片：与个人中心 .pfg-ico 同一语言——无底色纯描线（去灰底瓦片）；色＝1011 行首统一档 */
.pf-ico {
  width: 22px; height: 22px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--text-2);
}
.pf-ico svg { width: 22px; height: 22px; }
.pf-ico-sm { width: 22px; height: 22px; }
.pf-ico-sm svg { width: 22px; height: 22px; }

/* 1030 清死样式：原「我的概览 KPI 卡」一族（.dc-card .kpi-grid / .pf-kpi-card /
   .pf-kpi-card .pf-ico / .summary-card.pf-kpi-card:active / .pf-kpi-main 及其下三个 .summary-*）
   全部依赖已退役的 pfKpiCard()（本轮作为死函数删除），运行件里 0 命中。
   共用的 .pf-ico 基样式在别处，不在这段里，未受影响。 */

/* 数据统计 / 数据管理：行式列表 */
.pf-list { border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; background: var(--bg-card); }
.pf-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-3); }
.pf-row + .pf-row { border-top: 1px solid var(--border); }
.pf-k { flex: 1; min-width: 0; font-size: var(--fs-caption); color: var(--text-2); }
.pf-v { flex: none; font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--fs-caption); color: var(--text-1); }
.pf-row.is-danger .pf-v, .pf-row.is-danger .pf-ico { color: var(--tag-bad-fg); }

/* 回收站数量角标 */
.pf-chip {
  flex: none; min-width: 20px; padding: 1px var(--sp-2);
  border-radius: var(--radius-pill); background: var(--bg-muted);
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--fs-micro); color: var(--text-2); text-align: center;
}

.pf-list .field-hint { padding: var(--sp-2) var(--sp-3) var(--sp-2); }

/* 偏好开关（行内 switch） */
.pf-switch { position: relative; flex: none; width: 38px; height: 22px; display: inline-block; }
.pf-switch input {
  position: absolute; inset: 0; width: 100%; height: 100%;
  margin: 0; opacity: 0; cursor: pointer; z-index: 1;
}
.pf-track {
  position: absolute; inset: 0; pointer-events: none;
  background: var(--switch-track); border-radius: var(--radius-pill);
  transition: background var(--transition-fast);
}
.pf-track::after {
  content: ''; position: absolute; top: 2px; left: 2px;
  width: 18px; height: 18px; border-radius: var(--r-circle); background: var(--white); /* 开关旋钮恒白（iOS 语言，明暗两档不翻） */
  box-shadow: 0 1px 2px rgba(0, 0, 0, .15);
  transition: transform var(--transition-fast);
}
.pf-switch input:checked + .pf-track { background: var(--primary); }
.pf-switch input:checked + .pf-track::after { transform: translateX(16px); }
/* 暗档开态：--primary 暗档翻成近白 #E8E9EC，与恒白旋钮撞成一片、看不出开没开（1026 实拍）。
   改用 token 里现成的 --primary / --on-primary 黑白反转对——近白轨道落近黑旋钮，和亮档「墨轨白钮」
   是同一条 iOS 语言，无彩色、不破墨灰调性。关态深灰轨+白钮两档本可辨，不动。 */
[data-theme="dark"] .pf-switch input:checked + .pf-track::after { background: var(--on-primary); }
.pf-switch input:focus-visible + .pf-track { outline: 2px solid var(--border-strong); outline-offset: 2px; }
/* 无权拨动的开关（「每句都走 AI」对无权账号）：本体压暗 + 不给手指响应 */
.pf-switch input:disabled + .pf-track { opacity: .45; cursor: default; }

/* ============================================================
   个人中心「灰标题 + 白卡 + 单行」分组（参考图新样式）
   样板：数据管理。桌面/移动共用，靠 token 随断点自适应。
   结构：卡片外灰色小标题（无图标）→ 白卡 → 单行「图标+名称+箭头/角标」，无描述。
   ============================================================ */
.pfg { margin-top: var(--pfg-gap); }
.pfg:first-child { margin-top: 0; }
/* 显形开关直接挂在 .pfg 上（见 :root Settings stack 的规矩）；点名防未来谁给它添 display */
.pfg[hidden] { display: none; }
/* 组还没内容（如余额组等 status 回包）时不占位，避免回包瞬间页面往下跳 */
.pfg:empty { display: none; }
.pfg-label {
  margin: 0 0 var(--pfg-label-gap) var(--sp-1);
  font-size: var(--fs-label);
  font-weight: 500;
  color: var(--text-4);
  letter-spacing: .01em;
}
.pfg-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.pfg-row {
  display: flex; align-items: center;
  /* 图标列宽与行内间距各立一枚局部令牌：凡是要「与标题文字起线对齐」的整块控件，
     一律引 calc(这两枚之和)，不再各写一遍 magic number
     （1003 站主点名：通栏分段器从卡片内距一路铺到右缘，比标题整整左凸一截）。
     写在行上而不是 :root，是因为这两枚就是这一行的几何——改了它们，对齐自动跟着走。 */
  --pfg-ico-w: 22px;
  --pfg-row-gap: 12px;
  gap: var(--pfg-row-gap);
  width: 100%; text-align: left; font: inherit; color: inherit;
  background: none; border: 0; cursor: pointer;
  padding: 0 var(--card-pad);
  min-height: var(--pfg-row-h);
  transition: background var(--transition-fast);
}
.pfg-row + .pfg-row { border-top: 1px solid var(--border); }
@media (hover: hover) { .pfg-row:hover { background: var(--bg-hover); } }
.pfg-row:active { background: var(--bg-hover); }
.pfg-ico {
  /* 兜底 22px：这枚令牌挂在 .pfg-row 上，卡外单独用到 .pfg-ico 的地方拿不到它 */
  flex: none; width: var(--pfg-ico-w, 22px); height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--text-2); /* 1011 行首统一档（同 .fg-i/.dd-ico，站主判 text-4 太灰后压深） */
}
.pfg-ico svg { width: 22px; height: 22px; }
.pfg-t { flex: 1; min-width: 0; font-size: var(--fs-body); color: var(--text-1); }
/* 两行字档（标题 + 小字说明）：讲得清这一行的说明就地收进标题列，
   不单开 .pfg-note——飘成独立一行会把白卡切成「行/注/行/注」的零碎节奏。
   0928 桌面小部件页先立这套（当时叫 .ws-t），0929 提醒与震动页并入时统一成 pfg 家族、
   由 app.js 的 pfTitleHtml(title, sub) 一处产出，两页共用一份样式。 */
.pfg-t.pfg-t-2 { display: flex; flex-direction: column; gap: 2px; }
/* 1018 带说明的两行字行（图1 规范）：图标与右侧控件都**对齐标题那一行**，不再整块垂直居中——
   说明一长（折两行）时开关悬在大段字中间就是截图点名的那种「乱」。改 flex-start 后：
   行上下各补 sp-2 内距，图标/开关 22px 与标题首行（≈22px）顶边同起，中心线天然对齐。
   nt-page 本来就有同款 padding 覆盖（见后文），这里统一成全站默认。 */
.pfg-row:has(> .pfg-t-2) { align-items: flex-start; padding-top: var(--sp-2); padding-bottom: var(--sp-2); }
/* 「底部上下滑换向」行：swap 图标是横向双箭头，这行讲的是上下对调——转 90° 竖过来，
   图标方向与它管的手势同向（站主 1018 点名）。挂 :has(#pf-dock-vswap)，不动共用构造器。 */
.pfg-row:has(#pf-dock-vswap) .pfg-ico svg { transform: rotate(90deg); }
/* 两行各自把 line-height 写死：说明行本来就有，标题行这里补上——
   没有确定行高，排版量具就没法判「标题被挤成两字竖排」这类回归（只能量出「大概几行」）。
   1018 层级照站内参照档（新增事件页 swRow 的「每年重复 / 过农历」那套，05-views 3618/3619）：
   主标题 16px·medium·text-1，说明 12px（--fs-12）·text-4·1.5——与那页逐字同档，不另立标准。 */
.pfg-t-2 .pfg-t-main { line-height: 1.45; font-size: calc(16px * var(--fs-scale)); font-weight: var(--fw-medium); }
.pfg-t-sub {
  font-size: var(--fs-12); color: var(--text-4); line-height: 1.5; margin-top: var(--sp-1);
  /* 说明折成两行时把两行拉齐：不处理的话常见「第二行只剩一两个字」的孤尾，
     一整页行行如此，读起来就是「哪儿没对齐」（0929 实拍）。balance 只重排行、不改内容 */
  text-wrap: balance;
}
.pfg-chev { flex: none; width: 18px; height: 18px; color: var(--text-disabled); }
.pfg-chev svg { width: 18px; height: 18px; }
/* 控制行（开关 / 分段）：整行不可点，取消悬停/按压高亮与指针 */
.pfg-ctl { cursor: default; }
.pfg-ctl:hover, .pfg-ctl:active { background: transparent; }
/* 行被禁用（无权拨「每句都走 AI」）：只压标题一档，说明行保持原可读性——
   压成整行灰字会把「为什么不能开」那句理由也一起埋掉 */
.pfg-row.is-off .pfg-t-main { color: var(--text-3); }
/* ===================== 桌面小部件 · 预览画廊 =====================
   「添加到桌面」这一组：整卡即「添加」按钮，卡面是那只小部件的等比缩微。
   皮肤全部走站内 token——白卡 = --bg-card、强调 = --text-1、发丝线 = --border，
   深色模式下自动反转，不引入渐变与第二套色板。 */
.ws-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4) var(--sp-3); }
.ws-span2 { grid-column: 1 / -1; }
.ws-card {
  display: flex; flex-direction: column; align-items: stretch;
  width: 100%; padding: 0; border: 0; background: none;
  text-align: left; font: inherit; color: inherit; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
/* 展台等高：两列里一高一矮的卡会把题注推到不同基线上（真机目检的「乱」）。
   题注因此永远从同一高度起排，缩微自己在展台里居中。 */
.ws-stage {
  display: flex; align-items: center; justify-content: center;
  height: 148px; flex: none;
}
/* 缩微按**真实长宽比**画（0928 那版按感觉给尺寸，2×1 成了药丸、2×2 偏小）：
   一格行高 = 展台一半 → 2 行的卡（4×2、2×2）铺满展台，1 行的卡（2×1）占一半；
   宽度上 4×2 跨两列＝四格，2×2 与 2×1 同占一列＝两格。
   于是 4×2≈2.6:1、2×2≈1.25:1、2×1≈2.5:1，与真机上量到的一致。 */
.ws-mock.ws-mock-42 { width: 100%; height: 100%; display: flex; flex-direction: column; }
.ws-mock.ws-mock-22 { width: 100%; height: 100%; }
.ws-mock.ws-mock-21 { width: 100%; height: 74px; display: flex; align-items: center; gap: var(--sp-1); }
/* 题注两行：第一行「名字 + 添加」各自不折行（名字超长省略），第二行小字说明。
   「添加」只写文字、不带加号——2×1 的缩微里已经有一颗黑「＋」，两个加号会打架。 */
.ws-cap { display: flex; flex-direction: column; gap: 2px; margin-top: var(--sp-3); padding: 0 1px; }
.ws-cap-line { display: flex; align-items: baseline; gap: var(--sp-2); }
.ws-cap-t {
  flex: 1; min-width: 0; font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--text-1);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ws-cap-a { flex: none; font-size: var(--fs-label); color: var(--text-3); white-space: nowrap; }
/* 合并分组后卡内的小标题：比段落标题轻一档、比说明文字重一档 */
.ws-sub {
  padding: var(--sp-3) var(--card-pad) var(--sp-1);
  font-size: var(--fs-label); font-weight: var(--fw-medium);
  color: var(--text-3); letter-spacing: .01em;
}
.ws-sub:not(:first-child) { border-top: 1px solid var(--border); }
/* 页尾孤行说明：不进卡，直接坐在灰底上收掉，省一整组「说明」 */
.ws-legal { padding: var(--sp-4) var(--sp-2) var(--sp-1); font-size: var(--fs-label); color: var(--text-4); line-height: 1.6; }
.ws-card:active .ws-mock { transform: scale(.985); border-color: var(--text-3); }
.ws-card:active .ws-cap-a { color: var(--text-1); }
.ws-mock {
  display: block; box-sizing: border-box; flex: none;
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: var(--sp-3); overflow: hidden;
  transition: transform var(--transition-fast), border-color var(--transition-fast);
}
.ws-mk-head { display: flex; align-items: center; gap: var(--sp-1); }
.ws-mk-head b { font-size: calc(12px * var(--fs-scale)); font-weight: var(--fw-medium); color: var(--text-1); }
.ws-mk-head i {
  flex: 1; min-width: 0; font-size: calc(10px * var(--fs-scale)); font-style: normal; color: var(--text-4);
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.ws-mk-head s {
  flex: none; font-size: calc(10px * var(--fs-scale)); line-height: 1; text-decoration: none;
  color: var(--bg-card); background: var(--text-1); border-radius: var(--r-pill); padding: var(--sp-1);
}
.ws-mk-row { display: flex; align-items: center; gap: var(--sp-1); margin-top: var(--sp-3); }
.ws-mk-row u {
  flex: none; width: 6px; height: 6px; border-radius: var(--r-circle);
  border: 1px solid var(--text-disabled); background: none;
}
.ws-mk-row u.on, .ws-mk-row u.bad { background: var(--text-1); border-color: var(--text-1); }
.ws-mk-row em {
  flex: 1; min-width: 0; font-size: calc(11px * var(--fs-scale)); font-style: normal; color: var(--text-1);
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.ws-mk-row i { flex: none; font-size: calc(10px * var(--fs-scale)); font-style: normal; color: var(--text-4); }
.ws-mk-row i.bad { color: var(--text-1); font-weight: var(--fw-medium); }
/* 4×2 缩微改双栏（与真卡同一版式）：左待办带勾选圆、右习惯竖列、中间发丝竖线 */
.ws-mk-cols { display: flex; flex: 1; min-height: 0; margin-top: var(--sp-1); }
.ws-mk-col { display: flex; flex-direction: column; min-width: 0; }
.ws-mk-col-l { flex: 1.55; }
.ws-mk-vdiv { width: 1px; background: var(--border); margin: 1px var(--sp-2); flex: none; }
.ws-mk-round {
  flex: none; width: 20px; height: 20px; border-radius: var(--r-pill); padding: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: calc(13px * var(--fs-scale)); line-height: 1; text-decoration: none;
  color: var(--bg-card); background: var(--text-1);
}
.ws-mk-cb {
  flex: none; width: 15px; height: 15px; border-radius: var(--r-circle);
  border: 1.5px solid var(--text-disabled); background: none;
}
.ws-mk-hb { flex: 1; display: flex; align-items: center; gap: var(--sp-1); min-height: 22px }
.ws-mk-hb u {
  flex: none; width: 6px; height: 6px; border-radius: var(--r-circle);
  border: 1.5px solid var(--text-disabled); background: none;
}
.ws-mk-hb u.on { background: var(--text-1); border-color: var(--text-1) }
.ws-mk-hb em {
  min-width: 0; font-size: calc(10px * var(--fs-scale)); font-style: normal; color: var(--text-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ws-mk-hb b { margin-left: auto; font-family: var(--font-mono); font-size: calc(9px * var(--fs-scale)); font-weight: 400; color: var(--text-4) }
/* 2×1 缩微：单行（圆点=今日状态、名字、大号次数、黑圆「＋」），与真卡同一版式 */
.ws-mk-d {
  flex: none; width: 6px; height: 6px; border-radius: var(--r-circle);
  border: 1px solid var(--text-disabled);
}
.ws-mk-d.on { background: var(--text-1); border-color: var(--text-1); }
.ws-mk-name {
  flex: 1; min-width: 0; font-size: calc(12px * var(--fs-scale)); font-weight: var(--fw-medium); color: var(--text-1);
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.ws-mk-n { display: flex; align-items: baseline; gap: 1px; flex: none; }
.ws-mk-n b { font-size: calc(24px * var(--fs-scale)); line-height: 1; font-weight: var(--fw-semibold); color: var(--text-1); }
.ws-mk-n i { font-size: calc(10px * var(--fs-scale)); font-style: normal; color: var(--text-4); }
.ws-mk-plus {
  flex: none; width: 28px; height: 28px; border-radius: var(--r-circle);
  display: flex; align-items: center; justify-content: center;
  font-size: calc(15px * var(--fs-scale)); line-height: 1; color: var(--bg-card); background: var(--text-1);
}
/* ≤768 手机端样式 → 06-mobile.css */
/* ===================== 桌面小部件 · 预览画廊 结束 ===================== */

/* 卡内辅助说明行（如桌面提醒权限提示）
   说明行讲的是**它上面那一行**，所以线画在下面：紧贴上一行（4px 归组）、
   与下一行之间由线分开（0927 真机：线画在说明行上方时，说明文字像被下一行顶上来，
   整页看着「都紧贴下边线」）。 */
.pfg-note {
  padding: var(--sp-1) var(--card-pad) var(--sp-3);
  font-size: var(--fs-label); color: var(--text-4); line-height: 1.6;
}
.pfg-note + .pfg-row, .pfg-note + .pfg-ctl, .pfg-note + .pfg-note { border-top: 1px solid var(--border); }
.pfg-note:last-child { padding-bottom: var(--sp-4); }
/* 只读值（如「本机存储」）：右对齐等宽数字，与 .nt-time 同款语言——
   不加边框底色，避免一行里出现两个看起来可点的控件 */
.pfg-val {
  flex: none; min-width: 60px; text-align: right;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--fs-caption); color: var(--text-2);
}
/* 存储说明行：App 内要分行报「上次写入 / 开机读取」实况，允许软换行成多行 */
.pfg-note-store { white-space: pre-line; }
.pfg-note.is-warn { color: var(--tag-bad-fg); }
/* 一行两行字：标题 + 小字说明用的是 pfg 家族的 .pfg-t-2（见上文 pfg 章节），
   两页共用一份样式，这里只留小部件页特有的东西 */
.ws-row .pf-seg { flex: none; }
/* 分组留白：这两页（桌面小部件 / 提醒与震动）分组多、又都是「标题 + 一两张卡」，
   标签与卡之间要能喘气 —— 页面级前缀把通用节奏抬到 26px / 10px */
.ws-page .pfg, .nt-page .pfg, #view-settings .pfg { margin-top: var(--pfg-gap-page); }
.ws-page .pfg:first-child, .nt-page .pfg:first-child, #view-settings .pfg:first-child { margin-top: 0; }
.ws-page .pfg-label, .nt-page .pfg-label, #view-settings .pfg-label { margin-bottom: var(--pfg-label-gap); }
/* 设置页（dock 第三席 · 1010 dock 三席收编）：整页节奏就借上面这三条，
   不另起规则块——块语言整只复用 pfg（灰标题 + 白卡行），tip 间距吃基础款同值。 */
/* 卡里第一行就是说明文字时（空态、排错提示），4px 顶距会让文字贴住卡的上沿。
   必须连「嵌一层的容器」一起管：实例列表装在 #ws-instances 这类 div 里，
   只写 `.pfg-card > .pfg-note:first-child` 会漏掉它们（真机目检：那几行顶距还是窄）。 */
.pfg-card > .pfg-note:first-child,
.pfg-card > div > .pfg-note:first-child { padding-top: var(--sp-3); }
/* 同理收口底部：容器里最后一条说明与卡下沿留 15px，不靠 .pfg-note:last-child 的巧合 */
.pfg-card > div > .pfg-note:last-child { padding-bottom: var(--sp-4); }
/* 一段＝标题行 + 通栏分段器：手机端四枚胶囊塞不进标题行右侧，分段器独占一行 */
.ws-item { border-bottom: 1px solid var(--border); }
.ws-item:last-child { border-bottom: 0; }
.ws-item .pfg-row { min-height: 46px; padding-bottom: var(--sp-1); }
/* 分段器独占一行。必须是 flex 容器：站内的 .pf-seg-fill 靠 `flex:1 1 100%` 撑开、
   并用 margin-left 把左缘对齐到标题（图标列宽），放在普通块里这两条都会落空、
   分段器缩成一小坨（1003 实测）。 */
.ws-segline { display: flex; padding: 0 var(--card-pad) var(--sp-3); }
/* 危险分组：分组标题与行文字/图标转红 */
.pfg.is-danger .pfg-label { color: var(--tag-bad-fg); }
.pfg-row.is-danger .pfg-t, .pfg-row.is-danger .pfg-ico { color: var(--tag-bad-fg); }
/* 个人中心灰底画布：账户卡改白底，与分组卡一致浮起。
   登录态账户卡是 .pf-idcard 容器（内含 border-radius:0 的透明 .pf-account），只给容器刷白即可；
   本地态是挂在 body 下的独立 .pf-account，才需要单独刷白。
   切勿写成裸 `.pf-account` 类——那会盖掉登录态嵌套账户的透明基线、把它刷成方块而吃掉容器上圆角。 */
.dc-card.dd-modal .pf-idcard { background: var(--bg-card); }
.dc-card.dd-modal .modal-body > .pf-account { background: var(--bg-card); }
/* 移动端：头部是半透明「页面灰」，与账户卡顶部几乎无间隙会让圆角被误看成直角；
   给个人中心顶部多留一段灰色沟槽，账户卡上圆角才浮得出来 */
/* ≤768 手机端样式 → 06-mobile.css */
/* 重置按钮：桌面只显示文字（图标隐藏），移动端媒体查询内切换为仅图标 */
.dc-reset-btn .dc-reset-ico { display: none; }

/* ---- pfg 家族扩展：AI 快速录入等设置页（与「提醒与震动自检」同族语言） ---- */
/* 卡内无边框输入行：行高吃堆叠令牌（与 .pfg-row 同一档），等宽字体承 Key */
.pfg-in {
  flex: 1; min-width: 0; width: 100%; height: var(--pfg-row-h); box-sizing: border-box;
  border: none; background: transparent; outline: none;
  font-family: var(--font-mono); font-size: calc(16px * var(--fs-scale)); color: var(--text-1); padding: 0;
}
.pfg-in::placeholder { font-family: var(--font-sans); color: var(--text-hint); }
/* 卡外灰说明（对齐 .pfg-label 的起行位置） */
.pfg-tip { margin: var(--pfg-tip-gap) var(--sp-1) 0; font-size: var(--fs-label); color: var(--text-4); line-height: 1.6; }

/* ============================================================
   AI 快速录入 · 连接卡（0929 立版式，1010 换品牌面）
   一页只允许一处彩色，就是「连没连上」这件事：
   已连接=绿 / 未连接=静灰 / 问不到服务器=红。三态共用同一份版式，
   只换 data-state 上的那一个令牌（--ai-accent，状态点与它的光晕吃它），
   所以状态切换是原地变色，不会跳版式、也不会各写一套颜色规则。
   左侧那块底板不再是「会随状态变色的闪电标」，而是品牌 K 字底板
   （与侧栏 / 登录页的 .logo-icon 同色同档，永远黑底白字，暗色反转）；
   闪电收进状态点，颜色跟着状态走——品牌归品牌、状态归状态，两处不再抢活。
   卡本体仍是站内白卡（.pfg-card 外壳照用），底部那条浅灰带是「设备铭牌」，
   承 deepseek 这只等宽型号——AI 气质靠这一处等宽 + 一处绿，不靠渐变。
   ============================================================ */
.ai-conn {
  --ai-accent:   var(--text-4);
}
.ai-conn[data-state="on"] {
  --ai-accent:   var(--status-good);
}
.ai-conn[data-state="err"] {
  --ai-accent:   var(--status-bad);
}
.ai-conn-main {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4) var(--card-pad);
}
/* 品牌底板：照 .logo-icon 那份锁定（黑底 #000 / 字形 #F4F4F4，暗色反过来），字形占板 75%。
   别图省事给这只 span 叠 .logo-icon 类——05 在 02 之后加载、同特异度后者胜，
   两处 background 与 svg 尺寸会打架（站内「同元素双类升级」那条教训）。 */
.ai-mark {
  flex: none; width: 36px; height: 36px; border-radius: var(--r-1);
  display: inline-flex; align-items: center; justify-content: center;
  background-color: var(--brand-plate); color: var(--brand-plate-ink);
}
/* 暗档反转已由 --brand-plate/--brand-plate-ink 令牌完成，此处原手写 dark 行删除（1025） */
.ai-mark svg { width: auto; height: 27px; display: block; }
.ai-conn-id { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
/* 品牌大字：字距收紧到 -0.02em，松了就没有「一台设备」的那种整块感。
   1013 收到 18 档——右上角多了余额小签之后，21 的品牌字与它并排会抢成一排 */
.ai-name {
  font-size: calc(18px * var(--fs-scale)); font-weight: var(--fw-semibold); line-height: 1.15;
  letter-spacing: -.022em; color: var(--text-1);
}
.ai-state {
  display: flex; align-items: center; gap: var(--sp-2); min-width: 0;
  font-size: var(--fs-caption); color: var(--text-4); line-height: 1.3;
}
.ai-state-word { flex: none; font-weight: var(--fw-medium); color: var(--text-2); }
.ai-state-sep { flex: none; color: var(--text-disabled); }
/* 诊断小字（「问不到服务器」「仅本地规则」）留一条地板宽：卡角上多了余额小签之后，
   谁该让位要说清楚——**小签让，诊断不让**（2.37 首版反过来，实拍把「问不到服务器」
   挤得只剩一个「问」字）。88px 是这六字在 --fs-caption 下的实际占宽（量到 86）。
   ⚠ 必须挂 :not(:empty)——连上时 sub 是空串，给它留 88px 等于凭空占掉半行，
   反而把右边小签挤出卡外。 */
.ai-state-sub { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.ai-state-sub:not(:empty) { min-width: calc(88px * var(--fs-scale)); }
/* 状态点（1010）：7px 圆点换成带光晕的圆角小方块，方块里站着那枚闪电。
   只有连上那一态才呼吸——没连上就别装作在动。
   光晕走 ::after 且 z-index:-1 垫到底板背后，只能从四边溢出来；
   不这么做的话放大那一层同色绿会盖住闪电，闪一下就变成「图标没了」。
   底板要有自己的堆叠上下文（position:relative + z-index:0），负层级才出得去它。 */
.ai-dot {
  position: relative; z-index: 0; flex: none;
  width: 15px; height: 15px; border-radius: var(--r-2);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--ai-accent); color: var(--white);
  transition: background var(--d-enter) var(--ease-float);
}
.ai-dot svg { width: 9px; height: 9px; fill: currentColor; }
.ai-conn[data-state="on"] .ai-dot::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  border-radius: var(--r-2); background: var(--status-good);
  animation: aiPulse 2.4s var(--ease-float) infinite;
}
/* 15px 底板（1013 收小一档）放大到 1.9 倍 ≈ 28px，正落在状态行的行高里；
   沿用旧圆点那个 2.6 会从「一圈光」变成糊到「已连接」字底下的一片绿 */
@keyframes aiPulse {
  0%   { transform: scale(1);   opacity: .5; }
  70%  { transform: scale(1.9); opacity: 0; }
  100% { transform: scale(1.9); opacity: 0; }
}
/* 铭牌条：通栏浅灰带，卡壳 overflow 已经把两端圆角裁好，这里不再补圆角 */
.ai-conn-foot {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-2) var(--card-pad);
  border-top: 1px solid var(--border); background: var(--bg-soft);
  font-size: var(--fs-label); color: var(--text-4); line-height: 1.4;
}
.ai-model {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  color: var(--text-3); letter-spacing: .01em;
}
/* 余额小签（1013 站主点名）：从下面那张「只放一个数」的整行卡收上来，挂在连接卡右上角。
   字档退在读数以下（--fs-label 标签 + --fs-caption 等宽数字）、颜色只到 --text-2，
   不跟品牌标抢视线；负外距把热区撑回 38 档（站内触控下限），版面高度一点没动。
   ⚠ 宽度必须是**绝对上限**而不是百分比（2.37 首版写 46% 被实拍打回）：读不到余额时
   nlBalText 回的是「登录已过期，请重新登录」这类整句诊断，百分比会跟着行宽一起涨，
   把左边「连接失败 · 问不到服务器」那行挤得只剩一个字。132px 是量好的：
   「余额 ¥9.91 ↻」正好一行读完，长诊断自己省略号，标题列永远拿得到剩下的。
   按下反馈与那枚刷新图标并进下面 .nl-bal 的选择器里（拆开写会撞棘轮的逐字重复组）。
   失败时 nlBalPaint 给数值挂 is-bad：降成小灰字，同时把「余额」二字让位——
   「余额 未配置 Key」在这个宽度里读不通，去掉标签反而一眼懂。 */
.ai-bal {
  flex: none; max-width: 132px; display: inline-flex; align-items: center; gap: var(--sp-1);
  box-sizing: border-box; margin: -11px -8px -11px 0; padding: var(--sp-3) var(--sp-2);
  appearance: none; -webkit-appearance: none; border: 0; border-radius: var(--r-2);
  background: transparent; font-family: inherit; cursor: pointer;
  transition: background var(--transition-fast);
}
.ai-bal-k { flex: none; font-size: var(--fs-label); color: var(--text-4); }
/* 数值的地板在 62px：够「¥9.91」整串站直（实测 43px），长串（含赠送后缀、整句诊断）
   自己省略号——让位的是小签，不是左边那行状态诊断（见上面 .ai-state-sub 那条）。 */
.ai-bal-v {
  flex: 0 1 auto; min-width: 0; max-width: 62px;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--fs-caption); color: var(--text-2);
}
.ai-bal-v.is-bad { font-size: var(--fs-label); font-weight: 400; color: var(--text-4); }
.ai-bal:has(.ai-bal-v.is-bad) .ai-bal-k { display: none; }
/* 读不到余额时那半句诊断再收一档：这一档左边那行「连接失败 · 问不到服务器」已经把
   病因说完了，右边再挤一整句进去是复读，还会把左边顶穿（dead 档实拍量出来的）。
   全文留在 title 里，点它一下重问也照旧。 */
.ai-bal:has(.ai-bal-v.is-bad) .ai-bal-v { max-width: 40px; }
/* Key 行：sk- 前缀是形状提示，不参与输入，也不许被一起复制走 */
.ai-key-pre {
  flex: none; font-family: var(--font-mono); font-size: calc(16px * var(--fs-scale)); color: var(--text-disabled);
  user-select: none; -webkit-user-select: none;
  transition: color var(--transition-fast);
}
.ai-keyrow:focus-within .ai-key-pre { color: var(--text-3); }
/* 聚焦时只把卡描深一档，不给输入框描红、不刷主色（站内校验语言：控件本身不描边） */
.pfg-card:has(.ai-keyrow:focus-within) { border-color: var(--border-strong); }
@media (prefers-reduced-motion: reduce) {
  .ai-conn[data-state="on"] .ai-dot::after { animation: none; }
}
/* 窄屏（≤360）大字先退一档，别让「可序Ai」把状态行挤成两行；底板跟着收到品牌标准 32 */
/* ≤768 手机端样式 → 06-mobile.css「窄屏（≤360）大字先退一档，别让「可序Ai」把状态行挤成两行；底板跟着收到品牌标准 32」 */

/* ============================================================
   登录进行中的反馈（App「登录云端同步」页）
   站内此前没有任何加载态——点下登录到页面重载之间是一片死寂，
   网络一慢就像「没反应」。这里补一套克制的最小语言：
   · .wbf-stage：卡下灰字状态行，文案随阶段走（正在登录 → 正在同步云端）；
   · .wbf-spin：发丝弧（1.8 描边、轨道 22% 透明），与站内图标同一字重；
   · .modal-head-act.is-busy：头部白圆钮原地换成转弧（同幅 20px，一排钮不跳位）。
   动效只有一条旋转，交给全局 prefers-reduced-motion 归零即可（文案仍在说进度）。
   ============================================================ */
@keyframes wbfSpin { to { transform: rotate(360deg); } }
@keyframes wbfStageIn { from { opacity: 0; transform: translateY(-3px); } to { opacity: 1; transform: none; } }
.wbf-spin { display: inline-flex; width: 16px; height: 16px; flex: none; color: var(--text-2); }
.wbf-spin svg { width: 16px; height: 16px; animation: wbfSpin .72s linear infinite; }
.wbf-stage {
  display: flex; align-items: center; gap: var(--sp-2);
  margin: var(--sp-3) var(--sp-1) 0; font-size: var(--fs-label); color: var(--text-3);
  animation: wbfStageIn var(--d-fast) var(--ease-float);
}
.wbf-stage[hidden] { display: none; } /* 自带 display:flex 会压掉 UA 的 hidden，必须点名 */
.modal-head-act .mha-spin { display: none; }
.modal-head-act.is-busy { pointer-events: none; } /* 连点不重复发请求 */
.modal-head-act.is-busy > svg { display: none; }
.modal-head-act.is-busy .mha-spin { display: inline-flex; }
.modal-head-act.is-busy .mha-spin svg { width: 20px; height: 20px; }
.pfg-in:disabled, .form-input:disabled { opacity: .55; }
/* 不可逆操作降红字行（与详情「删除」同档，不做通栏大按钮）。
   1002 起收进所在的白卡里：发丝线隔开输入行，红字不再孤零零飘在卡外
   （.pfg-clear 裸排版随 0929 版一起退役，全站已无调用点） */
.pfg-clear-in {
  display: block; width: 100%; min-height: 44px; box-sizing: border-box;
  border: none; border-top: 1px solid var(--border); background: transparent; cursor: pointer;
  color: var(--tag-bad-fg); font-size: calc(15px * var(--fs-scale)); text-align: center;
}
.pfg-clear-in:active { opacity: .55; }

/* ---- 一句话录入：实时解析预览（小黑标胶囊 + 正文，去 emoji） ----
   0923 曾改成「落点胶囊条 + 18px 结果正文 + 卡内定高 AI 行」，真机目检后用户否掉：
   悬浮胶囊要保留、布局不如原来。骨架已还原，只留「输入井随内容长高」这一处不改版面的改进。 */
/* 特异性对齐 textarea.form-input (0,1,1)，桌面端也压得住默认 vertical */
textarea.form-input.nl-ta { resize: none; min-height: 96px; }
.nl-pvbox { padding: 0 var(--card-pad); }
.nl-pvbox:empty { display: none; }
.nl-pv {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) 0; border-top: 1px solid var(--border);
  font-size: var(--fs-caption); color: var(--text-2);
}
.nl-pv-tag {
  flex: none; background: var(--primary); color: var(--on-primary);
  border-radius: var(--radius-pill); padding: 3px var(--sp-2);
  font-size: var(--fs-label); font-weight: var(--fw-medium);
}
.nl-pv-txt { min-width: 0; }
/* 日期 + 钟点是一个整体，窄屏要整段换行，不能在连字符处被劈开 */
.nl-nw { white-space: nowrap; }
.nl-pv b { color: var(--text-1); font-weight: var(--fw-medium); }
/* 多条结果列表（0924）：一句拆出多条时逐行列出，点哪行单独改哪条。
   行本身是 button：热区 ≥44px、按下只给背景衬底（文字不挂 :active 透明度，那读作闪烁）；
   可点性靠下面那行提示语交代，不在行内加可见的「改」钮（用户偏好：宁要不可见手势）。 */
.nl-pv-list { border-top: 1px solid var(--border); }
.nl-pv-row {
  display: flex; align-items: center; gap: var(--sp-2); width: 100%; min-height: 44px;
  padding: var(--sp-2) var(--sp-1); margin: 0 -6px; border: 0; border-radius: var(--r-2);
  background: transparent; cursor: pointer; text-align: left; font: inherit;
  font-size: var(--fs-caption); color: var(--text-2);
  transition: background var(--transition-fast);
}
.nl-pv-row:active { background: var(--bg-muted); }
.nl-pv-row-t { min-width: 0; }
.nl-pv-row-t b { color: var(--text-1); font-weight: var(--fw-medium); }
@media (prefers-reduced-motion: reduce) { .nl-pv-row { transition: none; } }
/* 桌面弹窗底栏本来就有「取消 / 编辑 / 应用」三颗，弹窗态收起悬浮动作胶囊免得重复出口。
   但 .nl-sheet（手机底部抽屉）没有底栏，宽屏下也不能收 —— 收了就只剩回车一条路。

.nl-pv-hint { padding: 0 0 11px; font-size: var(--fs-label); color: var(--text-4); line-height: 1.6; }
.nl-pv-ai { padding: 8px 0 12px; font-size: var(--fs-label); color: var(--text-4); }

/* ---------- API 余额行（0925；0930 起两种底：裸排 / 卡内）----------
   裸排（桌面录入弹窗，与 .nl-pvbox 同一份横向内距），不挤动 0923 定稿的抽屉版面；
   卡内（Klog 设置 / AI 快速录入，inCard）：白卡承着，负外距全部归零，
   行高对齐 pfg-row 的 52 档。左灰标签 + 右数值 + 刷新图标，整行可点，
   反馈只给一层背景色；失败只降成小灰字，不描红、不 toast。 */
.nl-balbox { padding: 0 var(--card-pad); margin-top: var(--sp-1); }
.nl-bal {
  display: flex; align-items: center; gap: var(--sp-2);
  /* 负外边距把热区撑回整行宽，内距再用同一份 card-pad 把文字收回原位 */
  box-sizing: border-box; width: calc(100% + var(--card-pad) * 2);
  margin: 0 calc(-1 * var(--card-pad)); padding: var(--sp-3) var(--card-pad); min-height: 44px;
  appearance: none; -webkit-appearance: none; border: 0; border-radius: 0;
  background: transparent; color: var(--text-2); font-family: inherit; text-align: left;
  cursor: pointer; transition: background var(--transition-fast);
}
/* 卡内版：卡壳给边框圆角和底色，行自己只留内距与高度；行高与 pfg 行同档 */
.nl-bal.nl-bal-card {
  width: 100%; margin: 0; padding: 0 var(--card-pad); min-height: var(--pfg-row-h);
}
@media (hover: hover) { .nl-bal:hover { background: var(--bg-hover); } }
/* 按下往「页面文字色」方向压一点：暗色主题里 --bg-soft 比 --bg-hover 更暗，
   直接用它两套主题的下压方向会反过来。连接卡角上那枚小签（.ai-bal）共用这一份反馈 */
.nl-bal:active, .ai-bal:active { background: color-mix(in srgb, var(--bg-hover) 82%, var(--text-1)); }
.nl-bal-k { flex: none; font-size: var(--fs-caption); color: var(--text-4); }
.nl-bal-v {
  flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  /* 数值右靠，与白卡里「左标签 / 右控件」同一读法；中间那段空白由弹性撑出来 */
  text-align: right;
  font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.nl-bal-v.is-bad { font-size: var(--fs-caption); font-weight: 400; color: var(--text-4); }
/* 刷新那枚图标与转法两种壳共用（连接卡角上的 .ai-bal 是 1013 那份小签） */
.nl-bal-i, .ai-bal-i { flex: none; display: inline-flex; line-height: 0; color: var(--text-4); }
.nl-bal-i svg, .ai-bal-i svg { width: 15px; height: 15px; }
.nl-bal.is-busy .nl-bal-i, .ai-bal.is-busy .ai-bal-i { animation: nlBalSpin .9s linear infinite; }
@keyframes nlBalSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .nl-bal.is-busy .nl-bal-i, .ai-bal.is-busy .ai-bal-i { animation: none; } }

/* ---------- 一句话修改（0923）：撤销 toast 与候选抽屉 ----------
   撤销钮嵌在同一枚 toast 胶囊里，用描边小胶囊，不另起第二个实心大按钮；
   候选抽屉直接复用 .tf-list / .tf-row，与「全部类型 · 全部分类」同一外壳、同一触控尺寸。 */
.toast-act {
  flex: none; margin-left: var(--sp-1); padding: var(--sp-1) var(--sp-3);
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  background: transparent; color: var(--text-1);
  font-size: var(--fs-label); font-weight: var(--fw-medium);
  cursor: pointer; transition: background var(--d-fast), transform var(--d-micro);
}
@media (hover: hover) { .toast-act:hover { background: var(--bg-hover); } }
.toast-act:active { transform: scale(.95); }
.nl-pick-sheet .tf-list { padding: 2px var(--card-pad) var(--sp-3); }
.nl-pick-sheet .np-kind {
  flex: none; padding: 2px var(--sp-2); border-radius: var(--radius-pill);
  background: var(--bg-soft); color: var(--text-2);
  font-size: var(--fs-label); font-weight: var(--fw-medium);
}

/* ---------- 一句话 AI 识别：悬浮状态胶囊（脱离白卡、独立浮于底部，不被 overflow 裁切） ---------- */
.nl-ai-slot {
  position: sticky; bottom: 14px; z-index: 6;
  display: flex; justify-content: center;
  margin-top: var(--sp-3); pointer-events: none;
}
.nl-ai-slot:empty { display: none; }
.nl-ai-float {
  display: inline-flex; opacity: 0;
  animation: nlFloatIn var(--d-enter) var(--ease-nl) both;
}
.nl-ai-out { animation: nlFloatOut var(--d-modal) ease both; }
.nl-ai-bob {
  position: relative; overflow: hidden;
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4) var(--sp-2) var(--sp-3); border-radius: var(--radius-pill);
  background: var(--text-1); color: var(--bg-card);
  font-size: var(--fs-label); font-weight: var(--fw-medium); letter-spacing: .3px;
  /* 与动作胶囊同一材质同一阴影：一个轻一个重会露出两套标准 */
  box-shadow: var(--shadow-float), 0 2px 6px rgba(17,17,17,.04);
  animation: nlBob 2.6s ease-in-out var(--d-enter) infinite;
}
/* 微光沿胶囊表面扫过 */
.nl-ai-bob::after {
  content: ""; position: absolute; top: 0; left: 0; height: 100%; width: 42%;
  background: linear-gradient(100deg, transparent, color-mix(in srgb, var(--bg-card) 42%, transparent), transparent);
  transform: translateX(-150%) skewX(-18deg);
  animation: nlShine 1.9s ease-in-out var(--d-push) infinite;
}
.nl-ai-spark { display: inline-flex; line-height: 0; }
.nl-ai-spark svg { width: 15px; height: 15px; fill: currentColor; animation: nlSpark 1.7s ease-in-out infinite; }
.nl-ai-txt { position: relative; }

/* ---------- 处理完的动作胶囊（编辑 / 应用）----------
   与 AI 胶囊同一材质、同一位置、同一入场动画：处理期间是「AI 正在理解」，
   处理完原地换成两段动作，视线不用重新找。
   「应用」反白（白底黑字）承担主操作，「编辑」透明底白字——小面积强调给该给的那一个。
   槽本身 pointer-events:none（AI 胶囊不该可点），胶囊自己恢复可点。 */
.nl-act {
  display: inline-flex; align-items: stretch; overflow: hidden;
  border-radius: var(--radius-pill); background: var(--text-1); pointer-events: auto;
  /* 阴影一律走站内 --shadow-float（0 10px 28px / 9% 黑）：大模糊、低不透明度才叫柔和。
     白底那段在浅页面上会糊掉轮廓，补一圈 6% 的描边而不是加重视觉。 */
  box-shadow: var(--shadow-float), 0 2px 6px rgba(17,17,17,.04), 0 0 0 1px rgba(17,17,17,.06);
  animation: nlFloatIn var(--d-enter) var(--ease-nl) both;
}
.nl-act-btn {
  appearance: none; -webkit-appearance: none; border: 0; background: transparent; cursor: pointer;
  height: 42px; padding: 0 var(--sp-4); font-family: inherit;
  color: var(--bg-card); font-size: var(--fs-label); font-weight: var(--fw-medium); letter-spacing: .3px;
}
.nl-act-btn:active { opacity: .7; }
.nl-act-apply { background: var(--bg-card); color: var(--text-1); }
.nl-act-apply:active { opacity: .86; }/* (1008 死规则清理) */
/* 桌面弹窗底栏本来就有「取消 / 编辑 / 应用」三颗，弹窗态收起悬浮动作胶囊免得重复出口。
   但 .nl-sheet（手机底部抽屉）没有底栏，宽屏下也不能收 —— 收了就只剩回车一条路，
   所以按「承载体」判，不按视口宽度一刀切。
   ⚠ 媒体查询不加特异性：这条必须写在上面 .nl-act 基础规则之后，
      否则会被同选择器的 display:inline-flex 盖掉（0929 静默失效过，探针 L2 抓到）。 */
@media (min-width: 769px) {
  .nl-act { display: none; }
  .nl-sheet .nl-act { display: inline-flex; }
}
/* ≤768 手机端样式 → 06-mobile.css */
@keyframes nlFloatIn { from { opacity: 0; transform: translateY(12px) scale(.9); } to { opacity: 1; transform: translateY(0) scale(1); } }
@keyframes nlFloatOut { from { opacity: 1; transform: translateY(0) scale(1); } to { opacity: 0; transform: translateY(8px) scale(.95); } }
@keyframes nlBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
@keyframes nlShine { 0% { transform: translateX(-150%) skewX(-18deg); } 55%, 100% { transform: translateX(340%) skewX(-18deg); } }
@keyframes nlSpark { 0%, 100% { transform: rotate(0deg) scale(1); opacity: .85; } 50% { transform: rotate(180deg) scale(1.18); opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .nl-ai-float, .nl-ai-bob, .nl-ai-bob::after, .nl-ai-spark svg, .nl-act { animation: none !important; }
  .nl-ai-float, .nl-act { opacity: 1; }
}

/* ============================================================
   一句话录入 · 手机端底部矮抽屉（0927 第二轮）
   输入条那一版真机看下来整体不对：浮签、动作胶囊、连续录入，全都在跟站内既有的
   「抽屉」语言抢手感。这版只借 .wp-mask / .wp-sheet 那只现成的壳——把手、下拉即关、
   遮罩、入场、返回栈全归 mountSheet 管——把 0923 定稿的那套版面原样搬进来：
   井 → 语音提示 → 通栏分隔线 → 黑标胶囊 + 一行结果 → 悬浮胶囊。一样不删。
   这里只补壳本身没有的四件：井的台面、聚焦描边、悬浮位常驻定高、空句被拒时抖一下。
   ============================================================ */
/* 内容自适应 = 天然就是矮抽屉（不像筛选抽屉那样吃 50vh），但长句要能滚、不许顶到状态栏 */
.nl-sheet {
  max-height: calc(100vh - var(--header-h) - var(--safe-top) - 24px);
  overflow-y: auto; overscroll-behavior: contain;
}
/* 井：1005 收编进 --fld-* 家族。此前它吃的是小票机台面色（--rm-well #EDEFF2）+
   一圈 2px 实心灰环，是站内最后一处「编外井」——桌面那只早就在 .fg-card .fg-stack 里
   领了 1004b 定稿的配方（软垫底不翻白 + 静止预留 1px 透明描边 + 聚焦 1px 主描边
   + 12px 柔光渐隐）。两边现在同一枚材质、同一枚光环，只差尺寸档（手机 16px 地板）。
   16px 是地板：iOS 聚焦小于 16px 的输入框会整页放大。起始 96 由 JS 随内容长到 168 封顶后内部滚 */
.nl-sheet-well {
  background: var(--fld-fill); border: 1px solid transparent; border-radius: var(--fld-r);
  transition: background var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast);
}
textarea.nl-sheet-ta {
  display: block; width: 100%; box-sizing: border-box;
  min-height: 96px; max-height: 168px; overflow-y: auto;
  border: 0; border-radius: var(--fld-r); background: transparent; box-shadow: none; outline: none;
  -webkit-appearance: none; appearance: none; resize: none;
  padding: var(--sp-3); font-family: inherit; font-size: calc(16px * var(--fs-scale)); line-height: 1.75; color: var(--text-1);
}
textarea.nl-sheet-ta::placeholder { color: var(--text-hint); }
/* 聚焦：井底不翻白，换 1px 主描边 + 柔光渐隐；不描红（校验失败走「整块抖 + toast」那条语言） */
.nl-sheet-well:focus-within { border-color: var(--primary); box-shadow: var(--focus-glow); }
.nl-sheet .field-hint { margin-top: var(--sp-3); }
/* 预览盒：1005 第二轮——站主点名「画布要白的」，灰画布撤掉，抽屉恢复纯白，
   分层改由卡片自己那一档浅面（--bg-inset）+ 1px 描边承担。
   只留一点上间距，让第一张卡不贴着提示行。 */
.nl-sheet .nl-pvbox { margin: var(--sp-3) 0 0; padding: 0; }
/* 单条结果同上一张卡，不再留「发丝线 + 一行字」那一版 */
.nl-sheet .nl-pv {
  margin-bottom: var(--sp-3); padding: var(--sp-3); font-size: var(--fs-caption);
  background: var(--bg-inset); border: 1px solid var(--border);
  border-radius: var(--radius-card-m); box-shadow: var(--shadow-card);
}
.nl-sheet .nl-pv-list { border-top: 0; }
/* 卡片材质照抄 .tl-item 的描边/圆角/阴影档，底色换 --bg-inset（比纯白抽屉深一档）。
   min-height 44 是热区地板，不随两行布局缩 */
.nl-sheet .nl-pv-row {
  align-items: flex-start; margin: 0 0 var(--sp-3); padding: var(--sp-3);
  background: var(--bg-inset); border: 1px solid var(--border);
  border-radius: var(--radius-card-m); box-shadow: var(--shadow-card);
}
/* 按下只沉底色 + 描边加深一档，整卡不 scale、文字不挂透明度（与 .tl-item:active 同一口径） */
.nl-sheet .nl-pv-row:active { background: var(--bg-hover); border-color: var(--border-strong); }
.nl-sheet .nl-pv-tag { margin-top: 1px; }
/* 多条卡片里标题与次要信息分两行：一行塞不下，而截断等于丢信息。
   桌面弹窗态这两条不命中——那里仍是「标题 · 次要信息」一行，与 1005 之前逐字一致 */
.nl-sheet .nl-pv-row-m { display: block; margin-top: 3px; font-size: var(--fs-micro); color: var(--text-4); }
.nl-sheet .nl-pv-row-sep { display: none; }
.nl-sheet .nl-pv-hint { padding: 0 0 var(--sp-3); }
/* 悬浮位常驻定高：胶囊出现/消失都不该推抽屉顶边。
   align-items:center 是必需的——flex 项默认 stretch，会把 42px 的胶囊拉到 54px 轨道高，
   而里面两段按钮写死 height:42 不跟着长，于是「应用」那块白底比黑底矮一截、
   底下露出一条黑边，整枚读起来像裁坏了（0927 用户报「胶囊不对」，放大 4x 才看得出）。 */
.nl-sheet .nl-ai-slot { position: static; display: flex; justify-content: center; align-items: center; min-height: 54px; margin: var(--sp-3) 0 0; }
.nl-sheet .nl-ai-slot:empty { display: flex; }
/* 胶囊落在白色抽屉上：0924 那套「黑底本体 + 白底应用」的反白逻辑是给**灰色画布**写的——
   整枚药是暗物体时，白那段才「亮」。搬到白色抽屉上眼睛先抓黑的那半，主次正好读反
   （0927 用户判「编辑与应用那枚胶囊不对」）。所以这一层反过来：
   白底描边本体 + 黑底「应用」，与站内 .btn-primary / .btn-default 同一对配对。
   位置、尺寸、圆角、阴影仍与 AI 胶囊同一份，原地换内容不跳；桌面灰画布上不套这条。 */
.nl-sheet .nl-act { background: var(--bg-card); box-shadow: 0 0 0 1px var(--border), var(--shadow-float); }
.nl-sheet .nl-act-btn { color: var(--text-1); }
.nl-sheet .nl-act-apply { background: var(--primary); color: var(--on-primary); }
.nl-sheet .nl-act-apply:active { opacity: .88; }
/* 两段的分界由填充色自己承担，再画一条 32% 白线就是重复 */
.nl-sheet .nl-act-sep { display: none; }
/* 空句被拒：整块抽屉抖一下 + toast（0924 定稿的校验语言；这里没有白卡可抖，就抖抽屉本身） */
.nl-sheet.is-shake { animation: nlSheetShake var(--d-enter) var(--ease-enter); }
@keyframes nlSheetShake {
  0%, 100% { transform: translateY(0); }
  20% { transform: translateX(-7px); } 40% { transform: translateX(6px); }
  60% { transform: translateX(-4px); } 80% { transform: translateX(2px); }
}
@media (prefers-reduced-motion: reduce) {
  .nl-sheet.is-shake { animation: none; }
  .nl-sheet-well { transition: none; }
}

/* ============================================================
   一句话 · 居中核对卡（1005）
   点一张结果卡 → 只核对这一条，「确认记下」才落库，其余卡片留在抽屉里原地不动。
   载体：复用 .wp-mask 那只现成遮罩（fixed / z 9000 / is-open 淡入），
   只把对齐从 flex-end 改成居中——抽屉那层也是 9000，靠 append 到 body 的 DOM 序压住它。
   卡内一切照站内既有语言：36 白圆钮、dd-row 图标行、灰画布白卡、--control-h-lg 主操作。
   两种承载体（手机抽屉 / 桌面弹窗）共用这一层，所以规则不圈在 .nl-sheet 里。
   ============================================================ */
/* 双层遮罩会叠暗（抽屉 32% + 这一层），所以这层自己的底压到 18%，合计约 45% */
/* 1006 修居中失效：基础 .wp-mask{align-items:flex-end}（4510）写在后、同特异度，
   把这里先写的居中盖掉了——「居中核对卡」其实一直贴底弹。抬成 .wp-mask.nl-peek-mask 稳赢。 */
.wp-mask.nl-peek-mask {
  align-items: center; justify-content: center;
  padding: var(--sp-6) var(--sp-4);
  background: color-mix(in srgb, var(--text-1) 18%, transparent);
}
.nl-peek {
  width: 100%; max-width: 330px; max-height: 100%; overflow-y: auto; overscroll-behavior: contain;
  background: var(--bg-card); border-radius: var(--r-5); box-shadow: var(--shadow-modal);
  transform: translateY(14px) scale(.97); opacity: 0;
  transition: transform var(--d-push) var(--ease-enter), opacity var(--d-modal) ease;
}
.wp-mask.is-open .nl-peek { transform: none; opacity: 1; }
.np-head { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-3) var(--sp-2); }
/* 36 白圆钮：站内弹窗头部唯一那枚返回/操作钮的语言，不加文字 */
.np-x {
  flex: none; width: 36px; height: 36px; border-radius: var(--r-circle); padding: 0; cursor: pointer;
  background: var(--bg-card); border: 1px solid var(--border); box-shadow: var(--shadow-card);
  color: var(--text-1); display: inline-flex; align-items: center; justify-content: center;
}
.np-x:active { background: var(--bg-hover); }
.np-x svg { width: 16px; height: 16px; }
.np-crumb { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--sp-2); }
.np-body { padding: 0 var(--sp-4) var(--sp-1); }
/* 标题点字即改：无井底、无描边，只留一道发丝线，聚焦换成主色——
   与「管理面直改」同一口径（校验不描红，这里连校验都没有） */
.np-title {
  display: block; width: 100%; box-sizing: border-box;
  border: 0; border-bottom: 1px solid var(--border); border-radius: 0; outline: none;
  background: transparent; padding: 2px 0 var(--sp-1); font-family: inherit;
  font-size: calc(21px * var(--fs-scale)); font-weight: var(--fw-bold); line-height: 1.35; color: var(--text-1);
  transition: border-color var(--transition-fast);
}
.np-title:focus { border-bottom-color: var(--primary); }
.np-from { margin-top: var(--sp-1); font-size: var(--fs-label); color: var(--text-4); line-height: 1.5; }
/* 卡里的字段组：白卡上再开一块灰画布，与详情页 .dd-group 同一读法 */
.np-group { margin-top: var(--sp-3); padding: 2px var(--sp-3); background: var(--bg-page); border-radius: var(--radius-card-m); }
.np-group .dd-v.is-strong { color: var(--text-1); font-weight: var(--fw-medium); }
.np-with { font-style: normal; color: var(--text-4); font-weight: 400; }
.np-more {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%; min-height: 44px;
  padding: var(--sp-3) 0; border: 0; background: transparent; cursor: pointer; text-align: left;
  font: inherit; font-size: var(--fs-caption); color: var(--text-4);
}
.np-more .dd-ico { color: var(--text-disabled); }
.np-chev { margin-left: auto; flex: none; width: 14px; height: 14px; transition: transform var(--d-base) ease; }
.np-more.is-open .np-chev { transform: rotate(90deg); }
/* 动效 S4（2026-10-20）：展开区从「hidden 属性 + display:none」硬切 → 「is-open 类 +
   grid-template-rows 0fr↔1fr」双向软放。天然吃动态高度（多行 .np-row 无需 JS 测量）；
   与 .np-more.is-open 箭头 rotate 同步（都是 0.24s / --ease-ios 尾段减速档）。
   子层 .np-extra-inner 承载 overflow:hidden + min-height:0 —— 这是 grid-rows 0fr 塌陷
   的必要条件（否则内容 intrinsic 高会把轨道撑起来）。
   老 WebView 兜底：Chromium <117 不支持 fr 插值 → 折叠/展开功能仍对、只失去过渡（退化硬切）。
   回滚＝撤本段 + 还原 .np-extra[hidden] / app.js 里 ex.hidden 那行。 */
.np-extra {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows var(--d-modal) var(--ease-ios);
}
.np-extra.is-open { grid-template-rows: 1fr; }
.np-extra-inner { overflow: hidden; min-height: 0; }
.np-foot { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4) var(--sp-4); }
.np-ghost {
  flex: none; height: var(--control-h-lg); padding: 0 var(--sp-1); border: 0; background: transparent;
  cursor: pointer; font: inherit; font-size: var(--fs-caption); color: var(--text-3);
}
.np-ghost:active { color: var(--text-1); }
.np-confirm {
  flex: 1; height: var(--control-h-lg); border: 0; border-radius: var(--radius-lg); cursor: pointer;
  background: var(--primary); color: var(--on-primary);
  font: inherit; font-size: calc(15px * var(--fs-scale)); font-weight: var(--fw-medium); letter-spacing: .4px;
}
.np-confirm:active { opacity: .88; }

/* ---- 结果卡的「已记下」态（1005 逐条核对）：只降档，不划掉、不消失——
       它还得能被点回去看一眼 ---- */
.nl-sheet .nl-pv-row .nl-pv-row-t { flex: 1; }
.nl-pv .nl-pv-txt { flex: 1; }
.nl-pv-row-tick {
  flex: none; display: none; align-items: center; justify-content: center;
  width: 18px; height: 18px; margin-top: 2px; border-radius: var(--r-circle);
  background: var(--text-1); color: var(--on-primary);
}
.nl-pv-row-tick svg { width: 11px; height: 11px; }
.nl-pv-row.is-saved, .nl-pv.is-saved { background: var(--bg-soft); border-color: transparent; box-shadow: none; }
.nl-pv-row.is-saved .nl-pv-row-t b { color: var(--text-2); }
.nl-pv-row.is-saved .nl-pv-tag, .nl-pv.is-saved .nl-pv-tag { background: var(--bg-count); color: var(--text-3); }
.nl-pv-row.is-saved .nl-pv-row-tick, .nl-pv.is-saved .nl-pv-row-tick { display: inline-flex; }
/* 单条结果那张卡也能点，所以要有可点性与按下反馈（与多条卡片同一档） */
.nl-pv.is-tap { cursor: pointer; }
.nl-sheet .nl-pv.is-tap { background: var(--bg-inset); border: 1px solid var(--border);
  border-radius: var(--radius-card-m); box-shadow: var(--shadow-card); }
.nl-pv.is-tap:active { background: var(--bg-hover); border-color: var(--border-strong); }
@media (prefers-reduced-motion: reduce) {
  .nl-peek { transition: none; transform: none; opacity: 1; }
  .np-more .np-chev { transition: none; }
  .np-extra { transition: none; }
}

/* ===================== ≤380px 超窄屏（iPhone SE / 小屏安卓 / 系统大字体） ===================== */
/* 触控目标、dock 尺寸与字号地板的超窄屏收缩已迁至文件末尾
   「手机端全局 UI/UX 优化 v1.0」——那些规则必须晚于 ≤768 基线才会生效；
   此处只保留与后续基线不冲突的两条收缩。 */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   手机端可读性强化（≤768px）
   原则：正文 15~16px、辅助文字不低于 12px、触控目标 ≥44px；
   保持桌面端建立的字阶层级，只抬手机端基线与地板。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* 超窄屏回补：在 768 新基线上做温和收缩，不再压回小字号
   （dock 标签字号地板已迁至文件末尾的 ≤380 块） */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   父子级联瀑布动效（详情弹窗）
   勾选父待办：子任务自上而下依次弹入勾选；取消：同序依次熄灭。
   ============================================================ */
@keyframes subPop {
  0%   { transform: scale(1); }
  38%  { transform: scale(1.32); }
  70%  { transform: scale(.94); }
  100% { transform: scale(1); }
}
@keyframes subFlash {
  0%   { background: var(--bg-hover); border-color: var(--border-strong); }
  100% { background: var(--bg-card);  border-color: var(--border); }
}
.dt-sub-check.sub-pop { animation: subPop var(--d-med) var(--ease-float); }
.sub-row.sub-flash    { animation: subFlash var(--d-slow) ease-out; }

/* ============================================================
   底部导航 · 果冻指示块（双层结构）
   外层 .tabbar-ind：只负责位移；内芯 .tabbar-ind-core：软胶镜片，负责形变。
   两条通道都由 app.js 的同一条弹簧逐帧驱动（见 updateTabIndicator），
   所以这里绝不能再挂 transition——CSS 再补一条曲线，就是「到位后还自己抖两下」的来源。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   底部导航 · 柔光玻璃 dock（与右侧加号同一枚材质令牌）
   --glass-* 定义在文件头的主题令牌层，暗色在 [data-theme="dark"] 里整组换值；
   这里只负责「谁来消费」，任何一处都不再手写透明度/模糊参数。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* （0925 回退：这里曾有「换形态席次淡入 .dock-morph / @keyframes dockSeatIn」一节，
   名单不再随视图置换，也没有任何 JS 会挂那个类——留着就是骗下一个读样式的人。） */

/* ============================================================
   事件详情 · 分组卡片式（灰底画布 + 白色圆角卡 + 巨型倒计时）
   参考 iOS 设置式信息分组，融入 Klog 黑白 + 等宽数字语言。
   ============================================================ */
.dd-modal { background: var(--bg-page); }
.dd-modal .modal-body { padding-bottom: var(--sp-6); }

.dd-hero {
  background: var(--bg-card); border-radius: var(--r-5);
  padding: var(--sp-4); box-shadow: var(--shadow-card);
}
.dd-hero-name { font-size: calc(20px * var(--fs-scale)); font-weight: var(--fw-bold); color: var(--text-1); margin-top: var(--sp-3); line-height: 1.35; }
.dd-cap { display: block; font-size: var(--fs-micro); color: var(--text-4); margin-top: var(--sp-3); letter-spacing: .5px; }
.dd-big { display: flex; align-items: baseline; gap: var(--sp-1); margin-top: 2px; }
.dd-num {
  font-family: var(--font-mono); font-size: 56px; font-weight: var(--fw-bold);
  color: var(--text-1); line-height: 1.05; letter-spacing: -2px; font-variant-numeric: tabular-nums;
}
.dd-num-today { font-size: 40px; letter-spacing: 0; color: var(--status-bad); }
.dd-unit { font-size: calc(14px * var(--fs-scale)); color: var(--text-4); }
.dd-hero-date { font-size: calc(14px * var(--fs-scale)); color: var(--text-4); margin-top: var(--sp-3); }
.dd-hero-since { font-size: var(--fs-caption); color: var(--text-3); margin-top: var(--sp-2); }
.dd-hero-since b { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-weight: var(--fw-semibold); color: var(--text-1); }
/* 人物档案英雄区：站主实拍右侧太空。与事件详情/日记/停用页共用的 .dd-hero 默认是竖排
   左对齐，大数字和名字挤在左半边、右边整片空。is-person 这个修饰类**只在人物详情挂**
   （见 app.js openPersonCard），改成「左文字 / 右倒计时」两栏，把巨型天数甩到右列填白。
   右列用事件详情同名容器 .dd-hero-count，垂直居中对齐左列，两栏窄屏自动靠 gap 收窄。 */
.dd-hero.is-person { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); }
.dd-hero.is-person .dd-hero-main { flex: 1; min-width: 0; }
.dd-hero.is-person .dd-hero-count { flex: none; text-align: right; }
/* 1029 站主定稿：灰字三段（农历 / 每年·按农历 / 至今 N 天）**在卡内独占一整行**，
   右列「下次生日 N 天」整体上移与左列顶齐平。
   做法是把这张卡改成上下两段：上段 .dd-hero-cols 走原来的两栏，下段是灰字行。
   根因是宽度：两栏的左列只有 231px，农历一开三段自然宽合计 244px → 溢出 13px →
   flex 把三段同时压缩、词内断字（「农历 九月十 / 二」）。
   `> span` 那条是补上一版的洞：灰字段落原本是**裸文本节点**，`.dd-meta > *`
   选不中匿名 flex item，所以「nowrap + 不收缩」的保护从来没真正吃到。
   事件详情只是借 .is-person 的两栏填白（见下方注释），不复用这一条，故另起钩子。 */
.dd-hero.is-person-full { flex-direction: column; align-items: stretch; justify-content: flex-start; gap: var(--sp-3); }
.dd-hero.is-person-full .dd-hero-cols { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-2); }
/* 段间距交给上面那条 gap：行自带的 margin-top 在卡内会叠成两份呼吸 */
.dd-hero.is-person-full > .dd-meta, .dd-hero.is-person-full > .dd-hero-date { margin-top: 0; }
.dd-hero.is-person-full .dd-meta > span { white-space: nowrap; }
/* 右列三行（标签 / 巨型数 / 日期）都贴右缘：`.dd-hero-count` 的 text-align:right 管不到
   .dd-big 这只 flex 行——数字那行按 flex-start 左包，日期比它长时就从左边露出来一截
   （订阅带年份的续费日「2027 年 2 月 2 日」正是这种）。人物/事件那两页这行本来就是最宽的，
   加这条是原地不动，只有更长的兄弟行才会显出差别。 */
.dd-hero.is-person-full .dd-hero-count .dd-big { justify-content: flex-end; }

.dd-group {
  background: var(--bg-card); border-radius: var(--radius-card-m); margin-top: var(--sp-3);
  box-shadow: var(--shadow-card); overflow: hidden;
}
.dd-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); position: relative; }
/* 行分割线（1015 站主定稿：通栏）：原先从文字起笔缩进 48px，站主要求全站统一成
   统计卡那种「顶到卡边」的一条——left 归 0 即是。发丝线仍只归 dd 行自己画，
   tp-mgr 这类自带 border-top 的行在下面单独掐掉，避免同一道缝叠出粗细两条。 */
.dd-row + .dd-row::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0;
  border-top: 1px solid var(--border);
}
.dd-ico { width: 20px; flex-shrink: 0; color: var(--text-2); display: inline-flex; justify-content: center; }
.dd-ico svg { width: 17px; height: 17px; }
.dd-k { flex: 1; min-width: 0; font-size: calc(15px * var(--fs-scale)); color: var(--text-1); }
.dd-v { color: var(--text-4); font-size: calc(14px * var(--fs-scale)); text-align: right; max-width: 62%; word-break: break-word; }
/* 公历生日那行带「日期 · 属年 · 星座」，比一般 .dd-v 长：中大字号下 62% 上限会把
   星座拆成「狮子 / 座」两行（站主实拍）。is-date（仅人物详情生日行挂）放开上限，
   并把断行交给空格——keep-all 让 CJK 不在词内断，只可能在「 · 」的空格处折，
   星座整词不再被截，也不会撑破卡片（最宽那截「YYYY年M月D日」本就放得下）。 */
.dd-v.is-date { max-width: none; word-break: keep-all; overflow-wrap: normal; }
/* 详情里的「动作行」（归档这类）：排版照 dd-row 抄，只加可按的明示——光标＋右侧箭头＋图标提亮一档。
   按下不压暗（站主定：文字禁挂 :active 压暗，即时反馈交给最轻一档震动）。 */
.dd-row.dd-act { cursor: pointer; }
/* 动作行的撑满权从「主语」挪到「说明」：.dd-k 在普通行里是撑满的那一列（站内契约），
   但动作行的主语就是那颗动作名（确认已续费 / 取消订阅），它一旦跟着缩、跟着折，
   「取消订 / 阅」这种断字就把整行的主语劈开（1107 手机端实拍，大字号档必现）。
   改成主语 hug 且不折行、说明去 flex:1 吃剩下的宽度并右对齐——
   真挤不下时折的是说明那段话，不是那颗动作名。 */
.dd-row.dd-act .dd-k { flex: none; white-space: nowrap; }
.dd-row.dd-act .dd-v { flex: 1; min-width: 0; }
.dd-row.dd-act .dd-ico { color: var(--text-1); } /* 1011 基档压深到 text-2 后，「提亮一档」改走纯黑 */
.dd-row.dd-act .dd-chev { width: 14px; flex-shrink: 0; color: var(--text-4); display: inline-flex; }
.dd-row.dd-act .dd-chev svg { width: 14px; height: 14px; }
@media (hover: hover) and (pointer: fine) {
  .dd-row.dd-act:hover .dd-k { color: var(--primary); }
}

/* 底部主操作：手机端把弹窗底栏抬到大按钮档（--control-h-lg 高 · --radius-lg 圆角 · --fs-ctrl-lg 字号）。
   这两条曾漏写在媒体查询外，把 app 端规格污染到桌面详情——桌面应落回 .modal-foot 基础 .btn
   （--control-h 34px · --radius-btn 4px · 右对齐），故一并收进 ≤768。
   历史第三条 flex:1 已删：按钮挂在内容宽的 .modal-foot-group 里，剩余空间全被 .modal-foot-left 的
   margin-right:auto 吃掉，实测右组宽 == 子按钮之和（126==126），flex:1 从来没有可分配空间。 */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   详情页参考图改版 v1.2（2026-09-21 · 样板=待办详情，手机端专属）
   真机反馈收敛：返回=参考图同款白圆钮（图标）、圆钮右侧「待办 · 标题名」面包屑、
   编辑回标题栏铅笔、悬浮条只留居中的圆形删除钮（阴影减淡至 .08 档）。
   v1.3 收口（2026-09-21）：白圆钮升级为「详情+编辑」共用头部语言——
   编辑页返回、铅笔（详情）、对勾/加号（编辑保存）全部换成同款白圆钮，
   编辑页主标题从绝对居中移到返回钮右侧（与详情面包屑同一节奏）。
   借参考图的层级骨架，转译进站内语言：
   · dd-notitle：隐藏居中标题（标题职责交正文 22px 大标题）；
   · .dd-meta：标题下一行灰字 meta（截止·分类·重复·创建于），发丝竖线分隔；
   · dd-fab + .dd-fabbar：底部悬浮圆形删除钮（居中），内容从其下滚过。
   桌面 >768 不挂这些类也不命中（全部圈在 ≤768），底栏语言原样保留。
   ============================================================ */
.dd-crumb { display: none; } /* 面包屑仅手机端详情标题栏出现（v1.2 起圆形返回钮右侧） */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   待办详情 · dd-modal 迁移 v1.0（2026-09-16）
   把待办详情从旧的扁平 detail-hero/detail-kv 提升到与备忘/事件/回顾
   一致的「灰底画布 + 白色圆角卡 + iOS 图标行」语言。dd-hero/dd-group/
   dd-row 复用既有 token（shadow-card、16 内距、8 组距、发丝线缩进 48px），
   这里只补站内没有覆盖的两块：完成勾选英雄区 + 卡内子任务行。
   ============================================================ */
/* 英雄卡：完成勾选 + 标题；整块可点 = 一键完成（勾选框走原生，JS 里跳过避免二次取反） */
.td-hero { cursor: pointer; -webkit-tap-highlight-color: transparent; }
/* 注意：不要给 .td-title 加 :active 压暗——按下变淡、抬起恢复的往返就是
   「点完成时标题闪一下」，用户明确不要（勾选框填色本身就是按压反馈） */
.td-hero-row { display: flex; align-items: flex-start; gap: var(--sp-3); }
.td-hero-row .todo-check { flex-shrink: 0; margin-top: 3px; }
.td-title { flex: 1; min-width: 0; font-size: calc(20px * var(--fs-scale)); font-weight: var(--fw-bold); color: var(--text-1); line-height: 1.35; word-break: break-word; }
.td-title.is-done { color: var(--text-4); text-decoration: line-through; }

/* 详情 = 整屏页（1010 站主定，推翻 1009 的 78% 底部抽屉）：点卡片 → 整屏自下而上快速升起，
   入场直接吃 04 的 `.modal-card{animation:sheetUp var(--d-enter)}`，不再单开一档 .6s 抽屉语言（同一套入场语言，
   不与别的弹窗分叉）。「详情↔编辑」的共享元素形变（td-grow 长满 / td-shrink 收回）整套撤掉——
   点编辑或点新增进表单一律自上而下推入（见文件末尾「弹窗链切换」6），入场方向由「页面角色」决定，
   不再看 380ms 链窗口，所以同一个动作不会再「一会儿从下、一会儿从上」。
   cmdk 面板虽也带 dd-notitle 但没有 dd-modal，不受影响。 */
/* ≤768 手机端样式 → 06-mobile.css */
@media (prefers-reduced-motion: reduce) {
  .modal-card.dd-modal.dd-notitle, .modal-card.dd-modal.dd-notitle.closing { animation: none; }
  .modal-mask:has(.modal-card.dd-modal.dd-notitle.closing) { animation: none; }
}

/* 分类值：色点与文字上下居中 + 拉开间距（dd-v 里内联成一条，不再贴边） */
.td-cat { display: inline-flex; align-items: center; gap: var(--sp-2); }
.td-cat .cat-dot { width: 9px; height: 9px; flex-shrink: 0; }

/* 描述卡：单独一张白卡内的正文块，长文换行、保留手打换行 */
.td-desc-group { padding: var(--sp-4); }
.td-desc { font-size: calc(15px * var(--fs-scale)); line-height: 1.7; color: var(--text-2); white-space: pre-wrap; word-break: break-word; }

/* 信息组计数徽标：等宽数字，与 dd-v 灰字同档 */
.td-sub-head .chip-cnt { font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--text-4); }
/* 子任务表头行与本组列表之间补一道发丝线（dd-row 相邻规则只连 dd-row，此处手动收尾） */
.td-sub-head { padding-bottom: var(--sp-3); }
.td-sub-head::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; border-bottom: 1px solid var(--border); } /* 1015 同上：通栏 */

/* 卡内子任务行：拍平掉旧 .sub-row 的独立外框，降为无边框 hairline 行，与 dd-row 同缩进节奏 */
.td-sub-editor { display: flex; flex-direction: column; gap: 0; margin: 0; padding: 0; }
.td-sub-editor .sub-row {
  display: flex; align-items: center; gap: var(--sp-3); position: relative;
  min-height: 46px; padding: var(--sp-3) var(--sp-4);
  border: none; border-radius: 0; background: transparent;
  cursor: pointer;
}
.td-sub-editor .sub-row + .sub-row::before {
  content: ""; position: absolute; top: 0; left: 43px; right: 0; border-top: 1px solid var(--border);
}
.td-sub-editor .dt-sub-check { accent-color: var(--primary); width: 17px; height: 17px; flex-shrink: 0; margin: 0; }
.td-sub-editor .sub-title { font-size: calc(15px * var(--fs-scale)); color: var(--text-1); white-space: normal; overflow: visible; text-overflow: clip; }
.td-sub-editor .sub-row.is-done .sub-title { color: var(--text-4); text-decoration: line-through; }
.td-sub-editor .sub-row:active { background: var(--bg-hover); }

/* ============================================================
   习惯详情 · dd-modal 迁移 v1.0（2026-09-16）
   与待办/备忘详情统一：灰底画布 + 白色圆角卡。习惯特有的热力面板
   保留 hm-modal 的宽度（年视图网格需要），但外壳从 bg-soft 描边框
   升级为白卡（与 .dd-group 同壳）。仅作用于 .dd-modal 内的习惯详情，
   习惯列表卡片的 .habit-meta 完全不受影响。
   ============================================================ */
.hb-hero-dot { width: 12px; height: 12px; flex-shrink: 0; }
.hb-hero-name { flex: 1; min-width: 0; font-size: calc(20px * var(--fs-scale)); font-weight: var(--fw-bold); color: var(--text-1); line-height: 1.35; word-break: break-word; }
.hb-hero .hb-ctl { flex-shrink: 0; }

/* 统计组数值：等宽大数字，呼应站内「黑白 + 等宽数字」语言 */
.hb-stats .hb-num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-weight: var(--fw-bold); font-size: calc(16px * var(--fs-scale)); color: var(--text-1); }

/* 热力面板：在灰底画布上升级为白卡，与 dd-group 同壳同距 */
.dd-modal .hm-panel {
  margin-top: var(--sp-3); padding: var(--sp-4);
  background: var(--bg-card); border: none; border-radius: var(--radius-card-m);
  box-shadow: var(--shadow-card);
}

/* ============================================================
   回收站 / 已归档 · 卡片布局 v2（09-19 晚：手机底部抽屉 + 桌面 dd-modal，
   两端内容同一「灰画布 + 每条一张白色圆角卡」。
   说明行 = .bin-cap（图标 + 保留期 + 等宽计数）浮在画布上，
   条目 = .trash-row 白卡，尾部说明 = .bin-tip 灰字；
   卡内操作 = 图标钮：恢复（↩ 中性）/ 彻底删除（红），底栏清空也是同一只删除图标钮。
   ============================================================ */
/* 管理抽屉表头/说明行（分类/标签/类型管理共用；回收站/已归档已改用 .bin-cap/.bin-tip） */
.tb-head { padding-bottom: var(--sp-3); }
.tb-head::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; border-bottom: 1px solid var(--border); } /* 1015 同上：表头线也归通栏 */
.tb-head .chip-cnt { font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--text-4); }
.tb-tip { position: relative; padding: var(--sp-3) var(--sp-4); font-size: calc(13px * var(--fs-scale)); line-height: 1.6; color: var(--text-4); }
.tb-tip::before { content: ""; position: absolute; top: 0; left: 16px; right: 0; border-top: 1px solid var(--border); }

.bin-cap {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 2px var(--sp-1) var(--sp-3); font-size: calc(13px * var(--fs-scale)); color: var(--text-4);
}
.bin-cap svg { flex: none; width: 16px; height: 16px; }
.bin-cnt { margin-left: auto; font-family: var(--font-mono); font-variant-numeric: tabular-nums; letter-spacing: .02em; color: var(--text-4); }
.trash-rows { display: flex; flex-direction: column; gap: var(--sp-3); max-height: none; overflow: visible; }
.trash-row {
  display: flex; align-items: center; gap: var(--sp-3);
  background: var(--bg-card); border: none; border-radius: var(--r-3);
  padding: var(--sp-3); box-shadow: var(--shadow-card);
  transition: transform var(--d-micro) ease, background var(--transition-fast);
}
.trash-rows .cat-row-empty {
  background: var(--bg-card); border: none; border-radius: var(--r-3);
  padding: var(--sp-6) var(--sp-4); text-align: center; font-size: calc(14px * var(--fs-scale)); color: var(--text-4);
  box-shadow: var(--shadow-card);
}
.bin-tip { padding: var(--sp-3) var(--sp-1) 2px; font-size: calc(13px * var(--fs-scale)); line-height: 1.6; color: var(--text-4); }
/* 行内动作 = 图标钮：恢复（↩ 中性）/ 彻底删除（红），层级靠配色不靠字号；触控档见文件下方块 */
.trash-row .cat-act { width: 32px; height: 32px; }
.trash-row .cat-act svg { width: 16px; height: 16px; }
.trash-row .cat-act.cat-act-del { color: var(--status-bad); }
@media (hover: hover) { .trash-row .cat-act.cat-act-del:hover { background: var(--tag-bad-bg); color: var(--status-bad); } }
.trash-row .cat-act:active { transform: scale(.94); }

/* 手机端底部抽屉：灰画布通铺并一路铺到抽屉底（吃掉 sheet 自己的 16px + 安全区下内衬），
   列表区吃 --sheet-max 高度档，把手两档 detent/下拉即关由 wireSheetGrab 接管（list 已认 .bin-scroll）。
   画布必须铺到底：否则底下顶出一条 .wp-sheet 自己的白带，灰字卡在灰/白交界上读作「位置错位」（0927 真机反馈）；
   回收站与已归档现在同一口径——底栏不再占高度（见下 .wp-foot），抽屉底部整块都是画布。 */
.bin-scroll { overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
.bin-sheet { position: relative; }
.bin-sheet .bin-scroll {
  background: var(--bg-page); margin: 0 -16px calc(-16px - var(--sab));
  padding: var(--sp-3) var(--sp-4) calc(var(--sp-4) + var(--sab));
  max-height: var(--sheet-max); transition: max-height var(--d-push) var(--ease-enter);
}
.bin-sheet .trash-row:active { transform: scale(.985); }
/* 单胶囊底栏通栏（选项类抽屉通用） */
.wp-foot > .wp-btn:only-child { flex: 1; }
/* 清空回收站 = 一只悬浮钮（1105 站主两轮点名：灰的、白的收口条都不要，只留钮）：
   底栏退出文档流，不再占那 62px 一条——chrome 少 62px，wireSheetGrab 的 geo() 就把列表区
   长高 62px 补回来，抽屉总高度不动。钮绝对定位浮在画布下缘，左右两段空白靠
   pointer-events:none 穿透（否则整条透明带会拦住列表滚动与卡片点击），钮自己恢复 auto。
   列表末尾另留 62px（钮 46 + 上下各 8）滚出余量，最后一张卡能滚到钮上方、不被压住。 */
.bin-sheet .wp-foot {
  position: absolute; left: 0; right: 0; bottom: calc(var(--sp-3) + var(--sab));
  justify-content: center; pointer-events: none;
}
.bin-sheet .wp-foot .bin-clear { pointer-events: auto; }
.bin-sheet:not(.bin-nofoot) .trash-rows { margin-bottom: 62px; }
/* 一枚删除图标圆钮：白底 + 红字（浮在灰画布上就是一片浮起的白，不叠淡红色块），
   阴影走站内黑影令牌 --shadow-float（0 10px 28px / 9% 黑）：要柔要模糊，不带红调、不压重量 */
.wp-btn.wp-btn-danger.bin-clear {
  flex: 0 0 auto; width: 46px; height: 46px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-card); color: var(--status-bad);
  box-shadow: var(--shadow-float);
  transition: background var(--transition-fast), box-shadow var(--transition-fast), transform var(--d-fast) var(--ease-float);
}
.wp-btn.wp-btn-danger.bin-clear:active {
  background: var(--bg-hover);
  box-shadow: var(--shadow-hover);
  transform: scale(.94);
}
/* 两端同一只垃圾桶：图标幅面统一；桌面沿用 .btn-danger 描边皮肤，只把通栏收成方钮。
   宽度取 --control-h 而非裸 46px：binMobile()=innerWidth<=768，这条只在桌面命中，而桌面底栏
   按钮统一是 --control-h 高——46px 宽配 34px 高是个被压扁的长方形（1003 体检实测 48×35）。
   写成 min-width:769 显式跟 JS 门对齐：≤768 段把 --control-h 重映射成 44px，
   不圈起来的话这条会在手机端取到 44 宽、配 --control-h-lg 的 46 高，又歪一档。 */
.bin-clear svg { width: 20px; height: 20px; flex: none; }
@media (min-width: 769px) {
  .dd-modal .modal-foot .btn.bin-clear { width: var(--control-h); padding: 0; }
}

/* 模块面板（手机端）：按住 dock 上滑弹出，复用 wp-sheet 两档抽屉壳；
   行 = 侧栏菜单克隆（概览/用户/未来新模块自动跟进），白卡行 + 右侧计数/当前位。
   面板只在 ≤768 由 JS 创建，无需媒体查询 */
.mod-scroll { overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
.mod-sheet .mod-scroll {
  background: var(--bg-page); margin: 0 -16px; padding: var(--sp-3) var(--sp-4) var(--sp-4);
  max-height: var(--sheet-max); transition: max-height var(--d-push) var(--ease-enter), min-height var(--d-push) var(--ease-enter);
}
.mod-rows { display: flex; flex-direction: column; gap: var(--sp-3); }
.mod-row {
  display: flex; align-items: center; gap: var(--sp-3);
  width: 100%; border: none; cursor: pointer;
  background: var(--bg-card); border-radius: var(--r-3);
  padding: var(--sp-3); box-shadow: var(--shadow-card);
  font-size: calc(15px * var(--fs-scale)); color: var(--text-1);
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; /* 长按=拿起拖换，不弹选择/呼出 */
  transition: transform var(--d-base) var(--ease-float); /* 拖动让位补间（§4.3b 四口同一套） */
}
.mod-row svg { width: 20px; height: 20px; flex: none; color: var(--text-3); }
.mod-row .mod-label { flex: 1; min-width: 0; text-align: left; }
/* 固定席序号：钉在 dock 第几格（长按拖到别的行互换） */
.mod-row .mod-seat {
  flex: none; min-width: 16px; height: 16px; padding: 0 var(--sp-1); border-radius: var(--r-2);
  background: var(--bg-count); color: var(--text-3);
  font-family: var(--font-mono); font-size: var(--fs-10); line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  font-variant-numeric: tabular-nums;
  transition: background var(--d-base), color var(--d-base);
}
.mod-row .mod-seat.is-active { background: var(--primary); color: var(--on-primary); }
.mod-row .mod-cnt { animation: none; }
.mod-row .mod-cnt-inline { font-size: var(--fs-12); font-weight: var(--fw-regular); color: var(--text-3); font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.mod-row .mod-cur { flex: none; font-size: var(--fs-12); color: var(--text-4); }
/* 概览=主页：右侧主页小图标，锁定第一行不参与拖动 */
.mod-row .mod-home { flex: none; display: inline-flex; color: var(--text-3); }
.mod-row .mod-home.is-active { color: var(--text-1); }
.mod-row .mod-home.is-active svg { fill: currentColor; }
.mod-row .mod-home svg { width: 16px; height: 16px; color: inherit; }
.mod-row.mod-locked { cursor: default; }
.mod-row.is-cur { font-weight: var(--fw-semibold); }
.mod-row.is-cur svg { color: var(--text-1); }
.mod-row:active { transform: scale(.985); }
/* 拖拽态（§4.3b 公共标准）：拿起行由 JS 逐帧写 transform（位移+1.015 放大），
   浮起用 --shadow-float（与其余三面同档，此前是 hover 档）；
   「跟手禁补间」交给容器态类压，松手摘掉容器类＝补间回来、浮起还在，才落得进空位 */
.mod-row.is-drag { position: relative; z-index: 3; box-shadow: var(--shadow-float); }
.mod-rows.is-dragging-mode .mod-row.is-drag { transition: none; }
.mod-rows.is-dragging-mode .mod-row:active { transform: none; }

/* ============================================================
   滚轮日期选择器（移动端 · 底部抽屉 + 三列滚轮 + 公历/农历）
   ============================================================ */
.wp-mask {
  position: fixed; inset: 0; z-index: 9000;
  background: var(--mask);
  display: flex; align-items: flex-end;
  opacity: 0; transition: opacity var(--d-modal) ease, padding-bottom var(--d-modal) var(--ease-enter, ease);
}
.wp-mask.is-open { opacity: 1; }
.wp-sheet {
  width: 100%; background: var(--bg-card);
  border-radius: var(--radius-sheet);
  padding: var(--sp-2) var(--sp-4) calc(var(--sp-4) + var(--sab));
  box-shadow: var(--shadow-modal);
  transform: translateY(100%); transition: transform var(--d-med) var(--ease-enter);
}
.wp-mask.is-open .wp-sheet { transform: translateY(0); }
.wp-title { text-align: center; font-size: calc(17px * var(--fs-scale)); font-weight: var(--fw-bold); color: var(--text-1); margin-bottom: var(--sp-3); }

.wp-seg {
  display: flex; justify-content: center; gap: var(--sp-1); margin: 0 auto var(--sp-3);
  padding: var(--sp-1); width: max-content; max-width: 100%;
  background: var(--bg-muted); border-radius: var(--radius-pill);
}
.wp-seg-btn {
  border: none; background: transparent; height: 36px; padding: 0 var(--sp-6);
  border-radius: var(--radius-pill); font-size: calc(15px * var(--fs-scale)); color: var(--text-3); cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.wp-seg-btn.is-on { background: var(--primary); color: var(--on-primary); font-weight: var(--fw-medium); }

.wp-wheels { display: flex; height: 220px; margin: var(--sp-1) 0 var(--sp-4); }
.wp-col {
  flex: 1; position: relative; overflow: hidden;
  touch-action: none; user-select: none; -webkit-user-select: none; cursor: grab;
  -webkit-mask-image: linear-gradient(transparent 0%, #000 24%, #000 76%, transparent 100%);
  mask-image: linear-gradient(transparent 0%, #000 24%, #000 76%, transparent 100%);
}
.wp-col:active { cursor: grabbing; }
/* 中心选中带：浅灰圆角横带（各列独立，贴合参考图） */
.wp-col::before {
  content: ""; position: absolute; left: 6px; right: 6px; top: 50%;
  height: 40px; margin-top: -20px;
  background: var(--bg-hover); border-radius: var(--r-2); z-index: 0;
}
.wp-list { position: absolute; left: 0; right: 0; top: 0; will-change: transform; z-index: 1; }
.wp-item {
  height: 44px; line-height: 44px; text-align: center;
  font-size: calc(15px * var(--fs-scale)); color: var(--text-4);
  font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.wp-item.is-on { color: var(--text-1); font-weight: var(--fw-semibold); font-size: calc(17px * var(--fs-scale)); }

/* ---- 滚轮抽屉（日期/时间，0922）：单档固定高，标题栏对称双白圆钮——
   左 ✕ 清值（仅可选场景渲染）、右 ✓ 保存（均为详情页 .modal-head-act.is-icon 同材质），
   下拉即关、点标题栏不换档（wireSheetGrab expand:false, tap:false） ---- */
.wp-drawer .wp-title { position: relative; display: flex; align-items: center; justify-content: center; min-height: 38px; }
.wp-drawer .wp-title .wp-ok { position: absolute; right: 0; top: 50%; margin-top: -18px; }
.wp-drawer .wp-title .wp-x { position: absolute; left: 0; top: 50%; margin-top: -18px; }
.wp-drawer .wp-title .wp-x svg { width: 16px; height: 16px; }
/* 「指定今天 / 指定现在」：滚轮下一枚灰底胶囊 + 线性小图标，一眼可读可点（区别于裸文字） */
.wp-drawer .wp-under { text-align: center; margin: 2px 0 var(--sp-1); }
.wp-jump {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  border: 0; background: var(--bg-muted); color: var(--text-2);
  border-radius: var(--radius-pill); height: 38px; padding: 0 var(--sp-4);
  font-family: inherit; font-size: calc(14px * var(--fs-scale)); font-weight: var(--fw-medium); line-height: 1;
  cursor: pointer; -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  transition: background var(--transition-fast), color var(--transition-fast), transform var(--d-fast) var(--ease-float);
}
.wp-jump svg { width: 16px; height: 16px; flex: none; opacity: .8; }
.wp-jump:active { background: var(--bg-count); color: var(--text-1); transform: scale(.95); }

.wp-foot { display: flex; gap: var(--sp-3); }
.wp-btn { border: none; height: 50px; border-radius: var(--radius-pill); font-size: calc(16px * var(--fs-scale)); cursor: pointer; }
.wp-btn-cancel { flex: 1; background: var(--bg-muted); color: var(--text-2); }
.wp-btn-cancel:active { background: var(--bg-count); }
/* 可选值滚轮（如待办具体时间）左侧的「清除」：窄胶囊、弱化色，别跟确定抢注意力 */
.wp-btn-clear { flex: 0 0 auto; padding: 0 var(--sp-4); background: none; color: var(--text-3); }
.wp-btn-clear:active { color: var(--text-1); }
.wp-btn-ok { flex: 1.5; background: var(--primary); color: var(--on-primary); font-weight: var(--fw-medium); }
.wp-btn-ok:active { background: var(--primary-hover); transform: scale(.985); }
/* 危险确认：同一枚胶囊，只换成语义红（与左滑删除展开的胶囊同款红） */
.wp-btn-ok.wp-btn-danger { background: var(--status-bad); color: var(--on-primary); }
.wp-btn-ok.wp-btn-danger:active { background: var(--status-bad); filter: brightness(.9); transform: scale(.985); }

@media (prefers-reduced-motion: reduce) {
  .wp-mask, .wp-sheet, .wp-list { transition: none !important; }
}

/* ============================================================
   移动端选项选择卡片（复用 .wp-mask/.wp-sheet 抽屉骨架）
   列表行 + 右侧勾选态：选中不整行反白，只显 ✓ + 加粗，走「小面积强调」语言
   ============================================================ */
.op-list {
  display: flex; flex-direction: column;
  max-height: 46vh; overflow-y: auto; -webkit-overflow-scrolling: touch;
  margin: 2px 0 0; overscroll-behavior: contain;
}
.op-item {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%;
  min-height: 52px; padding: var(--sp-3) var(--sp-2);
  background: transparent; border: none; border-top: 1px solid var(--border);
  color: var(--text-1); font-family: inherit; font-size: calc(16px * var(--fs-scale)); text-align: left;
  cursor: pointer; -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  transition: background var(--transition-fast);
}
.op-list .op-item:first-child { border-top: none; }
.op-item:active { background: var(--bg-hover); }
.op-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.op-check {
  color: var(--primary); display: inline-flex; flex: none;
  opacity: 0; transform: scale(.6);
  transition: opacity var(--d-base) ease, transform var(--d-base) var(--ease-float);
}
.op-check svg { width: 20px; height: 20px; }
.op-item.is-on { font-weight: var(--fw-semibold); }
.op-item.is-on .op-check { opacity: 1; transform: scale(1); }
/* 表单内的分类 / 类型抽屉：骨架就是上面这只 op-sheet（46vh 滚动窗、不换档、不锁视口），
   窗里换成列表页同款的 tf-row 卡片行——行距借 .tf-list 的 8px gap，不挂 .tf-list 类本身，
   免得把手拖档时选到另一只容器；管理入口留在滚动窗外，列表再长它也不跟着滚走 */
.fp-sheet .op-list { gap: var(--sp-2); }
.fp-sheet .tps-mgr { width: 100%; margin-top: var(--sp-3); }

/* ============================================================
   详情/表单 · 内联操作区（手机端）：mobDetailify / mobFormify 把底栏动作
   搬进内容末尾时挂的容器。两种形态共用同一个类名——
     · float 详情：.dd-foot-inline.dd-fabbar（悬浮白圆删除钮，见上方 ≤768 段）
     · 表单页：.dd-foot-inline 里只放一枚 .dd-del-text 红字行
   类名不许改：站内十余个探针按 '#modalCard .dd-foot-inline …' 契约点击。
   gate-ok：这两个类只由 wbCoarse() 为真时挂上，桌面 mouse 环境永远匹配不到，
   所以刻意不圈媒体查询——圈了反而伤横屏手机：wbCoarse() 的第二条腿
   (hover:none) and (pointer:coarse) 在 844×390 这类横屏下为真，而 max-width:768 为假，
   圈起来会让横屏手机连这层 flex 容器都拿不到。（横屏结构性错位在 CSS 侧还有 .dd-fabbar
   那条同源问题，1003 已单独记为待议项，不在本轮动。）
   ============================================================ */
.dd-foot-inline {
  margin-top: var(--sp-4);
  padding-bottom: var(--sab);
  display: flex; flex-direction: column; gap: var(--sp-2);
}
.dd-del-text {
  width: 100%; height: 40px; border: none; background: transparent;
  color: var(--tag-bad-fg); font-size: calc(14px * var(--fs-scale)); cursor: pointer;
}
.dd-del-text:active { opacity: .55; }

/* ============================================================
   表单分组卡（编辑页 · 参考 iOS 设置式）
   桌面端 .fg-card 完全透明（display:contents，布局照旧）；
   移动端：灰底画布 + 白色分组卡 + 左标签右控件行 + 头部保存胶囊。
   ============================================================ */
/* 图标尺寸与点字间距立成两枚局部令牌：定义在 .fg-card 本身（桌面端也在），
   下面的标签列下限从它们推出来——改图标大小，不会把「同一张卡各行输入起始线齐平」
   这条设计意图悄悄挤掉 */
.fg-card { display: contents; --fg-i-w: 20px; --fg-i-gap: 8px; }
/* 表单行标题前那枚图标片：与「提醒与震动自检」页同族描线字形（PF_ICONS），小 2px。
   1011 定稿全站行首图标统一一档；首版取详情档 text-4 被站主打回「太灰」，
   四档并排试作（dbg-ico-align-tone-trial）后压到 --text-2——图标要贴着标题的实度。
   行式/开关行的居中没有用 vertical-align 魔法数（标题升 16px 后实测偏低 2px），
   改由下面 label/.switch-label 的 inline-flex 承担；-5px 只服务堆叠行那类纯内联场景。 */
.fg-card .fg-i {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: var(--fg-i-w); height: var(--fg-i-w);
  margin-right: var(--fg-i-gap); vertical-align: -5px;
  color: var(--text-2);
}
.fg-card .fg-i svg { width: var(--fg-i-w); height: var(--fg-i-w); }

.modal-head-act {
  margin-left: auto; flex-shrink: 0;
  border: none; height: 32px; padding: 0 var(--sp-4);
  border-radius: var(--radius-pill); background: var(--primary); color: var(--on-primary);
  font-size: calc(14px * var(--fs-scale)); font-weight: var(--fw-medium); cursor: pointer;
  transition: transform var(--d-micro) ease, background var(--transition-fast);
}
.modal-head-act:active { transform: scale(.94); background: var(--primary-hover); }

/* ≤768 手机端样式 → 06-mobile.css */

/* 分组卡内开关联动拍平：switch-row 自带的小内衬与卡片叠层冲突 */
/* ≤768 手机端样式 → 06-mobile.css「分组卡内开关联动拍平：switch-row 自带的小内衬与卡片叠层冲突」 */

/* 头部对勾保存（移动端表单通用） */
.modal-head-act.is-icon {
  width: 34px; height: 34px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
}
.modal-head-act.is-icon svg { width: 20px; height: 20px; } /* 与返回钮 chevron 同幅 */

/* ≤768 手机端样式 → 06-mobile.css */

/* 历史遗留分支（已删，1003 体检）：这一段是为「非悬浮版详情」写的——主操作通栏胶囊、
   删除降成居中红字行。五只详情现在一律 mobDetailify({float:true})，非悬浮分支只剩
   mobFormify 挂的 .dd-del-text（不是 .btn），于是这里六条规则全部被 .fab-circle 逐条遮蔽，
   唯独 :hover / :active 两条盖不住，实测把白圆删除钮洗成透明（hover 时白底消失、
   按下时 opacity .55）。删掉即回到 .btn-danger 基础皮肤，圆钮由 .fab-circle 自己说话。 */

/* ============================================================
   纪念日列表卡 · 信息层级重排
   名称行（类型圆点+名字）/ 属性文字行 / 时间语境行；右侧数字去重
   ============================================================ */
.date-card .date-title { gap: var(--sp-2); flex-wrap: nowrap; }
.date-name { font-size: calc(16px * var(--fs-scale)); }
/* 1011 D：类型徽章进属性行——.date-attrs 变 flex 容器（分类徽章 + 其余属性文字并排）；
   标题前的 .dd-dot 随「类型圆点挪进徽章」一并撤除，三处列表同一套装束 */
.date-attrs { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-1); color: var(--text-4); font-size: var(--fs-micro); margin-top: var(--sp-1); letter-spacing: .2px; }
.date-when {
  color: var(--text-3); font-size: var(--fs-caption); margin-top: var(--sp-1);
  font-variant-numeric: tabular-nums; font-family: var(--font-mono);
}
.date-when { font-size: calc(13px * var(--fs-scale)); }

/* ============================================================
   手机端提示 · 灵动岛（2.64 定稿体积生长语言；1105 修「两段」与「收缩别扭」）
   同一枚 dock 上方深色毛玻璃胶囊，动效语言是「体积生长」：
   从种子宽（左右内衬+状态点，点恰居中）真变 width 展开——高度/圆角锁死，
   禁非等比缩放（样板量过：scaleX/Y 拉胶囊=读成变形）；展宽 450ms 走
   cubic-bezier(.12,.9,.22,1)「早冲刺收尾」。
   1105 两条改动（样式在 06-mobile，编排全在 app.js 的 islandToast 一族）：
   · 出场不再「等宽度停稳才亮字」——每颗字按「裁剪边什么时候揭到自己」各排各的拍，
     展宽与出字叠成同一个动作（旧写法实测宽 154ms 到位、末字 358ms 才起跑＝读成两段）；
   · 退场三拍：灭字拍（.12s 内整句文字与状态点一起先散）→ 90ms 后缩回种子与淡出同帧起
     （缩回 .22s 从容收、淡出 .15s 不压延迟，两拍叠着走完，肉眼总长 ~210ms）；
     旧写法只改 duration 且 il-glyph 没绑 il-lit＝文字全程不淡出，
     被缩回去的右缘当场切掉 38~136px（站主说的「收缩别扭」，逐帧量出来的）；
     状态点原先也不吃灭字拍，一直亮到岛凭空没＝收尾没有先后（站主：突兀）。
   桌面端保持顶部白卡 + toastIn 不动。--il-bottom 是高度调节的唯一变量。
   标记名（供盘账 grep）：is-in / il-lit / il-unlit / il-closing / il-sustain / il-instant / il-shrink / islandSeed / data-cls
   ============================================================ */
.toast { pointer-events: auto; cursor: pointer; }
/* ≤768 手机端样式 → 06-mobile.css */
/* 2.64：toastUp 入场关键帧退役——手机端改走岛形变（JS 驱动 width 过渡），桌面用 toastIn */

/* ============================================================
   设置整合：顶栏单头像入口 + 外观三分段
   ============================================================ */
/* 头像按钮全端可见（顶栏唯一入口） */
.avatar-btn { display: inline-flex; }
@media (min-width: 1025px) {
  .avatar-btn { width: 34px; height: 34px; }
}
/* 设置行内三分段（iOS 设置式：灰轨白胶囊） */
.pf-seg {
  display: inline-flex; flex-shrink: 0; gap: 2px;
  background: var(--bg-muted); border-radius: var(--radius-pill); padding: 3px;
}
.pf-seg button {
  border: none; background: transparent; cursor: pointer;
  height: 28px; padding: 0 var(--sp-3); border-radius: var(--radius-pill);
  font-size: calc(12.5px * var(--fs-scale)); color: var(--text-3);
  transition: background var(--transition-fast), color var(--transition-fast);
}
.pf-seg button.active {
  background: var(--bg-card); color: var(--text-1);
  font-weight: var(--fw-medium); box-shadow: var(--shadow-sm);
}
/* 紧凑档：一行只有一颗钮时（桌面小部件「添加 / 选择习惯」、提醒页「去设置」），
   38px 触控地板的通用胶囊会把行顶得虚胖——图形收到 26px，
   热区用 ::before 上下各外扩 6px 回到 38px（视觉轻、点得住）。
   两个类名并列抬到 (0,2,1)：手机端那条 `.pf-seg button{height:38px}` 是同元素更晚的规则，
   单类写会被静默盖掉（0928 实拍：钮根本没变小）。 */
.pf-seg.pf-seg-tight { padding: 2px; }
/* 0929 审计：这一档专用于「一行只有一颗」的独立动作（桌面小部件「添加/选择习惯」、
   提醒页「去设置」）。原本继承 .pf-seg button 的 --text-3 弱色，读起来像「未选中的分段」
   而非可点动作——对比虽够（#555/#F3F4F6≈6.7:1 过 AA），但主动作不该穿最低强调。
   抬到 --text-1 + 中等字重，让它读作按钮；仍是站内既有外壳，不另创。 */
.pf-seg.pf-seg-tight button { position: relative; height: 26px; padding: 0 var(--sp-3); font-size: var(--fs-12); color: var(--text-1); font-weight: var(--fw-medium); }
.pf-seg.pf-seg-tight button::before { content: ''; position: absolute; left: 0; right: 0; top: -6px; bottom: -6px; }
/* 小一号分段器（0929 真机：设置页里的分段钮比标题还抢眼）：
   图形 30px / 12px 字，热区靠 ::before 上下各外扩 4px 回到 38px。
   与 .pf-seg-tight 同规格思路，只是这档用于「一排多枚」的分段（提前提醒、强度、自检） */
.pf-seg.pf-seg-sm { padding: 2px; }
.pf-seg.pf-seg-sm button { position: relative; height: 30px; padding: 0 var(--sp-2); font-size: var(--fs-12); }
.pf-seg.pf-seg-sm button::before { content: ''; position: absolute; left: 0; right: 0; top: -4px; bottom: -4px; }

/* 本地模式名片右侧「登录账号」文字入口 */
.pf-login-act {
  margin-left: auto; flex-shrink: 0;
  display: inline-flex; align-items: center; gap: 2px;
  border: none; background: transparent; cursor: pointer;
  color: var(--primary); font-size: calc(14px * var(--fs-scale)); font-weight: var(--fw-medium);
  padding: var(--sp-2) 0 var(--sp-2) var(--sp-3);
}
.pf-login-act svg { width: 15px; height: 15px; }
.pf-login-act:active { opacity: .55; }

/* ============================================================
   个人中心 · 退出登录（2.13）：圆图标钮 → 满宽贴底大按钮
   ------------------------------------------------------------
   站主点名「退出按钮往下移动，位置参考修改登录密码页那颗」。钮本身用账户向导
   那一档现成皮肤（.acct-act .acct-act-block），这里只补两件事：
     ① .pf-exit-btn —— 图标与文字并排（站内同款：危险操作那颗 .dc-reset-btn）；
     ② .pf-pinfoot —— 把 .dd-foot-inline 推到「剩余空隙之下」，并把内容底距换成
       --auth-btn-bottom：它贴的是 1008 定的那条主按钮基准线，与改密 / 绑定页那颗同一行
       （所以 .dd-foot-inline 自带的那份 --sab 内距在这里收掉，免得安全区被算两遍）。
   gate-ok：.pf-pinfoot 只由 wbCoarse() 为真时挂上（与 .dd-foot-inline 同一份约定），
   所以刻意不圈媒体查询——横屏手机 wbCoarse() 为真而 max-width:768 为假，圈起来会漏。
   内容长过一屏时 flex 的 auto 外边距自动归零，退回顺序排布，不裁不跳。
   ============================================================ */
.pf-exit-btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2); }
.pf-exit-btn svg { width: 18px; height: 18px; flex: none; }
.modal-card.pf-pinfoot .modal-body { display: flex; flex-direction: column; padding-bottom: var(--auth-btn-bottom); }
.modal-card.pf-pinfoot .modal-body > * { flex: none; }
.modal-card.pf-pinfoot .dd-foot-inline { margin-top: auto; padding-top: var(--sp-4); padding-bottom: 0; }
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   头像圆形化（手机端）+ 编辑资料页居中放大点头像
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* 编辑资料：头像独立浮于灰底画布居中，昵称卡在其下方 */
.pf-edit-avatar { flex-direction: column; align-items: center; gap: 0; margin-bottom: 0; padding: var(--sp-6) var(--sp-4) var(--sp-4); }
.user-avatar-xl { width: 92px; height: 92px; font-size: calc(36px * var(--fs-scale)); border-radius: var(--r-circle); }
.ep-avatar-btn {
  position: relative; display: block; padding: 0; border: none; background: transparent;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: transform var(--d-fast) ease;
}
.ep-avatar-btn:active { transform: scale(.955); }
.ep-avatar-cam {
  position: absolute; right: -2px; bottom: -2px;
  width: 30px; height: 30px; border-radius: var(--r-circle);
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-card); border: 1px solid var(--border);
  color: var(--text-3); box-shadow: var(--shadow-sm);
}
.ep-avatar-cam svg { width: 15px; height: 15px; }

/* ============================================================
   头像取景页（2.13）：圆框舞台 + 舞台里的图 + 缩放滑杆
   ------------------------------------------------------------
   页面壳整个走账户向导那一套（.acct-modal .acct-wizard：大标题落基准线、白卡装内容、
   主钮贴底），所以本页只添这三件新皮。
   · 舞台按「所见即所得」裁成圆形——头像本来就是圆的，给方框会骗人（四角其实不上屏）；
   · 图永远盖满舞台（位移在 JS 里夹住），touch-action:none 把手势交给我们、页面不跟着滚；
   · 只动 transform / width / height，与站内「动效只动 transform/opacity」同源；
   · 滑杆是原生 range（键盘左右键与读屏天然可用），皮按令牌上，不引第二套控件；
     只上 webkit 那一套前缀——承载体是 Chrome 与 Android WebView，Firefox 分支是白付体量。
   ============================================================ */
.av-card { display: flex; flex-direction: column; gap: var(--sp-3); }
.av-stage {
  position: relative; align-self: center;
  width: min(62vw, 260px); height: min(62vw, 260px);
  overflow: hidden; border-radius: var(--r-circle);
  background: var(--bg-muted); touch-action: none; cursor: grab;
}
.av-stage:active { cursor: grabbing; }
.av-img {
  position: absolute; left: 50%; top: 50%;
  display: block; max-width: none;
  transform: translate(-50%, -50%);
  pointer-events: none; /* 手势一律由舞台接：图自己不去接 pointer，少一半丢手 */
  user-select: none; -webkit-user-drag: none;
}
/* 1025：取景缩放滑杆删除——双指捏合已覆盖缩放，页面只留圆框舞台 + 重新选择图片。 */

/* ============================================================
   Klog 手机端间距规范 v1.0（2026-09-14 定稿，仅 ≤768px 生效）
   ------------------------------------------------------------
   4pt 基准网格，对齐 iOS HIG。后续所有手机端改动必须遵循：

     页面边距        16px   --content-px   页面内容左右
     卡片内距      16px横 / 14px纵  --card-pad（纵向为光学修正）
     组内间距        8px   同组元素：label↔控件、图标↔文字、标题↔内容
     卡片间距       12px   --card-gap    卡片列表、全部网格 gap
     模块间距       20px   --module-gap  工具栏↔列表、分区↔分区、hero↔卡区
     触控目标      ≥44px   --control-h；表单行 54、列表行 ≥44
     浮层规则       dock=底12+安全区 · toast=dock 上 96 · 弹窗底栏=横16+安全区

   桌面端维持自身 24/16 节奏，本规范只在手机端媒体查询内覆盖。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   待办左滑快捷操作层（移动端）：归档 / 删除
   参考 HarmonyOS 短信两段式：动作层从行右外随内容同步滑入；
   圆形图标按钮 → 完全展开时主操作（删除）膨胀为大胶囊，
   次操作（归档）保持小圆；内容平移同时渐隐。
   ============================================================ */
.swipe-acts { display: none; }
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   手机端全局 UI/UX 优化 v1.0（2026-09-15）
   ------------------------------------------------------------
   本块统一收口手机端的手感、层级、安全区与字号缺陷，
   只在 ≤768px / 触屏生效，桌面端零影响；视觉风格不动。
   遵循「手机端间距规范 v1.0」：4pt 网格、主操作 ≥44、
   icon 类 ≥38、表单行 54、列表行 ≥44、正文 ≥15、辅助 ≥12。
   ============================================================ */

/* ---- 1. 触摸目标：视觉尺寸克制，热区用 ::after 隐形扩张 ---- */
/* ≤768 手机端样式 → 06-mobile.css「---- 1. 触摸目标：视觉尺寸克制，热区用 ::after 隐形扩张 ----」 */

/* ---- 2. 层级：用户管理角色菜单曾被底部 dock（z60）压住 ---- */
/* ≤768 手机端样式 → 06-mobile.css「---- 2. 层级：用户管理角色菜单曾被底部 dock（z60）压住 ----」 */

/* ---- 3. 触屏按压反馈（1104 起视觉 hover 已全部在 @media (hover: hover) 内门控，
   触屏不再产生粘滞态，hover 复位已删；本块只保留 :active 即时按压） ---- */
@media (hover: none) {
  /* 即时按压反馈 */
  .cat-act:active, .sub-del:active, .dd-item:active, .pwd-toggle:active,
  .login-pop-x:active, .dc-reset-btn:active, .pf-seg button:active,
  .memo-pin:active, .rm-cal:active, .habit-today-row:active,
  .cat-row:active, .trash-row:active { background: var(--bg-hover); }
  .cat-swatch:active { transform: scale(.88); }
  .wd-btn:active, .habit-toggle-btn:active { transform: scale(.97); }
  .habit-card:active, .diary-card:active, .summary-card[data-goto]:active,
  .user-row:active { transform: scale(.985); }
  .rm-save-btn:active { transform: scale(.92); }
  .dd-item:active { color: var(--text-1); }
}

/* ---- 4. 视口与安全区：登录页 / 引导页贴 home 条、固定 px 高在横屏溢出 ---- */
/* ≤768 手机端样式 → 06-mobile.css「---- 4. 视口与安全区：登录页 / 引导页贴 home 条、固定 px 高在横屏溢出 ----」 */

/* ---- 5. 字号地板与 4pt 网格回归 ---- */
/* ≤768 手机端样式 → 06-mobile.css「---- 5. 字号地板与 4pt 网格回归 ----」 */

/* ---- 6. 弹窗链切换：详情→编辑/删除确认时新内容自顶部推入 ----
   （原「1802 行」声明为空块，此处补齐；与返回时的下移离场成对） */
/* ≤768 手机端样式 → 06-mobile.css */
@media (prefers-reduced-motion: reduce) {
  .modal-card.chain-in .modal-body > * { animation: none !important; }
  .modal-card.swap-fade .modal-body > *:not(.modal-ghost), .modal-card.fade-open .modal-body > *,
  .modal-card.swap-fade .modal-body > .modal-ghost, .modal-card .modal-head-ghost,
  .modal-card .modal-fadeout, .modal-card.is-stacked .modal-body > * { animation: none !important; }
}

/* ============================================================
   ≤380px 超窄屏收缩（必须排在所有 ≤768 规则之后才生效）
   规范：只收缩字号与 dock 宽度，间距与触控目标不回退。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   【样板 · 待确认】待办列表卡片化（仅手机端）
   ------------------------------------------------------------
   把「表格行 + 分隔线」升级为独立信息卡：
   · 卡片各自呼吸（--card-gap），去掉行分隔线的表感
   · 截止时间降为第二行等宽数字，创建日期让位（详情页仍完整可见）
   · 优先级星标补语义色：高=警示红 / 中=正文灰 / 低=禁用灰
   · 完成态整卡降权重，与未完成拉开层次
   不满意可整块删除，不影响上面的规范收口。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   【推广】卡片列表语言统一：备忘 / 事件 / 习惯 / 日记
   ------------------------------------------------------------
   四张列表的卡壳（白底 + 1px 描边 + radius-card + 14/16 内距 +
   shadow-card）本就与待办样板一致，此处补齐的是文字层级与节奏：
   · 主标题一律 16px（与待办标题同档），事件名此前已是 16px
   · 次级信息一律 12px 地板，数字统一 tabular-nums
   · 列表间距回归 --card-gap（事件列表原本 10px 脱离 4pt 网格）
   · 按压缩放全部统一 .985
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   确认类弹窗外壳（删除 / 清空 / 重置 / 退出 / 容量 / 数据异常）
   ------------------------------------------------------------
   线性描边图标圆底 → 对象名 → 说明，三段纵向居中；
   桌面沿用窄卡，手机端在全屏页里垂直居中、底栏转通栏胶囊。
   危险色只取站点已有的 --tag-bad-* / --danger（左滑删除胶囊同款红）。
   ============================================================ */
.cf-body {
  display: flex; flex-direction: column; align-items: center;
  gap: var(--sp-2); text-align: center;
}
.cf-mark {
  width: 52px; height: 52px; border-radius: var(--r-circle); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-muted); color: var(--text-3);
}
.cf-mark svg { width: 24px; height: 24px; }
.cf-mark.is-danger { background: var(--tag-bad-bg); color: var(--tag-bad-fg); }
.cf-headline {
  font-size: calc(17px * var(--fs-scale)); font-weight: var(--fw-semibold); color: var(--text-1);
  line-height: 1.45; word-break: break-word; max-width: 24em;
}
.cf-headline b { font-weight: var(--fw-bold); }
.cf-msg {
  font-size: var(--fs-caption); color: var(--text-3); line-height: 1.7;
  max-width: 30em; word-break: break-word;
}
.cf-msg b { color: var(--text-1); font-weight: var(--fw-medium); }

/* 手机端：确认弹窗改为与滚轮日期选择器 / 选项卡片同款的底部抽屉
   （.wp-mask / .wp-sheet 一套参数：24 圆角、18/16 内距、自下而上 .32s、
   标题居中 17px 粗、底栏 50px 双胶囊 flex 1 / 1.5） */

/* 手机端确认抽屉排版 v1.1（cfSheet 独立抽屉）
   ------------------------------------------------------------
   历史上四级内容挤在 gap:10 里、说明与按钮间距实测为 0，读起来一坨。
   现在按 4pt 网格拉开节奏，并让「对象名」成为唯一主标题：
   带 headline 时把 .wp-title 降为 13px 眉标（:has 判定，退出 / 重置等
   没有对象名的确认仍保持 17px 粗标题）。数值与下方 .cf-modal 成对维护。
   选择器一律带 .cf-sheet：.wp-title / .wp-foot 与滚轮选择器、选项卡片共用。 */
/* ≤768 手机端样式 → 06-mobile.css */
/* ≤768 手机端样式 → 06-mobile.css */

@media (prefers-reduced-motion: reduce) {
  .cf-modal .cf-mark, .cf-sheet .cf-mark { animation: none; }
  .cf-modal, .cf-modal.closing { animation: none; }
}

/* ============================================================
   dock 瘦身：概览退出底部导航（4 tab + 加号）
   回归路径：点 dock 首席「首页」
   （1010g：原来这句写的是「点顶栏 logo」——那只 logo 已撤，改指首席；
     1010h：连点两下回首页也随之退役）
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   四页排版优化 v1.0（备忘详情 / 备忘编辑 / 已归档 / 回收站）
   ------------------------------------------------------------
   全部收口到站内已定稿的两套语言：详情＝iOS 分组卡片（灰底画布 + 白色
   圆角卡 + 图标行组，同 .dd-modal），表单＝.wbf-modal + .fg-card。
   只补三类硬伤：
   ① 触控目标：弹窗返回键 28px、恢复按钮 34px、置顶开关行 37px；
   ② 可读性：详情时间戳原为 --text-disabled 12px 灰字（对比度≈1.5:1），
      改走图标行组；正文 14.4px → 15px 地板；
   ③ 分组与描边：归档/回收站条目浮在灰底上没有卡片、Markdown 分段控件
      白底贴白卡完全看不见、搬家后的开关行带着 .switch-row 的小内衬灰底。
   选择器坑（与历史教训同类）：mobFormify 把 .check-line 原节点升级成
   .fg-switch.switch-row 时，两个类挂在同一元素上，
   「.fg-card .fg-switch .switch-row」是后代选择器，永远匹配不到 → 必须写复合。
   ============================================================ */

/* ---- 弹窗头部返回钮：全站唯一语言（v1.4，2026-09-23）----
   原为「详情 + 编辑」专属的 36 白圆钮（.dd-modal.dd-notitle / .wbf-modal），
   个人中心下的数据概览 / 关于 / 小票机 / AI 录入 / 提醒自检仍是裸 chevron，
   同一屏出现两种返回钮。现统一收进这一条：白圆 + ::before 外扩热区到 48px
   （规范 icon 类 ≥38），桌面 >768 不命中（返回钮本身只在手机端显示）。
   位置必须留在此处、且带 .modal-card 抬特异性（0,3,0）：文件更靠前的基础规则
   .modal-back(0,1,0) 与 .modal-back:hover(0,2,0) 都会来抢背景与尺寸。 ---- */
/* ≤768 手机端样式 → 06-mobile.css */

/* ---- 备忘详情：hero 内的标题与置顶钮同轴 ---- */
.md-hero-top { display: flex; align-items: flex-start; gap: var(--sp-3); }
.md-hero-top .dd-hero-name { flex: 1; min-width: 0; }
.md-hero-tags { margin-top: var(--sp-3); }
/* 置顶：裸图标升级为圆形幽灵钮（44px 触控，选中态实心黑） */
#dt-pin.memo-pin {
  width: 44px; height: 44px; flex: 0 0 44px; border-radius: var(--radius-pill);
  background: var(--bg-muted); color: var(--text-3);
}
#dt-pin.memo-pin svg { width: 18px; height: 18px; }
#dt-pin.memo-pin.on { background: var(--primary); color: var(--on-primary); }
#dt-pin.memo-pin.on svg { fill: none; }
/* 正文卡：白卡自带描边会再套一层框，这里拍平成卡片本身的内容 */
.md-doc { padding: 2px 0; }
.md-doc .md-body {
  background: transparent; border: none; border-radius: 0;
  padding: var(--sp-4); min-height: 0; max-height: none; overflow: visible;
  font-size: calc(15px * var(--fs-scale)); line-height: 1.8; color: var(--text-2);
}
.md-doc .md-body h1 { font-size: calc(18px * var(--fs-scale)); }
.md-doc .md-body h2 { font-size: calc(16px * var(--fs-scale)); }
.md-doc .md-body code { font-size: calc(13px * var(--fs-scale)); }
.md-doc .md-empty-hint { color: var(--text-4); }

/* ---- 备忘编辑：分段控件、开关行、正文输入 ---- */
/* ≤768 手机端样式 → 06-mobile.css「---- 备忘编辑：分段控件、开关行、正文输入 ----」 */

/* ---- 回收站 / 已归档 · 卡片触控档（手机端卡更大、行内按钮 ≥38） ---- */
.tr-main { flex: 1; min-width: 0; }
.trash-row .trash-title {
  font-size: calc(15px * var(--fs-scale)); font-weight: var(--fw-medium); color: var(--text-1); line-height: 1.45;
  white-space: normal;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.tr-meta { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-1); }
.tr-acts { display: flex; align-items: center; gap: var(--sp-1); flex-shrink: 0; }
/* ≤768 手机端样式 → 06-mobile.css */
@media (prefers-reduced-motion: reduce) {
  .trash-row:active { transform: none; }
}

/* ============================================================
   回顾详情 · 编辑排版 v2（2026-09-16）
   外壳走站内既有 .dd-modal（灰底画布），内容拆成白色圆角卡，
   与灰色背景形成图底分离；仅作用于 .diary-detail，待办/习惯
   详情共用类（detail-hero / detail-kv / detail-meta-line）不受影响。
   基调：黑白杂志——封面大日期 + 编号时间轴卡片 + 版权页脚
   ============================================================ */
.diary-detail { position: relative; color: var(--text-1); }

/* 封面卡：心情胶囊 + 眉标 + 大日期 */
.diary-detail .dd-cover {
  background: var(--bg-card); border-radius: var(--r-5);
  padding: var(--sp-4) var(--sp-4) var(--sp-6); box-shadow: var(--shadow-card);
}
/* 心情胶囊徽章同款语言：小记封面与事件详情英雄区共用（.dd-mood 单源，勿另起一套） */
.diary-detail .dd-mood, .dd-hero-head .dd-mood {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  height: 24px; padding: 0 var(--sp-2) 0 var(--sp-2);
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  background: var(--bg-card);
  font-size: var(--fs-micro); color: var(--text-3); letter-spacing: .02em;
}
.diary-detail .dd-mood { margin-bottom: var(--sp-4); }
.diary-detail .dd-mood-dot, .dd-hero-head .dd-mood-dot {
  width: 8px; height: 8px; border-radius: var(--r-circle);
  background: var(--mood, var(--text-4));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--mood, transparent) 18%, transparent);
}
.diary-detail .dd-mast { position: relative; }
.diary-detail .dd-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-11); letter-spacing: .28em; text-transform: uppercase;
  color: var(--text-4); margin-bottom: var(--sp-3);
}
.diary-detail .dd-dateline { display: flex; align-items: baseline; gap: var(--sp-3); }
.diary-detail .dd-day {
  font-family: var(--font-mono); font-weight: var(--fw-bold);
  font-size: 68px; line-height: .86; letter-spacing: -.04em;
  color: var(--text-1); font-variant-numeric: tabular-nums;
}
.diary-detail .dd-my {
  display: inline-flex; align-items: baseline; gap: var(--sp-3);
  font-size: var(--fs-body); color: var(--text-3); letter-spacing: .02em;
}
.diary-detail .dd-week {
  font-style: normal; padding-left: var(--sp-2); position: relative;
  color: var(--text-4); font-size: var(--fs-caption);
}
.diary-detail .dd-week::before {
  content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 1px; height: 12px; background: var(--border-strong);
}

/* 三问：每条一张白色卡，编号 + 短横刻度作时间轴导轨 */
.diary-detail .dd-entries { display: flex; flex-direction: column; gap: var(--sp-3); margin-top: var(--sp-3); }
.diary-detail .dd-entry {
  position: relative; display: grid;
  grid-template-columns: 40px 1fr; gap: var(--sp-3);
  background: var(--bg-card); border-radius: var(--radius-card-m); box-shadow: var(--shadow-card);
  padding: var(--sp-4);
}
.diary-detail .dd-no {
  font-family: var(--font-mono); font-weight: var(--fw-semibold);
  font-size: calc(13px * var(--fs-scale)); letter-spacing: .04em;
  color: var(--text-4); padding-top: 2px;
  font-variant-numeric: tabular-nums;
}
.diary-detail .dd-no::after {
  content: ''; display: block; width: 14px; height: 1px;
  background: var(--border-strong); margin-top: var(--sp-1);
}
.diary-detail .dd-label {
  margin: 0 0 var(--sp-2);
  font-family: var(--font-mono); font-size: var(--fs-11); font-weight: var(--fw-medium);
  letter-spacing: .22em; text-transform: uppercase; color: var(--text-4);
}
.diary-detail .dd-text {
  font-size: calc(15px * var(--fs-scale)); line-height: 1.8; color: var(--text-1);
  white-space: pre-wrap; word-break: break-word; letter-spacing: .01em;
}
.diary-detail .dd-text .dd-empty { color: var(--text-disabled); font-style: italic; }
.diary-detail .dd-entry.is-empty .dd-text { color: var(--text-disabled); }
.diary-detail .dd-entry.is-empty .dd-no { color: var(--text-disabled); }
.diary-detail .dd-entry.is-empty { background: color-mix(in srgb, var(--bg-card) 55%, var(--bg-page)); box-shadow: none; }

/* 版权页脚：细字直接落在灰底上 */
.diary-detail .dd-colophon {
  display: flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-4); padding-left: var(--sp-1);
  font-family: var(--font-mono); font-size: var(--fs-11);
  letter-spacing: .1em; color: var(--text-4);
}
.diary-detail .dd-rule { flex: 0 0 24px; height: 1px; background: var(--text-4); opacity: .5; }

/* 载入 stagger：封面 → 三问 → 页脚自上而下轻入，幅度克制 */
@media (prefers-reduced-motion: no-preference) {
  .diary-detail .dd-cover    { animation: dd-in var(--d-enter) var(--ease-enter) both; }
  .diary-detail .dd-entry    { animation: dd-in var(--d-enter) var(--ease-enter) both; }
  .diary-detail .dd-entry:nth-of-type(1) { animation-delay: var(--d-micro); }
  .diary-detail .dd-entry:nth-of-type(2) { animation-delay: var(--d-fast); }
  .diary-detail .dd-entry:nth-of-type(3) { animation-delay: var(--d-modal); }
  .diary-detail .dd-colophon { animation: dd-in var(--d-enter) var(--ease-enter) var(--d-toast) both; }
}
@keyframes dd-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/* 手机端 ≤768：遵循手机端间距规范 v1.0（卡片内距/正文地板/触控目标） */
/* ≤768 手机端样式 → 06-mobile.css「手机端 ≤768：遵循手机端间距规范 v1.0（卡片内距/正文地板/触控目标）」 */

/* ============================================================
   日记配图 · 每日小记「今日剪贴簿」
   ------------------------------------------------------------
   · 编辑态 = 方形网格（4 列，最多 9 张）：不横向滚动，格子才敢吃
     touch-action: pan-y，长按拖动排序才不被原生手势抢走
   · 详情态 = 横向胶片条：只读滑动，边缘渐隐复用 tgf-l / tgf-r 约定
   · 看图台 = 全站唯一的整屏黑底层（.iv-mask，z 高于弹窗与小票预览、低于 toast）
   手机端遵循「手机端间距规范 v1.0」：4pt 网格、格内 --card-gap、
   主触控 ≥44、icon 类热区 ≥38（小圆点用 ::after 扩热区，不放大图形）
   ============================================================ */

/* ---------- 编辑态：方形网格 ---------- */
.dg-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--card-gap);
}
.dg-grid .dg-cell { touch-action: pan-y; }   /* 竖向仍可滚表单，横向交给拖排 */
.dg-cell {
  position: relative; aspect-ratio: 1 / 1; margin: 0;
  border-radius: var(--r-3); overflow: visible;
  background: var(--bg-count); cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.dg-cell img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  border-radius: var(--r-3); background: var(--bg-count);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--text-1) 9%, transparent);
  pointer-events: none;                     /* 点击一律交给格子本身 */
  -webkit-user-drag: none; user-select: none;
}
/* 取不到图的一格：说明白「失效/没取到」并留出点按动作，绝不是一片空白当坏了 */
.dg-dead {
  position: absolute; inset: 0; z-index: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px; padding: var(--sp-1); text-align: center; border-radius: var(--r-3);
  background: var(--bg-count); color: var(--text-4);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--text-1) 9%, transparent);
}
.dg-dead b { font-size: var(--fs-10); font-weight: var(--fw-semibold); line-height: 1.25; }
.dg-dead i { font-style: normal; font-size: var(--fs-micro); color: var(--text-4); opacity: .72; }
.dg-cell.is-dead img { visibility: hidden; }
.dg-grid .dg-dead i { display: block; }
.dg-film .dg-dead i { display: none; }      /* 胶片条格子小，只留「图片已失效」一行 */
/* 照片叠放控件（§1 材质豁免「图片上的幽灵」：删除钮/本机点永远压在用户照片上，
   照片内容不可控 → 控件恒深底白 icon，两档主题都不翻，与 .iv 影院同语言） */
.dg-del {
  position: absolute; top: 5px; right: 5px;
  width: 22px; height: 22px; padding: 0; border: 0; border-radius: var(--r-circle);
  background: rgba(17, 17, 17, .66); color: var(--white); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  opacity: 0; transform: scale(.82);
  transition: opacity var(--d-fast) ease, transform var(--d-base) var(--ease-float), background var(--d-fast) ease;
}
.dg-del svg { width: 11px; height: 11px; }
.dg-del::after { content: ''; position: absolute; inset: -9px; }   /* icon 热区 ≥38 */
.dg-cell:focus-within .dg-del { opacity: 1; transform: none; }
@media (hover: hover) { .dg-cell:hover .dg-del { opacity: 1; transform: none; } }
@media (hover: hover) { .dg-del:hover { background: rgba(17, 17, 17, .84); } }
.dg-del:active { transform: scale(.92); }

/* 「仅存本机」小圆点（编辑态为纯提示，详情态才可点按补传） */
.dg-local {
  position: absolute; left: 7px; bottom: 7px;
  width: 8px; height: 8px; border-radius: var(--r-circle);
  background: var(--white); box-shadow: 0 0 0 1.5px rgba(17, 17, 17, .6); /* 照片上白点黑环＝材质色（同 .dg-del） */
  pointer-events: none;
}
.dg-add {
  aspect-ratio: 1 / 1; min-height: 56px;
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; padding: 0; border: 1.5px dashed var(--border-strong); border-radius: var(--r-3);
  background: transparent; color: var(--text-4); cursor: pointer;
  font-size: var(--fs-micro); letter-spacing: .04em;
  transition: border-color var(--d-base) ease, color var(--d-base) ease, background var(--d-base) ease, transform var(--d-base) var(--ease-float);
}
.dg-add svg { width: 18px; height: 18px; }
@media (hover: hover) { .dg-add:hover { border-color: var(--text-1); color: var(--text-1); background: color-mix(in srgb, var(--text-1) 4%, transparent); } }
.dg-add:active { transform: scale(.96); }
.dg-grid.is-busy { opacity: .62; pointer-events: none; }
.dg-grid.is-busy .dg-add { animation: dg-breathe 1.1s ease-in-out infinite; }

/* 拖起态：抬一层阴影，其余格子瞬时让位（避免多点同时缓动造成的抖动） */
.dg-cell.is-drag { z-index: 3; cursor: grabbing; }
.dg-cell.is-drag img {
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--text-1) 9%, transparent),
              0 12px 26px rgba(17, 17, 17, .24);
}
.dg-grid.is-drag { cursor: grabbing; }
@keyframes dg-breathe { 0%, 100% { opacity: .6; } 50% { opacity: 1; } }

/* ---------- 详情态：横向胶片条（落在灰底上，图片自身即视觉主体） ---------- */
.dd-film { margin-top: var(--module-gap); }
.dd-film-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3);
  padding: 0 var(--sp-1) var(--sp-2);
}
.dd-film-eyebrow {
  font-family: var(--font-mono); font-size: var(--fs-11); font-weight: var(--fw-medium);
  letter-spacing: .22em; text-transform: uppercase; color: var(--text-4);
}
.dd-film-count {
  font-family: var(--font-mono); font-size: var(--fs-11); color: var(--text-4);
  font-variant-numeric: tabular-nums;
}
.dg-film {
  overflow-x: auto; overflow-y: hidden;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding: 2px 0 var(--sp-1);
}
.dg-film::-webkit-scrollbar { display: none; }
.dg-film-track { display: flex; gap: var(--sp-3); width: max-content; }
.dg-film .dg-cell { flex: 0 0 96px; width: 96px; cursor: zoom-in; }
.dg-film .dg-cell img { border-radius: var(--r-3); }
.dg-film .dg-local-dot {
  position: absolute; right: 6px; bottom: 6px;
  width: 22px; height: 22px; padding: 0; border: 0; border-radius: var(--r-circle);
  background: rgba(17, 17, 17, .62); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--d-base) ease, transform var(--d-base) var(--ease-float);
}
.dg-film .dg-local-dot::after { content: ''; position: absolute; inset: -9px; }   /* 热区 40 */
.dg-film .dg-local-dot span {
  width: 7px; height: 7px; border-radius: var(--r-circle); background: #fff;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .5);
}
@media (hover: hover) { .dg-film .dg-local-dot:hover { background: rgba(17, 17, 17, .8); } }
.dg-film .dg-local-dot:active { transform: scale(.9); }
.dg-film .dg-local-dot.is-busy { animation: dg-breathe 1s ease-in-out infinite; }
/* 边缘渐隐：与站内 chip-scroll 同一套 JS 挂类约定 */
.dg-film.tgf-l { -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 26px); mask-image: linear-gradient(90deg, transparent 0, #000 26px); }
.dg-film.tgf-r { -webkit-mask-image: linear-gradient(270deg, transparent 0, #000 26px); mask-image: linear-gradient(270deg, transparent 0, #000 26px); }
.dg-film.tgf-l.tgf-r {
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 26px, #000 calc(100% - 26px), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 26px, #000 calc(100% - 26px), transparent 100%);
}

/* ---------- 小记图片 · 本机媒体缓存抽屉（个人中心「存储」组 → 抽屉） ----------
   纵向节奏不写页面级 magic number：读数→主操作吃 --pfg-label-gap，主操作→策略卡由
   .pfg 自己的 --pfg-gap 管，卡→卡外说明由 .pfg-tip 的 --pfg-tip-gap 管，三段各归一处。
   抽屉本体已有 16px 横向内距，卡内行再吃一份 --card-pad 会叠成 32px——旧写法是逐条
   `padding-left:0 + margin:0 14px` 硬压（14px 无出处）。正解是把这一族卡片的内距令牌
   就地降到 --sp-3：行、说明、通栏分段器一起跟着走，谁也不用再被单独拽一次。 */
.mc-sheet { --card-pad: var(--sp-3); padding-bottom: calc(var(--sp-4) + var(--sab)); }
.mc-body { display: flex; flex-direction: column; }
/* 读数两行讲的是同一件事（本机有什么 / 还缺什么），2px 归组——与 .pfg-t-2 标题与说明同档。
   两行都带张数与体积：等宽数字让读数上下对齐，不随字宽跳。 */
.mc-read { display: flex; flex-direction: column; gap: 2px; font-variant-numeric: tabular-nums; }
.mc-acct { margin: 0; font-size: var(--fs-body); line-height: 1.45; color: var(--text-1); }
.mc-need { margin: 0; font-size: var(--fs-label); line-height: 1.45; color: var(--text-4); text-wrap: balance; }
/* .wp-btn-ok 自带 flex: 1.5（为 .wp-foot 那一行准备的横向权重）。这里是纵向 flex 容器的子项，
   那枚 flex-basis:0 会作用到**高度**上，钮会被压成 0 高——先把它退回 none。
   站主口径：这颗「全部存到本机」收小一档、去掉圆角（0＝把圆角关掉的复位语境，非新造型），
   不再是大圆角胶囊。写成 .mc-sheet .mc-fetch 是为了稳赢 .wp-btn-ok 的同特异度，不赌源码先后。 */
.mc-sheet .mc-fetch { flex: none; height: 42px; border-radius: 0; font-size: calc(14px * var(--fs-scale)); margin-top: var(--pfg-label-gap); }
.mc-prog { margin: var(--pfg-label-gap) 0 0; font-size: var(--fs-label); line-height: 1.45; color: var(--text-4); font-variant-numeric: tabular-nums; }
/* 两行字档进了抽屉：行上下各补一口气，否则标题、说明、发丝线三样贴成一团（与 nt-page 同值） */
.mc-body .pfg-row:has(.pfg-t-2) { padding-top: var(--pfg-label-gap); padding-bottom: var(--pfg-label-gap); }

/* ---------- 列表卡片：相机张数角标 ---------- */
.diary-head-r { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.diary-imgs {
  display: inline-flex; align-items: center; gap: 3px;
  height: 22px; padding: 0 var(--sp-2); border-radius: var(--radius-pill);
  background: var(--bg-muted); color: var(--text-4);
  font-size: var(--fs-micro); position: relative;
}
.diary-imgs svg { width: 12px; height: 12px; }
.diary-imgs b { font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
.diary-imgs-local {
  width: 5px; height: 5px; border-radius: var(--r-circle); margin-left: 1px;
  background: var(--text-3); box-shadow: 0 0 0 1.5px var(--bg-muted);
}

/* ---------- 看图台：整屏黑底（接入 WbBack 返回栈） ---------- */
.iv-mask {
  position: fixed; inset: 0; z-index: 9200;
  background: rgba(8, 8, 10, .985);
  opacity: 0; transition: opacity var(--d-modal) ease;
  touch-action: none; -webkit-user-select: none; user-select: none;
}
.iv-mask.is-open { opacity: 1; }
.iv-mask.is-closing { opacity: 0; }
/* 下拉关闭时跟手压暗（--iv-fade 由 JS 实时写入） */
.iv-mask[style*="--iv-fade"] { opacity: var(--iv-fade, 1); }
.iv { position: absolute; inset: 0; display: flex; flex-direction: column; }
.iv-bar {
  flex: 0 0 auto; display: flex; align-items: center; gap: var(--sp-3);
  padding: calc(var(--sp-2) + var(--sat)) var(--sp-3) var(--sp-2);
  color: rgba(255, 255, 255, .9);
}
.iv-x {
  flex: 0 0 auto; width: 38px; height: 38px; padding: 0; border: 0; border-radius: var(--r-circle);
  background: rgba(255, 255, 255, .14); color: #fff; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--d-base) ease;
}
@media (hover: hover) { .iv-x:hover { background: rgba(255, 255, 255, .26); } }
.iv-x svg { width: 17px; height: 17px; }
.iv-meta { flex: 1; min-width: 0; display: flex; align-items: baseline; justify-content: center; gap: var(--sp-3); }
.iv-cnt {
  font-family: var(--font-mono); font-size: var(--fs-12); letter-spacing: .12em;
  font-variant-numeric: tabular-nums; color: rgba(255, 255, 255, .92);
}
.iv-title {
  font-size: var(--fs-caption); color: rgba(255, 255, 255, .58);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.iv-flag {
  flex: 0 0 auto; min-width: 38px; text-align: right;
  font-family: var(--font-mono); font-size: var(--fs-10); letter-spacing: .1em;
  color: rgba(255, 255, 255, .5);
}
.iv-stage {
  flex: 1; min-height: 0; position: relative; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  padding: var(--sp-1) var(--sp-3) calc(var(--sp-6) + var(--sab));
}
/* 翻页轨道：每一页并排摆好（100% 宽一页），跟手与吸附都只动这一条；
   缩放/平移单独作用在当前那张 <img> 上，两套位移互不打架。
   1016：gap 止「静置露邻图」，落笔按每页实距（stride()）。 */
.iv-track {
  display: flex; align-items: center; height: 100%; width: 100%;
  gap: var(--card-gap);
  will-change: transform;
}
.iv-slide {
  flex: 0 0 100%; height: 100%; margin: 0; position: relative;
  display: flex; align-items: center; justify-content: center;
}
.iv-img {
  display: block; max-width: 100%; max-height: 100%;
  border-radius: var(--r-1); background: #0c0c0e; /* 看图台「黑影院」舞台底＝材质色（§1 豁免），两档都暗 */
  box-shadow: 0 24px 60px rgba(0, 0, 0, .5);
  will-change: transform;
  -webkit-user-drag: none;
}
/* 取不到的那一页：说清楚，并给一次重取机会（点按见 app.js 的 stage click） */
.iv-dead {
  display: none; position: absolute; inset: 0;
  flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-1); padding: 0 var(--sp-7); text-align: center;
}
.iv-slide.is-dead .iv-dead { display: flex; }
.iv-slide.is-dead .iv-img { visibility: hidden; }
.iv-dead b { font-size: var(--fs-caption); font-weight: var(--fw-semibold); color: rgba(255, 255, 255, .86); }
.iv-dead i { font-style: normal; font-size: var(--fs-micro); color: rgba(255, 255, 255, .45); }
.iv-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 44px; height: 44px; padding: 0; border: 0; border-radius: var(--r-circle);
  background: rgba(255, 255, 255, .1); color: #fff; cursor: pointer;
  display: none; align-items: center; justify-content: center;
  transition: background var(--d-base) ease, opacity var(--d-base) ease;
}
.iv-nav svg { width: 22px; height: 22px; }
@media (hover: hover) { .iv-nav:hover { background: rgba(255, 255, 255, .22); } }
.iv-prev { left: 16px; } .iv-next { right: 16px; }
.iv-mask.is-first .iv-prev, .iv-mask.is-last .iv-next { opacity: .25; pointer-events: none; }
@media (min-width: 769px) {
  .iv-nav { display: inline-flex; }
}
.iv-mask.is-zoomed .iv-nav { opacity: 0; pointer-events: none; }

/* ---------- 手机端 ≤768（间距规范 v1.0：格内距吃 --card-gap、图标热区 ≥38） ---------- */
/* ≤768 手机端样式 → 06-mobile.css「---------- 手机端 ≤768（间距规范 v1.0：格内距吃 --card-gap、图标热区 ≥38） 」 */

/* ---------- 超窄屏 ≤380：只收格子与缩略尺寸，间距与热区不回退 ---------- */
/* ≤768 手机端样式 → 06-mobile.css「---------- 超窄屏 ≤380：只收格子与缩略尺寸，间距与热区不回退 ----------」 */

/* ---------- 减动效：呼吸与位移全部归零 ---------- */
@media (prefers-reduced-motion: reduce) {
  .dg-add, .dg-cell.is-drag img, .dg-film .dg-local-dot,
  .iv-mask, .iv-track, .iv-img, .iv-nav { transition: none !important; animation: none !important; }
  .dg-grid.is-busy .dg-add { animation: none; }
}

/* 详情入场：胶片条接在三问之后、版权页脚之前，节奏与既有 dd-in 一致 */
@media (prefers-reduced-motion: no-preference) {
  .diary-detail .dd-film { animation: dd-in var(--d-enter) var(--ease-enter) var(--d-modal) both; }
}

/* ============================================================
   回顾编辑 · 桌面端与详情同一套「灰底画布 + 白色圆角卡」语言
   （≤768 仍走 mobFormify 的 .wbf-modal + .fg-card，本块不介入）
   ============================================================ */
@media (min-width: 769px) {
  .diary-form { background: var(--bg-page); }
  .diary-form .modal-body { padding-bottom: var(--sp-6); }

  /* 顶层字段组各成一张白卡（嵌套在 head 行内的 .field 不重复套壳） */
  .diary-form .modal-body > .field,
  .diary-form .modal-body > .field-row {
    background: var(--bg-card); border-radius: var(--radius-card-m); box-shadow: var(--shadow-card);
    padding: var(--sp-4); margin-bottom: var(--sp-3);
  }
  .diary-form .modal-body > .form-error { margin: 0; padding: 0 var(--sp-1); }
  .diary-form .field-row .field { margin-bottom: 0; }

  /* 字段标题收进全站唯一档（1104 站主令）。从前这里是第四档：等宽 + .18em 字距 +
     大写 + --fs-11 + text-4 的「眉标」，与隔壁待办/备忘的标题完全不同形。
     现在只保留日记自己的下间距，字体/字重/墨色全部回落到 03 的 .field > label。 */
  .diary-form .field > label,
  .diary-form .field-row > div > label {
    margin-bottom: var(--sp-3);
  }

  /* 输入材质 / 状态 / 字号已收口到「输入框规范 v2 · 编辑表单族样板」（本文件后段）：
     原软底 --bg-soft + 10px 圆角 + 16px 字号就地退役——它是桌面端唯一
     一只先跑的「井」，收编后五个表单共用同一组 --fld-* 参数 */
  .diary-form textarea.form-input { padding: var(--sp-3); min-height: 68px; line-height: 1.7; resize: vertical; }

  /* 头部：日期定宽 + 心情自适应（心情段皮肤归 seg-slide v2 / mood-seg，桌面同 34px 控制档） */
  .diary-form .field-diary-head { display: grid; grid-template-columns: 176px 1fr; gap: var(--sp-4); align-items: start; }
  .diary-form .diary-bring { margin-top: var(--sp-3); gap: var(--sp-3); }
  .diary-form .diary-bring .btn-link {
    font-size: var(--fs-caption); color: var(--text-3);
    padding: var(--sp-1) var(--sp-2); border: 1px solid var(--border); border-radius: var(--radius-pill);
    transition: border-color var(--transition-fast), color var(--transition-fast);
  }
  @media (hover: hover) { .diary-form .diary-bring .btn-link:hover { border-color: var(--border-strong); color: var(--text-1); } }
  .diary-form .field-hint { margin-top: 0; }
}

/* ============================================================
   手机端编辑表单统一规范 v1.0（2026-09-16，仅 ≤768px）
   ------------------------------------------------------------
   五个编辑弹窗（待办 / 事件 / 回顾 / 备忘 / 习惯）收口到同一套语言，
   基准取自已定稿的事件页：灰底画布 + 语义分组白卡。卡内只允许两种行：

     行式 .fg-row    单值控件（文本 / 下拉 / 日期 / 开关）
                     54px 行高、左标签右值、无边框、行间发丝线
     堆叠 .fg-stack  多行或复合控件（正文 / 子任务 / 心情 / 农历 / 色板）
                     上标签（13px --text-4）下「井」

   本块修掉的三类不统一（改前实测）：
     ① 分组：待办一张 895px 巨卡、回顾一张 726px 巨卡 vs 事件 4 张语义卡
        → mobFormify 按字段 data-fg 分组，桌面端 .fg-card 仍是 display:contents 零影响；
     ② 同类控件三种长相：日期在事件＝右对齐行、在回顾＝描边盒 44px 左对齐、
        在待办＝描边盒 40px 居中；下拉同理 → 行式一律无边框右对齐；
     ③ 「井」不存在：正文井用 --bg-soft(#FAFBFC) 落在白卡上几乎看不见，
        下拉 / 日期 / 子任务 / 添加步骤用 --bg-page + 1px 描边 + 4px 直角
        → 统一 --bg-muted 衬底 + 12px 圆角 + 无边框（与卡片 16px 圆角成层级）。

   选择器纪律：本块排在全部 ≤768 基线块之后，且与旧规则同特异性或更高
   （如 .fg-card .fg-stack .sub-add .form-input 必须写满四级，否则被 2719 行压死）。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* ---- ⑥ 待办表单收口（实测两处「乱」）：
   a) 重复的附加行「每 [3] [天][周] 重复一次 / 每月 [X] 号」：数字 input 被
      .fg-card .fg-row .form-input 的 flex:1 + 右对齐 + 54px 拉满整行，「每」与数字间
      出现大空洞、还撑高行 → 收回紧凑居中小井。
   b) 「具体时间」的 dp-display 是 field 直接子级（日期是 enhanceDates 包在 .date-wrap 里，
      不受影响），继承 .fg-row .dp-display{width:100%} 触发 flex-wrap，「未设置」掉到第二行
      孤零零右对齐 → 让它与标签同行、值右对齐。 ---- */
/* ≤768 手机端样式 → 06-mobile.css */

/* 描述收起态（手机端）：整行按行式呈现，右侧「＋ 填写描述」是无框幽灵入口 */
/* ≤768 手机端样式 → 06-mobile.css「描述收起态（手机端）：整行按行式呈现，右侧「＋ 填写描述」是无框幽灵入口」 */

/* ---- ⑦ 抽屉入口右箭头提示（0929）：
   移动端表单里每一枚 .sel-btn / .dp-display（分类 / 重复 / 优先级 / 类型 /
   截止日 / 具体时间 / 农历日月…）点开都是底部抽屉（选择卡片 / 滚轮），
   桌面那条「下拉小三角」在手机上语义错了 → 统一换成站内右向 chevron，
   提示「可进入」。形状沿用 .pfg-chev（个人中心跳转行）的箭头语言，
   只是按站内既有做法用 border 画，跟原来那只 border 三角同一实现口径。
   仅 ≤768 生效，桌面维持原下拉小三角不动。 ---- */
/* ≤768 手机端样式 → 06-mobile.css */

/* 子任务手柄 / 行内编辑 / 描述入口：两端共用（拖动排序在桌面端同样可用） */
.sub-handle {
  flex: 0 0 22px; width: 22px; height: 32px; padding: 0; border: none; background: transparent;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--text-4); opacity: .55; cursor: grab;
  touch-action: none; -webkit-user-select: none; user-select: none;
}
.sub-handle svg { width: 14px; height: 14px; }
@media (hover: hover) { .sub-handle:hover { opacity: .85; } }
.sub-handle:active, .sub-row.is-dragging .sub-handle { cursor: grabbing; opacity: 1; }
/* 拖动三段（§4.3b 公共标准）：浮起皮肤与手机端 06 那条同参，此前桌面只有 z-index，
   拖起来看不出「拿离了纸面」 */
.sub-row.is-dragging {
  position: relative; z-index: 3;
  background: var(--bg-card); border-bottom-color: transparent;
  border-radius: var(--r-3); box-shadow: var(--shadow-float);
}
.is-dragging-mode .sub-row.is-dragging { transition: none; } /* 拖起那行必须逐帧跟手 */
/* 行内标题：无边框输入框，看起来就是这行文字本身，随时可改（含已完成的步骤） */
.sub-name {
  flex: 1; min-width: 0; border: none; background: transparent; box-shadow: none; outline: none;
  padding: 0; font-family: var(--font-sans); font-size: var(--fs-caption); color: var(--text-1);
  text-align: left; height: auto; min-height: 24px;
}
.sub-row.is-done .sub-name { color: var(--text-4); text-decoration: line-through; }
.desc-field .desc-toggle { display: none; }
.desc-field.is-collapsed > .form-input { display: none; }
.desc-field.is-collapsed .desc-toggle {
  display: inline-flex; align-items: center; gap: var(--sp-1); cursor: pointer;
  border: 1px dashed var(--border-strong); border-radius: var(--radius-btn);
  background: transparent; color: var(--text-3); font-size: var(--fs-caption); padding: var(--sp-2) var(--sp-3);
  transition: border-color var(--transition-fast), color var(--transition-fast);
}
@media (hover: hover) { .desc-field.is-collapsed .desc-toggle:hover { border-color: var(--text-4); color: var(--text-1); } }

/* 超窄屏（≤380）：只收缩字号与井内距，分组与行高不回退（间距规范 v1.0） */
/* ≤768 手机端样式 → 06-mobile.css「超窄屏（≤380）：只收缩字号与井内距，分组与行高不回退（间距规范 v1.0）」 */

/* ============================================================
   输入框规范 v2 · 编辑表单族样板（2026-10-03）
   ------------------------------------------------------------
   家族基因：填充衬底（--fld-fill）+ 圆角 --fld-r + 桌面文本档
   --fld-fs + 悬停加深一档；聚焦跑 1004b 定稿配方——保持衬底不翻白
   + 1px 主描边 + 12px 柔光渐隐（--focus-glow），与账户盒 / 手机端井族同语言。
   这是手机端 v1.0「井」语言的桌面表达——材质 / 状态走同一组
   --fld-* 令牌，尺寸按平台分档（手机 44-54 / 16px 地板；桌面 36 / 14）。

   改前实测（.workbuddy/fldv2-desk-before.log，2026-10-03）：
     桌面五表单里文本 / 正文 / 下拉 / 日期 = --bg-page 底 + 1px 描边
     + 4px 直角 + 13px；只有「回顾」的正文井是软底 + 10px 圆角 + 16px
     ——两种口径并存。聚焦口径更碎：2px 主光环 / 3px 主光环 / 3px
     柔光环 / 无光环四种写法。本块把五个表单在桌面端收进同一材质、
     同一文本档与同一枚光环；1004b 起聚焦定稿（不翻白 / 1px / 12px 柔光渐隐），
     手机端井族同日同配方（尺寸仍按平台分档）。

   作用域 .edit-form：五个表单在 Modal.open 时挂（app.js 五处，
   与 diary-form / wbf-modal 同一清理名单），其余弹窗零影响。
   ============================================================ */
@media (min-width: 769px) {
  .edit-form .form-input,
  .edit-form .sel-btn,
  .edit-form .dp-display,
  .edit-form .sub-row,
  .edit-form .sub-add .btn {
    background: var(--fld-fill);
    border-color: transparent;
    border-radius: var(--fld-r);
    transition: background var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast);
  }
  /* 1004b：三只可聚焦井静止即预留 1px 透明描边——聚焦换 1px 主描边不跳字 */
  .edit-form .form-input,
  .edit-form .sel-btn,
  .edit-form .dp-display { border: 1px solid transparent; }
  /* 文本档统一 14（--fs-body）：收口 13 / 16 两口径（回顾正文井曾整只是 16） */
  .edit-form .form-input,
  .edit-form .sel-btn,
  .edit-form .dp-display { font-size: var(--fld-fs); }
  @media (hover: hover) {
  .edit-form .form-input:hover,
  .edit-form .sel-btn:hover,
  .edit-form .dp-display:hover,
  .edit-form .sub-add .btn:hover { background: var(--fld-fill-hover); border-color: transparent; }
  }
  .edit-form .form-input:focus,
  .edit-form .sel-btn:focus-visible,
  .edit-form .sel-btn.is-open,
  .edit-form .dp-display:focus-visible,
  .edit-form .dp-display.is-open {
    background: var(--fld-fill); border-color: var(--primary); box-shadow: var(--focus-glow);
  }
  .edit-form .form-input[readonly] { background: var(--bg-disabled); }
}

/* ============================================================
   打卡热力 · 手机端适配（遵循「手机端间距规范 v1.0」：
   4pt 网格、字号地板、icon 类触控目标 ≥38、主操作 ≥44）
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* 触屏无 hover：热力面板控件按压反馈补齐 */
@media (hover: none) {
  .hb-minus:active { transform: scale(.94); }
}

/* 超窄屏（≤380）：只收缩年视图格宽，间距与字号地板不回退 */
/* ≤768 手机端样式 → 06-mobile.css「超窄屏（≤380）：只收缩年视图格宽，间距与字号地板不回退」 */

/* ============================================================
   登录弹窗 → 底部抽屉（≤768，2026-09-16；2026-09-19 收进标准抽屉语言）
   与 wp-sheet / cf-sheet 同一骨架：贴底、顶圆角 24、
   .32s ease-enter 自下而上滑入，关闭 .28s 下滑退场，
   内距吃 --card-pad、底部垫安全区；顶部 .wp-grab 把手 + .wp-title 标题，
   底栏 .wp-foot 两枚胶囊（继续本地=灰、登录=黑），右上 × 收起、
   关闭交给把手下拉 / 浏览器返回 / Esc / 取消按钮（wireSheetGrab expand:false）。
   必须排在文件末尾：压过基线 .login-mask/.login-pop 与
   前文 ≤768 的安全区 padding、≤600 padding 覆写。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */
@keyframes loginSheetUp { from { transform: translateY(100%); } to { transform: translateY(0); } }
@keyframes loginSheetDown { from { transform: translateY(0); } to { transform: translateY(100%); } }

/* 减动效：排在末尾的手机端规则必须在同位置归零，
   否则会反压文件前部的 prefers-reduced-motion 块 */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   自建取色抽屉 · 手机端（间距规范 v1.0：主操作 ≥44、iOS 输入字号 ≥16px）
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */
/* 排在末尾的手机端规则必须在同位置归零，否则会反压前部 prefers-reduced-motion 块 */
/* ≤768 手机端样式 → 06-mobile.css「排在末尾的手机端规则必须在同位置归零，否则会反压前部 prefers-reduced-motion 块」 */

/* ============================================================
   首次访问引导 → 全屏轮播（≤768，2026-10-01）
   引导是首启全屏门（非次级面板），手机端铺满整屏：磨砂模块卡 +
   大标题 + 圆点 + 底部黑胶囊，左右滑动换屏，末屏「开始使用」原地
   切到昵称表单（同卡、不关卡重开、不键盘跳动）。
   安全区一律吃令牌 --sat/--sab 并写进 padding 简写（同块后置简写会清零单独 padding-top）。
   主操作 50（≥44）、昵称井 54（表单行）、输入 18px（iOS ≥16）。
   必须排在文件末尾：压过基线 .ob-mask/.ob-card 与前置 ≤768 覆写。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */
/* 触屏无 hover：引导层控件按压即反馈，悬停态一律退回基线 */
@media (hover: none) {
  .ob-back:active { background: var(--bg-hover); }
  .ob-dot:active { opacity: .6; }
  .btn.ob-go:active { transform: scale(.985); background: var(--primary-hover); }
}
/* 暗色：磨砂卡换深色玻璃，柔光与高光边同步 */
/* ≤768 手机端样式 → 06-mobile.css「暗色：磨砂卡换深色玻璃，柔光与高光边同步」 */
/* 超窄屏（≤380）：只收字号，画布内距不回退 */
/* ≤768 手机端样式 → 06-mobile.css「超窄屏（≤380）：只收字号，画布内距不回退」 */
/* 排在末尾的手机端规则必须在同位置归零，否则会反压前部 prefers-reduced-motion 块 */
/* ≤768 手机端样式 → 06-mobile.css「排在末尾的手机端规则必须在同位置归零，否则会反压前部 prefers-reduced-motion 块」 */

/* ============================================================
   备忘标签条 / 待办分类条 · 单行横滑 + 「全部…」浮层（2026-09-16）
   标签/分类只增不减，换行会无限占高：收成一横行滑区，溢出靠
   左右渐隐提示，全量收进浮层（手机 wp-sheet 抽屉 / 桌面 dd-modal）。
   scope 到 .memo-tagbar / .todo-catbar / .date-typebar / .mem-groupbar 与 .tag-pick* / .cat-list。
   1029：记忆页人物档的筛选条入族（当时按「关系」）；1030 站主令改按「分组」，族名跟着改成
   .mem-groupbar——它要的是同一件东西（一行、横滑、边缘渐隐、右侧固定全量入口），
   照族里换一档，不复制规则（复制会撞 css-bloat-gate 的重复组棘轮）。
   ============================================================ */
.memo-tagbar, .todo-catbar, .date-typebar, .mem-groupbar { flex-wrap: nowrap; min-width: 0; }
.memo-tagbar .chip-scroll, .todo-catbar .chip-scroll, .date-typebar .chip-scroll, .mem-groupbar .chip-scroll {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: var(--sp-2);
  overflow-x: auto; overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none; -ms-overflow-style: none;
  scroll-padding: 0 12px;
}
.memo-tagbar .chip-scroll::-webkit-scrollbar, .todo-catbar .chip-scroll::-webkit-scrollbar, .date-typebar .chip-scroll::-webkit-scrollbar, .mem-groupbar .chip-scroll::-webkit-scrollbar { display: none; }
.memo-tagbar .chip-scroll .chip, .todo-catbar .chip-scroll .chip, .date-typebar .chip-scroll .chip, .mem-groupbar .chip-scroll .chip { flex: 0 0 auto; }
/* 边缘渐隐：由 JS 按滚动位置挂 tgf-l / tgf-r，未溢出不加遮罩 */
.memo-tagbar .chip-scroll.tgf-l, .todo-catbar .chip-scroll.tgf-l, .date-typebar .chip-scroll.tgf-l, .mem-groupbar .chip-scroll.tgf-l {
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 16px, #000 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 16px, #000 100%);
}
.memo-tagbar .chip-scroll.tgf-r, .todo-catbar .chip-scroll.tgf-r, .date-typebar .chip-scroll.tgf-r, .mem-groupbar .chip-scroll.tgf-r {
  -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 16px), transparent 100%);
          mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 16px), transparent 100%);
}
.memo-tagbar .chip-scroll.tgf-l.tgf-r, .todo-catbar .chip-scroll.tgf-l.tgf-r, .date-typebar .chip-scroll.tgf-l.tgf-r, .mem-groupbar .chip-scroll.tgf-l.tgf-r {
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
}
/* 固定「全部…」入口：不参与收缩，压在滚动区右侧 */
.memo-tagbar .chip-more, .todo-catbar .chip-more, .date-typebar .chip-more, .mem-groupbar .chip-more, .todo-catbar .chip-sort { flex: 0 0 auto; color: var(--text-3); }
/* 1014：三处「全部标签/分类/类型」入口只留网格图标 + 计数（文字进 title/aria），
   占位从 ~110px 收到 ~58px，分类行不再被它挤走半排 chips；
   腾出的右缘给排序钮（图标 + 当前档两字，声明并进上面同一族）。 */
.chip.chip-only { padding: 0 var(--sp-2); }
.todo-catbar .chip-sort svg { width: 15px; height: 15px; flex: none; }
.memo-tagbar .chip-more svg, .todo-catbar .chip-more svg, .date-typebar .chip-more svg, .mem-groupbar .chip-more svg { width: 13px; height: 13px; }
/* ≤768 手机端样式 → 06-mobile.css */

/* 浮层内容：白卡内 chip 全量平铺（复用 .chip 壳，不另造样式） */
.tag-pick-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4) 2px; }
.tag-pick-cap { font-size: var(--fs-micro); color: var(--text-4); }
.tag-pick-head.no-sel #tpClear { display: none; }
.tag-pick { display: flex; flex-wrap: wrap; gap: var(--sp-3); padding: var(--sp-2) var(--sp-4) var(--sp-3); }
.tag-pick-empty { padding: var(--sp-1) var(--sp-4) var(--sp-3); color: var(--text-4); font-size: calc(14px * var(--fs-scale)); }
/* 管理入口：dd-row 语言的内联行（图标 + 文本 + 右箭头），替代旧底部固定栏 */
.tp-mgr {
  width: 100%; text-align: left; cursor: pointer;
  border: 0; border-top: 1px solid var(--border); border-radius: 0;
  background: none; color: inherit; font: inherit;
  transition: background var(--transition-fast);
}
.tp-mgr:active { background: var(--bg-hover); }
@media (hover: hover) { .tp-mgr:hover { background: var(--bg-hover); } }
/* tp-mgr 自带通栏 border-top：dd 行的发丝线再叠上来就是同一道缝两根线
   （待办分类管理的「新建分类」尾行、账本分类的每一行都中过招，1015 站主实拍）——
   掐掉发丝线，行线只归 tp-mgr 自己画 */
.dd-row.tp-mgr::before { content: none; }
.tp-chev { flex: none; width: 16px; height: 16px; color: var(--text-disabled); }
.tp-chev svg { width: 16px; height: 16px; }
/* —— 手机端底部抽屉：与滚轮时间选择器同款 .wp-mask/.wp-sheet 壳，网格 56vh 比滚轮窗更高 —— */
.tp-sheet .tp-grid {
  display: flex; flex-wrap: wrap; align-content: flex-start; gap: var(--sp-3);
  min-height: 40vh; max-height: 56vh; overflow-y: auto; margin-bottom: var(--sp-3);
  -webkit-overflow-scrolling: touch;
}
.tp-sheet .tps-mgr { width: 100%; margin-bottom: var(--sp-3); }
/* 抽屉底栏已撤（三张筛选抽屉：标签/分类/类型都「点即筛、下拉即关」，无「完成」）。
   标签是多选，唯一还需要的批量操作「清空已选」搬到标题行右侧：iOS 导航栏式文字钮，
   标题仍居中不被推位；只在有选中时淡入（.has-sel 由 JS 跟 state.memoTags 同步），
   空态不可点也不留噪声。标题行加高到 38px 当触控地板——热区只吃行内与左右内距，
   不上侵把手带（.wp-grab），拖动区不受影响。 */
.tp-sheet .wp-title { position: relative; display: flex; align-items: center; justify-content: center; min-height: 38px; }
.tps-clear {
  position: absolute; right: 0; top: 0; bottom: 0;
  display: inline-flex; align-items: center; padding: 0; border: 0;
  background: none; cursor: pointer; font-family: inherit;
  font-size: calc(14px * var(--fs-scale)); font-weight: var(--fw-medium); line-height: 1;
  color: var(--text-3); white-space: nowrap;
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  opacity: 0; pointer-events: none;
  transition: opacity var(--d-base) ease, color var(--transition-fast), transform var(--d-base) var(--ease-float);
}
.tp-sheet.has-sel .tps-clear { opacity: 1; pointer-events: auto; }
.tps-clear::after { content: ""; position: absolute; inset: 0 -10px; } /* 横向再吃 10px 内距，纵向已满 38 */
.tps-clear:active { color: var(--text-1); transform: scale(.94); }
/* 全部分类浮层行组：桌面进白卡加衬；手机抽屉保底高度（同标签抽屉的「更长」取向） */
.dd-group .cat-list { padding: var(--sp-3) var(--sp-3) 0; margin-bottom: 0; }
.tp-sheet .cat-list { min-height: 32vh; max-height: 56vh; }
/* —— 1025 待办「分类排序」合并抽屉（.fs-sheet）：三段共用一只 tp-sheet 壳 ——
   排序段直接复用滚轮抽屉那对 .wp-seg / .wp-seg-btn（灰槽 + 黑把手反白，零新组件），
   这里只把它从「居中 max-content」改成「通栏等宽四格」——四枚两字标签在 320px 窄屏也摊得开。
   ⚠ 本段刻意不写进 @media ≤768：这只抽屉的门禁是 wbCoarse()（触屏或窄屏任一即真），
   宽屏平板也会用到它，写进宽度块等于给平板发一只没样式的抽屉。 */
.fs-sheet .wp-seg { width: 100%; margin-bottom: var(--sp-1); }
.fs-sheet .wp-seg-btn { flex: 1 1 0; min-width: 0; padding: 0 var(--sp-4); }
.fs-sheet .fs-cur { margin-bottom: var(--sp-3); padding: 0 var(--sp-1); }
/* C 案的主读数：抽屉行右侧那个数字现在讲是「还剩几件」，就是这一行的 payload，
   不能再穿着 .tf-cnt 那身灰小字（--text-4 / 13px）的旧衣服——实拍过一回，
   名字黑、说明灰、数字也灰，整行没有重点。升墨 + 升重，字号不动（等宽数字自己会站住）。
   ⚠ 必须排在下面 .fs-over .tf-cnt 之前：逾期那行的数字要跟红字同色，靠后来者胜盖回去。 */
.fs-sheet .tf-cnt { color: var(--text-1); font-weight: var(--fw-semibold); }
/* 分区小标题：一行 --text-4 小字 + 一条发丝线把段切开，不另起一张卡 */
.fs-sec { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) 0;
  font-size: var(--fs-micro); color: var(--text-4); letter-spacing: .03em; }
.fs-sec::after { content: ""; flex: 1; height: 1px; background: var(--border); }
/* 只看已逾期：整行即热区（label 包 checkbox，勾选由原生行为翻转，JS 只接 change）。
   红点与 1020 那枚逾期胶囊同族色；选中态描边走告警红而非主色——它是状态告警不是导航选中。 */
.fs-over { color: var(--tag-bad-fg); margin-bottom: var(--sp-2); cursor: pointer; }
.fs-over .over-dot { width: 7px; height: 7px; border-radius: var(--r-circle); background: currentColor; flex: none; }
.fs-over .tf-cnt { color: inherit; }
.fs-over:has(input:checked) { border-color: var(--status-bad); background: var(--bg-hover); }
.fs-over .status-switch { margin-left: var(--sp-1); }
/* —— 手机端体检补丁：触控地板 ≥38（热区扩展走 .modal-head-act ::after 先例，视觉尺寸不动）—— */
/* ≤768 手机端样式 → 06-mobile.css「—— 手机端体检补丁：触控地板 ≥38（热区扩展走 .modal-head-act ::after 先例，视觉尺」 */

/* 取色抽屉 · 桌面形态：同一套外壳转成居中对话框。
   特异性必须压过 .wp-sheet（width:100% / 24px 顶圆角 / translateY 贴底），故带 .wp-mask 前缀且排在其后 */
@media (min-width: 769px) {
  .wp-mask.cp-mask { align-items: center; justify-content: center; }
  .wp-mask .cp-sheet {
    width: 420px; max-width: calc(100vw - 48px);
    border-radius: var(--r-5); padding: var(--sp-6) var(--sp-6) var(--sp-4);
    transform: translateY(10px) scale(.985); opacity: 0;
    transition: transform var(--d-toast) var(--ease-enter), opacity var(--d-modal) ease;
  }
  .wp-mask.cp-mask.is-open .cp-sheet { transform: none; opacity: 1; }
  .wp-mask .cp-sv { height: 168px; }
}

/* ============================================================
   详情热力 · 动效卡顿修正
   ============================================================ */
/* 内联操作区（mobDetailify 事后挂进 body 的「编辑 / 删除」）：
   吃到 .modal-body > *:nth-child(n) 的错峰延迟，会在弹窗开完后「晚一拍冒出来」，
   看着就是闪一下。这里给它独立的零延迟淡入，必须排在级联规则之后才能压住同特异性 */
/* ≤768 手机端样式 → 06-mobile.css */
@keyframes ddFootIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .modal-card.cascade .modal-body > .dd-foot-inline,
  .modal-card.chain-in .modal-body > .dd-foot-inline { animation: none; }
}

/* ============================================================
   分类 / 标签管理卡改版（2026-09-16）
   旧 dc-block 扁平 → dd-modal 语言：白卡 + tb-head 图标行首 +
   dd-row 发丝线条目 + 行内编辑区（井式输入 + 色板 + 双按钮）。
   条目行 = .mg-row；操作钮 = .mg-act（38px 触控）；编辑器 = .mg-edit。
   ============================================================ */
.mg-row .dd-k { font-size: calc(15px * var(--fs-scale)); }
.mg-row .dd-v { flex: none; max-width: none; margin-left: auto; }
.mg-act {
  flex: none; width: 38px; height: 38px; margin-right: -8px;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent; border-radius: var(--r-2);
  color: var(--text-4); cursor: pointer;
  transition: background var(--transition-fast);
}
.mg-act svg { width: 16px; height: 16px; }
.mg-act:active { background: var(--bg-hover); }
.mg-act-del { color: var(--tag-bad-fg); }
/* 行内编辑区：从被编辑的行下方长出来，与列表同一张白卡 *//* (1008 死规则清理) */
.mg-edit .cat-palette { margin-top: var(--sp-3); }
.mg-empty { padding: var(--sp-6) var(--sp-4); text-align: center; color: var(--text-4); font-size: calc(14px * var(--fs-scale)); }
/* 单卡弹窗（管理/浮层）首卡不带 12px 顶距（同 .tb-card:first-child 先例） */
.dd-modal .modal-body > .dd-group:first-child { margin-top: 0; }

/* 管理抽屉（分类/标签 · 手机）：行组通铺抵消 sheet 16px 内衬，列表区 52vh 内滚动 */
.mgr-sheet .mg-inner { margin: 0 -16px var(--sp-1); max-height: 52vh; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.mgr-sheet .wp-foot { margin-top: var(--sp-4); }

/* 管理抽屉叠在选择抽屉上时：透明遮罩（暗底由下层负责），只承接点击与动画 */
.wp-mask.wp-mask-bare { background: transparent; }

/* ============================================================
   管理抽屉 · 行级直改（样板：标签管理，2026-09-17）
   点行即改：名称原地变常驻输入（子任务行 input 同款思路），
   行高不变 → 键盘抬升只动一次，无展开跳动。
   ============================================================ */
.mg-row[data-tag] { cursor: text; -webkit-tap-highlight-color: transparent; }
.mg-row[data-tag]:active { background: var(--bg-hover); }
.mg-inline {
  flex: 1; min-width: 0; width: auto; height: auto; padding: 0;
  border: none; border-bottom: 1.5px solid transparent; border-radius: 0;
  background: transparent; outline: none;
  font: inherit; font-size: calc(16px * var(--fs-scale)); color: var(--text-1); caret-color: var(--primary);
  transition: border-color var(--transition-fast);
}
.mg-row.is-editing .mg-inline { border-bottom-color: var(--primary); }
.mg-row.is-editing .dd-v { opacity: .55; }

/* 行级直改推广到分类/类型：色点可点（14px 视觉 + ::after 热区到 38px）、迷你色板条 */
.mg-row[data-id] { cursor: text; -webkit-tap-highlight-color: transparent; }
.mg-row[data-id]:active { background: var(--bg-hover); }
.mg-dot {
  width: 14px; height: 14px; border: none; padding: 0; cursor: pointer;
  position: relative; flex-shrink: 0; border-radius: var(--r-circle);
  -webkit-tap-highlight-color: transparent;
}
.mg-dot::after { content: ""; position: absolute; inset: -12px; } /* 14px 色点 → 38px 热区 */
/* 它是 dd-row（flex 行）里的子块：不给 flex-basis 就会被压成 min-content——
   1015 图形格改成 auto-fill 网格之后当场塌成一排 1 枚（网格的 max-content 只有一轨），
   旧的 flex-wrap 靠 34px 定宽项侥幸撑住，换成网格就露了形。通栏才是本意。 */
.mg-palette { padding: 0 var(--sp-4) var(--sp-3); flex: 1 1 100%; }
.mg-palette .cat-palette { margin-top: 0; }

/* ============================================================
   概览 · 今日时间线 v1.0（2026-09-17）
   ------------------------------------------------------------
   取代原「KPI 六卡 + 进度环 + 四张面板」。一屏只回答两件事：
   今天该做什么（时间线一条流）、做得怎么样（hero 进度条）。
   · hero 是全站唯一一张反白卡，用它压住整页层级
   · 时间线：图标列 + 贯穿轨道线 = 一条「今天」的流水
   · 洞察三卡合并成一张「本周」；数据说明迁到「关于」(.ab-*)
   桌面 ≥1024 走「左内容 / 右本周」两栏；手机端单列走间距规范 v1.0。
   ============================================================ */

/* ---- 1. 今日 hero（1010 信息重排 · 方案 A）
   ------------------------------------------------------------
   这一版没新增任何一枚令牌，只干一件事：**把字号档位改指向该被看见的东西**。
   问候原来吃全卡最大的 --fs-num-md（手机端 22px）却不承载信息，真正要回答的
   「做得怎么样」只有 13px 灰字；现在问候让给 --fs-h3、读数把 22px 接过去。
   四件新结构全是站内既有语言的搬家：
     · 分段日槽 .ov-seg —— 一件一格替掉「百分比 + 分数 + 连续条」三处重复
     · 欠账芯片 .ov-chip —— 借 .tl-mini / .chip 同一把尺（高 --control-h-sm、圆角 r-2 徽章档、
       ::after 补热区到 38），色点走模块色且只落在点上（习惯色不进文字底）
     · 页脚 .ov-foot —— 一言保留但降为细行（2.32 起这一行只有它）
   快捷胶囊撤掉五枚：待办 / 备忘 / 习惯与 dock 同名重复，「事件」与 dock 的「纪念」
   是同一个模块两个名字，小记由上面那枚芯片承担。hero 只留 dock 到不了的一步直达。 ---- */
.ov-day {
  --ovd-bg: var(--bg-card);
  --ovd-ink: var(--text-1);
  --ovd-dim: var(--text-3);
  --ovd-faint: var(--text-4);
  --ovd-line: var(--border);
  --ovd-well: var(--bg-muted);
  background: var(--ovd-bg); color: var(--ovd-ink);
  border: 1px solid var(--ovd-line); border-radius: var(--radius-lg);
  padding: var(--sp-6) var(--sp-6) var(--sp-4); box-shadow: var(--shadow-card);
}
.ov-day-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-2) var(--sp-4); }
.ov-hi { margin: 0; font-size: var(--fs-h3); font-weight: var(--fw-semibold); line-height: 1.35; letter-spacing: -.01em; }
/* 日期两行右对齐、各自 nowrap：旧版连排成一句挂在问候右边，手机宽度下自己折行，
   把标题挤成孤零零一行（1010 真机图）。农历取不到时整条 <i> 不渲染，不留空行。 */
.ov-date { flex: none; text-align: right; line-height: 1.45; }
.ov-date b { display: block; font-family: var(--font-mono); font-size: var(--fs-12);
  font-weight: var(--fw-medium); color: var(--ovd-dim); white-space: nowrap; letter-spacing: .01em; }
.ov-date i { display: block; font-style: normal; font-size: var(--fs-12); color: var(--ovd-faint); white-space: nowrap; }

/* 读数：这张卡的主角。0 安排时同一档字号改说人话——别让「0 / 0」当全卡最大字 */
.ov-read { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-3); margin-top: var(--sp-4); }
.ov-read-l { display: flex; align-items: baseline; gap: var(--sp-3); min-width: 0; }
.ov-read-n { font-family: var(--font-mono); font-size: var(--fs-num-md); font-weight: var(--fw-semibold);
  line-height: 1; letter-spacing: -.02em; font-variant-numeric: tabular-nums; color: var(--ovd-ink); }
.ov-read-n s { text-decoration: none; color: var(--ovd-faint); }
.ov-read-n.is-txt { font-family: var(--font-sans); letter-spacing: -.01em; }
.ov-read-c { font-size: var(--fs-caption); line-height: 1.4; color: var(--ovd-dim); text-align: right; padding-bottom: 2px;
  white-space: nowrap; flex-shrink: 0; }   /* 结论区不许被左侧重字挤到换行（站主要「图标+文字」一行） */
.ov-read-c b { font-weight: var(--fw-semibold); color: var(--ovd-ink);
  display: inline-flex; align-items: center; gap: var(--sp-1); }   /* 左图标右文字，垂直居中同一行 */
/* 全清结论里的内联表情图标：尺寸走 em（跟字号）、墨色靠 fill=currentColor 继承 .ov-read-c b 的 --ovd-ink，
   暗色主题自动翻白；它是 flex 子项，故 display:block 去掉行内基线带来的偏移。 */
.ov-read-c svg { width: 1.3em; height: 1.3em; display: block; flex: none; }

/* 分段日槽：实心＝已收，**今天几件事就几格**（2.32 撤掉旧的 10 格上限 + 虚线尾）。
   只动 transform/opacity（站内动效铁律）；逐格入场只给切页那一次，
   JS 用 animate 决定是否挂 .is-enter——在概览里连点完成不重放整排。
   逐格快慢由 JS 按件数写进 --seg-step（件数越多每格越快）；格多到一行放不下
   才折行，min-width 4px 是「一眼还数得清」的地板。 */
.ov-segs { display: flex; flex-wrap: wrap; gap: 3px; margin-top: var(--sp-3); }
.ov-seg { flex: 1; min-width: 4px; height: 8px; border-radius: var(--radius-pill);
  background: var(--ovd-well); transform-origin: left center;
  animation: ovSegIn var(--d-push) var(--ease-float) both; }
.ov-seg.is-on { background: var(--ovd-ink); }
.ov-segs.is-enter .ov-seg { animation-delay: calc(var(--i, 0) * var(--seg-step, 26ms)); }
@keyframes ovSegIn { from { transform: scaleX(.2); opacity: .35; } to { transform: scaleX(1); opacity: 1; } }
/* 空日子：一条虚线浅槽，读作「没安排」而不是「坏了」 */
.ov-segs.is-empty .ov-seg { background: transparent; border: 1px dashed var(--border-strong); }
@media (prefers-reduced-motion: reduce) {
  .ov-seg, .ov-segs.is-enter .ov-seg { animation: none; }
}

/* 欠账芯片：全卡最该点、原来却唯一不可点的那句灰字。
   手机端高度与 .tl-mini / .chip 同档（38，站内触控地板），
   桌面收在 --control-h-sm；::after 借 .tl-check 同一写法再往外扩 3px → 44 热区。
   色点走模块色且只落在点上（习惯色不进文字底）；底色只给「过期」这一枚上红底。 */
.ov-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3); }
.ov-chip {
  position: relative; display: inline-flex; align-items: center; gap: var(--sp-2);
  height: var(--control-h-sm); padding: 0 var(--sp-3) 0 var(--sp-2); border-radius: var(--r-2);
  border: 1px solid transparent; background: var(--ovd-well); color: var(--text-2);
  font-family: inherit; font-size: var(--fs-12); white-space: nowrap; cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast), transform var(--d-micro) ease;
}
.ov-chip::after { content: ""; position: absolute; inset: -3px; }
.ov-chip:active { transform: scale(.97); }
.ov-chip-d { flex: none; width: 6px; height: 6px; border-radius: var(--r-circle); background: var(--ovd-dim); }
.ov-chip b { font-family: var(--font-mono); font-weight: var(--fw-semibold); color: var(--ovd-ink); }
.ov-chip.is-habit .ov-chip-d { background: var(--hm-3); }
.ov-chip.is-diary .ov-chip-d { background: var(--ovd-faint); }
.ov-chip.is-bad { background: var(--tag-bad-bg); }
.ov-chip.is-bad .ov-chip-d { background: var(--tag-bad-fg); }
.ov-chip.is-bad b { color: var(--tag-bad-fg); }

/* 页脚：2.32 起只剩「今日一句」一行——那枚「一句话」黑胶囊（连同 .qbtn 一族）撤了，
   快速记走首页 FAB ＋ 与 dock 下滑。留 border-top 是因为它上面还压着欠账芯片。 */
.ov-foot { display: flex; align-items: center; gap: var(--sp-3);
  margin-top: var(--sp-4); padding-top: var(--sp-3); border-top: 1px solid var(--ovd-line); }
/* 今日一句的说话人一行（2026-10-26 站主定稿：助手形象 + 自定义昵称 + “句子”）：
   .ov-quote 吃掉 .ov-foot 的整行宽（flex:1 + min-width:0），句子长时只有句子被截断，
   形象与署名 flex:none 永不参与挤压；三件内部用 --sp-1 挨成一组，形象那一档补到 --sp-2
   （署名↔句子要贴，全角“自带半个空位的左边距，再留 8px 就读成两段话了）。
   形象与署名之间那 4px 由署名自己带 margin-left，不另开一条 `.ai-face` 规则——
   单声明规则会被 css-bloat-gate 记成新的「逐字重复组」。
   形象复用 .ai-face 的 16px 档（活体徽章，与设置页 / 对话流同一个形象），零新资源。 */
.ov-quote { display: flex; align-items: center; gap: var(--sp-1); flex: 1; min-width: 0; }
.ov-quote-who { flex: none; margin-left: var(--sp-1); font-size: var(--fs-12); line-height: 1.4;
  font-weight: var(--fw-medium); color: var(--ovd-dim); }
.ov-quote-text { min-width: 0; font-size: var(--fs-12); line-height: 1.4; color: var(--ovd-faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  transition: opacity var(--d-base) var(--ease-float); }
/* 今日一句（Pro+）异步回来时先淡出、换字后再淡回——硬切会被点名 */
.ov-quote-text.is-swap { opacity: 0; }

/* 首页 hero「早晚简报」通知位（2026-1025）：仅移动端出现，未读时临时替掉「今日一句」。
   沿用 .ov-chip 按压语言（.97）与今日一句细行字号档；整页不新增彩色——简报非状态，遵守「唯一彩色是状态」原则。
   ::after 扩点击热区（同 .ov-chip），够手机端触控地板。 */
.ov-brief { position: relative; display: flex; align-items: center; gap: var(--sp-2);
  flex: 1; min-width: 0; margin: 0; padding: 2px 0; background: none; border: 0;
  font: inherit; color: var(--ovd-ink); text-align: left; cursor: pointer;
  -webkit-tap-highlight-color: transparent; }
/* 热区上下各扩 10（左右仍 7）：本体只有 24px 高，按旧写法 -7 只到 38，够不着手机端 44 触控地板
   （1027 探针实测抓到，DESIGN_SYSTEM §9「触达 <44px」那条欠账在简报胶囊上的具体一处）。
   只抹隐形热区、不动布局盒；页脚与上面欠账芯片之间还有 28px 呼吸，芯片自己的 ::after 只扩 3px，互不抢点。 */
.ov-brief::after { content: ""; position: absolute; inset: -10px -7px; }
.ov-brief:active { transform: scale(.97); }
.ov-brief-lead { min-width: 0; font-size: var(--fs-12); line-height: 1.4;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ov-brief-go { flex: none; font-size: var(--fs-12); color: var(--ovd-dim); }

/* ================= 简报·对话页一只白卡（2026-10-26 站主定稿：只走对话流承载，卡内分段）=================
   承载 = 可序页对话流里的一条助手气泡（.npg-ans 本就是一只白卡），整份简报塞进 .bp-inline：
   顶部 .bp-hi 问候，下面每段一个 .bp-seg，段间细分隔线分层——即「用一个白色卡片装下」。
   ★ 配色只走 :root 全站语义 token（--text-1/3/4、--border、--bg-muted）——
   这里曾用 --ovd-* 一族，但它们是 .ov-day（hero 卡）作用域内的局部别名，气泡里继承不到，
   整层落回深色 hex 兜底，暗色档深字压深底全糊（1026 站主实拍点名）。不再带 hex 兜底（R6）。 */
.bp-inline { display: block; }
/* 简报气泡宽度（1105 站主实拍「整体感觉太窄」）：.npg-ans 本就 `width: fit-content`，
   而卡里那几行是「标题 flex:1 ＋ 右对齐读数」——标题越短，内容撑出来的宽度越小，整只卡跟着缩。
   简报这一支不参与 fit-content 的取舍：铺满对话流宽度（`:has` 的先例见本页 .nl-page:has(...)）。
   只认「直系子里有 .bp-inline」这一条结构判据，别的气泡（普通回复、查询卡）一个字不动。 */
.npg-ans:has(> .bp-inline) { width: 100%; max-width: 100%; }
.bp-hi { padding: 0 0 2px; }
.bp-hi-t { font-size: var(--fs-15); font-weight: 700; color: var(--text-1); line-height: 1.35; }
.bp-hi-sub { margin-top: var(--sp-1); font-size: var(--fs-12); color: var(--text-4); }
.bp-seg { padding: var(--sp-3) 0; border-top: 1px solid var(--border); }
.bp-seg:first-child, .bp-hi + .bp-seg { border-top: 0; padding-top: var(--sp-1); }
.bp-card-h { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.bp-ico { width: 16px; height: 16px; flex: none; color: var(--text-3); }
/* 图标点缀色（1026 站主「图标太墨」）：tone class 由 bpIco(p,tone) 挂 svg 上，
   色值在 01-tokens.css 立 --bp-ico-* 双档（暗档同色相提亮）；正文文字仍墨灰不动。 */
.bp-ico.ico-fortune, .bp-ico.ico-summary, .bp-ico.ico-quote { color: var(--bp-ico-gold); }
.bp-ico.ico-overall { color: var(--bp-ico-gold-2); }
.bp-ico.ico-work, .bp-ico.ico-plan { color: var(--bp-ico-blue); }
.bp-ico.ico-love { color: var(--bp-ico-rose); }
.bp-ico.ico-weather { color: var(--bp-ico-sky); }
.bp-ico.ico-todo { color: var(--bp-ico-teal); }
.bp-card-t { font-size: var(--fs-13); font-weight: 700; color: var(--text-1); }
.bp-tag { margin-left: auto; font-size: var(--fs-11); color: var(--text-4);
  border: 1px solid var(--border); border-radius: var(--r-1); padding: 1px var(--sp-2); }
.bp-p { margin: 0 0 var(--sp-1); font-size: var(--fs-13); line-height: 1.6; color: var(--text-1); }
.bp-p:last-child { margin-bottom: 0; }
.bp-muted { color: var(--text-3); }
.bp-faint { color: var(--text-4); font-size: var(--fs-12); }
.bp-term-n { font-size: var(--fs-14); font-weight: 700; color: var(--text-1); margin-bottom: var(--sp-1); }
/* 1030 清死样式：早报「运势三格 / 宜忌 / 运势尾行」与晚报「小结三格」那批版式随
   bpCell()/bpNum() 等死函数一并摘掉（10-29 版式定稿后 briefHtml 已不消费 m.fortune），
   温度读数只留 .bp-wx-now 这一枚 chip。以下类名在运行件里 0 命中：
   .bp-f3 .bp-cell .bp-cell-k .bp-cell-v .bp-yj .bp-yj-k .bp-luck .bp-wx-days
   .bp-stat3 .bp-num .bp-num-k .bp-num-v ——顺带消掉 R4 三条字号违例（12px/26px/15px）。
   （.bp-wx-deg 1107 复生：参考图2 温度大字，见下；.ico-term 随概览并入「今日节气」退役。） */
.bp-wx-now { display: flex; align-items: baseline; gap: var(--sp-2); font-size: var(--fs-13); color: var(--text-1); }
/* 温度大字＋天况旁注（1107 参考图2）：大字号只落在 .bp-wx-deg 上——
   旧持久化快照的 chip 是纯文本、没有这层子元素，回放时仍是原小字长相，不会被整行放大。 */
.bp-wx-deg { font-size: var(--fs-num-sm); font-weight: 700; line-height: 1.25; font-variant-numeric: tabular-nums; }
.bp-wx-meta { font-size: var(--fs-12); color: var(--text-3); white-space: nowrap; }
/* 明日天气条（1107 参考图2：灰底圆角一条，只报事实不追加带伞） */
.bp-wx-tmr { margin-top: var(--sp-2); padding: var(--sp-2) var(--sp-3); border-radius: var(--r-2); background: var(--bg-muted); font-size: var(--fs-12); line-height: 1.5; color: var(--text-3); }
/* 洞察暖底 / 寄语紫底（1107 参考图2）：白卡内的着色分块，不再吃段间分隔线；
   暖底借 --tag-warn-bg 琥珀族（暗档随令牌翻面），紫底走新立 --bp-quote-bg 双档。 */
.bp-seg-warm, .bp-seg-quote { border-top: 0; border-radius: var(--r-3); padding: var(--sp-3); }
.bp-seg-warm { background: var(--tag-warn-bg); }
.bp-seg-quote { background: var(--bp-quote-bg); }
.bp-seg-warm + .bp-seg, .bp-seg-quote + .bp-seg { border-top: 0; }
.bp-li { padding: var(--sp-2) 0; border-top: 1px solid var(--border); }
.bp-li:first-child { border-top: 0; padding-top: 0; }
/* 「逾期提醒」这类段里第一条行（1105 站主实拍「中间还多一根横线，像这一行没有内容」）：
   :first-child 命不中它——它前面还压着 .bp-card-h 那行标题，于是标题下凭空多一条上边线。
   补一条相邻判据把它收掉，段与段之间那条分隔线（.bp-seg 的 border-top）照旧留。 */
.bp-card-h + .bp-li { border-top: 0; padding-top: 0; }
.bp-li-h { font-size: var(--fs-13); font-weight: 700; color: var(--text-1); }
.bp-li-p { margin-top: 2px; font-size: var(--fs-13); line-height: 1.55; color: var(--text-3); }
.bp-quote { font-size: var(--fs-14); line-height: 1.6; font-weight: 600; color: var(--text-1); }
/* ---- 参考图版式件（2026-10-29 站主「照着做」）：待办真列表 / 左右状态行 / 温度角标行 / 两枚新 tone ----
   只走 :root 语义 token（R6）；「重要/不急」徽标用既有状态族（--status-bad 即站内逾期/加急同源红），
   不另发明颜色。 */
.bp-item { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-1) 0; font-size: var(--fs-13); color: var(--text-1); }
.bp-dot { flex: none; width: 12px; height: 12px; border-radius: var(--r-1); border: 1.6px solid var(--text-4); }
.bp-item-t { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bp-item-time { flex: none; font-size: var(--fs-11); color: var(--text-4); font-variant-numeric: tabular-nums; }
.bp-pri { flex: none; font-size: var(--fs-11); line-height: 1.5; padding: 0 var(--sp-1); border-radius: var(--r-1); }
.bp-pri.high { color: var(--status-bad); }
.bp-pri.low { color: var(--text-4); }
.bp-stat-row { display: flex; align-items: baseline; gap: var(--sp-2); padding: 2px 0; font-size: var(--fs-13); color: var(--text-1); }
.bp-stat-row > span:first-child { flex: 1; min-width: 0; color: var(--text-3); }
.bp-stat-v { font-size: var(--fs-12); color: var(--text-3); text-align: right; }
.bp-chip-h { display: flex; margin-bottom: var(--sp-2); }
.bp-ico.ico-insight { color: var(--bp-ico-gold-2); }
.bp-ico.ico-knowledge { color: var(--bp-ico-blue); }

/* ---- 2. 今日时间线 ---- */
#ovTimeline { margin-top: var(--module-gap); }
.tl-group { display: flex; align-items: center; gap: var(--sp-2); margin: var(--sp-6) 0 var(--sp-3); }
#ovTimeline > .tl-group:first-child { margin-top: 0; }
.tl-group-l { font-size: var(--fs-label); font-weight: var(--fw-semibold); letter-spacing: .08em; color: var(--text-3); flex-shrink: 0; }
.tl-group-n {
  flex-shrink: 0; min-width: 18px; height: 18px; padding: 0 var(--sp-1); border-radius: var(--radius-pill);
  background: var(--bg-count); color: var(--text-4);
  font-family: var(--font-mono); font-size: var(--fs-micro); line-height: 18px;
  display: inline-flex; align-items: center; justify-content: center; font-variant-numeric: tabular-nums;
}
.tl-group::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.tl-group.is-bad .tl-group-l { color: var(--tag-bad-fg); }
.tl-group.is-bad .tl-group-n { background: var(--tag-bad-bg); color: var(--tag-bad-fg); }

.tl-item {
  position: relative; display: flex; align-items: center; gap: var(--sp-3);
  margin-bottom: var(--sp-3); padding: var(--sp-3);
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-card); box-shadow: var(--shadow-card);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast),
              background var(--transition-fast), transform var(--d-fast) var(--ease-float), opacity var(--d-base) ease;
}
/* 贯穿轨道：1px 竖线落在图标列中心，被不透明的图标底盘截断。
   底色走 --border-strong 而不是 --border：这条线一半的行程落在 12px 行缝里，
   那里露的是画布 --bg-page(#F7F8FA)，用 #E5E7EB 只差 6% 亮度，手机上等于没画
   （1003 真机反馈「连接线被卡片挡在下面」，量的结果是根本没看见）。 */
.tl-item::before {
  content: ""; position: absolute; left: 25px; top: -11px; bottom: -11px;
  width: 1px; background: var(--border-strong);
}
.tl-group + .tl-item::before { top: 50%; }
.tl-item:last-child::before,
.tl-item:has(+ .tl-group)::before,
.tl-item:has(+ .tl-more)::before,
.tl-item:has(+ .tl-empty)::before { bottom: 50%; }
.tl-item[data-tl-id] { cursor: pointer; }
@media (hover: hover) and (pointer: fine) {
  .tl-item[data-tl-id]:hover { border-color: var(--border-strong); box-shadow: var(--shadow-hover); }
  .tl-item[data-tl-id]:hover .tl-title { color: var(--primary); }
}
.tl-ico {
  position: relative; z-index: 1; flex-shrink: 0;
  width: 26px; height: 26px; border-radius: var(--r-circle);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-card); border: 1px solid var(--border); color: var(--text-4);
}
.tl-ico svg { width: 14px; height: 14px; }
.tl-todo .tl-ico { color: var(--text-2); }
.tl-item.is-overdue .tl-ico { background: var(--tag-bad-bg); border-color: transparent; color: var(--tag-bad-fg); }
.tl-item.is-done { background: var(--bg-soft); box-shadow: none; }
.tl-item.is-done .tl-title { color: var(--text-3); }
.tl-item.is-done .tl-ico { border-color: transparent; background: var(--bg-count); }
/* 概览「今天纪念行」不再给整行染色（用户定：只换标不染色）——柔和类型色「今天」小标见 .tl-tag.is-today。 */
/* 「今天还没写」是一句邀请，不是一条空位：底色与其它行同为白卡。
   原先写 transparent，透出的是页面灰底，整行读起来像禁用件；
   而且图标底盘不再能遮住贯穿轨道，竖线会从卡片中间穿过去（0929）。
   「未填写」只由虚线边框表达。 */
.tl-item.is-pending { background: var(--bg-card); border-style: dashed; box-shadow: none; }
/* 按下的反馈只落在「卡片表面」，不落几何：
   时间线是一根竖线串起来的，整卡 scale 会把图标底盘与 ::before 轨道一起缩掉，
   而每行的缩放中心各不相同 → 相邻行的线段互相错开，看起来就是轨道在抖（0929 反馈）。
   表面一沉（底色 + 描边）之后，图标列与轨道纹丝不动，手机端也不会因文字被缩放而发虚；
   控件自己的即时反馈（完成圈 .tl-check:active、去写 .tl-mini）照旧，不在这里叠加。
   ⚠ 必须排在 is-done / is-hit / is-pending 之后：同为 (0,2,0) 特异性，靠源序压过它们的底色，
      否则「已打卡」「就是今天」「待写小记」这三类行按下会一点反馈都没有。 */
.tl-item:active { background: var(--bg-hover); border-color: var(--border-strong); }
.tl-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.tl-title { font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--text-1); line-height: 1.4; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tl-meta { display: flex; align-items: center; min-width: 0; overflow: hidden; font-size: var(--fs-micro); color: var(--text-4); line-height: 1.5; white-space: nowrap; }
.tl-meta > span { flex-shrink: 0; }
/* 分类点与紧随的分类名之间原本 0 间距（dot 与文字是 .tl-meta 两个相邻匿名 flex 项，贴脸）。
   补 --sp-1 右距，与日记行心情点（.tl-mood 自带 4px gap）同一节奏。
   ⚠ .tl-mood 内的点走它自己的 gap，这里必须归零 margin，否则被撑成 8px。 */
.tl-meta .cat-dot { vertical-align: 0; margin-right: var(--sp-1); }
.tl-mood .cat-dot { margin-right: 0; }
.tl-sep { margin: 0 var(--sp-1); color: var(--text-disabled); }
.tl-strong { color: var(--tag-warn-fg); font-weight: var(--fw-medium); }
/* 具体钟点：整条 meta 里唯一「读数字」的元素，等宽 + 加重，比相邻说明大一号。
   字号从 --fs-micro 派生（该令牌在手机端断点被抬到 12px），不写裸 px 也不占新令牌 */
.tl-clock {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: calc(var(--fs-micro) + 2px); font-weight: var(--fw-semibold);
  color: var(--text-1); letter-spacing: -.01em;
}
/* 摘要是整行唯一可收缩项：空间不够时它自己出省略号，不连累前面的色点与分类。
   ⚠ 选择器必须写全链 .tl-meta > .tl-desc：上面那条 `.tl-meta > span` 的特异性是 (0,1,1)，
   裸 `.tl-desc` 只有 (0,1,0) 压不过它——旧版就是这么被静默盖成 flex-shrink:0，
   摘要永远不收缩，窄屏上被 .tl-meta 的 overflow 拦腰裁掉，省略号根本没机会出现
   （1003 探针量出来的，红框里那句「· ·」之外还藏着这一处）。 */
.tl-meta > .tl-desc { min-width: 2.5em; max-width: 12em; flex-shrink: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 心情＝色点 + 档位词，读起来是一个词，不是一点一字。
   旧写法把档位词当裸文本直接挂在 .tl-meta 这个 flex 容器上，匿名项之间零间距，
   色点贴上字、又和后面的摘要糊成一串（1003 真机红框指的就是这一坨）。
   点与字 5px 沿用 .mood-chip / .todo-cat 那两枚「色点 + 文字」的既有节奏，
   只是不描边、不铺底——时间线的次级行本来就靠字号分层，不该再出现一枚胶囊。 */
.tl-mood { display: inline-flex; align-items: center; gap: var(--sp-1); flex-shrink: 0; }
.tl-act { flex-shrink: 0; display: flex; align-items: center; gap: var(--sp-2); }

/* 行内完成：空圈 → 悬停点亮，语义即「把这件事划掉」 */
.tl-check {
  position: relative; width: 30px; height: 30px; padding: 0; flex-shrink: 0;
  border-radius: var(--r-circle); cursor: pointer;
  border: 1.5px solid var(--border-strong); background: var(--bg-card); color: var(--text-disabled);
  display: inline-flex; align-items: center; justify-content: center;
  transition: border-color var(--transition-fast), color var(--transition-fast),
              background var(--transition-fast), transform var(--d-micro) ease;
}
.tl-check svg { width: 15px; height: 15px; }
@media (hover: hover) and (pointer: fine) {
  .tl-check:hover { border-color: var(--primary); color: var(--primary); background: var(--bg-hover); }
}
.tl-check:active { transform: scale(.88); background: var(--primary); border-color: var(--primary); color: var(--on-primary); }

.tl-tag {
  padding: 3px var(--sp-2); border-radius: var(--radius-badge); background: var(--bg-muted);
  color: var(--text-3); font-size: var(--fs-micro); white-space: nowrap; font-variant-numeric: tabular-nums;
}
.tl-tag.is-warn { background: var(--tag-warn-bg); color: var(--tag-warn-fg); }
.tl-tag.is-bad { background: var(--warning); color: var(--white); font-weight: var(--fw-medium); }
/* ⚠ 登记发现（1025 复审）：琥珀实底+白字约 2.2:1，AA 不达标。改字色属视觉变更，待站主定：
   A) 底换 --status-bad 实底+白字（≈3.9:1，仍不达正文但徽标大字可读）B) 改淡底深字同族 is-warn。此处仅等价换 --white，不动视觉 */
/* 概览纪念行柔和标：类型色淡底（--mood 由 tlRow 从事件色带入），退役通用警告橙 */
.tl-tag.is-today { background: color-mix(in srgb, var(--mood, var(--text-3)) 12%, transparent); color: color-mix(in srgb, var(--mood, var(--text-3)) 80%, var(--text-1)); font-weight: var(--fw-medium); }
.tl-tag.is-mood  { background: color-mix(in srgb, var(--mood, var(--text-3)) 10%, transparent); color: color-mix(in srgb, var(--mood, var(--text-3)) 82%, var(--text-1)); }
.tl-mini {
  height: 28px; padding: 0 var(--sp-3); border-radius: var(--radius-pill); cursor: pointer;
  border: 1px solid var(--primary); background: transparent; color: var(--primary);
  font-family: inherit; font-size: var(--fs-caption);
  transition: background var(--transition-fast), color var(--transition-fast);
}
@media (hover: hover) and (pointer: fine) {
  .tl-mini:hover { background: var(--primary); color: var(--on-primary); }
}
/* 实心档：整行唯一的黑色强调点，给「还差一件事」这类待办式邀请用 */
.tl-mini.is-solid { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
@media (hover: hover) and (pointer: fine) {
  .tl-mini.is-solid:hover { background: var(--text-2); border-color: var(--text-2); color: var(--on-primary); }
}
/* 时间线里「打卡」与「去写」是同一类黑底文字胶囊，须同规格：二者只差在 habit 基础高 30（mini 28）。
   只在时间线作用域把高压到 mini 档；习惯页的 habit-toggle-btn 保持原大按钮尺寸（那里是主 CTA，不吃这条）。
   padding / 圆角 / 黑底配色两枚本就一致，无需再补。
   字重同样拉平：habit 基础带 --fw-semibold(600)，tl-mini 从未声明→落 400，故给去写补同一档（.tl-mini 全站仅此一处用，波及面零）。 */
.tl-item .habit-toggle-btn { height: 28px; }
.tl-item .tl-mini { font-weight: var(--fw-semibold); }
.tl-more {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); width: 100%;
  margin: 0 0 var(--sp-3); padding: var(--sp-2) var(--sp-3) var(--sp-2) 51px; cursor: pointer;
  border: 1px dashed var(--border-strong); border-radius: var(--radius-card);
  background: transparent; color: var(--text-3); font-family: inherit; font-size: var(--fs-caption);
  transition: border-color var(--transition-fast), color var(--transition-fast), background var(--transition-fast);
}
.tl-more-go { color: var(--text-4); font-size: var(--fs-micro); flex-shrink: 0; }
@media (hover: hover) and (pointer: fine) {
  .tl-more:hover { border-color: var(--text-4); color: var(--text-1); background: var(--bg-hover); }
}
.tl-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-1);
  padding: 34px var(--sp-4); text-align: center;
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-card); box-shadow: var(--shadow-card);
  color: var(--text-4); font-size: var(--fs-caption);
}
.tl-empty .empty-ico { width: 32px; height: 32px; margin: 0 0 var(--sp-1); }
.tl-empty-t { font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--text-2); }
.tl-empty-acts { display: flex; gap: var(--sp-3); margin-top: var(--sp-3); }

/* ---- 2b. 概览「已打卡」叠卡（1003）----
   卡一律绝对定位、位置只由 transform 表达，容器高度由 JS 量完写死：
   摊开 / 收回于是只剩 transform 与 height 两条补间，子树全程不重排——
   概览是可滚页，这里掉一帧都会被手指感觉到（同一条教训见 .tl-item:active 那段）。
   下面这几枚 --deck-* 数是 deckPaint 唯一读得到的口径：断点里改数值不用动 app.js。 */
.tl-deck {
  --deck-gap: 10px;        /* 摊开时卡与卡的间隙 = .tl-item 原本的 margin-bottom */
  --deck-step: 7px;        /* 叠放时每往下一张往下走多少，也就是「漏出一点边」的厚度 */
  --deck-shrink: .022;     /* 每往下一张缩的比例；缩在顶边（transform-origin），下缘才漏得出来 */
  --deck-layers: 3;        /* 最多露几层边；往后几张不再往外走，摞十张也不会拖出一条长尾 */
  position: relative;
  height: 0;               /* 占位，真值由 deckPaint 量完写进来 */
  margin-bottom: var(--deck-gap);
  transition: height var(--d-morph) var(--ease-nl);
}
.tl-deck > .tl-item {
  position: absolute; left: 0; right: 0; top: 0;
  margin-bottom: 0;
  transform-origin: 50% 0;
  transition: transform var(--d-morph) var(--ease-nl), border-color var(--transition-fast),
              box-shadow var(--transition-fast), background var(--transition-fast), opacity var(--d-base) ease;
}
/* 轨道：摞里每张卡照旧自己画 ::before，不换成容器上的一根。两个理由都是 1003 真机红框指出来的：
   ① 绝对定位的 left 从 padding box 起算——平铺卡带 1px 边框、.tl-deck 不带，
      同一枚数落点差 1px，两根线在行缝里并排就是「红箭头那儿粗了一倍」；
   ② 容器那根压在所有卡（z-index ≥1）底下，卡身那一段被白底盖光；
      而卡自己的 ::before 画在自己背景之上、又被不透明的图标底盘截断——只有后者对。
   下面三条只管「从哪儿起笔、到哪儿收笔」，不改谁来画。 */
.tl-deck[data-open="0"] > .tl-item:not(.is-top)::before { display: none; }
/* 收尾那一张由 JS 指定（摊开＝末张，收起＝首张），且只在这摞确实是本段末位时才收在中线：
   中线正是图标底盘的圆心，于是线「走到小图标就停」，两种状态同一个收法。
   少了这半条，收起态的线会穿过图标、穿过整张卡、再从露边带里继续往下爬（1003 真机图2）。 */
.tl-deck.is-terminal > .tl-item.is-rail-end::before { bottom: 50%; }
.tl-deck.is-after-group > .tl-item.is-top::before { top: 50%; }
/* 摊开时脚下那条「叠起 ↑」：借 .tl-more 的虚线细行外壳，只改成跟着摞一起平移 */
.tl-deck > .tl-deck-fold {
  position: absolute; left: 0; right: 0; top: 0; margin: 0;
  transition: transform var(--d-morph) var(--ease-nl), opacity var(--d-modal) ease,
              border-color var(--transition-fast), color var(--transition-fast),
              background var(--transition-fast);
}
/* 摞起来时后面那几张只是「边」，不抢悬停也不抢点击（点哪儿都算点这摞） */
.tl-deck[data-open="0"] > .tl-item:not(.is-top) { pointer-events: none; }

/* ---- 3. 本周卡已于 0927 撤除：柱子与分类分布不再出现在概览，
        四类内容的家底计数搬进统计页「全部数据」（样式见 .st-counts）。
        .ov-bars / .ov-bar-* 仍被统计页产出趋势复用，留在此处不动。 ---- */

/* ---- 4. 手机端（≤768）：间距规范 v1.0 ---- */
/* ≤768 手机端样式 → 06-mobile.css「---- 4. 手机端（≤768）：间距规范 v1.0 ----」 */
/* 系统要求减少动效时，摊开/收回直接到位（几何仍然照算，只是不补间） */
@media (prefers-reduced-motion: reduce) {
  .tl-deck, .tl-deck > .tl-item, .tl-deck > .tl-deck-fold { transition: none !important; }
}

/* ---- 5. 关于（个人中心 → 设置 → 关于）：沿用 dd-modal 详情页语言 ----
   品牌 lockup 三排居中：① K 字形带底板（亮黑底/暗白底）② 「可序」+ Klog 文字 ③ 版本号 */
.ab-brand { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 0; }
.ab-logo {
  width: 56px; height: 56px; border-radius: var(--r-2); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--brand-plate-ink); background-color: var(--brand-plate); box-shadow: var(--shadow-card);
}
.ab-logo svg { width: auto; height: 42px; display: block; }
.ab-id { min-width: 0; display: flex; flex-direction: column; align-items: center; margin-top: var(--sp-3); }
.ab-name { display: flex; align-items: center; gap: var(--sp-3); font-size: calc(22px * var(--fs-scale)); font-weight: var(--fw-bold); color: var(--text-1); line-height: 1.2; letter-spacing: -.01em; }
.ab-cn { letter-spacing: .06em; }
.ab-ver { margin-top: var(--sp-2); font-size: var(--fs-caption); color: var(--text-3); font-family: var(--font-mono); font-variant-numeric: tabular-nums; letter-spacing: .01em; }
.ab-text { padding: var(--sp-3) var(--sp-4); font-size: var(--fs-caption); line-height: 1.85; color: var(--text-2); }
.ab-text b { color: var(--text-1); font-weight: var(--fw-medium); }
.ab-copy { text-align: center; margin-top: var(--sp-4); font-size: var(--fs-micro); color: var(--text-4); letter-spacing: .02em; }
.pf-chip-ver { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
/* ≤768 手机端样式 → 06-mobile.css */


/* 更新日志（整屏层内容语言：白圆角卡列表） */
.cl-list { padding: 2px 2px 0; }
.cl-item { background: var(--bg-card); border-radius: var(--radius-card-m); box-shadow: var(--shadow-card); padding: var(--sp-3) var(--sp-4) var(--sp-4); margin-bottom: var(--sp-3); }
.cl-ver { font-family: var(--font-mono); font-size: calc(15px * var(--fs-scale)); font-weight: var(--fw-bold); color: var(--text-1); font-variant-numeric: tabular-nums; }
.cl-date { font-size: var(--fs-caption); color: var(--text-4); font-variant-numeric: tabular-nums; }
.cl-cur { margin-left: auto; font-size: var(--fs-micro); font-weight: var(--fw-medium); color: var(--on-primary); background: var(--primary); border-radius: var(--radius-pill); padding: 2px var(--sp-2); }
.cl-ul { margin: var(--sp-3) 0 0; padding: 0; list-style: none; }
.cl-ul li { position: relative; padding-left: var(--sp-4); margin-top: var(--sp-1); font-size: var(--fs-caption); line-height: 1.7; color: var(--text-2); }
.cl-ul li::before { content: ""; position: absolute; left: 3px; top: 9px; width: 5px; height: 5px; border-radius: var(--r-circle); background: var(--text-4); }
.cl-foot { text-align: center; font-size: var(--fs-micro); color: var(--text-4); margin: 2px 0 var(--sp-1); font-variant-numeric: tabular-nums; }
/* 抽屉态：灰底画布 + 内部可滚动，顶部把手/标题固定（无底栏：下拉即关，见 app.js wireSheetGrab） */
.ab-sheet { background: var(--bg-page); display: flex; flex-direction: column; max-height: 88vh; }
.ab-sheet .wp-grab, .ab-sheet .wp-title { flex: none; }
.ab-sheet .cl-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 2px 2px var(--sp-2); }
/* 桌面（≥769）：同一只已接入 WbBack 的整屏层，居中成紧凑对话框，隐去把手 */
@media (min-width: 769px) {
  .ab-mask { align-items: center; justify-content: center; }
  .ab-mask .ab-sheet { width: auto; max-width: 460px; max-height: 82vh; border-radius: var(--r-6); padding-bottom: var(--sp-4);
    transform: translateY(12px); }
  .ab-mask.is-open .ab-sheet { transform: translateY(0); }
  .ab-mask .ab-sheet .wp-grab { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .ab-mask .ab-sheet { transition: none !important; }
}

/* ============================================================
   抽屉把手（拖拽换档 · 2026-09-19）
   把手 + 其下标题行 + 左右空白都可拖：默认≈2/3，上拉到「最长」（顶边贴 App 顶部标题栏下沿）；
   最长态再往下轻拉回到默认；默认态往下拉才关闭；点按在两档间切换。
   按住/拖动时把手小杠只变色（is-on→--text-4），不再变长短。
   与 JS wireSheetGrab 的 DEF/HEADER_GAP 常量成对，改一处要同步另一处。
   ============================================================ */
.wp-sheet { --sheet-max: 50vh; --sheet-tall: calc(100vh - var(--header-h) - var(--safe-top) - 210px); }
.wp-sheet.is-tall { --sheet-max: var(--sheet-tall); }
.wp-grab {
  position: relative; width: 100%; height: 30px; margin: -8px 0 3px;
  background: transparent; touch-action: none; cursor: grab;
  display: flex; align-items: center; justify-content: center;
}
.wp-grab::before { /* 视觉小杠与通栏热区分开：看得见 40×5，摸得到一整条 */
  content: ""; width: 40px; height: 5px; border-radius: var(--radius-pill);
  background: var(--border-strong);
  transition: background var(--d-base) var(--ease-float);
}
.wp-grab:active { cursor: grabbing; }
/* 按住/拖动态由 JS 切 is-on（触屏 :active 会被 preventDefault 吞掉）：只变色，不变长短 */
.wp-grab.is-on::before { background: var(--text-4); }
.tp-sheet .tp-grid, .tp-sheet .cat-list, .mgr-sheet .mg-inner { max-height: var(--sheet-max); }
/* 高档：选择类抽屉保底 60vh 内容高（拉长对短内容也有反馈） */
.wp-sheet.is-tall .tp-grid, .wp-sheet.is-tall .cat-list, .wp-sheet.is-tall .tf-list { min-height: 60vh; }
.tp-grid, .cat-list, .mg-inner { transition: max-height var(--d-push) var(--ease-enter), min-height var(--d-push) var(--ease-enter); }
/* 抽屉内容下拉到顶后再拖直接关：拦住链式滚动，避免连带页/底层滚动回弹 */
.wp-sheet .tp-grid, .wp-sheet .cat-list, .wp-sheet .tf-list, .wp-sheet .mg-inner { overscroll-behavior: contain; }
@media (prefers-reduced-motion: reduce) {
  .tp-grid, .cat-list, .mg-inner, .wp-grab, .wp-grab::before { transition: none; }
  .tps-clear { transition: none; }
}

/* （v3 修订）管理抽屉改全屏后不再泊藏下层：关闭直接下滑露出，零复播 */
/* 键盘升起：遮罩已缩到键盘上方，列表区同步收高保证标题/底栏都在框内 */
.mgr-sheet.is-kbd .mg-inner { max-height: 34vh; }

/* ============================================================
   全屏管理抽屉（2026-09-17）：与全屏详情同一语言。
   遮罩跟随可视视口 → 键盘升起时 flex 内容区自动压缩，
   顶栏常驻、列表滚动，输入框天然露在键盘上方。
   ============================================================ */
.mgr-full {
  height: 100%; border-radius: 0;
  padding: calc(var(--sp-1) + var(--safe-top)) 0 calc(var(--sp-2) + var(--sab));
  display: flex; flex-direction: column;
}
.mgr-full .wp-grab { margin: 0 0 2px; flex: none; }
.mgr-full .mf-head { display: flex; align-items: center; gap: var(--sp-1); padding: 0 var(--sp-1) var(--sp-2); flex: none; }
.mgr-full .wp-title { flex: 1; min-width: 0; margin: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mgr-full .mf-back, .mgr-full .mf-done {
  border: none; background: transparent; cursor: pointer; flex: none;
  height: 40px; min-width: 44px; padding: 0 var(--sp-2);
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-3); -webkit-tap-highlight-color: transparent;
}
.mgr-full .mf-back { color: var(--text-1); }
.mgr-full .mf-back svg { width: 22px; height: 22px; }
.mgr-full .mf-back:active, .mgr-full .mf-done:active { background: var(--bg-hover); }
.mgr-full .mf-done { color: var(--primary); font-size: calc(15px * var(--fs-scale)); font-weight: var(--fw-medium); }
/* 一句话录入 · 按住说话（App 内才有，网页里整条不渲染）：
   底部居中的圆钮——微信式按住落在拇指热区，底部锚定、键盘收起也不挪位；
   放在「应用」胶囊轨道**上方**，胶囊原地进出、麦克风纹丝不动（不抢那颗已定稿的底部胶囊位）。
   三态：静止＝描边软圆 / 按住＝填成黑胶囊并轻轻放大 / 上滑取消＝退回描边并压暗。
   反馈克制：填色 + 提示行文字 + 最轻档震动，不加脉冲动画（站内按下即时态口径）。
   touch-action:none 是按住不动的前提——否则手指上滑会变成滚动整页。 */
.nl-mic-bar { flex: none; display: flex; justify-content: center; align-items: center; padding: 2px var(--sp-4) 0; }
.nl-mic-btn {
  width: 56px; height: 56px; border-radius: var(--r-circle);
  border: 1px solid var(--border); background: var(--bg-card); color: var(--text-1);
  display: inline-flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-float); cursor: pointer; -webkit-tap-highlight-color: transparent;
  touch-action: none; user-select: none; -webkit-user-select: none;
  transition: transform var(--d-fast) var(--ease-float, ease), background var(--d-fast) ease, color var(--d-fast) ease, border-color var(--d-fast) ease;
}
.nl-mic-btn svg { width: 24px; height: 24px; }
.nl-mic-btn:active { transform: scale(.93); }
.nl-mic-btn.is-on { background: var(--primary); color: var(--on-primary); border-color: transparent; transform: scale(1.05); }
.nl-mic-btn.is-cancel { background: var(--bg-card); color: var(--text-3); border-color: var(--border); transform: scale(.93); }
.mgr-full .mg-inner { flex: 1; min-height: 0; max-height: none; margin: 0; }
.mgr-full.is-kbd .mg-inner { max-height: none; }

/* ============================================================
   App 原生外壳（Capacitor）：状态栏避让收口 + 「提醒与手感」分区
   ------------------------------------------------------------
   本块只服务 App：.nt-* 类仅由 assets/klog-native.js 产出，
   [data-shell="app"] 由 index.php 头部探测脚本落到 <html> 上；
   浏览器版两者都不存在，因此对网页版零影响。
   放在文件末尾：确保同等特异性的 ≤768 基线不会把它压成死代码。
   ============================================================ */

/* ---- 1. App 内不该出现的入口：只剩网页表单登录遮罩 ----
   登录账号 / 每日自动备份 / 账户安全 在 App 已改走令牌通道（见 App 登录 + API 接入），
   与网站手机端「完全同页」，故不再对它们隐藏；.login-mask 是网页表单登录遮罩，
   App 用 openCloudSettings 登录页，继续屏蔽。
   「桌面提醒」不再在这里压 display：0923 起 app.js 的 dcManageBlocks 在 App 内直接不渲染
   这一行（连同 #pf-remind-hint），一处决定、不留第二套开关。 */
[data-shell="app"] .login-mask { display: none !important; }

/* ---- 2. 行内时间：它是这一类的「值」，不是第二个按钮 ----
   外观上就是右对齐的等宽数字，点一下开站内时/分滚轮（KlogTimeWheel，
   与日期滚轮同壳）；不加边框不加底色，避免一行里出现两个看起来可点的控件。 */
.nt-time {
  flex: none; -webkit-appearance: none; appearance: none;
  border: 0; background: none; border-radius: var(--r-2);
  color: var(--text-2); font: inherit; font-size: var(--fs-body);
  font-variant-numeric: tabular-nums; letter-spacing: .02em;
  text-align: right; cursor: pointer;
  min-height: 44px; min-width: 64px; padding: 0 var(--sp-1); margin-right: var(--sp-1);
  -webkit-tap-highlight-color: transparent;
  transition: color var(--transition-fast), background var(--transition-fast), opacity var(--transition-fast);
}
.nt-time:active { background: var(--bg-hover); }
.nt-time:focus-visible { outline: 2px solid var(--border-strong); outline-offset: -2px; }
/* WebView 会在数字右侧再画一个小钟，与行尾开关挤成一列参差 —— 去掉，靠说明文案提示可点 */
.nt-time::-webkit-calendar-picker-indicator { display: none; -webkit-appearance: none; appearance: none; }
/* 某一类关掉时：整行留在原位（还要靠它再打开），只把时间压暗禁点。
   0929 起标题列可能是两行字（.pfg-t-2），说明行跟着一起沉，别只压标题 */
.nt-time:disabled { color: var(--text-4); opacity: .4; }
.pfg-ctl:has(.nt-time:disabled) > .pfg-t { color: var(--text-3); }
.pfg-ctl:has(.nt-time:disabled) > .pfg-t .pfg-t-sub { color: var(--text-disabled); }

/* ---- 3. 子行：缩进对齐到标题文字起点，不重复图标 ---- */
.nt-sub { padding-left: calc(var(--card-pad) + var(--sp-6) + var(--sp-3)); }
.nt-sub > .pfg-t { flex: 0 1 auto; font-size: var(--fs-label); color: var(--text-4); }
/* .pfg-row/.pfg-ctl 自带 display 会压掉 UA 的 [hidden]{display:none}，必须点名补回 */
.pfg-row[hidden], .nt-sub[hidden], .nt-type[hidden] { display: none !important; }

/* ---- 4. 分区里的分段控件：沿用同款胶囊外观；手机端高度走 .pf-seg 38px 触控地板，
       桌面（基础档 28px 偏矮）单独抬到 34 ----
   1011 撤掉这里的 `--pfg-row-gap: 8px` 覆写：那 4px 是给分段器多腾的位子，代价是
   「操作强度 / 触感强度 / 自检 / 四类各试一条 / 逐条去开」这些行的标题比整页标题列
   左凸 4px（390 实测 63 vs 67，站主画直尺截图点名）。整页一列靠全站 12px 那枚令牌，
   通栏分段器的 margin-left 引的是同两枚令牌，跟着一起归线，不必另算 */
.nt-seg > .pfg-t { flex: 1 1 auto; }
.nt-seg .pf-seg { flex: 0 0 auto; }
/* 「自检」「触感强度」这类标签+一排按钮的行：按钮数一多就塞不进一行
   （0927 真机：五枚试按钮撑破卡片、"重建排程"被切掉，标签还被挤成两字竖排）。
   统一改成标签独占一行、分段器通栏均分——按钮宽度跟着屏宽走，不再靠缩内距硬塞。 */
/* 新增同类行必须带 .nt-wide——只按行名写死选择器会漏
   （0927 第一版就漏了新加的「操作强度」行，标签被挤成两字竖排）。
   row-gap 单钉 8px：折行后 gap 同时管列距与行距，列距跟全站 12px（标题才在同一列），
   标签↔分段器那 8px 是这只组件自己的节奏，别被 12 顶成 20（1011 实测行高 96→100） */
.nt-wide { flex-wrap: wrap; row-gap: var(--sp-2); }
.nt-wide > .pfg-t { white-space: nowrap; }
/* 两行字标题进了 nt-wide：nowrap 只该管标题，小字说明必须能折行，
   否则长句会把标题列撑破卡片（nowrap 是从 .pfg-t 继承下来的） */
.nt-wide > .pfg-t .pfg-t-sub { white-space: normal; }
/* 通栏分段器与标题行之间那口气：这是「标签一行 + 分段器一行」这只组件自己的几何，
   不是「提醒与震动」这一页的偏好，所以不挂 .nt-page —— 抽屉里同款行（小记图片的原图上限）
   不套页面外壳也该拿到同一个值。 */
.nt-wide .pf-seg-fill { margin-top: var(--sp-2); }
/* 通栏分段器：独占一行、按钮均分。左缘对齐「标题文字起线」（一枚图标列 + 一道行间距），
   右缘仍到卡内衬为止。旧写法从卡片内距一路铺到右缘，比标题整整左凸一个图标列，
   在一页全是「图标 + 标题」的节奏里读起来就是没对齐（1003 站主点名「有点长了」）。
   basis 照旧 100%：加了这段左距后由 flex-shrink 自己收回来，右侧不用另算宽度。 */
.pf-seg.pf-seg-fill {
  flex: 1 1 100%; order: 2; width: auto;
  /* 真塞不下时（≤320 那档六颗一排）整段换行，而不是把字切掉 */
  flex-wrap: wrap;
  margin-left: calc(var(--pfg-ico-w, var(--sp-6)) + var(--pfg-row-gap, var(--sp-3)));
}
/* 按钮均分这件事，旧写法是 basis 0 + min-width 0：min-width:0 把「至少装得下自己的字」
   这条地板也一起拆了，六颗一排时「重建排程」这类四字标签会被压到切字
   （1003 左缘对齐标题之后，390 上就切了）。
   正解是 basis 仍为 0（保证能均分）+ 地板换成 max-content：
   装得下就四颗等宽，装不下的那一颗自己认领宽度——而不是靠切字维持「看起来等宽」。 */
.pf-seg.pf-seg-fill button { flex: 1 1 0; min-width: max-content; padding: 0 var(--sp-1); white-space: nowrap; }
@media (min-width: 769px) {
  .nt-seg .pf-seg button { height: 34px; padding: 0 var(--sp-3); }
}

/* ---- 5. 超窄屏（≤380）：只收缩内距，间距与栅格不回退；高度与字号守住地板 ---- */
/* ≤768 手机端样式 → 06-mobile.css「---- 5. 超窄屏（≤380）：只收缩内距，间距与栅格不回退；高度与字号守住地板 ----」 */

/* ---- 6. 页面级留白（0929 小米真机：整页「太挤」）----
   两行字档把内容顶到 ~44px，可上下内距还是通用那套 0 —— 标题、说明、发丝线
   三样贴成一团。这一组只改「提醒与震动」页（小部件页昨天真机已过，不去动它）：
   行上下给 10px、标题与说明之间 3px、分组之间 30px。
   （通栏分段器与标题之间那 8px 已上移进 .nt-wide 组件段——它是这只组件的几何，不是这页的偏好。） */
.nt-page .pfg { margin-top: 30px; }
/* 1011 并一条：折行的通栏分段器行（标签一行+分段器一行）同样上下 10px——
   .pfg-row 竖向 padding 本来是 0、全靠 min-height 居中，单行没事，折行把内容顶满
   就贴着发丝线/卡边了（站主点名「内边距没有了」）。选择器并进本条、不另开一条：
   同体的第二条规则会被防膨胀闸当场红成一组新重复 */
.nt-page .pfg-row:has(.pfg-t-2), .nt-page .pfg-row.nt-wide:has(.pf-seg-fill) { padding-top: var(--sp-2); padding-bottom: var(--sp-2); }
.nt-page .pfg-t-2 { gap: 3px; }
.nt-page .pfg-note { padding-top: var(--sp-2); padding-bottom: var(--sp-4); }
/* 「提前提醒」这类子行只有一行字，不给内距就会比上下两行字的行明显薄一层 */
.nt-page .nt-sub { padding-top: var(--sp-2); padding-bottom: var(--sp-2); }

/* 手机端筛选条撑满整行：「全部标签/分类/类型」入口钉右缘（桌面保持内容宽排布） */
/* ≤768 手机端样式 → 06-mobile.css「手机端筛选条撑满整行：「全部标签/分类/类型」入口钉右缘（桌面保持内容宽排布）」 */

/* 手机端待办分段器（待办/已完成/全部）：撑满一行、三段均分，与筛选条同宽。
   1014 站主点名「分段器高度降低一点」：按钮从 --control-h(44) 收到 38（chip 同档，热区不缺），
   整只 pill 由 52 降到 46。 */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   统计（一期：产出量趋势 · 日 / 周 / 月 / 年）
   刻意不另起视觉语言：卡片用现成 .panel、柱子用 .ov-bars、
   色阶走 --primary + color-mix（--on-primary 在暗色主题自动翻墨色，
   不需要第二套档位，也不必像习惯热力那样每次算 hmVars）。
   ============================================================ */
.st-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  flex-wrap: wrap; margin-bottom: var(--card-gap);
}
.st-nav { display: flex; align-items: center; gap: var(--sp-1); min-width: 0; flex: 1; min-height: var(--control-h); }
/* 工具区只剩粒度分段器：正方形钮靠右，时间标签自己在中间那一段里居中 */
.st-tools { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); min-width: 0; }
.st-navbtn {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border: 1px solid var(--border); border-radius: var(--radius-btn);
  background: var(--bg-card); color: var(--text-2); cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.st-navbtn svg { width: 16px; height: 16px; }
@media (hover: hover) { .st-navbtn:hover { background: var(--bg-hover); color: var(--text-1); } }
.st-navbtn:active { transform: scale(.94); }
/* 未来不可见：已到本期时「下一期」直接锁死，不是点了没反应 */
.st-navbtn:disabled { color: var(--text-disabled); background: transparent; cursor: default; border-color: var(--border-dashed, var(--border)); }
.st-navbtn:disabled:active { transform: none; }
/* 时间标签 + 尾巴上那枚「本期 / 回到本期」当成一组居中（照搬 .hm-range 的排法）：
   两态都住在 #stRangeTag 这一个槽里，所以「回本期」出现/消失不再需要影子位。
   1004 与心情/习惯热力同步：时间文本包进白卡，圆角对齐两侧方形翻页钮（--radius-btn） */
.st-range {
  flex: 1; min-width: 0; display: flex; align-items: center; justify-content: center; gap: var(--sp-1);
  /* 与 .hm-range 同步（1004）：允许尾巴那枚退到第二行，白卡用 min-height 自己长开 */
  flex-wrap: wrap; row-gap: 2px;
  font-size: var(--fs-body); font-weight: var(--fw-semibold); color: var(--text-1);
  font-variant-numeric: tabular-nums;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-btn);
  box-shadow: var(--shadow-sm); min-height: 38px; padding: 0 var(--sp-3);
}
.st-range-t { white-space: nowrap; }
.st-range-tag { flex: none; display: inline-flex; align-items: center; }
/* 本期徽章与「回到本期」钮：1004 起直接继承全站统一的黑底当期胶囊 / 灰底返回胶囊，
   不再做统计页特例（旧「灰底本期 + 放大返回钮」已并入基础 .hm-cur / .hm-back） */
/* 粒度钮做成正方形：宽度直接取控件高度令牌，改 --control-h 也不会变形 */
/* 1014 站主点名「日周月年这张卡圆角要圆润一些」：容器从 .seg 的 4px 抬到 r-3(12)，
   与待办分段器、内容卡同档；.seg 自带 overflow:hidden，方钮首尾随容器裁成圆角。 */
.st-seg { border-radius: var(--r-3); }
.st-seg button {
  flex: none; width: var(--control-h); padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
}
/* 「回本期」独立钮已于 1003 退役：复位入口搬到时间标签后面那枚 .hm-back（见上） */
.st-seg button { padding: 0 var(--sp-3); }
.st-body { display: flex; flex-direction: column; gap: var(--card-gap); }

/* hero：白卡 + 一个大数字，层级靠字号而不是加色块 */
.st-hero { padding: var(--sp-4) var(--sp-4) var(--sp-3); }
.st-hero-n { display: flex; align-items: baseline; gap: var(--sp-3); }
.st-hero-n b {
  font-size: var(--fs-num-lg); line-height: 1.05; font-weight: var(--fw-semibold); color: var(--text-1);
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
}
.st-hero-n span { font-size: var(--fs-caption); color: var(--text-3); }
.st-hero.is-quiet .st-hero-n b { color: var(--text-disabled); }
.st-hero-parts {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-3); margin-top: var(--sp-3);
  font-size: var(--fs-body); color: var(--text-2);
}
.st-hero-parts b { font-weight: var(--fw-semibold); color: var(--text-1); font-variant-numeric: tabular-nums; }
.st-hero-foot {
  margin-top: var(--sp-2); padding-top: var(--sp-2); border-top: 1px dashed var(--border);
  font-size: var(--fs-caption); color: var(--text-3);
}
.st-hero-foot b { font-weight: var(--fw-medium); color: var(--text-2); font-variant-numeric: tabular-nums; }

/* 热力网格：格子 = 日号 + 当日产出数（未来日留空数字、只保留轮廓） */
.st-heat { padding-bottom: var(--sp-3); }
.st-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--sp-1); padding: var(--sp-3) var(--sp-4) 0; }
/* 星期标头与 .st-grid 同列宽同间距（.hm-wkrow 有 336px 居中约束，这里借会错一格） */
.st-wkrow { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--sp-1); padding: var(--sp-3) var(--sp-4) 0; }
.st-wkrow span { text-align: center; font-size: var(--fs-micro); line-height: 1; color: var(--text-4); }
.st-g-year { grid-template-columns: repeat(6, 1fr); }
.st-g-week { grid-template-columns: repeat(7, 1fr); }
.st-cell {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  min-height: 42px; padding: var(--sp-1) 2px; border: none; border-radius: var(--r-1);
  background: var(--bg-soft); color: var(--text-2); font: inherit; cursor: pointer;
  transition: transform var(--d-micro) var(--ease-float), filter var(--transition-fast);
}
.st-cell.is-pad { background: transparent; cursor: default; }
.st-c-l { font-size: var(--fs-micro); line-height: 1.2; color: inherit; font-variant-numeric: tabular-nums; }
.st-c-n { font-size: var(--fs-caption); font-weight: var(--fw-semibold); line-height: 1.2; color: inherit; font-variant-numeric: tabular-nums; }
.st-cell.is-future .st-c-n:empty + .st-c-l, .st-cell.is-future { opacity: .55; }
@media (hover: hover) { .st-cell:hover { filter: brightness(.97); } }
.st-cell:active { transform: scale(.94); }
.st-cell.is-today { box-shadow: inset 0 0 0 1.5px var(--primary); }
/* 四档：1014 起与账本支出日历共用同一族 --lgd-* 墨档（透明度过台面，暗色自动翻亮）——
   站主点名「两页最深档一个太浅一个太深，浅一些后统一」。顶格从原 --primary 铺满（100%）
   收到 --lgd-3（78%），两页最深档同深浅，「最猛的那几天」仍一眼可辨。
   选择器并成一条（.st-l* 与 .lg-day/.lg-mo 的 l* 同深浅同声明，不抄两遍）。 */
.st-l0 { background: var(--bg-soft); color: var(--text-disabled); }
.st-l1, .lg-day.l1, .lg-mo.l1 { background: var(--lgd-1); color: var(--lgd-ink-1); }
.st-l2, .lg-day.l2, .lg-mo.l2 { background: var(--lgd-2); color: var(--lgd-ink-2); }
.st-l3, .lg-day.l3, .lg-mo.l3 { background: var(--lgd-3); color: var(--lgd-ink-3); }
.st-legend {
  display: flex; align-items: center; justify-content: flex-end; gap: var(--sp-1);
  padding: var(--sp-2) var(--sp-4) 0; font-size: var(--fs-micro); color: var(--text-4);
}
.st-legend .st-cell { min-height: 0; width: 14px; height: 14px; border-radius: var(--r-1); cursor: default; }
.st-legend .st-cell:active { transform: none; }

/* 趋势柱：.ov-bars 只负责排布，这里补高度与「按钮化」重置 */
.st-trend { padding-bottom: var(--sp-3); }
.st-bars { min-height: 118px; padding: var(--sp-3) var(--sp-4) 0; }
.st-bar-col { border: none; background: transparent; cursor: pointer; font: inherit; }
.st-bar-col .ov-bar-l { font-variant-numeric: tabular-nums; }
.st-bar-col:active .ov-bar { filter: brightness(.9); }

/* ---- 分项情况（原名「各科目 · 本期 + 家底」）：原「全部数据」四枚死数字的下一形态（1011）----
   每科一行头（图标 + 名 + 较上期）+ 本期内容；待办给在库结构条、
   打卡列习惯行（连续天数来自现成算法）、账本金额走 .num 等宽。
   快照类（在库/逾期/共 N）不随本期变，文案里标的都是「当前」语境。 */
.st-ms { padding: var(--sp-3) var(--sp-4) var(--sp-4); }
.st-ms + .st-ms { border-top: 1px solid var(--border); }
.st-ms-h {
  display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2);
  font-size: var(--fs-label); font-weight: var(--fw-semibold); color: var(--text-1);
}
.st-ms-h svg { width: 15px; height: 15px; color: var(--text-3); flex: none; }
.st-ms-dl {
  margin-left: auto; font-size: var(--fs-micro); font-weight: var(--fw-regular);
  color: var(--text-4); font-variant-numeric: tabular-nums;
}
.st-ms-l1 { font-size: var(--fs-body); color: var(--text-2); }
.st-ms-l1 b, .st-ms-slim b { font-weight: var(--fw-semibold); color: var(--text-1); font-variant-numeric: tabular-nums; }
.st-ms-slim {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2);
  font-size: var(--fs-body); color: var(--text-2);
}
.st-ms-x { margin-left: auto; font-size: var(--fs-micro); color: var(--text-4); font-variant-numeric: tabular-nums; }
.st-ms-now { white-space: nowrap; }
/* 待办结构条：完成占比铺墨，右侧给在库/未完成/逾期 */
.st-ms-bar { display: flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-2); }
.st-ms-track { flex: none; width: 84px; height: 6px; border-radius: var(--r-pill); background: var(--bg-muted); overflow: hidden; }
.st-ms-fill { display: block; height: 100%; border-radius: var(--r-pill); background: var(--text-1); }
.st-ms-cap { font-size: var(--fs-micro); color: var(--text-4); font-variant-numeric: tabular-nums; }
.st-ms-cap b { font-weight: var(--fw-medium); color: var(--text-2); }
/* 习惯行：色点 + 名 + 次数/连续 */
.st-ms-rows { margin-top: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-2); }
.st-ms-row { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-caption); color: var(--text-2); }
.st-ms-dot { width: 8px; height: 8px; border-radius: var(--r-circle); flex: none; }
.st-ms-name { min-width: 52px; }
.st-ms-val { margin-left: auto; color: var(--text-3); font-variant-numeric: tabular-nums; }
.st-ms-val b { color: var(--text-1); font-weight: var(--fw-semibold); }
.st-ms-row.is-off { opacity: .62; }

/* 环比小胶囊：中性灰语言，不引红绿（涨跌都是同一枚）。
   1014：撤掉旧的 translateY(-3px) 手调偏移——徽章与「本月完成」改由 .st-hero-side
   这只 inline-flex 容器 align-items:center 真正上下居中，不再靠像素硬顶。 */
.st-chg {
  font-style: normal; display: inline-flex; align-items: center; height: 22px; padding: 0 var(--sp-2);
  border-radius: var(--r-pill); background: var(--bg-muted); color: var(--text-3);
  font-size: var(--fs-micro); font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
}
/* 「本月完成 + 环比胶囊」这一组自成一条居中线，与大数字仍走 .st-hero-n 的 baseline */
.st-hero-side { display: inline-flex; align-items: center; gap: var(--sp-3); }

/* 趋势图例即筛选：点一科只看一科（热力跟着联动），再点同一科 /「显示全部」复位 */
.st-flt {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); padding: var(--sp-2) var(--sp-4) 0;
  font-size: var(--fs-micro); color: var(--text-3);
}
.st-flt button {
  display: inline-flex; align-items: center; gap: var(--sp-1); border: none; background: none;
  padding: 2px 0; font: inherit; font-size: var(--fs-micro); color: var(--text-3); cursor: pointer;
}
.st-flt button i { width: 9px; height: 9px; border-radius: var(--r-circle); flex: none; }
.st-flt button.on { color: var(--text-1); font-weight: var(--fw-semibold); }
.st-flt button.on i { box-shadow: 0 0 0 2px var(--bg-card), 0 0 0 3.5px var(--text-1); }
.st-flt-reset {
  margin-left: auto; border: none; background: none; padding: 2px 0; font: inherit;
  font-size: var(--fs-micro); color: var(--text-3); text-decoration: underline; cursor: pointer;
}
/* 堆叠柱：柱身仍用 .ov-bar 外壳（整列热区 / 按压 / 禁用规则原样生效），
   st-stk 只把「单色底」换成「五段墨阶」——段与段留 2px 缝 */
.st-bars .ov-bar.st-stk {
  background: transparent; min-height: 0; border-radius: 0;
  display: flex; flex-direction: column; justify-content: flex-end; gap: 2px;
}
.st-stk i { display: block; width: 100%; border-radius: var(--r-1); font-style: normal; }

/* 统计页脚注：口径写死在页面上，避免「这数字怎么算的」反复问 */
.st-note {
  margin-top: var(--card-gap); padding: 0 2px;
  font-size: var(--fs-micro); line-height: 1.6; color: var(--text-4);
}
.st-note b { font-weight: var(--fw-medium); color: var(--text-3); }

/* ---- 手机端（真机生效的那份）：导航行在上、粒度分段器撑满一行 ---- */
/* ≤768 手机端样式 → 06-mobile.css「---- 手机端（真机生效的那份）：导航行在上、粒度分段器撑满一行 ----」 */

/* ============================================================
   表单出错态（0924 定稿）：只点亮 label，不给输入框描红框
   ------------------------------------------------------------
   试过「控件描红 + 外圈柔红环 + 井底染红」，在浅底表单上太扎眼，用户否掉。
   定位靠这三样就够：label 变红（含必填星号）、滚动到位并聚焦、整卡抖一下；
   文案交给站内 toast 胶囊。
   .is-invalid 由 showFormError 挂在「看得见的那件控件」上（select / date 被
   enhance 成 .sel-btn / .dp-display，原生件 display:none），这里只当钩子用，
   不产生任何描边或底色。
   ============================================================ */
.field:has(.is-invalid) > label,
.field-row > div:has(.is-invalid) > label { color: var(--status-bad); }
/* 动效 S6 · label 校验红软切（2026-10-20）：#formError 已从各表单退役（app.js:3368 明写：
   长表单里红字常落在折叠线以下，点了保存像「没反应」；改为「label 变红 + 抖动 + toast」三件套）。
   红/黑切换此前是**色彩硬切**——与卡片抖一下不同拍、读起来「啪」跳色。补一条 transition:color 150ms
   --ease-float 让 label 软切色、与抖动同步；覆盖 is-invalid 变红与摘掉回墨两个方向。
   作用域限表单里 <label> 元素自身、不吃全站 label（tabbar/设置分组那些另有语义）。回滚＝删本段。 */
.fg-card .field > label,
.fg-card .field > label .req,
.field > label { transition: color var(--transition-fast) var(--ease-float); }
@media (prefers-reduced-motion: reduce) {
  .fg-card .field > label,
  .fg-card .field > label .req,
  .field > label { transition: none; }
}

/* ---- 统计 · 日视图流水账 ----
   一条一笔，时刻靠左等宽对齐；虚线分隔沿用小票语言，不加任何彩色 */
.st-lg { padding: 2px 0 var(--sp-1); }
.st-lg-row {
  display: flex; align-items: baseline; gap: var(--sp-3); padding: var(--sp-2) var(--sp-4);
  border-top: 1px dashed var(--border);
}
.st-lg-row:first-child { border-top: none; }
.st-lg-t {
  flex: none; width: 46px; font-family: var(--font-mono); font-size: var(--fs-body);
  color: var(--text-3); font-variant-numeric: tabular-nums;
}
.st-lg-x {
  flex: 1; min-width: 0; font-size: var(--fs-body); color: var(--text-1);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.st-lg-x i { font-style: normal; color: var(--text-3); margin-right: var(--sp-2); }
.st-lg-x b { font-weight: var(--fw-medium); }/* (1008 死规则清理) */
.st-lg-empty { padding: var(--sp-3) var(--sp-4) var(--sp-2); font-size: var(--fs-body); color: var(--text-4); }
.st-print {
  border: none; background: transparent; padding: 0 2px; cursor: pointer;
  font: inherit; font-size: var(--fs-caption); color: var(--text-3);
  text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--border-strong);
}
@media (hover: hover) { .st-print:hover { color: var(--text-1); text-decoration-color: currentColor; } }
.st-print:active { color: var(--primary); }

/* ---- 统计：未来不可看、不可点 ----
   格子与柱子直接降级成展示态（disabled），不留「点了没反应」的错觉；
   翻页的「下一期」到本期就锁死，上一期永远可走 */
.st-cell:disabled, .st-bar-col:disabled { cursor: default; }
@media (hover: hover) { .st-cell:disabled:hover { filter: none; } }
.st-cell:disabled:active { transform: none; }
.st-bar-col:disabled { opacity: .45; }
.st-bar-col:disabled:active .ov-bar { filter: none; }



/* ============================================================
   搜索体系 v2（2026-09-30）：顶栏一个入口
   手机端 = 顶栏圆形次要钮 → 底部检索抽屉（.wp-sheet 现成外壳）；
   桌面 = 「检索 Ctrl K」胶囊（同样是唯一入口）。
   v1 那套「把搜索框搬进分类 chip 行、跨断点搬 DOM」的几何已整体退役：
   入口唯一之后没有服务对象了。保留的只有药丸材质本身——抽屉里的输入框
   直接复用 .search-field / .search-field-input，不再另造一只输入框。
   本块仍刻意放在文件最末：它要覆盖 .form-input/.search-field-input 基线、
   757 的 .toolbar 白底、1380 与 3319~3329 的 ≤768 降级块。
   ============================================================ */

/* ---- 1. 药丸材质（抽屉与桌面页内框共用；1003 圆角并入 --fld-r 12 档） ---- */
.search-field { height: 36px; }
/* 1004b 收编（站主点名）：搜索框并入「1px 主描边 + 12px 柔光渐隐」家族，
   静息预留 1px 透明描边——从「宽度归 0」改回预留，换聚焦换色不跳字
   （当年归零是给无描边时代定的字起笔几何，现由聚焦描边接棒） */
.search-field-input {
  height: 100%; border: 1px solid transparent; border-radius: var(--fld-r); /* 1003：圆角并入家族 12 档（原全圆药丸） */
  font-size: var(--fs-caption);
  padding-left: 34px; padding-right: var(--sp-3);
  transition: background var(--transition-fast), box-shadow var(--transition-fast), border-color var(--transition-fast);
}
/* 底色写在 :where() 里（特异性 0）：任何一条站点级底色规则（含 757 的 .toolbar
   白底、1380 的 ≤768 深色块）都能自然盖过它，不必在文末再补一面墙 */
:where(.search-field-input) { background: var(--bg-count); }
/* 1004b：聚焦时悬停不再改底色（聚焦为准，与井族同规则；鼠标停在聚焦框上不吃 hover 档） */
@media (hover: hover) { .search-field-input:hover:not(:focus) { border-color: transparent; background: var(--bg-count-active); } }
/* 1004b 定稿：不再浮白（聚焦底色全程不动），聚焦 = 1px 主描边 + 12px 柔光渐隐
   （--focus-glow）——与井族 / 登录盒同一枚语言；旧的「浮白 + 3px 实环」退役 */
.search-field-input:focus {
  border-color: var(--primary); box-shadow: var(--focus-glow);
}
.search-field:focus-within .search-field-icon { color: var(--text-2); }

/* 清空钮：从「隐形 X」升级成可辨认的小灰圆 */
.search-clear { width: 20px; height: 20px; right: 8px; border-radius: var(--radius-pill); }
.search-clear svg { width: 9px; height: 9px; stroke-width: 1.8; }
@media (hover: hover) { .search-clear:hover { background: var(--bg-count-active); color: var(--text-1); } }

/* ---- 2. 命中词高亮：只靠重色块，绝不加粗（加粗会抖行宽） ---- */
.s-hit {
  background: color-mix(in srgb, var(--text-1) 13%, transparent);
  color: var(--text-1); font-weight: inherit; border-radius: var(--r-1);
  padding: 0 1px; box-decoration-break: clone; -webkit-box-decoration-break: clone;
}
[data-theme="dark"] .s-hit { background: color-mix(in srgb, var(--text-1) 32%, transparent); }

/* ---- 3. 桌面顶栏「检索」胶囊 ---- */
.cmdk-btn { display: none; }
@media (min-width: 769px) {
  .cmdk-btn {
    display: inline-flex; align-items: center; gap: var(--sp-2); height: 30px; padding: 0 var(--sp-2) 0 var(--sp-2);
    border: 1px solid var(--border); border-radius: var(--radius-pill); background: var(--bg-card);
    color: var(--text-3); font-size: var(--fs-micro); font-family: inherit; cursor: pointer;
    transition: border-color var(--transition-fast), color var(--transition-fast);
  }
  @media (hover: hover) { .cmdk-btn:hover { border-color: var(--border-strong); color: var(--text-1); } }
  .cmdk-btn svg { width: 13px; height: 13px; }
  .cmdk-key {
    font-family: var(--font-mono); font-size: var(--fs-10); color: var(--text-4);
    border: 1px solid var(--border); border-radius: var(--r-1); padding: 1px var(--sp-1);
    background: var(--bg-page);
  }
}

/* ---- 4. 手机端顶栏搜索入口（v3，1011）：圆钮 ⇄ 就地输入框 morph ----
   折叠态 = 原「描边不填充」圆形次要钮（与实心头像钮一眼分层）；点击后同一元素
   向左拉长成输入框（width 过渡到 --hs-w，由 JS 按「吃满标题区、右缘留头像」现算），
   标题区让位淡出、放大镜滑进框内左缘、输入框淡入（软聚焦弹键盘）。
   输入框直接复用 .search-field-input（v2 令「不再另造一只输入框」）：同一枚
   --bg-count 槽 + 聚焦主描边柔光；只做容器内绝对定位铺满与圆角跟随。 */
.head-search {
  display: none;                              /* 桌面隐藏，那里是「检索」胶囊 */
  position: relative; align-items: center; flex-shrink: 0;
  /* 半径必须是**定值**，不能用 --r-circle(50%)：50% 在 morph 里随宽度「活性」重算——
     圆钮拉宽时半径永远等于半宽，整只变成一个被拉扁的椭圆（站主真机反馈实拍）。
     17→12 的纯长度插值才平滑。闸门的「裸 px 圆角钉 0」要求吃令牌，但这里**不能用 --control-h**：
     它在 ≤768 段被重映射成 44px（iOS 触控档，见本文件 2198 行），拿它撑圆钮会把 34 撑成 44
     ——探针实测折叠态宽 44、半径 22，三只断言当场红。改成这只入口自己的尺寸变量，
     半径 = 尺寸的一半，天然正圆，尺寸档一动它跟着动 */
  --hs-size: 34px;
  width: var(--hs-size); height: var(--hs-size);
  border-radius: calc(var(--hs-size) / 2); cursor: pointer;
  border: 1px solid var(--border-strong); background: transparent; color: var(--text-2);
  -webkit-tap-highlight-color: transparent;
  transition: width var(--d-med) var(--ease-float), border-radius var(--d-med) var(--ease-float),
              border-color var(--transition-fast), background var(--transition-fast);
}
/* 按下反馈只给折叠态（展开后它是输入框的宿主，不再是一个按钮）。
   :not(.is-closing) 是防 Android「:active 粘滞」的挡板：点 ✕ 收起时容器作为祖先
   也点亮 :active，松手后 :active 还会残留几百 ms——is-open 一摘，这条 scale(.94)
   会突然命中、随后 :active 消退再回弹，正是站主实拍的「✕ 收起快结尾抖一下」
   （侧滑关闭没有点按所以不抖）。hsClose 给容器挂 is-closing 约 450ms 屏蔽掉它 */
.head-search:not(.is-open):not(.is-closing):active { transform: scale(.94); color: var(--text-1); }
.head-search:not(.is-open):focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }
.head-search.is-open {
  width: var(--hs-w, 240px);
  border-radius: var(--fld-r);                /* 收进输入框圆角档（原来漏写，圆角一直是 50%）；
                                                 不带 fallback——令牌根上必有，写了反而吞掉「令牌被误删」的事故 */
  border-color: transparent; background: var(--bg-count); cursor: default;
}
/* ≤768 手机端样式 → 06-mobile.css */
/* 放大镜：折叠态在圆钮中心（border 内侧 (32-16)/2=8），展开后滑到框内左缘 12 */
.hs-icon {
  position: absolute; left: 8px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; pointer-events: none; z-index: 1;
  transition: left var(--d-med) var(--ease-float), color var(--transition-fast);
}
.head-search.is-open .hs-icon { left: 12px; color: var(--text-4); }
/* 输入框：inset 超出 1px 恰好盖住容器描边位（34 整框=聚焦描边的画布，同 .ss-field 口径）。
   visibility 时序：展开先亮框、字延迟一拍淡入；收起字先退、框后收。
   transition 写全——覆盖基线那三枚（聚焦描边/底色）后不能让它们失去过渡。 */
.head-search .hs-in {
  position: absolute; inset: -1px; width: auto; height: auto;
  border-radius: inherit; padding-left: 38px; padding-right: var(--sp-8);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity var(--d-fast) ease, visibility 0s linear var(--d-fast),
              background var(--transition-fast), box-shadow var(--transition-fast), border-color var(--transition-fast);
}
.head-search.is-open .hs-in {
  opacity: 1; visibility: visible; pointer-events: auto;
  transition: opacity var(--d-base) ease .08s, visibility 0s,
              background var(--transition-fast), box-shadow var(--transition-fast), border-color var(--transition-fast);
}
/* 尾部 ✕：两段语义（有字先清空 / 空态再点收回）由 JS 接管，钮常驻可见；
   沿用 .search-clear 的底子，按 .ss-field 的口径放大 + ::after 扩热区 */
.head-search .hs-x {
  width: 26px; height: 26px; right: 6px; z-index: 2;
  opacity: 0; visibility: hidden;
  transition: opacity var(--d-fast) ease, visibility 0s linear var(--d-fast);
}
.head-search.is-open .hs-x { opacity: 1; visibility: visible; transition: opacity var(--d-fast) ease .06s, visibility 0s; }
.head-search .hs-x svg { width: 11px; height: 11px; }
.head-search .hs-x::after { content: ""; position: absolute; inset: -8px; }
/* 标题让位与回归。收起方向「先回宽度、再淡入」：文字必须 nowrap + 裁切——
   折行的话，宽度恢复途中每跨一个换行阈值（2 行→1 行）就跳一下（站主实拍
   「快完成收缩时跳动一下」；展开方向不跳是因为文字那时已淡出、看不见换行）。
   过渡参数取「变化后状态」的那份：展开（.hs-search 在场）立即淡出；
   收起（.hs-search 已摘）延迟 .1s 再淡入，让宽度先收过大半。 */
/* ≤768 手机端样式 → 06-mobile.css */

/* ---- 4b. 就地搜索结果布幕（v3，1011）：顶栏下沿拉下的白面板 ----
   顶锚在顶栏底部（top 抄 .header/.chain-bar 那一条 calc），键盘弹起只压底边——
   沿用全屏页的「位移从根上消失」结论；高度由 JS 按内容与 visualViewport 现算
   max-height（带过渡，键盘台阶摊成滑行），内容超出时 .ss-results 内滚动。
   内容复用旧页那套 .ss-hint / .ss-well / .ss-row（灰画布 + 描边白卡），
   两份同一口径。 */
.hs-guard {
  /* 搜索态遮罩：透明、吞掉布幕外的一切点击与手势（专注态，退出走 ✕ / 返回键）。
     顶边必须从顶栏底起——顶栏本身要保持可交互（点输入框挪光标、点 ✕ 清空/收回）。
     曾用 inset:0 全屏：guard(z69) 把顶栏(z50) 整个盖住，✕ 与输入框全点不动，
     探针 E 段「✕ 落点自证」当场抓到。 */
  position: fixed; left: 0; right: 0; bottom: 0;
  top: calc(var(--safe-top) + var(--header-h));
  z-index: 69; touch-action: none;
}
.hs-panel {
  position: fixed; left: 0; right: 0;
  top: calc(var(--safe-top) + var(--header-h));
  z-index: 70; box-sizing: border-box;
  background: var(--bg-card);
  border: 1px solid var(--border); border-top: none;
  border-radius: 0 0 var(--r-4) var(--r-4);
  box-shadow: var(--shadow-modal);
  overflow: hidden;
  display: flex; flex-direction: column;
  padding: 0 var(--sp-4) var(--sp-3);
  max-height: 0; opacity: 0;
  transition: max-height var(--d-toast) var(--ease-float), opacity var(--d-base) ease;
}
.hs-panel[hidden] { display: none; }
/* 搜索态收 dock：底锚是 fixed，键盘起落时它会在布幕下沿露头（同 body.ss-open 口径） */
body.hs-open .tabbar { display: none; }
/* 「最近搜索」组行右侧的清空钮（旧页清空贴在标题右侧，布幕没有标题行） */
.hs-hc {
  border: none; background: transparent; cursor: pointer; padding: 0 2px;
  font-size: var(--fs-micro); color: var(--text-4); font-family: inherit;
  -webkit-tap-highlight-color: transparent;
}
.hs-hc:active { color: var(--text-2); }
/* 历史词 chip 流（站主拍板「一行一条太占空间」）：材质与结果行同款
   （--bg-page 灰槽 + 1px --border），圆角跟 chip 件档 r-2(8)——站内刚两轮
   试作定案「胶囊与 r-3 均被否」，别回 9999；长词省略号截断，一排塞得下几个是几个 */
.hs-hist { display: flex; flex-wrap: wrap; gap: var(--sp-2); padding: var(--sp-2) 2px 2px; }
.hs-hist-pill {
  display: inline-flex; align-items: center; height: 30px; padding: 0 var(--sp-3);
  max-width: 100%; border: 1px solid var(--border); border-radius: var(--r-2);
  background: var(--bg-page); color: var(--text-2); cursor: pointer;
  font-family: inherit; font-size: var(--fs-caption);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.hs-hist-pill:active { background: var(--bg-count); border-color: var(--border-strong); color: var(--text-1); }
/* 空态有历史：提示行由 JS 收起（hsHint），组行直接贴近布幕顶——旧页
   「提示行永远占位」是防固定高抽屉硬跳的规矩，布幕高度实时现算、不适用 */
.hs-panel .ss-grp:first-child { padding-top: var(--sp-2); }
/* 布幕行规格（1011 站主拍板：甲案减一层 + 轻描边）：灰井撤掉——白布幕直接托
   「自带浅一档」的灰槽行（与顶栏搜索槽同族 --bg-page），保留 1px 轻描边勾边界、
   去阴影；井降级成纯结构层（滚动仍归 .ss-results）。旧全屏页（.ss-sheet）维持
   原「灰井+白卡」承载语言不动——作用域只圈在 .hs-panel。 */
.hs-panel .ss-well { background: transparent; padding: 0; margin-top: 0; border-radius: 0; }
.hs-panel .ss-row { background: var(--bg-page); border: 1px solid var(--border); box-shadow: none; }
/* 按下反馈在灰槽上要走「加深一档」（--bg-hover 在 bg-page 上几乎看不出来） */
.hs-panel .ss-row:active { background: var(--bg-count); }

/* ---- 5. 检索抽屉：外壳完全交给 .wp-mask / .wp-sheet / .wp-grab / .wp-title ---- */
/* 底锚 dock 是 position:fixed，键盘压缩可视视口时它会跟着被顶上来戳进抽屉；
   抽屉开着就整条收掉——它本来也被遮罩压在后面，留着只会露半截。 */
body.ss-open .tabbar { display: none; }

/* ---- 键盘跟随公共层（.wp-mask.kbd-follow）：搜索 / 一句话 / 分类·类型管理共用 ----
   逐帧量过才看清真身：键盘弹出那一帧底锚抽屉顶边跳 140px、同帧遮罩高跳 144px，
   而 is-kbd 的 padding 只占 4px。主犯是遮罩本身——它是 inset:0 的 fixed，键盘一弹
   visualViewport 高度一步到位缩掉，整块抽屉被瞬移上去。rAF 合帧救不了它：每帧的视口
   高度本来就真的不一样；很多 ROM 的 IME 高度就是离散给一两步。
   解法：给这层遮罩补 height/top 过渡，把台阶摊成滑行。以前只挂在搜索自己的 .ss-mask 上，
   另外两只带输入框的抽屉没挂 → 各跳各的。现在收口成 .kbd-follow 一只通用类，
   JS 侧配 wireKbdFollow（app.js）三处同一条路径。刻意不给无输入框的抽屉挂这个类——
   它们的遮罩 height/top 根本不会被 JS 改写，挂了也只是白占一层合成属性。 */
/* 这两条刻意用 linear 而不是 --ease-float：它不是「主动进场」，
   而是**跟一个外部离散台阶**（键盘高度一步到位）。ease-out 起步最快，
   140px 里第一帧就吃掉 35px（25%）；匀速摊下来每帧约 8px，最不留痕。
   面板内部的井高/内距仍是 --ease-float——那是我们自己发起的变化，该有动势。 */
.wp-mask.kbd-follow {
  transition: opacity var(--d-modal) ease, padding-bottom var(--d-modal) var(--ease-enter, ease), height var(--d-base) linear, top var(--d-base) linear;
}
/* 全屏壳（.mgr-sheet.mgr-full）横向内距是 0（管理行自己带），搜索这屏的内容
   要自己补回 16px；纵向交给 flex：头部/输入框/hint 固定，结果井吃掉剩余空间。
   井改成 flex 撑满之后，键盘起来只是压掉井的高度——面板顶边钉在屏幕顶，
   整块位移从根上消失了，也就不再需要 --ss-max 那套按可视高现算的数学。
   1004b：overflow 由 hidden 放开为 visible——搜索框聚焦柔光是「外发光」，
   hidden 会把顶部那截光晕裁平（站主截图实报；同账户页分组卡的坑）；
   列内各件自带滚动纪律（.ss-well / .ss-results 各自 overflow），放开零代价。 */
.ss-sheet .mg-inner {
  display: flex; flex-direction: column; overflow: visible;
  padding: 0 var(--sp-4); margin: 0;
}
/* 标题绝对居中于面板本身，和 .wp-grab 那根小杠共用同一条中线。
   原来吃 .mgr-full .wp-title{flex:1} —— 那是「居中在左右两颗钮剩下的空间里」：
   左返回 ≈44px、右栏宽度随文案变，而且「清空历史」在有/无历史时一隐一现，
   于是标题既对不上居中的把手，也会在清除搜索时横向跳一下。
   左右内距对称（64px），保证文字盒本身关于面板中线对称；pointer-events:none
   让这行字永远不挡两侧按钮的点击。
   1104：同一笔病管理抽屉也犯（站主实拍「分类管理标题没居中于把手」，390 实测右偏 24px，
   因为「完成」被点名删了、左边还留着 44px 返回钮）。带 mf-head 的整页壳只有搜索与管理两只，
   故把选择器从 .ss-sheet 升到 .mgr-full 一处管到底，不另起一条声明体相同的重复规则。 */
.mgr-full .mf-head { position: relative; }
.mgr-full .mf-head .wp-title {
  position: absolute; left: 0; right: 0;
  padding: 0 64px; box-sizing: border-box;
  text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  pointer-events: none;
}
/* 标题文字的盒子就是「清空历史」的坐标系：inline-block 才量得出文字宽度 */
.ss-sheet .mf-head .ss-title-t { display: inline-block; position: relative; }
.ss-sheet { padding-bottom: calc(var(--sp-4) + var(--sab)); }
/* 键盘起落时安全区内距没意义（底部已被键盘占），收回来把空间让给结果 */
.ss-sheet.is-kbd { padding-bottom: var(--sp-3); }
/* flex:none 是这块的关键：.mg-inner 是 flex 列，缺省 flex:0 1 auto 的项
   「可收缩」，键盘起来 + 结果一多就整列溢出，收缩量按基准高度分摊——
   输入框被吃掉 4~5px（实测 44 → 39.5），空态没井又不吃，于是「没字时高、
   有字时矮」。固定行（头部/把手）站内一律 flex:none，这行跟着同一口径。 */
.ss-field { width: 100%; height: 44px; margin: var(--sp-1) 0 0; flex: none; }
.ss-field .search-field-input { font-size: calc(16px * var(--fs-scale)); padding-left: 38px; padding-right: var(--sp-8); }
.ss-field .search-field-icon { width: 16px; height: 16px; }
.ss-field .search-clear { width: 26px; height: 26px; right: 6px; }
.ss-field .search-clear svg { width: 11px; height: 11px; }
.ss-field .search-clear::after { content: ""; position: absolute; inset: -8px; }  /* 热区 ≈46 */
/* 「清空历史」只在有历史时由 JS 摘 hidden。位置：紧贴标题文字右侧。
   借 mf-done 的格位与按下反馈（高 40 / min-width 44 / :active 底色），但刻意不借它的颜色：
   .mgr-full .mf-done 是 (0,2,0)，只写 .ss-hist-clear 会被它盖成主色，
   看着像「确认」——清空历史是次要动作，压回 --text-4。 */
.mf-done.ss-hist-clear {
  border: none; background: transparent; cursor: pointer;
  font-size: var(--fs-caption); color: var(--text-4); font-weight: var(--fw-regular);
  /* 绝对定位挂在标题文字（.ss-title-t）的右缘：left:100% + margin-left 就是「文字后面」，
     钮自己不在行内流里 → 「搜索」始终占住面板中线，钮出现/消失都不会横向顶偏它。
     这是站内居中铁律的写法：会消失的控件不与居中对象同组，也不用影子位补宽。 */
  position: absolute; left: 100%; top: 50%; transform: translateY(-50%);
  margin: 0 0 0 var(--sp-3); padding: 0 var(--sp-2); min-width: 0; white-space: nowrap;
  /* .wp-title 整行 pointer-events:none（那行字不许挡两侧按钮），钮要自己收回来 */
  pointer-events: auto;
  -webkit-tap-highlight-color: transparent;
}
.ss-hist-clear[hidden] { display: none; }
/* 提示行永远占着那一行：以前 :empty 会把 min-height 与 margin 一起收掉，
   结果「有结果 → 清空」那一帧抽屉整体往上硬跳 20px（真机反馈的第二次闪动，
   比第一次更明显）。占位高度必须等于一行字的真实行盒（20px），
   写 17px 仍会留 3px 的小跳——逐帧采样抓出来的。 */
.ss-hint {
  margin: var(--sp-3) 2px 2px; min-height: 20px; line-height: 20px;
  font-size: var(--fs-micro); color: var(--text-4);
  font-variant-numeric: tabular-nums;
}
/* 灰画布 + 白卡：抽屉本身是 --bg-card（白），结果行再写白底等于没有卡片。
   刻意用 --bg-page 而不是小票机那枚更重的 --rm-well(#EDEFF2)——真机反馈「太灰了」；
   #F7F8FA 也正是全站「白卡浮在页面底」那层关系，语义对得上。
   底色一浅，卡片与画布的明度差就不够撑层次了，改由 1px 描边承担（同 .date-card）。
   height 过渡是给井的显隐用的：以前直接翻 hidden，抽屉当场跳一下（真机「拉长闪烁」）。
   缓动刻意用 --ease-float 而不是 --ease-enter：后者 cubic-bezier(.16,1,.3,1) 严重前突，
   260ms 的动画第一帧就冲掉 43px，肉眼读起来是「弹一下再爬」而不是「长过去」
   （逐帧采样实测）。--ease-float 是站内给尺寸/位移类过渡那枚（.date-card 同款）。 */
/* 全屏之后井是 flex 撑满剩余空间的，高度不再由内容决定 —— 以前那套
   「量旧高 → 钉住 → 长到新高」的 FLIP 整个不需要了，也就彻底没有
   「井高跨过键盘 resize 被钉住 → 撑出一大片空井」这类 bug 的生存空间。
   井只剩一个开关：有没有条目（空灰底比空白更难看）。
   但 flex:1 试过之后否掉了——只有两条结果时灰面被拉到整屏高，下面一大片空灰，
   正是「太灰」那轮抱怨的观感。改成「可收缩、不生长」：灰面只包住内容，
   剩余空间留给白面板；空间不够时它自己缩下去、滚动仍在井内。 */
.ss-well {
  box-sizing: border-box;
  background: var(--bg-page); border-radius: var(--r-3);
  padding: 2px var(--sp-2) var(--sp-2); margin-top: var(--sp-2);
  flex: 0 1 auto; min-height: 0;
  display: flex; flex-direction: column;
  overflow: hidden;
}
.ss-well[hidden] { display: none; }
/* 井里这一层才是真正滚的那位（外层 .mg-inner 是 overflow:visible 的 flex 列）。
   overscroll-behavior: contain 与 .tp-grid/.cat-list/.mg-inner 同一口径：
   滚到顶再往下拽，位移要交给抽屉的下拉关手势，不能顺手把背后那页也滚走。 */
.ss-results {
  flex: 1; min-height: 0;
  overflow-y: auto; -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
.ss-grp {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-1) 0; font-size: var(--fs-micro); color: var(--text-4);
  font-family: var(--font-mono); letter-spacing: .04em;
}
/* 「最近搜索」那一行不再挂清空历史链接（入口只有标题右侧那颗），
   旧的 .ss-grp .ss-hc 两条随本轮一起收掉，免得下轮误以为井里还有第二个入口 */
.ss-n { color: var(--text-3); }
.ss-row {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%; min-height: 46px;
  padding: var(--sp-3); margin: var(--sp-2) 0 0; box-sizing: border-box;
  border: 1px solid var(--border); border-radius: var(--r-3); background: var(--bg-card);
  box-shadow: var(--shadow-card);
  color: var(--text-1); font-family: inherit; font-size: var(--fs-body);
  text-align: left; cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast), transform var(--d-fast) var(--ease-enter);
}
.ss-row:first-child { margin-top: var(--sp-1); }
.ss-grp + .ss-row { margin-top: var(--sp-1); }
.ss-row:active { transform: scale(.985); background: var(--bg-hover); border-color: var(--border-strong); }
.ss-row svg { width: 14px; height: 14px; flex: 0 0 auto; color: var(--text-4); }
/* 主列：标题 + 命中语境。命中在描述/正文里时，光印标题看不出这条凭什么出现 */
.ss-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.ss-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ss-x {
  min-width: 0; font-size: var(--fs-micro); color: var(--text-4);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ss-s {
  flex: 0 0 auto; max-width: 38%; font-size: var(--fs-micro); color: var(--text-4);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* hint 文案换档（空态 ↔ 输入中 ↔ 命中数）别硬切：重挂一次站内 fadeSoft */
.ss-hint.ss-pulse { animation: fadeSoft var(--d-base) ease; }

/* ---- 6. 桌面聚合检索面板（Modal 皮）：标题/底栏由 Modal 收起 ---- */
.cmdk-modal { max-width: 620px; }
.cmdk-modal .modal-body { padding-top: var(--sp-1); }
.cmdk-in {
  width: 100%; height: 44px; border: none; outline: none; background: transparent;
  font: inherit; font-size: var(--fs-body); color: var(--text-1); padding: 0 2px;
}
.cmdk-in::placeholder { color: var(--text-hint); }
.cmdk-rule { height: 1px; background: var(--border); margin: 0 0 var(--sp-1); }
.cmdk-grp {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-3) 2px var(--sp-1); font-size: var(--fs-micro); color: var(--text-4);
  font-family: var(--font-mono); letter-spacing: .04em;
}
.cmdk-row {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%; min-height: 40px;
  padding: var(--sp-1) var(--sp-2); border: none; border-radius: var(--radius-btn); background: transparent;
  color: var(--text-1); font-family: inherit; font-size: var(--fs-caption);
  text-align: left; cursor: pointer;
}
.cmdk-row.is-sel { background: var(--bg-hover); }
.cmdk-row svg { width: 13px; height: 13px; color: var(--text-4); }
.cmdk-t { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cmdk-s {
  flex: 0 0 auto; max-width: 42%; font-size: var(--fs-micro); color: var(--text-4);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.cmdk-hint { padding: var(--sp-6) var(--sp-1); text-align: center; color: var(--text-4); font-size: var(--fs-micro); }
.cmdk-foot {
  padding: var(--sp-2) 2px 2px; font-size: var(--fs-micro); color: var(--text-4);
  display: flex; align-items: center; gap: var(--sp-3); font-family: var(--font-mono);
}
.cmdk-foot kbd {
  font-family: inherit; border: 1px solid var(--border); border-radius: var(--r-1);
  padding: 0 var(--sp-1); background: var(--bg-page); color: var(--text-3);
}

/* ============================================================
   邮箱绑定（个人中心 → 账户安全）
   ------------------------------------------------------------
   只补「验证码流程」独有的几块：已绑定卡、解绑、更换分隔、输入 + 发送按钮行、提示小字。
   输入框 / 分组卡 / 头部 ✓ 一律复用站内 .field / .fg-card / .form-input / .modal-head-act，
   桌面走居中弹窗（白底），手机端 wbf-modal 灰底画布 + 白卡 + 左标签右控件行。
   触控：发送胶囊视觉高 36px，热区靠 min-height + 行高补足 ≥38px。
   ============================================================ */

/* 已绑定邮箱卡 */
.eb-unbind {
  flex: none; min-height: 38px; padding: 0 var(--sp-3); border: none; background: transparent;
  color: var(--status-bad); font-size: var(--fs-caption); cursor: pointer;
  border-radius: var(--radius-btn); transition: background var(--transition-fast);
}
@media (hover: hover) { .eb-unbind:hover { background: var(--bg-hover); } }
.eb-unbind:active { opacity: .6; }

/* 更换绑定分隔线 */

/* 输入 + 获取验证码（桌面：描边输入 + 右侧胶囊按钮） */
.eb-code-row { display: flex; align-items: center; gap: var(--sp-2); }
.eb-send {
  flex: none; min-height: 38px; padding: 0 var(--sp-3); white-space: nowrap;
  border: 1px solid var(--border-strong); border-radius: var(--radius-pill);
  background: var(--bg-card); color: var(--text-1);
  font-size: var(--fs-caption); font-weight: var(--fw-medium); cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}
@media (hover: hover) { .eb-send:hover:not(:disabled) { background: var(--bg-hover); } }
.eb-send:active:not(:disabled) { transform: scale(.96); }
.eb-send:disabled { opacity: .55; cursor: default; color: var(--text-4); }

/* 提示小字 / 未开启说明 */
.eb-hint { margin: var(--sp-2) 0 0; font-size: var(--fs-micro); color: var(--text-4); line-height: 1.6; }
.eb-off { margin: 0; padding: var(--sp-1) 0 var(--sp-1); font-size: var(--fs-caption); color: var(--text-3); line-height: 1.7; }

/* 邮箱绑定行的「已绑定」胶囊态：比默认稍实，一眼看出绑过了 */
.pf-chip-on { background: var(--bg-count); color: var(--text-1); }

[data-theme="dark"] .eb-send { background: var(--bg-soft); }

/* ≤768 手机端样式 → 06-mobile.css */


/* 降低动效：行按压与底色、hint 淡入全部瞬切
   （井高过渡已随全屏 flex 布局一起删掉，这里不再列它） */
@media (prefers-reduced-motion: reduce) {
  .search-field-input, .ss-row { transition: none; }
  .ss-hint.ss-pulse { animation: none; }
  /* v3 顶栏 morph / 布幕：宽度、淡入、面板高度全瞬切 */
  .head-search, .hs-icon, .head-search .hs-in, .head-search .hs-x, .header-left, .hs-panel { transition: none; }
}

/* ============================================================
   账户页精致输入框体系（个人中心 / 登录账号 / 云端登录 共用）
   ------------------------------------------------------------
   统一「灰底画布 + 白卡分区 + 大字号描边输入框」的账户语言：
   - 输入框抬到 48 高、15px 字、圆角 12、浅灰填充；聚焦浮白 + 主色描边 + 3px 光环；
   - 校验失败仍只让 label 变红（0924 铁律），不给输入框描红框；
   - 手机端 Web 登录弹卡原用 .fg-card .fg-row 无边框右对齐，这里在 .acct-modal 下就地
     改回「标签在上、描边框在下」的堆叠式，与桌面一致（靠 .acct-modal 前缀抬特异性到 0,4,0）。
   作用域只在 .acct-modal（个人中心 / 云登录由 Modal cls 挂、Web 登录由 index.php 表单挂），
   不碰全站 .form-input / .pfg-in，其它表单零影响。
   ============================================================ */

/* 画布：把账户页正文底铺成浅灰，白卡分区才浮得起来 */
.acct-modal .modal-body { background: var(--bg-page); }

/* 分区卡 */

/* 应用按钮：小面积近黑强调（与 hero 的黑色进度条 / 主胶囊同一语言） */

/* 退出登录：底部整行弱化文字钮，hover 才转危险色 */

/* —— 输入框：核心升级 —— */
/* 1004b 定稿（承 1003 账户盒 B′，按站主「两层边框」反馈收窄）：默认无描边、底用软垫 #F3F4F6
   （与表单「井」同料）/ 聚焦黑描边 1px + 12px 柔光渐隐（--focus-glow，不翻白）。
   1px 透明占位让聚焦不跳字；小数描边会被 Chrome 截整，别写 1.5。云登录三处同源；
   手机端另在下方 ≤768 块补 14px 字段间距。 */
.acct-modal .form-input,
.acct-modal .pfg-in {
  width: 100%; height: 48px; box-sizing: border-box; padding: 0 var(--sp-3);
  font-family: var(--font-sans); font-size: calc(15px * var(--fs-scale)); color: var(--fld-ink); text-align: left;
  background: var(--bg-muted); border: 1px solid transparent; border-radius: var(--r-3);
  outline: none; transition: border-color var(--transition-fast), box-shadow var(--transition-fast), background var(--transition-fast);
}
.acct-modal .form-input::placeholder,
.acct-modal .pfg-in::placeholder { color: var(--text-hint); font-family: var(--font-sans); }
@media (hover: hover) {
.acct-modal .form-input:hover,
.acct-modal .pfg-in:hover { background: var(--bg-count); }
}
.acct-modal .form-input:focus,
.acct-modal .pfg-in:focus { background: var(--bg-muted); border-color: var(--primary); box-shadow: var(--focus-glow); }
/* 标题字形不再在这里另写一档：1104 前它是 13px/500/--text-3，且选择器特异度
   (0,3,1) 高于 06 的 `.fg-card .fg-row > label` (0,2,1)，手机端也照样被它压住——
   这就是「登录/账号抽屉的标题跟别的页面不一样」的根因。只留它自己的间距。 */
.acct-modal .field > label { margin-bottom: var(--sp-2); }

/* 密码框：给小眼睛留位并随 48 高度重定心 */
.acct-modal .pwd-field { position: relative; }
.acct-modal .pwd-field .form-input { padding-right: 46px; }
.acct-modal .pwd-toggle { right: 7px; width: 34px; height: 34px; }
.acct-modal .pwd-toggle svg { width: 17px; height: 17px; }

/* 验证码行：输入占满 + 右侧发送胶囊 */

/* 云端登录（App）：两只描边输入装进一张白卡承载（不再裸浮灰底），行间去掉分隔线。
   只作用在 .cloud-login（云登录专属类），否则会连「个人中心」里复用的 .pfg-card 白卡一起掀掉。 */
.cloud-login .pfg-card { display: flex; flex-direction: column; gap: var(--sp-3); background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-card-m); box-shadow: var(--shadow-card); padding: var(--sp-4); margin: 0; overflow: visible; }
.cloud-login .pfg-row.pfg-ctl { padding: 0; min-height: 0; }
/* 两只描边输入盒各自独立，行间的 border-top 分隔线多余 → 去掉（基础是 .pfg-row+.pfg-row{border-top}，不是 ::before） */
.cloud-login .pfg-row + .pfg-row { border-top: none; }
/* 云登录的两只输入 = .acct-modal .pfg-in 同一口径（1003 收口：原在此处的两份复制删除——
   云登录弹窗恒带 acct-modal 类（app.js 一处），主规则已覆盖，免再「改一处漏一处」）。 */

/* Web 登录弹卡：手机端 .fg-card .fg-row 的无边框右对齐 → 改回堆叠描边 */
.acct-modal .fg-card .fg-row { display: block; min-height: 0; gap: 0; }
.acct-modal .fg-card .fg-row > label { display: block; min-width: 0; flex: none; margin: 0 0 var(--sp-2); }
.acct-modal .fg-card .fg-row .form-input {
  border: 1px solid transparent; background: var(--bg-muted); box-shadow: none;
  height: 48px; padding: 0 var(--sp-3); text-align: left; font-size: calc(15px * var(--fs-scale)); border-radius: var(--r-3);
}
.acct-modal .fg-card .fg-row .form-input:focus { border-color: var(--primary); box-shadow: var(--focus-glow); background: var(--bg-muted); }
.acct-modal .fg-card .fg-row .form-input::placeholder { text-align: left; }
/* 密码行：给眼睛留位（右 46）+ 与用户名同款。历史坑：≤768 的 `.login-pop … .pwd-field .form-input`
   旧式（0,5,0）比上面（0,4,0）高，手机端密码框曾整只漏吃账户款（透明底、无框、右对齐 54）。
   这里以同特异度、更晚序补全 B 定稿全件套。 */
.acct-modal .fg-card .fg-row .pwd-field .form-input {
  border: 1px solid transparent; background: var(--bg-muted); height: 48px;
  text-align: left; font-size: calc(15px * var(--fs-scale)); padding: 0 46px 0 var(--sp-3);
}
/* 密码行聚焦补齐（1003 真机反馈：密码框聚焦还像旧样）：上面 pwd 规则的 border 简写与聚焦规则
   同为 (0,5,0) 且顺序更晚，会把 border-color 压回 transparent——这里同特异度、更晚序把聚焦补回 */
.acct-modal .fg-card .fg-row .pwd-field .form-input:focus { border-color: var(--primary); box-shadow: var(--focus-glow); }
/* 描边输入框的聚焦柔光是「外发光」，会被分组卡的 overflow:hidden 裁掉 → 光晕看着缺一块、位置不对；
   账户页的分组卡放开裁切，让渐隐柔光（1004b：12px）完整露出。 */
.acct-modal .fg-card { overflow: visible; }
/* 登录卡两行也各自成盒，去掉手机端 .fg-card 行间的 ::before 分隔线 */
.acct-modal .fg-card .field + .field::before { display: none; }

/* 深色输入底：基类那枚 --bg-muted 在暗档就是 #202228（比卡片 #191B1F 亮一档），
   已经满足「提亮一档、别和卡片糊在一起」——原先另写的一条 --bg-disabled（#1A1B1F，
   与卡片只差 1）把盒子压回卡片色，站主实拍「深色模式看不见输入框在哪」即此，删。 */
/* 暗档聚焦不翻色（B 定稿：底色全程不动，随上方基类 --bg-muted 接管） */

/* ≤768 手机端样式 → 06-mobile.css「暗档聚焦不翻色（B 定稿：底色全程不动，随上方 [dark] 底色规则接管）」 */

/* 改密页 · 邮箱验证码块：发往提示 / 未绑定引导（复用 eb-* 与描边输入语言） */
.sp-to { margin: 0 0 var(--sp-3); font-size: calc(13px * var(--fs-scale)); color: var(--text-3); }
.sp-to b { color: var(--text-1); font-weight: 600; }
/* 「未绑定邮箱」空态：只留一句话居中在卡片里——卡片本身就是那只盒，
   别再套一层 bg-soft 小盒（白卡里浮灰卡＝双盒，站主点名「排版不好看」）。 */
.sp-nobind {
  margin: 0; padding: var(--sp-1) 0; text-align: center;
  font-size: calc(14px * var(--fs-scale)); line-height: 1.6; color: var(--text-2);
}

/* ============================================================
   账户页白卡承载 + 验证码六宫格（改密 / 绑邮箱 / 云登录 共用）
   ------------------------------------------------------------
   每页把字段装进 .acct-card 白卡（灰底画布上浮起，输入框不再和背景糊成一片）；
   验证码用 .otp 六宫格（正方形小格，逐格输入 / 粘贴铺满）；应用钮 .acct-act 近黑胶囊。
   ============================================================ */
.acct-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-card-m); box-shadow: var(--shadow-card); padding: var(--sp-4); margin-bottom: var(--sp-3); overflow: visible; }
.acct-card:last-child { margin-bottom: 0; }/* (1008 死规则清理) */
.acct-card .field:last-of-type { margin-bottom: 0; }/* (1008 死规则清理) *//* (1008 死规则清理) */

/* 应用钮：近黑圆角矩形（1008 站主：圆角对齐引导页「起昵称」那颗 .btn.ob-go 的 12px，不再胶囊）；危险态转红 */
.acct-act {
  min-height: 38px; padding: 0 var(--sp-4); border: none; border-radius: var(--radius-lg);
  background: var(--text-1); color: var(--bg-card);
  font-size: calc(14px * var(--fs-scale)); font-weight: 600; cursor: pointer;
  transition: transform var(--d-micro) ease, background var(--transition-fast), opacity var(--transition-fast);
}
@media (hover: hover) { .acct-act:hover:not(:disabled) { background: var(--text-2); } }
.acct-act:active:not(:disabled) { transform: scale(.96); }
.acct-act:disabled { opacity: .5; cursor: default; }
.acct-act-danger { background: transparent; color: var(--status-bad); border: 1px solid rgba(229, 62, 62, .42); }
@media (hover: hover) { .acct-act-danger:hover:not(:disabled) { background: rgba(229, 62, 62, .08); border-color: rgba(229, 62, 62, .58); } }
.acct-act-danger:disabled { opacity: .5; }

/* 改密「设置新密码」卡：验证码通过前锁住 */
.acct-lock.is-locked .acct-lock-body { opacity: .45; pointer-events: none; filter: saturate(.6); }/* (1008 死规则清理) */
.acct-lock.is-locked .acct-lock-note { display: block; }
.acct-lock:not(.is-locked) .acct-lock-note { display: none; }

/* 当前邮箱行（绑邮箱页） */
.eb-cur { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.eb-cur-mail { font-size: calc(15px * var(--fs-scale)); font-weight: 600; color: var(--text-1); word-break: break-all; }
.eb-cur-sub { font-size: calc(12px * var(--fs-scale)); color: var(--text-4); }

/* —— 验证码六宫格 —— */
.otp { display: flex; gap: var(--sp-2); }
.otp-box {
  flex: 1 1 0; min-width: 0; max-width: 52px; height: 52px; box-sizing: border-box;
  text-align: center; font-family: var(--font-mono); font-size: calc(22px * var(--fs-scale)); font-weight: 700; color: var(--text-1);
  background: var(--bg-soft); border: 1px solid var(--border); border-radius: var(--r-3); outline: none;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast), background var(--transition-fast);
  -webkit-user-select: none; user-select: none;
}
@media (hover: hover) { .otp-box:hover { border-color: var(--border-strong); } }
.otp-box:focus { background: var(--bg-card); border-color: var(--text-4); box-shadow: 0 0 0 3px var(--focus-ring-soft); }
/* 「已填」档靠 :placeholder-shown 判空，所以 markup 必须留那颗 placeholder=" "（见 app.js otpHtml）；
   :not(:focus) 是让聚焦描边永远赢过它——否则填过的格子聚焦时看不出哪一格在打字 */
.otp-box:not(:placeholder-shown):not(:focus) { border-color: var(--text-3); }

/* 深色：输入底提亮。聚焦柔光现随 --focus-ring-soft 令牌自动切换（含此前漏网的 .cloud-login），原显式补偿块收口删除 */
[data-theme="dark"] .otp-box { background: var(--bg-disabled); }
[data-theme="dark"] .otp-box:focus { background: var(--bg-card); }

/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   分段选择器 v2 · seg-slide（待办状态筛选 · 习惯详情热力视图）
   ------------------------------------------------------------
   只换皮、不换结构：仍是 .seg + button.active，JS 那套 active 切换原样能用。
   1009 按参考图重定三档：轨道 --seg-track(#E9EAEE，比画布深一档冷灰) / 凸块纯白 /
   未选中墨 --seg-idle(#8A8A94)；圆角走分段器自己的 --seg-r(16，1010 站主点名再放大一档)，
   凸块 = --seg-r - --seg-pad(4) = 12 与轨道同心。计数不再穿灰泡，直接跟本段墨色走。
   凸块位置 = transform: translateX(--seg-i × 自身宽)，段数 = --seg-n，
   两个变量由 app.js 写进行内样式（待办走 segPaint，热力走 hmTabs），
   CSS 里给缺省 0 / 3：JS 还没跑的时候凸块停在第一格，与 HTML 里的
   class="active" 对得上，不会出现「选中在第三格、白块还在第一格」。
   段宽必须硬等分（width: 100% / n）：凸块是按段数算的，让某一格按内容
   自撑宽就会整体错位，看着像白块盖不住选中项。
   写在文件末尾：同特异性的 .seg 老规则（含 ≤768 那两条降级）都要让位。
   ============================================================ */
.seg.seg-slide {
  position: relative;
  display: inline-flex; align-items: stretch; gap: 0;
  border: none; padding: var(--seg-pad); overflow: visible;
  background: var(--seg-track); border-radius: var(--seg-r);
}
.seg.seg-slide::before {
  content: ''; position: absolute; z-index: 0;
  left: var(--seg-pad); top: var(--seg-pad); bottom: var(--seg-pad);
  width: calc((100% - 2 * var(--seg-pad)) / var(--seg-n, 3));
  border-radius: calc(var(--seg-r) - var(--seg-pad));
  background: var(--bg-card); box-shadow: var(--shadow-sm);
  transform: translateX(calc(var(--seg-i, 0) * 100%));
  transition: transform var(--d-toast) var(--ease-enter), background-color var(--transition-fast);
}
.seg.seg-slide > button {
  position: relative; z-index: 1;
  flex: 1 1 0; width: calc(100% / var(--seg-n, 3)); min-width: 0;
  display: inline-flex; align-items: center; justify-content: center;
  height: var(--control-h); padding: 0 var(--sp-3);
  border: none; background: transparent; box-shadow: none;
  border-radius: calc(var(--seg-r) - var(--seg-pad));
  font-size: var(--fs-caption); color: var(--seg-idle);
  white-space: nowrap; cursor: pointer;
  transition: color var(--transition-fast);
}
/* 老 .seg 的竖内分隔线 / 黑底选中态 / :hover :active 反馈全部交还给凸块承担 */
.seg.seg-slide > button + button { border-left: none; }
@media (hover: hover) { .seg.seg-slide > button:hover { background: transparent; color: var(--text-2); } }
.seg.seg-slide > button:active { background: transparent; }
.seg.seg-slide > button.active { background: transparent; color: var(--text-1); font-weight: var(--fw-medium); }
@media (hover: hover) { .seg.seg-slide > button.active:hover { background: transparent; color: var(--text-1); font-weight: var(--fw-medium); } }
/* 计数：1009 参考图里数字就是「跟标签同一枚墨的等宽小字」，不穿灰泡。
   凸块底下是白卡，所以也绝不沿用 .seg 那套 on-primary 反白；
   min-width / padding 一并交还 0——留着会让一位数被撑成一位半的空档。 */
.seg.seg-slide > button .seg-cnt,
.seg.seg-slide > button.active .seg-cnt {
  background: transparent; color: inherit; min-width: 0; padding: 0;
}
/* 深色轨道（#202228）比卡片（#191B1F）还亮，2px 阴影托不住凸块 → 补一圈极淡描边。
   暗档的计数不再单开一条：上面那条「灰泡 + --text-2」已删，数字统一 color: inherit，
   暗档未选中墨由 --seg-idle 的暗值(#B0B4BC)说话——令牌层改一处，不必在这里再抄一遍。 */
[data-theme="dark"] .seg.seg-slide::before { box-shadow: inset 0 0 0 1px rgba(240,241,243,.08), 0 1px 3px rgba(0,0,0,.4); }
@media (prefers-reduced-motion: reduce) { .seg.seg-slide::before { transition: none; } }
/* 习惯详情的分段器每次重绘面板都是新建节点：切视图要先「无过渡地摆到上一格」，
   下一帧再交给 transition 滑过去，否则凸块永远瞬移（.no-anim 只压动画，不改位置） */
.seg.seg-slide.no-anim::before { transition: none; }

/* 圆角档 · seg-round（1005 站主定：记一笔的收支两档要胶囊形）
   做成 seg-slide 的变体而不是页面级覆写：待办状态筛选 / 习惯热力 / 心情段
   这三处既有使用者零影响，要胶囊的自己点名。
   不直接改用 .pf-seg：那只按钮只有 28px 高（手机端热区靠 ::before 扩补），
   而收支要的是 seg-slide 那枚会滑动的凸块。
   轨道与凸块必须同一档圆角——只圆轨道会露出方方的白块。
   ★ 高度必须降档（站主一眼看出「椭圆」）：seg-slide 本体跟 --control-h（手机 44），
     两档一排时单格只有 41px 宽，凸块就成了 41×44——比高还窄，圆角端被拉成上下长，
     读起来是蛋形不是正圆。降到 --control-h-sm（手机实测 34）让凸块回到宽 > 高；
     热区照 .pf-seg-tight 那条老路子用 ::before 上下各扩 4px 补回 38px 地板——
     **靠加热区补，不靠加高**。横向给 14px：手机端 .seg-slide 那档只留 6px，
     两格并排时凸块 41×34 只比高宽一点点，端头两个半圆几乎接上，
     4× 单拍下读起来还是「圆疙瘩」而不是胶囊。 */
.seg.seg-slide.seg-round { border-radius: var(--radius-pill); }
.seg.seg-slide.seg-round::before { border-radius: var(--radius-pill); }
.seg.seg-slide.seg-round > button {
  position: relative; height: var(--control-h-sm);
  padding: 0 var(--sp-3); border-radius: var(--radius-pill);
}
.seg.seg-slide.seg-round > button::before {
  content: ''; position: absolute; left: 0; right: 0; top: -4px; bottom: -4px;
}

/* 习惯详情热力视图：整行三段均分（凸块要盖满才不像三枚独立钮），字号跟 .hm-tab 的等宽数字 */
.seg.hm-seg.seg-slide { display: flex; width: 100%; }
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
    心情分段 · mood-seg（编辑小记表单，1003 定稿）
    ------------------------------------------------------------
    与待办状态筛选同款 seg-slide v2（灰轨白凸块 + .26s 滑动），
    1003~1024 曾应用户点名整体胶囊化；**1025 第五轮站主点名改回来**：
    圆角退回 seg-slide 基础档（轨道 --seg-r=12、凸块同心 8），不再三层 pill；
    轨道减灰一档用 --bg-muted（亮 #F3F4F6；暗档 --bg-muted 与 --seg-track 同为
    #202228，天然同色，不必特判）——凸块自带 --shadow-sm（6868），浅轨上仍凸得出。
    结构/JS 全沿用 v2：四段硬等分（凸块按 --seg-n 算宽，段内不许自撑）、
    段内 = 心情彩点 + 两字标签，选中反馈全在凸块（文字只提字重，无黑底反白）。
    开窗初值由 openDiaryForm 内联 --seg-i 写死（首帧不闪滑）；
    点击走 segPaint，AI 回填（fillDiary）程序化设选中后也必须补一次。
    ============================================================ */
 .seg.seg-slide.mood-seg { display: flex; width: 100%; background: var(--bg-muted); }
 .seg.seg-slide.mood-seg > button { gap: var(--sp-1); }

/* ============================================================
   账户分步向导 · 主操作按钮移到卡片外（改密 / 绑定 / 解绑 一步一屏）
   ------------------------------------------------------------
   .acct-card 只装当前步的输入/验证码；.acct-foot 是卡片下方灰底上的操作区。
   单按钮走 .acct-act-block 满宽；有「上一步」时 .acct-foot-split 左回右进。
   ============================================================ */
.acct-foot { margin-top: var(--sp-4); display: flex; gap: var(--sp-3); }
.acct-foot .acct-act { flex: 1; }
.acct-act-block { width: 100%; min-height: 48px; font-size: calc(15px * var(--fs-scale)); }
.acct-sendrow { display: flex; justify-content: center; margin-top: var(--sp-3); }
.acct-sendlink {
  border: 0; background: transparent; color: var(--text-1);
  font: inherit; font-size: calc(14px * var(--fs-scale)); font-weight: var(--fw-semibold); cursor: pointer;
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r-2); transition: background var(--transition-fast);
}
@media (hover: hover) { .acct-sendlink:hover:not(:disabled) { background: var(--bg-hover); } }
.acct-sendlink:disabled { color: var(--text-4); font-weight: 400; cursor: default; }
.eb-cur { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.eb-cur-mail { font-size: calc(15px * var(--fs-scale)); font-weight: var(--fw-semibold); color: var(--text-1); word-break: break-all; }
.eb-cur-sub { font-size: var(--fs-12); color: var(--text-4); }

/* 云登录页顶部品牌区（与登录重绘一致：logo + 标题 + 一句说明） */
.cl-hero { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); margin: var(--sp-1) 0 2px; }
.cl-mark { display: inline-flex; color: var(--text-1); }
.cl-mark svg { width: 40px; height: 40px; display: block; }
.cl-wm { font-size: calc(20px * var(--fs-scale)); font-weight: var(--fw-bold); letter-spacing: .02em; color: var(--text-1); }
.cl-title { text-align: center; font-size: calc(19px * var(--fs-scale)); font-weight: var(--fw-bold); color: var(--text-1); margin-top: var(--sp-3); }
.cl-alt { text-align: center; font-size: calc(12.5px * var(--fs-scale)); color: var(--text-4); margin-top: var(--sp-3); line-height: 1.6; }
.cl-alt a { color: var(--text-1); font-weight: var(--fw-semibold); cursor: pointer; text-decoration: none; border-bottom: 1.5px solid var(--border-strong); }
.cloud-login .acct-act-block { margin-top: var(--sp-4); }

/* 账户向导 · 居中大标题 + 说明（效果图版式：标题在卡外、居中，卡只装内容） */
.acct-hero { text-align: center; margin: var(--sp-1) var(--sp-1) var(--sp-4); }
.acct-hero h2 { margin: 0; font-size: calc(21px * var(--fs-scale)); font-weight: var(--fw-bold); color: var(--text-1); letter-spacing: .01em; }
.acct-hero p { margin: var(--sp-2) auto 0; font-size: calc(13.5px * var(--fs-scale)); line-height: 1.6; color: var(--text-4); max-width: 280px; }
.acct-hero p b { color: var(--text-2); font-weight: var(--fw-semibold); }



/* ============================================================
   1008 账户七页版式定稿：大标题贴顶基准线 + 主按钮贴底基准线
   ------------------------------------------------------------
   取代 1005 的「整组居中偏上」——那套让每页标题随内容高度浮动、
   七页各站各的位置。现在两条线钉死：大标题一律落在距弹窗内容顶
   --auth-title-top（登录页 logo 占在这条线以上的预留位，向导页顶部
   留等高空间，于是标题严格同线）；主按钮一律落在距弹窗底
   --auth-btn-bottom；中间用弹性空隙拉开——红框上移、黄框下移。
   空间不够（键盘弹出）时弹性空隙归零、自动退回顶对齐，不跳不裁。
   只挂 .acct-wizard（改密 / 绑定 / 解绑）/ .cloud-login（登录）；2.13 起「个人中心」的
   退出那颗也上这条线（.pf-pinfoot 复用同一个 --auth-btn-bottom，见上方退出钮那一段）。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* 1.60 补 1.59 的欠账：登录页 logo 瓦片（引导页 .ob-morph 同款语言：深色底 + 白 K + 25% 圆角）。
   底色走 --text-1、字走 --bg-card——暗档自动翻成浅底深字，不用另写一套。 */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   1006 一句话全屏抽屉（站主点名，替代 0927 矮抽屉）
   ------------------------------------------------------------
   壳走「管理分类/标签」那只：.mgr-full——贴顶无圆角、安全区内距、
   grab + mf-head（左返回钮+标题）常驻，井/提示固定，结果列表自己滚。
   列表上翻过阈值 → 井收成一行钉在标题下（点井即长回，编辑优先）。
   承载链（mountSheet / wireSheetGrab / WbBack / wireKbdFollow / onClosed 清场）
   一条不动；桌面 Modal 不动。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */
/* 1006c 升级表单「抬层」：抽屉全程可见（不隐身——隐身那帧会把主页和 dock 漏出来闪），
   表单层临时抬到抽屉上面；表单关掉摘类回座。 */
#modalMask.is-above-nl { z-index: 9500; }
/* 2026-10-19 站主真机：从可序页快捷钮进新增表单后，表单内的滚轮/分类等 .wp-mask 抽屉
   （z9000）被抬到 9500 的表单压住不显示。抬层期间同场抽屉一并抬到 9600；
   双保险：兄弟选择器依赖 DOM 顺序（动态抽屉都 append 在 #modalMask 之后），:has 不依赖。 */
#modalMask.is-above-nl ~ .wp-mask { z-index: 9600; }
body:has(#modalMask.is-above-nl) .wp-mask { z-index: 9600; }

/* ============================================================
   1005 账本（记账）· 流水页 + 记一笔
   ------------------------------------------------------------
   三条自律，写在这儿免得下次被问：
   1 尺寸全走令牌——间距只用 --sp-* / --card-pad / --module-gap，
     字号只用 --fs-* 族与 calc(Npx * var(--fs-scale))，无页面级覆写；
     巨数直接吃站内现成的 --fs-num-lg（40px 档），不另立一档。
   2 金额整段显式 font-mono + tabular-nums：KlogNum 的 unicode-range 只认领
     0-9 : %，- + , . 会漏回 sans，一列金额就会出现「数字齐、符号歪」。
   3 收支不用红绿（站内禁大面积彩色与反白卡）：支出 -38.00、收入 +1280.00，
     只把收入重一档字重；颜色只出现在分类色点与日历墨阶上。
   粒度切换与收支两档复用现成的 .seg（它自带高度与内距），这里零新增。
   ============================================================ */

/* ---- hero：本期支出 ---- */
.lg-hero { background: var(--bg-card); border-radius: var(--radius-card-m); box-shadow: var(--shadow-card); padding: var(--card-pad); }
.lg-hero-k { font-size: var(--fs-label); color: var(--text-4); letter-spacing: .5px; }
.lg-hero-n { margin-top: var(--sp-2); font-family: var(--font-mono); font-size: var(--fs-num-lg); font-weight: var(--fw-bold);
  line-height: 1.05; letter-spacing: -1px; font-variant-numeric: tabular-nums; }
.lg-hero-n i { font-style: normal; font-family: var(--font-sans); font-size: var(--fs-label); font-weight: var(--fw-medium);
  color: var(--text-4); margin-left: var(--sp-1); letter-spacing: 0; }
.lg-hero-c { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1) var(--sp-4); margin-top: var(--sp-3);
  padding-top: var(--sp-3); border-top: 1px solid var(--border); font-size: var(--fs-caption); color: var(--text-4); }
.lg-hero-c span { display: flex; align-items: baseline; gap: var(--sp-1); }
.lg-hero-c b { font-family: var(--font-mono); font-weight: var(--fw-semibold); color: var(--text-1); font-variant-numeric: tabular-nums; }

/* ---- 分组标题（左标题 / 右口径小字） ---- */
.lg-grp { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2);
  margin: var(--module-gap) 2px var(--sp-2); font-size: var(--fs-label); font-weight: var(--fw-semibold);
  color: var(--text-4); letter-spacing: .4px; }
.lg-grp span { font-weight: var(--fw-regular); letter-spacing: 0; }

.lg-card { background: var(--bg-card); border-radius: var(--radius-card-m); box-shadow: var(--shadow-card);
  padding: var(--sp-3) var(--card-pad); }
/* 1107 轮 17：白卡上下那圈「空气」是两层内距叠出来的——卡自己 16（手机 sp-4）、
   首/末行又各加 12（sp-3），合起来 28，比一行正文还高，一眼就是「上下间距太大」。
   首/末行贴卡边的那一侧内距归零，让卡自己的内距成为唯一的上下留白；行与行之间
   仍保留各自内距做分隔。行高与触达线一律不动（可点行还是那么高），只收卡边空气。
   订阅总览/统计的 .sb-tl、.lg-rk 与账本分类的 .lg-rk 都直系住在 .lg-card 里，一条 rule 两处同收。 */
.lg-card > .sb-tl:first-child, .lg-card > .lg-rk:first-child { padding-top: 0; }
.lg-card > .sb-tl:last-child, .lg-card > .lg-rk:last-child { padding-bottom: 0; }

/* ---- 分类排行：横条 + 色点（不引图表库、不做饼图） ----
   1014：整行改 button（点分类单独看消费）——重置 UA 字体/底色/对齐，
   按下反馈按行卡铁律只沉底色、不 scale。 */
.lg-rk { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-3) 0; border-bottom: 1px solid var(--hm-line);
  width: 100%; border-left: none; border-right: none; border-top: none; background: transparent; color: inherit;
  font: inherit; text-align: left; cursor: pointer; transition: background var(--transition-fast); }
.lg-rk:active { background: var(--bg-hover); }
.lg-rk:last-child { border-bottom: none; }
.lg-rk-n { width: calc(48px * var(--fs-scale)); flex: none; font-size: calc(14px * var(--fs-scale)); color: var(--text-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lg-rk-bar { flex: 1; min-width: 0; height: 5px; border-radius: var(--radius-pill); background: var(--bg-muted); overflow: hidden; }
.lg-rk-bar > i { display: block; height: 100%; border-radius: var(--radius-pill); background: var(--primary);
  transition: width var(--d-morph) var(--ease-enter); }
.lg-rk-a { flex: none; font-family: var(--font-mono); font-size: calc(14px * var(--fs-scale)); font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums; white-space: nowrap; letter-spacing: -.2px; }
.lg-rk-p { flex: none; width: calc(34px * var(--fs-scale)); text-align: right; font-family: var(--font-mono);
  font-size: var(--fs-10); color: var(--text-4); font-variant-numeric: tabular-nums; }

/* ---- 支出日历（通栏自列：.hm-grid7 带 336px 居中约束，借了一定错一格） ----
   1014 加年档：.lg-mo 是同一族格子的「月」形态（12 格 4×3），与 .lg-day 共写一条——
   点有数字的月跳到那一月，档位按当月总支出分。 */
.lg-cal { padding: var(--sp-3) var(--sp-4) var(--sp-4); }
.lg-cal-w { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--sp-2); margin-bottom: var(--sp-2); }
.lg-cal-w b { font-weight: var(--fw-regular); text-align: center; font-size: var(--fs-10); line-height: 1; color: var(--text-4); }
.lg-cal-g { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--sp-2); }
.lg-cal-my { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-2); }
.lg-day, .lg-mo { aspect-ratio: 1 / 1; border: none; border-radius: var(--radius-badge); background: transparent;
  color: var(--text-disabled); font-family: var(--font-mono); font-size: var(--fs-12); display: grid; place-items: center;
  cursor: default; font-variant-numeric: tabular-nums;
  transition: transform var(--d-micro) var(--ease-float), box-shadow var(--transition-fast); }
.lg-mo i { font-style: normal; font-family: var(--font-sans); font-size: var(--fs-10); margin-left: 1px; }
/* l1/l2/l3 三档墨与统计热力同深浅，声明并到统计段那条 .st-l* 里（一族只写一遍） */
.lg-day.has, .lg-mo.has { cursor: pointer; }
.lg-day.today, .lg-mo.today { box-shadow: 0 0 0 1.5px var(--text-1); }
.lg-day.sel { box-shadow: 0 0 0 1.5px var(--primary), 0 0 0 4px color-mix(in srgb, var(--primary) 18%, transparent); }
/* 周视图的选区是一条软带，不是七圈环：环是「单格」的语言，
   七个环挤在同一行互相打架（站主真机点名「不太好看」）。
   空格垫灰底、数字从禁用灰抬到可读；有账的格子保持墨色不叠加
   （无数据才有底，inband 与 l1..l3 天然互斥）。 */
.lg-day.inband:not(.has) { background: var(--bg-muted); color: var(--text-3); }
.lg-day:active.has, .lg-mo:active.has { transform: scale(.9); }
.lg-cal-lg { display: flex; align-items: center; justify-content: flex-end; gap: var(--sp-1); margin-top: var(--sp-3);
  font-size: var(--fs-10); color: var(--text-4); }
.lg-cal-lg i { width: 11px; height: 11px; border-radius: var(--r-1); display: block; box-shadow: inset 0 0 0 1px var(--border-strong); }
.lg-cal-lg i.l1 { background: var(--lgd-1); box-shadow: none; }
.lg-cal-lg i.l2 { background: var(--lgd-2); box-shadow: none; }
.lg-cal-lg i.l3 { background: var(--lgd-3); box-shadow: none; }

/* ---- 流水（按日分组；行卡按下只沉底色、不 scale） ---- */
.lg-day-hd { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-1) var(--sp-2); font-size: calc(13px * var(--fs-scale)); }
.lg-day-hd > span:first-child { font-weight: var(--fw-semibold); color: var(--text-3); }
.lg-day-hd > span:last-child { font-family: var(--font-mono); color: var(--text-4); font-variant-numeric: tabular-nums; }
.lg-row { display: flex; align-items: center; gap: var(--sp-3); width: 100%; text-align: left; font: inherit; color: inherit;
  background: var(--bg-card); border: none; border-radius: var(--radius-card-m); box-shadow: var(--shadow-card);
  padding: var(--sp-3) var(--card-pad); margin-bottom: var(--sp-2); cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: background var(--transition-fast); }
.lg-row:active { background: var(--bg-hover); }
.lg-row-t { flex: 1; min-width: 0; font-size: calc(15px * var(--fs-scale)); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lg-row-t em { font-style: normal; color: var(--text-4); font-size: calc(13px * var(--fs-scale)); margin-left: var(--sp-1); }
.lg-row-a { flex: none; font-family: var(--font-mono); font-size: calc(15px * var(--fs-scale));
  font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; white-space: nowrap; letter-spacing: -.2px; }
.lg-row.is-in .lg-row-a { font-weight: var(--fw-bold); }
.lg-row.is-ro { cursor: default; }
.lg-row.is-ro:active { background: var(--bg-card); }

/* ---- 分类消费详情（1014：点分类行单独看，手机抽屉 / 桌面弹窗共用内容） ---- */
.lg-cat-sheet .lg-cd-body, .dd-modal .lg-cd-body { padding: 2px var(--card-pad) var(--sp-4); }
.lg-cd-seg { display: flex; width: 100%; margin-bottom: var(--sp-3); }
.lg-cd-nav { display: flex; align-items: center; gap: var(--sp-1); margin-bottom: var(--sp-3); }
.lg-cd-range { flex: 1; min-width: 0; display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  font-size: calc(15px * var(--fs-scale)); font-weight: var(--fw-medium); color: var(--text-1); }
.lg-cd-sum { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2);
  padding: var(--sp-3) 2px; margin-bottom: var(--sp-2); border-top: 1px solid var(--hm-line); border-bottom: 1px solid var(--hm-line);
  font-size: var(--fs-caption); color: var(--text-3); }
.lg-cd-sum b { font-family: var(--font-mono); font-weight: var(--fw-bold); color: var(--text-1); font-variant-numeric: tabular-nums; letter-spacing: -.3px; }
.lg-cd-sum span { color: var(--text-4); font-variant-numeric: tabular-nums; }
.lg-cd-dot { width: 10px; height: 10px; border-radius: var(--r-circle); flex: none; display: inline-block; margin-right: var(--sp-2); vertical-align: middle; }

/* 暗档下给所有色点补一圈描边：CAT_COLORS 第一枚是 #111111，落在 --bg-card #191B1F 上
   「日常 / 工资」两类会整个看不见（样板页暗色档实测）。 */
/* 暗色下分类色整体提亮（含 #111111 的「日常/工资」两类），统一走 .lg-ic 的 color-mix——
   原先给色点加描边的那条随图标化退役（色点已不再渲染）。 */

/* ---- 记一笔：金额「账盒」（软垫无描边、聚焦才动 1px + 柔光，与输入框规范 v2 同一族） ----
   ¥ 与数字用 center 对齐、两边同吃 line-height:1，刻意不用 baseline：
   <input> 参与基线对齐时取的是**盒子底缘**而不是文字基线，
   符号会永远比数字高半截（390 真页面实测：符号底 157 / 输入框底 161）。
   行内宽度靠 .fg-stack 让整只井独占一行，这里再兜一道 min-width:0，
   免得 input 的固有宽度把井顶出卡片右缘。 */
.lg-well { display: flex; align-items: center; gap: var(--sp-2); min-width: 0;
  background: var(--fld-fill); border: 1px solid transparent; border-radius: var(--fld-r);
  padding: var(--sp-3) var(--sp-4);
  transition: background var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast); }
.lg-well.is-focus { background: var(--bg-card); border-color: var(--text-1); box-shadow: var(--focus-glow); }
.lg-well-cur { flex: none; line-height: 1; font-size: calc(20px * var(--fs-scale)); font-weight: var(--fw-semibold); color: var(--text-4); }
.lg-well-in { flex: 1; min-width: 0; width: 100%; line-height: 1; border: none; background: transparent; outline: none; padding: 0;
  font-family: var(--font-mono); font-size: calc(32px * var(--fs-scale)); font-weight: var(--fw-bold);
  color: var(--text-1); letter-spacing: -.8px; font-variant-numeric: tabular-nums; }
/* 大账盒是占位色统一的唯一特例（1011 站主点名保留 hero 档） */
.lg-well-in::placeholder { color: var(--text-disabled); font-weight: var(--fw-semibold); }
/* 收支那一只贴右缘：手机端表单行的语言是「标签在左、控件在右」（日期行就是靠右的），
   跟在标签屁股后面会留出一截没人认领的空档 */
.lg-dir { margin-left: auto; }
/* 粒度四段通栏：手机端 .st-tools 本来就是 width:100%，但 .seg 自身是 inline-flex，
   不撑开就几颗挤在左边、右边空一截（站主真机截图）。皮肤与待办状态筛选同族 seg-slide。 */
.lg-seg { display: flex; width: 100%; }
/* 1015 站主实拍：记一笔的分类格一排只塞得下 4 个，右边空出整整一格却硬换行。
   根因是「写死 56px 格宽 + flex 换行」——余量永远留在行尾没人认领。
   改成 auto-fill 网格：列数按容器实际宽度算，余量摊进 1fr，右缘不留空档。
   48px 是「最小列宽」不是列宽，304px 容器实排 5 列 × 54px，与旧 56 同档；
   大字体档（--fs-scale 1.12 → 最小 53.8）仍守得住 5 列，窄屏 360 才回落 4 列并自动加宽。 */
.lg-cats { display: grid; grid-template-columns: repeat(auto-fill, minmax(calc(48px * var(--fs-scale)), 1fr)); gap: var(--sp-2); }
.lg-cat-btn { display: flex; flex-direction: column; align-items: center; gap: var(--sp-1); width: auto;
  border: none; background: transparent; padding: 2px 0; cursor: pointer; font: inherit; }
/* 分类图标（1006 定稿「形状 × 颜色」）：单色线性形，描边吃分类色（--c）。
   选中 = 垫 10% 同色底 + 1.5px 同色环——线条没法像色点那样加一圈外环，
   选中感靠底色垫出来；暗色整体提亮（color-mix），黑的两类（日常/工资）才读得出。 */
/* 分类图标：单色线性形，描边吃分类色（--c 由 JS 写在行内）。
   ★ 明暗两档只改一处 `color`，选中底与选中环一律用 currentColor 跟着它走——
     描边就是唯一真源，暗档提亮了什么、环和底就是什么，不存在「两套」。
     （先前那版把生效色再套一层自定义属性 --cc，实测浅档里 var 嵌套没解析出
     行内的 --c，颜色退回继承的 --text-1，整条选中规则跟着失效——环和底双双消失。） */
.lg-ic { display: inline-flex; align-items: center; justify-content: center; flex: none;
  color: var(--c, var(--text-1)); }
.lg-ic svg { display: block; stroke: currentColor; fill: none; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round; overflow: visible; }
html[data-theme="dark"] .lg-ic { color: color-mix(in srgb, var(--c, var(--text-1)) 62%, var(--text-1)); } /* 混色向暗档主墨提亮（原裸 #f2f3f5 与 --text-1 暗值 Δ2，等价归单源） */
.lg-cat-btn .lg-ic { border-radius: var(--radius-pill);
  transition: transform var(--d-fast) var(--ease-spring), background var(--transition-fast), box-shadow var(--transition-fast); }
.lg-cat-btn.is-sel .lg-ic { transform: scale(1.12);
  background: color-mix(in srgb, currentColor 12%, transparent);
  box-shadow: 0 0 0 1.5px currentColor; }
/* 名字行：必须排掉 .lg-ic——图标本身也是 span，之前这条把图标的描边色一起刷掉了，
   浅档下图标退回继承色、选中环跟着看不见（暗档靠更高特异度才侥幸盖住） */
.lg-cat-btn > span:not(.lg-ic) { font-size: var(--fs-12); color: var(--text-3); }
.lg-cat-btn.is-sel > span:not(.lg-ic) { color: var(--text-1); font-weight: var(--fw-semibold); }

/* ---- 分类格末尾的「＋」与就地新增面板 ---- */
.lg-cat-add .lg-add-ico { display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: var(--radius-pill); background: var(--bg-muted); color: var(--text-3); }
.lg-cat-add .lg-add-ico svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; }
@media (hover: hover) { .lg-cat-add:hover .lg-add-ico { background: var(--bg-count); color: var(--text-1); } }
.lg-cat-new { margin-top: var(--sp-3); padding: var(--sp-3) var(--sp-3) var(--sp-2);
  background: var(--bg-inset); border: 1px solid var(--border); border-radius: var(--fld-r); }
.lg-cat-new[hidden] { display: none; }        /* 折叠点名：不写这条 hidden 会被 flex 盖掉 */
.lg-cat-new > input[type=text] { width: 100%; border: 1px solid transparent; border-radius: var(--fld-r);
  background: var(--bg-card); padding: var(--sp-2) var(--sp-3); font: inherit; font-size: var(--fs-input, 16px); color: var(--text-1); outline: none;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast); }
.lg-cat-new > input[type=text]:focus { border-color: var(--text-1); box-shadow: var(--focus-glow); }
.lg-new-lab { margin: var(--sp-3) 2px var(--sp-2); font-size: var(--fs-10); color: var(--text-4); letter-spacing: .4px; }
/* 图形格与分类格同一把尺子（1015）：写死 34 排 6 个、行尾空一格，
   auto-fill 后同一宽度排得下 7 个，15 枚字形从 6+6+3 变 7+7+1。 */
.lg-shapes { display: grid; grid-template-columns: repeat(auto-fill, minmax(33px, 1fr)); gap: var(--sp-1); }
.lg-shp { width: auto; height: 34px; position: relative; display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid transparent; border-radius: var(--radius-card); background: transparent; cursor: pointer; padding: 0;
  transition: background var(--transition-fast), border-color var(--transition-fast); }
/* 格宽压到 33 后热区不足 38：外扩 3px 补回 39，格间 6px 各让 3px，互不抢点 */
.lg-shp::before { content: ""; position: absolute; inset: -3px; }
.lg-shp.is-sel { background: var(--bg-card); border-color: var(--text-1); }
.lg-colors { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.lg-col { width: 22px; height: 22px; border-radius: var(--r-circle); border: none; cursor: pointer; padding: 0;
  transition: transform var(--d-fast) var(--ease-spring), box-shadow var(--d-fast); }
.lg-col.is-sel { transform: scale(1.14); box-shadow: 0 0 0 2px var(--bg-inset), 0 0 0 3.5px var(--text-1); }
.lg-new-foot { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-3); }
.lg-new-hint { margin-left: auto; font-size: var(--fs-10); color: var(--text-4); }

/* 支付方式：文字胶囊一排（点一下即选、再点取消）。
   选中用黑底反白——与 .seg button.active 同一档语言，不新造一套。 */
.lg-pays { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.lg-pay { height: 30px; padding: 0 var(--sp-3); border-radius: var(--radius-pill);
  border: 1px solid var(--border); background: var(--bg-card); color: var(--text-3);
  font-size: var(--fs-12); cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast); }
.lg-pay.is-sel { background: var(--primary); border-color: var(--primary); color: var(--on-primary);
  font-weight: var(--fw-semibold); }

/* ---- 分类组标题的「管理」入口 + 管理面里的行 ---- */
.lg-grp .lg-mgr { border: none; background: transparent; padding: 0 0 0 var(--sp-1); font: inherit;
  font-size: var(--fs-10); color: var(--text-4); cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px; }
@media (hover: hover) { .lg-grp .lg-mgr:hover { color: var(--text-1); } }
.lg-rk-empty { padding: var(--sp-3) 0; font-size: calc(13px * var(--fs-scale)); color: var(--text-4); }
.lg-ic-btn { border: none; background: transparent; padding: 0; margin-right: 2px; cursor: pointer; display: inline-flex; }
.lc-add-btn { display: inline-flex; align-items: center; gap: var(--sp-1); margin: var(--sp-3) 0 var(--sp-1); }
.lc-add-btn svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; }
.lc-off-tag { font-style: normal; margin-left: var(--sp-1); font-size: var(--fs-10); color: var(--text-4); }
.mg-row .lg-ic svg { width: 20px; height: 20px; }
html[data-theme="dark"] .lg-shp .lg-ic, html[data-theme="dark"] .lg-col { box-shadow: none; }

/* ============================================================
   分类编辑悬浮卡（1015 站主定稿 · 方案 A）
   ------------------------------------------------------------
   外壳整块借一句话核对卡那只（.wp-mask.nl-peek-mask + .nl-peek + .np-head/.np-x/
   .np-body/.np-title/.np-from/.np-group/.np-foot），这里只补它没有的：大预览、
   灰井里的小标签行、收支/停用两行的行语言。井里的控件全是站内现成的——
   .lg-shapes 图形格、.cat-palette 色板、.seg.seg-slide.seg-round 分段（记一笔那对同款）、
   .pf-switch 开关、.pfg-t-sub 行内小字、.mg-act/.mg-act-del 删除钮（含它的 :active 底色）。
   写在 .np-group 之后：同特异度靠加载序压过核对卡那几行。
   ============================================================ */
.lc-mob-row.is-off .dd-k, .lc-mob-row.is-off .lg-ic { opacity: .4; }
/* 表头那道缝只归 tb-head::after 画（已通栏）：首行的 tp-mgr border-top 让位，
   否则又是一道缝两根线 */
#lcRows .lc-mob-row:first-child { border-top: 0; }
.lc-peek-big { flex: none; width: 44px; height: 44px; border-radius: var(--radius-card-m);
  display: inline-flex; align-items: center; justify-content: center; } /* 1015 站主点名：图标不要垫底色 */
.lc-peek-name { flex: 1; min-width: 0; }
.lc-peek-meta b { font-family: var(--font-mono); font-weight: var(--fw-medium); color: var(--text-3); }
.lc-peek-lab { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-3) 0 var(--sp-2);
  font-size: var(--fs-label); color: var(--text-1); letter-spacing: .3px; } /* 1015 站主点名：与主标题同一墨色 */
.lc-peek-lab .now { margin-left: auto; font-style: normal; color: var(--text-3); }
/* 色板铺满整行：8 档等分，格宽跟着卡宽走，行尾不空一截（同 .lg-cats 那把尺子） */
.lc-peek-colors { display: grid; grid-template-columns: repeat(8, 1fr); gap: var(--sp-2); }
.lc-peek-colors .cat-swatch { width: 100%; height: 26px; }
.lc-peek-line { display: flex; align-items: center; gap: var(--sp-3); min-height: 44px; padding: var(--sp-2) 0; }
/* 1015 站主点名撤掉行顶那根发丝线：灰井 + 小标签已经把段落讲清了，线是多余的一根 */
.lc-peek-line .pfg-t-sub { display: block; margin-top: 2px; }
.lc-peek-line > .seg { flex: none; }
.lc-peek-note { padding: var(--sp-1) var(--sp-4) var(--sp-4); font-size: var(--fs-label); color: var(--text-4); line-height: 1.5; }
/* 删除钮的底色、:active、红字都来自 .mg-act/.mg-act-del，这里只把它从 38 方钮拉成通栏文字行。
   上下留白照 .np-foot 收紧一档（1015 站主点名「太宽」）：只压这张卡的 foot，不碰核对卡。 */
.lc-peek-del { width: 100%; height: 40px; margin-right: 0; border-radius: var(--radius-lg);
  font-family: inherit; font-size: calc(14px * var(--fs-scale)); }
.lc-peek .np-foot { padding-top: 2px; padding-bottom: var(--sp-3); }

/* ---- 手机端（≤768）：卡面内距收一档，日历字号抬到移动地板 ---- */
/* ≤768 手机端样式 → 06-mobile.css「---- 手机端（≤768）：卡面内距收一档，日历字号抬到移动地板 ----」 */

/* ============================================================
   AI 用量（1007 第二次重做，2026-10-30 语料采集下线后只余用量）
   ------------------------------------------------------------
   1007 首版把壳从 openMgrSheet 换成 dd-modal 之后，框对上了，但站主实拍仍说
   「排版乱、看着费劲」。这一版动的是读法，不是配色：
     ① 用量卡上半改成两枚并排的圆环——「我的今日额度还剩多少」「全站今天一共多少」
        是这页的两个主问题，原来只答了第一个，还得肉眼比 43 和 120 两个数。
        环只两色（轨道 --border、进度 --text-1），用满交给「闭合的环 + 黑胶囊」说，
        不引红：站内连校验失败都不描红，一个正常状态更不该。
   语料候补池那一半（判据胶囊组、@谁·三方链 meta、采纳/不采处置钮、导出行、
   按人清空的下拉）随采集功能整条删除，它们专属的那批选择器一并撤走。
   仍然只补现成组件给不了的：圆环。行 / 卡 / 值一律 .pfg 家族。
   ============================================================ */

/* 值里的中文走 sans：.pfg-val 是等宽档，CJK 落回退字体会吃到等宽空格，
   「175  句 ·  失败  8  次」那种忽宽忽窄的缝就是这么来的（aiSetConn 同一条老教训） */
.pfg-val i { font-family: var(--font-sans); font-style: normal; }
/* 两行档里的第二行：整幅右靠，与标题不再抢宽度 */
.aiu-v-line { width: 100%; min-width: 0; white-space: normal; }
/* 「已用满」是本页唯一需要一眼看出的状态，转黑底 */
.aiu-full { margin-left: var(--sp-2); padding: 1px var(--sp-2); border-radius: var(--radius-pill);
  vertical-align: 2px; background: var(--text-1); color: var(--bg-card);
  font-family: var(--font-sans); font-size: var(--fs-label); }

/* ---- 双环 ----
   两环等宽并排、中间一道发丝线：两个数是一回事的两副账（自己的 / 全站的），
   不等宽就会读成「一大一小两件事」。环尺寸固定 88px，不随字号档放大——
   环是图形，跟着 --fs-scale 长会顶破这一行的等高关系；环心的数字才吃字号。 */
.aiu-rings { display: flex; border-bottom: 1px solid var(--border); }
.aiu-ring { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column;
  align-items: center; padding: var(--sp-4) var(--sp-2) var(--sp-3); }
.aiu-ring + .aiu-ring { border-left: 1px solid var(--border); }
.aiu-ring-wrap { position: relative; width: 88px; height: 88px; }
.aiu-ring-svg { display: block; width: 100%; height: 100%; }
.aiu-ring-bg,
.aiu-ring-fg { fill: none; stroke-width: 7; }
.aiu-ring-bg { stroke: var(--border); }
/* 进度弧从 12 点起（viewBox 中心旋转 -90°），端点收圆：
   硬端点在比例很小时会读成「一条断头线段」而不是「刚开始」 */
.aiu-ring-fg { stroke: var(--text-1); stroke-linecap: round; transform: rotate(-90deg);
  transform-origin: 48px 48px; }
.aiu-ring-c { position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 1px; pointer-events: none; }
.aiu-ring-n { font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: calc(25px * var(--fs-scale)); line-height: 1.1; color: var(--text-1); }
.aiu-ring-d { font-size: var(--fs-label); color: var(--text-4); }
.aiu-ring-t { margin-top: var(--sp-3); font-size: var(--fs-caption); color: var(--text-2);
  text-align: center; }

/* ============================================================
   分类显示与直改（1011）：详情点开即改 / 列表胶囊可点 / 管理页直拖
   ------------------------------------------------------------
   全部是「既有语言的接线件」，不另起第二套外观：
   · .td-cat-tap / .dd-mood-tap = 详情里的可点徽章（热区用负 margin 内扩，不外扩几何）
   · .tag-add                   = 备忘标签「＋」胶囊（.tag 同尺码）
   · .te-newrow                 = 编辑标签抽屉/弹窗的新标签输入行
   · .mg-grip + 拖动态           = 管理行拖动把手（与子任务/习惯同一只六点形）
   ============================================================ */

/* 待办详情 meta 里的分类胶囊：点开即改。4px 负 margin 换约 26px 高的热区，
   不撑行高、不推邻近分隔线（dd-meta 行本身只有一行小字高） */
.td-cat-tap {
  cursor: pointer; padding: var(--sp-1) var(--sp-2); margin: -4px -7px;
  border-radius: var(--radius-pill); -webkit-tap-highlight-color: transparent;
}
.td-cat-tap:active { background: var(--bg-hover); }
.td-cat-tap.is-empty { color: var(--text-4); }
@media (hover: hover) { .td-cat-tap:hover { color: var(--text-1); } }

/* 事件详情「类型 · X」胶囊：右缘补一枚小箭头，与 dd-act 行同一读法 */
.dd-mood-tap { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.dd-mood-chev { display: inline-flex; width: 12px; margin: 0 -3px 0 -1px; color: var(--text-4); }
.dd-mood-chev svg { width: 12px; height: 12px; }
.dd-mood-tap:active { transform: scale(.97); }
@media (hover: hover) { .dd-mood-tap:hover { border-color: var(--border-strong); } }

/* 备忘「＋」标签钮：与 .tag 同尺码；有标签时只一颗「＋」，空态给「＋ 标签」 */
.tag-add {
  border: 1px dashed var(--border); background: transparent; color: var(--text-4);
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.tag-add:active { color: var(--text-2); border-color: var(--border-strong); }
.tag-add.is-empty { padding: 0 var(--sp-2); }

/* 备忘表单（手机）标签行：readOnly 只挡键盘，视觉保持普通行 */
.fg-card .fg-row .form-input[readonly] { color: var(--fld-ink); }

/* 新标签输入行：软垫字段家族档（--fld-fill 无描边、聚焦才起 1px + 柔光），
   与子任务添加行同一档；「+」做成同款软垫方形图标钮，不再是描边盒子 */
.te-newrow { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4) var(--sp-1); }
.te-newrow .form-input { flex: 1; min-width: 0; height: 46px; padding: 0 var(--sp-3);
  background: var(--fld-fill); border: 1px solid transparent; border-radius: var(--fld-r);
  color: var(--fld-ink); font-size: calc(15px * var(--fs-scale)); }
.te-newrow .form-input:focus { background: var(--fld-fill); border-color: var(--primary); box-shadow: var(--focus-glow); }
.te-newrow .btn { flex: none; width: 46px; height: 46px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--fld-fill); border: 1px solid transparent; border-radius: var(--fld-r); color: var(--text-1);
  transition: background var(--transition-fast); }
.te-newrow .btn:active { background: var(--fld-fill-hover); }
.te-newrow .btn svg { width: 18px; height: 18px; }

/* 管理行拖动把手：与子任务 .sub-handle / 习惯 .hb-grip 同一只形与手感；
   让位滑行交给 CSS，拖起行本身即时跟手（transition:none） */
.mg-grip {
  flex: 0 0 24px; width: 24px; height: 38px; margin-left: -8px; margin-right: 2px; padding: 0;
  border: none; background: transparent;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--text-4); opacity: .55; cursor: grab;
  touch-action: none; -webkit-user-select: none; user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.mg-grip:active, .mg-row.is-dragging .mg-grip { cursor: grabbing; opacity: 1; }
.mg-row { transition: transform var(--d-base) var(--ease-float); }
.mg-row.is-dragging {
  position: relative; z-index: 3;
  background: var(--bg-card); border-bottom-color: transparent;
  border-radius: var(--r-3); box-shadow: var(--shadow-float);
}
.is-dragging-mode .mg-row.is-dragging { transition: none; } /* 拖起那行必须逐帧跟手 */
#catRows.is-dragging-mode, #typeRows.is-dragging-mode { user-select: none; -webkit-user-select: none; }
#catRows.is-dragging-mode .mg-row:active, #typeRows.is-dragging-mode .mg-row:active { background: transparent; }

/* ============================================================
   「快速记」独立一页（1011 落地）
   ------------------------------------------------------------
   站主口径：点首页那颗加号 → 它向左长开成输入条，同时整页换成「快速记」；
   首页整块退场（不是压在底下当背景），顶栏保留（壳与钮一个字不动，只有标题换）。
   本块只**新增**，不动上面 .nl-sheet / .nl-full 那几段旧抽屉——出问题把
   app.js 里的 NL_PAGE_ON 翻成 false 就整条回退，样式留着不碍事。

   几何照搜索 v3 那条结论：**顶锚**（顶边钉在顶栏底、键盘只压底边，
   整块位移这条链从根上消失）。遮罩顶边必须从顶栏底起，顶栏才保持可点
   （搜索那轮踩过：guard 从 0 起会把顶栏整个盖住，✕ 与输入框全点不动）。
   高度走 --npg-h（JS 按 visualViewport 现算），键盘起落时输入条自然骑在键盘沿上。
   ============================================================ */
.nl-guard {
  position: fixed; left: 0; right: 0; bottom: 0;
  top: calc(var(--safe-top) + var(--header-h));
  z-index: 8990; touch-action: none;
}
.nl-page {
  position: fixed; left: 0; right: 0;
  /* 1012 第二轮：页顶从「停在顶栏底」改成**伸到屏幕最上沿**，让开的那一截（--npg-head）
     交给顶栏与「最近 / 开新对话」两截玻璃。原来那一版内容压根滑不进顶栏底下，那块柔光
     玻璃就永远只糊着一层静止的旧页面——站主说的「翻动时什么都看不见，等于没有玻璃」。
     顶栏靠下面 body.nl-page-on .header 抬到本页之上：这一页开着时 .app 没有 transform
     （has-layer 只由 #modalMask 与 body>.wp-mask 驱动，见 app.js initLayerDepth），
     所以顶栏的 z-index 还在根层叠上下文里，抬得动。 */
  top: 0;
  height: var(--npg-h, 100dvh);
  --npg-head: calc(var(--safe-top) + var(--header-h) + 12px);   /* 状态栏 + 顶栏那一截，页内三处共用；+12px＝1106 顶栏助手脸（V3）让位 */
  z-index: 8995; box-sizing: border-box;
  background: var(--bg-page);
  display: flex; flex-direction: column;
  overflow: hidden;
  /* 1018：入场用「纵深入场」——本页淡入 + 轻微放大（.97→1，读作往前浮出），
     与此同时底下整块 .app（含顶栏）经 has-layer 后退 scale(.94)（app.js 把 nl-page-on 纳入纵深判定，
     复用抽屉/详情那条现成的背景后退）。背景后退 .55s 是主角，本页淡入 .3s 与之重叠即可。
     不再走左右推。 */
  animation: nlPageIn var(--d-push) var(--ease-float);
  /* 键盘那一台阶摊成滑行（1012 动效第一条）。与 .wp-mask.kbd-follow 同一个理由、
     同一条曲线：安卓很多 ROM 的 IME 高度就是一两步到位，JS 每帧算得再对也只是换个
     更小的台阶，唯一治法是给**被 JS 重写的那个属性**挂过渡。刻意 linear 不 --ease-float：
     这不是我们主动发起的进场，是跟一个外部离散台阶（见本文件 .kbd-follow 那段注释）。
     首拍不滑：app.js 在 appendChild **之前**先 syncH() 把 --npg-h 写好，
     入场那一下没有高度可过渡（否则页面会从兜底值长上来）。 */
  transition: height var(--d-base) linear;
}
/* 1018 A 案：不再把共享顶栏浮到本页之上。可序自带一条顶栏（.npg-head），
   打开时整块 .app（含原顶栏）经 has-layer 后退到本页背后、被不透明页盖住——这才是「纵深入场」。
   （原 body.nl-page-on .header{z-index:9000} 撤掉；浮在页上的表单另走 #modalMask.is-above-nl，不受影响。） */
/* 退场：与纵深入场成对——本页淡出 + 轻微缩小，背景 .app 同时经 has-layer 从 .94 弹回 1。
   退场期间仍让页跟着视口长满（bottom:0 / height:auto）、摘掉那条 height 过渡（键盘回落用的、
   别在退场这一下里搅），沿用 1012 第四轮「侧滑收起画面一闪就没」那次的几何修法。 */
.nl-page.is-out { bottom: 0; height: auto; transition: none;
  animation: nlPageOut var(--d-toast) var(--ease-float) forwards; }
@keyframes nlPageIn  { from { opacity: 0; transform: scale(.97); } to { opacity: 1; transform: none; } }
@keyframes nlPageOut { from { opacity: 1; transform: none; } to { opacity: 0; transform: scale(.98); } }
.nl-page[hidden] { display: none; }
/* 收 dock：它 z 60、本页 z 8995，留着只会在条底下露半截（同 body.hs-open 口径） */
body.nl-page-on .tabbar { display: none; }

/* ---- 上半页：大标题 · 分段 · 为你推荐（照参考图那五件） ---- */
/* 页内导航行（1011d 方案 A）：历史入口放页内、不动顶栏。常驻页顶不跟内容滚走——
   对话很长时它俩仍然够得着；文字钮（不是胶囊），与页内小字同级。 */
/* 「最近 / 开新对话」这一行（1012 第二轮改成玻璃）：材质与 dock 同一枚令牌
   （--glass-fill / --glass-blur，站主点名「与引导导航滑块那个背景一致」）。
   它从 .nl-page 的直接子元素**搬进 .npg-scroll 当第一件**——不进滚动容器就没有 sticky，
   会话也不会从它底下划过；底下没东西可透，玻璃就又是一块贴片。
   左右各 -14px 是把玻璃铺满整幅（.npg-scroll 自带 14px 内距），文字仍靠自己的 padding
   回到那条 14px 竖线上。刻意不再补下沿描边：顶栏自己那条 1px 就在它头顶上。
   ⚠ sticky 的 `top: 0` 不是笔误：参考边是滚动容器的**内容盒上沿**，而那一截正好被
   .npg-scroll 的 padding-top（= 状态栏 + 顶栏）垫到了顶栏底下——写 top: 0 才粘在顶栏下沿，
   写 top: var(--npg-head) 会再往下多让一截（探针 I3 实测 112 vs 56 抓出来的）。 */
 /* 1018 A 案：可序自带顶栏——逐字复刻共享顶栏 .header 的柔光玻璃（同底色 / 同 blur / 同下沿描边 /
    同内距），绝对浮在页顶；下方内容靠 .npg-scroll 的 padding-top 从它底下滚过，才有原生毛玻璃观感。
    共享顶栏随整块 .app 后退到本页背后被盖住，这条顶栏就是它的替身（返回 ‹ + 标题「可序AI」）。 */
 .npg-head { position: absolute; left: 0; right: 0; top: 0; z-index: 4; box-sizing: border-box;
   height: var(--npg-head); padding: var(--safe-top) var(--content-px) 0;
   display: flex; align-items: center; gap: var(--sp-3); overflow: hidden;
   background: color-mix(in srgb, var(--bg-card) 55%, transparent);
   -webkit-backdrop-filter: blur(28px) saturate(180%); backdrop-filter: blur(28px) saturate(180%);
   border-bottom: 1px solid color-mix(in srgb, var(--border) 60%, transparent); }
 /* 返回钮＝站内二级页通用 .mf-back 同款材质：透明幽灵、40 高 / 44 触控宽、r-3、text-1、22px chevron、按下 --bg-hover。 */
 .npg-back { flex: none; border: none; background: transparent; cursor: pointer;
   height: 40px; min-width: 44px; padding: 0 var(--sp-2); margin-left: calc(-1 * var(--sp-2));
   display: inline-flex; align-items: center; justify-content: center;
   border-radius: var(--r-3); color: var(--text-1); -webkit-tap-highlight-color: transparent; }
 .npg-back svg { width: 22px; height: 22px; }
 .npg-back:active { background: var(--bg-hover); }
 /* 标题复用站内 .wp-title（17px·bold），像 .nl-full / .mgr-full 二级整页那样居中在返回钮这一行；
    top 让开状态栏、bottom 撑到条底，flex 居中与返回钮同一条基线。 */
  .npg-head .wp-title { position: absolute; left: 0; right: 0; top: var(--safe-top); bottom: 0; margin: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: calc(var(--sp-1) / 2); text-align: center; pointer-events: none; }
  /* 顶栏助手脸（1106 选型 V3，1107 站主加两笔：脸调大到 34px、昵称收 13px、脸下压叠住胶囊上沿）：
     容器不收点击（点击仍归胶囊），脸抬 z-index 压在胶囊上面——pointer-events:none，压着也不挡点。
     尺寸在这一处定——引擎按实际盒子换算最小厚度保底。 */
  .npg-head-face { flex: none; display: flex; align-items: center; justify-content: center; pointer-events: none;
    position: relative; z-index: 1; }
  .npg-head-face .ai-face { width: 34px; height: 34px; }
  /* 助手名＝可点击白胶囊（1107 站主令撤掉尾部 > 箭头：入口性由整枚胶囊的点击承担）。
     整行容器仍 pointer-events:none 不挡返回/对话钮；只有这颗 .npg-title-cap 收点击、进「可序Ai 设置」页。
     胶囊自适应宽、文字过长省略号，底色吃 --bg-card（浅色=白、深色自动跟随）。 */
  .npg-title-cap { pointer-events: auto; display: inline-flex; align-items: center; max-width: 68%;
    background: var(--bg-card); color: var(--text-1); border: 1px solid var(--border); border-radius: var(--radius-pill);
    padding: var(--sp-1) var(--sp-3); font: inherit; font-size: calc(13px * var(--fs-scale)); font-weight: var(--fw-bold); line-height: 1.15;
    /* 1107 站主令「形象压着一点昵称」：胶囊上提 6px（净叠 ≈4px，flex gap 2px 抵掉一点），
       负值走 --sp-1 倍数——裸 px 间距是棘轮硬闸。 */
    margin-top: calc(var(--sp-1) * -1.5);
    cursor: pointer; -webkit-tap-highlight-color: transparent; transition: background var(--d-base) ease; }
  .npg-title-txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .npg-title-cap:active { background: var(--bg-hover); }
 /* 历史抽屉里那几行：标题 + 时间/条数（顶栏右抽屉 npg-rd-list 复用同一套；壳用 .tf-list/.tf-row，容器类名别改） */
.npg-h-tip { font-size: var(--fs-micro); color: var(--text-4); padding: 0 2px var(--sp-2); }
.npg-h-empty { font-size: var(--fs-micro); color: var(--text-4); padding: var(--sp-3) 2px; }
.npg-h-row { flex-direction: column; align-items: flex-start; gap: 3px; }
.npg-h-t { font-size: var(--fs-body); color: var(--text-1); }
.npg-h-m { font-size: var(--fs-micro); color: var(--text-4); font-variant-numeric: tabular-nums; }
.npg-h-row.is-live .npg-h-t { font-weight: var(--fw-bold); }
/* 顶部那截 padding ＝ 状态栏 + 顶栏：内容从这一屏的**最上沿**开始滚（padding 区仍算进
   可滚范围），往上翻时字会一路滑到顶栏底下。内容起点由 .npg-welcome 的 margin-top 决定
   ——2026-10-20 历史入口搬到顶栏右抽屉后，原页内 .npg-nav 那行（含 sticky 玻璃）已移除。 */
 .npg-scroll { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain;
    padding: var(--npg-head) var(--sp-3) 0; display: flex; flex-direction: column; }
.npg-welcome { flex: none; margin-top: 46px; }
.npg-big { font-size: calc(23px * var(--fs-scale)); font-weight: var(--fw-bold); letter-spacing: -.4px; text-align: center; line-height: 1.35; }
.npg-seg { display: flex; width: 236px; margin: var(--sp-4) auto 0; background: var(--bg-count); border-radius: var(--radius-pill); padding: 3px; }
.npg-seg button { flex: 1; border: none; background: transparent; font-family: inherit; font-size: var(--fs-label); font-weight: var(--fw-medium);
  color: var(--text-3); padding: var(--sp-2) 0; border-radius: var(--radius-pill); cursor: pointer;
  transition: background var(--d-base) var(--ease-float), color var(--d-base) var(--ease-float), box-shadow var(--d-base) var(--ease-float); }
.npg-seg button.on { background: var(--bg-card); color: var(--text-1); box-shadow: 0 1px 3px rgba(17,17,17,.10); }
.npg-hr { height: 1px; background: var(--border); margin-top: var(--sp-6); }
.npg-reco { flex: none; margin-top: var(--sp-3); }
.npg-reco .lab { font-size: var(--fs-micro); color: var(--text-4); }
.npg-reco button { display: flex; align-items: center; gap: var(--sp-3); width: 100%; min-height: 48px; padding: var(--sp-3); margin-top: var(--sp-2);
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-card-m); box-shadow: var(--shadow-card);
  font-family: inherit; text-align: left; color: var(--text-1); cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast); }
.npg-reco button:active { background: var(--bg-page); border-color: var(--border-strong); }
.npg-reco .q { flex: 1; min-width: 0; font-size: var(--fs-caption); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.npg-reco .go { flex: none; font-size: var(--fs-micro); color: var(--text-4); }
.npg-reco .note { margin-top: var(--sp-2); font-size: var(--fs-micro); color: var(--text-4); line-height: 1.6; }
/* 说过一句之后：大标题与推荐让位，对话接手中区 */
.nl-page.is-chat .npg-welcome { display: none; }
/* 结构不变式（返回重进实拍：对话气泡与「你好我是可序AI / 为你推荐」空态同屏叠在一起）：
   只要对话流里有**真实消息气泡**（用户气泡 .npg-msg 或回复 .npg-ans），空态就必须让位——
   不依赖 JS 有没有把 is-chat 补上。真机上「侧滑/返回键」重进这一页时，恢复会话 + 置
   is-chat 那几步偶发被 WebView 的 rAF/定时器节流漏掉，于是空态 chrome 压在已恢复的气泡上。
   ⚠ 只认 .npg-msg/.npg-ans，不认 .npg-sep：「新开对话」resetThreadDom 后立刻 append 一条
   `.npg-sep` 分隔线（app.js:12649），若按 :not(:empty) 会把分隔线也算内容 → 新对话永远请不回 hero
   （本轮踩过的坑）。用「有没有真实气泡」判定才与 is-chat 语义一致；is-chat 那条照旧保留。 */
.nl-page:has(.npg-thread .npg-msg) .npg-welcome,
.nl-page:has(.npg-thread .npg-ans) .npg-welcome { display: none; }
/* ---- 快速记独立一页 · 聚焦态（1012 拆成两条线，别再并排写在一起）----
   ① 大标题 / 分段 / 分隔线挂 is-focus：它们在 .npg-welcome 里，聊起来之后整块
      本来就 display:none，收起时动的只有「推荐」那一坨——列表底边不受影响，
      所以这一档瞬变交给 JS 的 FLIP 补滑行（app.js flipRun），不必等键盘。
   ② 底排六枚改挂 **is-kbd**（键盘真的收着）才折叠，且走高度滑行：
      挂在 is-focus 上会先键盘 150~300ms 生效，会话列表的底边先掉 56px、
      再随键盘抬上去，一来一回正是站主说的「聚焦时闪一下」。键盘起了再一起折，
      方向只剩一个「上」。display:none 不能插值，所以起点高度用 --pills-h
      （打开时 JS 量一次真实高写进来；字号三档下它不是常数，不许写死）。 */
/* ---- 快速记独立一页 · 折叠时机（1012 第四轮：全部改挂 is-kbd，一个触发、一个方向）----
   第三轮只把底排六枚从 is-focus 挪到 is-kbd，站主真机仍看见「聚焦时先往上顶一下，
   然后才是正常的往上移动」——因为欢迎区那三件（大标题 / 分段 / 分隔线）与页内那一栏
   还挂在 is-focus 上：手指一按就先收它们（往上顶一次），键盘两百毫秒后到了再收底排、
   页面压矮（再往上一次）。两段路同向但分两拍，读起来就是「顶一下再滑」。
   现在**只认键盘真的收着**这一件事：聚焦那一刻布局纹丝不动，键盘起来所有折叠与压矮
   挤进同一条 .2s 里一起走。is-focus 这个状态位仍然维护（焦点判定与 FLIP 的触发口），
   只是不再拿它改布局。 */
.nl-page.is-kbd .npg-big,
.nl-page.is-kbd .npg-seg,
.nl-page.is-kbd .npg-hr { display: none; }
.nl-page.is-kbd .npg-welcome { margin-top: var(--sp-4); }
/* ⚠ border-box 那一夹（探针实测抓出来的）：height:0 时**上下内距仍然占位**，
   used height 被夹到 padding 之和（6+4=10px）——底排折到 10px 就再也下不去，
   列表底边永远悬着这一截。折叠必须把上下内距一起归零，且走同一条 .2s。 */
.nl-page.is-kbd .npg-pills { height: 0; padding-top: 0; padding-bottom: 0; opacity: 0; pointer-events: none; }

/* ---- 对话流：自己的话进深色气泡；**回复也包成气泡**（1011c 站主真机第二条）----
   站主的原话：「快速记的回复也用聊天气泡包住」。所以回复＝白底气泡（圆角 16/16/16/4，
   与用户那颗镜像），识别中那条用同一个壳、只换内容与小标（✦ 星芒转 → 文字「快速记」）。
   1012：小标前那枚红点撤掉（站主点名）——`.who` 只剩文字，`.npg-ans .who i` 那条死规则一并删。
   **贴顶，只有溢出了才钉底**（1012 第二轮修正，别走回头路）：会话列表**顶对齐**，
   几条短对话就从上往下排。上一轮我给这条加了 `margin-top: auto` 想让列表「骑在输入条
   上方」，结果打开旧对话、以及新对话的第一条全被推到屏幕底下，中间空一大片，站主打回。
   想清楚了一件事：键盘压矮这一屏时，真正会挡住最新几条的只有**内容已经溢出**那一种形态，
   而那正是 app.js `pinBottom()` 逐帧钉 scrollTop 管的；没溢出就谁也挡不着，不需要贴底。
   底部留 10px：键盘态底排六枚折叠之后，这条 padding 是最后一条与输入条之间唯一的间距
   （原来只有 2px，站主点「太近」）。 */
.npg-thread { flex: none; padding: var(--sp-3) 0 var(--sp-2); }
.npg-msg { width: fit-content; max-width: 84%; margin-left: auto; margin-top: var(--sp-3);   /* 与上一条之间留出间距（1011c 第四条：原来贴着 0） */
  background: var(--primary); color: var(--on-primary);
  border-radius: var(--r-4) var(--r-4) var(--r-1) var(--r-4); padding: var(--sp-2) var(--sp-3); font-size: var(--fs-body); line-height: 1.5;
  box-shadow: var(--shadow-card); animation: npgIn var(--d-med) var(--ease-float); }
@keyframes npgIn { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
.npg-thread > *:first-child { margin-top: 0; }
.npg-ans { margin-top: var(--sp-3); max-width: 96%; width: fit-content;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--r-4) var(--r-4) var(--r-4) var(--r-1);
  padding: var(--sp-2) var(--sp-3) var(--sp-3); box-shadow: var(--shadow-card); animation: npgIn var(--d-med) var(--ease-float); }
.npg-ans .who { display: flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-micro); color: var(--text-4); font-weight: var(--fw-medium); }
/* 2026-10-26「名字从气泡去掉」→ 11-02 H1 翻案恢复 → 2026-11-07 再翻案（站主令「气泡里的
   助手形象与昵称三处全摘」）：答案气泡不再画身份行，.who 只剩忙碌条那一行文字（正在翻/正在记…）。
   从前这里靠 :not(.is-busy) 把答案行的视觉还回来——现在没有答案 .who 了，那条随之退役。 */
/* 换场不重弹（2026-10-26 站主真机：思考气泡→结果气泡观感是「又冒出来一个」）：
   忙碌条被答案顶掉那一拍，观察器给新答案挂 .np-swap 压掉 npgIn 入场重演——
   气泡不再重新入场，只有文字按既有 npTypeIn 逐行浮现（站主同轮拍板：浮现含 blur 照旧保留）。
   历史还原 / 无忙碌条垫底的新气泡不挂此标记，入场照旧。 */
.npg-ans.np-swap { animation: none; }
/* 识别在途：那颗星芒转起来（复用站内 .nl-ai-spark 的既有动画，不自造第二套），
   成了原地换成红点 + 「快速记」（1011b/c）。 */
.npg-ans.is-busy .who { color: var(--text-3); }
.npg-ans.is-busy .think { margin-top: var(--sp-1); font-size: var(--fs-body); color: var(--text-4); }
@keyframes npgBlink { 0%, 100% { opacity: .35; transform: scale(.85); } 50% { opacity: 1; transform: none; } }
.npg-ans .say { margin-top: var(--sp-1); font-size: var(--fs-body); line-height: 1.6; }
 .npg-ans .say b { font-family: var(--font-mono); font-weight: 700; }
/* 长串（邮箱 / URL / 等宽字段值）在气泡内换行，不撑出横向可滚范围（配合 .npg-scroll overflow-x:hidden） */
 .npg-msg, .npg-ans, .npg-ans .say { overflow-wrap: anywhere; word-break: normal; }
/* ---- 可序AI 查询卡（1012）：骨架完全复用 .nl-pv/.nl-pv-row，只添三样——
   金额列（等宽字右靠）、分类占比条、脚注行。查询行**不可点**，:active 一律不给按压反馈
   （站内铁律：干不了事的行不许装按得下去）；覆盖必须排在本段基础规则之后。 ---- */
.npq-amt { margin-left: auto; padding-left: var(--sp-2); font-family: var(--font-mono); font-size: var(--fs-caption); color: var(--text-2); white-space: nowrap; }
.npq-cat { flex-wrap: wrap; row-gap: var(--sp-1); }
.npq-cat .nl-pv-row-t { max-width: calc(100% - 76px); }
.npq-bar { flex-basis: 100%; height: 5px; border-radius: var(--r-pill); background: var(--border); overflow: hidden; }
.npq-bar i { display: block; height: 100%; border-radius: var(--r-pill); background: var(--primary); }
.npq-foot { color: var(--text-4); font-size: var(--fs-caption); }
.npq-foot .nl-pv-tag { display: none; }
.npq-q .nl-pv-row:active { background: var(--bg-page); border-color: var(--border); }
.npq-q .nl-pv-row.is-done { opacity: .55; }
.npq-q .nl-pv-row.is-done .nl-pv-tag { background: var(--border-strong); color: var(--bg-card); }
/* ---- 1012 真机二轮：查询卡是**阅读内容**不是按钮列表——一行一卡太费劲。
   行退回紧凑列表：无独立卡底、分隔线分行、行高从 44px 热区档降到阅读档。
   .nl-page 前缀抬特异性（0,3,0），压过上面 .nl-page .nl-pv-row 的卡片化。 ---- */
.nl-page .npq-q .nl-pv,
.nl-page .npq-q .nl-pv-row { background: transparent; border: 0; box-shadow: none; border-radius: 0; }
.nl-page .npq-q .nl-pv { margin: 0; padding: 0 2px var(--sp-1); }
.nl-page .npq-q .nl-pv-row { min-height: 0; padding: var(--sp-2) 2px; margin: 0; }
.nl-page .npq-q .npq-sum b { color: var(--text-3); font-weight: var(--fw-medium); }
.nl-page .npq-q .npq-sum .nl-pv-row-m,
.nl-page .npq-q .npq-sum .nl-pv-tag { color: var(--text-4); }
/* ---- 修改卡上的「应用」（1012）：页面载体把悬浮槽藏了（.npg-bar 那条 display:none），
   修改是唯一要确认才落库的落点，它的应用面就长在对话卡右下——
   材质沿用动作胶囊那颗（黑底白字、反白主操作），但它在白气泡里不是悬浮件，不挂重影。 ---- */
/* 气泡内的「撤销」：跟随应用钮同排右对齐，热区 38 档（站主手感标准），点了转「已撤销」灰字。
   两行声明合并（1012：拆开写会撞棘轮的逐字重复组）。 */
.npg-actrow, .npg-undorow { margin-top: var(--sp-2); display: flex; justify-content: flex-end; }
.npg-actrow { margin-top: var(--sp-3); }
.npg-actrow .nl-act-apply {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-1); white-space: nowrap;
  height: 32px; min-height: 32px; padding: 0 var(--sp-3);
  background: var(--primary); color: var(--on-primary);
  border-radius: var(--r-2); font-size: var(--fs-label); font-weight: var(--fw-medium);
}
.npg-actrow .nl-act-apply .npg-cbtn-ico { flex: none; width: 14px; height: 14px; }
.npg-undorow .npg-undo {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-1); white-space: nowrap;
  min-height: 32px; padding: 0 var(--sp-2); border: 1px solid transparent; border-radius: var(--r-2);
  /* 撤销是低频动作（2026-10-22 站主点名「再弱化一点」）：去描边去底、字降到最淡的 --text-4、
     字重降 regular——从「一颗实心钮」退成一行淡灰轻字，图标走 currentColor 跟着淡。
     :active 仍给 bg-muted、min-height 仍 32：只让它不抢视觉，可点性与热区不丢。 */
  background: transparent; color: var(--text-4); font-size: var(--fs-label); font-weight: var(--fw-regular);
}
.npg-undorow .npg-undo:active { background: var(--bg-muted); }
.npg-undorow .npg-undo:disabled { cursor: default; }
/* 已撤销：降为哑光描边、去图标、纯灰字，明确「已失效、不可再点」 */
.npg-undorow .npg-undo.is-done { border-color: var(--border); color: var(--text-4); background: transparent; }
.npg-undorow .npg-undo.is-done .npg-cbtn-ico { display: none; }
/* ---- 1012 四轮（图2 去胶囊化 / 图1 排版 / 新对话分隔线）---- */
/* 查询卡头部：一行小灰字（区间 · 计数），不再黑胶囊 */
.npq-head { font-size: var(--fs-micro); color: var(--text-4); padding: 0 2px var(--sp-2); }
/* 行内标签：描边小标替代黑胶囊，视觉重量让给内容
   （1031 追加第二个选择器：确认卡 .npg-cbody 里的行标共用这一把尺，不另写一条重复规则） */
.npq-q .npq-tag2,
.npg-ans .npg-cbody .npq-tag2 {
  flex: none; border: 1px solid var(--border-strong); color: var(--text-3); background: transparent;
  border-radius: var(--r-pill); padding: 1px var(--sp-2); font-size: var(--fs-label);
}
/* AI 长回复的编号行：编号淡色、内容跟读；行距给呼吸 */
.npg-ans .say { line-height: 1.75; }
.npg-ans .say .np-li { display: block; padding-left: var(--sp-4); text-indent: -20px; margin-top: var(--sp-1); }
.npg-ans .say .np-li-n { color: var(--text-4); font-family: var(--font-mono); }
/* 智能升级⑤·Markdown 排版：段落/小标题/分点的垂直节奏全部交给这里（块之间已不再叠 <br>），
   间距只用设计 token，收尾块不留底边距。 */
.npg-ans .say .np-p { margin: 0 0 var(--sp-2); }
.npg-ans .say .np-h { display: block; font-weight: 700; font-size: calc(var(--fs-body) + 1px); color: var(--text-1); margin: var(--sp-1) 0; letter-spacing: .01em; }
.npg-ans .say .np-ul .np-li-n { color: var(--text-4); font-family: var(--font-sans); }
.npg-ans .say > :last-child { margin-bottom: 0; }
/* 开新对话的流内分隔线：细线 + 小字 + 撤销入口（4 秒后 is-calm 淡掉撤钮与高亮，线留着当页码） */
.npg-sep { display: flex; align-items: center; gap: var(--sp-3); margin: var(--sp-4) 0 var(--sp-1); }
.npg-sep .npg-sep-line { flex: 1; height: 1px; background: var(--border); }
.npg-sep .npg-sep-t { font-size: var(--fs-micro); color: var(--text-4); }
 .npg-sep .npg-sep-undo {
   border: 1px solid var(--border-strong); border-radius: var(--r-2); background: transparent;
   color: var(--text-2); font-size: var(--fs-label); padding: 3px var(--sp-3); min-height: 26px;
 }
.npg-sep.is-calm .npg-sep-undo { opacity: 0; pointer-events: none; transition: opacity var(--d-morph) ease; }
/* 删除确认流（1012「全部都做」C）：确认深钮 + 算了描边钮，同行右对齐；
   打字即放弃（sendNl 开头清 pending），不做超时。 */
 .npg-confirmrow { margin-top: var(--sp-3); display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--sp-2); }
 .npg-confirmrow .npg-cbtn {
   display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-1); white-space: nowrap;
   min-height: 32px; padding: 0 var(--sp-3); border-radius: var(--r-2);
   font-size: var(--fs-label); font-weight: var(--fw-medium);
 }
 .npg-cbtn-ico { flex: none; width: 14px; height: 14px; }
.npg-confirmrow .npg-cyes { background: var(--primary); color: var(--on-primary); border: 0; }
 .npg-confirmrow .npg-cno { background: transparent; color: var(--text-2); border: 1px solid var(--border-strong); order: -1; }
/* 查询卡的跳页提示（E 的可见入口）与行按压反馈（行现在可点跳页）
   （1031 追加第二个选择器：确认卡里仍可点的候选行共用这一档按压衬底，不另抄一条） */
.npq-hint { margin-top: var(--sp-1); font-size: var(--fs-micro); color: var(--text-4); text-align: right; }
.nl-page .npq-q .nl-pv-row[data-npq-jump]:active,
.npg-ans .npg-cbody .nl-pv-row[data-nl-cand]:active { background: var(--bg-muted); border-radius: var(--r-2); }
/* ---- 流式模糊打字（1012 二轮站主点名）：AI 回复逐段浮现——每段 blur 渐清 + 淡入；
   渲染节奏不是假内容（全文已到手），点击气泡立即出全文，reduced-motion 直接显示 ---- */
@keyframes npTypeIn { from { opacity: 0; filter: blur(3px); transform: translateY(2px); } to { opacity: 1; filter: blur(0); transform: none; } }
.npg-ans .say .np-ti { animation: npTypeIn var(--d-morph) var(--ease-float) both; }
/* ---- 卡片出场（1013 站主点名）：文字有 .np-ti 逐段浮现，卡却是「想完啪一下」整块出现。
   补一条同一语言的入场：卡里每一块淡入 + 轻微上浮，逐块错峰（delay 由 JS 按序号写进来，
   不在 CSS 里铺 nth-child）。走 transform/opacity 两个可合成属性，不碰布局。 ---- */
@keyframes npPartIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.npg-ans .np-rev { animation: npPartIn var(--d-enter) var(--ease-float) both; }
/* 行动出口（1012「全部都做」②→ 2.85 重排）：结果动作压成整行、等宽，
   最右那颗＝实心主操作（去/查），其余＝描边（补充/放弃）。文案由 go 派生（app.js NL_ACT_LABEL），
   标签与目标不会串页。 */
 .npg-aiactrow { margin-top: var(--sp-2); display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--sp-2); }
  .npg-aiactrow .npg-aibtn {
    flex: 0 1 auto; min-width: 0; min-height: 32px; padding: 0 var(--sp-3);
    display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-1);
    border: 1px solid var(--border-strong); border-radius: var(--r-2); background: var(--bg-card);
    color: var(--text-1); font-size: var(--fs-label); font-weight: var(--fw-medium);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* 1030 清死样式：.npg-aibtn-ico 0 命中（钮还在，图标改由 .npg-cbtn-ico 出品），规则永不匹配，摘掉。 */
  /* 动态落点动作钮（去账本/去备忘…）用 nlBtnIcon 产的 npg-cbtn-ico，与主操作同档 14px */
  .npg-aiactrow .npg-aibtn:last-child { background: var(--primary); color: var(--on-primary); border-color: var(--primary); }
/* 点一下即存（2026-10-28 站主令：快捷钮点完要直接存好，别丢进空白新增页）：
   按过的钮留在原地、退一档、收掉点击（防连点写两遍）。让它消失反而更可疑——
   用户会觉得那颗钮是坏的。写失败时代码会把类摘掉、文案还原、重新可点。 */
.npg-aiactrow .npg-aibtn.is-done { opacity: .5; pointer-events: none; }
/* 可序AI · 档案卡 = 数字名片（站主 2026-10-19，对齐新参考图）：满宽白卡、头像+姓名+关系药丸+年龄/性别、
   兴趣浅灰 chips、基本信息「线性图标 + 灰标签 + 深色值」靠留白分行、相关记忆「时钟 + 日期 + 内容」。
   彩色克制（关系徽章也走中性 token，暗档安全）。整卡可点跳人物页（.npf-card 带 data-npq-jump）。
   含此卡的气泡放开成满宽白卡——解决站主点名的「档案太窄」；纯文字聊天气泡仍是贴合的小气泡不受影响。 */
.npg-ans:has(.npf-card){ width:100%; max-width:100%; background:var(--bg-card); border:0; border-radius:var(--r-5);
  padding:var(--sp-4); box-shadow:0 2px 14px rgba(17,17,17,.07); }
.npf-card{ background:transparent; }
.npf-head{ display:flex; align-items:center; gap:var(--sp-3); }
.npf-av{ flex:none; width:56px; height:56px; border-radius:var(--r-circle); background:var(--bg-count);
  display:flex; align-items:center; justify-content:center; font-size:calc(22px * var(--fs-scale)); font-weight:var(--fw-semibold); color:var(--text-3); overflow:hidden; }
.npf-id{ flex:1; min-width:0; }
.npf-name-line{ display:flex; align-items:center; gap:var(--sp-2); }
.npf-name{ font-size:calc(18px * var(--fs-scale)); font-weight:var(--fw-bold); color:var(--text-1); line-height:1.2; }
.npf-rel{ flex:none; font-size:var(--fs-11); font-weight:var(--fw-medium); color:var(--text-3); background:var(--bg-count); border-radius:var(--r-pill); padding:2px var(--sp-2); }
.npf-meta{ font-size:calc(13px * var(--fs-scale)); color:var(--text-4); margin-top:var(--sp-1); }
.npf-chips{ display:flex; flex-wrap:wrap; gap:var(--sp-2); margin-top:var(--sp-3); }
.npf-chip{ font-size:calc(13px * var(--fs-scale)); color:var(--text-2); background:var(--bg-muted); border-radius:var(--r-pill); padding:var(--sp-1) var(--sp-3); }
.npf-sec{ margin-top:var(--sp-4); }
.npf-sec-h{ font-size:calc(13px * var(--fs-scale)); font-weight:var(--fw-medium); color:var(--text-3); margin-bottom:var(--sp-2); }
.npf-kv{ display:flex; align-items:baseline; gap:var(--sp-2); padding:var(--sp-2) 0; }
.npf-ico{ flex:none; width:16px; height:16px; color:var(--text-4); align-self:center; }
.npf-k{ flex:none; min-width:52px; color:var(--text-4); font-size:var(--fs-caption); }
.npf-v{ flex:1; min-width:0; color:var(--text-1); font-size:var(--fs-caption); overflow-wrap:anywhere; }
.npf-vm{ color:var(--text-4); font-size:var(--fs-micro); margin-left:var(--sp-1); }
.npf-mem{ border-top:1px solid var(--border); padding-top:var(--sp-3); }
.npf-mrow{ display:flex; align-items:center; gap:var(--sp-2); padding:var(--sp-2) 0; }
.npf-mtime{ flex:none; font-size:var(--fs-micro); color:var(--text-4); font-variant-numeric:tabular-nums; }
.npf-mtext{ flex:1; min-width:0; font-size:var(--fs-caption); color:var(--text-1); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.npf-card[data-npq-jump]:active{ opacity:.7; }
/* 结果卡：站内那条 .nl-pv / .nl-pv-row 骨架，在这一屏换成**白卡 + 1px 描边 + 小阴影**
   （1011b 站主真机第四条：原来用 --bg-page 灰槽，在灰页上等于没有承载，读成「背景色重叠」）。
   行内标题 17px 当主角，落点仍是一枚黑胶囊。 */
.nl-page .nl-pvbox { padding: 0; }
.nl-page .nl-pvbox:empty { display: none; }
.nl-page .nl-pv,
.nl-page .nl-pv-row { background: var(--bg-card); border: 1px solid var(--border); box-shadow: var(--shadow-card); border-radius: var(--r-3); }
.nl-page .nl-pv { margin: var(--sp-2) 0 0; padding: var(--sp-3); font-size: var(--fs-caption); }
.nl-page .nl-pv-row { padding: var(--sp-3); margin: var(--sp-2) 0 0; align-items: flex-start; }
.nl-page .nl-pv-row:active, .nl-page .nl-pv.is-tap:active { background: var(--bg-page); border-color: var(--border-strong); }
/* ---- 1011c 站主真机三条收口（必须排在上面那几条之后：同特异度，后写的赢）----
   ① 卡住进白气泡之后，卡回到「浅一档」灰槽 + 无阴影——白气泡里再放白卡会糊成一片；
   ② 多条时那块次要信息（「截止 10-13 09:00」）不再另起一行：气泡够宽，跟标题同一行走，
      换行是上一条版面的遗留（≤768 段把它设成了 block）；标题过长时自己省略号，不许把行高撑开。 */
.npg-ans .nl-pv,
.npg-ans .nl-pv-row { background: var(--bg-page); box-shadow: none; }
/* ② 多条那行次要信息（「截止 10-13 09:00」）跟标题同一行走、不换行——下面那条
   `.nl-page .nl-pv-row-m` 是本块唯一的定义处，改在那里（别在这儿再写一条，
   同特异度谁后谁赢，两条并存就是下一个人踩的坑）。 */
.nl-page .nl-pv, .nl-page .nl-pv-row { max-width: 100%; }
.nl-page .nl-pv-row-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nl-page .nl-pv b, .nl-page .nl-pv-row-t b { font-size: calc(17px * var(--fs-scale)); font-weight: var(--fw-medium); letter-spacing: -.2px; }
.nl-page .nl-pv-tag, .nl-page .nl-pv-row .nl-pv-tag { background: var(--primary); color: var(--on-primary); border-radius: var(--radius-pill); }
/* 1011c：次要信息与标题**同一行**（原来照 ≤768 那套折成第二行，站主真机点单「不要自动换行」）。
   气泡够宽，`inline` 让「待办 开展会 · 截止 10-13 09:00」一行读完；标题过长时自己省略号
   （见下面 .nl-pv-row-t 那条），不许把行高撑开。 */
.nl-page .nl-pv-row-m { display: inline; margin-top: 0; font-size: var(--fs-micro); color: var(--text-4); }
.nl-page .nl-pv-row-sep { display: inline; }
.nl-page .nl-pv-hint { display: none; }   /* 引导语并进底部提示条，卡下不再复读 */
.nl-page .nl-pv-row.is-saved, .nl-page .nl-pv.is-saved { opacity: .55; }

/* ---- 底排：六类直达压成一行（横滑；右缘渐隐＝还有更多） ----
   折叠那档见上面 is-kbd 那条：起点高度 --pills-h 由 JS 量一次写进来（auto 不能插值）。 */
.npg-pills { flex: none; display: flex; gap: var(--sp-2); padding: var(--sp-1) var(--sp-3) var(--sp-1); height: var(--pills-h, auto);
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
  transition: height var(--d-base) linear, padding-top var(--d-base) linear, padding-bottom var(--d-base) linear, opacity var(--d-fast) ease;
  -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 26px), transparent 100%);
  mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 26px), transparent 100%); }
.npg-pills::-webkit-scrollbar { display: none; }
 .npg-pills .nlq-row { flex: none; display: inline-flex; align-items: center; gap: var(--sp-1); border: 1px solid var(--border);
   background: var(--bg-card); border-radius: var(--r-3); padding: var(--sp-1) var(--sp-3); margin: 0; min-height: 34px;   /* 2026-10-19 站主第二轮：44 太厚，收到 34/5-11，一行小胶囊即可 */
   font-family: inherit; font-size: var(--fs-caption); font-weight: var(--fw-medium); color: var(--text-1); cursor: pointer; }
 .npg-pills .nlq-row:active { background: var(--bg-page); border-color: var(--border-strong); }
 .npg-pills .nlq-t { white-space: nowrap; }
 .npg-pills .nlq-k, .npg-pills .nlq-chev, .npg-pills .nlq-div { display: none; }
 /* 2026-10-18：图3 的按钮「图标 + 文字」，把 HTML 里本就带的类型图标露出来——做成裸内联图标（去 .tl-ico 那枚 26px 圆井） */
 .npg-pills .tl-ico { width: auto; height: auto; border: 0; background: none; color: var(--text-2); }
 .npg-pills .tl-ico svg { width: 16px; height: 16px; }

/* ---- 底部输入条：就是那颗加号长开之后的样子 ----
   几何照样板：条自己是一块 60 高的舞台，井绝对定位在右侧，收起态＝60×44 的小圆角块
   （与那颗 60 圆钮几乎同位同尺寸，交接那一下眼睛读成「同一个东西在长」），展开＝通栏、圆角收进 12。
   1011b 站主真机四条：① 井底改 --bg-count——原来用 --fld-fill，与灰页几乎同色，
   读不出「这里是个输入框」；这一档就是搜索那个输入槽的既定材质。
   ② 白色 ⌄ 撤掉，常驻一颗黑色 ↑（有字黑、没字淡且不可点）。
   ③ 两个钮都贴右下角（bottom 锚，不是垂直居中）——换行长高时跟着往下走。
   ④ 井里那套「应用」胶囊不再出脸（#f-nl-foot 藏了）：发送就是那颗 ↑。 */
 .npg-bar { position: relative; flex: none; height: 68px; }
 .npg-well { position: absolute; right: 14px; bottom: calc(16px + var(--sab)); width: calc(100% - 28px);
  min-height: 48px; background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--fld-r);
  --npg-morph-r: 22px;            /* 收起态那颗的自有半径（2.12 那条教训：入口自己定值，别借 --control-h 那类会被 ≤768 重映射的令牌） */
  box-shadow: var(--shadow-card);
  overflow: hidden; transition: width var(--d-med) var(--ease-float), border-radius var(--d-med) var(--ease-float),
    background var(--transition-fast), box-shadow var(--transition-fast), border-color var(--transition-fast); }
/* 白坨彻底根治（站主手机实拍：入场后井永久卡在 is-morph 的 60px 白块、字还打不见；
   挂 JS 事件 / 用 forwards 补动画都不可靠——forwards 会把 is-morph 的收起样式「永久停住」，
   反而让发送钮卡在假启用态点不动、页面停在半初始化）。
   正解：is-morph 不再控制任何「静止态」样式。入场那一下的「60px→整条向左长开」改写成一条
   只演一次、结束后自动落到元素天然值（展开 / 可见）的 CSS 入场动画，不写 forwards。
   这样无论 JS 有没有摘掉 is-morph，井的最终态永远是展开：is-morph 赖着不走 = 无副作用
   （它已不再对应任何持久样式）；正常设备入场动画演完即停在展开态，视觉与旧的「摘类过渡」一致。 */
@keyframes npgWellOpen { from { width: 60px; min-height: 44px; border-radius: var(--npg-morph-r); } }
@keyframes npgInkOpen { from { opacity: 0; } }
.npg-well { animation: npgWellOpen var(--d-med) var(--ease-float); }
/* 注：is-morph 仍由 JS 开/收（settleWell），但此处不再给它任何持久视觉——
   井的静止态永远是天然展开，is-morph 卡在与否都不影响功能，白坨从根上不可能再出现。 */
.npg-well:focus-within { border-color: var(--primary); box-shadow: var(--focus-glow); }
.npg-well textarea { display: block; width: 100%; box-sizing: border-box; border: 0; outline: none; background: transparent;
  -webkit-appearance: none; appearance: none; resize: none; overflow-y: auto;
  font-family: inherit; font-size: var(--fs-input); line-height: 1.5; color: var(--text-1); padding: var(--sp-3) 84px var(--sp-3) var(--sp-3);
  /* 2026-10-19 站主：换行太早——右侧预留 102→84（贴着麦克风外缘 82 即可）；
     麦克风不在场（网页端/无语音）时再收到 46，长句能用到更多宽度 */
  min-height: 48px; max-height: 132px;
  opacity: 1; transition: opacity var(--d-fast) ease; animation: npgInkOpen var(--d-fast, var(--d-fast)) ease; }
.no-mic.npg-well textarea, .npg-well.no-mic textarea { padding-right: 46px; }
.npg-well textarea::placeholder { color: var(--text-4); }
/* 麦克风（按住说话）＋ 常驻那颗发送 ↑：都贴右下角（bottom 锚），换行长高时跟着往下。
   1011c：发送钮从 40 收到 34（站主真机「太大」），与麦克风同心（中心都在 27px 线上）。
   1012：再收到 28（站主第二轮还是点名大）。right/bottom 跟着从 10 抬到 13，
   两笔一起算才保住那条 27px 中心线（13+14=27）——只改尺寸不改锚位，钮会往下歪。 */
 .npg-mic { position: absolute; right: 50px; bottom: 8px; width: 32px; height: 32px; border: none;
  border-radius: var(--r-circle); background: transparent; color: var(--text-4); display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: opacity var(--d-fast) ease var(--d-micro); animation: npgInkOpen var(--d-base) ease var(--d-micro) both; }
.npg-mic::after { content: ""; position: absolute; inset: -6px; }
.npg-mic svg { width: 18px; height: 18px; }
.npg-mic.is-on { background: var(--primary); color: var(--on-primary); }
.npg-mic.is-cancel { background: var(--bg-card); color: var(--text-3); box-shadow: 0 0 0 1px var(--border); }
 .npg-send { position: absolute; right: 13px; bottom: 10px; width: 28px; height: 28px; padding: 0; border: none;
  border-radius: var(--r-circle); background: var(--primary); color: var(--on-primary); cursor: pointer;
  display: flex; align-items: center; justify-content: center; box-shadow: var(--shadow-card);
  transition: opacity var(--d-fast) ease var(--d-micro); animation: npgInkOpen var(--d-toast) ease; } /* 无 fill：结束后 opacity 交回 .is-off/base 规则，绝不假启用 */
.npg-send svg { width: 14px; height: 14px; }
.npg-send:active { opacity: .86; }
.npg-send.is-off { opacity: .35; pointer-events: none; }
/* 悬浮位只在 DOM 里待着（render / setSlot 认它），这一屏不出脸 */
.npg-bar .nl-ai-slot, .npg-bar #f-nl-foot { display: none; }
/* 提示条：一条轨道两个用途——说「该点哪」，或说「认到了什么」。
   1012：空态那句引导语删掉之后这一条平时是闭嘴的，只剩语音/额度那几句偶尔开口，
   所以它的开合改走 height 滑行（原来 [hidden] 是 display:none，
   出现与消失各把底排瞬推 20px —— 0930 抽屉那条「:empty 硬跳」的同族）。
   [hidden] 这里刻意留块不摘：display:none 没有可插值的起点。 */
.npg-lane { flex: none; padding: 0 var(--sp-4) 2px; height: 20px; line-height: 18px; overflow: hidden;
  font-size: var(--fs-micro); color: var(--text-4); font-variant-numeric: tabular-nums;
  transition: height var(--d-base) linear, opacity var(--d-fast) ease; }
.npg-lane[hidden] { display: block; height: 0; opacity: 0; }
.npg-lane.q-pulse { animation: fadeSoft var(--d-base) ease; }

@media (prefers-reduced-motion: reduce) {
  .nl-page { animation: none; transition: none; }
  /* 退场也要听话：不给位移，直接淡掉（.is-out 特异度比 .nl-page 高，单独压一条） */
  .nl-page.is-out { animation: none; opacity: 0; }
  .npg-msg, .npg-ans, .npg-ans .np-rev { animation: none; }
  .npg-pills, .npg-lane, .npg-well, .npg-well textarea { transition: none; }
  /* 降频偏好下入场动画直接落终态：井/输入/麦克风/发送全部瞬间到展开可见，不留淡入半帧 */
  .npg-well, .npg-well textarea, .npg-mic, .npg-send { animation: none; }
}

/* ============================================================
   记忆板块（2.50 M1 · 原「纪念日」视图原地升级，五档）
   ------------------------------------------------------------
   圆角按 V2「元素自身尺寸」走档：卡面 12（--radius-card-m，与备忘/纪念卡同档）、
   chip 8（r-2，chip 族定稿档）、hero 20（r-5，详情英雄区沿用 dd-hero 不另开）。
   热区一律 ≥38px（手机端）；色点只当身份标，不假装是头像。
   动效只动 transform/opacity，凸块滑动交还给 .seg.seg-slide 自己那一条。
   ============================================================ */
.mem-seg { display: flex; width: 100%; margin-bottom: var(--module-gap); }
.mem-pane { min-height: 120px; }
/* 记忆切档时事件档的二级分类工具条靠 [hidden]（display:none↔flex）硬显隐，读起来是「啪」地出现。
   元素从 none→显示会自动重播 CSS 动画，故复用站内 fadeSoft 给它补一段淡入（曲线/时长走整站入场档）。
   列表那侧由 renderMemory 传 animate=true 走 .list-cascade 逐行入场，两者合起来＝完整过渡。
   降级：reduce 下不淡入，配合 staggerList 的 reduce 判定一起静默到位。 */
@media (prefers-reduced-motion: no-preference) {
  #view-date #memToolbar { animation: fadeSoft var(--d-toast) var(--ease-enter); }
}
.mem-grp { margin: var(--module-gap) 2px var(--sp-2); font-size: var(--fs-label); font-weight: var(--fw-semibold);
  letter-spacing: .06em; color: var(--text-hint); }
.mem-grp:first-child { margin-top: 0; }
.mem-hint { margin: var(--sp-1) 2px; font-size: var(--fs-micro); color: var(--text-hint); }
.mem-foot-note { margin: var(--sp-4) 2px 0; font-size: var(--fs-micro); line-height: 1.7; color: var(--text-hint); }

/* 人物卡：**外壳整个复用站内 .memo-card**（它本来就是一条备忘），bg/描边/圆角/内衬/
   阴影/transition/hover/cursor 一行都不再抄——闸门把第 7 份卡片 hover 直接判成逐字重复，
   正确解法不是抬钉，是别另创第二套外壳（站规「新控件与整块载体一律复用站内既有外壳」）。
   列表容器同理用现成的 .card-grid（备忘在用），所以手机端单列、桌面自动多列，与备忘一致。 */
/* 顶行直接用现成的 .memo-head（备忘卡在用），这里不再抄一份 flex —— 抄了就是第 N 份 */
.mp-dot { flex: none; width: 42px; height: 42px; border-radius: var(--r-circle); display: grid; place-items:center;
  color: var(--on-primary); font-size: var(--fs-h2); font-weight: var(--fw-bold); }
.mp-dot.sm { width: 30px; height: 30px; font-size: var(--fs-body); }
/* emoji 头像：字形本身带色，别再套白字/粗体那套首字母排版——只保留彩色底框。
   按底框尺寸给 emoji 留足字号，`.sm`（今天投影那排）同步缩一档。 */
.mp-dot.is-emoji { color: inherit; font-weight: var(--fw-regular); font-size: calc(22px * var(--fs-scale)); line-height: 1; }
.mp-dot.sm.is-emoji { font-size: calc(16px * var(--fs-scale)); }
/* 人物详情页 hero 顶部那枚头像：与列表同款底框，下方留一点气口再排关系胶囊。 */
/* 人物详情页头像行：emoji 底框在左、名字+关系胶囊叠在右侧（站主：名字挪到头像右侧）。
   与列表卡 .mp-dot / .mp-h 同一套横向身份排法。名字去掉它原来单列时的上边距，
   胶囊跟在名字下方留一点气口。 */
/* 站主：头像与名字应读作「同一行」，关系 + 年龄作第二行。整块文字垂直居中会把头像
   顶到两行之间（头像看起来既不在名字行也不在关系行）。改成顶部对齐——头像与名字那行齐头，
   关系/年龄自然落到它下方第二行。 */
.dd-hero-id { display: flex; align-items: flex-start; gap: var(--sp-3); }
.dd-hero-id .dd-av { flex: none; }
.dd-hero-idtxt { flex: 1; min-width: 0; }
.dd-hero-idtxt .dd-hero-name { margin-top: 0; }
.dd-hero-idtxt .dd-hero-head { margin-top: var(--sp-1); }
/* 站主：农历 / 每年 / 至今这一行不要换行，可把右侧「下次生日」缩小。整行禁换行、
   各段禁内部断行（shrink:0），并把右列倒计时整块收窄（巨型数字降一档、标题贴紧、间距收紧），
   给左列腾出放得下这一行的宽度。 */
.dd-hero.is-person { gap: var(--sp-2); }
.dd-hero.is-person .dd-hero-main .dd-meta { flex-wrap: nowrap; gap: var(--sp-1); font-size: calc(12px * var(--fs-scale)); }
.dd-hero.is-person .dd-hero-main .dd-meta > * { flex-shrink: 0; white-space: nowrap; }
/* 站主：右侧「下次生日」天数再稍微大一些（30→40）。左列「农历/每年/至今」仍禁换行；
   实测大字号 + 5 位数天数时左列仍放得下（见探针），若换行就回退一档。 */
.dd-hero.is-person .dd-hero-count { flex-shrink: 0; margin-left: 0; }
.dd-hero.is-person .dd-hero-count .dd-cap { margin-top: 0; }
.dd-hero.is-person .dd-hero-count .dd-num { font-size: calc(40px * var(--fs-scale)); letter-spacing: -1px; }
.dd-hero.is-person .dd-hero-count .dd-num-today { font-size: calc(30px * var(--fs-scale)); }
/* 编辑人物页的头像选择器：一枚 emoji 一个可点格子；默认档用虚线圈与实色档区分开
   （同「自动上色」那套语言），选中仍让位给主色环。 */
.p-avatars .av-pick { width: 34px; height: 34px; font-size: calc(20px * var(--fs-scale)); line-height: 1;
  display: inline-flex; align-items: center; justify-content: center; background: var(--bg-count); }
.p-avatars .av-pick-default { background: var(--bg-page); box-shadow: inset 0 0 0 1px var(--border); }
/* 插画头像（2.85）：avatar 存成 il-m-xx / il-f-xx 时，底框塞一枚 assets/avatars 下的 PNG。
   底色仍吃调用点传进来的 personDotColor（inline style）——和 emoji 一样「色圈 + 内容」，
   图片 contain 居中、四周留出色圈；mp-dot 本就是圆角（--r-circle），图片被 overflow 收进圆内。 */
.mp-dot.is-illus { overflow: hidden; }
/* 圆内头像铺满（cover）：contain 会把插画缩成一团、四周空一大圈色底，站主实拍「内边距不对」。
   偏上取像（center 22%）——头与上身居中、多余肩膀被圆裁掉，和照片头像同一裁法。 */
.mp-dot .mp-av-img { width: 100%; height: 100%; object-fit: cover; object-position: center 22%; display: block; pointer-events: none; }
/* 弹层里男生 / 女生两组插画缩略图：与 emoji 同款圆角方块 + 中性底，缩略图 contain 放进去；
   选中环沿用 .cat-swatch.is-sel（.p-avatars 那排 emoji 复用同一尺寸规则，见下方 .p-avatars .av-pick）。 */
.p-avatars-il { flex: 1; min-width: 0; gap: var(--sp-1); }
.p-avatars-il .av-pick { width: 34px; height: 34px; overflow: hidden; background: var(--bg-count);
  display: inline-flex; align-items: center; justify-content: center; }
.p-avatars-il .av-pick img { width: 92%; height: 92%; object-fit: contain; display: block; pointer-events: none; }

.mp-h { flex: 1; min-width: 0; }
.mp-n { margin: 0; font-size: var(--fs-h3); font-weight: var(--fw-semibold); line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mp-r { margin: 3px 0 0; font-size: var(--fs-caption); color: var(--text-4); }
.mp-cd { flex: none; margin-left: auto; text-align: right; }
.mp-cd-l { display: block; font-size: var(--fs-micro); color: var(--text-hint); letter-spacing: .04em; }
.mp-cd-n { font-family: var(--font-mono); font-size: var(--fs-num-sm); font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums; letter-spacing: -.5px; }
.mp-cd-u { font-style: normal; font-size: var(--fs-micro); color: var(--text-4); margin-left: 2px; }
/* 与 .mp-last 同一条规矩（见下 8168）：外壳 .memo-card 已是 flex column + gap，
   这里再加 margin-top 会叠成空洞（站主实拍：关系/年龄行与口味徽章之间空白太大）。
   归零，交给卡片自己的 flex gap 给节奏。 */
.mp-chips { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.mp-chip { font-size: var(--fs-micro); color: var(--text-3); background: var(--bg-muted);
  border-radius: var(--r-2); padding: 3px var(--sp-2); }
/* 兴趣徽章单独一行：不叫 .dd-row（那条线长在行顶，会贴到徽章底下）；左 48 与标题齐。 */
.dd-chips { padding: 0 var(--sp-4) var(--sp-3) var(--sp-12); margin-top: -6px; }
/* ---- 1029 人物「时间线」重排版（站主令）----
   原来一行是「内容井 + 156px 带框日期 + 删除」，两个控件并排抢宽，日期把半行吃掉了
   （156 是当年量出来的：钮内衬 14+40，「2025-10-08」最大字号要 95px——那把尺子今天作废）。
   新版式两拍：上拍＝日期胶囊靠左、删除靠右；下拍＝内容本身吃满整行。
   新增行搬到列表上面（新条目本来倒序插最前），并自带一枚日期（默认今天，点一下换），
   补记一件上周的事当场就能定日子，不用先加进列表再去那一行改。
   ⚠ 命名：这一批一律带 .ptl- 前缀。曾经直接叫 .tl-main / .tl-meta，撞上了概览「今天」
   时间线（5624/5626 那两条）在用的同名类——两条 (0,1,0) 的规则后者覆盖前者，
   于是概览那侧的 .tl-main 被塞进 align-items:center + gap:8px、.tl-meta 被塞进
   space-between，隔壁组件当场被改脸（探针 cdp-1029-timeline-check ⑨ 段钉住这条）。
   ⚠ 特异性：手机端 4650-4700 那段「卡内井 / 无框子任务行」是 (0,3,0) 的媒体块规则，
   这里凡与它交手的都带上 .fg-card + 容器类抬到 (0,3,0)~(0,4,0) 并排在它之后——
   只写 `.ptl-row .dp-display`（0,2,0）会被压回 46px 带框井（实测撞过：胶囊 144×46、行没拆开）。
   行与行的发丝线：手机端白拿上面那条 border-bottom，桌面端才补一条 border-top（见本段末尾）。
   enhanceDates 仍负责把 input[type=date] 包成 .date-wrap + .dp-display（点开站内滚轮/日历），
   这里只换它的长相与位置——数据层与选择器一只都不动。 */
.ptl-row { display: block; padding: var(--sp-3) 0; border: none; border-radius: 0; background: none; }
.ptl-meta { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.ptl-main { display: flex; flex-direction: row; align-items: center; gap: var(--sp-2); margin-top: var(--sp-1); }
.ptl-row .sub-name { font-size: var(--fs-body); min-height: 22px; }   /* 桌面档；手机端 16px 地板由上面那条给 */
.fg-card .sub-editor .ptl-row { display: block; min-height: 0; padding: var(--sp-3) 0; }
.fg-card .sub-editor .ptl-row .date-wrap, .fg-card .fg-stack .ptl-add .date-wrap { flex: none; width: auto; }
/* 日期胶囊：小、等宽、灰底圆药，不带日历小图标（整枚可点）。它是「这条的日期」，
   不是一栏输入框，所以从 .dp-display 那套 46px 带框井形态里单独摘出来。 */
.fg-card .sub-editor .ptl-row .dp-display,
.fg-card .fg-stack .ptl-add .dp-display {
  width: auto; height: 28px; line-height: 26px; padding: 0 var(--sp-3);
  border: none; border-radius: var(--r-pill); background: var(--bg-muted); color: var(--text-3);
  font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--fs-11);
}
.fg-card .sub-editor .ptl-row .date-ico, .fg-card .fg-stack .ptl-add .date-ico { display: none; }
/* 新增行：日期在上、输入 + ＋ 在下（与下面每一条同一个骨架）。
   .sub-add 那 46px 井与 40px 钮照白拿，这里只把横排拆成两拍。 */
.fg-card .fg-stack .ptl-add { display: block; gap: 0; margin-top: 0; }
.fg-card .fg-stack .ptl-add .ptl-main { margin-top: var(--sp-2); }
/* 桌面端没有那条 border-bottom 的发丝线壳，补一行上边线分组（手机端不补，免得双线） */
@media (min-width: 769px) { .ptl-row + .ptl-row { border-top: 1px solid var(--border); } }
/* 折叠起来的那部分：只过渡 height/opacity；曲线 --ease-float（--ease-enter 前突，会读成弹一下）。 */
.tl-rest { overflow: hidden; height: 0; opacity: 0; transition: height var(--d-toast) var(--ease-float), opacity var(--d-base) linear; }
/* 外壳 .memo-card 是 flex column + gap:var(--sp-3)，这里再加 margin-top 会叠成空洞
   （实拍抓到「口味偏好」那张没有 chips 时中间悬一条分隔线）——所以只留描边 + 极小 padding。
   站主实拍：标签行与「最近动静」之间太空。gap 已给 12px 节奏，padding-top 再从 sp-3 收到 sp-1，
   只让描边与文字之间留 4px 呼吸，总间距从 24px 降到 16px。 */
.mp-last { padding-top: var(--sp-1); border-top: 1px solid var(--border);
  font-size: var(--fs-micro); color: var(--text-hint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 时间线：行卡挂白底外壳（与同页 .mem-re 一套：bg-card + radius-card-m + shadow-card，
   不加 border 以免把 ::before 圆点的 left 计算顶偏 1px），这里再补"从轴线上伸出一个小圆点"。
   上下内衬收 sp-2（12 太厚把首行文字顶离圆点）、卡间距放 sp-3；事件圆点 top:50% + translateY(-50%)
   在整张卡上上下居中（卡高随行数变，故不用定值）。年份小标题 .mt-y 也在轴上落一颗点，与年份数字
   上下居中（行盒 40px、中线 20px → 点 top 15.5px＝中线减半点高 4.5px）。 */
.mt-y { position: relative; margin: var(--module-gap) 0 var(--sp-2); font-family: var(--font-mono); font-size: var(--fs-num-sm);
  font-weight: var(--fw-bold); letter-spacing: -.5px; font-variant-numeric: tabular-nums; }
.mt-y:first-child { margin-top: 0; }
.mt-y::before { content: ""; position: absolute; left: calc(-1 * var(--sp-6) + 1px); top: 15.5px;
  width: 9px; height: 9px; border-radius: var(--r-circle); background: var(--bg-card); border: 2px solid var(--text-1); }
.mem-tl { position: relative; padding-left: var(--sp-6); }
.mem-tl::before { content: ""; position: absolute; left: 5px; top: 8px; bottom: 8px; width: 1px; background: var(--border); }
.mt-row { position: relative; padding: var(--sp-2) var(--sp-4); margin-bottom: var(--sp-3);
  background: var(--bg-card); border-radius: var(--radius-card-m); box-shadow: var(--shadow-card); }
.mt-row:last-child { margin-bottom: 0; }
.mt-row::before { content: ""; position: absolute; left: calc(-1 * var(--sp-6) + 1px); top: 13.1px;
  width: 9px; height: 9px; border-radius: var(--r-circle); background: var(--bg-card); border: 2px solid var(--text-1); }
/* 实心点＝人物（"这是一个人"），空心点＝事件。描边与填充同色才是一颗干净的实心点 */
.mt-row.is-p::before { border-color: var(--text-1); background: var(--text-1); }
/* 首行日期＝"小标题"，与左侧圆点上下对齐。把它做成定高块（display:block + nowrap），块高＝字号×行高
   （strut，与字形无关）——否则数字用 JetBrains Mono、"每年"回落系统 CJK，真机与探针行盒不同、
   圆点就会看着"贴顶"。块高实测 19.2px → 中线 8 + 9.6 = 17.6px → 圆点 top = 17.6 − 半点高 4.5 = 13.1px。 */
.mt-row em { display: block; line-height: 1.6; white-space: nowrap; font-style: normal;
  font-family: var(--font-mono); font-size: var(--fs-micro); color: var(--text-hint); letter-spacing: .03em; }
.mt-row div { margin-top: 2px; font-size: var(--fs-body); font-weight: var(--fw-semibold); }
.mt-row p { margin: var(--sp-1) 0 0; font-size: var(--fs-micro); color: var(--text-4); }

/* 今天 */
.mem-re { background: var(--bg-card); border-radius: var(--r-5); box-shadow: var(--shadow-card);
  padding: var(--sp-6) var(--sp-6) var(--sp-4); margin-bottom: var(--card-gap); cursor: pointer; }
.mr-n { font-family: var(--font-mono); font-size: var(--fs-num-lg); font-weight: var(--fw-bold);
  line-height: 1.05; letter-spacing: -1px; font-variant-numeric: tabular-nums; }
.mr-n i { font-style: normal; font-family: var(--font-sans); font-size: var(--fs-label);
  font-weight: var(--fw-regular); color: var(--text-4); margin-left: var(--sp-1); letter-spacing: 0; }
.mr-t { margin-top: var(--sp-2); font-size: var(--fs-h3); font-weight: var(--fw-semibold); line-height: 1.4; }
.mr-d { margin: var(--sp-1) 0 0; font-size: var(--fs-micro); color: var(--text-hint); }
.mem-soon { display: flex; align-items: center; gap: var(--sp-3); background: var(--bg-card);
  border-radius: var(--radius-card-m); box-shadow: var(--shadow-card); padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-2); cursor: pointer; min-height: 38px; }
.ms-t { flex: 1; min-width: 0; font-size: var(--fs-body); font-weight: var(--fw-medium);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ms-d { flex: none; font-family: var(--font-mono); font-size: var(--fs-caption); color: var(--text-4);
  font-variant-numeric: tabular-nums; }

/* 新建人物：虚线空位，一眼看出是「往这儿填」而不是某个人（实心在这个板块里已经有含义 = 一条真记忆）。
   ＋号的点色与图标尺寸**不在这开规则**：两声明的小块分别撞进站内既有的「图标尺寸族」和一条同声明组合，
   闸门各记一组重复。点色本来随人名内联下发（见 rowPerson），这里同样内联，反而与人物点一条路子。 */
.mem-add { background: transparent; border: 1px dashed var(--border-strong); box-shadow: none; }
@media (hover: hover) { .mem-add:hover { background: var(--bg-hover); border-color: var(--text-4); transform: none; box-shadow: none; } }

/* 空态与人物页 */
.mem-empty { padding: var(--sp-8) var(--sp-4); text-align: center; font-size: var(--fs-caption);
  line-height: 1.85; color: var(--text-hint); }
.mem-empty b { display: block; margin-bottom: var(--sp-1); font-size: var(--fs-body); font-weight: var(--fw-semibold); color: var(--text-3); }
.mem-empty.sm { padding: var(--sp-6) var(--sp-4); text-align: left; }

/* ≤768 手机端样式 → 06-mobile.css */
@media (prefers-reduced-motion: reduce) {
  .mem-soon, .mem-re { transition: none; }
}

/* ============================================================
   一级页「第一行」统一 · 工具带（档2，1017 站主定）
   站主反馈切一级页时四页第一个元素视觉割裂。只读盘点后修正定性——
   顶栏→首行间距与左右内缩本已共用 .content 令牌（手机 16/16）、首行→内容
   下间距也早已统一成 card-gap(12)；真正各写一套的是：①首行的「容器语言」
   （首页独立白卡 / 待办灰槽 / 备忘裸标签 / 账本各自带阴影的小白卡）
   ②选中态（白凸块滑动 / 描边 / 黑胶囊）③只有首页首行有专属逐格揭示、
   别页首行光秃秃跟整页入场。本段只做表现层，作用域锁死这四页（id 前缀），
   不改 .toolbar/.seg/.chip/.st-head 多页共用件的全局定义，也不碰 switchView
   的推/半途动画。全部复用现成 token，暗色靠 --primary/--on-primary/--bg-card
   自动翻档。整段删除即回退。
   ------------------------------------------------------------
   A  待办/备忘/账本首行装上与首页 hero 同规格的白卡「工具带」。
   A' 拆卡套卡：账本时间标签/翻页钮自带小白卡，在带里改透明、去边去影。
   C  选中态统一黑底反白（装进白卡后白凸块看不见，必须换黑；滑动跟手保留）。
   B  收掉首页首行逐格揭示，四页首行统一只随整页 pageUpIn 一起淡入上移。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   一级页「第一行」统一 · 统计页并入（1017，站主令先只改统计）
   统计首行 .st-head 与账本同款壳：装同一张白卡带、拆掉里面的小白卡
   （时间标签 / 翻页钮自带 bg-card+边+影）。粒度那排是老式 .seg
   （button.active 本就黑底反白），已合「小面积黑强调」，故选中态不动。
   整段删除即回退；只加 #view-stats 作用域，不碰任何共用件的全局定义。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* 统计粒度挂上 seg-slide（改在 index.php + app.js）后，滑块外观与账本完全一致：
   灰槽里的滑动块改黑底、选中标签反白。并同步需求：账本 + 统计把「日/周/月/年」
   与「切换年月」上下对调（粒度在上、年月在下）。纯追加、只认这两页作用域。 */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   1017 需求①② · 待办滑块对齐账本 + 账本周/年布局参考统计（纯追加，只认作用域）
   ------------------------------------------------------------
   ① 待办 #todoSeg 与账本 #lgSeg 本是同一 .seg.seg-slide，唯一残差是站主 1014
      点名把待办按钮高度从 --control-h(手机44) 收到 38——矮一格，滑块凸块像
      浮着的「把手」。这里让待办回到与账本同高的 --control-h，两只彻底一致。
   ② 账本年视图「上下间隙太大」两处根因：.lg-day/.lg-mo 是 1/1 正方（4 列被撑很高）
      + 汇总卡→支出日历标题之间吃 .lg-grp 的 module-gap(20)。参考统计口径：
      格改矮（去正方、min-height 同统计 .st-cell）、组标题上距收到 card-gap(12)。
      整段删除即回退；色阶（需求③）另在 01-tokens.css 把 --lgd 引用 --stg 完成。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   1017 补 · 待办分段器通栏（对齐账本 .lg-seg 口径，纯追加）
   ------------------------------------------------------------
   分段器基础 .seg.seg-slide 是 display:inline-flex → 按内容自撑、居中收缩，
   待办左右两侧就空出一大片。账本靠 .lg-seg{display:flex;width:100%} 撑满；
   待办原来只有 flex:1 1 100%（作为 flex 子项的意图），没覆盖自身 display，
   故没铺满。这里补同款：#todoSeg 的 id 特异性压得住基础 inline-flex，
   内部三按钮自带 flex:1，容器一撑即等分通栏，与账本完全一致。整段删除即回退。
   ============================================================ */
 /* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   1017 补② · 待办工具带左右内距对齐账本（纯追加，只认 #view-todo）
   ------------------------------------------------------------
   上面统一块里整组（待办/备忘/账本）白卡是 padding: var(--sp-2) var(--sp-3)，
   但账本随后被单列覆盖成 padding: var(--sp-2)（左右 8）。待办没被覆盖，
   左右仍是 --sp-3(12) → 分段器两侧各比账本多 4px 空白（站主红框所指）。
   这里只把待办的左右内距收到 --sp-2，与账本那只卡片完全等宽；上下不动、
   不碰备忘。整段删除即回退。
   ============================================================ */
/* ≤768 手机端样式 → 06-mobile.css */

/* 1018 用户管理列表那一排角色胶囊改等宽、并收窄。原自然宽实测 Ultra=72 / Max=66 / Pro=62 / Free=51，
   右对齐时左缘参差；先按 72 等宽又嫌胖。min-width 压不动最宽的 Ultra，故从内容侧收：
   两侧内距 --sp-3(12) 收到 --sp-2(8)（现成间距档，不破 spacing），Ultra 降到 64、余三枚更窄，
   min-width 取新的最宽 Ultra=64 → 四枚全等宽 64、左缘成一条线。徽记与 gap 不动，不显挤。
   纯追加、不改写上方 .u-role-pill 原块：同特异性后者胜，只对手机端可点胶囊这一族生效。 */
.u-role-pill.role-badge { padding: 0 var(--sp-2); min-width: 64px; justify-content: center; height: 30px; }

/* 1018 站主续2：用户管理列表那排胶囊比别处要更鼓一点（24 显矮），单独回抬到 30；
   普通 .role-badge（详情/账户卡/顶栏）保持手机端 24，两族不再强求等高——站主本轮点名「管理页更高」。 */
/* ≤768 手机端样式 → 06-mobile.css */

/* 1018 站主续：上一步只把圆角改圆，但手机端普通角色徽章高度仍是「地板档 20」，
   与用户管理列表那排 .u-role-pill（30 高胶囊）比还是扁一截——站主截图「扁」即此 10px 落差。
   这里把手机端 .role-badge 高度抬到 30 与列表胶囊齐平；字号(fs-12)、左右内距(sp-2)两档本已一致，只补高度。
   刻意不给 min-width：详情行/账户卡/顶栏那枚都是单出现、无需等宽，宽 64 会撑破窄顶栏。
   纯追加覆盖中段那条 height:20（同在 ≤768、同特异性，靠后者胜），不改写原块、不碰 .u-role-pill。 */
/* ≤768 手机端样式 → 06-mobile.css */

/* 1018 站主实拍：副行 nowrap+省略号会把跟在日期后的「今用/余」截没（长账号连额度都轮不到），
   手机端把额度单起一行 .u-cap-line，永不被截、也更醒目。该 div 只在 coarse(手机)分支渲染，
   桌面不产出此元素（桌面副行无 nowrap，额度并进行内 u-cap-note），故无需媒体查询。 */
.u-cap-line { margin-top: 2px; font-size: var(--fs-micro); color: var(--text-3); line-height: 1.4; }

/* ============================================================
   2.89 今日全部完成 · 小庆祝（klog-celebrate-preview.html 定稿落地）
   彩带层（压在灵动岛 z9999 之下、遮罩 9500 之上 → 岛盖住喷口，粒子从背后涌出）
   + 灵动岛庆祝变体（前位四角星芒替绿点，其余岛语言一分不动）。纯追加，不改写上方岛原块。
   ============================================================ */
#klog-confetti { position: fixed; inset: 0; z-index: 9990; pointer-events: none; display: block; }
/* ≤768 手机端样式 → 06-mobile.css */

/* 可序AI · 档案卡「统一回复模板」样式已**收进中段 .npq-b* 块**（对齐 dev/previews/klog-npg-rich-preview.html：
   去卡中卡灰底、头像52、姓名/关系上下、字段一行一值、底部浅灰描边胶囊）。
   上一版误在文件末尾再追加一份 npq-b* 覆盖，导致「中段一份 + 末尾一份」打架——当末尾那份未被加载/缓存时
   就退化成中段旧值（灰底、小头像、无可见按钮）。现全部终态只留中段一处，此处不再重复定义。 */

/* ============================================================
   可序AI · 结构化卡片（2026-10-19 P1）：问线回包里清洗后的 table / accordion，
   渲染在 .npg-ans 气泡内（nlStructHtml 产）。含卡片的气泡撑成满宽白卡（对齐数字名片 .npf），
   纯文字气泡不受影响；模型没给合法结构 → 不产出 .nstruct，气泡保持贴合、零副作用。全走 token，暗档安全。 */
.npg-ans:has(.nstruct){ width:100%; max-width:100%; background:var(--bg-card); border:0; border-radius:var(--r-5);
  padding:var(--sp-4); box-shadow:0 2px 14px rgba(17,17,17,.07); }
.nstruct{ margin-top:var(--sp-3); }
.nstruct-tblwrap{ border:1px solid var(--border); border-radius:var(--r-3); overflow:hidden; }
.nstruct-tbl{ width:100%; border-collapse:collapse; font-size:var(--fs-caption); }
.nstruct-tbl th{ background:var(--bg-muted); color:var(--text-3); font-weight:700; text-align:left; padding: var(--sp-2); font-size:var(--fs-micro); }
.nstruct-tbl td{ padding: var(--sp-2); color:var(--text-1); border-top:1px solid var(--border); vertical-align:top; line-height:1.45; overflow-wrap:anywhere; }
.nstruct-tbl td.tc0{ font-weight:600; }
.nstruct-acc{ border:1px solid var(--border); border-radius:var(--r-3); overflow:hidden; }
.nstruct-acc-i + .nstruct-acc-i{ border-top:1px solid var(--border); }
.nstruct-acc-h{ display:flex; align-items:center; gap:var(--sp-2); width:100%; text-align:left; background:var(--bg-card);
  border:0; padding: var(--sp-3); font-family:inherit; font-size:var(--fs-caption); font-weight:600; color:var(--text-1); cursor:pointer; }
.nstruct-chev{ margin-left:auto; flex:none; width:16px; height:16px; color:var(--text-4); transition:transform var(--d-base) ease; }
.nstruct-acc-i.is-open .nstruct-chev{ transform:rotate(90deg); }
.nstruct-acc-b{ max-height:0; overflow:hidden; transition:max-height var(--d-modal) ease; }
.nstruct-acc-i.is-open .nstruct-acc-b{ max-height:320px; }
.nstruct-acc-a{ padding:0 var(--sp-3) var(--sp-3); font-size:var(--fs-label); color:var(--text-3); line-height:1.6; overflow-wrap:anywhere; }

/* ============================================================
   可序AI · 本地数据查询卡 v2（2026-10-19 站主点名）：账本/习惯/日程三类
   由 nlQueryCardHtml 渲染成满宽卡片（.nqk-card），含卡气泡 :has 撑满宽，
   与数字名片 .npf、结构化 nstruct 同一外壳语言。靠留白分行、无行间线、全 token、暗档安全。 */
.npg-ans:has(.nqk-card){ width:100%; max-width:100%; background:var(--bg-card); border:0; border-radius:var(--r-5);
  padding:var(--sp-4); box-shadow:0 2px 14px rgba(17,17,17,.07); }
.nqk-total{ font-size:calc(18px * var(--fs-scale)); font-weight:var(--fw-bold); color:var(--text-1); }
.nqk-total-in{ font-size:var(--fs-12); font-weight:var(--fw-medium); color:var(--text-4); margin-left:var(--sp-2); }
.nqk-cats{ margin-top:var(--sp-2); }
.nqk-cat{ padding:var(--sp-2) 0; cursor:pointer; }
.nqk-cat:active{ opacity:.6; }
.nqk-catline{ display:flex; align-items:baseline; justify-content:space-between; gap:var(--sp-3); }
.nqk-name{ font-size:var(--fs-caption); color:var(--text-1); font-weight:600; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.nqk-amt{ font-family:var(--font-mono); font-size:var(--fs-caption); color:var(--text-2); white-space:nowrap; flex:none; }
.nqk-track{ height:6px; border-radius:var(--r-pill); background:var(--bg-count); overflow:hidden; margin:var(--sp-1) 0 var(--sp-1); }
.nqk-track i{ display:block; height:100%; border-radius:var(--r-pill); background:var(--primary); }
.nqk-meta{ font-size:var(--fs-micro); color:var(--text-4); }
.nqk-sec{ margin-top:var(--sp-3); }
.nqk-sec-h{ font-size:var(--fs-micro); color:var(--text-4); margin-bottom:var(--sp-1); }
.nqk-row{ display:flex; align-items:baseline; justify-content:space-between; gap:var(--sp-3); padding:var(--sp-2) 0; cursor:pointer; }
.nqk-row:active{ opacity:.6; }
.nqk-row.is-muted{ opacity:.55; }
.nqk-side{ font-size:var(--fs-micro); color:var(--text-4); text-align:right; flex:none; max-width:60%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.nqk-amt2{ font-family:var(--font-mono); margin-left:var(--sp-2); color:var(--text-2); }
.nqk-hrow{ display:flex; align-items:baseline; justify-content:space-between; gap:var(--sp-3); padding:var(--sp-2) 0; cursor:pointer; }
.nqk-hrow:active{ opacity:.6; }
.nqk-hrow.is-done{ opacity:.5; }
.nqk-hm{ font-size:var(--fs-micro); color:var(--text-4); text-align:right; flex:none; }
.nqk-more{ margin-top:var(--sp-3); font-size:var(--fs-micro); color:var(--text-4); }

/* ================= 字重对齐层 · 2026-10-19 =================
   规则：页面大标题 700 / 卡片·条目名称 600 / 辅助标签·副标题·提示文字 400；
   500 保留给按钮·选中态·次级小标题。此层置于 05 末尾，只重声明"值要变"的选择器，
   靠后定义覆盖上方同名规则；不 in-place 改别处，避免与并发写冲突。回滚＝删本段。 */
/* 超档 800 → 700（无 --fw-800 令牌，且 mono 只加载到 700，800 会合成发虚）
   1025 收口：.acct-wizard .acct-hero h2 与 .cloud-login .cl-title 已在源头落 --fw-bold，此处两条删除；
   --fw-normal 幽灵已在源头修（2844/9168 改 --fw-regular，且 01 已收编 --fw-normal 别名），1025 治理层补丁退役 */
.rm-box-day b { font-weight: var(--fw-bold); }
/* 列表·时间线条目名称：从 500 升到 600，对齐卡片名称档 */
.tl-title, .ms-t { font-weight: var(--fw-semibold); }
/* 副标题·提示·辅助徽标：从 500 收到 400，与正文同级 */
.rm-box-empty p, .npg-ans .who, .nqk-total-in, .npf-rel { font-weight: var(--fw-regular); }

/* ---- 次级小标题统一 500（截图：设置/可序Ai 页行标题偏细） ----
   .pfg-t 基类原本无 font-weight → 无副标题的行(贡献录入语句/近7天合计/全部跳转行 pfItem)继承成常规，
   而带副标题的行走 .pfg-t-main=500，同页两种粗细。基类补 500 后，无 sub 行与 .pfg-t-main / .pfg-label 对齐。
   .pfg-t-sub(副文字)、.pfg-t-2 容器(纯排版)不受影响；.nt-sub>.pfg-t 是辅助子标签，下面回锁 400。 */
.pfg-t { font-weight: var(--fw-medium); }
.nt-sub > .pfg-t { font-weight: var(--fw-regular); }
/* 整站"次级小标题"同档：分组标签从 600 / 无 收拢到 500，与 .pfg-label .mk-hd 一致 */
.tl-group-l, .lg-day-hd > span:first-child, .nqk-sec-h, .npf-sec-h { font-weight: var(--fw-medium); }

/* ================= 小票机·悬浮切换控制卡 · 2026-10-20 =================
   标题栏右侧「切换」按钮 → 原地弹出悬浮卡：视图（小票机/小票盒）+ 票种（日志票/账本月票）。
   承接原 body 顶部 .rm-tabs 与机器内 .rm-mode 两处内联分段器（已从 app.js 移除）。
   纯追加自块，作用域限 .rm-switch-* / .rm-sw-*；不动 .modal-head-act / .seg / .seg-slide 共用基定义。
   回滚＝删本段 + 还原 app.js 两处删除。 */
/* 切换钮：桌面基类 .modal-head-act 继承为黑底（--primary），与手机端「白圆钮语言」不一致，
   站主反馈按下/开卡变黑。这里按手机端同款材质钉成白圆钮，:active 与开卡 is-active 都不压黑。
   作用域锁 .modal-card.rm-modal .rm-switch-btn，只改这一颗，不动详情页/编辑页其它头部圆钮。 */
.modal-card.rm-modal .rm-switch-btn.is-icon {
  background: var(--bg-card); color: var(--text-1);
  box-shadow: 0 4px 12px rgba(17, 17, 17, .08);
}
@media (hover: hover) { .modal-card.rm-modal .rm-switch-btn.is-icon:hover { color: var(--primary); } }
.modal-card.rm-modal .rm-switch-btn.is-icon:active {
  background: var(--bg-card); color: var(--text-1); transform: scale(.94);
}
.modal-card.rm-modal .rm-switch-btn.is-icon.is-active { /* 卡片开起：白底 + 主色图标 + 一圈淡描边，而非黑底 */
  background: var(--bg-card); color: var(--primary);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 42%, transparent), 0 4px 12px rgba(17, 17, 17, .08);
}

/* 悬浮卡不再铺遮罩层（遮罩会盖住标题栏返回/关闭钮并压暗背景）——点卡外收起改由 JS 捕获监听处理。 */

.rm-switch-pop {
  position: absolute; right: var(--sp-3); top: 64px; z-index: 8; /* top 由 JS 按标题栏钮实测下沿锚定覆盖 */
  min-width: 216px; max-width: calc(100% - var(--sp-4) * 2);
  padding: var(--sp-3);
  display: flex; flex-direction: column; gap: var(--sp-3);
  background: var(--bg-card);
  border: 1px solid var(--border); border-radius: var(--r-3);
  box-shadow: var(--shadow-modal);
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translateY(-6px) scale(.98); transform-origin: top right;
  transition: opacity var(--d-base) ease, transform var(--d-base) var(--ease-enter), visibility 0s linear var(--d-base);
}
.rm-switch-pop.is-open {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translateY(0) scale(1);
  transition: opacity var(--d-base) ease, transform var(--d-base) var(--ease-enter), visibility 0s;
}
.rm-sw-lbl { font-size: var(--fs-12); color: var(--text-3); margin-bottom: var(--sp-1); }
.rm-switch-pop .rm-sw-seg { display: flex; width: 100%; } /* 通栏等分：白凸块随 --seg-i 走位 */
/* 昵称行搬进悬浮卡后：去掉机身里的上外边距，收进卡片 gap 节奏；底色贴合卡片、只留淡描边作分组 */
.rm-switch-pop .rm-nick-row { margin-top: 0; padding: var(--sp-2); background: var(--bg-page); }
/* 票种组在小票盒视图下作筛选器用（不再禁用置灰）——is-dis 相关规则已移除。 */

@media (prefers-reduced-motion: reduce) {
  .rm-switch-pop, .rm-switch-pop.is-open { transition: none; }
}

/* ================= 动效规划 · S1 显隐离散过渡地基 · 2026-10-20 =================
   动机：站主反馈「卡片高度/显隐常常硬切」。全局 `[hidden]{display:none!important}`(05:995)
   是多数硬切的总根因——display 不可过渡，任何"消失"都瞬间蒸发，!important 还压死局部淡出。
   本段不重写那条全局规则（100+ 消费者风险高），只新增一只 opt-in 工具类 .fade-swap：
   谁想「淡入/淡出而非啪一下」就挂上它，靠 transition-behavior:allow-discrete + @starting-style
   让 display 参与过渡（出场等过渡结束再切 none，入场首帧取淡入起点）。站内 02:95 已用过同一招。
   作用域限 .fade-swap*，不动 [hidden] 基定义、不动 .seg/.dd-modal/.wp-sheet 等共用件。
   回滚＝删本段。 */
.fade-swap {
  transition:
    opacity var(--d-modal) var(--ease-enter),
    transform var(--d-modal) var(--ease-enter),
    display var(--d-modal) allow-discrete;
}
/* 出场：hidden 落下时 opacity→0 + 轻微下沉，display:none 由 allow-discrete 延到过渡末帧才生效 */
.fade-swap[hidden] {
  opacity: 0;
  transform: translateY(6px);
}
/* 入场：hidden 刚摘掉的首帧从淡入起点起，再过渡回常态（display 已由全局 !important 立即切到可见） */
@starting-style {
  .fade-swap:not([hidden]) {
    opacity: 0;
    transform: translateY(6px);
  }
}
/* 不支持 allow-discrete / @starting-style 的旧 WebView：display 仍瞬时切，fade 自动无副作用退化为现状硬切
   ——故本能力对老浏览器安全，不需再写 feature-query 分支。 */
@media (prefers-reduced-motion: reduce) {
  .fade-swap { transition: none; }
  .fade-swap[hidden] { transform: none; }
}
/* ==== 可序Ai · 顶栏对话右抽屉（2026-10-20 站主令：历史入口从「页内行+底锚抽屉」搬到顶栏右侧一枚钮） ==== */
/* 顶栏右侧「对话」钮：与左侧返回钮同材质（40 高幽灵 / r-3 / 按下 --bg-hover / 22px 内线性图标）。
   标题 .npg-head .wp-title 是 absolute 铺满整行但 pointer-events:none——钮相对定位抬到其上、margin-left:auto 可靠右。 */
.npg-head-act { position: relative; z-index: 1; flex: none; margin-left: auto;
  border: none; background: transparent; cursor: pointer;
  height: 40px; min-width: 44px; padding: 0 var(--sp-2);
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-3); color: var(--text-1); -webkit-tap-highlight-color: transparent; }
.npg-head-act svg { width: 21px; height: 21px; }
.npg-head-act:active { background: var(--bg-hover); }
/* 遮罩全屏淡入 + 面板从右滑入；z-index 压在二级页(.nl-page z8995)之上、与底锚抽屉同档。 */
.npg-rd-mask { position: fixed; inset: 0; z-index: 9010; background: rgba(15,17,20,.34);
  opacity: 0; transition: opacity var(--d-toast) ease; -webkit-tap-highlight-color: transparent; }
.npg-rd-mask.is-open { opacity: 1; }
.npg-rd { position: absolute; top: 0; right: 0; bottom: 0; width: min(84vw, 340px);
  display: flex; flex-direction: column; background: var(--bg-card);
  border-radius: var(--r-5) 0 0 var(--r-5); box-shadow: -10px 0 40px rgba(17,17,17,.14);
  padding: calc(var(--safe-top) + var(--sp-4)) var(--sp-4) calc(var(--sab) + var(--sp-3));
  transform: translateX(100%); transition: transform var(--d-push) cubic-bezier(.32,.72,.35,1); }
.npg-rd-mask.is-open .npg-rd { transform: translateX(0); }
.npg-rd-h { display: flex; align-items: center; min-height: 34px; margin-bottom: var(--sp-3); }
.npg-rd-t { font-size: var(--fs-body); font-weight: var(--fw-bold); color: var(--text-1); }
/* 抽屉头部右侧的齿轮已移除（2026-10-25）——设置入口搬到对话页顶栏助手名胶囊（见下方 .npg-title-cap）。
   关抽屉交给遮罩点击/侧滑返回/新开对话。 */
/* 上方「新开对话」＝主操作实心黑、圆角矩形(r-2)、图标+文字——与全站按钮语言一致（非整宽胶囊）。 */
.npg-rd-new { display: flex; align-items: center; justify-content: center; gap: var(--sp-1);
  height: 44px; margin-bottom: var(--sp-3); border: none; cursor: pointer;
  border-radius: var(--r-2); background: var(--primary); color: var(--on-primary);
  font-family: inherit; font-size: var(--fs-body); font-weight: var(--fw-medium);
  -webkit-tap-highlight-color: transparent; }
.npg-rd-new svg { width: 17px; height: 17px; }
.npg-rd-new:active { opacity: .86; }
/* 列表沿用 .tf-list/.tf-row/.npg-h-row（载入那段 + 长按删带撤销的 DOM 逻辑一并搬过来）；
   右抽屉里行不做描边卡，重设成透明整行、当前段浅底标记。 */
.npg-rd .npg-h-tip { padding-top: 0; }
.npg-rd-list { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch;
  display: flex; flex-direction: column; gap: 2px;
  max-height: none; margin-bottom: 0; } /* 共用壳 .tf-list 的 max-height:52vh 会把抽屉列表钉在半屏、底下空一片（站主红框）；抽屉里靠 flex:1 撑到脚栏，故复位上限与下边距 */
.npg-rd-list .npg-h-row { width: 100%; text-align: left; background: transparent; border: none;
  font-family: inherit; cursor: pointer; padding: var(--sp-2); border-radius: var(--r-2);
  -webkit-tap-highlight-color: transparent; }
.npg-rd-list .npg-h-row.is-live { background: var(--bg-muted); }
.npg-rd-list .npg-h-row:active { background: var(--bg-hover); }
@media (prefers-reduced-motion: reduce) {
  .npg-rd-mask { transition: none; }
  .npg-rd { transition: none; }
}

/* ================= 动效规划 · S2 v2 折叠行展开「保列长井」· 2026-10-20 =================
   展开只摘 .is-collapsed、保留 .fg-row（逻辑见 app.js flipHeight）：标题列不重排重着色，
   「描述」永远 16px/500/墨，不再被压成 fg-stack 的 12px 灰（那 2px 差＝站主的「字重变小」）。
   代价：textarea 落在 fg-row 会吃到行式的「无边框 / 54px / 右对齐」（05:3025），不成井。
   故展开态在这里把它单独还原成一只整行井——衬底 / 描边 / 圆角 / 左对齐 / 96 起高，
   观感与 fg-stack 井一致，走的是「不换列、只换控件外观」这条低风险路。仅 ≤768。
    选择器 (0,4,0) 压过行式默认 (0,3,0)，聚焦 / 占位同理。回滚＝删本段。
    v3 追补（2026-10-20 站主实拍）：折叠态靠 .fg-row min-height:54 + align-items:center 天然给
    标题上下各 19 呼吸；一展开内容超过 54 → 标题「啪」贴到卡片顶、井底「啪」贴到卡片底，
    读起来这块「从有归属掉到没归属」。展开态 field 补上下内衬，吃 fg-stack 同族规格
    （上 --sp-3 / 下 --sp-4）。标题↔井口维持 .fg-row 默认 row-gap=12、不额外补——
    站主指认「标题↔井口 24 间距是改错的」，v2 曾加的 margin-top:12 已回退。 */
/* ≤768 手机端样式 → 06-mobile.css */

/* ================= 动效规划 · S3 空态 ↔ 列表 接力过渡 · 2026-10-20 =================
   动机：renderTodos 的 empty.hidden / table.style.display 是瞬间互换——一整块表格「啪」
   蒸发、空态卡「啪」亮起，正是站主点名「卡片高度硬切」的另一处典型。
   改法（接力式，非重叠 crossfade，风险低）：只给「即将消失」的一方挂 .ws-exit（180ms 加速
   淡出 + 微下沉），演完再重跑 renderTodos 走同步分支切 display，此时给「新登场」的一方挂
   .ws-enter（220ms 从容淡入 + 上浮落位）；重入用 wsFlipTimers 收口。减动 / 首访 / 同侧内
   变化全部走同步。时长吃令牌：--d-fast(150≈180) / --d-modal(220)，缓动吃 --ease-float(退场
   加速) / --ease-enter(入场减速)。作用域限 .ws-exit / .ws-enter，不动 .list-cascade /
   .tbody-enter / .empty 基定义。回滚＝删本段 + 还原 renderTodos 里跨侧分支。 */
@keyframes wsExit  { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(6px); } }
@keyframes wsEnter { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.ws-exit  { animation: wsExit  var(--d-fast)  var(--ease-float) forwards; }
.ws-enter { animation: wsEnter var(--d-modal) var(--ease-enter) backwards; }
@media (prefers-reduced-motion: reduce) {
  .ws-exit, .ws-enter { animation: none; }
}
/* ================= 历史抽屉 · 底部操作栏 + 多选删除 · 2026-10-20 追加（2026-10-25 弱化） =================
   底部一行操作（非多选＝「清空 / 多选」；多选＝「全选 / 删除(N) / 完成」）。
   站主：别做成撑满等宽的描边块（跟顶部实心「新开对话」抢戏、不搭）→ 收成右对齐的小号文字钮，
   删除用主色文字轻点即可、不再实心块。列表 flex:1 撑到本栏上沿为止。 */
.npg-rd-foot { flex: none; display: flex; align-items: center; justify-content: flex-end; gap: var(--sp-4);
  margin-top: var(--sp-1); padding: var(--sp-1) 2px 0; }
.npg-rd-fbtn { flex: 0 0 auto; min-width: 0; height: 32px; padding: 0 var(--sp-1); border: none; border-radius: var(--r-2); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: inherit; font-size: var(--fs-label); font-weight: var(--fw-medium);
  background: transparent; color: var(--text-3);
  -webkit-tap-highlight-color: transparent; }
.npg-rd-fbtn:active { background: var(--bg-hover); color: var(--text-1); }
.npg-rd-fbtn[disabled] { opacity: .4; pointer-events: none; }
.npg-rd-foot .npg-rd-del { color: var(--primary); }   /* 多选态当下主操作：主色文字，非实心块 */
.npg-rd-foot .npg-rd-del[disabled] { color: var(--text-4); }
/* 复选框：非多选态藏、多选态露；选中填黑勾变白。整行随之从竖排改横排（复选框 + 标题栏）。 */
.npg-rd-list .npg-h-row { flex-direction: row; align-items: center; gap: var(--sp-2); }
.npg-h-check { display: none; flex: none; width: 20px; height: 20px; border-radius: var(--r-circle);
  border: 1.5px solid var(--border-strong); background: var(--bg-card); color: transparent;
  align-items: center; justify-content: center; }
.npg-h-check svg { width: 12px; height: 12px; }
.npg-h-body { display: flex; flex-direction: column; min-width: 0; gap: 3px; }
.npg-rd-list.is-manage .npg-h-check { display: inline-flex; }
.npg-rd-list .npg-h-row.is-sel { background: var(--bg-muted); }
.npg-rd-list .npg-h-row.is-sel .npg-h-check { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
/* 标题单行截断：整行转横排后，长标题不许挤成两行或撑破复选框对齐。 */
.npg-rd-list .npg-h-body .npg-h-t { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (prefers-reduced-motion: reduce) { .npg-rd-foot, .npg-rd-fbtn { transition: none; } }

/* ============================================================
   可序Ai「今日已用」额度卡（站主要参考版式：左对齐 · 低密度大留白 · 关键数字加粗 ·
   底部一枚浅灰胶囊模块内嵌黑色 pill 作唯一行动点）。壳仍是自建自摘的
   .wp-mask.nl-peek-mask + .nl-peek（不复用 .modal-card，避免上次的专属类泄漏污染二级页）。
   新增「升级 Pro」引导：只列站内坐实的真差异（每句走 AI 高频识别 + 个性化今日一句）——
   额度不随 Pro 变（全站默认+小灶，与角色无关），故绝不写「更多额度」这类假卖点。
   仅免费档显示引导块；Pro 及以上不推销、只留一行轻标。配色守纯墨灰，唯一强调是那枚黑 pill。
   所有类都带 ai-cap-* 或键在 .ai-cap-peek 下，绝不外溢到别的弹层。
   ============================================================ */
.ai-cap-hd { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5) 0; }
.ai-cap-kicker { flex: 1; min-width: 0; display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: var(--fs-label); font-weight: var(--fw-medium); color: var(--text-2); letter-spacing: .01em; }
.ai-cap-kicker svg { width: 15px; height: 15px; flex: none; color: var(--text-3); }
/* 主体：左对齐纵向流，靠字重层级（大字标题 / 灰副标）拉节奏，不靠颜色 */
.ai-cap-bd { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-2); padding: var(--sp-3) var(--sp-5) var(--sp-5); }
.ai-cap-num { font-size: calc(32px * var(--fs-scale)); font-weight: var(--fw-bold); line-height: 1.05; letter-spacing: -.02em; color: var(--text-1); }
.ai-cap-num b { font-size: calc(14px * var(--fs-scale)); font-weight: var(--fw-medium); color: var(--text-3); letter-spacing: 0; margin-left: var(--sp-1); }
/* 进度条：复用 .lg-rk-bar 轨道/填充色，只把 flex:1（横排用的）收成 none、否则在 column 里会被撑高塌掉 */
.ai-cap-bar { flex: none !important; width: 100%; height: 5px; }
.ai-cap-sub { font-size: var(--fs-caption); color: var(--text-3); }
/* Pro 引导块：发丝分隔 → 小标题 → 图标行 → 底部浅灰胶囊模块（左「当前 · 免费」右黑 pill） */
.ai-cap-pro { width: 100%; margin-top: var(--sp-2); padding-top: var(--sp-3); border-top: 1px solid var(--border);
  display: flex; flex-direction: column; gap: var(--sp-3); }
.ai-cap-prok { font-size: var(--fs-caption); font-weight: var(--fw-medium); color: var(--text-3); letter-spacing: .02em; }
.ai-cap-fi { flex: none; width: 28px; height: 28px; border-radius: var(--r-circle); background: var(--bg-muted); color: var(--text-2);
  display: inline-flex; align-items: center; justify-content: center; }
.ai-cap-fi svg { width: 16px; height: 16px; }
.ai-cap-ft { font-size: var(--fs-caption); color: var(--text-2); line-height: 1.5; }
.ai-cap-ft b { color: var(--text-1); font-weight: var(--fw-medium); }
.ai-cap-up { margin-top: var(--sp-1); display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-4);
  background: var(--bg-muted); border-radius: var(--radius-pill); }
.ai-cap-cur { flex: 1; min-width: 0; font-size: var(--fs-label); color: var(--text-2); }
.ai-cap-btn { flex: none; border: none; cursor: pointer; font-family: inherit; font-size: var(--fs-label); font-weight: var(--fw-medium);
  padding: var(--sp-2) var(--sp-4); border-radius: var(--radius-pill); background: var(--primary); color: var(--on-primary);
  transition: transform var(--d-micro) ease, filter var(--transition-fast); }
.ai-cap-btn:active { transform: scale(.985); filter: brightness(.92); }

/* ============================================================
   1020 待办「统计即分段器 + 合并控件行」（手机端专属，纯追加，整段删除即回退）
   ------------------------------------------------------------
   ① #todoSeg 升格为 stats-seg：段内「大数字在上、标签退灰在下」竖堆，
      黑凸块滑动语言零新增（照吃 .seg.seg-slide 的 --seg-i/.26s --ease-enter）；
      按钮改纵向流后高度由内容撑（padding 定节奏），凸块 ::before 上下钉在
      --seg-pad 上自动跟高。桌面端不在此段作用域内 → 结构带 .seg-lab 但排布照旧。
   ② 分类行（#todoCatBar 手机端态）：「全部分类 / 已逾期 / 排序」合并一行，
      横滑 chips 退役；新增钮维持 .toolbar>.btn-primary ≤768 隐藏的老规矩
      （手机端新增一贯走 dock 右侧 ＋/#fabAdd，本次只是把 toolbar 里那枚死重撤干净）。
   ③ 已逾期胶囊：状态色走 --status-bad / --tag-bad-fg 一族（与行内「已过期」同门），只在有逾期时在场。
   ------------------------------------------------------------
   ⚠ 1025 站主改版（本段 ②③ 已被覆盖，留着只为讲清 ① 的来历）：分类行不再是「三枚 chip 一行」，
      改成「左固定入口钮 + 右横滑分类 rail」——② 说的「横滑 chips 退役」已反悔；
      ③ 那枚已逾期胶囊整枚退役，开关搬进合并抽屉。新规则见下方 ②③ 注释与 5145 段 .fs-*。
   ============================================================ */
/* 段内 DOM 改为「数字在前、标签在后」（手机端 column 即上下堆叠）；
   桌面横排两枚 span 之间原本靠源码空格，DOM 重排后回补一枚小间距。 */
#view-todo .seg.seg-slide .seg-cnt { margin-right: var(--sp-1); }
/* ≤768 手机端样式 → 06-mobile.css */
@keyframes todoSortFlip { from { transform: translateY(7px); opacity: 0; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  #todoCatBar .chip.flip .todo-cat-lab { animation: none; }
}

/* ============================================================
   1020 续10（站主令「备忘与记忆页也同款优化」）
   只搬待办定稿的「表现层」，不适配的部分不强搬：
     · 记忆 #memSeg：5 格文字段（全部/人物/事件/时间线/今天，仅 2 格带计数）——
       翻成「白轨+发丝边 + --primary 黑把手 + 选中反白」，不上待办的「大数字在上」堆叠
       （堆了其余三格空、五格不齐）；分段器→工具带留白由 module-gap(20) 收到 sp-2，同待办 seg→catbar 节奏。
       memSeg 不在 block C 名单，故选择器 1id+3cls 已稳赢 base `.seg.seg-slide`，无需叠类抬特异。
     · 备忘 view-memo：无分段器，把 block C 那张白卡工具带拆透明（对齐待办「分段条即白卡、工具带透明」），
       标签 chip 合并行化（换行 + 自然宽 + 收紧）；选中态 block C 已黑反白、不动。
   色全走令牌（--primary/--on-primary/--bg-card/--border/--seg-idle），暗档自动翻。
   作用域锁 #view-date / #view-memo，只 ≤768，不碰 block C 全局与共用件定义。整段删除即回退。 */
/* ≤768 手机端样式 → 06-mobile.css */

/* 待办 · 分段器→分类条 21→12（1022，实测定位：工具栏 flex-wrap:wrap + gap:12 把零高 .spacer 挤到第二行，
   与 seg 之间凭空一道 12px row-gap 死空白 + 底距 8 = 21）。待办工具带视觉只有一行（新增钮 ≤768 隐藏），
   把它的 row-gap 归零消掉那 12px，底距回补 card-gap(12) → 分段器→分类条 = 12，与「分类条→列表 12」同节奏。
   文件末尾最后生效，只认 #view-todo，不碰备忘/账本/记忆。 */
/* ≤768 手机端样式 → 06-mobile.css */

/* 可序AI · 回执/查询卡 v3 视觉（2026-10-22 站主实拍「这种卡片有点不好看」，选型定档 v3 最轻）
   根因（真页面取证 dev/lab/cdp-receipt-card-trial.cjs + cdp-query-card-trial.cjs）：
   ① 落点 chip 用 --primary（Klog 主色是纯黑 #111）+ 白字，在白卡里像警告标签、压过正文；
   ② 正文与 chip 抢第一视觉落点（正文只 medium 17px）；
   ③ 回执单条卡带白底+描边+阴影，在一堆白卡里像「卡中卡」偏重（与上方 say 复读叠加更显啰嗦）。
   本块（末尾最后生效）：chip 降为站内既有的弱化配方（--bg-count 浅灰底 + --text-3 深灰字，
   与 .nl-pv.is-saved 同语言，不引新色）；正文提为第一落点（700 + 抬一档，走 --fs-scale 三档自适应）；
   去壳**只作用回执单条 .nl-pv**——多行查询卡 .nl-pv-row 的容器保留（试拍验过：去壳只验过单条，
   多行去壳未验、且查询卡留容器更成组）。全程 .npg-ans 前缀限定「可序AI 气泡内」，
   不碰录入抽屉的 .nl-pv 预览（那在 .nl-sheet/.nl-page 但非 .npg-ans）。
   is-done/is-saved 态因特异性更高（.npq-q .is-done、.is-saved）自动不被本块盖，保留各自语义色。整块删除即回退。 */
.npg-ans .nl-pv-tag,
.npg-ans .nl-pv-row .nl-pv-tag { background: var(--bg-count); color: var(--text-3); font-weight: var(--fw-medium); }
.npg-ans .nl-pv { background: transparent; border: 0; box-shadow: none; padding: var(--sp-1) 0; margin: var(--sp-1) 0 0; }
.npg-ans .nl-pv-txt,
.npg-ans .nl-pv b,
.npg-ans .nl-pv-row-t b { color: var(--text-1); font-weight: 700; font-size: calc(17px * var(--fs-scale)); }

/* ============================================================
   【追加块 · 备忘卡标题↔正文间距根因修复（2.99）】
   真页面量测：手机端 .memo-pin 被 3521 行媒体查询撑到 38×38，而标题行盒仅 22.4px，
   .memo-head 取 flex-start 后头部高被图钉拉到 38px → 标题下方凭空多出 ~15.6px 死空白
   （实测 gap 标题→meta = 19.6px，而 meta→正文只有 4px）。1014 只收窄了 gap/meta，没治到这只图钉。
   根因不在 gap、在图钉撑高头部：把手机端图钉收成贴合标题行的紧凑方形（站主嫌 38px「又大又圆」），
   用透明 ::before 负 inset 保留触控热区（≥40×40），布局盒只让 head 高到 24px（≈标题行）→
   标题→meta 回到 ~5.6px、与 meta→正文 4px 同一档节奏。桌面（>768）hover 圆钮不受影响。整块删除即回退。 */
/* ≤768 手机端样式 → 06-mobile.css */

/* ============================================================
   【追加块 · 可序Ai 设置页 居中陪伴锚点 Hero + API Key 折叠（2026-10-22 站主令）】
   仅 openAiSettings 这一页的新组件，类名 .ai-hero-* / .ai-keyfold-* 全站独一份，
   不改任何既有全局规则；颜色/圆角/间距全吃令牌。整段删除即回退到旧连接卡。
   Hero 复用 .ai-conn 的 data-state 与 .ai-dot 状态色（on=绿 / err=红），这里把版式
   从「左对齐 + 铭牌条」覆盖成「居中锚点（星芒黑底圆头像·名字·陪伴天数·连接胶囊）+ 卡内功能行」。
   头像用站内品牌黑底白星芒（与 .ai-mark / 启用行同款星芒一致），不搬参考图彩色 3D。 */
.ai-hero { padding: 0; overflow: hidden; }
.ai-hero-top { display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: var(--sp-6) var(--card-pad) var(--sp-4); }
/* 2026-11-05 活体引擎：圆盘本体画在 SVG 里（要随挤压/转身一起变形，CSS 背景板做不到），
   所以这里**不再涂底**——留着 `background: var(--primary)` 的话，脸一动就漏出底下那块
   不动的黑底，观感是「一个圆在另一个圆里漂」。颜色改由 .af-body{fill:var(--primary)} 承担。 */
.ai-hero-avatar { width: 66px; height: 66px; border-radius: var(--r-circle);
  display: flex; align-items: center; justify-content: center;
  color: var(--on-primary); box-shadow: var(--shadow-hover); }
/* 原 `.ai-hero-avatar svg { width:32px; height:32px; fill:currentColor }` 是死星芒时代的遗留：
   它会把脸 SVG 锁在 32px 并统一填色，正好盖掉引擎的分层着色与 100% 铺满。随星芒一起退役。 */
.ai-hero-name { margin-top: var(--sp-3); font-size: calc(22px * var(--fs-scale));
  font-weight: var(--fw-semibold); line-height: 1.15; letter-spacing: -.02em; color: var(--text-1);
  cursor: pointer; border-radius: var(--r-2); padding: 2px var(--sp-2);
  outline: none; transition: background var(--d-fast) var(--ease-float); }
.ai-hero-name:focus-visible { background: var(--bg-hover); }
@media (hover: hover) { .ai-hero-name:hover { background: var(--bg-hover); } }
.ai-hero-edit { margin-top: var(--sp-3); width: 168px; max-width: 72%; text-align: center;
  font-size: calc(22px * var(--fs-scale)); font-weight: var(--fw-semibold); line-height: 1.15;
  letter-spacing: -.02em; color: var(--text-1); background: var(--bg-card);
  border: 1px solid var(--border-strong); border-radius: var(--r-2); padding: 2px var(--sp-2);
  outline: none; }
.ai-hero-edit:focus { box-shadow: var(--focus-glow); border-color: var(--border-strong); }
.ai-hero-days { margin-top: var(--sp-2); font-size: var(--fs-caption); line-height: 1.4;
  color: var(--text-4); min-height: 18px; }
.ai-hero-days:empty { display: none; }
.ai-hero-days b { font-weight: var(--fw-semibold); color: var(--text-2); font-variant-numeric: tabular-nums; }
.ai-hero-conn { margin-top: var(--sp-3); display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-label); color: var(--text-4); }
.ai-hero-conn .ai-model { font-family: var(--font-mono); color: var(--text-3); }
.ai-hero-conn .ai-state-word { color: var(--text-2); }
.ai-hero-fn { border-top: 1px solid var(--border); }
.ai-hero-fn .pfg-row { background: var(--bg-card); }
.ai-hero-fn .pfg-row + .pfg-row { border-top: 1px solid var(--border); }
/* 我的 API Key 折叠：body 常驻可见（不 hidden），只靠 max-height 收放——余额按钮 .nl-bal
   靠自身宽度排版，一旦进 hidden 容器取不到宽会塌陷；余额渲染函数一字不改，靠此规避。 */
.ai-keyfold-head .ai-keyfold-chev { transition: transform var(--d-fast) var(--ease-float); }
.ai-keyfold-head.is-open .ai-keyfold-chev { transform: rotate(90deg); }
.ai-keyfold-body { max-height: 0; overflow: hidden; transition: max-height var(--d-modal) var(--ease-float); }
.ai-keyfold-body.open { max-height: 300px; }
.ai-keyfold-body .ai-keyrow { border-top: 1px solid var(--border); }
.ai-keyfold-body #ai-balzone:empty { display: none; }
.ai-keyfold-body #ai-balzone:not(:empty) { border-top: 1px solid var(--border); }
@media (prefers-reduced-motion: reduce) {
  .ai-keyfold-head .ai-keyfold-chev, .ai-keyfold-body { transition: none; }
}

/* ============================================================
   2.85b 人物编辑 · 头像「居中预览 + 分类悬浮卡」（纯追加，作用域 .p-av-* / .av-sheet*）
   ------------------------------------------------------------
   站主：头像改成第一行居中一枚，点开弹悬浮卡分「表情 / 男生 / 女生」三类；底色固定在
   表单里那一行、不进卡也不随分类切。卡片用站内 mountSheet 的 .wp-sheet 皮肤（自带遮罩 /
   返回栈 / 下滑关闭），分段器用 .seg.seg-slide，全部零新造交互件。
   ⚠ 1029 站主推翻其中一半：底色不再固定在表单那一行，而是搬进这只抽屉（见下面 .av-sheet-colors）；
   「不随分类切」这半句照旧成立。旧注释留着是为了记下这次反转，别照它把底色再搬回表单。 */
/* 站主：头像上边离卡片顶太近、灰字离卡片底太近 → hero 的 field 补上下内距；
   头像与「点击更换头像」太松 → 灰字上间距压小（这块原命中 .fg-card .field 上下 0 内距）。 */
.p-av-hero .field { text-align: center; padding-top: var(--sp-4); padding-bottom: var(--sp-4); }
.p-av-pick { border: none; background: none; padding: 0; cursor: pointer; display: inline-block; line-height: 0; }
.p-av-pick:active { transform: scale(.94); }
.mp-dot.p-av-preview { width: 96px; height: 96px; }
.mp-dot.p-av-preview.is-emoji { font-size: calc(50px * var(--fs-scale)); }
.p-av-tip { margin-top: var(--sp-1); text-align: center; font-size: var(--fs-micro); color: var(--text-hint); }
.av-sheet { padding-bottom: max(var(--sp-4), var(--sab)); }
/* 站主：标题挪到把手正下方居中，分段滑块换到它下面单独一行也居中（不再与标题挤同一横排）。
   故 head 改纵向列排、align-items:center；分段器是 inline-flex，给它一个上限宽度后
   在列里自然居中，不铺满整行。 */
/* 把手↔标题间距「改小很多」（仅作用域 .av-sheet，不动全局 .wp-grab）：
   原 .wp-grab 30px 高里小杠下方约 15px 空档 + head 顶衬 sp-2 ≈ 23px 死白。
   压热区到 20px、小杠下方空档随之缩到 ~7px，head 顶衬归零 → 标题基本贴着把手。 */
.av-sheet .wp-grab { height: 20px; margin-bottom: 0; }
/* 标题↔内容间距「改小一点」：列 gap sp-3→sp-1，head 底衬 sp-3→sp-2。 */
.av-sheet-head { display: flex; flex-direction: column; align-items: center; gap: var(--sp-1); padding: 0 var(--sp-4) var(--sp-2); }
.av-sheet-head .wp-title { flex: none; font-size: var(--fs-h3); font-weight: var(--fw-semibold); text-align: center; }
.av-pop-seg { flex: none; width: min(280px, 100%); }
/* 分段滑块降一档：seg-slide 本体跟 --control-h（手机 44）在这张窄抽屉里顶天立地、字像被大框套住。
   照 seg-round 同款思路把这条压到 32，热区靠 button::before 上下各扩 5px 补回（靠加热区补、不靠加高）。 */
.av-sheet .av-pop-seg > button { position: relative; height: 32px; font-size: var(--fs-12); padding: 0 var(--sp-2); }
.av-sheet .av-pop-seg > button::before { content: ''; position: absolute; left: 0; right: 0; top: -5px; bottom: -5px; }
.av-sheet-body { max-height: 52vh; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 0 var(--sp-4) var(--sp-4); }
/* 头像格放大 + 加间距：34px 五列太挤、易误触。放大到 46、间距抬到 sp-3，flex-wrap 自动降列数、
   每格更突出；缩略图与最终圆像同用 cover（所见即所得，不再一圈色底）。 */
/* 站主：头像固定每行 5 个共 5 列。原 flex-wrap 按宽度自动排成 6 列，换 grid 锁死 5 列。
   justify-items:center 让每格（46px）在更宽的轨道里居中、左右各留距——选中环（box-shadow 外扩 4px）
   因此落在轨道内、不再贴到 .av-sheet-body 的滚动裁切边被削掉（这正是最右列描边被切的根因）。
   emoji 格靠 flex 居中字形。 */
.av-sheet .cat-palette { display: grid; grid-template-columns: repeat(5, 1fr); gap: var(--sp-3); justify-items: center; padding-top: var(--sp-2); }
.av-sheet .av-pick { display: flex; align-items: center; justify-content: center; }
.av-sheet .p-avatars .av-pick, .av-sheet .p-avatars-il .av-pick { width: 46px; height: 46px; }
.av-sheet .p-avatars .av-pick { font-size: calc(28px * var(--fs-scale)); }
.av-sheet .p-avatars-il .av-pick img { width: 100%; height: 100%; object-fit: cover; object-position: center 22%; }
.av-pop-pane[hidden] { display: none; }
/* 头像底色一行（1029 站主令：从人物表单那一行搬进这只抽屉，钉在格子下面）：
   · 切 emoji / 男生 / 女生 都不动它——底色与分类本来就是两件事；
   · 它也不跟着格子一起滚（.av-sheet-body 自己滚，这一行住在它外面，中间一根发丝线分组）；
   · 色块沿用站内 .cat-swatch 的材质（.is-sel 双环、:active 回弹、「自动 A」虚线圈全白拿），
     只把这一档尺寸定在 34px——比头像格 46 小一档，读起来是「次要选择」而不是第二排头像；
   · 故意不套 .cat-palette：那一条 `.av-sheet .cat-palette` 是 5 列网格，会把 8 枚色块拆成两行。 */
.av-sheet-colors { margin-top: var(--sp-1); padding: var(--sp-3) var(--sp-4) 0; border-top: 1px solid var(--border); }
.av-colors-k { font-size: var(--fs-caption); color: var(--text-3); }
.av-sheet .av-colors { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--sp-2); margin-top: var(--sp-2); }
.av-sheet .av-colors .cat-swatch { width: 32px; height: 32px; } /* 32×8 + 8×7 = 312 ≤ 326（抽屉左右各缩两档内衬后的可用宽）——
   定这一档是为了 8 枚（自动 + 6 色 + 自定义）老实待在一行；34 就差 2px 被挤成两行（实拍撞过）。 */
@media (prefers-reduced-motion: reduce) { .p-av-pick:active { transform: none; } }
/* 生日方式三枚 chip（编辑人物页）：过农历时「显示至今天数」置灰不可点，
   与数据层 showSince 的 !lunar 闸同源；淡化 + 关事件，别让人点了没反应还以为是坏了。 */
.p-bdsw-chips .chip[disabled] { opacity: .4; pointer-events: none; }
/* 分组那一格：1030 一天内改了两版。第一版把七枚预设平铺在输入框下面，站主实拍点名
   「间距优化」（井底→chip 实测 0px、两行胶囊行距 4px 太挤），补了 --sp-2；
   紧接着二次令「还是改成点击后弹出底部抽屉进行选择」——平铺那排整个撤掉，
   改成「输入框 + 右侧一枚选一个的钮」，外壳白拿 .sub-add（井 flex:1 + 40px 方钮 +
   手机端 46px 井档），label→井 8px 由 .fg-stack 那条既有规则给，**这里不再需要任何规则**。
   留这段话是为了别再把它加回平铺：抽屉那版才是定稿。 */




/* ===================== 「关于我」·可序记忆页（Track B 呈现层）=====================
   参考图那股「被了解」的感觉：顶部叙事大卡（AI 第一人称散文 + 宽行距）、下面事实清单、
   底部一条常驻输入。配色全走站内墨灰 token（暗色自适应），不抄参考图的多巴胺装饰；
   大圆角 + 宽留白 + 黑 pill 主操作，与额度卡/个人中心同一套语言。 */
.ab-modal .modal-body { display: flex; flex-direction: column; }
.ab-wrap { display: flex; flex-direction: column; min-height: 0; }
.ab-scroll { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; }
/* 大卡底色：站主 2026-10-28 点名「背景色太灰」。以前吃 --bg-page（画布灰 #F7F8FA，
   手机端还重映射成更深的 #F1F2F5），而这张卡是浮在白色弹窗里的——把画布色搬进白卡，
   读起来就是一块脏底。改走设计系统里现成的 --bg-inset（白卡之上「浅一档」卡面 #FCFCFC，
   暗档 #1D1F24）：它与 --bg-card 只差 1% 亮度，真正撑住分层的是那圈 1px --border，
   所以这两件必须成对出现（DESIGN_SYSTEM 2.3 的硬规矩），不许单独用。 */
.ab-hero { background: var(--bg-inset); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: var(--sp-6) var(--sp-4); margin-bottom: var(--sp-5, var(--sp-4)); }
.ab-kicker { display: flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-caption); color: var(--text-3); font-weight: var(--fw-medium); }
.ab-kico { width: 15px; height: 15px; display: inline-flex; }
.ab-kico svg { width: 100%; height: 100%; }
.ab-title { font-size: calc(20px * var(--fs-scale)); font-weight: var(--fw-semibold); color: var(--text-1); margin-top: var(--sp-2); letter-spacing: .2px; }
.ab-prose { margin-top: var(--sp-4); font-size: var(--fs-body); line-height: 1.8; color: var(--text-2); }
.ab-prose p { margin: 0 0 var(--sp-3); }
.ab-prose p:last-child { margin-bottom: 0; }
.ab-herofoot { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); margin-top: var(--sp-6); flex-wrap: wrap; }
.ab-meta { font-size: var(--fs-caption); color: var(--text-3); }
.ab-regen { display: inline-flex; align-items: center; gap: var(--sp-1); border: none; cursor: pointer; background: var(--text-1); color: var(--bg-card); border-radius: var(--r-pill); padding: 0 var(--sp-4); height: 36px; font-size: var(--fs-caption); font-weight: var(--fw-semibold); }
.ab-regen svg { width: 15px; height: 15px; }
.ab-regen:active { opacity: .82; }
.ab-regen.is-busy { opacity: .55; pointer-events: none; }
.ab-sect { font-size: var(--fs-caption); color: var(--text-3); font-weight: var(--fw-medium); margin: var(--sp-2) 0 var(--sp-3); }
.ab-list { display: flex; flex-direction: column; gap: var(--sp-2); }
.ab-fact { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-3); background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--r-3); padding: var(--sp-3) var(--sp-4); }
.ab-fact-t { font-size: var(--fs-body); line-height: 1.5; color: var(--text-1); }
.ab-fact-t b { color: var(--text-3); font-weight: var(--fw-medium); margin-right: 2px; }
.ab-fact-d { font-style: normal; color: var(--text-3); font-size: var(--fs-caption); margin-left: var(--sp-2); }
.ab-fact-del { flex: none; width: 26px; height: 26px; border: none; background: transparent; color: var(--text-3); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; border-radius: var(--r-2); }
.ab-fact-del svg { width: 16px; height: 16px; }
.ab-fact-del:active { color: var(--text-1); }
.ab-empty { color: var(--text-3); font-size: var(--fs-caption); line-height: 1.6; padding: var(--sp-4); background: var(--bg-page); border-radius: var(--r-3); }
.ab-input { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-4); padding-top: var(--sp-3); position: sticky; bottom: 0; background: var(--bg-card); }
.ab-input input { flex: 1; height: 42px; border: 1px solid var(--border); border-radius: var(--r-pill); padding: 0 var(--sp-4); font-size: var(--fs-body); background: var(--bg-page); color: var(--text-1); }
.ab-input input:focus { outline: none; border-color: var(--text-3); }

/* ============================================================
   事件详情 / 编辑 跟进人物页最近改动（纯追加）
   事件详情 hero 两栏填白复用上面 .dd-hero.is-person，不新写规则；
   编辑事件三开关的 chip 复用 .mp-chips + .chip.active（人物页 bdSwitchCard 同源）。
   ------------------------------------------------------------
   编辑事件 · 相关人物：把输入的名字按档案渲染成头像行，复用人物头像唯一出口
   personAvatarHtml（.mp-dot.sm）。命中档案 = 头像 + 档案标题；没建过档 = 淡色问号占位，
   一眼看出「这不是档案里的人」，与人物页头像体系同长相。 */
 .f-people-avs { display: flex; flex-wrap: wrap; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4) var(--sp-4); }
 .f-people-avs[hidden] { display: none; }
 .f-ppl-chip { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-caption); color: var(--text-2); }
 .f-ppl-chip b { font-weight: var(--fw-medium); }
 .f-ppl-chip.is-none { color: var(--text-hint); }
 .f-ppl-chip.is-none .f-ppl-q { width: 30px; height: 30px; border-radius: var(--r-circle); background: var(--bg-muted); color: var(--text-4); display: grid; place-items: center; font-size: var(--fs-body); }
 /* 事件详情「相关人物」行：右列从纯文字换成头像 chip，flex 右对齐 + 换行，人多了不挤。
    左右内缩吃 .dd-v 原有列宽，这里只把内部排成一行头像。 */
 .dd-v.dd-v-people { display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: flex-end; align-items: center; }
.ab-send { flex: none; width: 42px; height: 42px; border: none; border-radius: var(--r-circle); background: var(--text-1); color: var(--bg-card); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
.ab-send svg { width: 18px; height: 18px; }
.ab-send:active { opacity: .82; }
@media (prefers-reduced-motion: reduce) { .ab-regen:active, .ab-send:active { opacity: 1; } }
@media (min-width: 769px) { .modal-card.ab-modal { max-width: 560px; height: 80vh; } }
/* ============ 1025 待办表单精简 · 标题当主角 ============
   scope 到 .todo-form，只命中「新增/编辑待办」弹窗，不外溢其他表单。
   并卡（main/extra/remind）复用现成的 .fg-card 白卡 + 分割线 + 浅灰页底，
   这里只把主标题输入放大、去掉它自身的井框，让「标题 + 提醒」一眼成为主区。
   全部取值走 token（--fs-scale / --sp / --fw / --text / --primary），不写裸值、不造第二套方言。 */
/* 主标题输入：字号升到 20px 当主角。两个「光标短一截」的真凶都在这里治（站主 1025 真机实拍）：
   ① 盒高：必须等于文字行盒，否则 caret（物理高=字形上下缘，不随 line-height 变长）居中悬空、
      上下各空一截 → 只保留 height:auto，绝不设 min-height / 加纵向 padding，留白交给 .fg-stack。
   ② 圆角（「在首时被上下裁短」的直接原因）：#f-title 左边距 0，光标落 selectionStart=0 时
      正压在最左圆角上；<input> 内容按圆角矩形裁剪，--r-1=4px 的角把 ~28px 光标顶/底各啃几 px。
      这字段无边框、无底色、纯文字，圆角已无任何视觉作用 → border-radius 归零，光标不再被啃。
   （#f-desc / #f-sub-new 左内衬约 --sp-3(~12px)，首端光标落在圆角咬合区之外，故无需归零。） */
.todo-form #f-title {
  border: none; box-shadow: none; background: transparent;
  padding: 0; height: auto;
  border-radius: 0;   /* 无边框平铺字段：圆角只会按 4px 角裁掉首端光标，去掉 */
  font-size: calc(20px * var(--fs-scale)); font-weight: var(--fw-medium);
  line-height: normal;
  color: var(--fld-ink); text-align: left;
}
.todo-form #f-title::placeholder { color: var(--text-hint); text-align: left; }
.todo-form #f-title:focus { border: none; box-shadow: none; }
/* 光标(caret)又矮又偏上的真根因（站主 1025 两图对比）：全站 --font-sans 栈首是 KlogNum
   （JetBrains Mono，unicode-range 只认领 0-9:%，01:33）。汉字由后面的 CJK 回退字体画，
   但 Chrome 取「第一个可用字体」当 caret 度量 → caret 按拉丁等宽体的上下伸展画，比汉字矮、
   基线偏高，于是「您」的 caret 顶不到字顶、够不到字底。修法：待办这几处自由文本输入把
   KlogNum 从栈首去掉（用 --font-sans 去掉 KlogNum 后的 CJK 优先栈），让 caret 度量=汉字字体。
   代价：这几个字段里手打的数字不再走等宽 KlogNum——标题/子任务是散文，可接受。 */
.todo-form #f-title,
.todo-form #f-desc,
.todo-form #f-sub-new {
  font-family: -apple-system, "PingFang SC", "HarmonyOS Sans SC", "MiSans", "OPPO Sans 4.0",
    "vivo Sans SC", "Noto Sans SC", "Noto Sans CJK SC", "Microsoft YaHei", Roboto, sans-serif;
}
.todo-form .field[data-fg="main"].fg-stack { padding-top: var(--sp-2); }
/* 子任务「添加步骤」输入：与主标题同款「平铺、聚焦不起框」（站主 1025）。
   手机端衬底 + 聚焦描边/柔光来自 .fg-card .fg-stack .sub-add .form-input
   与其 :focus（05:4673/4680，均 (0,4,0)/(0,5,0)），以及基础 .form-input:focus
   （03:53 primary 边 + focus-ring）。这里加 .todo-form 前缀抬到 (0,5,0)/(0,6,0) 稳压：
   静息透明底、聚焦透明底 + 透明边（沿用 1px 占位不跳版）+ 无光晕，与 #f-title 一致。
   「+」按钮已随 HTML 删除，故不覆写 .sub-add .btn。 */
.todo-form .fg-card .fg-stack .sub-add .form-input { background: transparent; }
.todo-form .fg-card .fg-stack .sub-add .form-input:focus {
  background: transparent; border-color: transparent; box-shadow: none;
}
/* 头部保存钮已是全站既有的主色胶囊（.modal-head-act 非 is-icon 态）——
   这里不再重复定义，仅确保待办去掉 icon:true 后走文字主钮即可。 */
/* ↑ 该注释随 1025 第四轮作废：站主点名待办保存钮也改回勾图标（icon:true），
   与其余新增页统一。全站不再有待办专属的文字主钮特例。 */

/* ============ 1025 第四轮（站主四图点名：勾钮 / 描述收回与平铺 / 平铺化 / 小记减负） ============
   全部 scope 到各页专属类（todo-form / date-form / diary-form / ledger-form），不外溢。 */
/* 待办·描述输入平铺：展开态去井底 / 描边 / 聚焦光晕，与主标题同款观感。
   特异性：基础井 (0,4,1)/聚焦 (0,5,1)（本文件 S2 段），.todo-form 前缀各抬一级稳压。 */
.todo-form .fg-card .desc-field:not(.is-collapsed) > .form-input { background: transparent; border: none; box-shadow: none; padding-left: 0; padding-right: 0; }
.todo-form .fg-card .desc-field:not(.is-collapsed) > .form-input:focus { background: transparent; border: none; box-shadow: none; }
/* 待办·「− 收起描述」入口展开态也要可见：基础规则 .desc-field .desc-toggle{display:none}
   (0,2,0) 只在收起态亮按钮（S2 语言），这里 (0,4,0) 让它在展开态留一枚同位小字钮。 */
.todo-form .desc-field:not(.is-collapsed) .desc-toggle {
  display: inline-flex; border: 0; background: transparent; box-shadow: none;
  color: var(--text-4); font-size: var(--fs-caption); padding: var(--sp-1) 0 0;
}
/* 1025 五轮收口跳（逐帧量具：动画末端 fieldH 103→54 单帧 49px）：展开态把「− 收起描述」
   从自带一行提上「描述」label 同一行（label order -2 先上 L1、钮 order -1 跟右缘，
   textarea 100% 自然落 L2），settle 挂类的瞬间钮不再跳位、gap 行不塌陷——动画落点=终态。
   margin-left:auto 同 mood-seg 先例；只动 .todo-form 展开态，人物/备忘 desc-field 不沾。 */
.todo-form .desc-field:not(.is-collapsed) > label { order: -2; }
.todo-form .desc-field:not(.is-collapsed) > .desc-toggle { order: -1; margin-left: auto; align-self: center; padding: 0; }
/* 事件·描述/备注 textarea 平铺：fg-stack 井族共用的衬底+描边+聚焦光晕
   （本文件 4620/4645，各 (0,3,0)/(0,4,0)）在 date-form 里一并撤掉；
   尺寸/行高/占位不动，只去「井」的外观。 */
 .date-form .fg-card .fg-stack .form-input { background: transparent; border-color: transparent; box-shadow: none; }
 .date-form .fg-card .fg-stack .form-input:focus { background: transparent; border-color: transparent; box-shadow: none; }
 /* 1029 备忘页（站主点名并入样板）：主角「标题」走 .add-form .hero-field 平铺放大；
    内容 textarea + md-body 预览 + 标签行撤「井」——与 date-form 同款处理。
    特异度对位：内容 textarea 有 4078 那条 .fg-card textarea.form-input 的井 (0,3,1)，
    这里 .memo-form .fg-card textarea.form-input 也是 (0,3,1)，靠文件更靠后取胜；
    标签行由 mobFormify 打成 .fg-row (0,3,0)，被本条一并抹平。 */
 .memo-form .fg-card .fg-stack .form-input,
 .memo-form .fg-card textarea.form-input,
 .memo-form .fg-card .md-body,
 .memo-form .fg-card .fg-row .form-input {
   background: transparent; border: none; box-shadow: none;
 }
 .memo-form .fg-card textarea.form-input { padding-left: 0; padding-right: 0; }
 .memo-form .fg-card .fg-stack .form-input:focus,
 .memo-form .fg-card textarea.form-input:focus,
 .memo-form .fg-card .fg-row .form-input:focus { background: transparent; border: none; box-shadow: none; }
 /* 备忘正文与预览字号统一 15px / 1.75，与 date-form 语言对齐；md-body 井高不再拉满。 */
 .memo-form .fg-card textarea.form-input,
 .memo-form .fg-card .md-body { font-size: calc(15px * var(--fs-scale)); line-height: 1.75; }
 .memo-form .fg-card .md-body { min-height: 0; }

/* 小记·带入两枚幽灵胶囊调小：基础语言 38 高 / 13 字（05:4690，(0,3,0)）——
   本条与其等特异、文件更靠后取胜：30 高 / 12 字。桌面基 (0,2/3,0) 同样被盖。 */
.diary-form .diary-bring .btn-link { height: 30px; padding: 0 var(--sp-2); font-size: calc(12px * var(--fs-scale)); }
/* 小记·正文主角 20px 太大（站主点名）：回落 16px 正文档、去中字重。
   hero 共享规则 (0,4,0)，这里 .add-form.diary-form 双类同级、靠源码在后取胜。 */
.add-form.diary-form .fg-card .hero-field .form-input { font-size: calc(16px * var(--fs-scale)); font-weight: var(--fw-regular); }
/* 账本·金额账盒去衬底与选中态：站主 1025 点名，覆盖 1011「保留 hero 档」的旧特例。
   只换皮肤——¥ 前缀、32px 等宽数字、内衬与布局全不动；聚焦那圈 1px+柔光一并撤。 */
.ledger-form .lg-well { background: transparent; border-color: transparent; box-shadow: none; }
.ledger-form .lg-well.is-focus { background: transparent; border-color: transparent; box-shadow: none; }

/* ============ 1025 「其他新增表单」共用样板（事件/习惯/小记/账本/人物）============
   把待办验证过的三条收进一份共享类，5 页共用、不各抄一遍：
     · .add-form  = 这些新增/编辑弹窗都挂的公共 scope（在各 open*Form 的 cls 里加）。
     · .hero-field = 该页的「主角」字段（名称/金额/正文…），走堆叠式：放大、左对齐、
                    无边框无底色、圆角归零、聚焦不起框/光晕——与待办 #f-title 同款观感。
   主角输入按 .hero-field .form-input 定位（各页 hero 的 id 不同，故不钉 id）。
   圆角归零专治「首端 caret 被 --fld-r=12px 角啃」；CJK 优先栈专治「caret 取拉丁等宽体度量、
   汉字光标又矮又偏上」——见 MEMORY 同名条目。全部走 token，不外溢其他非新增表单。 */
.add-form .hero-field { padding-top: var(--sp-2); }
/* 主角字段的标题不另起一档（1104：从前吃 --fs-label + --text-4，比同页行式标题小一号、
   还浅一档）。这里只留它自己的下间距，字形交给 03 的 .field > label 与 06 的 .fg-stack。 */
.add-form .hero-field > label { margin-bottom: var(--sp-2); }
/* 抬到 .add-form .fg-card .hero-field（0,4,0）才能同时压住移动端
   .fg-card .fg-stack textarea.form-input（0,3,1）那套「井」（字号/圆角），
   否则主角若是 textarea（如小记正文）会退回 16px + 12px 圆角。 */
.add-form .fg-card .hero-field .form-input {
  border: none; box-shadow: none; background: transparent;
  padding: 0; height: auto; min-height: 0; border-radius: 0;
  font-size: calc(20px * var(--fs-scale)); font-weight: var(--fw-medium);
  line-height: normal; color: var(--fld-ink); text-align: left;
  font-family: -apple-system, "PingFang SC", "HarmonyOS Sans SC", "MiSans", "OPPO Sans 4.0",
    "vivo Sans SC", "Noto Sans SC", "Noto Sans CJK SC", "Microsoft YaHei", Roboto, sans-serif;
}
.add-form .fg-card .hero-field .form-input::placeholder { color: var(--text-hint); text-align: left; }

/* ============================================================
   1025 站主令 · 账本 + 统计首行「框套框」返修（两轮才定稿，两轮都记）
   ------------------------------------------------------------
   第一轮判成「拆外层带」：把 .st-head 抹透明，让分段条自己当那张白卡浮在画布上
   （对齐记忆 #memSeg——它是裸分段器、本就没有外层容器；待办 / 备忘也早已拆带）。
   台子 cdp-sthead-flat-check 36 项绿、改前产物反证 13 红——**证据没错，方向错了**：
   站主实拍回来一句「下面的切换时间要与分段滑块在同一个白色卡片内」，翻页那行不该
   被留在画布上裸着，首行整体仍是一张卡。
   第二轮（定稿）反过来拆里面那层框：外层白卡工具带（1017 统一块 A + 统计并入块）
   原样留着不重写，分段器自己的轨道抹透明——一层框 = 那张带，黑把手直接坐在带面上。
   与记忆 / 待办的差别是**有意**的：那两页首行只有分段器一件事，拆带浮在画布上成立；
   账本 / 统计首行是「粒度 + 翻页」两件事，合成一张卡才成组。别再顺手统一回去。
   第三轮「把手贴字收窄」被站主推翻（第四轮 00:1x 实拍）：宽度还原铺满整格，收的是块与卡的
   内衬（带 padding 降 --sp-1，块与卡边 12 → 8）。
   凸块 / 选中反白 / 计数一律不重复声明（块 C 与统计块已管）。只 ≤768（桌面首行本就
   无带），纯追加、只认这两页作用域。整段删除即回退到第一轮那版（拆带）。 */
/* ≤768 手机端样式 → 06-mobile.css */
.add-form .fg-card .hero-field .form-input:focus { border: none; box-shadow: none; background: transparent; }
/* 主角若是多行正文（小记），去掉 textarea 最小高，让它像大号标题一样贴着卡片铺开 */
.add-form .fg-card .hero-field textarea.form-input { min-height: 1.6em; resize: none; }

/* ============================================================
   助手「活体徽章」.ai-face —— 2026-11-05 起改由 KlogFaceEngine 每帧驱动
   ------------------------------------------------------------
   这一段以前是 25 组 @keyframes + 六组眼型切 opacity（一批基座 / 二批动作 / 三批
   A-D-F-H / 四批情绪事件早晚，共五块 prefers-reduced-motion 补丁）。换引擎之后
   **动画侧全部退役**，这里只留三样：尺寸档、颜色语义、引擎图层的静态样式。

   为什么必须留在 CSS 而不是全交给 JS：
     · 尺寸档（20 / 100%）是控件尺寸，跟全站 S20 一档同源（1102 站主拍板），
       由 JS 写会绕开令牌体系；
     · `--primary` / `--on-primary` 的暗档反白是令牌层的事，引擎只 currentColor 取用；
     · 语义件的「盘内反白 / 盘外墨色」分档是颜色口径，不是动效。

   ⚠ 两条改不动的连带项：
     ① 圆盘本体进了 SVG ⇒ `.ai-face` 与 `.ai-hero-avatar` 的 `background: var(--primary)`
        必须撤掉，否则脸一动就漏底（黑底留在容器上、盘在里面对着它压过去）。
     ② 旧卡冻结与 reduced-motion 归零**不再靠 CSS**：`animation: none` 拦不住 JS 写
        transform，两件事都改由引擎侧 live 门控与 REDUCED 分支承担（见 app.js 引擎段）。
        原来那五块 reduce 补丁与两处 `:not(.is-live)` 冻结块因此退役。
   ============================================================ */
.ai-face { position: relative; display: inline-flex; flex: 0 0 auto;
  align-items: center; justify-content: center;
  width: 20px; height: 20px; color: var(--on-primary) }
.ai-face[data-size="lg"] { width: 100%; height: 100% }
.ai-face svg { width: 100%; height: 100%; display: block; overflow: visible }
/* 盘与五官：盘走 --primary（暗档自动反白），五官走 currentColor＝--on-primary */
.ai-face .af-body { fill: var(--primary) }
.ai-face .af-eye { fill: currentColor }
/* 语义件分两档：画在盘内的用反白（波形·笔迹·三点·zzz），画在盘外的用墨色
   （卫星·星芒环·语音波纹）——同色画在黑盘上会直接看不见，实拍抓到过。 */
.ai-face .af-g { fill: none; stroke: var(--text-1); stroke-width: 1.5;
  stroke-linecap: round }
.ai-face .af-gin { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round }
.ai-face .af-sat, .ai-face .af-sp { fill: var(--text-1) }
.ai-face .af-fx circle, .ai-face .af-fx path { fill: var(--text-1) }
.ai-face .af-belt-back circle, .ai-face .af-belt-front circle { fill: var(--text-1) }
.ai-face text { fill: currentColor; font: 700 6.5px var(--font-mono) }
/* think 态接管「加载指示」的职责（站主 10-26 定：忙碌态那行是加载指示、不是名字）：
   撤掉星芒转圈之后由引擎的 think 态「凝神眼 + 抬眼 + 轻摆」承担，语义不丢。 */

/* ============ 1029「关于我」P0–P7 补口 · 逐条「别喂模型」与运行读数 ============
   全部 scope 在 .ab-* 之下，不外溢。两枚行尾钮沿用 .ab-fact-del 那对 26×26 的密度
   （站主口径：同类细节拿相邻元素当标尺）；「已私密」的钮只靠黑白反转表意——
   功能控件不上色（DESIGN_SYSTEM 彩色边界）。 */
.ab-fact-priv { flex: none; width: 26px; height: 26px; border: none; background: transparent;
  color: var(--text-4); cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-2); }
.ab-fact-priv svg { width: 16px; height: 16px; }
.ab-fact-priv:active { color: var(--text-1); }
.ab-fact-priv.is-on { color: var(--text-1); }
.ab-fact.is-priv .ab-fact-t { color: var(--text-2); }
.ab-fact-lock { font-style: normal; color: var(--text-4); font-size: var(--fs-caption); margin-left: var(--sp-2); }
.ab-foot { margin: var(--sp-3) 0 var(--sp-1); font-size: var(--fs-caption); color: var(--text-4); line-height: 1.6; }
@media (prefers-reduced-motion: reduce) { .ab-fact-priv:active { color: var(--text-4); } }

/* ============================================================
   1029 · 结果回执卡（站主参考图版式，对话流里「助手做完了某件事」那张）
   ----
   六拍：卡头（助手脸 + 名字 · 相对时间 + 右端状态角标）→ 标题主角 →
   类型浅灰胶囊 + 线性图标 + 元信息 →（发丝线）→ 卡脚（✦ 助手那句话 + 撤销）。
   作用域全部钉在 `.npg-ans.is-card` 这一层：纯文字气泡、查询卡、档案卡、简报卡
   一张都不受影响（站主 10-29 定：这套解剖只给结果回执卡）。
   材质：白卡 + --r-5（对话内嵌卡的既有定档）+ --shadow-card，**卡里不再套第二层卡底**
   ——站主口径「框套框要去掉的是里面那层」，所以多条/修改那两种卡身的 .nl-pv 行抹平皮、
   改用发丝线分行。角标是状态标签不是控件，走现成的 --tag-good-* 淡底深字（暗档有值）。
   ============================================================ */
.npg-ans.is-card { width: 100%; max-width: 560px; border: 0; border-radius: var(--r-5);
  padding: var(--sp-4); box-shadow: var(--shadow-card); }
/* ---- 卡头（1107 站主令「气泡里的助手形象与昵称三处全摘」：脸与名字都撤，
       只剩相对时间与角标；rc-av/rc-name 两条规则随之退役）---- */
.npg-ans.is-card .rc-head { display: flex; align-items: center; gap: var(--sp-2); }
/* 历史那几张定妆（2026-11-05 起不在 CSS 这边做）：形象改 KlogFaceEngine 每帧写
   transform 与 path，`animation:none` 拦不住它——冻结与视线钉回都由引擎侧 live 门控
   承担（非 is-live 且非忙碌条的脸不 tick，停在最后一帧，表情与眼形一律不动）。
   原来这五条 `.af-open / .af-wander / .af-gaze` 选择器指向的节点已随眼型组退役，
   留着就是死规则；1031 那条「视线跟随不是动画」的坑在新架构里由 live 门控一并解决。 */
.npg-ans.is-card .rc-id { flex: 1; min-width: 0; font-size: var(--fs-micro); color: var(--text-4);
  font-weight: var(--fw-medium); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 1107 卡头摘名后：rc-when 是卡头唯一文字，前面那枚「·」分隔点（从前隔名字与时间）一并退役。 */
.npg-ans.is-card .rc-badge { flex: none; margin-left: auto; display: inline-flex; align-items: center;
  gap: var(--sp-1); padding: 0 var(--sp-2); line-height: 1.9; border-radius: var(--r-pill);
  background: var(--tag-good-bg); color: var(--tag-good-fg);
  font-size: var(--fs-11); font-weight: var(--fw-medium); }
.npg-ans.is-card .rc-badge svg { flex: none; width: 12px; height: 12px; }
/* ---- 卡身：标题当主角，类型退成浅灰胶囊 + 线性图标 ---- */
.npg-ans.is-card .rc-body { min-width: 0; }
.npg-ans.is-card .rc-title { margin-top: var(--sp-3); font-size: var(--fs-h2); font-weight: var(--fw-bold);
  color: var(--text-1); line-height: 1.35; letter-spacing: -.2px; overflow-wrap: anywhere; }
/* ⚠ 这一行**不许再用 flex-wrap 兜长文本**（2026-10-29 站主实拍「有子待办时排版乱」的根因）：
   长文字一旦超过一行，wrap 会把整个 .rc-mt 项甩到第二行，第一行只剩胶囊与图标＝孤儿行。
   改 nowrap + .rc-mt 吃剩余宽，长文字在自己的盒子里折行（悬挂在图标右缘，不孤立任何东西）。 */
.npg-ans.is-card .rc-meta { display: flex; flex-wrap: nowrap; align-items: center;
  gap: var(--sp-2); margin-top: var(--sp-2);
  font-size: var(--fs-caption); color: var(--text-3); }
/* 类型胶囊一条规则管到底：单条拆出来的 .rc-tag 与多条/修改那两种卡身里借来的 .nl-pv-tag
   同住一档浅灰胶囊（站主口径：框套框去掉里面那层，黑胶囊在这里让位给内容）。
   合并写而不是各写一条，是为了不给棘轮再添一组逐字重复。 */
.npg-ans.is-card .rc-tag,
.npg-ans.is-card .nl-pv-tag,
.npg-ans.is-card .nl-pv-row .nl-pv-tag { padding: 0 var(--sp-2); line-height: 1.9; border-radius: var(--r-2);
  background: var(--bg-muted); color: var(--text-2); font-size: var(--fs-11); font-weight: var(--fw-medium); }
.npg-ans.is-card .rc-tag { flex: none; }
/* 原 `.rc-meta .npg-cbtn-ico` 那条随图标一起撤（1031 站主令删胶囊与截止之间那枚图标）：
   生产者没了还留着规则＝给棘轮添一条死规则。 */
.npg-ans.is-card .rc-mt { flex: 1; min-width: 0; overflow-wrap: anywhere; }
/* 子待办这种「清单类」事实另起一拍（P2，2026-10-29 站主选定）：
   短事实留在 .rc-meta 那一行，清单带一个小标签另起一行，两件事不再用「 · 」硬连。
   与上面 .rc-meta 同一字号档，只靠标签退一档灰、内容进一档墨来分层，不加底不画框（不框套框）。 */
.npg-ans.is-card .rc-fact { display: flex; align-items: baseline; gap: var(--sp-2);
  margin-top: var(--sp-2); font-size: var(--fs-caption); line-height: 1.6; }
.npg-ans.is-card .rc-fact-k { flex: none; color: var(--text-4); font-size: var(--fs-11); }
.npg-ans.is-card .rc-fact-v { min-width: 0; color: var(--text-2); overflow-wrap: anywhere; }
/* 多条 / 修改那两种卡身：借 render() 的 .nl-pv 行原样进来，皮抹平、发丝线分行（不框套框）。
   与上面 .npg-ans .nl-pv 那条 (0,2,0) 灰槽、与 .nl-page .nl-pv-tag 那条黑胶囊在此语境下反义，
   本块 (0,3,0) 且排在它们之后，同特异度后写的赢。 */
.npg-ans.is-card .nl-pv, .npg-ans.is-card .nl-pv-row { background: transparent; border: 0; box-shadow: none;
  border-radius: 0; margin: 0; padding: var(--sp-2) 0; }
.npg-ans.is-card .nl-pv-list > .nl-pv-row + .nl-pv-row { border-top: 1px solid var(--border); }
/* ---- 卡脚：那句话降成脚注，撤销并进同一行右端（不再另起一行吊在卡底） ---- */
.npg-ans.is-card .rc-foot { display: flex; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--border); }
.npg-ans.is-card .rc-spark { flex: none; display: inline-flex; color: var(--text-4); }
.npg-ans.is-card .rc-spark svg { width: 14px; height: 14px; }
.npg-ans.is-card .rc-foot .say { flex: 1; min-width: 0; margin-top: 0; line-height: 1.5;
  font-size: var(--fs-caption); color: var(--text-3); }
.npg-ans.is-card .rc-foot .npg-undorow { margin-top: 0; margin-left: auto; }

/* 晚报 V2（2026-10-29）：「今天的小结」完成条目的打勾态圆点——实心墨底＋反白勾，暗档随语义档自动反转 */
.bp-dot.done { background: var(--text-1); border-color: var(--text-1); color: var(--bg-card); display: inline-flex; align-items: center; justify-content: center; }
.bp-dot.done svg { width: 9px; height: 9px; }


/* ============================================================
   Klog 设置 · C4 版式（1030 站主拍板，只这一页用，前缀 ks- 防撞名）
   ------------------------------------------------------------
   三件事：① 连接卡卡底那条「模型固定 | deepseek」铭牌带换成**三格读数带**
   （今日额度 / 今日花费 / 开机耗时）——只读不可点，下钻入口留在末尾两行；
   ② 额度与单价从「一行一格」的长流水改成**一行多格**（同类并列字段并排，
   格间一道发丝线），留空口径那类说明收成卡底**一条**浅灰带，不再行行挂小字；
   ③ 开关行走**高密度档**：比标准 .pfg-row 矮一档、去图标列、标签左控件右。
   红线自查：颜色/间距/圆角/字号全走令牌；数值字号吃 --fs-scale；
   44px 是控件高度档（同 .pfg-clear-in 的 min-height），不是间距。
   ============================================================ */
/* 读数带：坐的是原铭牌带的位置，所以底色与发丝线沿用同一族令牌（--bg-soft / --border），
   一张卡只允许一条底带，不叠两条 */
.ks-band { display: flex; align-items: stretch; border-top: 1px solid var(--border); background: var(--bg-soft); }
.ks-band .ks-b { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 1px;
  padding: var(--sp-3) var(--sp-3) var(--sp-3) var(--card-pad); }
.ks-band .ks-b + .ks-b { border-left: 1px solid var(--border); padding-left: var(--sp-3); }
.ks-bk { font-size: var(--fs-10); color: var(--text-4); letter-spacing: .02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ks-bv { font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: calc(17px * var(--fs-scale)); line-height: 1.15; color: var(--text-1);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ks-bv small { font-size: var(--fs-10); color: var(--text-4); font-family: var(--font-sans); margin-left: 2px; }
/* 「没数 / 未设」是缺信息不是零，压一档灰，别让空值看着像 0 */
.ks-bv.is-mut { color: var(--text-disabled); }

/* 高密度开关行：比 --pfg-row-h 矮一档；无图标列，标签与短注同排 */
.ks-dense { display: flex; align-items: center; gap: var(--sp-3);
  padding: 0 var(--card-pad); min-height: 44px; }
.ks-dense + .ks-dense, .ks-dense + .ks-grid, .pfg-row + .ks-dense,
.pfg-clear-in + .ks-dense { border-top: 1px solid var(--border); }
.ks-dt { flex: 1; min-width: 0; font-size: var(--fs-ctrl-lg); color: var(--text-1);
  display: flex; align-items: baseline; gap: var(--sp-2); }
.ks-dt em { font-style: normal; font-size: var(--fs-10); color: var(--text-4); flex: none; }

/* 一行多格：格内「上标签下数值」，格间一道发丝线。
   轨道用 repeat(N,1fr) 等分——同类并列字段等宽才读得出「这是一排」；
   窄屏下三格各约 71px，六位对六位的极端值走省略号（读数带同规矩） */
.ks-grid { display: grid; gap: 0 var(--sp-4); padding: var(--sp-2) var(--card-pad) var(--sp-3); }
.ks-grid.c3 { grid-template-columns: repeat(3, 1fr); }
.ks-grid.c2 { grid-template-columns: repeat(2, 1fr); }
.ks-grid + .ks-grid { border-top: 1px solid var(--border); }
.ks-cell { min-width: 0; display: flex; flex-direction: column; gap: 1px; padding: var(--sp-2) 0; }
.ks-cell + .ks-cell { border-left: 1px solid var(--border); padding-left: var(--sp-4); }
.ks-k { font-size: var(--fs-11); color: var(--text-4); line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 数值直接吃行内输入格：不另画一层框（站主「框套框要去掉里面那层」）——
   轨道抹透明、只留文字，聚焦时靠 --focus-glow 说话 */
.ks-v { display: flex; align-items: baseline; min-width: 0; }
.ks-cell .pfg-in { height: auto; min-width: 0;
  font-size: calc(17px * var(--fs-scale)); font-weight: var(--fw-medium); color: var(--text-1); }
.ks-cell .pfg-in::placeholder { font-weight: var(--fw-regular); font-size: calc(17px * var(--fs-scale)); }
.ks-cell .pfg-in:focus { outline: none; }

/* 卡底一条说明带：讲整卡口径的那句住这里，不再行行挂 .pfg-t-sub */
.ks-tip { padding: var(--sp-3) var(--card-pad); border-top: 1px solid var(--border);
  background: var(--bg-soft); font-size: var(--fs-11); color: var(--text-4); line-height: 1.6; }

/* ============================================================
   1031 · 确认卡去壳 + 长清单折叠（站主实拍两图：41 条的删除卡铺满一屏、
   灰盒嵌在白气泡里＝框套框；外加「卡啪一下出来，一点思考都没有」）
   ----
   去壳口径沿用 1029 结果回执卡那条「框套框要去掉的是里面那层」：外层白气泡 .npg-ans
   原封不动，里面那几行抹掉灰底（8021 那档 --bg-page）+ 描边 + 圆角 + 外边距，
   改发丝线分行；行首类型标与查询卡 .npq-tag2 合用同一条规则（不抄第二份、不引新色）。
   查询卡的行早在 1012/1013 那轮就去过壳（.npq-q .nl-pv-row 透明），确认卡是这一屏
   最后一张还留着灰盒的——本轮把两者拉成同一语言。
   作用域钉死在只有 confirmBodyHtml 生产的 .npg-cbody 上：查询卡 .npq-q、
   回执卡 .npg-ans.is-card、录入抽屉 .nl-sheet 一张都不碰。
   折叠：默认露前 5 条（档在顶层 NL_CONFIRM_FOLD，CSS 只认行上的 data-nl-more，
   不铺 nth-child），末尾一枚无框小字钮就地全展开。整块删除即回退。
   ============================================================ */
.npg-ans .npg-cbody { margin-top: var(--sp-2); }
/* (0,3,0) 起跳 + 排在 8012/8014/8021 之后：白气泡里那层灰盒的皮全部抹平 */
.npg-ans .npg-cbody .nl-pv-row {
  align-items: center; min-height: 0; margin: 0; padding: var(--sp-2) 0;
  background: transparent; border: 0; border-radius: 0; box-shadow: none;
}
.npg-ans .npg-cbody > .nl-pv-row + .nl-pv-row { border-top: 1px solid var(--border); }
/* 候选行仍要点：热区回到 44 地板（§8 触达）；按压衬底不另写一条，
   并进 7948 那条与查询卡跳页行共用的 :active（同声明各写一遍＝凭空多一组逐字重复） */
.npg-ans .npg-cbody .nl-pv-row[data-nl-cand] { min-height: 44px; }
/* 折叠：多出来的行收着，展开只翻列表那一个 is-open 类 */
.npg-ans .npg-cbody .nl-pv-row[data-nl-more] { display: none; }
.npg-ans .npg-cbody.is-open .nl-pv-row[data-nl-more] { display: flex; }
/* 展开/收起钮：一行小字 + 一枚箭头，无底无框（里面那层不再加皮）；箭头走 .np-more 同款旋转 */
.npg-cfold {
  display: flex; align-items: center; gap: var(--sp-1); margin-top: var(--sp-1);
  padding: var(--sp-1) 0; border: 0; background: transparent; cursor: pointer; text-align: left;
  font: inherit; font-size: var(--fs-label); color: var(--text-3);
}
.npg-cfold:active { color: var(--text-1); }
.npg-cfold-chev { flex: none; width: 12px; height: 12px; transition: transform var(--d-base) var(--ease-float); }
.npg-cfold.is-open .npg-cfold-chev { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) { .npg-cfold-chev { transition: none; } }

/* ============================================================
   回执卡统一 · 2026-11-02 站主拍板（H1 / S20 / 语义角标 / C2）
   ① 角标语义三色：成功绿（.rc-badge 基础档不变）＋ 待定蓝（待应用 / 保存中）＋ 失败红。
      色值全部走 01-tokens.css 的 --tag-info-* / --tag-bad-*（1102 新立 info 双档）。
   ② H1 恢复档 2026-11-07 已再翻案（气泡三处全摘）：答案 .who 行没了，卡头名字也撤了，
      这条灰档只剩忙碌条文字还吃着（与 .is-busy .who 同值，规则本身在 6386 那条里）。
   ③ 动效只留最新一条（1031 卡那套的同族）：非最新气泡的脸钉回声明态——
      呼吸 / 眨眼 / 视线跟随全停；忙碌条自带 think 态，用 :not(.is-busy) 让路。
      is-live 由 nlWhoFaces 对气泡与卡统一发牌。
      ⚠ 1107 气泡三处全摘后对话流里已无脸，这套发牌与门控一起退役（见 app.js isLive 注）。
   ============================================================ */
.npg-ans.is-card .rc-badge.is-info { background: var(--tag-info-bg); color: var(--tag-info-fg); }
.npg-ans.is-card .rc-badge.is-bad { background: var(--tag-bad-bg); color: var(--tag-bad-fg); }
/* 旧卡冻结与 reduce 归零 2026-11-05 起**不在 CSS 这边做**：形象改 KlogFaceEngine 每帧
   写 transform 与 path，animation:none 拦不住它。两件事都移到引擎侧——
   live 门控（非最新气泡 / 非忙碌条的脸不 tick，停在最后一帧）与 REDUCED 静态帧。
   is-live 仍由 nlWhoFaces 发牌，引擎读同一个类，口径与 1031「动效只留最新一条」一致。 */

/* ============================================================
   1103 订阅管理（v13 模块）· 列表卡片 + 统一新增/编辑抽屉 + 详情抽屉
   ------------------------------------------------------------
   段头自律三条（照 1005 账本段同一口气）：
   ① 尺寸全走令牌——间距走 --sp- 族与 --card-gap、--card-pad；圆角走 --r- 族；
      字号走 --fs- 族；时长走 --d- 族；缓动走 --ease- 族。
      控件自身尺寸（图标盒 38/44、圆钮 34）归控件不归间距。
      ⚠ 段头里禁止写「星号紧跟斜杠」那一串：它会提前闭合本注释，把紧跟的第一条规则
      整条当成选择器残骸吞掉（本轮实测踩过，症状是 .sb-body 的 gap 莫名不生效）。
   ② 金额一律 --font-mono + tabular-nums，与账本共用 lgYuan 那一把读数尺，不另立 formatter。
   ③ 颜色只用 :root 语义档（--bg-card、--bg-inset、--bg-muted、--bg-count、--border、
      --text-1 到 --text-4、--tag-info- 与 --tag-bad- 两档、--primary、--on-primary）；
      分类色只由 JS 内联落在那一只图标上，功能控件与正文保持无彩色——
      选中态走黑白反转，不借状态绿（站主 1025 定论）。
   ④ 尺子不自造：账本已有的件并挂 .lg-grp / .lg-row / .lg-card / .lg-rk，.sb- 只留订阅多出来
      的一档（06 的窄屏重映射随之生效）。自造那把尺量出来是 16 圆角描边无投影 vs 站内 12
      圆角投影、行内距四边 16 vs 12/24、组标题上 24 下 16 vs 上 28 下 8。
   追加段：整段删除即回退（并挂在 markup 的 class 串上，回退要一起撤）。前缀 .sb- 站内未占用。
   ============================================================ */
/* 组标题走 space-between 后，口径读数一长就把标题挤成两行（「分类概/况」）：标题不折，让读数折 */
.sb-grp { white-space: nowrap; }
.sb-grp span { white-space: normal; text-align: right; }
.sb-row.is-idle { opacity: .72; }
/* 图标两处都裸贴（1105 站主两轮各点名一次：先列表、后详情 hero）。
   PRD §8 原文「图标尽量使用无底色或轻量化背景」——详情那枚 44px 的封面底框也撤了，
   留尺寸不留框：白卡上再垫一层 --bg-muted 灰底，读起来就是「这块能点」，而它不是按钮。
   圆角随底色一起收掉：没有底色可切圆角，留着是一条不会生效的死声明。 */
.sb-icwrap { display: inline-flex; flex: none; align-items: center; justify-content: center; width: 38px; height: 38px; color: var(--text-3); }
.sb-icwrap.sb-ic-lg { width: 44px; height: 44px; }
.sb-ic { display: block; }
.sb-main { display: flex; flex: 1 1 auto; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.sb-name { overflow: hidden; font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--text-1); white-space: nowrap; text-overflow: ellipsis; }
.sb-meta { overflow: hidden; font-size: var(--fs-micro); color: var(--text-4); white-space: nowrap; text-overflow: ellipsis; }
/* 副行与徽章并同一行（1105 站主点名「每个订阅项还要再优化」）：
   放得下就两行读完，放不下靠 wrap 自己掉到第二行——下面那条 8145 行的教训原样保留，
   只是兜底对象从「名字 + 两枚徽章」换成「副行 + 徽章」，溢出概率更低而不是更高。
   窄屏实测：长中文名 + 自动续费 + 暂时闲置 三件仍会折行，不会互相压省略号。
   ⚠ 副行是 flex: 0 1 auto（能缩、不撑）而不是 1 1 auto：撑满会把徽章推到右缘，
     紧挨着金额那一列，读起来像右侧读数的一部分。徽章必须紧跟副行成一个簇才对。 */
.sb-sub { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1) var(--sp-2); min-width: 0; }
.sb-sub .sb-meta { flex: 0 1 auto; min-width: 0; }
/* flex-wrap 是真需要：中文长名 + 「自动续费」+「暂时闲置」三件在窄屏挤一行会溢出，
   让徽章自己换行，不去压名字那一列的省略号 */
.sb-tags { display: flex; flex: none; flex-wrap: wrap; gap: var(--sp-1); }
.sb-tag { padding: 0 var(--sp-2); font-size: var(--fs-9); font-style: normal; line-height: 1.6; border-radius: var(--r-1); background: var(--bg-count); color: var(--text-3); }
/* 强调态一律加一档字重：与上面 .sb-due.is-soon 同一条尺（只换色相不算强调）。
   顺带避开 css-bloat-gate 的「声明体逐字重复」——站内 .rc-badge.is-info 已经写过同一对色值，
   再抄一遍就是凭空多造一组重复账。 */
/* 自动续费徽章是这一行里唯一的强调项：走 --tag-info 淡底 + 提一档字重。
   加字重是有意的（只换个色相不算强调，与 .sb-due.is-soon 同一条尺），
   顺带避开 css-bloat-gate 的「声明体逐字重复」——站内已有一处只写这一对色值。 */
.sb-tag:not(.sb-tag-mute) { background: var(--tag-info-bg); color: var(--tag-info-fg); font-weight: var(--fw-medium); }
.sb-right { display: flex; flex: none; flex-direction: column; align-items: flex-end; gap: var(--sp-1); }
.sb-amt { font-family: var(--font-mono); font-size: var(--fs-h3); font-variant-numeric: tabular-nums; font-weight: var(--fw-semibold); color: var(--text-1); white-space: nowrap; }
/* 1107 轮 17：折算参考不再独占右列中间一行（那会把整张卡撑高一档）。改成金额同一行
   尾随的 inline <i>（与总览 .sb-tl 里 sbCnyI 的 inline 折算是同一语言）：主金额大、参考小，
   右列回到「金额 / 日期」两行，外币卡与人民币卡同高。font-style 归正是因为它现在是 <i>。 */
.sb-amt2 { font-style: normal; font-family: var(--font-mono); font-size: var(--fs-9); font-weight: var(--fw-regular); color: var(--text-4); margin-left: var(--sp-1); }
.sb-due { font-size: var(--fs-caption); color: var(--text-3); }
.sb-due.is-soon { font-weight: var(--fw-medium); color: var(--text-1); }
.sb-due.is-over { color: var(--tag-bad-fg); }

/* 币种符号不再进标签（会让 label 首文本节点变成「当前每期实付（」，
   FG_ICONS 按标签文字查表就匹配不上、图标整排缺一档）；币种由下方「币种」行自己显示。 */
/* 8 枚图标在 390 宽下要一行放得下：间距收到 --sp-1（8 枚 34px + 7×4 = 300，
   用 --sp-2 会溢出成 7+1，第二行孤零零一枚） */
.sb-glyphs { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.sb-glyph { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; color: var(--text-3); background: var(--bg-muted); border: 1px solid transparent; border-radius: var(--r-2); cursor: pointer; transition: color var(--d-micro) var(--ease-float), background var(--d-micro) var(--ease-float); }
.sb-glyph.is-on { color: var(--on-primary); background: var(--primary); }
.sb-hide { display: none; }
/* .seg 本体是 inline-flex（宽度贴内容），放进字段里必须撑满一行——
   否则三项只占半张卡，滑动白块只有三分之一宽，后两项文字挤成一串（实拍抓到过） */
.sb-use-seg, .sb-seg { display: flex; width: 100%; }
/* 详情 hero 归类那行（图标右侧）：只剩字号与墨色——周期与归类已并成一个文本节点，
   两栏骨架与右列倒计时全部借 .dd-hero.is-person（纪念日详情在用），见 app.js openSubDetail */
.sb-dd-kind { font-size: var(--fs-caption); color: var(--text-4); }

@media (prefers-reduced-motion: reduce) {
  .sb-row, .sb-glyph { transition: none; }
}

/* ---- 1103 轮 3 · 订阅总览段（接在上面的 1103 订阅段之后，同属整段删除即回退） ----
   只补「账本没有、订阅必须有」的四件：外币分列行、时间线小行、不可点的排行行、分段器外边距。
   hero 与白卡与横条全部借 .lg-*（与 1007 小票设置页借 .lg-hero-* 同一先例），
   所以这里零重复声明体；间距圆角字号一律令牌，无裸值。 */
.sb-segbar { display: flex; margin-bottom: var(--card-gap); }
/* 第二、第三枚币种各占一行：币名在左、原币种金额在中、折算参考在右，
   跨币种永远不加总（方案 D5：混币种相加在财务上是错数）。 */
.sb-hero-x { display: flex; align-items: baseline; gap: var(--sp-2); margin-top: var(--sp-2);
  font-size: var(--fs-caption); color: var(--text-4); }
.sb-hero-x b { font-family: var(--font-mono); font-size: var(--fs-h3); font-weight: var(--fw-semibold);
  color: var(--text-1); font-variant-numeric: tabular-nums; }
.sb-hero-x i { font-style: normal; font-family: var(--font-mono); font-size: var(--fs-9); color: var(--text-4); }
/* 动态 / 实际那两张白卡里的小行：左主语右读数，读数是等宽。与 .lg-rk 的差别只是不需要条，
   所以不复用它的声明体；上下内距同它（--sp-3），写 --sp-2 时单行只有 38px、压在 44 触达线下。 */
.sb-tl { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-3) 0; border-bottom: 1px solid var(--hm-line); font-size: var(--fs-caption); color: var(--text-4); }
.sb-tl:last-child { border-bottom: none; }
/* 主语那列可以ellipsis、右列读数绝不换行：长订阅名（ChatGPT Plus 这种）挤到读数上，
   这段就没法一眼扫了。 */
.sb-tl b { min-width: 0; overflow: hidden; font-weight: var(--fw-medium); color: var(--text-1); text-overflow: ellipsis; white-space: nowrap; }
.sb-tl span { text-align: right; white-space: nowrap; }
.sb-tl i { font-style: normal; margin-left: var(--sp-2); font-family: var(--font-mono);
  color: var(--text-2); font-variant-numeric: tabular-nums; }
.sb-tl em { font-style: normal; margin-left: var(--sp-2); color: var(--text-4); }
/* 分类概况那几行在总览里只是读数、不筛选（筛选器还没做），所以借 .lg-rk 的皮肤
   但必须撤掉它给「可点行」准备的两样：手型与按下底色——留着就是假装可点。 */
.sb-rk, .sb-rk:active { cursor: default; background: transparent; }
/* 分类名那一列必须比账本宽一档：账本内置类名最短 2 字、48px 够；订阅这 8 档最长 4 字
   （视频娱乐 / 音乐会员 / 游戏会员 / 生活服务），照 48px 会被省略号截成「视频…」（实拍抓到）。 */
.sb-rk-n { width: calc(64px * var(--fs-scale)); }
/* 日历那一格要放两行（日号在上、那天几笔在下）：.lg-day 本体是 grid + place-items:center，
   第二行会和日号叠在一起，所以这里必须换成纵向 flex。深浅与按下缩放继续吃 .lg-day 那套。 */
.sb-day { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0; }
.sb-day i { font-style: normal; font-family: var(--font-mono); font-size: var(--fs-9); line-height: 1; }
/* 当日清单的每一行是按钮（点它就开那条订阅的详情）：UA 的字体/底色/对齐全清掉，
   行本身的皮肤继续用上面 .sb-tl 那一套小行，不再抄一份。 */
.sb-tl-row { width: 100%; font: inherit; color: inherit; text-align: left; background: transparent; border-top: none; border-right: none; border-left: none; cursor: pointer; }
.sb-tl-row:active { background: var(--bg-hover); }
/* 轮 5 两处实拍挑出来的毛病：
   ① 面板标题被右侧灰字挤成两行（「未来 12 个月预 / 计」），标题必须整行不换；
   ② 币种从属行（美元 / 日元那两行）与主行长得一样，读起来像一条独立指标叫「美元」，
      得缩进一档并把墨色压一档，才看得出是上面那个数的拆分。 */
.sb-trend .ph-title { white-space: nowrap; }
.sb-tl-sub b { padding-left: var(--sp-3); color: var(--text-3); font-weight: var(--fw-regular); }

/* ---- 1104 第二轮实拍：分类详情抽屉的流水层自己封顶（append-only） ----
   只做三件事：封顶（吃 .wp-sheet 的 --sheet-max，把手拉到最长档时 wireSheetGrab
   会写行内值覆盖）、自己滚、下拉不顺手把抽屉拖走。上限之外不给 min-height——
   只读详情不该被「保底」顶高。刻意不借现成的 .tf-list：那只壳带一条
   「选择类抽屉 is-tall 保底 60vh」，只读详情一旦上拉就被顶到 802px（视口 844），
   空态也满屏、只能侧滑退。桌面 .dd-modal 不挂这层（弹窗自己有滚动窗）。 */
.lg-cat-sheet .lg-cd-flow { max-height: var(--sheet-max); overflow-y: auto;
  -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }

/* ---- 1104 账本联动 · 回跳小标（append-only，整段删除即回退） ----
   账本流水行的来源小字（.lg-row-t em 挂上本类）与订阅历史行的「已记入账本」共用一枚语言：
   只说「能点」（下划线 + 手型 + 按压沉一档），读数本身的字号墨色一律不动、不新造控件。
   margin-left 在账本那侧被 .lg-row-t em（多一枚元素选择器、特异性更高）压回 --sp-1，
   正是那边既定的小字间距；只有订阅 .dd-v 里吃得到这 8px——两处都合适，不用各写一条。 */
.lg-src { margin-left: var(--sp-2); font-style: normal; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.lg-src:active { opacity: .55; }
.lg-src.is-off { text-decoration: none; cursor: default; opacity: .7; }
