/* 设计意图：表格要密（信息多），但呼吸感要够。
   做法：去掉竖线只留极浅横线，靠留白和字重分层，颜色只用在真正要提醒的地方。 */
@import url("/static/tokens.css");   /* 颜色令牌拆到了 tokens.css，手机版共用 */

*{box-sizing:border-box}
html,body{height:100%}
/* 整页不滚动，只有表格区滚。
   原来 .wrap 写死 height:calc(100vh - 100px)，但顶栏实际 120px、打开提醒还要再多约 90px，
   页面就比屏幕高，body 也跟着能滚。滚下去之后提醒面板（在 .wrap 上方、不是 sticky）
   被滚出视野，再点「提醒」看着就像没反应——其实它出来了，只是在屏幕外。
   改成 flex 按实际高度分配，顶栏和提醒条占多少就是多少，剩下的全给表格。 */
body{margin:0;background:var(--bg);color:var(--fg);
  font:13.5px/1.55 -apple-system,BlinkMacSystemFont,"PingFang SC","Helvetica Neue",sans-serif;
  -webkit-font-smoothing:antialiased;
  height:100%;display:flex;flex-direction:column;overflow:hidden}
header,#rem{flex:none}

/* ---- 顶栏 ---- */
/* 顶栏给一层极浅的冷色底，和白色表格分层。
   （这层底色本来就设计好了，但写成了 .topbar，而 HTML 用的是 <header>，
     类名对不上，三条规则一直是死代码——"太素"有一半是这个 bug。） */
