/* ==============================================================================
   销售 CRM · 主题样式  ——  v14  UI 改版「方案 A · 现代清爽」
   ------------------------------------------------------------------------------
   · 本版把颜色 / 圆角 / 阴影 / 文字色全部收进 :root 设计令牌，组件只引用变量；
     以后单点微调 = 改一个变量，不再满文件找硬编码色值。
   · 只动样式：类名、HTML 结构、app.js 逻辑一律不变。回滚 = 换回 v13 版本文件。
   ⚠️ 下面「通用浮层 / 提示条 / 三方关系 / 分页」这一段，在 app.js 的
      _ensureToastStyle() 里有一份同名兜底副本（样式表没加载完时顶上）——
      改这一段请**同步改 app.js**，否则两处会分叉。
   ⚠️ .kv{display:grid} 是 app.js 用来探测「样式表是否已生效」的规则，
      必须保留 grid，且**不能**出现在 app.js 的兜底副本里。
   ============================================================================== */
:root{
  /* —— 品牌与交互 —— */
  --brand:#2563eb;          /* 主色（交互元素） */
  --brand-d:#1d4ed8;        /* 主色按下 / 深一档 */
  --brand-l:#dbeafe;        /* 主色浅底 */
  --brand-t:#eff6ff;        /* 主色极浅底 */
  --deep:#16304f;           /* 品牌深蓝：顶栏、标题、强调 */
  --deep-2:#1d4470;         /* 顶栏渐变尾色 */
  /* —— 版面 —— */
  --bg:#f4f6fb;             /* 页面底 */
  --card:#ffffff;           /* 卡片 */
  --line:#e9eef6;           /* 主描边 */
  --line-2:#f1f5f8;         /* 浅分隔线 */
  --head:#f7f9fc;           /* 表头底 */
  /* —— 语义色 —— */
  --ok:#12b76a;  --ok-d:#067647;
  --warn:#f79009;
  --danger:#ef4444;  --danger-d:#b42318;
  /* —— 文字 —— */
  --t1:#101828;             /* 主文字 */
  --t2:#475467;             /* 次文字 */
  --t3:#98a2b3;             /* 弱文字 */
  /* —— 形状与投影 —— */
  --r8:8px; --r10:10px; --r14:14px;
  --sh1:0 1px 2px rgba(16,24,40,.04),0 1px 3px rgba(16,24,40,.06);
  --sh2:0 6px 16px rgba(16,24,40,.08),0 2px 4px rgba(16,24,40,.04);
  --ring:0 0 0 3px rgba(37,99,235,.15);
}
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif;
     color:var(--t1);font-size:14px;line-height:1.6;
     background-color:var(--bg);
     /* 两处极淡径向光：让平涂底色有层次（旧内核退化纯色，不会错位） */
     background-image:radial-gradient(760px 420px at 8% -6%,rgba(37,99,235,.055),transparent 62%),
                      radial-gradient(680px 380px at 102% 2%,rgba(96,165,250,.05),transparent 58%);
     background-repeat:no-repeat;background-attachment:fixed}
header{background:linear-gradient(135deg,var(--deep) 0%,var(--deep-2) 100%);color:#fff;
       display:flex;align-items:center;padding:0 24px;height:60px;
       position:sticky;top:0;z-index:100;
       box-shadow:0 1px 2px rgba(16,24,40,.08),0 4px 16px rgba(16,24,40,.10)}
.logo{font-size:17px;font-weight:600;margin-right:28px;letter-spacing:.2px}
.logo small{font-size:12px;opacity:.72;font-weight:400;margin-left:6px}
header nav{display:flex;gap:4px;flex:1}
/* 胶囊导航：选中项用白底 + 深蓝字，在渐变顶栏上最清爽 */
header nav a{padding:7px 15px;border-radius:999px;cursor:pointer;font-size:14px;white-space:nowrap;
             opacity:.86;transition:background .18s,color .18s,opacity .18s}
header nav a:hover{background:rgba(255,255,255,.14);opacity:1}
header nav a.on{background:rgba(255,255,255,.96);color:var(--deep);opacity:1;font-weight:600;
                box-shadow:0 1px 3px rgba(16,24,40,.18)}
.user{font-size:13px;opacity:.85}
main{max-width:none;margin:0;padding:18px 22px}
.page{display:none}.page.on{display:block}
.page>.card:first-child{margin-top:0}
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--r14);
      padding:18px 20px;box-shadow:var(--sh1);margin-bottom:18px}
.card h2{font-size:15px;margin-bottom:14px;padding-left:10px;border-left:3px solid var(--brand);
         display:flex;align-items:center;justify-content:space-between}
.h2sub{font-size:12px;color:var(--t3);font-weight:400;margin-left:8px}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:18px}
.btn{padding:6px 13px;border:1px solid #d0d5dd;background:#fff;border-radius:var(--r8);cursor:pointer;
     font-size:13px;color:var(--t2);font-family:inherit;
     transition:background .16s,border-color .16s,box-shadow .16s,transform .16s}
