:root {
  --bg: #F5F7FA;
  --surface: #FFFFFF;
  --surface-2: #F8F9FB;
  --border: #E4E7ED;
  --border-strong: #CDD3DC;
  --text: #1A1D23;
  --text-2: #5F6570;
  --text-3: #939AA6;

  --blue: #185FA5;   --blue-bg: #E6F1FB;
  --green: #1D7A4D;  --green-bg: #E5F5EC;
  --yellow: #B67A00; --yellow-bg: #FDF3DC;
  --orange: #C05A10; --orange-bg: #FDEEE1;
  --red: #C0392B;    --red-bg: #FCEBEA;
  --gray: #6B7280;   --gray-bg: #EFF1F4;
  --purple: #5B4BC4; --purple-bg: #EFEDFC;
  --teal: #0E7C86;   --teal-bg: #E2F4F5;

  --radius: 10px;
  --radius-lg: 14px;
  --shadow: 0 1px 2px rgba(16,24,40,.05), 0 4px 12px rgba(16,24,40,.05);
  --topbar-h: 52px;
  --sidebar-w: 208px;
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font: 14px/1.6 -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
}
.hidden { display: none !important; }
button { font-family: inherit; cursor: pointer; }
a { color: inherit; text-decoration: none; }

/* ============ 登录 ============ */
.auth-screen {
  min-height: 100%; display: flex; align-items: center; justify-content: center;
  padding: 24px; background: linear-gradient(160deg, #EAF1F9 0%, #F5F7FA 55%, #F0EDF9 100%);
}
.auth-card { width: 100%; max-width: 380px; background: var(--surface); border-radius: 16px; padding: 28px; box-shadow: var(--shadow); }
.auth-brand { display: flex; gap: 12px; align-items: center; margin-bottom: 22px; }
.auth-logo, .side-logo {
  width: 38px; height: 38px; border-radius: 10px; flex: 0 0 auto;
  background: var(--blue); color: #fff; display: grid; place-items: center; font-weight: 500; font-size: 17px;
}
.auth-brand h1 { margin: 0; font-size: 16px; font-weight: 500; }
.auth-brand p { margin: 2px 0 0; font-size: 12px; color: var(--text-2); }
.auth-tabs { display: flex; gap: 4px; background: var(--surface-2); padding: 3px; border-radius: 9px; margin-bottom: 18px; }
.auth-tab { flex: 1; padding: 7px; border: 0; background: transparent; border-radius: 7px; font-size: 13px; color: var(--text-2); }
.auth-tab.active { background: var(--surface); color: var(--text); box-shadow: 0 1px 3px rgba(0,0,0,.08); font-weight: 500; }
.field { display: block; margin-bottom: 13px; }
.field > span { display: block; font-size: 12px; color: var(--text-2); margin-bottom: 5px; }
.field input, .field select, .field textarea {
  width: 100%; padding: 9px 11px; border: 1px solid var(--border-strong); border-radius: 9px;
  font-size: 14px; font-family: inherit; background: var(--surface); color: var(--text);
}
.field textarea { min-height: 66px; resize: vertical; line-height: 1.55; }
.field input:focus, .field select:focus, .field textarea:focus { outline: 2px solid var(--blue-bg); border-color: var(--blue); }
.auth-msg { min-height: 18px; font-size: 12px; color: var(--red); margin-bottom: 8px; }
.btn-primary {
  padding: 10px 16px; border: 0; border-radius: 9px; background: var(--blue); color: #fff;
  font-size: 14px; font-weight: 500;
}
.btn-primary:hover { background: #15518d; }
.btn-primary:disabled { opacity: .5; cursor: not-allowed; }
.btn-block { width: 100%; }
.btn-ghost { padding: 8px 14px; border: 1px solid var(--border-strong); border-radius: 8px; background: var(--surface); color: var(--text); font-size: 13px; }
.btn-ghost:hover { background: var(--surface-2); }
.btn-danger { padding: 8px 14px; border: 1px solid var(--red); border-radius: 8px; background: var(--surface); color: var(--red); font-size: 13px; }
/* 小号按钮。
 * 坑：.btn-primary 是 border:0，.btn-ghost/.btn-danger 是 border:1px，
 * 同样 padding:5px 10px 下 ghost/danger 会比 primary 高 2px，
 * 并排放在页头时肉眼能看出「按钮大小不一」。
 * 这里给 .btn-sm 固定高度 + 居中，抹平有无边框的差异。
 * 高度 27px = 5px*2 padding + 12px 字号*1.35 行高 + 2px 边框。 */
.btn-sm { padding: 5px 10px; font-size: 12px; border-radius: 7px; height: 27px; line-height: 1.35; display: inline-flex; align-items: center; justify-content: center; }

/* ============ 框架 ============ */
.topbar {
  height: var(--topbar-h); background: var(--surface); border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between; padding: 0 14px;
  position: sticky; top: 0; z-index: 30;
}
.topbar-left { display: flex; align-items: center; gap: 8px; }
.topbar-title {
  font-size: 15px; font-weight: 500;
  /* 标题不换行，否则窄屏会被挤成两行把顶栏撑高 */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.topbar-left { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; }
.topbar-right { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.topbar-left { display: flex; align-items: center; gap: 8px; }
.today-chip { font-size: 12px; color: var(--text-2); background: var(--surface-2); padding: 4px 9px; border-radius: 7px; white-space: nowrap; }
/* 周次徽标：Week 20 / 52 */
.week-no {
  display: inline-block; margin-left: 7px; padding: 1px 7px; border-radius: 6px;
  background: var(--blue-bg); color: var(--blue);
  font-size: 11px; font-weight: 500; letter-spacing: .02em;
  font-variant-numeric: tabular-nums;
}
.icon-btn {
  width: 32px; height: 32px; border: 0; background: transparent; border-radius: 8px;
  display: grid; place-items: center; color: var(--text-2);
}
.icon-btn:hover { background: var(--surface-2); }
.i-menu, .i-close, .i-refresh { display: block; width: 15px; height: 15px; position: relative; }
.i-menu::before, .i-close::before, .i-close::after, .i-refresh::before, .i-refresh::after { content:''; position:absolute; background:currentColor; }
.i-menu::before { top: 2px; height: 1.5px; width: 15px; box-shadow: 0 5px 0 currentColor, 0 10px 0 currentColor; }
.i-close::before { top: 6px; width: 15px; height: 1.5px; transform: rotate(45deg); }
.i-close::after { top: 6px; width: 15px; height: 1.5px; transform: rotate(-45deg); }
.i-refresh::before { top: 3px; width: 11px; height: 11px; border: 1.5px solid currentColor; border-radius: 50%; background: transparent; border-right-color: transparent; }
.i-refresh::after { width: 4px; height: 1.5px; left: 11px; top: 2px; }

.body-wrap { display: flex; align-items: flex-start; min-height: calc(100vh - var(--topbar-h)); }
.sidebar {
  width: var(--sidebar-w); flex: 0 0 var(--sidebar-w); background: var(--surface);
  border-right: 1px solid var(--border); padding: 12px 10px 24px;
  /* 左侧目录固定：右侧内容再长也不跟着滚 */
  position: sticky; top: var(--topbar-h);
  max-height: calc(100vh - var(--topbar-h)); overflow-y: auto;
}
.side-brand { display: flex; align-items: center; gap: 9px; padding: 6px 8px 16px; font-weight: 500; font-size: 14px; }
.side-logo { width: 28px; height: 28px; font-size: 14px; border-radius: 8px; }
.side-group { padding: 12px 8px 5px; font-size: 11px; color: var(--text-3); letter-spacing: .04em; }
.side-item {
  display: flex; align-items: center; gap: 9px; padding: 8px 9px; border-radius: 8px;
  font-size: 13px; color: var(--text-2); cursor: pointer; margin-bottom: 1px;
}
.side-item:hover { background: var(--surface-2); color: var(--text); }
.side-item.active { background: var(--blue-bg); color: var(--blue); font-weight: 500; }
/* 导航图标：用 SVG mask 绘制真实图形，随 currentColor 变色。
   早期版本这里只是个空心方框占位，所有菜单项图标长得一样，已废弃。 */
.si {
  width: 15px; height: 15px; flex: 0 0 15px; opacity: .85;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center;  mask-position: center;
  -webkit-mask-size: 15px 15px;  mask-size: 15px 15px;
}
.si-home    { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3.2 2.8 11h2.4v9.2h5.2v-5.6h3.2v5.6h5.2V11h2.4z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3.2 2.8 11h2.4v9.2h5.2v-5.6h3.2v5.6h5.2V11h2.4z'/%3E%3C/svg%3E"); }
.si-today   { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7 2v2.4h10V2h2v2.4h1.6A1.6 1.6 0 0 1 22.2 6v13.4a1.6 1.6 0 0 1-1.6 1.6H3.4a1.6 1.6 0 0 1-1.6-1.6V6A1.6 1.6 0 0 1 3.4 4.4H5V2zm-3 6.4v11h16v-11zm3.4 2.6h3.2v3.2H7.4zm5.6 0h3.2v3.2H13zm-5.6 5.4h3.2v3.2H7.4zm5.6 0h3.2v3.2H13z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7 2v2.4h10V2h2v2.4h1.6A1.6 1.6 0 0 1 22.2 6v13.4a1.6 1.6 0 0 1-1.6 1.6H3.4a1.6 1.6 0 0 1-1.6-1.6V6A1.6 1.6 0 0 1 3.4 4.4H5V2zm-3 6.4v11h16v-11zm3.4 2.6h3.2v3.2H7.4zm5.6 0h3.2v3.2H13zm-5.6 5.4h3.2v3.2H7.4zm5.6 0h3.2v3.2H13z'/%3E%3C/svg%3E"); }
.si-week    { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 2v2.4h12V2h2v2.4h.6A2.4 2.4 0 0 1 23 6.8v12.8a2.4 2.4 0 0 1-2.4 2.4H3.4A2.4 2.4 0 0 1 1 19.6V6.8a2.4 2.4 0 0 1 2.4-2.4H4V2zM3 8.6v11h18v-11zm3.2 2.2h4v2.4h-4zm6.4 0h4v2.4h-4zm-6.4 4h4v2.4h-4zm6.4 0h4v2.4h-4z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 2v2.4h12V2h2v2.4h.6A2.4 2.4 0 0 1 23 6.8v12.8a2.4 2.4 0 0 1-2.4 2.4H3.4A2.4 2.4 0 0 1 1 19.6V6.8a2.4 2.4 0 0 1 2.4-2.4H4V2zM3 8.6v11h18v-11zm3.2 2.2h4v2.4h-4zm6.4 0h4v2.4h-4zm-6.4 4h4v2.4h-4zm6.4 0h4v2.4h-4z'/%3E%3C/svg%3E"); }
.si-cal     { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7 2v2.4h10V2h2v2.4h1.6A1.6 1.6 0 0 1 22.2 6v13.4a1.6 1.6 0 0 1-1.6 1.6H3.4a1.6 1.6 0 0 1-1.6-1.6V6A1.6 1.6 0 0 1 3.4 4.4H5V2zm-3 6.6v11h16v-11z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7 2v2.4h10V2h2v2.4h1.6A1.6 1.6 0 0 1 22.2 6v13.4a1.6 1.6 0 0 1-1.6 1.6H3.4a1.6 1.6 0 0 1-1.6-1.6V6A1.6 1.6 0 0 1 3.4 4.4H5V2zm-3 6.6v11h16v-11z'/%3E%3C/svg%3E"); }
.si-list    { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 4h6v6H3zm8 1.6h11v2.8H11zM3 14h6v6H3zm8 1.6h11v2.8H11z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 4h6v6H3zm8 1.6h11v2.8H11zM3 14h6v6H3zm8 1.6h11v2.8H11z'/%3E%3C/svg%3E"); }
.si-repeat  { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 4h9V1.4l4.6 4L15 9.8V7H8a3 3 0 0 0-2.9 2.3l-1.9-.6A5 5 0 0 1 6 4zm12 16H9v2.6l-4.6-4L9 14.2V17h7a3 3 0 0 0 2.9-2.3l1.9.6A5 5 0 0 1 18 20z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 4h9V1.4l4.6 4L15 9.8V7H8a3 3 0 0 0-2.9 2.3l-1.9-.6A5 5 0 0 1 6 4zm12 16H9v2.6l-4.6-4L9 14.2V17h7a3 3 0 0 0 2.9-2.3l1.9.6A5 5 0 0 1 18 20z'/%3E%3C/svg%3E"); }
.si-inbox   { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 4h18a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1zm1 2v8h4l1.2 2h4.6l1.2-2h4V6zm4.6 11.4h6.8l-.8-1.4H9.4z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 4h18a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1zm1 2v8h4l1.2 2h4.6l1.2-2h4V6zm4.6 11.4h6.8l-.8-1.4H9.4z'/%3E%3C/svg%3E"); }
.si-folder  { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M2.6 5.4A1.4 1.4 0 0 1 4 4h5l2 2.6h9A1.4 1.4 0 0 1 21.4 8v10.6a1.4 1.4 0 0 1-1.4 1.4H4a1.4 1.4 0 0 1-1.4-1.4z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M2.6 5.4A1.4 1.4 0 0 1 4 4h5l2 2.6h9A1.4 1.4 0 0 1 21.4 8v10.6a1.4 1.4 0 0 1-1.4 1.4H4a1.4 1.4 0 0 1-1.4-1.4z'/%3E%3C/svg%3E"); }
.si-bank    { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2 1.5 8.2V10h21V8.2zM3 11.4h2.6V19H3zm5 0h2.6V19H8zm5 0h2.6V19H13zm5 0h2.6V19H18zM2 20.4h20V23H2z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2 1.5 8.2V10h21V8.2zM3 11.4h2.6V19H3zm5 0h2.6V19H8zm5 0h2.6V19H13zm5 0h2.6V19H18zM2 20.4h20V23H2z'/%3E%3C/svg%3E"); }
.si-doc     { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 2h8l5 5v15H6a1.4 1.4 0 0 1-1.4-1.4V3.4A1.4 1.4 0 0 1 6 2zm7.4 1.8V8h4.2zM8 11.4v2h8v-2zm0 4v2h8v-2zm0 4v2h5.4v-2z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 2h8l5 5v15H6a1.4 1.4 0 0 1-1.4-1.4V3.4A1.4 1.4 0 0 1 6 2zm7.4 1.8V8h4.2zM8 11.4v2h8v-2zm0 4v2h8v-2zm0 4v2h5.4v-2z'/%3E%3C/svg%3E"); }
.si-chart   { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 3h2.6v18.6H22V24H1.4A1.4 1.4 0 0 1 0 22.6V3zm6 12h2.8v4.6H9zm5.2-6H17v10.6h-2.8zM19.4 3H22v15.6h-2.6z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 3h2.6v18.6H22V24H1.4A1.4 1.4 0 0 1 0 22.6V3zm6 12h2.8v4.6H9zm5.2-6H17v10.6h-2.8zM19.4 3H22v15.6h-2.6z'/%3E%3C/svg%3E"); }
.si-gear    { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 8.4A3.6 3.6 0 1 0 12 15.6 3.6 3.6 0 0 0 12 8.4zm9 4.2v-1.2l-2.2-.7a6.9 6.9 0 0 0-.8-1.9l1.1-2-1.8-1.8-2 1.1a6.9 6.9 0 0 0-1.9-.8L12.7 3H11.3l-.7 2.2a6.9 6.9 0 0 0-1.9.8l-2-1.1L4.9 6.7l1.1 2a6.9 6.9 0 0 0-.8 1.9L3 11.3v1.4l2.2.7c.2.7.4 1.3.8 1.9l-1.1 2 1.8 1.8 2-1.1c.6.4 1.2.6 1.9.8l.7 2.2h1.4l.7-2.2c.7-.2 1.3-.4 1.9-.8l2 1.1 1.8-1.8-1.1-2c.4-.6.6-1.2.8-1.9z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 8.4A3.6 3.6 0 1 0 12 15.6 3.6 3.6 0 0 0 12 8.4zm9 4.2v-1.2l-2.2-.7a6.9 6.9 0 0 0-.8-1.9l1.1-2-1.8-1.8-2 1.1a6.9 6.9 0 0 0-1.9-.8L12.7 3H11.3l-.7 2.2a6.9 6.9 0 0 0-1.9.8l-2-1.1L4.9 6.7l1.1 2a6.9 6.9 0 0 0-.8 1.9L3 11.3v1.4l2.2.7c.2.7.4 1.3.8 1.9l-1.1 2 1.8 1.8 2-1.1c.6.4 1.2.6 1.9.8l.7 2.2h1.4l.7-2.2c.7-.2 1.3-.4 1.9-.8l2 1.1 1.8-1.8-1.1-2c.4-.6.6-1.2.8-1.9z'/%3E%3C/svg%3E"); }
.side-badge { margin-left: auto; background: var(--orange); color: #fff; font-size: 11px; min-width: 17px; height: 17px; border-radius: 9px; display: grid; place-items: center; padding: 0 5px; }
.side-badge:empty { display: none; }

.loading { padding: 40px; text-align: center; color: var(--text-3); }

/* ============ 通用组件 ============ */
.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; }
.page-head h2 { margin: 0; font-size: 17px; font-weight: 500; }
.page-head p { margin: 3px 0 0; font-size: 12px; color: var(--text-2); }
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow); margin-bottom: 14px; }
.card-head { padding: 13px 15px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.card-head h3 { margin: 0; font-size: 14px; font-weight: 500; }
.card-head .sub { font-size: 12px; color: var(--text-3); }
.card-body { padding: 14px 15px; }
.card-body.tight { padding: 8px; }

/* 指标卡：用 auto-fit + minmax 会让 9 个卡片排成 8+1 的孤行，
   改为固定基准 + 足够窄的下限，使列数随容器均匀分布。 */
.metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 9px; margin-bottom: 14px; }
.metric {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 11px 13px; cursor: pointer; transition: .12s;
}
.metric:hover { border-color: var(--border-strong); transform: translateY(-1px); }
.metric-n { font-size: 23px; font-weight: 500; line-height: 1.15; }
.metric-l { font-size: 12px; color: var(--text-2); margin-top: 3px; }
.metric.zero .metric-n { color: var(--text-3); }
.metric.alert .metric-n { color: var(--red); }
.metric.warn .metric-n { color: var(--orange); }
.metric.ok .metric-n { color: var(--green); }

.cols { display: grid; gap: 14px; }
.cols-2 { grid-template-columns: 1fr 1fr; }
.cols-3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 900px) { .cols-2, .cols-3 { grid-template-columns: 1fr; } }

/* 瀑布流双列（设置页专用）。
 * 坑：设置页 11 张卡被塞进 .cols-2 的两个子 div 里，左边只 3 张（1033px）、
 * 右边 8 张（3905px），容器高 4017px → 左列底部空出 2872px 近 3 屏，
 * 滚到底时左边早就是空白，看着像内容丢了。
 * grid 默认按行对齐，卡片高度差一多就必然留洞。
 *
 * 解法：设置页不用 grid 两列，改用 CSS multi-column —— 所有卡片平铺，
 * 浏览器自动顺流分配到左右两列，列高自动接近。卡片不会被拦腰截断。
 * 注意是「卡片平铺 + column-count:2」，不是「两个子 div 各排一列」——
 * 后者是两个独立容器，浏览器无法互相补偿高度，洞还是会有。
 */
.cols-masonry {
  display: block;              /* 覆盖 .cols 的 grid */
  column-count: 2;
  column-gap: 14px;
  column-fill: balance;
}
.cols-masonry > .card {
  break-inside: avoid;         /* 卡片不被分列截断 */
  -webkit-column-break-inside: avoid;
  page-break-inside: avoid;
  display: block;
  width: 100%;
  margin-bottom: 14px;
}
/* 卡片内部的表格/表单也不能被分列切开 */
.cols-masonry .card-head,
.cols-masonry .card-body { break-inside: avoid; }
@media (max-width: 900px) {
  .cols-masonry { column-count: 1; }
}

/* ============ 设置页：左侧分组目录 + 右侧内容 ============
 * 2026-10-20 重构。原来 11 张卡平铺一页，高 3074px 要滚 3 屏；
 * 改成左侧一列目录（4 组）、右侧只显示当前组，一屏装得下。
 *
 * 目录宽度固定 176px：它是「可点的地方」，不是内容区。
 * 窄屏（<1100px）折叠成图标条 —— 否则内容区被挤到只剩 500px，
 * 表格就得横向滚，反而更难用。
 */
.set-layout {
  display: grid;
  grid-template-columns: 176px minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}
.set-nav {
  position: sticky; top: 12px;
  display: flex; flex-direction: column; gap: 2px;
}
.set-nav-t {
  font-size: 11.5px; color: var(--text-3);
  padding: 0 8px 6px;
}
/* 组容器 */
.set-nav-g { display: block; }
/* 目录项：两行 —— 名称 + 规模（如「4 个板块 · 14 个角色」） */
.set-nav-i {
  display: block; width: 100%; text-align: left;
  background: none; border: 0; cursor: pointer;
  padding: 8px 10px; border-radius: 8px;
  font: inherit; color: var(--text-2);
  transition: background .12s, color .12s;
}
.set-nav-i:hover { background: var(--surface-2); color: var(--text); }
.set-nav-g.on > .set-nav-i { background: var(--surface-2); color: var(--text); font-weight: 500; }
.set-nav-i .ni-t { display: block; font-size: 13.5px; line-height: 1.35; }
/* 短标签：窄屏才显示 */
.set-nav-i .ni-abbr { display: none; }
.set-nav-i .ni-c {
  display: block; font-size: 11px; color: var(--text-3);
  margin-top: 2px; line-height: 1.3;
  font-variant-numeric: tabular-nums;
}
/* 组内子项：缩进一格，名字 + 规模 */
.set-nav-sub { padding: 1px 0 6px 6px; }
.set-sub-i {
  display: flex; align-items: baseline; gap: 6px; width: 100%; text-align: left;
  background: none; border: 0; cursor: pointer;
  padding: 5px 8px 5px 12px; border-radius: 7px;
  font: inherit; color: var(--text-3);
  border-left: 1.5px solid var(--border);
  /* 名字长了要能截断 —— 176px 的目录塞不下「角色与人员对应 14 个角色」 */
  min-width: 0;
}
.set-sub-i:hover { background: var(--surface-2); color: var(--text-2); }
.set-sub-i.on { color: var(--text); font-weight: 500; border-left-color: var(--text-2); }
.set-sub-i .si-t {
  font-size: 12.5px; line-height: 1.4;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.set-sub-i .si-c {
  font-size: 10.5px; color: var(--text-3); margin-left: auto;
  flex: none;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* 右侧内容区顶部的面包屑（当前在哪个组、哪一条） */
.set-crumb {
  font-size: 12px; color: var(--text-3); margin-bottom: 10px;
  padding-bottom: 8px; border-bottom: 1px solid var(--border);
}
/* 行数多的表格（模块 21 行、角色 14 行）内部滚动，
   否则单张卡就超一屏。表头跟着一起滚（不做 sticky），
   因为卡内还有 info-box 占位，sticky 表头会错位。
   ⚠️ 内滚动一定要给滚动条 —— 否则表格被拦腰切断，
   用户看着像渲染坏了（截图里就这么误判过一次）。 */
.set-tbl-scroll {
  max-height: 420px; overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
.set-tbl-scroll::-webkit-scrollbar { width: 8px; }
.set-tbl-scroll::-webkit-scrollbar-track { background: transparent; }
.set-tbl-scroll::-webkit-scrollbar-thumb {
  background: var(--border-strong); border-radius: 4px;
  border: 2px solid var(--surface);
}
.set-tbl-scroll::-webkit-scrollbar-thumb:hover { background: var(--text-3); }
/* 底部渐隐：告诉用户「下面还有内容」，否则被拦腰切断像渲染坏了。
   ⚠️ 渐变层要跟着内容一起滚（position:sticky 放在滚动容器里），
   用 absolute 盖在容器上会一直浮在底部、滚到底也不消失，反而挡字。 */
.set-tbl-fade {
  position: sticky; bottom: 0; left: 0;
  height: 24px; margin-top: -24px;
  background: linear-gradient(to bottom, transparent, var(--surface));
  pointer-events: none;
}
/* 窄屏专用的组内条目横条。宽屏隐藏（左侧目录已有子项，两处不同时出现） */
.set-tabs { display: none; }
.set-tab {
  background: none; border: 1px solid var(--border); border-radius: 7px;
  padding: 4px 10px; font: inherit; font-size: 12.5px; color: var(--text-2);
  cursor: pointer; white-space: nowrap;
}
.set-tab.on { background: var(--surface-2); color: var(--text); font-weight: 500; }
/* 窄屏：目录变图标条。组名用 title 提示，条目显示两字短标签。 */
@media (max-width: 1100px) {
  .set-layout { grid-template-columns: 46px minmax(0, 1fr); gap: 12px; }
  .set-nav-t { display: none; }
  .set-nav-i { padding: 8px 0; text-align: center; }
  .set-nav-i .ni-t { display: none; }
  .set-nav-i .ni-abbr {
    display: block; font-size: 12px; font-weight: 600; line-height: 1.3;
    letter-spacing: .5px;
  }
  .set-nav-i .ni-c { display: none; }
  /* 窄屏放不下子项（46px 宽），改用内容区顶部的一排横条 */
  .set-nav-sub { display: none; }
  .set-tabs {
    display: flex; gap: 6px; flex-wrap: wrap;
    margin-bottom: 12px; padding-bottom: 12px;
    border-bottom: 1px solid var(--border);
  }
  .set-crumb { display: none; }
}

table.tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
table.tbl th { text-align: left; font-weight: 400; color: var(--text-2); font-size: 12px; padding: 8px 10px; border-bottom: 1px solid var(--border); white-space: nowrap; }
/* 数字列表头必须右对齐。
   ⚠️ 上面的 `table.tbl th { text-align:left }` 特异性是 (0,0,1,2)，
   比 `.num { text-align:right }` 的 (0,0,1,0) 高，
   所以 `th.num` 拿不到右对齐 —— 表头文字贴在列左、数据贴在列右，
   标题和下方内容对不上（同一条竖线）。
   这条必须写成 `table.tbl th.num`（特异性 0,0,2,2）才压得住。
   2026-10-20 实测：分析看板 3 张表 20 个列全部中招，
   周期模板页 / 团队视图 / 设置页备份表同样中招 —— 一条规则全站修好。 */
table.tbl th.num { text-align: right; }
/* 操作列：表头和按钮统一右对齐。
   最后一列被 `td:last-child{width:1%}` 压到内容宽度，右对齐才贴得住右边界。
   ⚠️ 不能靠 `td:last-child{text-align:right}` 一刀切 ——
   有些表的最后一列是「状态」「大小」等文本列，会被误伤。 */
table.tbl th.act, table.tbl td.act { text-align: right; }
table.tbl td { padding: 9px 10px; border-bottom: 1px solid var(--border); vertical-align: middle; }
/* 操作列的按钮不能被压成竖排文字（表格 nowrap 会把窄列里的「编辑」挤成两行） */
table.tbl td:last-child { white-space: nowrap; width: 1%; }
table.tbl tr:last-child td { border-bottom: 0; }
table.tbl tbody tr:hover { background: var(--surface-2); }

/* 板块权重条：本周 / 本月各板块占比
   样式统一在下方 594 行附近定义（早期版本重复定义过 .wbar，
   宽度一个用 calc(100% - 40px)、一个用 84px，互相覆盖导致排版错乱）。 */
.wcol { white-space: nowrap; }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.sub { font-size: 11px; color: var(--text-3); font-weight: 400; }
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.mini-select {
  padding: 5px 8px; border: 1px solid var(--border-strong); border-radius: 7px;
  background: var(--surface); color: var(--text); font-size: 12px; font-family: inherit;
}
.notice {
  background: var(--yellow-bg); color: var(--yellow); padding: 10px 12px;
  border-radius: 9px; font-size: 13px; line-height: 1.6;
}

/* 风险色条 */
.tag {
  display: inline-flex; align-items: center; gap: 4px; padding: 2px 7px; border-radius: 6px;
  font-size: 11px; line-height: 1.5; white-space: nowrap; font-weight: 500;
}
.tag-normal { background: var(--blue-bg); color: var(--blue); }
.tag-soon   { background: var(--yellow-bg); color: var(--yellow); }
.tag-today   { background: var(--orange-bg); color: var(--orange); }
.tag-overdue { background: var(--red-bg); color: var(--red); }
.tag-blocked { background: var(--orange-bg); color: var(--orange); }
.tag-p0      { background: var(--red-bg); color: var(--red); }
.tag-hold    { background: var(--gray-bg); color: var(--gray); }
.tag-reopen  { background: var(--purple-bg); color: var(--purple); }
.tag-done    { background: var(--green-bg); color: var(--green); }
.tag-cancelled { background: var(--gray-bg); color: var(--text-3); }
.prio { font-size: 11px; font-weight: 500; padding: 1px 6px; border-radius: 5px; }
.prio-P0 { background: var(--red-bg); color: var(--red); }
.prio-P1 { background: var(--orange-bg); color: var(--orange); }
.prio-P2 { background: var(--blue-bg); color: var(--blue); }
.prio-P3 { background: var(--gray-bg); color: var(--text-3); }

/* 任务行 */
.tlist { display: flex; flex-direction: column; }
.titem {
  display: flex; gap: 10px; align-items: flex-start; padding: 10px 11px;
  border-bottom: 1px solid var(--border); cursor: pointer;
}
.titem:last-child { border-bottom: 0; }
.titem:hover { background: var(--surface-2); }
.titem.flag-overdue { box-shadow: inset 3px 0 0 var(--red); }
.titem.flag-today { box-shadow: inset 3px 0 0 var(--orange); }
.titem.flag-soon { box-shadow: inset 3px 0 0 var(--yellow); }
.titem.flag-blocked { box-shadow: inset 3px 0 0 var(--orange); }
.titem.flag-done { box-shadow: inset 3px 0 0 var(--green); }
.tmain { flex: 1; min-width: 0; }
.ttitle { font-size: 13px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.ttitle.closed { color: var(--text-3); text-decoration: line-through; }
.tmeta { font-size: 12px; color: var(--text-2); margin-top: 3px; display: flex; gap: 10px; flex-wrap: wrap; }
.tmeta span { display: inline-flex; align-items: center; gap: 3px; }
.tflags { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 5px; }
.flag-tag { font-size: 11px; padding: 1px 6px; border-radius: 5px; background: var(--gray-bg); color: var(--text-2); }
.flag-tag.blocked { background: var(--orange-bg); color: var(--orange); }
.flag-tag.need_manager { background: var(--red-bg); color: var(--red); }
.flag-tag.waiting_feedback { background: var(--yellow-bg); color: var(--yellow); }
.flag-tag.quality_issue { background: var(--purple-bg); color: var(--purple); }
.flag-tag.due_changed { background: var(--blue-bg); color: var(--blue); }
.tdue { flex: 0 0 auto; text-align: right; font-size: 12px; color: var(--text-2); min-width: 74px; }
.tdue .d-od { color: var(--red); font-weight: 500; }
.tdue .d-soon { color: var(--orange); }
.tdue .d-date { font-variant-numeric: tabular-nums; }

.chk {
  width: 17px; height: 17px; flex: 0 0 17px; border: 1.5px solid var(--border-strong);
  border-radius: 5px; margin-top: 2px; display: grid; place-items: center; background: var(--surface);
}
.chk:hover { border-color: var(--green); }
.chk.done { background: var(--green); border-color: var(--green); }
.chk.done::after { content: ''; width: 8px; height: 4px; border-left: 1.5px solid #fff; border-bottom: 1.5px solid #fff; transform: rotate(-45deg) translate(1px,-1px); }

/* 筛选栏 */
.filters { display: flex; gap: 7px; flex-wrap: wrap; align-items: center; margin-bottom: 12px; }
.filters select, .filters input {
  padding: 6px 9px; border: 1px solid var(--border-strong); border-radius: 8px;
  font-size: 12px; font-family: inherit; background: var(--surface); color: var(--text);
}
.filters input[type=search] { width: 168px; }
.chipbar { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }
.fchip {
  padding: 5px 11px; border: 1px solid var(--border-strong); border-radius: 16px;
  font-size: 12px; background: var(--surface); color: var(--text-2);
}
.fchip.active { background: var(--blue); border-color: var(--blue); color: #fff; }

/* 空状态 */
.empty { padding: 30px 16px; text-align: center; color: var(--text-3); font-size: 13px; }

/* 抽屉 */
.drawer-mask { position: fixed; inset: 0; background: rgba(16,24,40,.32); opacity: 0; pointer-events: none; transition: .2s; z-index: 40; }
/* 抽屉打开时禁用弹窗遮罩的点击，防止关弹窗后残留遮罩吃掉抽屉上的点击 */
.modal-mask.hidden { display: none !important; }
.drawer-mask.on { opacity: 1; pointer-events: auto; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: 480px; max-width: 100%;
  background: var(--surface); box-shadow: -4px 0 24px rgba(16,24,40,.12);
  transform: translateX(100%); transition: transform .22s ease; z-index: 46;
  display: flex; flex-direction: column;
}
.drawer.on { transform: translateX(0); }
.drawer-head { padding: 13px 16px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; }
.drawer-body { flex: 1; overflow-y: auto; padding: 15px 16px 28px; }
.drawer-sec { margin-bottom: 17px; }
.drawer-sec > h4 { margin: 0 0 8px; font-size: 12px; color: var(--text-3); font-weight: 400; }
.row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
/* 带前缀标签的紧凑输入：用于「P0/P1/P2/P3 阈值」这类需要说明对应关系的数字框 */
.mini-field { display: flex; align-items: center; gap: 7px; }
.mini-field i {
  font-style: normal; font-size: 12px; font-weight: 600; color: var(--text-2);
  min-width: 24px; text-align: center; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 6px; padding: 3px 0;
}
.mini-field input { flex: 1; min-width: 0; }

/* 复选框网格：用于「负责模块（可多选）」「板块能力复选框」这类密集勾选区。
   注意：文字竖排是因为 grid 列宽被 flex 子元素挤压后 span 只能逐字换行。
   这里给 span 显式 flex:1 + white-space:nowrap，并让列宽自适应内容。 */
.checkgrid {
  max-height: 190px; overflow-y: auto;
  border: 1px solid var(--border); border-radius: 8px; padding: 9px;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 6px;
}
.checkgrid label {
  display: flex; align-items: center; gap: 6px;
  font-size: 12.5px; color: var(--text); cursor: pointer;
  min-width: 0; padding: 2px 0;
}
/* 真凶是上面那条 `.field input { width: 100% }` ——
   选人复选框的 <label> 写在 .field 内部，复选框于是继承了 width:100%，
   撑满整列（实测 165px，和列宽一模一样），把人名 span 挤成 0 宽。
   症状：设置页「新增角色 / 调整承担人 / 新增模块」里所有选人复选框只有方框、没有人名。
   光写 `flex: 0 0 auto` 赢不过 width:100%（两者都作用于同一个盒子，width 先算），
   必须显式把 width 打回 auto。
   下面 span 用 flex:1 1 0（basis 为 0，由 grow 分配剩余空间）。 */
.checkgrid label > input[type=checkbox], .checkgrid label > input[type=radio] {
  flex: 0 0 auto; width: auto; margin: 0;
}
.checkgrid label > span { flex: 1 1 0; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.pickrow { display: flex; gap: 5px; flex-wrap: wrap; }
.pick {
  padding: 5px 11px; border: 1px solid var(--border-strong); border-radius: 7px;
  font-size: 12px; background: var(--surface); color: var(--text-2);
}
.pick.on { background: var(--blue-bg); border-color: var(--blue); color: var(--blue); font-weight: 500; }
.pick.on.red { background: var(--red-bg); border-color: var(--red); color: var(--red); }
.pick.on.orange { background: var(--orange-bg); border-color: var(--orange); color: var(--orange); }
.drawer-foot { display: flex; gap: 8px; padding-top: 12px; border-top: 1px solid var(--border); }
.hint { font-size: 11px; color: var(--text-3); margin-top: 4px; }

/* 弹窗 */
.modal-mask { position: fixed; inset: 0; background: rgba(16,24,40,.4); display: grid; place-items: center; z-index: 60; padding: 16px; }
.modal { background: var(--surface); border-radius: var(--radius-lg); width: 100%; max-width: 560px; max-height: 86vh; display: flex; flex-direction: column; box-shadow: 0 12px 40px rgba(16,24,40,.2); }
.modal-head { padding: 14px 16px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; }
.modal-body { padding: 16px; overflow-y: auto; }
.modal-foot { padding: 12px 16px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 8px; }

/* 表单分组：长表单必须分区，否则所有字段平铺一片、看不出必填还是选填。
   分组顺序按「先回答这是什么 → 谁来做 → 什么时候」这种自然提问顺序排。 */
.form-sec { padding: 14px 0 4px; border-bottom: 1px solid var(--border); }
.form-sec:first-child { padding-top: 0; }
.form-sec:last-child { border-bottom: none; padding-bottom: 0; }
.form-sec-h {
  font-size: 11.5px; color: var(--text-3); font-weight: 500;
  letter-spacing: .04em; margin-bottom: 11px;
}
.form-sec-h::before {
  content: ''; display: inline-block; width: 3px; height: 11px;
  background: var(--blue); border-radius: 2px; margin-right: 6px; vertical-align: -1px;
}

/* 折叠区：把「暂时填不了也没关系」的字段收起来，首屏只留真正要判断的东西 */
.fold { margin-top: 12px; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.fold > summary {
  list-style: none; cursor: pointer; padding: 10px 13px; font-size: 13px;
  color: var(--text-2); background: var(--bg); user-select: none;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary::after { content: '▾'; color: var(--text-3); font-size: 11px; }
.fold[open] > summary::after { content: '▴'; }
.fold > summary:hover { background: var(--blue-bg); color: var(--blue); }
.fold-body { padding: 13px; border-top: 1px solid var(--border); }
.fold-tip { font-size: 11px; color: var(--text-3); font-weight: 400; margin-left: auto; }

/* 一句话录入：首页第一眼就能用，输入时实时回显「系统读到了什么」 */
.quickadd {
  background: var(--surface); border: 1px solid var(--blue);
  border-radius: var(--radius-lg); padding: 13px 15px; margin-bottom: 15px;
}
.qa-row { display: flex; gap: 8px; }
.qa-input {
  flex: 1; height: 38px; padding: 0 12px; font-size: 14px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); color: var(--text); font-family: inherit;
}
.qa-input:focus { outline: 2px solid var(--blue-bg); border-color: var(--blue); }
.qa-hint { font-size: 11.5px; color: var(--text-3); margin-top: 8px; line-height: 1.6; }
.qa-preview { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.qa-chip {
  font-size: 12px; padding: 3px 9px; border-radius: 20px;
  border: 1px solid var(--border); background: var(--bg); color: var(--text-2);
}
.qa-chip.qa-title { border-color: var(--blue); color: var(--blue); background: var(--blue-bg); font-weight: 500; }
.qa-chip.qa-cycle { border-color: #B5D4F4; background: #E6F1FB; color: #185FA5; }
.qa-chip.qa-date { border-color: #F5C4B3; background: #FAECE7; color: #993C1D; }
.qa-chip.qa-owner { border-color: #9FE1CB; background: #E1F5EE; color: #0F6E56; }
.qa-chip.qa-board { border-color: #CECBF6; background: #EEEDFE; color: #534AB7; }
.qa-chip.qa-warn { border-color: #FAC775; background: #FAEEDA; color: #854F0B; }

/* 「新建任务」弹窗：上半句一句话录入，下半句两条路并存。
   .quickadd 是旧页面级横幅的样式，已随 quickAddBar 一起废弃，留着不影响。 */
.ask-box {
  background: var(--blue-bg); border: 1px solid var(--blue);
  border-radius: var(--radius-lg); padding: 13px 14px;
}
.ask-box .qa-input { background: var(--surface); }
/* 「或者直接选」分隔线：上下都留白，让两条路在视觉上平等、不像主次从属 */
.ask-or {
  display: flex; align-items: center; gap: 10px;
  margin: 15px 0 11px; color: var(--text-3); font-size: 11.5px;
}
.ask-or::before, .ask-or::after { content: ''; flex: 1; height: 1px; background: var(--border); }
.nature-btn { width: 100%; cursor: pointer; }
.nature-btn:hover { border-color: var(--blue); background: var(--blue-bg); }

/* Toast */
.toast-wrap { position: fixed; top: 62px; left: 50%; transform: translateX(-50%); z-index: 90; display: flex; flex-direction: column; gap: 7px; align-items: center; }
.toast { background: #23272F; color: #fff; padding: 8px 15px; border-radius: 9px; font-size: 13px; box-shadow: var(--shadow); animation: tin .2s ease; max-width: 82vw; text-align: center; line-height: 1.5; }
.toast.err { background: var(--red); }
.toast.ok { background: var(--green); }
@keyframes tin { from { opacity: 0; transform: translateY(-8px); } }

.side-mask { display: none; }

/* ============ 移动端 ============ */
.only-mobile { display: none !important; }

@media (max-width: 768px) {
  .only-mobile { display: grid !important; }
  .sidebar {
    position: fixed; top: var(--topbar-h); bottom: 0; left: 0; z-index: 35;
    transform: translateX(-100%); transition: transform .22s; width: 230px; flex-basis: 230px;
    padding-top: 8px;
  }
  .sidebar.on { transform: translateX(0); }
  .side-mask { display: block; position: fixed; inset: var(--topbar-h) 0 0; background: rgba(16,24,40,.3); opacity: 0; pointer-events: none; transition: .2s; z-index: 34; }
  .side-mask.on { opacity: 1; pointer-events: auto; }
  .main { padding: 12px; }
  .topbar-title { font-size: 14px; }
  /* 窄屏隐藏本周区间，日期信息在首页指标区已有，避免挤占标题空间 */
  .today-chip .week-range { display: none; }
  .metrics { grid-template-columns: repeat(3, 1fr); gap: 7px; }
  .metric { padding: 9px 10px; }
  .metric-n { font-size: 19px; }
  .metric-l { font-size: 11px; }
  .card-head { padding: 11px 13px; }
  .card-body { padding: 12px 13px; }
  .titem { padding: 9px 8px; }
  .tdue { min-width: 60px; font-size: 11px; }
  .drawer { width: 100%; top: 6vh; border-radius: 16px 16px 0 0; }
  .row2 { grid-template-columns: 1fr; }
  table.tbl { font-size: 12px; }
  table.tbl th, table.tbl td { padding: 7px 6px; }
  .hide-m { display: none !important; }
  .page-head h2 { font-size: 15px; }
  .filters input[type=search] { width: 100%; }
  /* 窄屏下复选框改单列，避免文字被挤压换行 */
  .checkgrid { grid-template-columns: 1fr; }
}
@media (max-width: 400px) {
  .metrics { grid-template-columns: repeat(2, 1fr); }
}

/* 日历 */
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.cal-h { background: var(--surface-2); padding: 7px 4px; text-align: center; font-size: 12px; color: var(--text-2); }
.cal-d { background: var(--surface); min-height: 74px; padding: 4px; }
.cal-d.out { background: var(--surface-2); opacity: .5; }
.cal-d.today { box-shadow: inset 0 0 0 2px var(--blue); }
.cal-d .dn { font-size: 12px; color: var(--text-2); margin-bottom: 3px; display: flex; justify-content: space-between; }
.cal-d.holiday .dn { color: var(--red); }
.cal-d .ev { font-size: 11px; padding: 1px 4px; border-radius: 4px; margin-bottom: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cal-more { font-size: 10px; color: var(--text-3); padding-left: 4px; }
@media (max-width: 768px) { .cal-d { min-height: 52px; } .cal-d .ev { font-size: 10px; } }

/* 周报 */
.report-text {
  white-space: pre-wrap; font: 13px/1.75 ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--surface-2); padding: 14px; border-radius: var(--radius); max-height: 54vh; overflow-y: auto;
}
.report-edit { width: 100%; min-height: 380px; font: 13px/1.75 ui-monospace, monospace; padding: 12px; border: 1px solid var(--border-strong); border-radius: var(--radius); font-family: inherit; }

/* 条形图 */
.bar { height: 7px; border-radius: 4px; background: var(--gray-bg); overflow: hidden; min-width: 42px; }
.bar > i { display: block; height: 100%; background: var(--blue); border-radius: 4px; }
.bar > i.over { background: var(--red); }
.bar > i.warn { background: var(--orange); }
.bar > i.ok { background: var(--green); }

.kv { display: grid; grid-template-columns: auto 1fr; gap: 6px 12px; font-size: 13px; }
.kv dt { color: var(--text-2); white-space: nowrap; }
.kv dd { margin: 0; }

.timeline { position: relative; padding-left: 18px; }
.timeline::before { content: ''; position: absolute; left: 5px; top: 4px; bottom: 4px; width: 1.5px; background: var(--border); }
.tl-item { position: relative; padding-bottom: 11px; }
.tl-item::before { content: ''; position: absolute; left: -16px; top: 5px; width: 7px; height: 7px; border-radius: 50%; background: var(--blue); }
.tl-item.od::before { background: var(--red); }
.tl-time { font-size: 11px; color: var(--text-3); }
.tl-text { font-size: 12px; color: var(--text-2); }

.warn-box { background: var(--yellow-bg); border: 1px solid #EFD9A0; border-radius: var(--radius); padding: 11px 13px; font-size: 12.5px; color: #7A5600; margin-bottom: 13px; }
.warn-box b { font-weight: 500; }
.info-box { background: var(--blue-bg); border: 1px solid #BCD8F2; border-radius: var(--radius); padding: 11px 13px; font-size: 12.5px; color: #124A85; margin-bottom: 13px; }
/* ============ 任务类型标识（周期 / 专项 / 临时） ============ */
/* 靠「颜色 + 文字 + 位置」三重编码区分，不依赖单一颜色，兼顾色弱用户 */
.kind-badge {
  display: inline-block; font-size: 10.5px; font-weight: 600;
  padding: 1px 5px; border-radius: 4px; letter-spacing: .3px;
  flex-shrink: 0; line-height: 1.5;
}
.kind-badge.cycle { background: var(--blue-bg); color: var(--blue); border: 1px solid #BCD8F2; }
.kind-badge.special { background: var(--purple-bg); color: var(--purple); border: 1px solid #D5CFF5; }
.kind-badge.adhoc { background: var(--gray-bg); color: var(--text-2); border: 1px solid var(--border-strong); }
.kind-freq {
  font-size: 10.5px; color: var(--text-2); background: var(--surface-2);
  border: 1px solid var(--border); padding: 1px 5px; border-radius: 4px;
}
.kind-name {
  font-size: 11.5px; color: var(--purple); font-weight: 500;
}

/* 任务行左侧色条区分类型，与类型标签互为冗余提示 */
.titem[data-kind="cycle"]   { box-shadow: inset 3px 0 0 var(--blue); }
.titem[data-kind="special"] { box-shadow: inset 3px 0 0 var(--purple); }
.titem[data-kind="adhoc"]   { box-shadow: inset 3px 0 0 var(--border-strong); }

/* ============ 周期分组（常规周期视图） ============ */
.cycle-group { margin-bottom: 14px; }
.cycle-group-head {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 2px 8px; border-bottom: 1.5px solid var(--border);
  margin-bottom: 4px;
}
.cycle-group-head h3 { margin: 0; font-size: 14px; font-weight: 600; }
.cycle-group-head .sub { font-size: 12px; color: var(--text-3); }
.cycle-group-head .spacer { flex: 1; }

/* 专项状态分组标题 */
.proj-group-head {
  grid-column: 1 / -1; display: flex; align-items: center; gap: 8px;
  padding: 12px 2px 4px; margin-top: 4px;
  border-bottom: 1.5px solid var(--border);
}
.proj-group-head:first-child { padding-top: 2px; margin-top: 0; }
.proj-group-head h3 { margin: 0; font-size: 14px; font-weight: 600; }
.proj-group-head .sub { font-size: 12px; color: var(--text-3); }
.proj-group-head .spacer { flex: 1; }

/* ========== 按板块分列（驾驶舱 / 今日事项 / 本周 / 本月） ========== */
.bgroup { margin-bottom: 12px; }
.bgroup:last-child { margin-bottom: 0; }
.bgroup-head {
  display: flex; align-items: center; gap: 7px;
  padding: 5px 2px 6px; margin-bottom: 4px;
  border-bottom: 1px dashed var(--border);
}
.bgroup-head:hover { background: var(--surface-2); }
.bgroup-name { font-size: 12.5px; font-weight: 600; color: var(--text-2); }
.bgroup-n {
  font-size: 11px; color: var(--text-3);
  background: var(--gray-bg); border-radius: 20px; padding: 1px 7px; font-weight: 500;
}
/* 板块色点：权重条与分组标题共用同一套颜色 */
.bdot {
  width: 8px; height: 8px; border-radius: 3px; flex: 0 0 8px;
  display: inline-block; vertical-align: middle; margin-right: 5px;
}
/* 卡片内的次级分隔标题（如「逾期未处理」「今日其余事项」） */
.bsub {
  font-size: 11.5px; color: var(--text-3); font-weight: 500;
  padding: 7px 2px 5px; letter-spacing: .02em;
}
.bsub.danger { color: var(--red); }

/* ========== 板块权重条 ========== */
/* 早期版本用了 var(--teal)，但 :root 里从未定义 --teal，填充色失效导致
   「只有 100% 那行看得见」。现在统一走 boardColorOf() 返回的硬编码板色。 */
/* 板块列：固定最小宽度 + 名称不折行。
   之前「业务支持与数字化」被压成三行竖着排（截图里可见），
   原因是板块列没有宽度约束，剩下的宽度全被两个百分比列吃掉了。 */
.wtbl th:first-child, .wtbl td:first-child { min-width: 108px; white-space: nowrap; }
.wtbl .wcol { width: 128px; }
.wbar {
  display: inline-block; vertical-align: middle;
  width: 84px; height: 7px; border-radius: 4px;
  background: var(--gray-bg); overflow: hidden;
}
.wbar > i { display: block; height: 100%; border-radius: 4px; min-width: 2px; }
.wpct {
  font-size: 11.5px; color: var(--text-3); margin-left: 5px;
  vertical-align: middle; font-variant-numeric: tabular-nums;
}
.wpct-none { font-size: 11.5px; color: var(--text-3); }

/* ========== 筛选面板（全部任务页） ==========
 * 早前把状态/标记/类型/时间做成四条独立 chipbar，下面又跟一排 select，
 * 一屏塞不下，看着乱。收进一块面板、按「行内标签 + 内容」排。
 */
.filter-panel {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 12px 14px; margin-bottom: 14px;
}
.fp-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.fp-row + .fp-row { margin-top: 9px; padding-top: 9px; border-top: 1px dashed var(--border); }
.fp-label {
  font-size: 11.5px; color: var(--text-3); font-weight: 500;
  min-width: 30px; margin-right: 2px; letter-spacing: .02em;
}
.fp-filters { align-items: stretch; }
.fp-filters input[type=search] { flex: 1 1 180px; min-width: 150px; }
.fp-filters select { flex: 0 1 auto; max-width: 150px; }
.fp-filters input[type=date] { flex: 0 1 auto; width: 132px; }
.fp-group { align-items: center; }


/* ========== 常规周期 · 板块内二级分组 ========== */
.cycle-sub + .cycle-sub { margin-top: 14px; padding-top: 12px; border-top: 1px dashed var(--border); }
.cycle-sub:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.cycle-sub-head {
  display: flex; align-items: center; gap: 8px;
  font-size: 12.5px; font-weight: 600; color: var(--text-2);
  padding: 4px 2px 6px; margin-bottom: 2px;
}
.cycle-sub-head .sub { font-size: 11.5px; color: var(--text-3); font-weight: 400; }

/* 确认弹窗里的按钮间距 */
.modal-foot .btn-danger + .btn-danger { margin-left: 4px; }

/* =========================================================
   视觉规范 v2（2026-10-17 用户定方向）
   风格：混合式 —— 列表保持可读（不追求极限紧凑），关键处用卡片突出
   配色：保持白底 + 蓝色主调的专业工具风
   ========================================================= */

/* 主内容区：设阅读宽度上限。
   早前没有任何约束，屏幕一宽表格就横着拉到 2000px，
   右侧留大片空白、左侧被拉散，看着松垮。 */
.main {
  flex: 1 1 auto; min-width: 0; overflow-x: hidden;
  /* 设阅读宽度上限：屏幕一宽内容就横着拉到 2000px，右侧留大片空白、左侧被拉散 */
  padding: 18px 22px 40px;
}
.main > * { max-width: 1440px; margin-left: auto; margin-right: auto; }

/* ---------- 表格：单元格两行分层 ---------- */
/* 用户反馈：括号里的小字挤在同一行、下次到期有的换行有的不换，排版很乱。
   解决：主信息一行、副信息独立一行，不同行高。 */
.cell-main {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: 13px; color: var(--text); line-height: 1.45;
}
.cell-sub {
  margin-top: 2px;
  font-size: 11.5px; color: var(--text-3); line-height: 1.4;
  /* 次要信息统一截断为一行，鼠标悬停看全文，避免行高参差 */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 100%;
}

table.tbl th, table.tbl td { vertical-align: top; }

/* ---------- 周期模板表格：列宽按内容分配 ----------
 * 用户反馈「右侧有很多空白」。
 * 根因：只有第 1 列（模板名称）写了 width:auto，其余列全是固定 px，
 * 累加约 530px + 名称列自适应。在1080px 宽的容器里，名称列被撑到 550px，
 * 而它内容只有几十个字 —— 多出来的空间全成了右侧的空白。
 * 修法：**名称列和截止规则列都写 auto**，让两列平分剩余宽度。
 * 备注列（cell-sub 里的说明文字）比较长，正好需要宽度。 */
.tbl-tpl { table-layout: fixed; width: 100%; }
.tbl-tpl th:nth-child(1), .tbl-tpl td:nth-child(1) { width: 40%; }    /* 模板名称 */
.tbl-tpl th:nth-child(2), .tbl-tpl td:nth-child(2) { width: 108px; }   /* 责任角色 */
.tbl-tpl th:nth-child(3), .tbl-tpl td:nth-child(3) { width: 68px; }    /* 周期 */
.tbl-tpl th:nth-child(4), .tbl-tpl td:nth-child(4) { width: 24%; }     /* 截止规则 */
.tbl-tpl th:nth-child(5), .tbl-tpl td:nth-child(5) { width: 92px; }    /* 下次到期 */
.tbl-tpl th:nth-child(6), .tbl-tpl td:nth-child(6) { width: 72px; }    /* 状态 */
/* 第 7 列是「操作」，固定窄宽、右对齐，紧贴右边缘（user反馈的空白主要在这里） */
.tbl-tpl th:nth-child(7), .tbl-tpl td:nth-child(7) { width: 68px; text-align: right; }
.tbl-tpl td .cell-sub, .tbl-tpl td .cell-main { overflow-wrap: anywhere; }
.tbl-tpl tr:hover td { background: var(--surface-2); }

/* ---------- 行距微调：混合风格，不追求紧凑 ---------- */
.tlist .titem { padding: 11px 12px; }
.tlist .titem + .titem { margin-top: 2px; }
.ttitle { font-size: 13.5px; line-height: 1.5; }
.tmeta { font-size: 11.5px; line-height: 1.5; }

/* ---------- 卡片：留白适度，不至于松散 ---------- */
.card-head { padding: 11px 14px; }
.card-body { padding: 14px; }
.card-body.tight { padding: 8px 10px; }

/* ---------- 任务行：角色 / 人名 视觉分层 ---------- */
/* 岗位是职责（稳定），人名是当下谁在做（会变）。用底色块区分。 */
.tmeta .m-role {
  background: var(--blue-bg); color: var(--blue);
  padding: 1px 6px; border-radius: 5px; font-weight: 500;
}
.tmeta .m-owner { color: var(--text-2); }
.tmeta .m-owner::before { content: '· '; color: var(--text-3); }

/* ============================================================
   团队视图（web/js/team.js）
   复用 .metrics/.metric/.tbl/.tag 等既有样式，这里只补本页独有的。
   ============================================================ */

/* 区间切换：本周 / 本月 / 本季 / 今年 */
.segbar {
  display: inline-flex; background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: 8px; overflow: hidden;
}
.seg {
  border: 0; background: transparent; color: var(--text-2);
  padding: 6px 12px; font-size: 12.5px; font-family: inherit; cursor: pointer;
  border-right: 1px solid var(--border);
}
.seg:last-child { border-right: 0; }
.seg:hover { background: var(--surface-2); }
.seg.on { background: var(--blue); color: #fff; }

/* 板块筛选 chips */
.bchips { display: flex; flex-wrap: wrap; gap: 7px; margin-bottom: 14px; }
.bchip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 20px; padding: 5px 12px; font-size: 12.5px;
  font-family: inherit; color: var(--text-2); cursor: pointer; transition: .12s;
}
.bchip:hover { border-color: var(--border-strong); }
.bchip.on { border-color: var(--blue); background: var(--blue-bg); color: var(--blue); font-weight: 500; }
.bchip b { font-weight: 600; color: var(--text); }
.bchip .bdot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
/* 筛选条和分布条长得一样容易混，用一条淡底把筛选区托起来 */
.bchips-filter {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 9px 11px; box-shadow: var(--shadow);
}
.bchips-filter .bchip { background: var(--surface-2); }
.bchips-filter .bchip.on { background: var(--blue-bg); border-color: var(--blue); }

/* 人员卡 */
.tgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 13px; }
.tcard {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow); display: flex; flex-direction: column; overflow: hidden;
}
.tcard.idle { opacity: .78; }
.tcard-head {
  padding: 12px 14px; border-bottom: 1px solid var(--border);
  display: flex; align-items: flex-start; justify-content: space-between; gap: 10px;
}
.tcard-name { font-size: 14.5px; font-weight: 500; display: flex; align-items: center; gap: 6px; }
.tcard-roles { font-size: 11.5px; color: var(--text-3); margin-top: 2px; }
.tcard-n { display: flex; flex-wrap: wrap; gap: 5px; justify-content: flex-end; flex-shrink: 0; }
.cnt {
  font-size: 11px; padding: 2px 7px; border-radius: 20px; white-space: nowrap;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text-2);
}
.cnt.ok  { background: var(--green-bg); border-color: #B7E0C9; color: var(--green); }
.cnt.od  { background: var(--red-bg);   border-color: #F3C4C0; color: var(--red); }
.cnt.bk  { background: var(--yellow-bg); border-color: #F0DBAA; color: var(--yellow); }

.tcard-body { flex: 1; padding: 4px 0; }
/* 卡内任务行：左边一条板块色，便于一眼分板块 */
.tline { display: flex; gap: 9px; align-items: flex-start; padding: 8px 14px; }
.tline + .tline { border-top: 1px solid var(--surface-2); }
.tbd { width: 3px; align-self: stretch; min-height: 18px; border-radius: 2px; flex: 0 0 3px; }
.tline-main { flex: 1; min-width: 0; }
.tline-t { font-size: 13px; line-height: 1.5; display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
.tline-m { font-size: 11.5px; color: var(--text-3); margin-top: 1px; }
.t-due { font-size: 11.5px; color: var(--text-3); white-space: nowrap; flex-shrink: 0; padding-top: 2px; }
.t-due.od { color: var(--red); font-weight: 500; }
.tblank { padding: 20px 14px; text-align: center; color: var(--text-3); font-size: 12.5px; }

.tcard-foot { padding: 9px 14px; border-top: 1px solid var(--border); }
.tlink {
  background: none; border: 0; padding: 0; cursor: pointer; font-family: inherit;
  color: var(--blue); font-size: 12.5px;
  text-decoration: underline; text-underline-offset: 2px;
}

/* 抽屉内的小汇总与分组标题 */
.team-fsum { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
.team-fsum .fs {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 8px; padding: 7px 12px; font-size: 12px; color: var(--text-2);
}
.team-fsum .fs b { display: block; font-size: 16px; color: var(--text); font-weight: 500; }
.team-h { font-size: 12.5px; color: var(--text-2); font-weight: 500; margin: 16px 0 7px; }

/* ================================================================
   横向按板块分列（今日 / 本周 / 本月事项）
   用户 2026-10-19 定的口径：
     - 列序固定：管理事务 → 核算与报表 → 资金与税务 → 业务支持与数字化
     - 专项任务从板块列移出，单独一列；一个专项都没有时整列不显示
     - 已完成放在各列底部，默认收起
     - 列头用简称，全称靠 title 提示
   设计目标：任务数 / 逾期数在同一水平线直接可比，不用上下滚。
   ================================================================ */

/* 列容器：固定五列 + 专项列，横向排开。minmax 下限保证窄屏自动换行而不是挤成一条缝
   ★ 上排进度行 .bc-prow-row 复用同一套模板（见下方），两边列宽逐像素一致，
     竖线才能 100% 贯通。改这里必须同时改 .bc-prow-row，两处模板不允许分叉。 */
.bc-board {
  display: grid;
  grid-template-columns: repeat(4, minmax(190px, 1fr));
  gap: 12px;
  align-items: start;
}
/* 有专项列时变五列。专项列稍窄（它的任务量通常远少于板块） */
.bc-board.has-special { grid-template-columns: repeat(4, minmax(180px, 1fr)) minmax(168px, .8fr); }
@media (max-width: 1240px) {
  .bc-board, .bc-board.has-special { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .bc-board, .bc-board.has-special { grid-template-columns: minmax(0, 1fr); }
}

/* 上排「每列完成进度」行（2026-10-20）。
   为什么不再用 4 个汇总方框：上排 4 格 / 下排 5 列，1920 实测上排竖线落在
   下排第 1/2/3 列中间、后两列头顶空，大脑找不到对应关系；
   而且 4 个框里的数字有 3 个和列头/折叠条重复。改成每列一格后一一对齐。 */
.bc-prow-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(190px, 1fr));
  gap: 12px;
  margin-bottom: 10px;
}
.bc-prow-row.has-special { grid-template-columns: repeat(4, minmax(180px, 1fr)) minmax(168px, .8fr); }
@media (max-width: 1240px) {
  .bc-prow-row, .bc-prow-row.has-special { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .bc-prow-row, .bc-prow-row.has-special { grid-template-columns: minmax(0, 1fr); }
}

/* 进度格：轻量、可点。视觉重量必须明显低于下面的看板列，
   否则又变成「上排比下排还重」的老问题（原来 4 个 63px 高的方框就是这样）。 */
.bc-prog {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--bc, var(--border-strong));
  border-radius: 8px;
  padding: 7px 10px 8px;
  min-width: 0;
  cursor: pointer;
  transition: border-color .12s, background .12s;
}
.bc-prog:hover { background: var(--surface-2); border-color: var(--bc, var(--border-strong)); }
.bc-prog-name {
  display: block;
  font-size: 11px; color: var(--text-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bc-prog-bar {
  height: 4px; margin: 5px 0 5px;
  background: var(--surface-2); border-radius: 2px; overflow: hidden;
}
.bc-prog-bar i { display: block; height: 100%; background: var(--bc, var(--text-3)); border-radius: 2px; }
.bc-prog-foot { display: flex; align-items: baseline; gap: 5px; min-width: 0; }
.bc-prog-pct {
  font-size: 15px; font-weight: 600; color: var(--text);
  font-variant-numeric: tabular-nums; line-height: 1.1; flex: 0 0 auto;
}
.bc-prog-pct.zero { color: var(--text-3); font-weight: 400; }
.bc-prog-sub {
  font-size: 10.5px; color: var(--text-3);
  margin-left: auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* 单列 */
.bc-col {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-width: 0;
}
/* 列头：色点 + 简称 + 数量徽章；底边不再单独画一条实线，
   改由下面的负荷条**兼任**分隔线（见 .bc-load 注释），避免两条横线叠在一起晃眼 */
.bc-head {
  padding: 9px 11px 0;
  background: var(--surface);
}
.bc-head-top { display: flex; align-items: center; gap: 6px; }
.bc-name {
  font-size: 12.5px; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
.bc-n {
  margin-left: auto; flex: 0 0 auto;
  min-width: 20px; height: 19px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 11.5px; font-weight: 600; line-height: 1;
  border-radius: 10px;
  background: var(--surface-2); color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
.bc-n.zero { color: var(--text-3); }
/* 负荷条：一身两职 —— 既是「哪个板块事多」的进度条，也是列头与列身的唯一分隔线。
   原来列头有 2px 实色 border-bottom，这里又有一条 3px 灰底彩条，
   两条横线上下贴着，扫视时像重影（用户 2026-10-19 反馈"看着眼花"）。
   现在合并成一条：满格时整条是板块色（等价于原来的分隔线），不满时露出灰底。 */
.bc-load {
  height: 3px;
  margin: 9px -11px 0;          /* 左右负边距顶到列边 → 视觉上贯穿整列 */
  background: var(--surface-2);
  overflow: hidden;
}
.bc-load i { display: block; height: 100%; background: var(--bc); transition: width .2s; }
/* 空列：没任务就不画进度条，但仍要留一条分隔线，否则列头会跟下面糊成一片 */
.bc-load.empty { background: var(--border); }
/* 逾期计数：只有有逾期时才出现，红色，很小 */
.bc-od {
  margin-left: auto; flex: 0 0 auto;
  font-size: 11px; color: var(--red); font-variant-numeric: tabular-nums;
}

/* 列身 */
.bc-body { padding: 3px 0; flex: 1; }
/* 首条任务紧贴负荷条，看着像被压住。留够呼吸间距 */
.bc-body .titem:first-child { padding-top: 10px; }
.bc-body .titem {
  padding: 8px 10px;
  gap: 8px;
  /* 竖排：due 挪到标题下面一行，横向留给标题。窄列里横向会把标题挤成三四个字一行 */
  flex-wrap: wrap;
}
.bc-body .tmain { flex: 1 1 100%; order: 2; }
.bc-body .chk { order: 1; }
.bc-body .tdue {
  order: 3; flex: 1 0 100%; text-align: left; min-width: 0;
  font-size: 11px; color: var(--text-3); margin-top: 2px;
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.bc-body .ttitle { font-size: 12.5px; line-height: 1.45; }
/* 板块列里不用再显示板块名（列头已经说了），省下的空间留给标题 */
.bc-body .tmeta { font-size: 11px; gap: 8px; margin-top: 2px; }
/* 窄列里 meta 是 flex，span 会被压扁截断成「关键节…」。
   允许换行 + 禁止单条被压缩，看板类信息宁可多一行也不能缺字。 */
.bc-body .tmeta span { flex: 0 0 auto; white-space: nowrap; }
.bc-body .tflags { margin-top: 3px; }
.bc-body .titem + .titem { margin-top: 0; }

/* 空列：别让整列塌成一个字高，列高对齐才好比 */
.bc-empty {
  padding: 16px 11px; font-size: 11.5px; color: var(--text-3); text-align: center;
}

/* 已完成：列内底部折叠 */
.bc-done-toggle {
  display: flex; align-items: center; gap: 5px;
  width: 100%; padding: 7px 11px;
  border: 0; border-top: 1px solid var(--border);
  background: var(--surface-2);
  font: inherit; font-size: 11.5px; color: var(--green);
  cursor: pointer; text-align: left;
}
.bc-done-toggle:hover { background: var(--green-bg); }
.bc-done-toggle .bc-caret { transition: transform .15s; display: inline-block; }
.bc-done-toggle[aria-expanded="true"] .bc-caret { transform: rotate(90deg); }
.bc-done-list { border-top: 1px solid var(--border); background: var(--surface-2); }
.bc-done-list .titem { opacity: .72; }
.bc-done-list .titem .ttitle.closed { color: var(--text-3); }

/* 未归板块：任务没落板块时也要看得见，不能凭空消失 */
.bc-unassigned {
  margin-top: 12px;
  border: 1px dashed var(--border-strong);
  border-radius: 10px; background: var(--surface); overflow: hidden;
}
.bc-unassigned .bc-load { background: var(--border); }

/* 专项列里的任务，左侧色条强制紫色。
   taskItem 自己判 data-kind（special/cycle/adhoc），但 bcIsSpecial 还认了
   「标题含专项」的手工录入任务（任务 708），不覆盖的话这类会显示灰色条。 */
.bc-col .titem.bc-sp { box-shadow: inset 3px 0 0 var(--purple); }
.bc-col .titem.bc-sp.flag-overdue { box-shadow: inset 3px 0 0 var(--red); }