header{position:sticky;top:0;z-index:30;padding:11px 20px 5pt;
  background:linear-gradient(180deg,#fbfdfe,#f2f7fb);
  /* 面板和表格的分界：不靠加粗线条（线越粗越像表格自己的一部分），
     用一条实线 + 一道向下的柔和投影，读起来就是"上面这块浮在内容之上"。
     再留一道 7px 的页面底色当缝，三者合起来才分得干净。 */
  border-bottom:1px solid var(--line2);
  box-shadow:0 5px 12px -7px rgba(31,41,55,.30);
  margin-bottom:7px}
@media(prefers-color-scheme:dark){
  header{background:linear-gradient(180deg,#1b2229,#161b21);
    box-shadow:0 5px 14px -7px rgba(0,0,0,.65)}}
/* 提醒面板紧贴在顶栏下面时，缝留给它下面，别把两块隔开 */
header:has(+ #rem:not([hidden]):not(.hide)){margin-bottom:0}
#rem:not(.hide){margin-bottom:7px;box-shadow:0 5px 12px -7px rgba(31,41,55,.22)}
.bar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding-bottom:11px}
h1{font-size:15px;margin:0 16px 0 0;font-weight:600;letter-spacing:.2px;color:var(--accent)}
/* 左边年份+月份两行，右边统计卡片纵向跨这两行——
   卡片不再单独占一层高度，是"借"月份行的高度长出来的。 */
/* align-items:flex-start —— 左栏顶对齐，展开月份时年份行原地不动、
   月份往下长出来。原来是 center，左栏一变高年份就会被顶上去。
   统计卡片单独 align-self:center，保持垂直居中的观感。 */
.tabs{display:flex;flex-direction:row;align-items:flex-start;gap:16px;flex-wrap:wrap}
.tabs-left{display:flex;flex-direction:column;align-items:flex-start;gap:2px;
  min-width:0;flex:0 1 auto}

/* 统计做成一张仪表盘卡片：小标签在上、大数字在下，格与格之间细竖线。
   原来是一行灰色小字，数字和指标名混在一起，"太素"主要就是这块。 */
/* align-self:flex-start —— 卡片钉在顶部，跟年份行同一条基线。
   原来是 center，左栏一展开月份，卡片就会跟着往下挪、收起又挪回来。 */
.stat{margin-left:auto;align-self:flex-start;display:flex;align-items:stretch;white-space:nowrap;
  padding:8px 4px;border-radius:10px;cursor:grab;user-select:none}
.stat:active{cursor:grabbing}
/* 拖起来之后才给底色和边框——浮在表格上面得有个"面"才看得清；
   在原位时是裸的，不要那圈框。 */
.stat[style*="fixed"]{background:var(--card);border:1px solid var(--line2);
  box-shadow:0 6px 20px rgba(31,41,55,.16)}
@media(prefers-color-scheme:dark){
  .stat[style*="fixed"]{box-shadow:0 6px 20px rgba(0,0,0,.5)}}
/* 三组：单量+营业额（规模）｜ 实收+未收（钱）｜ 缺凭据+待开工（待办）。
   组内不画线、只留间距，组间画一条线——不然七格平铺看不出归属关系。 */
.stat .g{display:flex}
.stat .g:empty{display:none}
.stat .g + .g{border-left:1px solid var(--line2);margin-left:6px;padding-left:6px}
.stat .s{display:flex;flex-direction:column;justify-content:center;align-items:center;
  gap:3px;padding:0 13px;text-align:center}
.stat .s em{font-style:normal;font-size:11px;color:var(--mut);font-weight:500;
  letter-spacing:.2px}
.stat .s i{font-style:normal;font-size:19px;font-weight:700;color:var(--fg);
  font-variant-numeric:tabular-nums;line-height:1.15}
/* 数字配色（Owen 2026-09-03 定）：单量黑、营业额绿、实收蓝、未收橙。
   类名跟着指标走（main/rev/paid/warn），不用颜色命名——
   哪天再调色只改这几行，不用回头改 renderStat 里的类名。 */
.stat .s.main i{color:var(--fg)}
.stat .s.rev i{color:var(--green-b)}
.stat .s.paid i{color:var(--accent)}
.stat .s.warn i{color:var(--amber)}
/* 深色底下那两个颜色发闷（绿 4.5、蓝 3.9），同色系各调亮一档。
   跟按钮点亮态、月份选中态用的是同一套做法，别再各写各的。 */
@media(prefers-color-scheme:dark){
  .stat .s.rev i{color:var(--done-t)}
  .stat .s.paid i{color:#7cbaea}
}
/* 缺凭据 / 待开工是"待办数"，做成琥珀色小圆牌，跟金额区分开 */
.stat .s.pill i{display:inline-flex;align-items:center;justify-content:center;
  min-width:26px;height:26px;padding:0 7px;border-radius:8px;font-size:14px;
  background:var(--w1);color:var(--w1t)}
/* 可点的三个：hover 和选中态限制在自己那一格里，不动卡片整体 */
.stat .s.click{cursor:pointer;border-radius:7px}
.stat .s.click:hover{background:var(--hover)}
.stat .s.click.on{background:var(--accent-bg)}
.stat .s.click.on em{color:var(--accent)}
.stat b{color:var(--fg2);font-weight:600}
button{font:inherit;font-size:13px;padding:6px 13px;border:1px solid var(--line2);
  border-radius:8px;background:var(--card);color:var(--fg2);cursor:pointer;
  box-shadow:none;transition:background .12s,border-color .12s}
button:hover{background:var(--accent-bg);border-color:var(--line2);color:var(--fg)}
button.pri{background:var(--accent);border-color:var(--accent);color:#fff}
button.pri:hover{filter:brightness(1.07)}
/* 开关型按钮（提醒、全部展开）打开时点亮，鼠标移开也保持——
   只靠 hover 色的话一移开就分不清面板到底是开着还是关着。 */
button.on{background:var(--accent-bg);border-color:var(--accent);color:var(--accent-h);
  font-weight:600}
button.on:hover{background:var(--accent-bg);border-color:var(--accent-h)}
/* 深色下 --accent 压在深底上只有 3:1，比没点亮的按钮还难读。
   同一个蓝，调亮一档，不另起色相。 */
@media(prefers-color-scheme:dark){
  button.on{color:#7cbaea;border-color:#3f8cc4}
  button.on:hover{border-color:#5aa3d8}
}
/* 搜索框：找一个人比按月份翻快得多。跟按钮同一套外形，有内容时跟着点亮。 */
.q{font:inherit;font-size:13px;padding:6px 11px;width:170px;
  border:1px solid var(--line2);border-radius:8px;
  background:var(--card);color:var(--fg);
  transition:border-color .12s,box-shadow .12s,background .12s}
.q::placeholder{color:var(--mut)}
.q:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px rgba(38,120,184,.13)}
.q.on{border-color:var(--accent);background:var(--accent-bg)}
.q-none{text-align:center;color:var(--mut);padding:18px}
/* 维护类按钮（扫描/导出/列设置/重置列宽/备份）不是每天用的，
   降成无边框灰字，让"新增客户 / 搜索 / 提醒"占住视线；鼠标移上去才浮出来。 */
button.ghost{border-color:transparent;background:none;color:var(--mut);padding:6px 10px}
button.ghost:hover{background:var(--accent-bg);border-color:var(--line2);color:var(--fg2)}
/* 常用组和维护组之间一条竖线，分组比对齐更能减少"杂" */
.sep{width:1px;align-self:stretch;margin:2px 4px;background:var(--line2)}
/* 「⋯」按钮：三个点用 CSS 画，不用 ⋯ 字符——字符的墨迹中心和字框中心对不齐，会看着偏 */
.more{position:relative;display:inline-flex}
#btn-more{width:32px;padding:6px 0;display:inline-flex;align-items:center;justify-content:center}
/* 竖排三点：偏移量从横向 x 改成纵向 y */
#btn-more .dots{width:3px;height:3px;border-radius:50%;background:currentColor;
  box-shadow:0 -5px 0 currentColor, 0 5px 0 currentColor}
.menu{position:absolute;top:calc(100% + 6px);right:0;z-index:40;
  background:var(--card);border:1px solid var(--line2);border-radius:9px;
  box-shadow:0 6px 20px rgba(31,41,55,.13);padding:5px;min-width:132px;
  display:flex;flex-direction:column;gap:2px}
.menu[hidden]{display:none}
.menu button{text-align:left;justify-content:flex-start;width:100%;
  border-color:transparent;padding:7px 11px}
.menu button:hover{background:var(--accent-bg);border-color:transparent;color:var(--fg)}
@media(prefers-color-scheme:dark){.menu{box-shadow:0 6px 20px rgba(0,0,0,.45)}}
/* 提醒条数做成徽章：有待办时用琥珀色（配色里已有的"该注意了"，不是新色相） */
#rem-n{display:inline-block;min-width:17px;padding:0 5px;margin-left:4px;border-radius:99px;
  background:var(--line2);color:var(--fg2);font-size:11px;font-weight:650;
  line-height:17px;text-align:center;vertical-align:1px}
#btn-rem.has #rem-n{background:var(--amber);color:#fff}
button.warn{border-color:#e6c9c4;color:var(--red)}
@media(prefers-color-scheme:dark){button.warn{border-color:#553}}

/* 月份标签两层：上层年份（小、灰），下层该年的月份（大、蓝）。
   月份到了 12 个，平铺一行会挤成一条看不清。 */
/* .tabs 的布局已改成"左边年月、右边统计卡"的横向排列，见上面的 .tabs 规则。
   原来这条 flex-direction:column 排在后面会把它盖掉（列方向下 align-items:center
   变成水平居中，年份月份会跑到中间）。 */
.yrs{display:flex;gap:3px;padding:5px 0 0}
.yrs .yr{border:none;background:none;padding:3px 11px;border-radius:7px;font-size:11.5px;
  color:var(--mut);cursor:pointer;display:flex;align-items:center;gap:5px}
.yrs .yr:hover{background:var(--band);color:var(--fg2)}
.yrs .yr.on{background:var(--band);color:var(--fg);font-weight:650}
.yrs .yr.warn{color:var(--orange)}
.yrs .yr .n{background:var(--line3);color:var(--mut);border-radius:99px;padding:0 6px;
  font-size:10px;font-variant-numeric:tabular-nums}
/* 月份：一个月一个独立小按钮（Owen 2026-09-02 按参考图定）。
   不套外层容器、不做连体分段控件、不用底部横杠——选中态只靠
   浅蓝底 + 蓝边框 + 深蓝字 + 蓝徽标表达。

   颜色一律走变量，不写死十六进制：参考图给的色值其实就是本项目的调色板
   （#DFE6EE=--line2、#667085=--fg2、#2678B8=--accent），写死会让深色模式
   变成"深色页面上一排白按钮"。只有两个边框蓝没有现成变量，在下面的
   深色区块里单独覆盖。

   align-self:flex-start 必须留着：.tabs 是 flex 竖排，子元素默认 stretch，
   不写就会被拉满整行。 */
.mons{display:flex;align-self:flex-start;flex-wrap:wrap;gap:8px;
  margin:6px 0 8px;padding:0;
  background:none;border:none;border-radius:0;overflow:visible}
.mons button{height:34px;padding:0 12px;border-radius:8px;
  border:1px solid var(--line2);background:var(--card);
  color:var(--fg2);font-size:13px;font-weight:500;
  display:inline-flex;align-items:center;gap:8px;cursor:pointer;
  box-shadow:0 1px 2px rgba(31,41,55,.04);
  transition:background .12s,border-color .12s,color .12s}
.mons button:hover{background:var(--hover);border-color:#b9d2e5;color:var(--accent)}
/* 用 :focus-visible 而不是 :focus —— 鼠标点击不该留下轮廓，只有键盘 Tab 才显示 */
.mons button:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.mons button.on{background:var(--accent-bg);border-color:#76aed3;
  color:var(--accent-h);font-weight:600;box-shadow:none}
@media(prefers-color-scheme:dark){
  /* 浅色那两个边框蓝在深色底上会刺眼；主色字压在深底上只有 3:1，调亮一档 */
  .mons button{box-shadow:none}
  .mons button:hover{border-color:#3f6d8c}
  .mons button.on{border-color:#3f8cc4;color:#7cbaea}
}

/* ---- 提醒条 ---- */
#rem{background:var(--card);border-bottom:1px solid var(--line2);
  padding:6px 20px 10px;max-height:34vh;overflow:auto;
  display:flex;align-items:flex-start;gap:0}
/* 左右两栏：左边交付（更急）、右边出结果。位置即优先级，所以两栏都常驻，
   空了也留着——否则右边那条会滑到左边的位置，看着像很急。 */
.rem-col{flex:1 1 0;min-width:0}
.rem-col.r{border-left:1px solid var(--line2);padding-left:16px;margin-left:16px}
/* 每条提醒锁一行：姓名学校不折行，末尾那句说明放不下就省略号。
   折行会让两栏高度参差不齐，也就毁掉了"左右分区"这个信息本身。 */
.rem-row{flex-wrap:nowrap}
.rem-row .who{white-space:nowrap}
.rem-row .sub{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.rem-h{color:var(--mut);font-size:10.5px;font-weight:650;letter-spacing:.6px;
  padding:2px 8px 3px;display:flex;align-items:center;gap:5px}
.rem-h i{font-style:normal;background:var(--band);border:1px solid var(--line2);
  border-radius:99px;padding:0 5px;font-size:10px;font-variant-numeric:tabular-nums}
#rem.hide{display:none}
.rem-row{display:flex;gap:9px;align-items:baseline;padding:5px 8px;font-size:12.8px;
  cursor:pointer;border-radius:7px;margin:1px 0}
.rem-row:hover{background:var(--hover)}
.rem-row b{font-weight:600;white-space:nowrap}
.pill{font-size:10.5px;padding:2px 8px;border-radius:99px;color:#fff;white-space:nowrap;
  font-weight:600;letter-spacing:.3px}
.rem-empty{color:var(--mut);font-size:12.8px;padding:6px 8px}

/* ---- 表格 ---- */
/* 左侧不能留内边距：冻结列的 left:0 贴的是内容边缘，
   留了内边距，横向滚动的内容就会从那条缝里透出来（看着很乱）。 */
/* 右侧留一段空白：最后一列不再贴着边，它的列宽拖拽手柄也才抓得住 */
.wrap{overflow:auto;flex:1;min-height:0;padding:0 16px 30px 0}
table{border-collapse:separate;border-spacing:0;table-layout:fixed;
  background:var(--card);border-top:1px solid var(--line2);
  border-bottom:1px solid var(--line2)}
th{position:sticky;top:0;z-index:10;background:var(--head);color:var(--fg2);
  font-weight:600;font-size:11.5px;letter-spacing:.4px;text-align:left;
  padding:9px 11px;white-space:nowrap;border-bottom:1px solid var(--line2);
  user-select:none}
/* 列宽拖动手柄 */
/* 列宽调整：和 Excel 一样，直接拖表头的单元格边框，不放可见的手柄。
   热区跨在边框两侧共 9px，光标变成 col-resize 就是提示；
   悬停时把那条边框线加深一点，作为轻量反馈。 */
.grip{position:absolute;top:0;right:-4px;width:9px;height:100%;cursor:col-resize;z-index:5}
.grip:hover{box-shadow:inset -5px 0 0 -4px var(--accent)}
th{position:relative;overflow:visible}
th{position:sticky}
thead th{position:sticky;top:0}
th{overflow:hidden}
/* 竖线分两档（Owen 2026-09-04："很多地方不加细线就不好看，也不好区分"）：
   **每一列都有**一条极浅的竖线（--line），列多了眼睛才跟得住行；
   五个列组的边界用深一档的（--line2），分组结构还看得出来。
   全用一样粗就又变回"一堆小方框"了，全不画就是他说的看不清。 */
td{padding:7px 11px;vertical-align:top;border-bottom:1px solid var(--line);
  border-right:1px solid var(--line);
  font-size:13px;color:var(--fg2);overflow:hidden;text-overflow:ellipsis;
  word-break:break-word;white-space:pre-wrap;border-radius:0}
th{border-right:1px solid var(--line)}
td.grp-end,th.grp-end{border-right-color:var(--line2)}
/* 最后一列按列定义标（JS 的 col-last），**不能用 :last-child**：
   客户级的列是 rowspan 合并的，子行只有 8 个格子，
   :last-child 会误伤子行里的「实际出结果」，那条竖线就断了。 */
td.col-last,th.col-last{border-right:none}
td[colspan]{border-right:none}          /* 「加一个客户」「没有匹配」这种通栏行 */
/* 客户之间**不再**加粗线：隔行底色已经把客户块分开了，再加一条粗线是重复表达
   （Owen 2026-09-04）。tr.bot 就用 td 默认那条细线，跟行与行之间完全一致。 */
tbody tr:last-child td{border-bottom:none}
tbody tr.b1 td{background:var(--band)}
tbody tr:hover td{background:var(--hover)}
tr.flash td{background:var(--wait)!important;transition:background .4s}
/* 不给格子圆角：要的是 Excel 那种横平竖直的线，不是一堆小圆卡片。
   （§12 那条 tbody td{border-radius:0} 压不过 td.ed 的特异度，所以直接在源头写 0。）
   竖线只保留在列组边界，没有竖线的地方维持原样。 */
td.ed{cursor:text;border-radius:0}
td.ed:hover{box-shadow:inset 0 0 0 1px var(--accent)}
/* 纵向：**所有格子一律居中**（Owen 2026-09-08）。
   原来是"客户级的列居中、进展/付款/完工日期/已交付贴顶"，
   于是同一行里有的贴顶有的居中，总价看着比完工日期低一截——他截图指的就是这个。
   进展通常是一行里最高的那格，它居中不居中看不出区别；其余的居中才对得齐。 */
td{vertical-align:middle}
tr.addrow td{vertical-align:top}          /* 「加一个客户」那行不参与 */

/* 横向对齐按**值等不等宽**分（Owen 2026-09-08 让我自己判断）：
     日期  等宽 → 居中，每列自然形成一条整齐的纵带
     数字  等宽 → 靠右，纵向能比大小
     文字  不等宽 → 靠左，每行有共同起点；居中会让起点参差，密集表格更难扫
   账号那列虽然也挂着 .dt 类，但它是身份证号/邮箱，长度不一，所以按文字走、不居中。
   表头必须跟着内容一起对齐，否则表头和数据各站各的。 */
td[data-f="deposit_at"],td[data-f="due_at"],td[data-f="delivered_at"],
td[data-f="eta"],td[data-f="result_at"],td[data-f="start_eta"],
th[data-k="deposit_at"],th[data-k="due_at"],th[data-k="delivered_at"],
th[data-k="eta"],th[data-k="result_at"],th[data-k="start_eta"]{text-align:center}

/* 数字靠右（等宽，纵向可比大小），文字靠左。表头跟着内容走。 */
td.num{text-align:right;font-variant-numeric:tabular-nums;color:var(--fg)}
th.right{text-align:right;padding-right:11px}
th[data-k="seq"]{text-align:center;padding-right:11px}
td.name{font-weight:600;color:var(--fg);white-space:normal;line-height:1.45}
/* 序号是标签不是数量，不需要靠右比大小；居中才能和下面的删除按钮对齐 */
td.seq{color:var(--mut);text-align:center;font-variant-numeric:tabular-nums;
  white-space:nowrap}

/* 阶段：收尾的三个状态（已完成/已失败/已流失）压暗，
   剩下亮着的就是还在手上的活。不加新色相（见 AGENTS.md 第 7 节颜色语义）。 */
td.stage{font-size:12.5px}
td.stage.closed{color:var(--mut)}
td.stage select.cell{width:100%}

/* 完工日期：只有它用底色，所以一眼就能扫到 */
td.due{font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap}
td.due.wait{background:var(--wait)!important;color:var(--wait-t);
  box-shadow:inset 3px 0 0 var(--wait-b)}
td.due.done{background:var(--done)!important;color:var(--done-t);
  box-shadow:inset 3px 0 0 var(--done-b)}
/* 被后面的完工日期替换掉的历史期限：标灰，不参与告警 */
td.due.past,td.eta.past{background:transparent!important;box-shadow:none!important;
  color:var(--mut);font-weight:400;text-decoration:line-through;
  text-decoration-color:var(--line2);background:transparent!important;box-shadow:none!important}
/* 空格子平时不显示占位符，鼠标移上去才提示可以填 */
td.ed:empty::after{content:'';color:var(--mut);opacity:.45;font-size:12px}
td.ed:empty:hover::after{content:'＋'}
td.dt{font-variant-numeric:tabular-nums;white-space:nowrap;color:var(--fg2)}

.prog{line-height:1.7;min-width:230px}
.more{color:var(--accent);font-size:11.5px;cursor:pointer;margin-top:1px;
  user-select:none;font-weight:500}
.more:hover{text-decoration:underline}
.prog>div{padding:0}
.prog .t{color:var(--mut);font-size:11.5px;font-variant-numeric:tabular-nums;
  margin-right:7px}
.sub{color:var(--mut);font-size:11.5px}
.owe{color:var(--orange);font-size:11.5px;font-weight:600}
.ph{color:var(--mut);font-style:normal}

/* 密码：默认打码，点一下复制 */
/* 打码的圆点绝不能换行——列窄了宁可被裁掉，也不要变成两行（很丑）。
   显示真实密码时才允许换行，否则长密码会看不全。 */
.sec{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;
  letter-spacing:1px;color:var(--mut);cursor:pointer;user-select:none;
  white-space:nowrap;display:inline-block;
  padding:2px 7px;border-radius:5px;background:var(--band);border:1px solid var(--line)}
.sec.show{white-space:normal;word-break:break-all}
.sec:hover{color:var(--fg);border-color:var(--accent)}
.sec.show{letter-spacing:0;color:var(--fg)}

input.cell,textarea.cell{font:inherit;font-size:13px;width:100%;min-width:90px;
  border:1px solid var(--accent);border-radius:6px;padding:5px 7px;
  background:var(--card);color:var(--fg);outline:none;
  box-shadow:0 0 0 3px rgba(47,122,181,.13)}
textarea.cell{min-height:74px;resize:vertical;line-height:1.6}
.del{opacity:0;border:none;background:none;color:var(--mut);font-size:14px;
  padding:2px 6px;cursor:pointer;border-radius:5px}
tr:hover .del{opacity:1}
.del:hover{background:var(--hover);color:var(--red)}

/* ---- 弹窗 ---- */
dialog{border:none;border-radius:14px;background:var(--card);color:var(--fg);padding:0;
  max-width:720px;width:92vw;box-shadow:0 16px 48px rgba(16,24,40,.22)}
dialog::backdrop{background:rgba(16,24,40,.35);backdrop-filter:blur(2px)}
.dlg-h{padding:16px 20px;border-bottom:1px solid var(--line);font-weight:600;font-size:15px}
.dlg-b{padding:18px 20px;max-height:64vh;overflow:auto}
.dlg-f{padding:13px 20px;border-top:1px solid var(--line);display:flex;gap:8px;
  justify-content:flex-end;background:var(--band);border-radius:0 0 14px 14px}
.grid{display:grid;grid-template-columns:96px 1fr;gap:10px 14px;align-items:center}
.grid label{color:var(--fg2);font-size:12.5px;text-align:right}
/* 弹窗里的输入框要用卡片色（白），不能用页面底色——
   页面底色 2026-09-02 调深了（为了让顶栏和表格之间那道缝看得见），
   输入框跟着变灰就不像可输入的地方了。 */
.grid input,.grid select{font:inherit;font-size:13px;padding:7px 9px;
  border:1px solid var(--line2);border-radius:7px;background:var(--card);
  color:var(--fg);width:100%}
.grid input:focus,.grid select:focus{outline:none;border-color:var(--accent);
  box-shadow:0 0 0 3px rgba(47,122,181,.13)}
.cand{border:1px solid var(--line2);border-radius:10px;padding:13px 15px;margin-bottom:10px}
.cand h4{margin:0 0 3px;font-size:14px;font-weight:600}
.guess{color:var(--orange);font-size:11.5px;font-weight:600}

#toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%) translateY(8px);
  background:#22262b;color:#fff;padding:10px 18px;border-radius:9px;font-size:13px;
  opacity:0;transition:opacity .18s,transform .18s;pointer-events:none;z-index:99;
  max-width:78vw;box-shadow:0 8px 24px rgba(0,0,0,.24)}
#toast.on{opacity:1;transform:translateX(-50%) translateY(0)}
#toast.err{background:var(--red)}

/* 行高：空行也要有正常高度，否则新加的行细得几乎看不见 */
tbody td{min-height:34px}
tbody tr{height:34px}
/* 这条本意是撑住空行的高度，但会误伤格子里任何第一个子元素
   （比如删除按钮的圆圈被撑成 18×19 的椭圆）。
   行高已由 tbody tr{height} 保证，这条不需要了。 */

/* 加行/删行按钮：放在文字下方、贴单元格左边。
   屏幕小，横向宽度金贵——所以不占一分横向空间，只在鼠标悬停时浮在左下角。 */
td.ed{position:relative}
/* 加行/删行按钮：跟着文字走，排在文字末尾。
   文字一行就跟着那一行、两行就跟着第二行；两行正好排满了自己换到第三行，
   **不压字**（Owen 2026-09-04：绝对定位居中时，两行文字会被按钮盖住）。
   靠正常内联流实现，不用 position——换行是浏览器排的，不用我算。

   仍然不能挂到文字下方左侧：新增一行后正是要点这一格开始打字，
   手指落点跟「－」重合，一不留神整行就没了（空行删除不弹确认）。

   用 visibility 不用 display：位置始终占着，鼠标移上去行高不跳。
   背景取 inherit，跟着隔行底色/悬停色走。 */
.rowbtn{display:inline-flex;gap:2px;visibility:hidden;
  vertical-align:middle;margin-left:4px;
  padding:1px;border-radius:6px;background-color:inherit}
/* 按钮占的横向宽度直接决定"要不要多折一行"，所以这里比别处的 .mini 再小一号 */
.rowbtn .mini{width:16px;height:16px;font-size:10px;border-radius:4px}
tr:hover .rowbtn{visibility:visible}
td:has(input,textarea) .rowbtn{display:none}
.mini{border:1px solid var(--line2);background:var(--card);color:var(--mut);
  width:18px;height:18px;padding:0;border-radius:5px;cursor:pointer;
  font-size:11px;font-weight:600;line-height:1;
  display:flex;align-items:center;justify-content:center}
.mini:hover{border-color:var(--accent);color:var(--accent);background:var(--hover)}

/* 空行给个淡淡的提示，让人知道这行是可以填的 */
tbody td.ed:empty::before{content:'';display:block;height:19px}
tr.blank td{color:var(--mut)}
tr.blank td[data-f="service"]:empty::after,
tr.blank td[data-f="prog"]:empty::after{content:'点这里填';color:var(--mut);opacity:.45;
  font-size:12px}

/* 新加的行闪一下，一眼看到加在哪 */
@keyframes newrow{0%{background:var(--wait)}100%{background:transparent}}
tr.justadded td{animation:newrow 1.6s ease-out}
.ph{color:var(--mut);opacity:.5}
td.prog .t{color:var(--mut);font-size:11.5px;font-variant-numeric:tabular-nums;
  margin-right:6px}

/* 付款：类型 + 金额 */
td.pay .pk{color:var(--fg2)}
td.pay{padding-right:0}
td.pay>div,td.pay .pk{display:inline}
td.pay .pa{float:right;font-variant-numeric:tabular-nums;font-weight:600;color:var(--fg);
  padding-right:11px}
/* 付出去的钱（退款、渠道费）标成暖红，和收进来的一眼区分 */
td.pay .pk.out,td.pay .pa.out{color:var(--red)}

/* 编辑态保持跟显示态同一个形状：左边类型下拉、右边金额，横排一行。
   原来是上下两行堆叠，把整格撑高一倍多——点一下格子就"跳"一大下，
   上下行跟着错位。横排之后点开几乎不改变行高。
   （注意 td.pay>div{display:inline} 排在前面，靠这里的 display:flex 压住。） */
/* 选择器必须写成 td.pay .payedit：前面那条 td.pay>div{display:inline}
   特异度是 (0,1,2)，光写 .payedit (0,1,0) 压不住它——
   之前看到的"上下两行"其实不是 flex，是 inline 容器里两个 100% 宽的块换了行。 */
td.pay .payedit{display:flex;flex-direction:row;align-items:center;gap:4px;width:100%}
td.pay .payedit .cell{box-sizing:border-box;margin:0;min-width:0;
  font-size:12px;line-height:1.4;padding:2px 5px;border-radius:5px;
  box-shadow:0 0 0 2px rgba(47,122,181,.10)}
/* 付款情况列只有 136px，下拉给弹性并允许截断（点开还是完整选项），
   金额定宽靠右——金额是要一眼看数的，不能被挤 */
td.pay .payedit .pk-sel{flex:1 1 auto;width:auto;min-width:0}
td.pay .payedit .pa-in{flex:0 0 56px;width:56px;text-align:right;
  font-variant-numeric:tabular-nums;font-weight:600}
/* 显示态 td.pay 是 padding-right:0（金额靠 float 贴右），
   编辑态得把右padding 还回来，否则金额框贴着格子边 */
td.pay:has(.payedit){padding-right:6px;padding-left:6px}
/* 去掉数字框的上下箭头——都是手动输入，那对箭头只会碍事 */
.payedit .pa-in::-webkit-outer-spin-button,
.payedit .pa-in::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.payedit .pa-in{-moz-appearance:textfield}
/* 顶部统计的样式全在上面的仪表盘卡片规则里。
   这里原来还留着一版"一行灰色小字"的旧样式（align-items:baseline、gap:16px、
   flex-wrap:wrap、字号 13.5px），排在后面会把卡片的排版盖掉，已删除。 */

/* 没收齐的客户：姓名格子左侧一道琥珀色，欠多少另起一行放在姓名下方——
   放在右边会把姓名列撑宽，而横向宽度是最金贵的。 */
td.name.owe{box-shadow:inset 3px 0 0 var(--orange)}
.owe-tag{display:inline-block;margin-top:3px;padding:0 6px;border-radius:5px;
  background:rgba(217,122,31,.13);color:var(--orange);font-size:10.5px;font-weight:650;
  white-space:nowrap;font-variant-numeric:tabular-nums}
.owe-tag.none{background:rgba(201,74,59,.13);color:var(--red)}
/* 统计条开关的样式已并入上面的仪表盘卡片规则 */

/* 官方预计完成时间：3~2天黄 → 1天橙 → 当天及逾期红 → 填了实际出结果转绿 */
td.eta{font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:600}
td.eta.d3{background:var(--w3)!important;color:var(--w3t);box-shadow:inset 3px 0 0 var(--w3b)}
td.eta.d1{background:var(--w1)!important;color:var(--w1t);box-shadow:inset 3px 0 0 var(--w1b)}
td.eta.d0{background:var(--w0)!important;color:var(--w0t);box-shadow:inset 3px 0 0 var(--w0b)}
/* 完工日期未交付时的临近预警，跟官方预计同一套色阶 */
td.due.d3{background:var(--w3)!important;color:var(--w3t);box-shadow:inset 3px 0 0 var(--w3b)}
td.due.d1{background:var(--w1)!important;color:var(--w1t);box-shadow:inset 3px 0 0 var(--w1b)}
td.due.d0{background:var(--w0)!important;color:var(--w0t);box-shadow:inset 3px 0 0 var(--w0b)}
td.eta.done{background:var(--done)!important;color:var(--done-t);
  box-shadow:inset 3px 0 0 var(--done-b);font-weight:400}

/* 左侧固定列：横向滚多远，加行按钮和姓名都还在眼前 */
th.stick,td.stick{position:sticky;z-index:6;background:var(--card)}
tbody tr.b1 td.stick{background:var(--band)}
tbody tr:hover td.stick{background:var(--hover)}
th.stick{z-index:12;background:var(--head)}
/* 固定区和滚动区之间画一条分界 */
th[data-k="name"],td[data-stick="name"]{
  border-right:1px solid var(--line2);
  box-shadow:2px 0 4px -2px rgba(0,0,0,.10)}
tbody tr:hover td[data-stick="name"].owe,tbody td[data-stick="name"].owe{
  box-shadow:inset 3px 0 0 var(--orange),2px 0 4px -2px rgba(0,0,0,.10)}
/* 加行按钮常驻可见，不用等鼠标悬停才出现 */


/* 扫描对话框里的说明条 */
.tip{background:var(--band);border:1px solid var(--line2);border-radius:9px;
  padding:11px 13px;margin-bottom:14px;font-size:12.5px;line-height:1.75;color:var(--fg2)}
.tip b{color:var(--fg)}
.cand h4{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px;
  font-weight:600;word-break:break-all}

td.nowrap{white-space:nowrap}

/* 姓名下方的「N 项 ▾」——点它展开/收起这个客户 */
.foldbtn{display:inline-block;margin-top:3px;padding:1px 7px;border-radius:5px;
  background:var(--band);border:1px solid var(--line2);color:var(--mut);
  font-size:10.5px;font-weight:600;cursor:pointer;white-space:nowrap;user-select:none}
.foldbtn:hover{border-color:var(--accent);color:var(--accent);background:var(--hover)}
/* 折叠行：只读汇总，不给编辑光标 */
/* 折叠行：日期和数字不折行，文字类允许折两行——
   整行 nowrap 会让长文本把列撑爆，也让人看不全学校名。 */
tr.folded td{overflow:hidden}
tr.folded td.dt,tr.folded td.due,tr.folded td.eta,tr.folded td.num,
tr.folded td.nowrap{white-space:nowrap}
/* 用 max-height 限制成两行，不能用 -webkit-box：
   td 的 display 一旦不是 table-cell，整个表格布局就散了。 */
tr.folded td.prog,tr.folded td[data-f="service"],tr.folded td[data-f="school"]{
  white-space:normal;max-height:3.1em;overflow:hidden}
td.folded-cell{cursor:default}
td.folded-cell:hover{box-shadow:none}
tr.folded td.name{white-space:normal}

/* 序号格下方的「删除客户」按钮：圆圈加减号，移到那行才出现 */
/* 序号格：数字在上、删除圆圈在下。
   矮行（比如刚加的空客户）里两者会挤到一起，所以给一个最小高度，
   保证数字底和圆圈顶之间始终有空隙。 */
/* 这里原来写的是 position:relative（给 .delc 当定位锚点），但它排在
   th.stick,td.stick{position:sticky} 后面且特异度相同，把序号列的固定给覆盖了——
   横向滚动时序号列会跟着跑掉。sticky 本身就是定位元素，能当包含块，relative 不需要。 */
td.seq{padding-bottom:26px;min-height:52px}
/* 别用 left:50% 去凑：绝对定位量的是含边框的盒子，文字居中量的是内容区，
   右边多一条 1px 竖线就会差半格。改成让按钮铺满内容区宽度、自己 margin:auto，
   和文字用同一个参照，天然对齐。 */
/* 正圆：flex 布局下 line-height 会把高撑开，必须锁死行高并禁止收缩，
   否则 17×17 会渲染成 17×19 的椭圆 */
.delc{position:absolute;left:0;right:0;margin:0 auto;bottom:4px;
  width:18px;height:18px;min-width:18px;min-height:18px;flex:0 0 auto;
  padding:0;border-radius:50%;box-sizing:border-box;
  border:1px solid var(--line2);background:var(--card);color:var(--mut);
  cursor:pointer;display:none;position:absolute;font-size:0}
/* 减号用 CSS 画，不用字符：
   U+2212 的墨迹中心在基线上方 3.69px，而 flex 居中对齐的是字框不是墨迹，
   视觉上就会偏高；靠字体度量去凑，换个字体又会歪。画出来的位置由几何决定。 */
.delc::before{content:'';position:absolute;left:50%;top:50%;
  width:8px;height:1.5px;border-radius:1px;background:currentColor;
  transform:translate(-50%,-50%)}
tr:hover .delc{display:flex}
.delc:hover{border-color:var(--red);color:var(--red);background:var(--card)}

/* 表尾那行「＋ 加一个客户」 */
/* 加一个客户：**只有圆圈+文字那一小块可点**，不是整条长条
   （Owen 2026-09-04：整条都可点，扫表格时误触过好几次，加出来还得再删） */
/* 加行区：上方留出的空隙和「加一个客户」到下边框的空隙一致（都是 9px），
   原来 tr 的最小高度把内容顶到了下半部分，上方空出 40px。 */
tr.addrow td{border-bottom:none;background:transparent!important;padding:0;
  vertical-align:top;height:auto;white-space:normal;min-height:0}
tr.addrow{height:auto}
tr.addrow:hover td{background:transparent!important}
.addline{display:inline-flex;align-items:center;gap:9px;padding:9px 11px;cursor:pointer;
  margin-top:9px;                     /* 上方空隙 = 内部 padding，上下对称 */
  border-radius:0;transition:background .12s}
.addline:hover{background:var(--hover)}
.addbtn{width:22px;height:22px;min-width:22px;flex:0 0 auto;border-radius:50%;
  border:1px dashed var(--line2);background:var(--card);color:var(--mut);
  font-size:0;padding:0;box-sizing:border-box;cursor:pointer;
  display:inline-block;position:relative}
/* 加号同理：两条杠，横竖各自居中 */
.addbtn::before,.addbtn::after{content:'';position:absolute;left:50%;top:50%;
  background:currentColor;border-radius:1px;transform:translate(-50%,-50%)}
.addbtn::before{width:9px;height:1.5px}
.addbtn::after{width:1.5px;height:9px}
.addline:hover .addbtn{border-color:var(--accent);border-style:solid;color:var(--accent)}
.addline .hint{color:var(--mut);font-size:12.5px}
.addline:hover .hint{color:var(--accent)}
.dlg-f button{border:1px solid var(--line2);background:var(--card);color:var(--fg2);
  padding:6px 15px;border-radius:8px;font-size:13px;cursor:pointer}
.dlg-f button:hover{filter:brightness(1.06)}
.warnbox{background:rgba(201,74,59,.1);border:1px solid rgba(201,74,59,.35);
  color:var(--red);border-radius:9px;padding:11px 13px;font-size:13px;line-height:1.7}
.grid2{display:grid;grid-template-columns:88px 1fr;gap:8px 13px;align-items:baseline}
.grid2 label{color:var(--mut);font-size:12.5px;text-align:right}
.grid2 div{font-size:13px}


/* ═══ 点缀（只用主色的不同浓度，不引入新色相）═══ */

/* 顶栏：极淡的青底 + 一条主色细线，和内容区分开 */
/* 顶栏底色和主色标题已并入上面的 header 规则（原来的 .topbar 类名 HTML 里不存在）*/

/* 年份标签：选中的给一点主色底 */
.yrs .yr.on{background:rgba(47,122,181,.11);color:var(--accent)}
.yrs .yr.on .n{background:var(--accent);color:#fff}
.yrs .yr.warn.on{background:rgba(217,122,31,.13);color:var(--orange-b)}
.yrs .yr.warn.on .n{background:var(--orange-b)}


/* 顶部统计的颜色已在上面的仪表盘卡片规则里定义，这里不再覆盖 */

/* 表头：淡青底 + 底部一条主色细线 */
thead th{border-bottom:1.5px solid rgba(47,122,181,.25)}

/* 客户块隔行：一条淡青、一条纯白，比原来的灰更柔和也更好分辨 */
tbody tr.b1 td{background:var(--band)}
tbody tr.b0 td{background:var(--card)}
tbody tr:hover td{background:var(--hover)!important}

/* 客户块的起止改用左端一小段主色收头，不再靠加粗下边框 */
tbody tr.top td:first-child{box-shadow:inset 2px 0 0 rgba(47,122,181,.35)}
tbody tr.top.owe td:first-child,tbody tr td.name.owe{box-shadow:inset 3px 0 0 var(--orange-b)}

/* 主按钮：从纯色改成很浅的主色底，不抢眼但有存在感 */
#btn-new{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600;
  box-shadow:0 1px 3px rgba(47,122,181,.3)}
#btn-new:hover{filter:brightness(1.08)}

/* 表尾加号：主色虚线圈 */
.addbtn{border-color:rgba(47,122,181,.4);color:var(--accent)}
.addbtn:hover{background:rgba(47,122,181,.08)}


/* ═══ 按方案微调（§5/§6/§11/§12）═══ */
#btn-new{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600;
  box-shadow:var(--sh-btn)}
#btn-new:hover{background:var(--accent-h);border-color:var(--accent-h);
  filter:none;color:#fff}
/* 年份/月份区底部一条极浅整体分隔，把控制区和表格分开 */
/* .tabs 原来自带一条 border-bottom，有三个毛病：被 header 的 20px 左右内边距
   截短、两头不到边；紧贴顶栏自己的下边框，两条叠在一起显得粗；
   颜色用的还是漏进来的近白 --line3。分隔线只留 header 那一条（本来就通栏），
   顶栏底部留出 5pt 让线和月份标签拉开（Owen 2026-09-05）。 */
/* .mons 自己是 display:flex，会盖过 [hidden] 的 display:none，留 2px 残影 */
.mons[hidden]{display:none}
/* 当前看的是哪个月。月份行平时收起，这里就是唯一的交代，也是展开的入口。 */
.cur{border:none;background:none;margin-left:10px;padding:3px 9px;border-radius:7px;
  font-size:12px;font-weight:650;color:var(--accent);cursor:pointer;
  display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.cur:hover{background:var(--accent-bg);border-color:transparent}
/* 三角用 CSS 画，不用字符——字符的墨迹中心和字框中心对不齐，会看着偏 */
.cur .caret{width:0;height:0;border-left:4px solid transparent;
  border-right:4px solid transparent;border-top:4.5px solid currentColor;
  transition:transform .15s}
.cur.open .caret{transform:rotate(180deg)}
.yrs .yr.on{background:var(--accent-bg);color:var(--accent);font-weight:650}
.yrs .yr.on .n{background:var(--accent);color:#fff}
.yrs .yr.warn{color:var(--amber)}
.yrs .yr.warn.on{background:var(--w1);color:var(--w1t)}
.yrs .yr.warn.on .n{background:var(--amber);color:#fff}
/* §11 统计的旧规则已并入上面的仪表盘卡片 */
/* §12 不给行和格子加圆角与阴影 */
table,tbody tr,tbody td{border-radius:0}
.tablewrap{box-shadow:none}
tbody tr.b1 td{background:var(--band)}
tbody tr.b0 td{background:var(--card)}
tbody tr:hover td{background:var(--hover)!important}

/* --line3 深色下变深之后，压在它上面的计数徽章文字要跟着提亮，否则深底深字看不清。
   **必须放在文件末尾**：`.yrs .yr .n` 那条原始规则在第 190 行左右，
   同特异度时后写的赢——写在前面会被它盖掉（2026-09-05 就这么翻过一次）。 */
@media(prefers-color-scheme:dark){.yrs .yr .n{color:var(--fg2)}}