.btn:hover{background:#f8fafc;border-color:#b9c2cf;color:var(--t1)}
.btn.pri{background:linear-gradient(180deg,#3b82f6,var(--brand));color:#fff;border-color:var(--brand);
         box-shadow:0 1px 2px rgba(37,99,235,.24)}
.btn.pri:hover{background:linear-gradient(180deg,var(--brand),var(--brand-d));border-color:var(--brand-d);
               color:#fff;transform:translateY(-1px);box-shadow:0 4px 12px rgba(37,99,235,.30)}
.btn.sm{padding:3px 9px;font-size:12px}
.btn.dan{color:var(--danger);border-color:#fecdca}
.btn.dan:hover{background:#fef3f2;border-color:#fda29b;color:var(--danger-d)}
.btn:disabled{opacity:.45;cursor:not-allowed;transform:none}
.kpis{display:grid;grid-template-columns:repeat(5,1fr);gap:14px;margin-bottom:18px}
.kpi{position:relative;background:var(--card);border:1px solid var(--line);border-radius:var(--r14);
     padding:18px 18px 16px;box-shadow:var(--sh1);overflow:hidden;
     transition:box-shadow .18s,transform .18s}
/* 顶部渐变彩条：让 KPI 一眼区别于普通卡片 */
.kpi::before{content:'';position:absolute;left:0;right:0;top:0;height:3px;
             background:linear-gradient(90deg,var(--brand) 0%,#60a5fa 100%)}
.kpi:hover{box-shadow:var(--sh2);transform:translateY(-1px)}
.kpi .l{font-size:12px;color:var(--t2)}
.kpi .v{font-size:26px;font-weight:600;margin-top:6px;letter-spacing:-.2px}
.kpi .v u{font-size:13px;color:var(--t3);text-decoration:none;font-weight:400;margin-left:2px}
.kpi .d{font-size:12px;margin-top:4px;color:var(--ok)}
.kpi .d.gray{color:var(--t3)}
.funnel{display:flex;flex-direction:column;align-items:center;gap:3px;padding:6px 0}
.frow{height:44px;display:flex;align-items:center;justify-content:center;position:relative;
      width:100%;max-width:900px}
.fbox{display:flex;align-items:center;justify-content:space-between;padding:0 16px;height:100%;
      border-radius:var(--r8);color:#fff;font-size:13px;white-space:nowrap;transition:.2s}
.fbox:hover{filter:brightness(1.06)}
.conv{position:absolute;left:50%;transform:translateX(-50%);bottom:-18px;font-size:11px;color:var(--t3)}
table{width:100%;border-collapse:collapse;font-size:13px}
th{background:var(--head);text-align:left;padding:12px;font-weight:600;color:var(--t2);font-size:12.5px;
   border-bottom:1px solid var(--line);white-space:nowrap}
td{padding:12px;border-bottom:1px solid var(--line-2)}
tr:hover td{background:#f5f8ff}
.num{text-align:right;font-variant-numeric:tabular-nums}
.tag{display:inline-block;padding:2px 9px;border-radius:999px;font-size:11px;white-space:nowrap;font-weight:500}
.t-blue{background:var(--brand-t);color:var(--brand-d);border:1px solid #c7d7fe}
.t-green{background:#ecfdf3;color:var(--ok-d);border:1px solid #abefc6}
.t-orange{background:#fff6ed;color:#b54708;border:1px solid #fddcab}
.t-red{background:#fef3f2;color:var(--danger-d);border:1px solid #fecdca}
.t-gray{background:#f2f4f7;color:var(--t2);border:1px solid #e4e7ec}
.t-purple{background:#f4f3ff;color:#5925dc;border:1px solid #d9d6fe}
.filters{display:flex;gap:8px;margin-bottom:12px;flex-wrap:wrap}
/* ⚠️ 这两条必须排除 checkbox/radio：否则复选框会被 min-width:130px + padding + 边框
   撑成约 152px 宽的"大方块"，把紧随其后的文字整段顶开（客户页「仅看计划超期」错位即此）。
   用 :where() 压低特异性，好让下面 input[type=date] 这条能正当地覆盖它。 */
.filters input:where(:not([type=checkbox]):not([type=radio])),.filters select{padding:7px 11px;border:1px solid #d0d5dd;border-radius:var(--r8);
   font-size:13px;min-width:130px;font-family:inherit;height:34px;color:var(--t1);
   transition:border-color .15s,box-shadow .15s}
.filters input:where(:not([type=checkbox]):not([type=radio])):focus,.filters select:focus{
   outline:none;border-color:var(--brand);box-shadow:var(--ring)}
.filters input:where(:not([type=checkbox]):not([type=radio])){flex:1;max-width:260px}
/* 日期框不参与拉伸：左右两个日期等宽，不随同行其它控件多少而变宽变窄 */
.filters input[type=date]{flex:0 0 auto;min-width:150px}
.tabs{display:flex;gap:8px;margin-bottom:12px;flex-wrap:wrap}
.tab{padding:6px 14px;border-radius:var(--r8);background:#f2f4f7;font-size:13px;cursor:pointer;
     color:var(--t2);border:1px solid transparent;transition:background .15s,color .15s,border-color .15s}
.tab:hover{background:#e9edf5;color:var(--t1)}
.tab.on{background:var(--brand);color:#fff;border-color:var(--brand);box-shadow:0 1px 2px rgba(37,99,235,.24)}
.bar{height:6px;background:#eef2f7;border-radius:999px;overflow:hidden;min-width:60px}
.bar i{display:block;height:100%;border-radius:999px}
.alert{display:flex;gap:10px;padding:10px 13px;border-radius:var(--r10);margin-bottom:7px;font-size:13px;
       background:#fef3f2;border:1px solid #fecdca;border-left:3px solid var(--danger);
       align-items:flex-start;color:var(--danger-d)}
.alert.warn{background:#fffaeb;border-color:#fedf89;border-left-color:var(--warn);color:#93370d}
.alert .m{color:var(--t2);font-size:12px}
.task{display:flex;justify-content:space-between;align-items:center;padding:9px 11px;
      border-bottom:1px solid var(--line-2);font-size:13px}
.task .t{color:var(--t3);font-size:12px}
/* 待办前的客户名标签 */
.cust-tag{display:inline-block;background:var(--brand-t);color:var(--brand-d);border:1px solid #c7d7fe;
      border-radius:6px;padding:1px 7px;margin-right:4px;font-size:12px;font-weight:600;white-space:nowrap}
.empty{color:var(--t3);text-align:center;padding:20px;font-size:13px}
/* 抽屉 */
/* 修 L7：不用 inset:0 简写 —— 部分国产内核 / 旧 Chromium(<87)、Safari(<14.5) 不识别，
   会导致遮罩层塌陷成 0 高度、弹窗点不到。展开为 top/right/bottom/left。 */
.drawer-mask,.modal-mask{position:fixed;top:0;right:0;bottom:0;left:0;background:rgba(16,24,40,.42);display:none;z-index:200;
   -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}
.drawer-mask.on,.modal-mask.on{display:block}
.drawer{position:fixed;right:0;top:0;bottom:0;width:640px;background:var(--card);z-index:210;
        transform:translateX(100%);transition:.25s;overflow-y:auto;box-shadow:-8px 0 28px rgba(16,24,40,.12)}
.drawer.on{transform:translateX(0)}
.drawer.wide{width:900px;max-width:96vw}
/* 商机详情：超宽抽屉，信息密度高（估值 10 项 + 产品明细 8 列） */
.drawer.xl{width:1200px;max-width:96vw}
.drawer.xl .kv{grid-template-columns:repeat(3,1fr)}
#drawer .drawer-hd>h3{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-right:10px}
#drawer .drawer-hd>span,#drawer .drawer-hd>button.hd-x{flex:0 0 auto}
/* 详情抽屉内的「上一个 / 下一个」切换（标题栏改白底后，这组按钮也改浅底深字） */
.dw-nav{display:flex;align-items:center;gap:6px;flex:0 0 auto;margin-right:14px}
.dw-nav .btn.sm.dwn{background:#fff;color:var(--t2);border-color:#d0d5dd;padding:3px 10px}
.dw-nav .btn.sm.dwn:hover{background:#f2f4f7;color:var(--deep);border-color:#b9c2cf}
.dw-nav .btn.sm.dwn:disabled{background:#f8fafc;color:var(--t3);border-color:var(--line);opacity:1;cursor:not-allowed}
.dw-nav .dw-pos{font-size:12px;opacity:1;cursor:default;color:var(--t3);min-width:60px;text-align:center;white-space:nowrap}

/* v26：名称查重提示（精确重名=红 / 相似名=橙） */
.name-hint{display:block;margin-top:4px;font-size:12px;line-height:1.5}
.name-hint.err{color:#d92d20;font-weight:600}
.name-hint.warn{color:#b54708}
/* 方案 A：抽屉 / 弹窗标题栏改白底 + 1px 分隔（比整条深色更现代、更轻） */
.drawer-hd,.modal-hd{position:sticky;top:0;background:#fff;color:var(--t1);padding:14px 20px;
        display:flex;justify-content:space-between;align-items:center;z-index:2;border-bottom:1px solid var(--line)}
.drawer-hd h3,.modal-hd h3{font-size:16px;font-weight:600;color:var(--deep)}
.drawer-hd span,.modal-hd span{cursor:pointer;font-size:18px;color:var(--t3)}
.drawer-hd span:hover,.modal-hd span:hover{color:var(--t1)}
/* 修 L7：关闭按钮由 <span onclick> 改为 <button>（可聚焦、可键盘 Enter/Space 触发）。
   这里把样式对齐原来的 span，并补可见焦点环。 */
.drawer-hd .hd-x,.modal-hd .hd-x{flex:0 0 auto;background:none;border:0;color:var(--t3);
        font:inherit;font-size:18px;line-height:1;cursor:pointer;padding:2px 6px;border-radius:6px;transition:background .15s,color .15s}
.drawer-hd .hd-x:hover,.modal-hd .hd-x:hover{color:var(--t1);background:#f2f4f7}
.drawer-hd .hd-x:focus-visible,.modal-hd .hd-x:focus-visible{outline:2px solid var(--brand);outline-offset:1px;color:var(--t1)}
/* 修 L7：键盘可达元素补可见焦点环 */
.tab:focus-visible,th[data-sort]:focus-visible,
.pick-item:focus-visible,.btn:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
header nav a:focus-visible{outline:2px solid #fff;outline-offset:2px}
.drawer-bd{padding:18px 20px}
.drawer-bd h4,.sec-t{font-size:13px;font-weight:600;color:var(--t1);margin:16px 0 8px;
        padding-left:8px;border-left:3px solid var(--brand)}
.drawer-bd h4:first-child{margin-top:0}
.kv{display:grid;grid-template-columns:repeat(2,1fr);gap:6px 16px;font-size:13px;margin-bottom:6px}
.kv div{color:var(--t2)}.kv b{color:var(--t1);font-weight:600;margin-left:4px}
.tl{border-left:2px solid var(--line);padding-left:14px;margin-left:6px}
.tl-item{position:relative;padding-bottom:14px}
.tl-item::before{content:'';position:absolute;left:-19px;top:6px;width:8px;height:8px;
   border-radius:50%;background:var(--brand)}
.tl-item .d{font-size:12px;color:var(--t3)}
.tl-item .c{font-size:13px;margin-top:2px}
/* 数据字典：左侧分类导航 + 右侧表格 */
.dict-layout{display:grid;grid-template-columns:280px 1fr;gap:16px;margin-top:8px}
/* 产品/行业/团队：无左侧分类栏，占满整行 */
.dict-layout.single{grid-template-columns:1fr}
.dict-layout.single .dict-side{display:none}
.dict-side{border-right:1px solid var(--line);padding-right:12px;max-height:65vh;overflow:auto}
.dict-side-hint{font-size:12px;color:var(--t2);padding:6px 4px 10px;border-bottom:1px dashed var(--line);margin-bottom:8px;line-height:1.6}
.dict-cat{position:relative;padding:10px 12px;border-radius:var(--r8);cursor:pointer;margin-bottom:4px;border:1px solid transparent;transition:.12s}
.dict-cat:hover{background:#f5f7fb}
.dict-cat.on{background:var(--brand-t);border-color:#c7d7fe;box-shadow:0 1px 0 rgba(37,99,235,.06)}
.dict-cat .lb{font-weight:600;font-size:14px;color:var(--deep);display:flex;align-items:center;gap:6px}
.dict-cat .lb .cnt{background:var(--brand-l);color:var(--brand-d);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:600}
.dict-cat .tg{color:var(--t2);font-size:12px;margin-top:4px;line-height:1.4}
.dict-cat .desc{color:var(--t3);font-size:11px;margin-top:4px;line-height:1.4}
/* 注意：不要用 <main> 标签，会被全局 main{max-width;margin:0 auto;padding} 命中导致缩进 */
.dict-main{min-width:0;max-width:none;margin:0;padding:0}
.dict-head{display:flex;align-items:center;gap:14px;margin-bottom:12px;flex-wrap:wrap}
/* 数据字典 → 系统配置：LOGO 上传面板（仅该分类显示） */
.dict-logo{margin:0 0 14px;padding:12px 14px;border:1px solid var(--line);border-radius:var(--r10);background:#fafbfd}
.dict-logo .dl-t{font-size:13px;font-weight:600;color:var(--t1);margin-bottom:8px}
.dict-logo .dl-body{display:flex;align-items:center;gap:16px;flex-wrap:wrap}
.dict-logo .dl-prev{width:160px;height:56px;border:1px dashed #cbd5e1;border-radius:var(--r8);background:#fff;
  display:flex;align-items:center;justify-content:center;color:var(--t3);font-size:12px;overflow:hidden}
.dict-logo .dl-prev img{max-width:100%;max-height:100%;object-fit:contain;display:block}
.dict-logo .dl-op{min-width:240px}
/* 报价单位输入行（与 LOGO 同面板） */
.dict-logo .dl-op.grow{flex:1 1 auto;min-width:320px}
.dict-logo .dl-input{width:100%;max-width:420px;padding:8px 11px;border:1px solid #d0d5dd;border-radius:var(--r8);font-size:13px;color:var(--t1)}
.dict-logo .dl-input:focus{outline:none;border-color:var(--brand);box-shadow:var(--ring)}
.dict-logo .dl-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.dict-head h3{margin:0;font-size:18px;color:var(--deep)}
.dict-desc-line{margin:2px 0 0;color:var(--t2);font-size:12px;line-height:1.5}
.dict-search{padding:8px 11px;border:1px solid #d0d5dd;border-radius:var(--r8);width:240px;font-size:13px;color:var(--t1)}
.dict-search:focus{outline:none;border-color:var(--brand);box-shadow:var(--ring)}
/* v23.1：字典头部右侧动作组整体贴右 —— 单框搜索紧挨「+ 新增」
   （原来靠 .dict-search 自己吃空白，产品字典切到四框筛选后单框被隐藏，搜索框会留在
     标题旁边；现在整组一起贴右，两种模式、五个页签下的位置完全一致）。 */
.dict-head .dict-acts{margin-left:auto;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.dict-head .dict-acts .dict-tools{display:inline-flex;align-items:center;gap:8px}
/* v23 产品字典筛选条：编码 / 名称 / 型号 / 规格 四个独立输入框（复用 .filters 外观，仅收紧宽度） */
.dict-f4 input:where(:not([type=checkbox]):not([type=radio])){flex:0 1 160px;max-width:200px}
/* v23.1：商机详情底部「整单折扣率 / 税率 / 单价口径」输入框 ——
   原来内联 width:64px / 56px，填「12.5」这类小数就被挤掉一半；
   这里统一 96px、数字右对齐、单位（%）单独用 <i> 显示，不占输入位。 */
.quote-bar{display:flex;flex-wrap:wrap;gap:10px 18px;align-items:center;margin-top:8px;
  padding-top:10px;border-top:1px solid var(--line)}
.quote-bar>span{display:inline-flex;align-items:center;gap:6px;font-size:13px;color:var(--t2);white-space:nowrap}
.quote-bar .qb-f input,.quote-bar .qb-f select{padding:6px 10px;border:1px solid #d0d5dd;border-radius:var(--r8);
  font-size:13px;color:var(--t1);background:#fff}
.quote-bar .qb-f input{width:96px;text-align:right}
.quote-bar .qb-f select{width:96px}
.quote-bar .qb-f input:focus,.quote-bar .qb-f select:focus{outline:none;border-color:var(--brand);box-shadow:var(--ring)}
.quote-bar .qb-f i{font-style:normal;color:var(--t3);font-size:12px}
.quote-bar .qb-sum b{color:var(--t1)}
/* 带百分号后缀的输入框（生成报价单弹窗的「整单折扣% / 税率%」） */
.pct-wrap{position:relative}
.pct-wrap input{padding-right:30px;text-align:right}
.pct-wrap i{position:absolute;right:11px;top:50%;transform:translateY(-50%);
  font-style:normal;color:var(--t3);font-size:12px;pointer-events:none}
.rpt-meta{display:flex;flex-wrap:wrap;gap:10px;align-items:center;font-size:12px;color:var(--t2);
          background:#f8fafc;border-radius:var(--r8);padding:8px 12px;margin-bottom:6px}
.chk-group{display:flex;flex-wrap:wrap;gap:6px 14px;border:1px solid var(--line);border-radius:var(--r8);
           padding:8px 10px;background:#fcfcfd;max-height:112px;overflow-y:auto}
.chk-group label{display:inline-flex;align-items:center;gap:5px;font-size:13px;color:var(--t2);
                 padding:3px 6px;border-radius:6px;cursor:pointer}
.chk-group label:hover{background:#eef2f7}
.chk-group input{margin:0}
/* 报告全文：一整段可复制文本 */
.rpt-copy-bar{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:8px 0 6px}
.rpt-text{width:100%;box-sizing:border-box;padding:12px 14px;border:1px solid var(--line);border-radius:var(--r10);
          background:#fbfcfe;color:var(--t1);font-size:13px;line-height:1.9;resize:vertical;
          font-family:inherit;white-space:pre-wrap}
.rpt-text:focus{outline:none;border-color:var(--brand);background:#fff;box-shadow:var(--ring)}
.rpt-row{display:flex;gap:12px;padding:8px 0;border-bottom:1px dashed var(--line-2);font-size:13px}
.rpt-row:last-child{border-bottom:0}
.rpt-k{flex:0 0 96px;color:var(--t2)}
.rpt-v{flex:1;color:var(--t1);white-space:pre-wrap;line-height:1.6}
/* 弹窗 */
.modal{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%) scale(.96);width:560px;
       max-height:86vh;background:var(--card);border-radius:var(--r14);z-index:210;display:none;
       flex-direction:column;opacity:0;transition:.2s;box-shadow:0 20px 48px rgba(16,24,40,.18)}
.modal.wide{width:820px}
/* v21 尺寸层级：子表单（+ 新建商机 / + 新增联系人）比拜访报告表单一档小 ——
   原来三个表单同宽同高、位置完全重叠，在外面点一下就把整张拜访报告一起关了。 */
.modal.sm{width:480px}
.modal.md{width:660px}
.modal.xl{width:940px}
/* v29.2：报价单明细改成 8 列三级联动下拉后 940px 不够 → 再加一档 1080px */
.modal.xxl{width:1080px}
.modal.on{display:flex;opacity:1;transform:translate(-50%,-50%) scale(1)}
/* 表单分组 */
.form-sec{margin:14px 0 6px;padding-bottom:4px;border-bottom:1px solid var(--line-2);
          font-size:13px;font-weight:600;color:var(--deep);display:flex;align-items:center;gap:6px}
.form-sec:first-child{margin-top:0}
.form-sec .sub{font-weight:400;color:var(--t3);font-size:12px}
/* 星级选择（影响力） */
.star-pick{display:inline-flex;gap:2px;align-items:center}
.star-pick i{font-style:normal;font-size:18px;line-height:1;cursor:pointer;color:#d0d5dd;
             transition:.1s;user-select:none;padding:0 1px}
.star-pick i:hover{transform:scale(1.15)}
.star-pick i.on{color:var(--warn)}
.star-txt{font-size:12px;color:var(--t2);margin-left:6px}
/* 开关式是/否 */
.yn-pick{display:inline-flex;border:1px solid #d0d5dd;border-radius:var(--r8);overflow:hidden}
.yn-pick b{font-weight:400;font-size:12px;padding:5px 14px;cursor:pointer;background:#fff;color:var(--t2);
           border-right:1px solid var(--line);transition:.1s}
.yn-pick b:last-child{border-right:none}
.yn-pick b.on{background:var(--brand);color:#fff}
.modal-bd{padding:18px 20px;overflow-y:auto}
.form-row{margin-bottom:12px}
.form-row label{display:block;font-size:12px;color:var(--t2);margin-bottom:4px}
.form-row input,.form-row select,.form-row textarea{width:100%;padding:8px 11px;
   border:1px solid #d0d5dd;border-radius:var(--r8);font-size:13px;font-family:inherit;color:var(--t1);
   height:34px;transition:border-color .15s,box-shadow .15s}
.form-row input:focus,.form-row select:focus,.form-row textarea:focus{outline:none;border-color:var(--brand);box-shadow:var(--ring)}
.form-row textarea{min-height:74px;height:auto;resize:vertical}
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 12px}
/* 操作栏：吸附在弹窗底部，长表单滚动时「取消/保存」始终可见 */
.modal-ft{padding:12px 20px;border-top:1px solid var(--line);display:flex;justify-content:flex-end;gap:8px;
          position:sticky;bottom:0;background:#fff;margin:0 -20px -18px;border-radius:0 0 var(--r14) var(--r14)}
/* 登录层（修 L7：inset 展开，兼容旧内核） */
.login-mask{position:fixed;top:0;right:0;bottom:0;left:0;
  background:radial-gradient(1100px 620px at 50% -12%,#1f4b7d 0%,var(--deep) 58%,#0f2137 100%);
  display:none;align-items:center;justify-content:center;z-index:500}
.login-mask.on{display:flex}
.login-box{background:#fff;border-radius:18px;padding:34px 38px;width:400px;
  box-shadow:0 24px 60px rgba(6,18,36,.38),0 2px 8px rgba(6,18,36,.20)}
.login-box h2{font-size:21px;margin-bottom:22px;color:var(--deep);text-align:center}
.login-box h2 small{font-size:12px;color:var(--t3);font-weight:400}
/* 登录主按钮：比通用 .pri 更大更厚（内联 padding 在 index.html 上，这里补字号与圆角） */
.login-box .btn.pri{font-size:15px;font-weight:600;border-radius:var(--r10);letter-spacing:2px}
.lg-tip{color:var(--danger);font-size:13px;text-align:center;margin-top:10px;min-height:18px}
.lg-acc{font-size:11px;color:var(--t3);text-align:center;margin-top:16px;
  border-top:1px solid var(--line-2);padding-top:12px;line-height:1.7}
.note{font-size:12px;color:var(--t3);margin-top:10px;line-height:1.7}
@media(max-width:1100px){.kpis{grid-template-columns:repeat(3,1fr)}.grid2{grid-template-columns:1fr}}
/* 漏斗趋势图 */
.legend{display:flex;flex-wrap:wrap;gap:6px 14px;margin:6px 0 10px}
.legend span{font-size:12px;color:var(--t2);cursor:pointer;user-select:none;
   display:inline-flex;align-items:center;gap:5px;padding:2px 6px;border-radius:6px}
.legend span:hover{background:#f2f4f7}
.legend span.off{opacity:.35;text-decoration:line-through}
.legend i{width:11px;height:11px;border-radius:3px;display:inline-block}
#trendChart svg{width:100%;height:auto;display:block}
#trendChart .gl{stroke:var(--line);stroke-width:1}
#trendChart .ax{stroke:#d0d5dd;stroke-width:1}
#trendChart .lb{fill:var(--t3);font-size:11px}
#trendChart .dot{stroke:#fff;stroke-width:1.5}
.chart-foot{display:flex;align-items:center;gap:12px;margin-top:10px;flex-wrap:wrap}

/* ============ 下一步计划超期报警 ============ */
.alert-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:10px 14px;margin-bottom:12px;
  border-radius:var(--r10);font-size:13px;background:#fef3f2;border:1px solid #fecdca;color:#912018;
  animation:odFlash 1.8s ease-in-out 2}
.alert-bar b{color:var(--danger-d)}
.alert-bar.sm{padding:6px 10px;font-size:12px;margin-bottom:10px;animation:none}
.od-chips{display:flex;gap:6px;flex-wrap:wrap}
.od-chip{display:inline-block;padding:2px 9px;border-radius:999px;background:#fff;border:1px solid #fecdca;
  color:var(--danger-d);font-size:12px;cursor:pointer}
.od-chip:hover{background:#fee4e2}
.tag.t-danger{background:var(--danger);color:#fff;border-color:var(--danger)}
tr.od-row td{background:#fffbfa}
tr.od-row:hover td{background:#fef3f2}
tr.od-row td:first-child{box-shadow:inset 3px 0 0 var(--danger)}
.plan-od{display:flex;align-items:center;gap:6px}
.od-txt{font-size:12px;color:var(--danger-d);white-space:nowrap}
.od-plan{font-size:12px;color:var(--t2);margin-top:2px;max-width:200px;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.plan-due{font-size:12px;color:var(--brand)}
.ck{display:inline-flex;align-items:center;gap:5px;font-size:13px;color:var(--t2);cursor:pointer}
.ck input{width:15px;height:15px;accent-color:var(--brand);cursor:pointer}
.od-ck{align-self:center}
.btn.sm.ok{color:var(--ok-d);border-color:#abefc6}
.btn.sm.ok:hover{background:#ecfdf3}
@keyframes odFlash{0%,100%{background:#fef3f2}50%{background:#fee4e2}}
.tab-od{color:var(--danger-d)}
.tab-od.on{background:var(--danger);color:#fff;border-color:var(--danger)}

/* ============ 商机估值与自动金额 ============ */
.amt-box{display:flex;align-items:baseline;gap:10px;padding:6px 10px;background:#f8fafc;
  border:1px dashed #d0d5dd;border-radius:var(--r8)}
.amt-box b{font-size:16px;color:#b54708}
.amt-box .note{margin:0;font-size:12px}

/* ============ 会话超时预警（P2⑩）============ */
#idleWarn{position:fixed;left:50%;bottom:18px;transform:translateX(-50%);z-index:9999;
  background:var(--deep);color:#fff;padding:10px 16px;border-radius:var(--r10);font-size:13px;
  box-shadow:0 10px 30px rgba(16,24,40,.28);display:flex;align-items:center;gap:12px}
#idleWarn b{color:#fdb022}
#idleWarn .btn{margin-left:4px}

/* ============ 回收站（P3⑪）============ */
.rec-group{border:1px solid var(--line);border-radius:var(--r10);margin-bottom:14px;overflow:hidden}
.rec-h{background:#f8fafc;padding:8px 12px;font-size:13px;border-bottom:1px solid var(--line)}
.rec-item{display:flex;align-items:center;justify-content:space-between;padding:7px 12px;font-size:13px;border-bottom:1px dashed var(--line-2)}
.rec-item:last-child{border-bottom:none}
.rec-item:hover{background:#fafbff}
.rec-id{color:var(--t3);font-size:12px;margin-left:6px}

/* ============ 通用浮层 / 提示条 / 三方关系 / 分页（必须随样式表加载！）============
   2026-09-12 修复（严重）：这一段原先只存在于 app.js 的 _ensureToastStyle() 里，
   而它只在 toast() 被调用时才注入。结果「刚打开/刷新页面但还没出现过任何提示」时：
     · .pick-mask 无样式 → 确认框变成一个没有定位的普通 div，被顶到页面最底部
       （实测 top≈1048px，视口只有 900px）→ 用户根本点不到「确定」，
       表现为「三方关系删除 / 下一步计划删除 点了没反应」；
     · .pt-* 无样式 → 三方关系区块像完全没有排版。
   app.js 里仍保留同名副本作为兜底（万一 style.css 没跟着覆盖，功能也不会废）。
   改这里时请同步改 app.js 的 _ensureToastStyle()。 */
#toastBox{position:fixed;top:16px;left:50%;transform:translateX(-50%);z-index:9999;display:flex;flex-direction:column;gap:8px;align-items:center;pointer-events:none}
.toast{max-width:80vw;padding:10px 16px;border-radius:var(--r10);font-size:13px;line-height:1.4;color:#fff;box-shadow:0 8px 24px rgba(16,24,40,.18);opacity:1;transition:opacity .3s,transform .3s;transform:translateY(0)}
.toast.out{opacity:0;transform:translateY(-8px)}
.toast-err{background:var(--danger)}
.toast-ok{background:var(--ok)}
/* ---------- 分页条（v21 重做外观）----------
   ⚠️ .pg-info 的文案「共 N 条 · 第 x/y 页」与 select.pg-size 的 4 档选项都被
      ui-smoke 断言，结构不许动；这里只改样式。 */
.pager{display:flex;align-items:center;gap:8px;padding:12px 2px 2px;flex-wrap:wrap}
.pager .pg-info{font-size:12.5px;color:var(--t2);margin-right:4px}
.pager .pg-info b{color:var(--t1);font-weight:600;font-variant-numeric:tabular-nums}
.pager .pg-btns{display:inline-flex;align-items:center;gap:6px}
.pager .pg-nav{min-width:58px;text-align:center;padding:4px 10px;font-size:12.5px;background:#fff}
.pager .pg-nav:hover:not(:disabled){background:var(--brand-t);border-color:#c7d7fe;color:var(--brand-d)}
/* 每页条数：去掉原生 3D 边框，自绘箭头（各浏览器原生小三角长得都不一样） */
.pager .pg-size-box{margin-left:auto;display:inline-flex;align-items:center}
.pager .pg-size{appearance:none;-webkit-appearance:none;-moz-appearance:none;
  height:32px;padding:0 30px 0 12px;border:1px solid #d0d5dd;border-radius:var(--r8);
  font-size:12.5px;font-family:inherit;color:var(--t1);background-color:#fff;cursor:pointer;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%2212%22%20height=%2212%22%20viewBox=%220%200%2024%2024%22%20fill=%22none%22%20stroke=%22%23667085%22%20stroke-width=%222.6%22%20stroke-linecap=%22round%22%20stroke-linejoin=%22round%22%3E%3Cpath%20d=%22M6%209l6%206%206-6%22/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 10px center;
  transition:border-color .15s,box-shadow .15s}
.pager .pg-size:hover{border-color:#b9c2cf}
.pager .pg-size:focus{outline:none;border-color:var(--brand);box-shadow:var(--ring)}
.batchbar{display:flex;align-items:center;gap:8px;margin:6px 0;padding:7px 10px;background:var(--brand-t);border:1px solid #c7d7fe;border-radius:var(--r10);font-size:13px;color:var(--brand-d);flex-wrap:wrap}
th[data-sort]{cursor:pointer;user-select:none;white-space:nowrap}
th[data-sort]:hover{color:var(--brand)}
/* .filters 是 flex 行、默认 align-items:stretch：纯文本 <span> 被拉满 32px 高后
   文字贴顶，看起来比日期框"高一截"（建档 / ~ / 创建 / 签单 / 日期）。align-self:center 居中。 */
.fl-sep{font-size:12px;color:var(--t3);margin-left:4px;align-self:center;line-height:1}
/* 日期区间是一个整体：标签 + 起 + ~ + 止 必须同进同退，绝不能被 flex 换行拆散
   （拆散就出现「建档」留在上一行、日期掉到下一行）。内部自己排，间距统一 6px。 */
.fl-range{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.fl-range .fl-sep{margin-left:0}
.pick-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(16,24,40,.42);z-index:9998;display:flex;align-items:center;justify-content:center;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}
.pick-box.anchored{position:absolute}
.pick-box{background:#fff;border-radius:var(--r14);min-width:280px;max-width:520px;max-height:70vh;display:flex;flex-direction:column;box-shadow:0 20px 48px rgba(16,24,40,.25)}
.pick-box h4{margin:0;padding:12px 16px;border-bottom:1px solid var(--line);font-size:14px;font-weight:600;color:var(--deep)}
.pick-list{padding:8px;display:flex;flex-wrap:wrap;gap:8px;overflow:auto}
.pick-item{border:1px solid #d7dce3;background:#f8fafc;border-radius:var(--r8);padding:7px 12px;font-size:13px;cursor:pointer}
.pick-item:hover{background:var(--brand);border-color:var(--brand);color:#fff}
.pick-foot{padding:10px 16px;border-top:1px solid var(--line);text-align:right}
/* ★ v31.19.0-roleroute 修⑤：.pick-mask / .pick-box 这套浮层里的输入框**从来没有样式** ——
   style.css 只写了 `.form-row input`（第 313 行），而 uiPrompt / uiConfirm 的框子既不在 .form-row 里、
   也没类名 ⇒ 走浏览器原生样式（无内边距、方角、高度不对）。
   「撤销申请」的原因录入框就是它。补一条通用规则：浮层内输入框与表单同款。 */
.pick-box .pk-inp,.pick-box [data-inp]{width:100%;padding:8px 11px;border:1px solid #d0d5dd;
  border-radius:var(--r8);font-size:13px;font-family:inherit;color:var(--t1);height:34px;
  box-sizing:border-box;transition:border-color .15s,box-shadow .15s}
.pick-box textarea.pk-inp{height:auto;min-height:74px;resize:vertical;line-height:1.6}
.pick-box .pk-inp:focus,.pick-box [data-inp]:focus{outline:none;border-color:var(--brand);box-shadow:var(--ring)}
/* ============ 商机 · 三方关系（业主 / 设计院 / 集成商 / 其他单位） ============ */
.pt-win{font-size:12px;color:var(--ok-d);background:#ecfdf3;border:1px solid #abefc6;border-radius:999px;padding:2px 10px;font-weight:500}
.pt-win b{font-weight:600}
.pt-win.no{color:var(--t3);background:#f8fafc;border-color:var(--line)}
.pt-grid{display:grid;grid-template-columns:1fr;gap:12px}
.pt-card{border:1px solid var(--line);border-radius:var(--r10);overflow:hidden;background:#fff}
.pt-h{display:flex;align-items:center;gap:8px;background:#f7f9fc;padding:6px 10px;border-bottom:1px solid var(--line)}
.pt-role{font-size:13px;font-weight:600;color:var(--deep)}
.pt-cnt{font-size:12px;color:var(--t3);flex:1 1 auto}
.pt-h .btn.sm{padding:1px 8px;font-size:12px}
/* 业主/设计院卡片：左侧单位信息、右侧操作按钮同一行，卡片更紧凑（原来按钮单独占一行、
   右侧留一大片空白，与集成商表格的密度差得远，看着"不协调"） */
.pt-one{display:flex;gap:14px;align-items:flex-start;padding:10px}
.pt-main{flex:1 1 auto;min-width:0}
.pt-one>.pt-ops{flex:0 0 auto;padding-top:1px}
.pt-one.off{opacity:.55}
.pt-name{font-size:13px;font-weight:600;color:var(--t1);display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.pt-meta{display:flex;flex-wrap:wrap;gap:4px 16px;margin-top:6px}
.pt-mi{font-size:12px;color:var(--t2)}
.pt-mi i{font-style:normal;color:var(--t3);margin-right:4px}
.pt-empty{padding:16px 10px;font-size:12px;color:var(--t3);text-align:center;background:#fcfdfe}
.pt-sec{border:1px solid var(--line);border-radius:var(--r10);overflow:hidden;background:#fff;margin-top:12px}
.pt-tbl{width:100%;border-collapse:collapse;font-size:12.5px}
.pt-tbl th{background:#fbfcfe;font-size:12px;font-weight:500;color:var(--t2);text-align:left;padding:6px 10px;border-bottom:1px solid var(--line)}
.pt-tbl td{padding:7px 10px;border-bottom:1px solid var(--line-2);vertical-align:top}
.pt-tbl tbody tr:last-child td{border-bottom:none}
.pt-tbl tr.off{opacity:.55}
.pt-tbl .num{text-align:right}
.pt-nm{display:flex;align-items:center;gap:6px;flex-wrap:wrap;font-weight:600;color:var(--t1)}
.pt-rm{font-size:12px;color:var(--t3);margin-top:3px;font-weight:400}
.pt-mute{color:#c3c9d2}
.pt-star{color:var(--warn);letter-spacing:1px}
/* P1-1 关系方状态胶囊：本身就是「一键切换」入口（有状态=蓝底 / 未标注=灰虚线 / 已失单=灰） */
.pt-state{display:inline-flex;align-items:center;gap:4px;font:inherit;font-size:12px;line-height:1.5;
  padding:1px 8px;border-radius:999px;cursor:pointer;background:var(--brand-t);border:1px solid #c7d7fe;color:var(--brand-d)}
.pt-state:hover{background:var(--brand-l)}
.pt-state i{font-style:normal;color:#7c93b8;font-size:11px}
.pt-state.none{background:#f7f8fa;border-color:#e3e6ec;color:#8b93a1;border-style:dashed}
.pt-state.off{background:#f2f4f7;border-color:var(--line);color:var(--t3)}
.pt-ops{display:flex;gap:5px;justify-content:flex-end;white-space:nowrap}
.pt-ops .btn.sm{padding:1px 7px;font-size:11.5px}
.pt-other{margin-top:12px;border:1px solid var(--line);border-radius:var(--r10);background:#fff}
.pt-other>summary{cursor:pointer;display:flex;align-items:center;gap:8px;padding:7px 10px;font-size:12.5px;list-style:none;background:#fbfcfe}
.pt-other>summary::-webkit-details-marker{display:none}
.pt-other>summary::before{content:'▸';color:var(--t3);font-size:11px}
.pt-other[open]>summary::before{content:'▾'}
.pt-other[open]>summary{border-bottom:1px solid var(--line)}

/* v16 「参与商机」区块：按角色自适应的统计条（设计院上图台账 / 集成商中标率） */
.pstats{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
.pstat{flex:1 1 260px;background:var(--head);border:1px solid var(--line);border-radius:var(--r10);
  padding:9px 12px;font-size:12.5px;color:var(--t2);line-height:1.8}
.pstat i{font-style:normal;display:block;font-size:11.5px;color:var(--t3);margin-bottom:2px}
.pstat b{color:var(--t1);font-variant-numeric:tabular-nums}
.pstat-sub{color:var(--t3);font-size:11.5px}
.plink{color:var(--brand-d);font-weight:600;text-decoration:none}
.plink:hover{text-decoration:underline}

/* ============ v21 · 下拉「可输入 + 模糊查询」控件 ============
   原生 <select> 原地保留（id / value / onchange / options 全部照旧），只做视觉隐藏 ——
   右侧留 36px 覆盖区（opacity:0、z-index 高于输入框）：用户点输入框、拖选文字都不受影响，
   同时自动化测试对原生 select 的可点判定继续通过。浮层挂 body + position:fixed，
   否则会被 .modal-bd / .drawer-bd 的 overflow 裁掉。 */
.se-wrap{position:relative;display:inline-block;vertical-align:middle;max-width:100%}
.se-wrap>select.se-native{position:absolute;right:0;top:0;width:36px;height:100%;opacity:0;z-index:3;
  border:0;padding:0;margin:0;min-width:0;cursor:pointer;appearance:none}
.se-wrap>.se-input{position:relative;z-index:1;display:block;width:100%;min-width:0;max-width:none;
  padding:7px 30px 7px 11px;border:1px solid #d0d5dd;border-radius:var(--r8);
  font-size:13px;font-family:inherit;height:34px;color:var(--t1);background:#fff;
  transition:border-color .15s,box-shadow .15s}
.se-wrap>.se-input:focus{outline:none;border-color:var(--brand);box-shadow:var(--ring)}
.se-wrap>.se-input::placeholder{color:var(--t3)}
.se-wrap:hover>.se-input{border-color:#b9c2cf}
/* 自绘箭头：跟随展开状态翻转 */
.se-wrap::after{content:'';position:absolute;right:11px;top:50%;width:6px;height:6px;
  border-right:1.7px solid var(--t3);border-bottom:1.7px solid var(--t3);
  transform:translateY(-70%) rotate(45deg);transition:transform .18s;pointer-events:none;z-index:2}
.se-wrap.on::after{transform:translateY(-25%) rotate(-135deg)}
.form-row .se-wrap,.form-grid .se-wrap{display:block;width:100%}
.filters .se-wrap{flex:0 1 auto;min-width:130px}
/* 卡片标题栏里的控件排成一行：搜索框与按钮同高对齐（≤900px 那档本来就是 flex） */
.card h2>span{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.card h2>span .se-wrap{width:auto;min-width:132px}
/* 结果浮层 */
.se-box{position:fixed;z-index:9997;display:none;max-height:280px;overflow:auto;padding:4px;
  background:#fff;border:1px solid var(--line);border-radius:var(--r10);
  box-shadow:0 12px 32px rgba(16,24,40,.16),0 2px 6px rgba(16,24,40,.06)}
.se-opt{padding:6px 10px;border-radius:6px;font-size:13px;color:var(--t1);cursor:pointer;line-height:1.5;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.se-opt b{color:var(--brand-d);font-weight:700}
.se-opt.on,.se-opt:hover{background:var(--brand-t)}
.se-opt.cur{color:var(--brand-d);font-weight:600}
.se-opt.dis{color:var(--t3);cursor:not-allowed}
.se-none{padding:8px 10px;font-size:12.5px;color:var(--t3);text-align:center}
/* ============ v28 · 产品线「下拉多选」自定义面板（美化版） ============ */
.ms{position:relative;display:block;width:100%}
.ms-trigger{position:relative;display:flex;align-items:center;gap:8px;width:100%;min-width:0;min-height:38px;
  padding:7px 36px 7px 12px;border:1px solid #d6dbe3;border-radius:10px;font-size:13px;font-family:inherit;
  background:#fff;color:#101828;text-align:left;cursor:pointer;box-sizing:border-box;transition:border-color .15s,box-shadow .15s}
.ms-trigger:hover{border-color:#b6c0cf}
.ms-trigger:focus{outline:none;border-color:#2563eb;box-shadow:0 0 0 3px rgba(37,99,235,.15)}
.ms-trigger .ms-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.5;flex:1}
.ms-trigger .ms-text.ph{color:#98a2b3;font-weight:400}
.ms-count{display:none;flex:0 0 auto;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 6px;
  background:#eef4ff;color:#2563eb;border-radius:999px;font-size:12px;font-weight:600;line-height:1}
.ms-trigger.has-sel .ms-count{display:inline-flex}
.ms-caret{position:absolute;right:13px;top:50%;width:7px;height:7px;
  border-right:2px solid #98a2b3;border-bottom:2px solid #98a2b3;
  transform:translateY(-70%) rotate(45deg);pointer-events:none;transition:transform .15s}
.ms-trigger[aria-expanded="true"] .ms-caret{transform:translateY(-30%) rotate(-135deg)}
.ms-panel{position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:60;display:none;
  max-height:280px;overflow:auto;padding:10px;background:#fff;border:1px solid #eef1f5;
  border-radius:12px;box-shadow:0 16px 40px rgba(16,24,40,.18),0 2px 8px rgba(16,24,40,.06)}
.ms-search{margin-bottom:8px;position:relative}
.ms-search input{width:100%;height:34px;box-sizing:border-box;border:1px solid #d6dbe3;border-radius:9px;
  padding:0 12px 0 32px;font-size:13px;font-family:inherit;color:#101828;background:#f8fafc}
.ms-search::before{content:"";position:absolute;left:11px;top:50%;width:12px;height:12px;
  transform:translateY(-50%);border:2px solid #9aa4b2;border-radius:50%}
.ms-search::after{content:"";position:absolute;left:16px;top:calc(50% + 3px);width:6px;height:2px;
  background:#9aa4b2;border-radius:1px;transform:rotate(45deg)}
.ms-search input:focus{outline:none;border-color:#2563eb;background:#fff;box-shadow:0 0 0 3px rgba(37,99,235,.15)}
.ms-actions{display:flex;gap:8px;margin-bottom:8px}
.ms-actions a{display:inline-flex;align-items:center;padding:4px 10px;border-radius:7px;background:#f1f5f9;
  color:#344054;cursor:pointer;text-decoration:none;font-size:12.5px;transition:background .15s}
.ms-actions a:hover{background:#e2e8f0}
.ms-list{display:flex;flex-direction:column;gap:4px}
.ms-opt{display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:8px;font-size:13px;
  color:#101828;cursor:pointer;white-space:nowrap;line-height:1.5;border:1px solid transparent;transition:background .12s,border-color .12s}
.ms-opt:hover{background:#f4f8ff;border-color:#dbeafe}
.ms-opt input[type=checkbox]{cursor:pointer;flex:0 0 auto;width:15px;height:15px;accent-color:#2563eb}
.ms-opt:has(input:checked){background:#eef4ff;border-color:#c7dbff}
/* ============ v29 · 报价单「新建报价单」明细行（与上面 .ms- 块一样：style.css 与 app.js 兜底副本必须一致） ============ */
/* v29.1：弹窗放大（原 560px，6 列明细挤成一团）；v29.2 再放大到 .xxl(1080px) —— 8 列三级联动 */
/* v29.2：明细 8 列 —— 产品名 / 型号 / 规格 三级联动下拉 + 数量 / 折数 / 折后单价 / 行小计 / 操作 */
.dq-head,.dq-row{display:grid;grid-template-columns:minmax(170px,1fr) 128px 158px 66px 66px 108px 98px 56px;gap:8px;align-items:center}
.dq-head{font-size:12px;color:#667085;padding:0 6px 6px;font-weight:600}
.dq-head span:last-child{text-align:center}
.dq-row{padding:6px;border:1px solid #eef1f5;border-radius:10px;background:#fbfcfe;margin-bottom:6px}
.dq-row select,.dq-row input{height:34px;box-sizing:border-box;border:1px solid #d6dbe3;border-radius:8px;
  padding:0 8px;font-size:13px;font-family:inherit;color:#101828;background:#fff;min-width:0;width:100%}
.dq-row select:focus,.dq-row input:focus{outline:none;border-color:#2563eb;box-shadow:0 0 0 3px rgba(37,99,235,.15)}
.dq-row .dq-line{text-align:right;font-size:13px;font-weight:600;color:#101828;white-space:nowrap;padding-right:2px}
/* 行内被 seEnhance 包出来的下拉：占满整格，免得格内只剩搜索框宽度 */
.dq-row .se-wrap{display:block;width:100%}
.dq-list{max-height:300px;overflow:auto;margin-bottom:8px;padding-right:2px}
.dq-total{text-align:right;font-size:13px;color:#344054;margin:2px 2px 12px}
.dq-total b{font-size:15px;color:#101828}
@media (max-width:640px){
  .dq-head{display:none}
  .dq-row{grid-template-columns:1fr 1fr;gap:6px}
  .dq-row .dq-line{text-align:left}
}
/* 子表单来源提示（从拜访报告里弹出来的「新建商机 / 新增联系人」） */
.form-tip{margin-bottom:12px;padding:7px 11px;background:#fffaeb;border:1px solid #fedf89;
  border-left:3px solid var(--warn);border-radius:var(--r8);font-size:12px;color:#93370d;line-height:1.6}

/* ============ v21 · 商机页视觉优化 ============ */
/* 筛选区收进一块浅底面板：6 个控件不再"散着飘"，日期区间之间加一道虚线分隔 */
.filters.opp-filters{background:#fafbfe;border:1px solid var(--line);border-radius:var(--r10);
  padding:10px 12px;gap:8px 10px;align-items:center}
.filters.opp-filters .fl-group{display:inline-flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding-left:10px;border-left:1px dashed #dfe5ee}
/* 商机表格 13 列本来就密：靠行高 / 斑马纹 / 语义分组提可读性（列结构与列序一行未动） */
.opp-tbl thead th{padding:11px 12px}
.opp-tbl tbody td{padding:10px 12px;vertical-align:middle}
.opp-tbl .opp-name{font-weight:600;color:var(--deep);text-decoration:none}
.opp-tbl .opp-name:hover{color:var(--brand);text-decoration:underline}
/* 估值三兄弟（最小 / 最大 / 平均）底子略深，跟后面的「评估金额」一眼分开 */
.opp-tbl tbody td.est{background-color:#f8fafd}
.opp-tbl tbody tr:not(.od-row):nth-child(even) td{background:#fbfcfe}
.opp-tbl tbody tr:not(.od-row):nth-child(even) td.est{background-color:#f4f7fc}
.opp-tbl tbody tr:not(.od-row):hover td{background:#eff5ff}
.opp-tbl tbody tr:not(.od-row):hover td.est{background-color:#e9f1fe}

/* ============ 响应式 ============
   P3⑮ 建立了 900 / 600 两档；v12 把移动端补成「能真正用」：
     · 顶部导航窄屏可横向滑动；header 固定 56px 高会让换行后的用户区被裁掉 → 改 min-height
     · 表格统一横向滚动 + 惯性滚动（保列宽，不挤压内容）
     · 触摸目标放大（手指点按；.btn.sm 原来上下内边距只有 2px）
     · 新增 ≤480 档：KPI 单列、抽屉占满宽、次要副标题让位
   ⚠️ 所有规则都在 max-width 媒体查询内 —— **桌面端（>900px）一行都不落**。 */
@media (max-width: 900px){
  header#hdr{flex-wrap:wrap;gap:6px;height:auto;min-height:60px;padding:6px 12px}
  header#hdr .logo{width:100%;margin-bottom:2px}
  header#hdr nav{order:3;width:100%;overflow-x:auto;white-space:nowrap;padding-bottom:4px;
    -webkit-overflow-scrolling:touch;scrollbar-width:none}
  header#hdr nav::-webkit-scrollbar{display:none}
  header#hdr .user{margin-left:auto;flex-wrap:wrap;gap:4px}
  .card h2>span{float:none;display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
  .filters{flex-wrap:wrap}
  /* 窄屏下筛选项最小宽度；.fl-sep（建档 / ~ 等纯文字）、.ck（复选框标签）、
     .fl-range（日期区间整体）不参与，否则一个「~」也会被撑成 120px，区间被拉得七零八落 */
  .filters>*:not(.fl-sep):not(.ck):not(.fl-range){min-width:120px}
  table{display:block;overflow-x:auto;white-space:nowrap;-webkit-overflow-scrolling:touch}
  .form-grid{grid-template-columns:1fr 1fr}
  .kpis{grid-template-columns:repeat(3,1fr)}
  .dict-layout{grid-template-columns:1fr}
  .drawer{width:92%}
  .drawer.xl .kv{grid-template-columns:1fr 1fr}
  .kv{display:grid;grid-template-columns:1fr 1fr;gap:4px 14px}
}
@media (max-width: 600px){
  body{font-size:13px}
  header#hdr nav a{padding:7px 12px;font-size:13px}
  main{padding:12px}
  .card{padding:14px}
  .card h2{font-size:15px}
  .form-grid{grid-template-columns:1fr}
  .kv{grid-template-columns:1fr}
  .kpis{grid-template-columns:1fr 1fr;gap:10px}
  .grid2{grid-template-columns:1fr}
  /* 触摸目标：窄屏一律放大到手指可点（原来 .btn.sm 只有 2px 上下内边距） */
  .btn{padding:8px 12px;font-size:13px}
  .btn.sm{padding:5px 10px;font-size:12.5px}
  .filters input,.filters select{padding:8px 10px}
  .modal{width:94%}
  .modal.wide{width:96%}
  .modal.sm,.modal.md{width:94%}
  .modal.xl,.modal.xxl{width:96%}
  .modal-bd{padding:14px}
  .modal-ft{flex-wrap:wrap}
  .drawer.wide{width:96%}
  .drawer.xl{width:96%}
  .drawer-bd{padding:14px}
  .drawer.xl .kv{grid-template-columns:1fr}
  .login-box{width:92%;max-width:92%;padding:24px 20px}
  .pager .pg-size-box{margin-left:0}
  /* v21：窄屏下日期区间必须能换行。原来 .fl-range 是 white-space:nowrap 的整块，
     两个 150px 日期框 + 分页筛选面板的内边距正好把页面撑出横向滚动条。 */
  .fl-range{flex-wrap:wrap;white-space:normal}
  .filters.opp-filters{padding:8px 10px}
  .filters.opp-filters .fl-group{padding-left:0;border-left:0;gap:8px}
}
@media (max-width: 480px){
  .kpis{grid-template-columns:1fr}
  .card h2>span{gap:4px}
  .card h2>span .btn{padding:6px 9px;font-size:12px}
  .drawer,.drawer.wide,.drawer.xl{width:100%}
  .modal,.modal.wide{width:98%}
  .h2sub{display:none}         /* 窄屏让位给操作按钮，说明文字在下方 note 里仍有 */
  .tag{font-size:10.5px}
}

/* ============================== */
/* ★ V31.29.1 §32 文本快速新建弹窗优化（PC）——统计 chip / 统一输入框 / 结果横幅 */
/* ============================== */
.qt-stats{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:8px}
.qt-chip{display:inline-flex;align-items:center;gap:6px;padding:5px 12px;border-radius:999px;
  font-size:12.5px;font-weight:600;border:1px solid var(--line);background:#f8fafc;color:var(--t2)}
.qt-chip b{font-size:15px}
.qt-chip.ok{background:#ecfdf3;border-color:#abefc6;color:#067647}
.qt-chip.warn{background:#fff6ed;border-color:#fddcab;color:#b54708}
.qt-sub{font-size:12px;color:var(--t3);margin-bottom:10px;line-height:1.7}
.qt-tbl td{padding:8px 8px;vertical-align:middle}
.qt-tbl input{padding:6px 9px;border:1px solid #d0d5dd;border-radius:8px;font-size:13px;
  font-family:inherit;color:var(--t1);background:#fff;transition:border-color .15s,box-shadow .15s}
.qt-tbl input:focus{outline:0;border-color:var(--brand);box-shadow:0 0 0 3px rgba(99,102,241,.12)}
.qt-tip{max-width:200px}
.qt-tip .tag{white-space:normal;line-height:1.6}
.qt-banner{display:flex;gap:10px;align-items:stretch;margin-bottom:10px}
.qt-banner .b{flex:1;border-radius:12px;padding:12px 16px;border:1px solid var(--line)}
.qt-banner .b .n{font-size:26px;font-weight:700;line-height:1.2;font-variant-numeric:tabular-nums}
.qt-banner .b .t{font-size:12px;color:var(--t3);margin-top:2px}
.qt-banner .b.ok{background:#ecfdf3;border-color:#abefc6}
.qt-banner .b.ok .n{color:#067647}
.qt-banner .b.bad{background:#fef3f2;border-color:#fecdca}
.qt-banner .b.bad .n{color:#b42318}
.qt-banner .b.skip{background:#f8fafc}
.qt-banner .b.skip .n{color:var(--t2)}
