/* ============================================================
   禹拓公司工作台 · 共享样式
   浅色主题 / 蓝色主色 / 卡片化布局
   ============================================================ */
:root {
  --bg: #f4f6fb;
  --card: #ffffff;
  --ink: #17233d;
  --muted: #6b7688;
  --faint: #9aa4b5;
  --line: #e8ecf3;
  --blue: #2f6bff;
  --blue-deep: #1e4fd6;
  --blue-soft: #eef3ff;
  --green: #10b981;
  --green-soft: #e7f8f1;
  --orange: #f59e0b;
  --orange-soft: #fef4e2;
  --purple: #8b5cf6;
  --purple-soft: #f1ecfe;
  --teal: #14b8a6;
  --shadow-card: 0 1px 2px rgba(23, 35, 61, 0.04), 0 8px 24px rgba(23, 35, 61, 0.06);
  --shadow-lift: 0 4px 10px rgba(23, 35, 61, 0.08), 0 16px 40px rgba(23, 35, 61, 0.10);
  --radius: 16px;
  /* ★ 交付那几页（_gen.js 里的 PLAN_CSS / PR_CSS）引用的三个别名。
     ⚠ 2026-09-29 才发现它们**一直没定义** —— 浏览器遇到 var() 取不到值会把整条声明丢掉，
     于是表头底色、二级灰文字全靠向上继承"碰巧"看着还行，层次其实一直是丢的。
     在节点卡片上加「负责」一栏、量实际渲染色时才对出来。 */
  --tx: var(--ink);        /* 正文色（PLAN_CSS 里的输入框、表体文字） */
  --tx-2: var(--muted);    /* 二级文字（说明、标签、块头的「N 个环节 · 完成 x/N」） */
  --soft: #f2f4f8;         /* 浅底（表头、hover、提示条） */
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body { height: 100%; }

body {
  font-family: "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif;
  background: var(--bg);
  color: var(--ink);
  font-size: 14px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }

/* ---------------- 顶栏 ---------------- */
.topbar {
  position: sticky;
  top: 0;
  z-index: 50;
  height: 64px;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 28px;
}

.brand { display: flex; align-items: center; gap: 12px; }

.brand-mark {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: linear-gradient(135deg, #2f6bff, #5ea0ff);
  color: #fff;
  font-weight: 800;
  font-size: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 12px rgba(47, 107, 255, 0.35);
}

.brand-text .brand-name { font-size: 16px; font-weight: 700; letter-spacing: 0.5px; }
.brand-text .brand-sub { font-size: 10px; color: var(--faint); letter-spacing: 2px; text-transform: uppercase; }

.topbar-divider { width: 1px; height: 26px; background: var(--line); }

.topbar-title { display: flex; align-items: center; gap: 10px; }
.topbar-title .t-main { font-weight: 600; font-size: 15px; }
.topbar-title .t-sub { color: var(--faint); font-size: 13px; }

.chip-open {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  color: var(--blue);
  background: var(--blue-soft);
  border: 1px solid #d8e3ff;
  padding: 3px 10px;
  border-radius: 999px;
}

.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }

.icon-btn {
  width: 38px;
  height: 38px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  cursor: pointer;
  transition: all 0.18s ease;
}
.icon-btn:hover { color: var(--blue); border-color: #c8d8ff; background: var(--blue-soft); }

.pill-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 38px;
  padding: 0 14px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: #fff;
  color: var(--muted);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.18s ease;
}
.pill-toggle:hover { color: var(--blue); border-color: #c8d8ff; }

.user-chip { display: flex; align-items: center; gap: 9px; margin-left: 4px; }
.avatar {
  width: 36px; height: 36px;
  border-radius: 50%;
  background: linear-gradient(135deg, #f59e0b, #f97316);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}
.user-chip .u-name { font-size: 13px; font-weight: 600; }

/* ---------------- 页面容器 ---------------- */
.page { max-width: 1200px; margin: 0 auto; padding: 28px 28px 60px; }

/* ---------------- Hero 横幅 ---------------- */
.hero {
  position: relative;
  border-radius: 20px;
  background:
    radial-gradient(1200px 300px at 85% -40%, rgba(47, 107, 255, 0.10), transparent 60%),
    linear-gradient(120deg, #eaf1ff 0%, #f6f9ff 55%, #eef7f4 100%);
  border: 1px solid #e3ebf8;
  padding: 44px 48px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
  overflow: hidden;
}
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(47, 107, 255, 0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(47, 107, 255, 0.05) 1px, transparent 1px);
  background-size: 36px 36px;
  mask-image: linear-gradient(115deg, rgba(0,0,0,.7), transparent 55%);
  pointer-events: none;
}

.hero-eyebrow {
  font-size: 11px;
  letter-spacing: 3px;
  color: var(--blue);
  font-weight: 700;
  margin-bottom: 14px;
}
.hero h1 { font-size: 30px; font-weight: 800; letter-spacing: 1px; }
.hero p { margin-top: 12px; color: var(--muted); font-size: 14px; max-width: 560px; }

.date-card {
  position: relative;
  flex-shrink: 0;
  background: #fff;
  border-radius: 16px;
  border: 1px solid var(--line);
  box-shadow: var(--shadow-card);
  padding: 20px 28px;
  text-align: left;
  min-width: 200px;
}
.date-card .d-label { font-size: 12px; color: var(--faint); margin-bottom: 6px; }
.date-card .d-value {
  font-size: 30px;
  font-weight: 800;
  color: var(--blue);
  font-variant-numeric: tabular-nums;
  letter-spacing: 1px;
}
.date-card .d-sub { font-size: 12px; color: var(--muted); margin-top: 4px; }

/* ---------------- 区块标题 ---------------- */
.section-head {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 36px 0 18px;
}
.section-head h2 { font-size: 18px; font-weight: 700; }
.section-head .line { flex: 1; height: 1px; background: var(--line); }
.section-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: linear-gradient(135deg, #2f6bff, #4f8bff);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  padding: 8px 16px;
  border-radius: 999px;
  box-shadow: 0 4px 14px rgba(47, 107, 255, 0.35);
}
.section-badge .dot { width: 6px; height: 6px; border-radius: 50%; background: #9ec2ff; }
.section-note { color: var(--faint); font-size: 12px; }

/* ---------------- 版块卡片 ---------------- */
.module-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 18px;
}
@media (max-width: 1080px) { .module-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px)  { .module-grid { grid-template-columns: 1fr; } }

.module-card {
  position: relative;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px 22px 18px;
  display: flex;
  flex-direction: column;
  min-height: 300px;
  box-shadow: var(--shadow-card);
  transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
  overflow: hidden;
}
.module-card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: var(--accent, var(--blue));
  opacity: 0;
  transition: opacity 0.22s ease;
}
.module-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lift); border-color: #d9e2f2; }
.module-card:hover::before { opacity: 1; }

.mc-top { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 18px; }

.mc-icon {
  width: 44px; height: 44px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--accent-soft, var(--blue-soft));
  color: var(--accent, var(--blue));
}

.mc-num {
  font-size: 11px;
  letter-spacing: 2px;
  color: var(--faint);
  font-weight: 600;
  text-transform: uppercase;
  text-align: right;
  white-space: pre-line;
}

.mc-title { font-size: 18px; font-weight: 700; margin-bottom: 8px; }
.mc-desc { font-size: 13px; color: var(--muted); flex: 1; }

.mc-tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 16px 0 14px; }
.tag {
  font-size: 11px;
  color: var(--muted);
  background: #f2f5fa;
  border: 1px solid var(--line);
  padding: 3px 9px;
  border-radius: 6px;
}

.mc-footer {
  border-top: 1px solid var(--line);
  padding-top: 13px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent, var(--blue));
}
.mc-footer .arrow { transition: transform 0.2s ease; }
.module-card:hover .mc-footer .arrow { transform: translate(3px, -3px); }

/* ---------------- 快捷入口 ---------------- */
.quick-strip {
  margin-top: 22px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.quick-item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 10px 16px;
  font-size: 13px;
  color: var(--ink);
  box-shadow: var(--shadow-card);
  transition: all 0.18s ease;
  cursor: pointer;
}
.quick-item:hover { border-color: #c8d8ff; color: var(--blue); transform: translateY(-2px); }
.quick-item .q-dot { width: 8px; height: 8px; border-radius: 3px; background: var(--blue); }

/* ---------------- 首页：版块快捷入口（整页最上面一条，2026-09-23 老张要求） ----------------
   老张原话：「首页上方是不是可以加一个各版块的快捷入口，加在最上面，要不然进入二级页板块有点费劲」。
   原来「业务版块」那 5 张大卡排在首页下半部分（qaDash 之后），首屏根本看不到 →
   现在把「进版块」这件事提到最上面，一格一个版块，点一下就到该版块的第一张落地页。
   6 格一行；每格 = 色块图标 + 版块名 + ›，名称/图标/配色/落地页全部来自 _gen.js 的 MODS。 */
.mod-strip {
  display: grid;
  /* ★ 2026-09-29 晚：原来写死 repeat(6, 1fr) —— 加「店铺经营」变成第 7 个板块后
     立刻折成 6+1 两行（桌面实测 rowTops=92,164）。改用 auto-fit：
     有几格排几格，以后再加板块不用回来改数字。
     ⚠ 阈值 150px 是按**实测容器宽 1144px** 定的：7 格需 7×150+6×12=1122 ≤ 1144 才排得下。
       写 158px 时需 1178px，排不下就退成 6 格一行（当时正是这个现象）。
       每格实得 153px —— 仍然 >145px（「CRM客户管理」不被截断的下限，_homecheck.js 会量）。
       窄屏由下面的媒体查询接管，不受这个值影响。 */
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
  margin-bottom: 18px;
}
.ms-cell {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  padding: 12px 14px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--shadow-card);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.ms-cell:hover {
  transform: translateY(-2px);
  border-color: var(--accent, var(--blue));
  box-shadow: var(--shadow-lift);
}
.ms-ico {
  flex: 0 0 auto;
  width: 34px; height: 34px;
  border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent-soft, #eef3ff);
  color: var(--accent, var(--blue));
}
/* 图标原件是 16×16（带 width/height 属性），CSS 这里统一放大到 18×18 */
.ms-ico svg { width: 18px; height: 18px; }
.ms-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ms-arrow { flex: 0 0 auto; font-size: 15px; line-height: 1; color: var(--faint); transition: color 0.18s ease; }
.ms-cell:hover .ms-arrow { color: var(--accent, var(--blue)); }
/* 兜底：不支持容器查询的浏览器按视口折列（可用宽度 = min(视口,1200) − 56） */
@media (max-width: 1080px) { .mod-strip { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 560px)  { .mod-strip { grid-template-columns: repeat(2, 1fr); } }

/* ---------------- 子页布局 ---------------- */
/* 侧栏宽 / 内容上限 / 内容左右留白：三个数只在这里定义一次，.main-body 与 .topbar-inner 共用。
   （以前两处各写一份数字，改一处忘一处就错开，所以提到变量里。） */
:root {
  --sidebar-w: 240px; --content-max: 1440px; --content-gutter: 32px;
  /* 内容居中留出的左空白：**只有这一份定义**，.main-body 与 .topbar-inner 都引用它
     （以前两处各写一遍公式，改一处忘一处，面包屑就和正文错开）。
     100% 在"引用处"求值：.main-body 参照 .main、.topbar-inner 参照 .main-topbar —— 两者同宽，所以结果一致。 */
  --topbar-lead: max(0px, calc((100% - var(--content-max)) / 2));
  /* 同一份留白，给 fixed/absolute 元素用（侧栏里的 ✕ 要与 ☰ 同位）：
     定位元素里的百分比参照的是"包含块宽"而不是父元素宽（abspos 参照 padding box、fixed 参照视口），
     直接复用 --topbar-lead 会算成另一个数，所以这里显式用 100vw。
     ⚠ 100vw 含竖向滚动条（约 15px）→ 与 ☰ 的实际位置最多差 7~8px，肉眼看不出来，够"点原处即收起"。 */
  --topbar-lead-vw: max(0px, calc((100vw - var(--content-max)) / 2));
}

/* ★★ 侧栏 = 悬浮菜单（2026-09-24 老张：「可以把侧栏做成悬浮菜单栏，跟内容分开算，
   悬浮于子页之上，这样就不会挤压子页」）。
   改前：.layout 是 flex、侧栏占 240px 宽 → 正文可用宽少 240，1440 屏上只能铺 1185px。
   改后：侧栏 position:fixed 脱离文档流、浮在内容之上，.main 铺满整窗 ——
        正文不再为侧栏让位，居中口径也就回归最朴素的「相对整个窗口居中」。
   默认状态：首次进入按窗口宽度决定 —— ≥1900 展开（此时内容居中后的左右留白 ≥240，
   侧栏正好落在留白里、不盖正文）；窄屏收起。之后按用户上次的选择（localStorage）。
   开关 = 顶栏最左的 ☰（桌面和手机同一个按钮、同一套逻辑）。 */
.layout { min-height: 100vh; }

.sidebar {
  position: fixed; top: 0; left: 0; bottom: 0;
  width: var(--sidebar-w);
  background: #fff;
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  padding: 22px 14px;
  transform: translateX(-102%);
  /* padding-top 也要过渡：展开时它从 22 涨到 62（给顶栏的 ☰ / 侧栏自己的 ✕ 让位），
     不加过渡会看到文字先"跳"下去再滑入。 */
  transition: transform .24s ease, padding-top .24s ease;
  z-index: 70;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  /* 悬浮抽屉里不出现滚动条（内容不长，滚动条很扎眼） */
  scrollbar-width: none;
}
.sidebar::-webkit-scrollbar { width: 0; height: 0; }
.layout.nav-open .sidebar {
  transform: none;
  /* 展开时顶部内边距 22 → 62：让出顶栏那一行的高度，给 ☰（被盖住）与侧栏的 ✕（同位）用，
     侧栏内容从顶栏下沿开始，两者不叠字。 */
  padding-top: 62px;
  box-shadow: 0 18px 50px rgba(16,26,45,.24);
}

/* ★★ 侧栏的「收起」按钮 —— 2026-09-24 老张截图报「这弹出来回不去了」。
   根因（三个叠加，缺一都还收得回来）：
     ① .sidebar 是 fixed 浮层、z-index:70；顶栏只有 40 且带 backdrop-filter + 40 的层叠上下文
        → 侧栏一展开就把顶栏最左的 ☰ **整个盖住**，点不到；
     ② 桌面档**不铺遮罩**（当天的修复：铺了会"整页灰蒙蒙、点不动"）→ 点正文不关闭；
     ③ 结果是：桌面展开后除了 Esc（没人知道）没有任何可见关闭入口。
   修复思路（不抬任何 z-index，避免波及命令面板 z-index:60/61、抽屉 200/210 的既有层级）：
     把 ✕ 放在 **☰ 的正上方同位**（top: 13px、34×34，同款边框与圆角）。
     侧栏盖住 ☰ 后，用户看到的就是「☰ 原地变成 ✕」—— 点同一处即收起，沿用原肌肉记忆。
     ⚠ ☰ 的横向位置不是常数组：它 = --topbar-lead-vw（内容居中算出来的留白）+ 内边距，随视口变。
       老版本写死 left:32px，1600 屏上 ☰ 在 104 而 ✕ 在 32 → 点原处仍然点空（验收脚本当场抓到）。
     再套一层 min(…, --sidebar-w − 46px)：宽屏时那个留白会算到 240 以上、✕ 会被侧栏的
       overflow 裁掉（侧栏 overflow-y:auto 会把 overflow-x 也变成 auto）。夹住后最右落在侧栏内缘。
       而宽屏本来也不需要同位 —— ☰ 在侧栏右缘(240)之外，一直可见可点。 */
.sidebar .sb-close {
  position: absolute; top: 13px; z-index: 2;
  left: min(calc(var(--topbar-lead-vw) + var(--content-gutter)), calc(var(--sidebar-w) - 46px));
  width: 34px; height: 34px; display: inline-flex;
  align-items: center; justify-content: center; cursor: pointer;
  border: 1px solid var(--line); border-radius: 10px;
  background: #fff; color: var(--ink); font-family: inherit; padding: 0;
  transition: background .16s ease, border-color .16s ease, color .16s ease;
}
.sidebar .sb-close:hover { background: #f2f6ff; border-color: #c8d8ff; color: var(--blue); }

.sb-label { font-size: 11px; letter-spacing: 2px; color: var(--faint); padding: 4px 12px; }
.sb-title { font-size: 20px; font-weight: 800; padding: 2px 12px 14px; border-bottom: 1px solid var(--line); margin-bottom: 12px; }

.sb-nav { display: flex; flex-direction: column; gap: 4px; }
.sb-item {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px 12px;
  border-radius: 10px;
  color: var(--muted);
  font-size: 13.5px;
  transition: all 0.16s ease;
}
.sb-item svg { flex-shrink: 0; }
.sb-item:hover { background: #f5f8ff; color: var(--ink); }
.sb-item.active {
  background: var(--blue-soft);
  color: var(--blue);
  font-weight: 600;
  box-shadow: inset 0 0 0 1px #dbe6ff;
}
.sb-item .sb-arrow { margin-left: auto; color: var(--faint); font-size: 11px; }

.sidebar-bottom { margin-top: auto; }
.sb-user {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px;
  border-radius: 12px;
  background: #f7f9fd;
  border: 1px solid var(--line);
}
.sb-user .u-role { font-size: 11px; color: var(--faint); }

.main { min-width: 0; }
/* 顶栏只是一条底：内容交给 .topbar-inner（它和 .main-body 用同一套「居中口径」，
   面包屑才永远和正文左边界对齐）。 */
.main-topbar {
  height: 60px;
  background: rgba(255,255,255,.92);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 40;
}
.topbar-inner {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 100%;
  padding: 0 var(--content-gutter);
  max-width: var(--content-max);
  /* ★ 与 .main-body 引用**同一份**居中留白（--topbar-lead）：同宽、同左边界。
     侧栏改悬浮后不再占布局宽度，所以不再扣 --sidebar-w —— 就是「相对整个窗口居中」。 */
  margin-left: var(--topbar-lead);
  margin-right: auto;
}
/* 侧栏开关（桌面与手机同一个按钮）：点它唤出/收起悬浮菜单。
   ⚠ 展开时 ☰ 会被侧栏盖住（侧栏 z-index:70 > 顶栏 40，且顶栏有 backdrop-filter 自成层叠上下文，
     子元素抬 z-index 也翻不出去）—— 这是**预期**的：同一位置有侧栏的 ✕ 接管（见 .sidebar .sb-close），
     点原处即收起。别试图靠给 ☰ 加 z-index 解决，那会把顶栏整体抬到命令面板遮罩之上。 */
.nav-toggle {
  width: 34px; height: 34px; flex-shrink: 0; display: inline-flex;
  align-items: center; justify-content: center; cursor: pointer;
  border: 1px solid var(--line); border-radius: 10px;
  background: #fff; color: var(--ink); font-family: inherit; padding: 0;
}
.nav-toggle:hover { background: #f2f6ff; border-color: #c8d8ff; color: var(--blue); }
/* 抽屉遮罩：**只在手机档出现**。
   ★ 2026-09-24 修正：桌面档侧栏改悬浮后是「左侧浮层/导航面板」—— ≥1900 的屏首次进入默认就是展开的，
     此时若还铺一层遮罩，正文会被压暗、点击也全被吃掉，表现就是"页面灰蒙蒙、点不动"。
     所以桌面不铺遮罩 —— 收起改用「侧栏里的 ✕（与 ☰ 同位）/ 点正文任意处 / Esc」这三条，
     只有手机才需要"点外部关闭"这一层（手机屏幕小，抽屉几乎占满，遮罩才是自然的手势）。 */
.nav-mask {
  display: none; position: fixed; inset: 0; z-index: 65;
  opacity: 0; pointer-events: none; transition: opacity .2s;
}
.crumb { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--faint); }
.crumb .cur { color: var(--ink); font-weight: 600; font-size: 14px; }

/* ★★ 内容块相对「整个窗口」居中。
   2026-09-23 老张全屏截图报过「还是歪的，往右边歪了」—— 当时侧栏实占 240px，
   若只按 .main 居中，左侧就要多空 240，所以公式里扣了 --sidebar-w/2 去补。
   2026-09-24 侧栏改悬浮（不再占布局宽度）→ 那半个侧栏的补偿项一并删掉，
   公式回到最朴素的一份：内容居中于整个窗口（.topbar-inner 引用同一份 --topbar-lead，面包屑与正文左边界恒等）。
   实测（doc 宽 = 视口 − 滚动条）：
     2304 → 内容 424.5~1864.5（宽 1440），左右各空 424.5  → 对称
     1920 → 内容 240~1680，           左右各空约 240    → 对称（侧栏展开时正好落在左侧留白里）
     1440 → 可用宽 ≤ 上限 1440         → 左外边距算出负数 → max() 取 0，内容铺满
            （此时没有"居中"的余地：要么铺满、要么缩窄留白，缩窄反而更奇怪） */
.main-body {
  padding: 28px var(--content-gutter) 64px;
  max-width: var(--content-max);
  margin-left: var(--topbar-lead);
  margin-right: auto;
}

.eyebrow { font-size: 11px; letter-spacing: 3px; color: var(--blue); font-weight: 700; margin-bottom: 10px; }
.hero-line h1 { font-size: 26px; font-weight: 800; }
.hero-line p { margin-top: 8px; color: var(--muted); font-size: 13.5px; max-width: 640px; }

/* 统计卡 */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  margin: 26px 0 30px;
}
@media (max-width: 900px) { .stat-grid { grid-template-columns: repeat(2, 1fr); } }
.stat-card {
  background: #fff;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent, var(--blue));
  border-radius: 12px;
  padding: 16px 18px;
  box-shadow: var(--shadow-card);
}
.stat-card .s-label { font-size: 12px; color: var(--muted); }
.stat-card .s-value { font-size: 24px; font-weight: 800; margin: 4px 0 2px; color: var(--ink); }
.stat-card .s-sub { font-size: 11px; color: var(--faint); }

/* 内容面板 */
.panel-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
@media (max-width: 900px) { .panel-grid { grid-template-columns: 1fr; } }

.panel {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  padding: 20px 20px 10px;
}
.panel.wide { grid-column: 1 / -1; }
.panel-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 8px; }
.panel-head .p-title { font-size: 15.5px; font-weight: 700; }
.panel-head .p-link { font-size: 12px; color: var(--blue); cursor: pointer; }
.panel-head .p-link:hover { text-decoration: underline; }

.row-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 4px;
  border-bottom: 1px solid #f0f3f8;
  cursor: pointer;
  transition: background .15s ease;
  border-radius: 6px;
}
.row-item:last-child { border-bottom: none; }
.row-item:hover { background: #f8faff; }
.row-item .r-ico {
  width: 28px; height: 28px;
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px;
  background: var(--accent-soft, var(--blue-soft));
  color: var(--accent, var(--blue));
  flex-shrink: 0;
}
.row-item .r-name { font-size: 13.5px; }
.row-item .r-desc { font-size: 11px; color: var(--faint); }
.row-item .r-meta { margin-left: auto; font-size: 12px; color: var(--faint); white-space: nowrap; display:flex; align-items:center; gap:8px; }
.row-item .r-count { color: var(--ink); font-weight: 600; }

/* ============================================================
   门户式工作台 · 版块子页通用组件
   ============================================================ */
.sb-group { margin-top: 16px; }
.sb-group .sg-head { font-size: 11px; letter-spacing: 1.5px; color: var(--faint); padding: 0 12px 6px; }

.brand-block { display: flex; align-items: center; gap: 10px; }
.brand-block .bb-name { font-size: 15px; font-weight: 800; letter-spacing: .5px; }
.brand-block .bb-sub { font-size: 9px; letter-spacing: 2px; color: var(--faint); }

.filter-bar {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 18px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 22px;
  box-shadow: var(--shadow-card);
  margin-top: 22px;
}
.filter-bar .fb-title { font-size: 16px; font-weight: 700; }
.filter-bar .fb-desc { font-size: 12.5px; color: var(--muted); margin-top: 5px; }
.fb-right { display: flex; align-items: flex-end; gap: 12px; flex-shrink: 0; }
.fb-field { display: flex; flex-direction: column; gap: 6px; }
.fb-field .lbl { font-size: 11px; color: var(--faint); }

.seg { display: inline-flex; background: #f2f5fa; border: 1px solid var(--line); border-radius: 10px; padding: 3px; }
.seg span { padding: 7px 18px; font-size: 13px; border-radius: 8px; color: var(--muted); cursor: pointer; transition: all .16s ease; }
.seg span.on { background: #fff; color: var(--ink); font-weight: 600; box-shadow: 0 1px 3px rgba(23,35,61,.12); }

.select {
  display: inline-flex; align-items: center; justify-content: space-between; gap: 10px;
  border: 1px solid var(--line); border-radius: 10px; padding: 8px 12px;
  font-size: 13px; background: #fff; color: var(--ink); min-width: 92px; cursor: pointer;
}
.select .caret { color: var(--faint); font-size: 10px; }

.auto-note { font-size: 12px; color: var(--faint); margin: 16px 0 10px; }

.tabs { display: inline-flex; background: #f2f5fa; border: 1px solid var(--line); border-radius: 10px; padding: 3px; }
.tabs span { padding: 7px 16px; font-size: 13px; color: var(--muted); border-radius: 8px; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; }
.tabs span.on { background: #fff; color: var(--ink); font-weight: 600; box-shadow: 0 1px 3px rgba(23,35,61,.12); }

.toolbar { display: flex; align-items: center; gap: 10px; margin: 14px 0 18px; }
.search {
  flex: 1; display: flex; align-items: center; gap: 9px;
  background: #fff; border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 14px; color: #b3bcc9; font-size: 13px;
}
.search:hover { border-color: #d9e2f2; }

/* 环形图 */
.donut-wrap { display: flex; align-items: center; gap: 26px; padding: 8px 0 6px; }
.donut {
  width: 186px; height: 186px; border-radius: 50%; position: relative; flex-shrink: 0;
  background: conic-gradient(#2f6bff 0 26%, #14b8a6 26% 46%, #f59e0b 46% 62%, #8b5cf6 62% 76%, #60a5fa 76% 88%, #94a3b8 88% 100%);
}
.donut::after { content: ""; position: absolute; inset: 29%; background: #fff; border-radius: 50%; }
.donut .d-center {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 12px; color: var(--faint); z-index: 2;
}
.legend { display: flex; flex-direction: column; gap: 10px; font-size: 12.5px; color: var(--muted); flex: 1; min-width: 0; }
.legend .lg-item { display: flex; align-items: center; gap: 9px; }
.legend i { width: 9px; height: 9px; border-radius: 3px; flex-shrink: 0; }
.legend .lg-val { margin-left: auto; color: var(--faint); }

/* 横向条形 */
.bars { display: flex; flex-direction: column; gap: 13px; padding: 6px 0 4px; }
.bar-row { display: grid; grid-template-columns: 96px 1fr 58px; align-items: center; gap: 12px; font-size: 12.5px; color: var(--muted); }
.bar-track { height: 9px; background: #eef2f8; border-radius: 6px; overflow: hidden; }
.bar-fill { height: 100%; border-radius: 6px; background: linear-gradient(90deg, #2f6bff, #5ea0ff); }
/* 条形右侧的数值（小组达成率等） */
.bar-val { font-size: 12px; font-weight: 600; color: var(--ink); text-align: right; letter-spacing: .01em; }
.bar-val.is-pending { color: var(--faint); font-weight: 500; }
.bar-fill.g { background: linear-gradient(90deg, #0f9d76, #34d399); }
.bar-fill.o { background: linear-gradient(90deg, #d97706, #fbbf24); }
.bar-fill.p { background: linear-gradient(90deg, #7c3aed, #a78bfa); }

/* 店铺经营日报：成交额走势折线（手写 SVG、零依赖）—— 2026-09-29 加 */
.sp-chart { padding: 6px 0 2px; }
.sp-chart .me-empty { padding: 40px 0; }
.sp-svg { display: block; width: 100%; height: auto; overflow: visible; }
.sp-legend {
  display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 12px; padding-top: 10px;
  border-top: 1px solid var(--line); font-size: 12px; color: var(--muted);
}
.sp-lg {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  padding: 3px 8px; border-radius: 6px; user-select: none;
  transition: background .15s, opacity .15s;
}
.sp-lg:hover { background: #f1f5fb; }
.sp-lg i { width: 15px; height: 3px; border-radius: 2px; flex-shrink: 0; }
.sp-lg.off { opacity: .35; }
.sp-lg.off i { background: #cbd5e1 !important; }
/* 折线图抬头 + 图例尾注（2026-09-30 老张：「不标折的是啥、各个轴也没标是啥、
   也不标每条线代表哪个店，这谁看得懂」）——图上方给标题，图例行尾解释虚线。 */
.sp-chart-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin: 16px 0 2px; }
.sp-chart-head b { font-size: 13.5px; font-weight: 700; color: var(--ink); }
.sp-chart-head span { font-size: 12px; color: var(--muted); }
.sp-note { margin-left: auto; font-size: 11.5px; color: var(--faint); }
/* 首页「线上店铺经营」块（2026-09-29 晚加）——
   折线直接复用上面那套 .sp-* 样式，这里只补首页特有的头部条（报告日 + 进详情）。
   ⚠ 报告日不是今天时标橙色：首页最容易被当成"今天的数"，这行字就是防线。 */
.hs-strip { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
.hs-date { font-size: 12.5px; color: var(--muted); }
.hs-date b { color: var(--ink); font-weight: 700; }
.hs-date.stale, .hs-date.stale b { color: #b45309; }
.hs-more { font-size: 12.5px; font-weight: 600; color: var(--blue); text-decoration: none; white-space: nowrap; }
.hs-more:hover { text-decoration: underline; }

/* 看板 */
.kanban { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-top: 6px; }
@media (max-width: 1000px) { .kanban { grid-template-columns: repeat(2, 1fr); } }
.kcol { background: #f8fafd; border: 1px solid var(--line); border-radius: 12px; padding: 12px 12px 14px; min-height: 190px; }
.kcol h4 { font-size: 12.5px; color: var(--muted); font-weight: 600; display: flex; justify-content: space-between; margin-bottom: 12px; }
.kempty { font-size: 12px; color: #b9c1cd; text-align: center; padding: 30px 0; }

/* 数据待接入标记 */
.pending {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; color: #b07d10; background: #fdf5e4;
  border: 1px solid #f6e3b8; border-radius: 6px; padding: 2px 8px;
}

/* 面板分组列表（人力资源式） */
.mini-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 6px; }
@media (max-width: 900px) { .mini-grid { grid-template-columns: 1fr; } }

.foot-note { margin-top: 28px; font-size: 12px; color: var(--faint); border-top: 1px solid var(--line); padding-top: 14px; }


/* ============================================================
   助手式工作台（Console）
   ============================================================ */
.console { display: flex; height: 100vh; overflow: hidden; background: #fff; }

.cs-side {
  width: 250px;
  flex-shrink: 0;
  background: #fff;
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  padding: 20px 14px 14px;
}

.cs-brand { padding: 4px 10px 18px; }
.cs-brand .csb-label { font-size: 10px; letter-spacing: 2.5px; color: var(--faint); margin-bottom: 8px; }
.cs-brand .csb-name { font-size: 24px; font-weight: 800; letter-spacing: -0.5px; }
.cs-brand .csb-name .accent {
  background: linear-gradient(120deg, #2f6bff, #4f9dff);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.cs-nav { display: flex; flex-direction: column; gap: 4px; }
.cs-item {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 11px 13px;
  border-radius: 11px;
  color: var(--muted);
  font-size: 13.5px;
  cursor: pointer;
  border: 1px solid transparent;
  transition: all .16s ease;
}
.cs-item:hover { background: #f5f8ff; color: var(--ink); }
.cs-item.active {
  background: var(--blue-soft);
  color: var(--blue);
  font-weight: 600;
  border-color: #dbe6ff;
}
.cs-item .cs-badge {
  margin-left: auto;
  font-size: 10.5px;
  color: var(--blue);
  background: #fff;
  border: 1px solid #dbe6ff;
  border-radius: 6px;
  padding: 1px 6px;
}

.cs-recent { margin-top: 22px; border-top: 1px solid var(--line); padding-top: 14px; }
.cs-recent .cr-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 12px 8px; font-size: 12px; color: var(--faint);
}
.cs-recent .cr-head .refresh { cursor: pointer; }
.cs-empty { padding: 10px 12px; font-size: 12.5px; color: var(--faint); }

.cs-main { flex: 1; min-width: 0; overflow-y: auto; background: #fbfcfe; }

.cs-topbar {
  height: 54px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 24px;
  border-bottom: 1px solid var(--line);
  background: rgba(255,255,255,.9);
  backdrop-filter: blur(10px);
  position: sticky;
  top: 0;
  z-index: 20;
}
.cs-topbar .cs-tb-title { font-size: 13px; font-weight: 600; }
.cs-topbar .cs-tb-sub { font-size: 12px; color: var(--faint); }
.cs-topbar .cs-links { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.cs-link {
  font-size: 12.5px;
  color: var(--muted);
  border: 1px solid var(--line);
  background: #fff;
  border-radius: 9px;
  padding: 5px 11px;
  transition: all .16s ease;
}
.cs-link:hover { color: var(--blue); border-color: #c8d8ff; background: var(--blue-soft); }

.cs-body { padding: 72px 40px 60px; }
.cs-body.inner { padding: 32px 40px 60px; }

.cs-hero { text-align: center; }
.cs-wordmark { font-size: 62px; font-weight: 800; line-height: 0.96; letter-spacing: -2px; }
.cs-wordmark .w1 { color: #17233d; display: block; }
.cs-wordmark .w2 {
  display: block;
  background: linear-gradient(120deg, #1e4fd6, #4f9dff);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.cs-eyebrow { margin-top: 20px; font-size: 10.5px; letter-spacing: 4px; color: var(--faint); font-weight: 600; }
.cs-title { margin-top: 18px; font-size: 30px; font-weight: 800; letter-spacing: 1px; }

.cs-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  max-width: 860px;
  margin: 34px auto 0;
}
@media (max-width: 900px) { .cs-cards { grid-template-columns: 1fr; } }
.cs-card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 16px 18px;
  text-align: left;
  cursor: pointer;
  box-shadow: var(--shadow-card);
  transition: all .18s ease;
}
.cs-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lift); border-color: #d9e2f2; }
.cs-card .cc-title { font-size: 14px; font-weight: 700; display: flex; align-items: center; gap: 6px; }
.cs-card .cc-title .go { color: var(--blue); font-size: 12px; }
.cs-card .cc-desc { margin-top: 7px; font-size: 12.5px; color: var(--muted); line-height: 1.65; }

.cs-composer {
  max-width: 860px;
  margin: 40px auto 0;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 18px;
  box-shadow: 0 4px 16px rgba(23,35,61,.06), 0 18px 46px rgba(23,35,61,.07);
  padding: 15px 18px 13px;
}
.cs-composer .cc-top {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--muted);
  padding-bottom: 10px;
}
.cs-composer .cc-top .skill-pill {
  display: inline-flex; align-items: center; gap: 5px;
  background: #f2f5fa; border: 1px solid var(--line);
  border-radius: 7px; padding: 2px 8px; color: var(--ink);
}
.cs-composer .cc-top .new-task { margin-left: auto; color: var(--faint); }
.cs-input {
  width: 100%;
  border: none;
  outline: none;
  resize: none;
  font-family: inherit;
  font-size: 14px;
  line-height: 1.7;
  min-height: 54px;
  color: var(--ink);
}
.cs-input::placeholder { color: #b3bcc9; }
.cs-tools { display: flex; align-items: center; gap: 12px; margin-top: 8px; color: var(--faint); font-size: 12.5px; }
.cs-tools .t-item { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.cs-tools .t-item:hover { color: var(--blue); }
.cs-tools .t-right { margin-left: auto; display: flex; align-items: center; gap: 12px; }
.cs-tools .model-pill { color: var(--muted); cursor: pointer; }
.cs-send {
  width: 38px; height: 38px;
  border-radius: 50%;
  border: none;
  background: #17233d;
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: all .18s ease;
}
.cs-send:hover { background: var(--blue); transform: scale(1.05); }

.toast {
  position: fixed;
  left: 50%;
  bottom: 42px;
  transform: translateX(-50%) translateY(16px);
  background: #17233d;
  color: #fff;
  font-size: 13px;
  padding: 11px 20px;
  border-radius: 10px;
  opacity: 0;
  pointer-events: none;
  transition: all .25s ease;
  z-index: 999;
  box-shadow: 0 10px 30px rgba(23,35,61,.28);
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* 视图切换 */
.view { display: none; }
.view.active { display: block; }

/* 控制台内的统计与面板沿用 */
.cs-body .stat-grid { margin-top: 22px; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 900px) { .grid-2 { grid-template-columns: 1fr; } }

/* 侧边分组 */
.sb-group { display: flex; flex-direction: column; gap: 4px; }
.sb-group .sg-head { margin-top: 8px; }

/* ---------------- 数据表 ---------------- */
.panel.flush { padding: 0; overflow: hidden; }
.tbl-wrap { overflow-x: auto; }
table.tbl { width: 100%; border-collapse: collapse; font-size: 13px; min-width: 720px; }

/* ★ 标签不许被挤成竖排（「领取」两个字拆成上下两行 = 看着像坏了）。
   2026-09-28 老张在客户管理里发现「领取」按钮有问题，起因就是这条。
   治本在 _gen.js 给表格兜 min-width（见下），这条是兜底：任何情况下标签都不断行。 */
table.tbl .tag { white-space: nowrap; }

/* ★ 宽表（列宽声明之和 > 内容区上限，_gen.js tableBlock 打的 .tbl-act）：
   .tbl-wrap 横向滚动时把**最右两列一起**钉住 —— 「操作」（领取/退回公海/还原）
   和它左边的「收录人 / 负责人」（老张：「收录人也钉住吧」）。
   前者保证按钮不用滑到最右才点得到，后者保证"这条客户归谁、谁录进来的"那一眼始终在。
   背景必须给实色，否则滚动的内容会从底下透出来。
   ⚠ 空态那一行是 colspan 独占的单元格，不能跟着钉（钉了会整块右移、文案跑出屏幕）。
   ⚠ 倒数第二列的 right 偏移必须 = 操作列的**渲染**宽度（声明值 ≠ 渲染值，auto 布局会重算），
     由 app.js 的 tblActInit() 实测后写进 --actw；110px 只是首帧兜底（就是它的声明宽度）。 */
table.tbl.tbl-act th:last-child,
table.tbl.tbl-act tbody tr:not(.tbl-empty) td:last-child {
  position: sticky; right: 0; z-index: 3;
}
table.tbl.tbl-act th:nth-last-child(2),
table.tbl.tbl-act tbody tr:not(.tbl-empty) td:nth-last-child(2) {
  position: sticky; right: var(--actw, 110px); z-index: 2;
  box-shadow: -10px 0 12px -10px rgba(20, 40, 90, .22);
}
table.tbl.tbl-act thead th:last-child,
table.tbl.tbl-act thead th:nth-last-child(2) { background: #fafbfe; z-index: 4; }
table.tbl.tbl-act tbody td:last-child,
table.tbl.tbl-act tbody td:nth-last-child(2) { background: #fff; }
table.tbl.tbl-act tbody tr:hover td:last-child,
table.tbl.tbl-act tbody tr:hover td:nth-last-child(2) { background: #f8faff; }
/* ⚠ 例外：询盘登记那张表按**企微表头原序**排（3.97），倒数第二列是「AI分析」——内容列，
   不是「收录人 / 负责人」。跟着「操作」一起钉会白占 ~150px，还把中间几列挤进滚动区。
   这张表只钉「操作」一列。（钉「收录人/负责人」的本意，看上面那段注释。） */
[data-table="crm-inquiry.t1"] table.tbl.tbl-act th:nth-last-child(2),
[data-table="crm-inquiry.t1"] table.tbl.tbl-act tbody tr:not(.tbl-empty) td:nth-last-child(2) {
  position: static; box-shadow: none;
}
table.tbl th {
  background: #fafbfe; color: var(--muted); font-weight: 600; font-size: 12px;
  text-align: left; padding: 11px 14px; border-bottom: 1px solid var(--line); white-space: nowrap;
}
table.tbl td { padding: 12px 14px; border-bottom: 1px solid #f0f3f8; color: var(--ink); vertical-align: middle; }
table.tbl tr:last-child td { border-bottom: none; }
table.tbl tbody tr:hover { background: #f8faff; }
.tbl-empty td { text-align: center; color: var(--faint); padding: 46px 14px; font-size: 12.5px; }
.tbl-empty td .em-sub { display: block; margin-top: 8px; font-size: 12px; color: #b9c1cd; }
.tbl-empty td .em-sub b { color: var(--blue); font-weight: 700; }
/* 空表时的跨池跳转：「业务员客户池里有 4 条 → 切过去看」 */
.tbl-empty td .em-go {
  margin-left: 8px; color: var(--blue); font-weight: 600; text-decoration: none;
  border-bottom: 1px solid rgba(47,107,255,.35); white-space: nowrap;
}
.tbl-empty td .em-go:hover { border-bottom-color: var(--blue); }
.tbl-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 16px; border-top: 1px solid var(--line); font-size: 12px; color: var(--faint); background: #fff;
}
.pager { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.pager span, .pager a {
  min-width: 26px; height: 26px; padding: 0 7px; border: 1px solid var(--line); border-radius: 7px;
  display: inline-flex; align-items: center; justify-content: center; font-size: 12px; color: var(--muted);
  text-decoration: none; transition: all .14s ease; box-sizing: border-box;
}
.pager span.on, .pager a.on { border-color: #c8d8ff; background: var(--blue-soft); color: var(--blue); font-weight: 600; }
.pager a:hover { border-color: var(--blue); color: var(--blue); }
.pager a.dis { opacity: .35; cursor: not-allowed; }
.pager a.dis:hover { border-color: var(--line); color: var(--muted); }
.pager .gap { border: 0; min-width: 12px; color: var(--faint); }

/* 表尾右侧那组「每页 N 条 + 页码」。包一层的原因：.tbl-foot 是 space-between，
   label 和 pager 各自当一个 item 平铺的话，这个 label 会被甩到正中间去。 */
.pgbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pg-size { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.pg-size select {
  height: 26px; padding: 0 6px; border: 1px solid var(--line); border-radius: 7px;
  background: #fff; color: var(--muted); font: inherit; font-size: 12px; cursor: pointer;
}
.pg-size select:hover { border-color: var(--blue); color: var(--blue); }

/* 返回顶部（老张 2026-09-28：「要有反上标，点击可反上，在下滑之后就要弹出这个标」）。
   默认 opacity+visibility 一起收起：只给 opacity 的话按钮透明了却还挡着点击。 */
.back-top {
  position: fixed; right: 26px; bottom: 28px; z-index: 60;
  display: inline-flex; align-items: center; gap: 6px;
  height: 40px; padding: 0 15px 0 13px;
  border: 1px solid var(--line); border-radius: 999px;
  background: #fff; color: var(--muted); font: inherit; font-size: 12.5px; font-weight: 600;
  cursor: pointer; box-shadow: 0 8px 22px rgba(20, 40, 90, .13);
  opacity: 0; visibility: hidden; transform: translateY(12px);
  transition: opacity .2s ease, transform .2s ease, visibility .2s ease,
              border-color .14s ease, color .14s ease;
}
.back-top.show { opacity: 1; visibility: visible; transform: none; }
.back-top:hover { border-color: var(--blue); color: var(--blue); }
.back-top .bt-ico { font-size: 15px; line-height: 1; margin-top: -1px; }
@media (max-width: 760px) {
  .back-top { right: 14px; bottom: 16px; height: 36px; padding: 0 12px; }
  .back-top .bt-txt { display: none; }   /* 手机上只留箭头，别挡内容 */
}

/* 分页上来之后工具栏里的真控件（原来那排 .select 是图片式占位，被 JS 换掉了） */
.tb-filters { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tb-filters .sel {
  height: 32px; padding: 0 8px; border: 1px solid var(--line); border-radius: 8px;
  background: #fff; color: var(--ink); font-size: 12.5px; font-family: inherit; cursor: pointer;
  max-width: 130px;
}
.tb-filters .sel:hover { border-color: var(--blue); }

/* 来源角标：企微同步 vs 聚水潭导入，一眼分开 */
.src {
  display: inline-block; padding: 2px 7px; border-radius: 6px;
  font-size: 11.5px; line-height: 1.5; white-space: nowrap; font-weight: 500;
}
.src-wecom { background: #eef6ff; color: #2f6fd0; }
.src-jst { background: #fff4e5; color: #a35f10; }
.text-late { color: #d94a3d; font-weight: 600; }

/* ---------------- 按钮 ---------------- */
.btn {
  display: inline-flex; align-items: center; gap: 6px; height: 38px; padding: 0 16px;
  border-radius: 10px; border: 1px solid var(--line); background: #fff; color: var(--ink);
  font-size: 13px; font-family: inherit; cursor: pointer; transition: all .16s ease; white-space: nowrap;
}
.btn:hover { border-color: #c8d8ff; color: var(--blue); }
.btn.primary { background: var(--blue); border-color: transparent; color: #fff; font-weight: 600; box-shadow: 0 4px 12px rgba(47,107,255,.24); }
.btn.primary:hover { filter: brightness(1.06); color: #fff; }
.btn.ghost { background: #f7f9fd; border-color: transparent; color: var(--muted); }
.btn.sm { height: 32px; padding: 0 12px; font-size: 12.5px; }

/* ---------------- 来源 / 规则 / 流程 ---------------- */
.src-line { display: flex; align-items: center; gap: 10px; margin-top: 18px; flex-wrap: wrap; }
.src-chip {
  display: inline-flex; align-items: center; gap: 7px; font-size: 12px; color: var(--muted);
  background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: 5px 11px;
}
.src-chip b { color: var(--ink); font-weight: 600; }

.rules { list-style: none; display: flex; flex-direction: column; gap: 11px; padding: 6px 0 8px; }
.rules li { position: relative; padding-left: 18px; font-size: 13px; color: var(--muted); line-height: 1.75; }
.rules li::before {
  content: ""; position: absolute; left: 2px; top: 10px; width: 6px; height: 6px;
  border-radius: 2px; background: var(--blue); opacity: .65;
}

.flow { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 8px 0 10px; }
.flow .step {
  display: inline-flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ink);
  background: #f7f9fd; border: 1px solid var(--line); border-radius: 9px; padding: 8px 12px;
}
.flow .step i {
  width: 18px; height: 18px; border-radius: 50%; background: var(--blue-soft); color: var(--blue);
  font-size: 10.5px; font-style: normal; display: inline-flex; align-items: center; justify-content: center; font-weight: 700;
}
.flow .sep { color: #c3cbd8; font-size: 12px; }

/* ---------------- 下拉菜单 ---------------- */
.menu-wrap { position: relative; }
.menu {
  position: absolute; right: 0; top: calc(100% + 8px); min-width: 232px; background: #fff;
  border: 1px solid var(--line); border-radius: 12px; box-shadow: 0 12px 34px rgba(23,35,61,.14);
  padding: 8px; display: none; z-index: 120;
}
.menu.open { display: block; }
.menu .m-head { font-size: 11px; letter-spacing: 1.4px; color: var(--faint); padding: 6px 10px; }
.menu a { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 9px; font-size: 13px; color: var(--ink); }
.menu a:hover { background: #f5f8ff; color: var(--blue); }
.menu a.on { background: var(--blue-soft); color: var(--blue); font-weight: 600; }
.menu .m-ico {
  width: 26px; height: 26px; border-radius: 8px; display: inline-flex; align-items: center;
  justify-content: center; background: #f2f5fa; font-size: 11.5px; font-weight: 700; color: var(--muted);
}
.menu a.on .m-ico { background: #fff; color: var(--blue); }

/* ---------------- 抽屉表单 ---------------- */
.drawer-mask {
  position: fixed; inset: 0; background: rgba(23,35,61,.36); opacity: 0; pointer-events: none;
  transition: opacity .22s ease; z-index: 200;
}
.drawer-mask.open { opacity: 1; pointer-events: auto; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: 540px; max-width: 94vw; background: #fff;
  box-shadow: -8px 0 40px rgba(23,35,61,.16); transform: translateX(102%);
  transition: transform .26s cubic-bezier(.4,0,.2,1); z-index: 210; display: flex; flex-direction: column;
}
.drawer.open { transform: none; }
.dw-head { display: flex; align-items: center; justify-content: space-between; padding: 18px 22px; border-bottom: 1px solid var(--line); }
.dw-title { font-size: 16px; font-weight: 700; }
.dw-sub { font-size: 12px; color: var(--faint); margin-top: 4px; }
.dw-close { width: 30px; height: 30px; border-radius: 8px; border: 1px solid var(--line); background: #fff; color: var(--muted); cursor: pointer; font-size: 15px; line-height: 1; }
.dw-close:hover { color: var(--blue); border-color: #c8d8ff; }
.dw-body { padding: 20px 22px; overflow-y: auto; flex: 1; }
.dw-foot { display: flex; gap: 10px; justify-content: flex-end; padding: 16px 22px; border-top: 1px solid var(--line); background: #fbfcfe; }

.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px 16px; }
@media (max-width: 560px) { .form-grid { grid-template-columns: 1fr; } }
.f-item { display: flex; flex-direction: column; gap: 6px; }
.f-item.full { grid-column: 1 / -1; }
.f-item label { font-size: 12px; color: var(--muted); }
.f-item label .req { color: #e0574a; margin-left: 2px; }
.f-item input, .f-item select, .f-item textarea {
  font-family: inherit; font-size: 13px; color: var(--ink); border: 1px solid var(--line);
  border-radius: 9px; padding: 9px 11px; background: #fff; outline: none; transition: all .16s ease; width: 100%;
}
.f-item input:focus, .f-item select:focus, .f-item textarea:focus { border-color: #b9cdff; box-shadow: 0 0 0 3px rgba(47,107,255,.10); }
.f-item textarea { min-height: 84px; resize: vertical; line-height: 1.7; }

/* ---------------- 标签页（链接版） ---------------- */
.tabs a { padding: 7px 16px; font-size: 13px; color: var(--muted); border-radius: 8px; display: inline-flex; align-items: center; gap: 6px; }
.tabs a.on { background: #fff; color: var(--ink); font-weight: 600; box-shadow: 0 1px 3px rgba(23,35,61,.12); }
/* 页签上的实时条数（跟着筛选走）：公海池 0 / 业务员客户池 4
   —— 用户选了 VIP 在公海看到空表，靠这个一眼看出东西在另一个池子里 */
.tabs a .tab-n {
  min-width: 20px; padding: 1px 7px; border-radius: 999px; font-size: 11.5px; font-weight: 600;
  background: rgba(23,35,61,.06); color: var(--muted); text-align: center; line-height: 1.7;
  font-variant-numeric: tabular-nums;
}
.tabs a.on .tab-n { background: var(--blue-soft); color: var(--blue); }
.tabs a .tab-n:empty { display: none; }

/* ---------------- 搜索框内的输入 ---------------- */
.search input { border: none; outline: none; font-family: inherit; font-size: 13px; flex: 1; background: transparent; color: var(--ink); min-width: 60px; }
.search input::placeholder { color: #b3bcc9; }

/* ---------------- 首页功能总览 ---------------- */
/* 统一卡高（2026-09-29）：这里原本挂着 align-items:start，每张卡各按内容撑高 ——
   CRM 11 项撑成业绩看板 2 项的 4 倍，同排高低错落、第二行右侧还空一格。
   去掉它，行内卡片自动拉平；行与行之间靠"折叠后每张卡最多 6 项"自然接近，
   所以不必再上 grid-auto-rows:1fr（那会让展开一张卡时全块一起变高）。 */
.all-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
@media (max-width: 1080px) { .all-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .all-grid { grid-template-columns: 1fr; } }
/* flex column：好让折叠按钮用 margin-top:auto 贴到卡底 —— 短卡的空白留在列表下方，
   边框依然齐平。 */
.all-card { background: #fff; border: 1px solid var(--line); border-radius: 16px; box-shadow: var(--shadow-card); padding: 18px 18px 14px; display: flex; flex-direction: column; }
.all-card .ac-head { display: flex; align-items: center; gap: 9px; padding-bottom: 12px; border-bottom: 1px solid var(--line); margin-bottom: 10px; }
.all-card .ac-num {
  width: 26px; height: 26px; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center;
  font-size: 11.5px; font-weight: 700; color: var(--blue); background: var(--blue-soft);
}
.all-card .ac-title { font-size: 14px; font-weight: 700; }
.all-card .ac-count { margin-left: auto; font-size: 11px; color: var(--faint); }
.all-list { display: flex; flex-direction: column; gap: 2px; }
.all-list a { font-size: 12.8px; color: var(--muted); padding: 6px 8px; border-radius: 8px; display: flex; align-items: center; gap: 8px; }
.all-list a:hover { background: #f5f8ff; color: var(--blue); }
.all-list a::before { content: ""; width: 5px; height: 5px; border-radius: 2px; background: #cbd4e3; flex-shrink: 0; }
.all-list a:hover::before { background: var(--blue); }

/* ---------------- 首页「全部功能」长列表折叠 ----------------
   可见项 > 6 时只显示前 6 条，卡底一个「还有 N 项 ▾」；点开展全部、再点收起。
   ★ 显隐与文案全部由 app.js 的 applyAllCollapse() 按**可见项**决定 ——
   无权页面已被 auth.js 设成 display:none，若按 DOM 里的项数算，
   业务员那张只剩 5 项的 CRM 卡会凭空多出一个点开来什么也没有的按钮。 */
.all-list a.is-hidden { display: none; }
.all-card.is-open .all-list a.is-hidden { display: flex; }
.all-card .ac-more {
  margin-top: auto; padding: 9px 8px 0; border: none; background: none;
  font-family: inherit; font-size: 12.2px; color: var(--blue); cursor: pointer;
  display: flex; align-items: center; gap: 5px; text-align: left;
}
.all-card .ac-more[hidden] { display: none; }
.all-card .ac-more::after { content: "\25BE"; font-size: 9px; line-height: 1; transition: transform .15s; }
.all-card.is-open .ac-more::after { transform: rotate(180deg); }
.all-card .ac-more:hover { text-decoration: underline; }


/* ============================================================
   v2.1 数据接入层 / 数据页 / 命令面板 / 移动端
   ============================================================ */

/* ---------------- 数值占位与就绪态 ---------------- */
.kv { font-style: normal; }
[data-kpi].k-pending, .k-pending { color: var(--faint); }
.stat-card .s-value .k-ready { color: #0f9d58; }
.s-value .u-unit, .lg-val .u-unit { font-size: 13px; color: var(--muted); margin-left: 2px; font-weight: 500; }
.k-delta { font-size: 11.5px; margin-left: 6px; font-weight: 600; }
.k-delta.up { color: #d93025; }
.k-delta.down { color: #0f9d58; }

/* ---------------- 数据未接入提示条 ---------------- */
.data-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: #fff8e6; border: 1px solid #f6e3b4; color: #8a6100;
  border-radius: 12px; padding: 10px 14px; font-size: 12.8px; margin-bottom: 16px;
}
.data-bar .db-dot { width: 7px; height: 7px; border-radius: 50%; background: #f0a500; flex-shrink: 0; }
.data-bar.on { background: #eefaf1; border-color: #c6eed5; color: #0b7a43; }
.data-bar.on .db-dot { background: #12a150; }
.data-bar a { color: inherit; font-weight: 600; text-decoration: underline; }

/* ---------------- 数据接入页 ---------------- */
.src-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; }
@media (max-width: 900px) { .src-grid { grid-template-columns: 1fr; } }
.src-card { background: #fff; border: 1px solid var(--line); border-radius: 16px; box-shadow: var(--shadow-card); padding: 18px; }
.src-card .sc-top { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.src-card .sc-logo { width: 34px; height: 34px; border-radius: 10px; display: inline-flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700; }
.src-card .sc-name { font-size: 14.5px; font-weight: 700; }
.src-card .sc-kind { font-size: 11.5px; color: var(--faint); }
.src-card .sc-desc { font-size: 12.6px; color: var(--muted); line-height: 1.75; margin-bottom: 12px; }
.badge { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; padding: 3px 9px; border-radius: 20px; font-weight: 600; }
.badge.wait { background: #fff5e6; color: #a3690a; }
.badge.ready { background: #e9f8ef; color: #0b7a43; }
.badge.plan { background: #eef1f6; color: #5b6a82; }
.badge.blue { background: #eaf1ff; color: var(--blue); }
.src-meta { display: flex; align-items: center; justify-content: space-between; gap: 10px; border-top: 1px dashed var(--line); padding-top: 11px; margin-top: 2px; font-size: 12px; color: var(--faint); }

/* ---------------- 接入步骤 ---------------- */
.flow4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
@media (max-width: 900px) { .flow4 { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .flow4 { grid-template-columns: 1fr; } }
.f4 { background: #fbfcfe; border: 1px solid var(--line); border-radius: 14px; padding: 14px; }
.f4 .f4-n { width: 22px; height: 22px; border-radius: 7px; background: var(--blue); color: #fff; font-size: 11.5px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 9px; }
.f4 .f4-t { font-size: 13.5px; font-weight: 700; margin-bottom: 5px; }
.f4 .f4-d { font-size: 12.3px; color: var(--muted); line-height: 1.7; }

/* ---------------- 进度 ---------------- */
.prog-row { display: flex; align-items: center; gap: 12px; padding: 11px 2px; border-bottom: 1px solid var(--line); font-size: 13px; }
.prog-row:last-child { border-bottom: none; }
.prog-row .pr-name { width: 150px; flex-shrink: 0; font-weight: 600; }
.prog-track { flex: 1; height: 7px; border-radius: 6px; background: #eef1f6; overflow: hidden; }
.prog-fill { height: 100%; border-radius: 6px; background: linear-gradient(90deg,#2f6bff,#66a0ff); width: 0; }
.prog-row .pr-val { width: 78px; text-align: right; color: var(--muted); font-size: 12.4px; }
@media (max-width: 640px) { .prog-row .pr-name { width: 96px; } }

/* ---------------- 代码 / 键名 ---------------- */
code.k { background: #f4f6fa; border: 1px solid var(--line); border-radius: 6px; padding: 1px 6px; font-size: 12px; font-family: Consolas, Menlo, monospace; color: #38506f; }
.kv-list { display: flex; flex-wrap: wrap; gap: 7px; }
.kv-list code.k { font-size: 11.6px; }

/* ---------------- 命令面板 ---------------- */
.palette-mask { position: fixed; inset: 0; background: rgba(16,26,45,.42); backdrop-filter: blur(2px); opacity: 0; pointer-events: none; transition: opacity .18s; z-index: 60; }
.palette-mask.open { opacity: 1; pointer-events: auto; }
.palette {
  position: fixed; top: 12vh; left: 50%; transform: translateX(-50%) scale(.98); width: min(620px, calc(100vw - 32px));
  background: #fff; border-radius: 16px; box-shadow: 0 24px 60px rgba(20,35,60,.28); z-index: 61;
  opacity: 0; pointer-events: none; transition: opacity .16s, transform .16s; overflow: hidden;
}
.palette.open { opacity: 1; pointer-events: auto; transform: translateX(-50%) scale(1); }
.palette .pl-top { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid var(--line); }
.palette .pl-top input { flex: 1; border: none; outline: none; font-family: inherit; font-size: 15px; color: var(--ink); background: transparent; }
.palette .pl-hint { font-size: 11.5px; color: var(--faint); border: 1px solid var(--line); border-radius: 6px; padding: 2px 6px; }
.palette .pl-list { max-height: 54vh; overflow: auto; padding: 8px; }
.palette .pl-item { display: flex; align-items: center; gap: 10px; padding: 9px 11px; border-radius: 10px; font-size: 13.4px; color: var(--ink); }
.palette .pl-item:hover, .palette .pl-item.on { background: #f2f6ff; }
.palette .pl-item .pl-mod { font-size: 11px; color: var(--faint); background: #f4f6fa; border-radius: 6px; padding: 2px 7px; flex-shrink: 0; }
.palette .pl-item .pl-arrow { margin-left: auto; color: var(--faint); font-size: 12px; }
.palette .pl-empty { padding: 26px; text-align: center; color: var(--faint); font-size: 13px; }
.palette .pl-foot { display: flex; gap: 14px; padding: 9px 16px; border-top: 1px solid var(--line); background: #fbfcfe; font-size: 11.5px; color: var(--faint); }
.tp-search { display: inline-flex; align-items: center; gap: 7px; background: #f4f6fa; border: 1px solid var(--line); border-radius: 20px; padding: 6px 13px; font-size: 12.5px; color: var(--muted); cursor: pointer; }
.tp-search:hover { background: #eef2f9; color: var(--ink); }
.tp-search kbd { font-family: inherit; font-size: 11px; background: #fff; border: 1px solid var(--line); border-radius: 5px; padding: 1px 5px; color: var(--faint); }

/* ---------------- 移动端（≤900px）：悬浮菜单收窄 + 顶栏换行 ----------------
   2026-09-23 老张问「用手机查看的话，侧边菜单栏的位置是不是也得调整一下」。
   原来手机上侧栏被压成页面最顶上一条横向标签条（挤在顶栏之上、还拖出一条滚动条）→ 改成左侧抽屉。
   2026-09-24 桌面也统一成悬浮菜单（见 .sidebar 全局规则），所以这里只留手机端的差异：
   抽屉更宽、内边距略收、遮罩更深、顶栏换行。 */
@media (max-width: 900px) {
  .sidebar {
    width: min(80vw, 300px);
    padding: 18px 14px 24px;
  }
  .nav-mask { display: block; background: rgba(16,26,45,.42); }
  .layout.nav-open .nav-mask { opacity: 1; pointer-events: auto; }
  /* 手机档顶栏是 padding: 10px 16px → ☰ 在 x≈16（不是 32），✕ 跟着同位，仍是"☰ 原地变 ✕" */
  .sidebar .sb-close { left: 16px; top: 11px; }
  .sidebar .sb-label { display: block; }
  .sidebar .sb-title { font-size: 18px; }
  .sidebar .sb-nav { display: flex; flex-direction: column; gap: 4px; overflow: visible; }
  .sidebar .sb-group { display: block; }
  .sidebar .sg-head { display: block; }
  .sidebar .sb-item { white-space: nowrap; }
  .sidebar-bottom { display: block; }

  /* 顶栏：不能写死 60px —— 窄屏要换行，写死高度会让第二行溢出、压住正文 */
  .main-topbar { height: auto; min-height: 56px; }
  .topbar-inner { flex-wrap: wrap; gap: 8px; padding: 10px 16px; height: auto; }
  .topbar-inner .crumb { font-size: 12.5px; }
  /* 手机上只留当前页名，去掉「禹拓公司工作台 ⁄」前缀 —— 顶栏少占一行 */
  .topbar-inner .crumb-root { display: none; }
  .topbar-inner .brand-block .bb-sub { display: none; }
  .topbar-inner .chip-open { display: none; }
  .main-body { padding: 18px 16px 48px; }
}

/* ---------------- 移动端：首页（≤760px） ---------------- */
@media (max-width: 760px) {
  .topbar { height: auto; flex-wrap: wrap; gap: 10px; padding: 12px 16px; }
  .topbar-divider { display: none; }
  .topbar-title { order: 3; width: 100%; }
  .topbar-right { margin-left: auto; gap: 8px; }
  .user-chip .u-name { display: none; }
  .hero { flex-direction: column; align-items: stretch; padding: 26px 20px; gap: 20px; }
  .hero h1 { font-size: 24px; letter-spacing: 0; }
  .hero p { font-size: 13px; }
  .date-card { min-width: 0; width: 100%; padding: 16px 18px; }
  .page { padding: 18px 16px 44px; }
  .section-head { margin: 26px 0 14px; gap: 10px; flex-wrap: wrap; }
  .section-head h2 { font-size: 16px; }
  .section-badge { display: none; }
  .tp-search { display: none; }
  .quick-item { font-size: 12.5px; padding: 9px 13px; }
  .module-card { padding: 18px; }
  .stat-card { padding: 14px; }
  .hero-line h1 { font-size: 22px; letter-spacing: 0; }
  .stat-grid { grid-template-columns: 1fr 1fr; gap: 12px; }
  /* 窄屏图例挤成一条时中文标签会按字拆行（「未分级」竖成三行）→ 禁止折行 */
  .legend .lg-item { white-space: nowrap; }
  .src-line { flex-wrap: wrap; }
  .data-bar { font-size: 12px; }
}
@media (max-width: 420px) { .stat-grid { grid-template-columns: 1fr; } }

/* （原来这里还有一段「手机端侧栏 = 横向标签条」的覆盖规则，2026-09-23 已换成上面的抽屉方案，
    两段并存会互相打架：一个把 sb-nav 排成横的一行、一个排成竖的一列。全部合并到上面那一块了。） */

/* ============================================================
   v2.2 周期筛选（按日 / 按月 / 按年）与日期选择器
   ============================================================ */
.fb-field[hidden] { display: none !important; }
.date-pick {
  display: inline-flex; align-items: center; gap: 2px;
  background: #f4f6fa; border: 1px solid var(--line); border-radius: 10px; padding: 1px 3px;
}
.dp-btn {
  width: 24px; height: 26px; border: none; background: transparent; color: var(--muted);
  font-size: 15px; line-height: 1; cursor: pointer; border-radius: 7px; font-family: inherit;
  display: inline-flex; align-items: center; justify-content: center;
}
.dp-btn:hover { background: #e8edf7; color: var(--blue); }
.dp-btn:active { transform: scale(.94); }
.dp-val {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  border: none; background: transparent; font-family: inherit; cursor: pointer;
  min-width: 84px; padding: 4px 8px; border-radius: 8px; text-align: center;
  font-size: 13px; font-weight: 700; color: var(--ink);
  font-variant-numeric: tabular-nums; letter-spacing: .3px;
}
.dp-val:hover { background: #e8edf7; }
.dp-val.on { background: #e8edf7; box-shadow: inset 0 0 0 1px #c9daff; }
.dp-caret { font-size: 9px; color: var(--faint); }
.dp-week { font-size: 11.5px; color: var(--faint); font-weight: 500; white-space: nowrap; }
.dp-today {
  border: 1px solid var(--line); background: #fff; color: var(--blue); font-size: 12px; font-weight: 600;
  font-family: inherit; border-radius: 8px; padding: 5px 11px; cursor: pointer; white-space: nowrap;
}
.dp-today:hover { background: #f2f6ff; border-color: #c9daff; }
.seg[data-period] { white-space: nowrap; }

/* 周期筛选条：左侧文案可收缩，右侧控件优先、超出自动换行 */
.filter-bar { flex-wrap: wrap; }
.filter-bar > div:first-child { min-width: 0; flex: 1 1 320px; }
.filter-bar .fb-right { flex-wrap: wrap; justify-content: flex-end; row-gap: 10px; }
.seg[data-period] span { padding: 7px 13px; }
.filter-bar .fb-field .lbl { font-size: 11.5px; color: var(--faint); }
.date-row { display: inline-flex; align-items: center; gap: 8px; position: relative; }

/* ---------------- 日历弹层（点日期值展开，年 / 月 / 日逐级选） ---------------- */
.cal-pop {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 45;
  width: 258px; padding: 10px 10px 12px;
  background: #fff; border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 18px 40px rgba(20, 35, 60, .18);
}
.cal-pop[hidden] { display: none !important; }
.cal-head { display: flex; align-items: center; justify-content: space-between; gap: 6px; margin-bottom: 8px; }
.cal-nav {
  width: 26px; height: 26px; flex-shrink: 0; border: 1px solid var(--line); background: #fff;
  border-radius: 8px; color: var(--muted); cursor: pointer; font-family: inherit; font-size: 13px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
}
.cal-nav:hover { background: #f2f6ff; border-color: #c9daff; color: var(--blue); }
.cal-nav:active { transform: scale(.94); }
/* 翻到年份范围两头时，箭头变灰，别让人一直点没反应的按钮 */
.cal-nav.is-dis { color: #c9d2e0; background: #fafbfd; border-style: dashed; cursor: default; }
.cal-nav.is-dis:hover { background: #fafbfd; border-color: var(--line); color: #c9d2e0; }
.cal-nav.is-dis:active { transform: none; }
.cal-title {
  border: none; background: transparent; font-family: inherit; cursor: pointer;
  padding: 4px 9px; border-radius: 8px; font-size: 13px; font-weight: 700; color: var(--ink);
}
.cal-title:hover { background: #f2f6ff; color: var(--blue); }
.cal-title.is-flat { cursor: default; color: var(--muted); font-weight: 600; }
.cal-title.is-flat:hover { background: transparent; color: var(--muted); }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal-wd { font-size: 11px; color: var(--faint); text-align: center; padding: 2px 0 4px; }
.cal-d {
  height: 30px; border: none; background: transparent; border-radius: 8px; cursor: pointer;
  font-family: inherit; font-size: 12.5px; color: var(--ink); font-variant-numeric: tabular-nums;
}
.cal-d:hover { background: #eef3fe; }
.cal-d.out { color: #bcc6d6; }
.cal-d.is-dis, .cal-d.is-dis:hover { color: #d3dae5; background: transparent; cursor: default; }
.cal-d.today { box-shadow: inset 0 0 0 1px #c9daff; color: var(--blue); font-weight: 700; }
.cal-d.on, .cal-d.on:hover { background: var(--blue); color: #fff; font-weight: 700; }
.cal-grid-3 { grid-template-columns: repeat(3, 1fr); gap: 6px; }
.cal-c {
  height: 38px; border: none; background: #f6f8fc; border-radius: 9px; cursor: pointer;
  font-family: inherit; font-size: 12.5px; font-weight: 600; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.cal-c:hover { background: #eef3fe; color: var(--blue); }
.cal-c.on, .cal-c.on:hover { background: var(--blue); color: #fff; }

/* 表格内「询盘转化率」列强调 */
.tbl td.col-rate, .tbl th.col-rate { color: var(--blue); font-weight: 700; }

@media (max-width: 860px) {
  .filter-bar { flex-direction: column; align-items: stretch; gap: 12px; }
  .filter-bar > div:first-child { flex: 0 0 auto; }
  .filter-bar .fb-right { flex-wrap: wrap; justify-content: flex-start; }
  .date-row { order: 1; }
  .dp-today { order: 2; }
  /* 窄屏下日历改为左对齐，避免超出屏幕左边缘 */
  .cal-pop { right: auto; left: 0; width: min(258px, calc(100vw - 56px)); }
}

/* ============================================================
   v2.2 岗位登录 / 岗位化首页 / 权限
   ============================================================ */

/* ---------------- 登录门（首页内联 + 独立登录页共用） ---------------- */
[data-gate], [data-role-section] { display: none; }
[data-gate].on, [data-role-section].on { display: block; }

.gate-wrap { max-width: 1060px; margin: 0 auto; padding: 38px 20px 64px; }
.gate-head { text-align: center; margin-bottom: 8px; }
.gate-head .gh-en { font-size: 11.5px; letter-spacing: .18em; color: var(--faint); font-weight: 700; }
.gate-head h1 { font-size: 26px; margin: 10px 0 9px; letter-spacing: -.3px; }
.gate-head p { color: var(--muted); font-size: 13.4px; margin: 0; line-height: 1.8; }

.role-tabs { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin: 22px 0 18px; }
.role-tab {
  display: inline-flex; align-items: center; gap: 7px; padding: 8px 15px;
  border-radius: 22px; border: 1px solid var(--line); background: #fff;
  font-size: 13px; font-weight: 600; color: var(--muted); cursor: pointer;
  transition: .16s; user-select: none;
}
.role-tab:hover { border-color: #c9d8ff; color: var(--ink); }
.role-tab.on { background: var(--blue); border-color: var(--blue); color: #fff; }
.role-tab .rt-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; opacity: .8; }
.role-tab .rt-n { font-size: 11px; opacity: .7; }

.role-intro {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  background: #f7faff; border: 1px solid #e3ebfb; border-radius: 12px;
  padding: 11px 15px; font-size: 12.8px; color: var(--muted); margin-bottom: 16px;
}
.role-intro b { color: var(--ink); }
.role-intro .ri-scope {
  background: #fff; border: 1px solid var(--line); border-radius: 20px;
  padding: 3px 10px; font-size: 11.5px; font-weight: 600; color: var(--blue);
}

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

.acct-card {
  background: #fff; border: 1px solid var(--line); border-radius: 14px;
  padding: 15px 16px; cursor: pointer; transition: .16s; box-shadow: var(--shadow-card);
}
.acct-card:hover { transform: translateY(-2px); border-color: #c9d8ff; }
.acct-card.on { border-color: var(--blue); box-shadow: 0 0 0 3px rgba(47, 107, 255, .13); }
.acct-card .ac-top { display: flex; align-items: center; gap: 10px; margin-bottom: 9px; }
.acct-card .ac-av {
  width: 34px; height: 34px; border-radius: 10px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 15px; font-weight: 700;
}
.acct-card .ac-nm { font-size: 14.5px; font-weight: 700; line-height: 1.3; }
.acct-card .ac-id { font-size: 11.5px; color: var(--faint); }
.acct-card .ac-meta { font-size: 12.2px; color: var(--muted); line-height: 1.7; }
.acct-card .ac-flag {
  display: inline-block; margin-top: 7px; font-size: 11px; font-weight: 600;
  background: #fff5e6; color: #a3690a; border-radius: 20px; padding: 2px 9px;
}

.pwd-row { display: flex; align-items: center; gap: 10px; margin: 22px 0 0; flex-wrap: wrap; }
.pwd-row .pw-lbl { font-size: 13px; color: var(--muted); }
.pwd-row input {
  flex: 1 1 200px; min-width: 0; border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 13px; font-family: inherit; font-size: 13.5px; color: var(--ink);
  background: #fff; outline: none;
}
.pwd-row input:focus { border-color: var(--blue); box-shadow: 0 0 0 3px rgba(47, 107, 255, .12); }
.gate-actions { display: flex; align-items: center; gap: 12px; margin-top: 16px; flex-wrap: wrap; }
.btn-primary {
  background: var(--blue); color: #fff; border: none; border-radius: 10px;
  padding: 11px 28px; font-family: inherit; font-size: 14px; font-weight: 600; cursor: pointer;
  transition: .16s;
}
.btn-primary:hover { background: #2560f0; }
.btn-primary:disabled { background: #c8d3ea; cursor: not-allowed; }
.gate-note {
  font-size: 12px; color: var(--faint); line-height: 1.85;
  margin-top: 20px; padding-top: 15px; border-top: 1px dashed var(--line);
}
.gate-note b { color: var(--muted); }

/* 独立登录页 */
.login-page { min-height: 100vh; background: linear-gradient(160deg, #f2f6ff 0%, #fbfdff 45%, #fff 100%); }
.login-top { display: flex; align-items: center; gap: 12px; padding: 20px 26px; }
.login-top .lt-sub { font-size: 11.5px; color: var(--faint); letter-spacing: .06em; }

/* 账号 + 密码登录卡（没有"选岗位"这一步：岗位写在账号上，服务端按账号判定） */
.login-card {
  max-width: 460px; margin: 14px auto 90px; background: #fff;
  border: 1px solid var(--line); border-radius: 18px;
  padding: 34px 34px 26px; box-shadow: var(--shadow-card);
}
.login-form { display: flex; flex-direction: column; gap: 15px; margin-top: 24px; }
.lf-item { display: flex; flex-direction: column; gap: 7px; }
.lf-item label { font-size: 12.5px; color: var(--muted); font-weight: 600; }
.lf-item input {
  border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px;
  font-family: inherit; font-size: 14px; color: var(--ink); background: #fff; outline: none;
  transition: .16s;
}
.lf-item input::placeholder { color: #b6c0d2; }
.lf-item input:focus { border-color: var(--blue); box-shadow: 0 0 0 3px rgba(47, 107, 255, .12); }
.lf-msg { font-size: 12.5px; color: #d93025; min-height: 17px; line-height: 1.5; }
.lf-submit { width: 100%; margin-top: 2px; }
.login-roles {
  display: flex; flex-wrap: wrap; gap: 7px; justify-content: center;
  margin: 22px 0 0; padding-top: 18px; border-top: 1px dashed var(--line);
}
.lr-chip {
  display: inline-flex; align-items: center; gap: 6px; background: #f7faff;
  border: 1px solid var(--line); border-radius: 20px; padding: 4px 11px;
  font-size: 11.8px; font-weight: 600; color: var(--muted);
}
.lr-chip .lr-dot { width: 7px; height: 7px; border-radius: 50%; }

/* 登录 / 注册页互跳 + 注册页的下拉与提示 */
.lf-alt { text-align: center; font-size: 13px; color: var(--muted); margin-top: 18px; }
.lf-alt a { color: var(--blue); font-weight: 600; text-decoration: none; }
.lf-alt a:hover { text-decoration: underline; }
.lf-item select {
  border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px;
  font-family: inherit; font-size: 14px; color: var(--ink); background: #fff; outline: none;
  transition: .16s; appearance: none;
}
.lf-item select:focus { border-color: var(--blue); box-shadow: 0 0 0 3px rgba(47, 107, 255, .12); }
.lf-item select:disabled, .lf-item input:disabled { background: #f6f8fc; color: var(--faint); cursor: not-allowed; }
.lf-hint { font-size: 12px; color: var(--faint); line-height: 1.7; }
.lf-msg.ok { color: #0b7a43; }

/* ---------------- 岗位首页：问候区 ---------------- */
.me-hero {
  display: flex; align-items: center; justify-content: space-between; gap: 22px;
  padding: 24px 26px; border-radius: 18px; margin-bottom: 18px;
  background: linear-gradient(120deg, #eef4ff 0%, #f7faff 58%, #fff 100%);
  border: 1px solid #dfe8fb;
}
.me-hero .mh-l { min-width: 0; }
.me-hero .mh-en { font-size: 11.5px; letter-spacing: .17em; color: var(--faint); font-weight: 700; }
.me-hero .mh-l h1 { font-size: 25px; margin: 9px 0 7px; letter-spacing: -.3px; }
.me-hero .mh-l p { margin: 0; font-size: 13.4px; color: var(--muted); line-height: 1.75; }
.me-hero .mh-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 13px; }
.role-badge {
  display: inline-flex; align-items: center; gap: 6px; background: #fff;
  border: 1px solid var(--line); border-radius: 20px; padding: 4px 12px;
  font-size: 12px; font-weight: 600; color: var(--muted);
}
.role-badge .rb-dot { width: 7px; height: 7px; border-radius: 50%; }
.scope-badge {
  display: inline-flex; align-items: center; gap: 6px; background: rgba(47, 107, 255, .08);
  border-radius: 20px; padding: 4px 12px; font-size: 12px; font-weight: 600; color: var(--blue);
}
.me-hero .date-card { min-width: 190px; }

/* ---------------- 岗位首页：核心指标卡 ---------------- */
.me-kpi-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
/* 首页是顶部导航、没有侧栏：可用宽度 = min(视口, 1200) − 56 页边距。
   ★ 真正的折列判据在下面的 @container（按「实际可用宽度」判断，见 [data-role-section] 那段）；
     这两条媒体查询只是不支持容器查询时的兜底（视口 < 1080 → 可用宽度 < 1024 → 4 列会挤）。 */
@media (max-width: 1080px) { .me-kpi-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .me-kpi-grid { grid-template-columns: 1fr; } }
/* 只剩两张卡时不要再去占四列网格（右边空两格很难看） */
.me-kpi-grid.is-2 { grid-template-columns: repeat(2, 1fr); }

/* ---------------- 首页：目标达成总览（四个环形） ---------------- */
.me-panel-gap { margin-top: 16px; }
/* 年 / 月 / 分组 / 个人 一排四个；窄屏（含手机）一律折成**两列** ——
   手机原来是一列、每环占掉一整屏、太占地方（2026-10-01 老张：
   「手机版的首页这环状图放两排吧，一排太占地方了」）。 */
.goal-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
/* 业务员版只有三环（公司 / 我组 / 我）→ 三列，别让第 4 格空着
   （2026-09-24 老张：「业务员也有总览，只是总览内容不一样」）。 */
.goal-grid.is-3 { grid-template-columns: repeat(3, 1fr); }
/* ⚠ 折列断点必须把 .is-3 一起写上：`.goal-grid.is-3` 特异性 (0,2,0) 高于 `.goal-grid`(0,1,0)，
   只写后者的话手机上这三环仍是 3 列、会挤（同 `.me-kpi-grid.is-2` 那个坑，2026-09-23 踩过）。 */
@media (max-width: 1100px) { .goal-grid, .goal-grid.is-3 { grid-template-columns: repeat(2, 1fr); } }
/* 手机档：2 列（4 环 → 2×2，三环 → 2+1），间距收紧一点让两排更贴
   （2026-10-01 老张要「两排」；环宽 116、390 宽两列每格 ≈172px，够放）。 */
@media (max-width: 560px) { .goal-grid, .goal-grid.is-3 { grid-template-columns: repeat(2, 1fr); gap: 12px 10px; } }
.goal-cell { text-align: center; padding: 2px 0; }
/* 四个环并排，比原来那个单环收小一号（168 → 116）；中心放达成率，字号比默认的「客户」大。
   ⚠ 底色只是"没数据时"的兜底灰环 —— 真实占比由 app.js 的 paintGoalRings() 画。 */
.donut.donut-sm { width: 116px; height: 116px; margin: 0 auto; background: #eef2f8; }
.donut-sm .d-center {
  flex-direction: column; gap: 2px; line-height: 1.15;
  font-size: 17px; font-weight: 700; color: var(--ink);
}
.donut-sm .d-center small { font-size: 10.5px; font-weight: 500; color: var(--faint); }
.goal-name { margin-top: 10px; font-size: 13px; font-weight: 600; color: var(--ink); }
/* 「目标 ¥ 90,190,000」这种带完整金额的行会折行，行高给足，免得两行挤在一起 */
.goal-foot { margin-top: 3px; font-size: 11.5px; line-height: 1.8; color: var(--faint); }
.goal-foot b { font-weight: 600; color: var(--ink); }

/* ---------------- 销售机会 ·「客户未回复 · 待催办清单」（2026-09-24 老张要求） ----------------
   把 k4 那个「未回复待催 9」的数字变成一份逐条能催的清单。
   勾选状态记在浏览器本地，所以视觉上必须一眼分清「还没催」和「已催」（置灰 + 删除线 + 沉底）。 */
.ot-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ot-title { font-size: 14.5px; font-weight: 700; color: var(--ink); }
.ot-hint { font-size: 12px; color: var(--faint); line-height: 1.6; }
.ot-list { margin-top: 12px; display: flex; flex-direction: column; gap: 8px; }
.ot-row {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; background: #fff;
}
.ot-row:hover { border-color: #c8d8ff; background: #fafbff; }
.ot-row.is-done { opacity: .55; background: #f7f9fd; }
.ot-row.is-done .ot-name { text-decoration: line-through; }
.ot-main { flex: 1; min-width: 220px; }
.ot-name { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13.5px; font-weight: 600; color: var(--ink); }
.ot-sub { margin-top: 4px; font-size: 12px; color: var(--muted); line-height: 1.6; }
.ot-act { display: flex; gap: 8px; flex-shrink: 0; }
@media (max-width: 560px) { .ot-act { width: 100%; justify-content: flex-end; } }

/* ---------------- 业绩看板：业绩仪表盘（一人一环 / 一店一环） ----------------
   ⚠ 环的底色只是"没数据时"的兜底灰；真实占比由 app.js 的 paintPerfDash() 内联画，
     绝不在 CSS 里写死百分比（CRM 总览页早年就这么错过一次）。 */
.dash-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));
  gap: 16px 10px; padding: 16px 18px 6px;
}
.dash-cell { text-align: center; min-width: 0; }
/* 小环：106px。内圆比首页 116px 那款挖得略小一点（inset 22% vs 29%），
   否则「114.5%」这种 6 个字挤不进中心。 */
.donut.donut-xs { width: 106px; height: 106px; margin: 0 auto; background: #eef2f8; }
.donut-xs::after { inset: 22%; }
.donut-xs .d-center {
  flex-direction: column; gap: 1px; line-height: 1.12;
  font-size: 14.5px; font-weight: 700; color: var(--ink); letter-spacing: -.3px;
}
.donut-xs .d-center small { font-size: 9.5px; font-weight: 500; color: var(--faint); letter-spacing: 0; }
/* 姓名 / 店名：给两行的高度。「2.东阳亿邦服饰」这种长名会折行，
   不预留高度的话下面那行「净 ¥…」在同一排里会高低不齐。 */
.dash-name {
  margin-top: 8px; font-size: 12.8px; font-weight: 600; color: var(--ink);
  line-height: 1.4; min-height: 36px;
}
.dash-name em {
  display: inline-block; margin-left: 4px; padding: 0 5px; border-radius: 6px;
  font-style: normal; font-size: 10px; font-weight: 500; vertical-align: 1px;
  color: var(--muted); background: #f2f5fa;
}
.dash-sub { margin-top: 3px; font-size: 11.4px; line-height: 1.65; color: var(--ink); font-weight: 600; }
.dash-sub span { font-weight: 400; color: var(--faint); }
.dash-legend { margin-left: auto; display: flex; align-items: center; gap: 5px; font-size: 11.5px; color: var(--faint); white-space: nowrap; }
.dash-legend i { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.dash-legend i:not(:first-child) { margin-left: 8px; }
.dash-foot { padding: 8px 18px 16px; font-size: 11.6px; line-height: 1.85; color: var(--faint); border-top: 1px solid var(--line); margin-top: 10px; }
.dash-foot .pending { color: var(--faint); }

/* ---------------- 首页「店铺当月业绩」店卡（2026-09-27 老张要的） ----------------
   ⚠ 列数用 auto-fit 自适应，**不写 repeat(3,1fr)** —— 格子数是 app.js 按
     WB_LIVE.shops 现算的（现在 3 个品牌，源表里多一个店/多一个主体就多一张卡），
     写死 3 列会挤出第四条腿。
   ⚠ 金额位数多（¥1,482,007.21），窄屏用 clamp 随宽度缩 —— 用固定 px 会被卡片裁掉
     （同 .mk-val 2026-09-23 手机端踩过的坑）。 */
.shop-perf { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; padding: 16px 18px 4px; }
.shop-card { border: 1px solid var(--line); border-radius: 14px; padding: 15px 16px; background: #fff; }
.shop-card .sc-hd { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.shop-card .sc-name { font-size: 14px; font-weight: 700; color: var(--ink); }
.shop-card .sc-share { font-size: 11.6px; font-weight: 600; color: var(--blue); white-space: nowrap; }
.shop-card .sc-val {
  font-size: clamp(17px, 4.6vw, 22px); font-weight: 700; letter-spacing: -.4px; color: var(--ink);
  font-variant-numeric: tabular-nums; margin: 9px 0 11px;
}
.shop-card .sc-bar { height: 6px; border-radius: 6px; background: #eef1f6; overflow: hidden; }
.shop-card .sc-bar i { display: block; height: 100%; border-radius: 6px; background: linear-gradient(90deg, #2f6bff, #66a0ff); transition: width .5s; }
.shop-card .sc-sub { font-size: 11.5px; line-height: 1.75; color: var(--faint); margin-top: 10px; }

.me-kpi {
  background: #fff; border: 1px solid var(--line); border-radius: 16px;
  padding: 18px 20px; box-shadow: var(--shadow-card); position: relative; overflow: hidden;
}
.me-kpi .mk-label { font-size: 12.4px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.me-kpi .mk-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--blue); }
/* 标签 → 数字 → 说明 三段之间各留一口气（原来 9/3 太贴，老张说看着挤）。
   金额位数多，窄屏/两列时 25px 会被卡片裁掉（2026-09-23 手机端实测「¥5,669,177.58」右边被切）→ 用 clamp 随宽度缩。 */
.me-kpi .mk-val {
  font-size: clamp(18px, 5.4vw, 25px); font-weight: 700; margin: 11px 0 5px; letter-spacing: -.5px;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
.me-kpi .mk-val.k-pending { color: var(--faint); font-weight: 600; }
.me-kpi .mk-sub { font-size: 11.8px; color: var(--faint); line-height: 1.72; }
.me-kpi .mk-bar { height: 7px; border-radius: 6px; background: #eef1f6; overflow: hidden; margin-top: 12px; }
.me-kpi .mk-fill { height: 100%; width: 0; border-radius: 6px; background: linear-gradient(90deg, #2f6bff, #66a0ff); transition: width .5s; }
.me-kpi.is-green .mk-dot, .me-kpi.is-green .mk-fill { background: linear-gradient(90deg, #10b981, #4bd0a0); }
.me-kpi.is-green .mk-dot { background: #10b981; }
.me-kpi.is-orange .mk-dot { background: #f59e0b; }
.me-kpi.is-orange .mk-fill { background: linear-gradient(90deg, #f59e0b, #fbc46a); }
.me-kpi.is-purple .mk-dot { background: #8b5cf6; }
.me-kpi.is-purple .mk-fill { background: linear-gradient(90deg, #8b5cf6, #b39bfa); }

/* ---------------- 岗位首页：两栏面板 ---------------- */
.me-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.me-2col.wide-left { grid-template-columns: 1.15fr .85fr; }
/* ★ KPI 卡行后面**直接**跟两栏面板时，必须补一段上下间距。
   首页别的区块都有人撑开：要么前面有 .section-head（margin-bottom 18）、要么外面包着
   .me-panel-gap（margin-top 16）—— 只有「1688 接待质检」那条路两边都没人管，
   卡行与面板贴成 **0px**（2026-09-22 老张截图：「上下没缝了，挤一块了」，
   实测 .me-kpi-grid 的 bottom 与 .me-2col 的 top 完全重合）。
   取 18px 与 .section-head 的下边距同值，整页垂直节奏才一致；
   用相邻选择器只修这一种拼法，不外溢到前面有标题的那些面板。 */
.me-kpi-grid + .me-2col { margin-top: 18px; }
/* 兜底（同上）：视口 < 1080 时可用宽度已 < 1024，两栏的右栏放不下条形图 */
@media (max-width: 1080px) { .me-2col, .me-2col.wide-left { grid-template-columns: 1fr; } }

/* ---------------- 首页：折列按「实际可用宽度」判断（2026-09-22 老张：「太挤了」） ----------------
   症状：4 张 KPI 卡被挤到 223px，「客户最后一条未回 / 全程无人工回复」的说明文字折成两行、
   整排卡从 124px 被撑到 143px；两栏面板的右栏也被「名字 104 + 数值 105」把条形槽压到 126px。
   根因：折列断点原来按 **视口** 拍（1100 / 1000），但真实可用宽度是
       可用宽度 = min(视口, 1200) − 56 页边距   （首页没有侧栏）
   两个数根本不是一回事 —— 视口在 1080 上下时可用宽度早就不到 1020 了，却还硬排 4 列；
   反过来，光靠注入样式把容器压窄也复现不出问题（媒体查询看的是视口，不是容器）。
   → 改用**容器查询**，容器选 [data-role-section]：
     · 只有首页有它（子页一律没有），改动不外溢；
     · 内部只有卡片与面板，没有 position:fixed 元素，加 contain 不会挪动抽屉 / toast。
     卡宽 < 243px（可用宽度 < 1020）折 2 列，可用宽度 < 500 折 1 列。 */
[data-role-section] { container-type: inline-size; }
@container (max-width: 1020px) {
  .me-kpi-grid { grid-template-columns: repeat(2, 1fr); }
  .me-2col, .me-2col.wide-left { grid-template-columns: 1fr; }
  /* 版块快捷入口：6 列要 150px/格才不折名，可用宽度 < 1020 时改 3 列 */
  .mod-strip { grid-template-columns: repeat(3, 1fr); }
}
@container (max-width: 500px) {
  /* ⚠ 必须带上 .is-2：`.me-kpi-grid.is-2{repeat(2,1fr)}` 的特异性(0,2,0)高于 `.me-kpi-grid`(0,1,0)，
     只写后者的话在手机上「只剩两张卡」的首页仍然是两列、数字被裁（2026-09-23 手机端实测）。 */
  .me-kpi-grid, .me-kpi-grid.is-2 { grid-template-columns: 1fr; }
  /* 版块快捷入口在手机上两列并排，图标与内边距各收一号，"CRM客户管理"才不会被截成省略号 */
  .mod-strip { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .ms-cell { padding: 10px 12px; gap: 8px; }
  .ms-ico { width: 30px; height: 30px; border-radius: 9px; }
  .ms-ico svg { width: 16px; height: 16px; }
  .ms-name { font-size: 13px; }
}

.panel-head {
  display: flex; align-items: center; gap: 10px; padding: 14px 18px;
  border-bottom: 1px solid var(--line);
}
.panel-head h3 { font-size: 14.5px; margin: 0; font-weight: 700; }
.panel-head .ph-sub { font-size: 11.8px; color: var(--faint); }
.panel-head .ph-right { margin-left: auto; font-size: 12px; color: var(--faint); }
.panel-head a.ph-right { color: var(--blue); font-weight: 600; text-decoration: none; }
.panel-body { padding: 16px 18px; }

/* 跟进状态分布 */
.fs-list { display: flex; flex-direction: column; gap: 13px; }
.fs-item { display: flex; align-items: center; gap: 11px; font-size: 13px; }
.fs-item .fs-name { width: 112px; flex-shrink: 0; color: var(--muted); }
.fs-item .fs-track { flex: 1; height: 8px; border-radius: 6px; background: #eef1f6; overflow: hidden; }
/* ⚠ `.fs-bar` 必须显式 display:block。
   它是 <span>（内联），而父级 `.fs-track` 只是普通块，**不是 flex 容器** —— 内联元素上的
   width / height 一律被忽略，于是"槽在、条不见"，整条看起来是空的（2026-09-22 老张截图发现）。
   `.fs-track` 自己之所以正常，是因为它同时是 `.fs-item`（display:flex）的 flex item，
   flex item 会被 blockify —— 别再把这个区别搞混。 */
.fs-item .fs-bar { display: block; height: 100%; width: 0; border-radius: 6px; background: #2f6bff; }
.fs-item .fs-n {
  width: 54px; text-align: right; font-weight: 700;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
.fs-item .fs-n.k-pending { color: var(--faint); font-weight: 600; }
@media (max-width: 560px) { .fs-item .fs-name { width: 88px; font-size: 12.4px; } }

/* 首页 · 聊天分析仪表盘：那两块列的是业务员名与客户昵称，比固定标签长得多，
   名字截断加省略号、右侧数字给足宽度，免得把中间的条形挤没。 */
.qa-dash-list .fs-item .fs-name {
  width: 104px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--ink);
}
.qa-dash-list .fs-item .fs-n { width: auto; min-width: 96px; }

/* 迷你趋势图 */
.ch-wrap { padding: 4px 2px 0; }
.ch-chart { display: flex; align-items: flex-end; gap: 10px; height: 132px; padding-top: 10px; }
.ch-col { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 6px; height: 100%; }
.ch-bar { width: 100%; max-width: 40px; border-radius: 7px 7px 3px 3px; background: linear-gradient(180deg, #66a0ff, #2f6bff); min-height: 4px; }
.ch-bar.pending { background: #e6ebf3; }
.ch-x { font-size: 11px; color: var(--faint); }
.ch-legend { display: flex; gap: 14px; font-size: 11.8px; color: var(--faint); margin-top: 12px; }

/* 提醒列表 */
.rem-list { display: flex; flex-direction: column; }
.rem-item {
  display: flex; align-items: center; gap: 12px; padding: 12px 18px;
  border-bottom: 1px solid var(--line); font-size: 13px;
}
.rem-item:last-child { border-bottom: none; }
.rem-item:hover { background: #fafcff; }
.rem-item .ri-main { min-width: 0; flex: 1; }
.rem-item .ri-nm { font-weight: 600; margin-bottom: 3px; }
.rem-item .ri-sub { font-size: 11.8px; color: var(--faint); }
.rem-item .ri-tag { font-size: 11.5px; font-weight: 600; border-radius: 20px; padding: 3px 10px; white-space: nowrap; }
.tag-blue { background: #eaf1ff; color: var(--blue); }
.tag-red { background: #fdeaea; color: #d93025; }
.tag-orange { background: #fff5e6; color: #a3690a; }
.tag-green { background: #e9f8ef; color: #0b7a43; }
.tag-grey { background: #eef1f6; color: #64748b; }
.rem-item .ri-go { font-size: 12px; color: var(--blue); font-weight: 600; white-space: nowrap; }

/* 空态 */
.me-empty { padding: 30px 18px; text-align: center; color: var(--faint); font-size: 12.6px; line-height: 1.9; }
.me-empty b { color: var(--muted); }

/* 岗位任务清单（客服 / 美工首页） */
.task-list { display: flex; flex-direction: column; gap: 11px; }
.task-item {
  display: flex; align-items: center; gap: 12px; padding: 13px 15px;
  border: 1px solid var(--line); border-radius: 13px; background: #fff; transition: .16s;
  text-decoration: none; color: inherit;
}
.task-item:hover { border-color: #c9d8ff; transform: translateX(2px); }
.task-item .ti-ico {
  width: 34px; height: 34px; border-radius: 10px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 700;
}
.task-item .ti-main { flex: 1; min-width: 0; }
.task-item .ti-t { font-size: 13.4px; font-weight: 600; margin-bottom: 3px; }
.task-item .ti-d { font-size: 11.8px; color: var(--faint); }
.task-item .ti-n {
  font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ink);
}
.task-item .ti-n.k-pending {
  color: var(--faint); font-size: 11.5px; font-weight: 600; letter-spacing: .2px;
  padding: 2px 8px; border: 1px dashed var(--line); border-radius: 999px;
}

/* ---------------- 顶栏用户菜单 ---------------- */
.user-chip { cursor: pointer; user-select: none; }
.user-chip:hover { background: #f2f6ff; }
.user-chip .u-role { font-size: 11px; color: var(--faint); line-height: 1.3; }
.umenu { min-width: 236px; }
.umenu .um-info { padding: 13px 14px; border-bottom: 1px solid var(--line); }
.umenu .um-info .ui-nm { font-size: 14px; font-weight: 700; margin-bottom: 4px; }
.umenu .um-info .ui-sub { font-size: 11.8px; color: var(--faint); line-height: 1.7; }
.umenu a { display: flex; align-items: center; gap: 9px; }
.umenu a .um-k { margin-left: auto; font-size: 11px; color: var(--faint); }

/* ---------------- 无权限提示 ---------------- */
.noperm {
  max-width: 560px; margin: 72px auto; background: #fff; border: 1px solid var(--line);
  border-radius: 18px; padding: 32px 28px; text-align: center; box-shadow: var(--shadow-card);
}
.noperm .np-ico {
  width: 52px; height: 52px; border-radius: 16px; background: #fdeaea; color: #d93025;
  display: inline-flex; align-items: center; justify-content: center; font-size: 22px; margin-bottom: 15px;
}
.noperm h2 { font-size: 18px; margin: 0 0 10px; }
.noperm p { font-size: 13px; color: var(--muted); line-height: 1.85; margin: 0 0 20px; }
.noperm .np-act { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
.btn-ghost {
  display: inline-flex; align-items: center; gap: 6px; background: #fff; color: var(--ink);
  border: 1px solid var(--line); border-radius: 10px; padding: 10px 20px;
  font-family: inherit; font-size: 13.5px; font-weight: 600; cursor: pointer; text-decoration: none;
}
.btn-ghost:hover { border-color: #c9d8ff; background: #f7faff; }
.perm-note {
  display: flex; align-items: center; gap: 9px; background: #e6f6fe; border: 1px solid #bfe6f8;
  color: #0a6c8f; border-radius: 12px; padding: 9px 14px; font-size: 12.6px; margin-bottom: 16px;
}
.perm-note b { color: #075a78; }
.perm-note a { color: #075a78; font-weight: 700; text-decoration: underline; }

/* ---------------- 板块权限：只读提示 / 权限抽屉 / 权限矩阵 ---------------- */
.perm-note.readonly { background: #fff7e6; border-color: #ffe0a3; color: #8a5a00; }
.perm-note.readonly b { color: #7a4f00; }
.perm-note .pn-tag {
  flex: none; background: #f59e0b; color: #fff; border-radius: 6px;
  padding: 2px 8px; font-size: 11.5px; font-weight: 700; letter-spacing: .3px;
}
.drawer-wide { width: 640px; max-width: 94vw; }

.perm-legend { display: flex; flex-direction: column; gap: 8px; margin-top: 15px; }
.pl-item { display: flex; align-items: center; gap: 10px; font-size: 12.8px; color: var(--muted); }
.pl-tag {
  flex: none; width: 64px; text-align: center; border-radius: 6px;
  padding: 3px 0; font-size: 11.5px; font-weight: 700;
}
.pl-tag.none { background: #eef1f6; color: #64748b; }
.pl-tag.view { background: #e6f6fe; color: #0a6c8f; }
.pl-tag.edit { background: #e7f8f1; color: #0b7a43; }

.perm-sec { border-top: 1px dashed var(--line); padding-top: 17px; margin-top: 17px; }
.perm-sec:first-of-type { border-top: none; padding-top: 0; margin-top: 0; }
.perm-sec-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 11px; flex-wrap: wrap; }
.perm-sec-head b { font-size: 13.5px; }
.perm-sec-head span { font-size: 12px; color: var(--muted); }

.perm-scopes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.perm-scope-opt {
  border: 1px solid var(--line); border-radius: 11px; padding: 10px 12px; cursor: pointer;
  display: flex; flex-direction: column; gap: 4px; background: #fff; transition: .15s;
}
.perm-scope-opt:hover { border-color: #c9d8ff; background: #f7faff; }
.perm-scope-opt.on { border-color: var(--blue); background: #eef3ff; box-shadow: inset 0 0 0 2px #dbe6ff; }
.pso-name { font-size: 13px; font-weight: 700; }
.pso-desc { font-size: 11.5px; color: var(--muted); line-height: 1.5; }
.perm-tip {
  margin-top: 10px; font-size: 12px; color: #0a6c8f;
  background: #f2f9fd; border-radius: 8px; padding: 8px 11px; line-height: 1.6;
}

.perm-tbl th { font-size: 12px; }
.perm-tbl td { padding: 8px 10px; }
.pm-name { font-size: 13px; font-weight: 600; }
.pm-cell { text-align: center; }
.pm-opt {
  display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px;
  color: var(--muted); cursor: pointer; user-select: none;
}
.pm-dot { width: 12px; height: 12px; border-radius: 50%; border: 2px solid #cdd6e3; background: #fff; }
.pm-opt.on { color: var(--ink); font-weight: 600; }
.pm-opt.on .pm-dot.none { border-color: #94a3b8; background: #94a3b8; }
.pm-opt.on .pm-dot.view { border-color: #0ea5e9; background: #0ea5e9; }
.pm-opt.on .pm-dot.edit { border-color: #10b981; background: #10b981; }

.perm-mini { font-size: 12.5px; color: var(--ink); }
.perm-mini em { font-style: normal; color: #0b7a43; }
.perm-scope-tag { display: inline-block; border-radius: 6px; padding: 2px 8px; font-size: 12px; font-weight: 600; }
.perm-scope-tag.s-self { background: #e6f6fe; color: #0a6c8f; }
.perm-scope-tag.s-team { background: #e7f8f1; color: #0b7a43; }
.perm-scope-tag.s-all { background: #eef3ff; color: #2f6bff; }

/* 只读模式下被禁用的写操作 */
[data-edit].is-readonly { opacity: .45; cursor: not-allowed; }

/* ---------------- CRM 人工修改层：提示条 / 保存条 / 可编辑单元格 ----------------
   数据分两层：企微每天同步的值 ⊕ 人工改过的值（人工优先）。
   改过的单元格标橙（.edited），没保存的再加深一层（.dirty），让人一眼分清。 */
.edit-bar {
  display: flex; align-items: center; gap: 9px; background: #fff7e6; border: 1px solid #ffe0a3;
  color: #8a5a00; border-radius: 12px; padding: 9px 14px; font-size: 12.6px;
  margin-bottom: 12px; line-height: 1.7;
}
.edit-bar .eb-tag {
  flex: none; background: #f59e0b; color: #fff; border-radius: 6px;
  padding: 2px 8px; font-size: 11.5px; font-weight: 700; letter-spacing: .3px;
}
.save-bar {
  position: sticky; bottom: 14px; z-index: 30;
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  background: #fff; border: 1px solid #ffd9a3; border-radius: 12px;
  padding: 10px 14px; margin-bottom: 14px;
  box-shadow: 0 6px 18px rgba(15, 23, 42, .12);
  font-size: 13px; font-weight: 600; color: #8a5a00;
}
.save-bar .btn { padding: 8px 18px; }
/* hidden 属性要压过上面的 display，否则两条一直挂着 */
.edit-bar[hidden], .save-bar[hidden] { display: none !important; }

.ce {
  width: 100%; min-width: 74px; box-sizing: border-box;
  border: 1px solid transparent; background: transparent; border-radius: 7px;
  padding: 4px 6px; margin: -4px -6px;
  font-family: inherit; font-size: 12.5px; line-height: 1.5; color: var(--ink);
  transition: border-color .12s, background .12s;
}
.ce:hover { border-color: #dbe3ef; background: #fbfcfe; }
.ce:focus {
  outline: none; border-color: var(--blue); background: #fff;
  box-shadow: 0 0 0 3px rgba(47, 107, 255, .12);
}
.ce.dirty { border-color: #f0a500; background: #fffaf0; }
.ce.edited { border-color: #ffd9a3; background: #fff7e6; }
.ce.dirty.edited { border-color: #f0a500; background: #fff3dd; }
.ce.wide { min-width: 132px; }
select.ce { cursor: pointer; }
.mut { color: var(--faint); font-size: 12px; }

@media (max-width: 760px) {
  .me-hero { flex-direction: column; align-items: stretch; padding: 20px; }
  .me-hero .mh-l h1 { font-size: 21px; }
  .me-hero .date-card { width: 100%; min-width: 0; }
  .gate-wrap { padding: 24px 16px 48px; }
  .gate-head h1 { font-size: 21px; }
  .umenu { right: 0; }
}

/* ---------------- 客户表格导入面板（在「表格导入客户」抽屉里） ----------------
   2026-09-24 老张：「客户导入加一个表格导入功能」。
   面板内容全部由 crm-import.js 按选中的文件渲染：
   概况 → 字段对照（逐列可改）→ 前 5 行预览 → 统计 → 导入结果。
   只在这一个抽屉里用，别的页面一个字节都不受影响。 */
.imp-panel { display: block; }
.imp-hint {
  background: var(--blue-soft); border: 1px dashed #c8d8ff; border-radius: 12px;
  padding: 12px 14px; color: var(--muted); font-size: 12.5px; line-height: 1.7;
}
.imp-note {
  display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: center;
  background: #f7f9fd; border: 1px solid var(--line); border-radius: 12px;
  padding: 10px 14px; font-size: 12.5px; color: var(--muted);
}
.imp-note b { color: var(--ink); font-weight: 700; }
.imp-sec { margin-top: 16px; }
.imp-sec-title {
  font-size: 12.5px; font-weight: 700; color: var(--ink);
  margin-bottom: 8px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.imp-sec-title small { font-weight: 400; color: var(--faint); }
.imp-map { border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
.imp-map-row {
  display: grid; grid-template-columns: 1.1fr 1.1fr 1.4fr; gap: 10px;
  align-items: center; padding: 8px 12px; border-top: 1px solid var(--line);
  font-size: 12.5px;
}
.imp-map-row:first-child { border-top: 0; }
.imp-map-row.head { background: #f7f9fd; color: var(--faint); font-weight: 600; }
.imp-map-row select {
  height: 32px; border: 1px solid var(--line); border-radius: 8px; padding: 0 8px;
  background: #fff; font-family: inherit; font-size: 12.5px; color: var(--ink); width: 100%;
}
.imp-map-row select.on { border-color: var(--blue); background: var(--blue-soft); color: var(--blue-deep); font-weight: 600; }
.imp-src { color: var(--ink); font-weight: 600; word-break: break-all; }
.imp-sample { color: var(--faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.imp-prev { border: 1px solid var(--line); border-radius: 12px; overflow: auto; max-height: 200px; }
.imp-prev table { border-collapse: collapse; width: 100%; font-size: 12px; }
.imp-prev th, .imp-prev td {
  border-bottom: 1px solid var(--line); padding: 6px 10px;
  text-align: left; white-space: nowrap;
}
.imp-prev th { background: #f7f9fd; color: var(--faint); font-weight: 600; }
.imp-stat { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.imp-chip {
  border: 1px solid var(--line); border-radius: 20px; padding: 4px 12px;
  font-size: 12px; color: var(--muted); background: #fff;
}
.imp-chip b { color: var(--ink); }
.imp-chip.ok { border-color: #bfe9d7; background: var(--green-soft); color: #0b7a58; }
.imp-chip.warn { border-color: #f6d9a8; background: var(--orange-soft); color: #97640a; }
.imp-chip.bad { border-color: #f3c6c6; background: #fdecec; color: #a83a3a; }
.imp-result {
  margin-top: 14px; border-radius: 12px; padding: 12px 14px;
  font-size: 12.5px; line-height: 1.8; display: none;
}
.imp-result.show { display: block; }
.imp-result.ok { background: var(--green-soft); border: 1px solid #bfe9d7; color: #0b7a58; }
.imp-result.err { background: #fdecec; border: 1px solid #f3c6c6; color: #a83a3a; }
.imp-result .imp-r-title { font-weight: 700; margin-bottom: 2px; }
.imp-toast {
  position: fixed; left: 50%; bottom: 48px; transform: translateX(-50%);
  background: rgba(23, 35, 61, .93); color: #fff; font-size: 13px;
  padding: 10px 18px; border-radius: 10px; z-index: 9999; max-width: 70vw;
  box-shadow: 0 8px 24px rgba(23, 35, 61, .24);
  transition: opacity .4s; opacity: 1;
}
.imp-toast.out { opacity: 0; }
@media (max-width: 760px) {
  .imp-map-row { grid-template-columns: 1fr; gap: 6px; }
  .imp-map-row.head { display: none; }
}

/* ============================================================
   「弹出提醒」浮层（alerts.js 生成，2026-09-27）
   ------------------------------------------------------------
   右下角堆叠卡片。manual（派单）红色左边框、不给 ✕，必须点「知道了」；
   auto（系统算出来的待跟进）蓝色左边框，可以只收起。
   顶栏铃铛的未读红点同在下面。
   ============================================================ */
.alert-stack {
  position: fixed; right: 20px; bottom: 20px; z-index: 3000;
  display: flex; flex-direction: column; gap: 10px;
  width: 340px; max-width: calc(100vw - 32px);
  pointer-events: none;
}
.alert-stack.show { pointer-events: auto; }

.alert-card {
  pointer-events: auto;
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 4px solid var(--blue);
  border-radius: 12px;
  box-shadow: var(--shadow-lift);
  padding: 12px 14px 10px;
  animation: alertIn .28s cubic-bezier(.16, .84, .44, 1);
}
.alert-card.is-manual { border-left-color: #d93025; }
/* mgr = 发给管理层的「跟进概况」（讲的是业务员，不是某条客户）—— 靛蓝，跟业务员的蓝、派单的红区分开 */
.alert-card.is-mgr { border-left-color: #6366f1; }
.alert-card.out { animation: alertOut .2s ease forwards; }
@keyframes alertIn { from { opacity: 0; transform: translateY(12px) scale(.98); } to { opacity: 1; transform: none; } }
@keyframes alertOut { to { opacity: 0; transform: translateX(24px); } }

.alert-hd { display: flex; align-items: center; gap: 8px; }
.alert-tag {
  flex: 0 0 auto; font-size: 11px; line-height: 18px; padding: 0 7px; border-radius: 9px;
  background: var(--blue-soft); color: var(--blue-deep); white-space: nowrap;
}
.alert-card.is-manual .alert-tag { background: #fdeceb; color: #c5221f; }
.alert-card.is-mgr .alert-tag { background: #eef0ff; color: #4338ca; }
/* 概况卡正文要列出该业务员手上的客户名，3 行截断会看不全（一个业务员一张卡之后
   正文短了，5 行够；管理账号一次会弹好几张，行数再放大会叠出屏幕） */
.alert-card.is-mgr .alert-bd { -webkit-line-clamp: 5; }
.alert-title {
  flex: 1 1 auto; font-weight: 600; font-size: 13.5px; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.alert-x {
  flex: 0 0 auto; border: 0; background: transparent; color: var(--faint);
  cursor: pointer; font-size: 12px; line-height: 18px; padding: 0 2px;
}
.alert-x:hover { color: var(--ink); }
.alert-bd {
  margin-top: 6px; font-size: 12.5px; color: var(--muted); line-height: 1.55;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.alert-due { margin-top: 6px; font-size: 12px; color: #c5221f; }
.alert-ft { margin-top: 10px; display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.alert-meta { font-size: 11.5px; color: var(--faint); }
.alert-ops { display: flex; gap: 6px; flex: 0 0 auto; }
.alert-btn {
  font-size: 12px; line-height: 24px; height: 24px; padding: 0 10px; border-radius: 6px;
  border: 1px solid var(--line); background: #fff; color: var(--muted); cursor: pointer;
  text-decoration: none; display: inline-block;
}
.alert-btn:hover { border-color: var(--blue); color: var(--blue); }
.alert-btn.primary { background: var(--blue); border-color: var(--blue); color: #fff; }
.alert-btn.primary:hover { background: var(--blue-deep); border-color: var(--blue-deep); color: #fff; }

/* 顶栏铃铛：有未读时数字红点 + 变蓝 */
.alert-bell { position: relative; }
.alert-bell .alert-dot {
  position: absolute; top: -5px; right: -5px; min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 8px; background: #d93025; color: #fff; font-size: 10.5px; line-height: 16px;
  text-align: center; font-weight: 600; box-shadow: 0 0 0 2px var(--card);
}
.alert-bell .alert-dot[hidden] { display: none; }
.alert-bell.has-alert { color: var(--blue); border-color: #c8d8ff; background: var(--blue-soft); }

@media (max-width: 640px) {
  .alert-stack { right: 10px; left: 10px; bottom: 10px; width: auto; }
}

/* ============================================================
   跟进截图（2026-10-09 加）
   ------------------------------------------------------------
   客户池「跟进记录（截图）」列 / 跟进记录页「截图」列 / 新增跟进记录抽屉里的选图，
   三处共用这一套类名。列表里只画 36×36 的缩略图（服务端另存了一份压缩过的缩略图，
   约 20KB），点开才取正图 —— 一页 50 行不能直接拉正图。
   ============================================================ */
.fl { display: flex; flex-direction: column; gap: 4px; }
.fl-txt { display: block; word-break: break-word; }
.fl-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.fl-thb {
  width: 36px; height: 36px; object-fit: cover; border-radius: 5px;
  border: 1px solid var(--line); background: #fff; cursor: zoom-in; display: block;
}
.fl-thb:hover { border-color: var(--blue); box-shadow: 0 0 0 2px var(--blue-soft); }
/* 缩略图 + 类别角标（3.92）：.fl-w 是包裹层，给角标定位用。
   「AI」= 紫、「聊」= 绿 —— 客户池那一格里两类图混着放，得一眼看出哪张是哪类。 */
.fl-w { position: relative; display: inline-flex; line-height: 0; }
.fl-k {
  position: absolute; left: 0; top: 0; font-style: normal; pointer-events: none;
  font-size: 9px; line-height: 1; padding: 1px 3px;
  border-radius: 5px 0 4px 0; color: #fff; background: #7a8699;
}
.fl-k.ai { background: #6a5acd; }
.fl-k.chat { background: #12a06a; }
.fl-add {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border: 1px dashed #cbd5e1; border-radius: 5px;
  color: var(--muted); font-size: 11.5px; text-decoration: none; background: #fff;
}
.fl-add:hover { border-color: var(--blue); color: var(--blue); background: var(--blue-soft); }
/* 抽屉里的选图区 */
.fl-pick { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.fl-tip { color: var(--faint); font-size: 12px; }
.fl-picked { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.fl-clr { color: var(--muted); font-size: 12px; text-decoration: none; margin-left: 4px; }
.fl-clr:hover { color: #d93025; }
/* 看大图：全屏浮层 —— 带鉴权的图必须走同一个会话取，另开窗口容易被当第三方请求拦掉 */
.imgview {
  position: fixed; inset: 0; z-index: 9999; padding: 24px;
  background: rgba(15, 23, 42, .72);
  display: flex; align-items: center; justify-content: center;
}
.imgview[hidden] { display: none; }
.imgview .iv-box {
  background: var(--card); border-radius: 12px; padding: 12px;
  max-width: 92vw; max-height: 92vh; display: flex; flex-direction: column; gap: 8px;
  box-shadow: var(--shadow-lift);
}
.imgview img {
  max-width: 86vw; max-height: 72vh; object-fit: contain;
  background: var(--soft); border-radius: 6px; display: block;
}
.imgview .iv-bar { display: flex; align-items: center; gap: 8px; }
.imgview .iv-info { flex: 1; color: var(--muted); font-size: 12px; }

/* ============================================================
   移动端 · 列表页与抽屉表单（2026-10-09 加）
   ------------------------------------------------------------
   起因：老张把询盘登记搬进工作台，明确「手机也要能顺畅填」——
        业务员在外面跑，习惯拿手机填表，不会特地开电脑。
   原有断点只覆盖了首页（topbar / hero / module-card / 侧栏抽屉），
   列表页和抽屉表单在手机上一直没专门照顾过。
   ============================================================ */
@media (max-width: 760px) {
  /* 抽屉：手机上直接全屏。原来 max-width:94vw 会留 6% 的缝，
     手指正好容易点到蒙层上把表单关掉、已填内容白填。 */
  .drawer { width: 100%; max-width: 100%; }
  .dw-head { padding: 14px 16px; }
  .dw-body { padding: 16px; }
  .dw-foot { padding: 12px 16px calc(12px + env(safe-area-inset-bottom)); }
  .dw-foot .btn { flex: 1; justify-content: center; height: 46px; font-size: 14.5px; }

  /* ★ 输入框字号必须 ≥16px：iOS Safari 对 font-size < 16px 的输入框聚焦时会
     **自动放大整个页面**，而且不会自己缩回去 —— 填一个字段页面就"炸"一次。
     这是移动端的硬要求，不是好不好看的问题。 */
  .f-item input, .f-item select, .f-item textarea { font-size: 16px; padding: 11px 12px; }
  .f-item textarea { min-height: 96px; }
  .f-item label { font-size: 13px; }

  /* 工具栏：搜索框与筛选条各占满一行，别挤成一条看不见 */
  .toolbar { flex-wrap: wrap; gap: 8px; margin: 12px 0 14px; }
  .toolbar .search { flex: 1 1 100%; }
  .toolbar .search input { height: 40px; font-size: 15px; }
  .tb-filters { flex: 1 1 100%; }
  .tb-filters .sel { flex: 1 1 46%; max-width: none; height: 38px; font-size: 14px; }

  /* 表格：手机上宁可横向滚动，也别把列压成一条条 —— 压扁了账号和数字全读不出来。
     （.tbl-wrap 本身就有 overflow-x:auto，先给表一个下限宽度才真的会滚。） */
  .tbl-wrap table { min-width: 860px; }
  .tbl-wrap th, .tbl-wrap td { white-space: nowrap; }
  .tbl-wrap td .tag { padding: 5px 10px; font-size: 12.5px; }
}

@media (max-width: 540px) {
  .tb-filters .sel { flex: 1 1 100%; }
}

/* ============================================================
   客户详情（只读）抽屉 —— 3.95 加
   内容由 app.js 的 openCustView() 现填（[data-cust-view] 是个空占位）。
   列表里塞不下的那几列（企微表的咨询产品图片 / 咨询产品及问题 / 下单金额 / AI分析）
   在这儿摊开看；长文本（背调、跟进记录、AI分析）给浅底块 + 自动换行。
   ============================================================ */
#df-cust-view .cv-wrap { font-size: 13px; color: var(--ink); }
#df-cust-view .cv-head {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 10px;
  padding-bottom: 10px; margin-bottom: 12px; border-bottom: 1px solid var(--line);
}
#df-cust-view .cv-head b { font-size: 16px; }
#df-cust-view .cv-sub { font-size: 12px; color: var(--muted); }
#df-cust-view .cv-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 16px;
}
#df-cust-view .cv-item { display: flex; gap: 8px; font-size: 13px; line-height: 1.65; }
#df-cust-view .cv-k { flex: 0 0 88px; color: var(--muted); }
#df-cust-view .cv-v { flex: 1; min-width: 0; word-break: break-all; }
#df-cust-view .cv-long { margin-top: 16px; display: flex; flex-direction: column; gap: 10px; }
#df-cust-view .cv-blk .cv-k { font-size: 12px; margin-bottom: 4px; }
#df-cust-view .cv-t {
  white-space: pre-wrap; word-break: break-word; font-size: 13px; line-height: 1.7;
  background: var(--soft); border-radius: 8px; padding: 8px 10px; color: var(--ink);
}
/* 图片墙 —— 企微源表里业务员贴的产品图 / 跟进截图（3.96 补采）。
   ⚠ 只引用企微 CDN 直链（wdcdn.qpic.cn），**图片不落地**：红线「图片不进代码目录/托管沙箱」。 */
#df-cust-view .cv-n { font-size: 11px; color: var(--muted); font-weight: 400; margin-left: 4px; }
#df-cust-view .cv-imgs {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 8px; margin-top: 6px;
}
#df-cust-view .cv-thumb {
  display: block; aspect-ratio: 1 / 1; border: 1px solid var(--line); border-radius: 8px;
  overflow: hidden; background: var(--soft);
}
#df-cust-view .cv-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
#df-cust-view .cv-thumb:hover { border-color: var(--blue); }

/* 只读抽屉：左边那个「取消」跟「关闭」是同一件事，收掉 */
#df-cust-view .dw-foot .btn:not(.primary) { display: none; }
/* 操作列「详」右上角的图片张数角标 —— 让业务员在列表里就知道「这条有图」 */
.tag .cv-badge {
  display: inline-block; margin-left: 3px; padding: 0 4px; border-radius: 8px;
  background: var(--blue); color: #fff; font-size: 10px; font-style: normal; line-height: 15px;
  vertical-align: 1px;
}
@media (max-width: 620px) {
  #df-cust-view .cv-grid { grid-template-columns: minmax(0, 1fr); }
}

/* ============================================================
   询盘登记 / 筛选登记列表里的图片格 —— 3.97 加
   企微源表的「咨询产品图片」「跟进记录（截图）」两列多数行都贴着图，
   只给文字等于什么都没给 → 直接在列表里出缩略图（最多 2 张 + 「+N」）。
   ⚠ 只引用企微 CDN 直链（wdcdn.qpic.cn），**图片不落地** —— 红线「图片不进代码目录」。
   ⚠ 列表行高度会因此变高一点，所以缩略图固定 40px、不让它撑破行。
   ============================================================ */
.inq-imgs { display: inline-flex; align-items: center; gap: 4px; vertical-align: middle; }
.inq-thb {
  display: inline-block; width: 40px; height: 40px; border: 1px solid var(--line);
  border-radius: 6px; overflow: hidden; background: var(--soft); flex: 0 0 auto;
}
.inq-thb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.inq-thb:hover { border-color: var(--blue); }
.inq-more {
  font-style: normal; font-size: 11px; color: var(--muted); background: var(--soft);
  border-radius: 6px; padding: 1px 5px;
}
.inq-tx { display: block; font-size: 12px; color: var(--muted); margin-top: 2px; word-break: break-all; }
