/* BOK 智能销供 · 设计令牌
   与接待工作台、进销存系统同一套视觉语言（需求规格书 v0.6 第14.1节）：
   藏青为骨，信号橙只做点与线，白纸绿灰打底。
   令牌层与 bok-erp/static/style.css 保持一致，改动需两边同步；
   本文件末尾的「EO 专属」段落是本系统新增的地图与计算页组件。
   数据密集页面，行高与字号按 ERP 而非 C 端标准，一屏可读 15～20 行。 */
:root{
  --paper:#F4F6F3; --surface:#FFFFFF; --surface-2:#FAFBF9; --surface-3:#F0F3EF;
  --ink:#1C2430; --ink-2:#5B6472; --ink-3:#8B9199; --line:#E2E6E0; --line-2:#CBD2C9;
  --brand:#142D59; --brand-2:#1B3A70; --brand-ink:#FFFFFF;
  --accent:#142D59; --accent-tint:#EEF2FA; --accent-line:#D7E3FA;
  --signal:#E8760F; --signal-tint:#FDF3E9;
  --ok:#12A67F; --ok-tint:#F0F9F6;
  --crit:#E23B3B; --crit-tint:#FDF0F0; --hold:#8B9199;
  --nav-bg:#1A2B56; --nav-ink:#AEB8D2;
  --shadow:0 1px 2px rgba(20,45,89,.05), 0 4px 14px rgba(20,45,89,.05);
  --sans:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei","Noto Sans SC",system-ui,sans-serif;
  --mono:"IBM Plex Mono","SFMono-Regular","SF Mono",Consolas,"Liberation Mono",monospace;
  --r:10px; --r-s:6px;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body,#app{height:100%}
body{font:13px/1.5 var(--sans);color:var(--ink);background:var(--paper);
  -webkit-font-smoothing:antialiased}
.mono,.num{font-family:var(--mono);font-variant-numeric:tabular-nums}
.r{text-align:right}.c{text-align:center}
a{color:var(--brand);text-decoration:none}
button{font:inherit;cursor:pointer;border:none;background:none;color:inherit}
input,select,textarea{font:inherit;color:var(--ink);border:1px solid var(--line-2);
  border-radius:var(--r-s);padding:6px 9px;background:var(--surface);width:100%}
input:disabled,input[readonly]{background:var(--surface-3);color:var(--ink-2)}
:focus-visible{outline:2px solid var(--brand);outline-offset:1px}
::placeholder{color:var(--ink-3)}
.hide{display:none !important}
@media (prefers-reduced-motion:reduce){*{transition:none !important;animation:none !important}}

/* ── 骨架 ── */
.shell{display:flex;height:100%}
.rail{width:214px;background:var(--nav-bg);color:var(--nav-ink);display:flex;
  flex-direction:column;flex-shrink:0;overflow-y:auto}
/* 品牌区：整张品牌图（含徽标与名称）。图自带深蓝底，与侧栏同色。
   宽度撑满、高度自适应，绝不拉伸变形 */
.rail .brand{padding:0;border-bottom:1px solid rgba(255,255,255,.09);line-height:0}
.rail .brand img{display:block;width:100%;height:auto}
.rail .grp{padding:11px 0 2px}
.rail .grp-t{font-size:10px;letter-spacing:.1em;text-transform:uppercase;
  color:#65788F;padding:0 16px 6px}
.rail nav button{display:flex;align-items:center;gap:10px;width:100%;text-align:left;
  color:var(--nav-ink);font-size:13px;margin:0 12px 5px;padding:8px 14px;
  border-radius:12px;width:calc(100% - 24px);transition:background .15s,color .15s}
.rail nav button:hover{background:rgba(255,255,255,.07);color:#fff}
.rail nav button.on{background:#fff;color:var(--brand);font-weight:700;
  box-shadow:0 6px 18px rgba(0,0,0,.22)}
.rail nav button .dot{width:6px;height:6px;border-radius:50%;background:currentColor;
  opacity:.45;flex:none}
.rail nav button.on .dot{opacity:1;background:var(--signal)}
.rail .me{margin-top:auto;padding:12px 16px;border-top:1px solid rgba(255,255,255,.1);
  font-size:12px;display:flex;align-items:center;gap:8px}
.rail .me .out{margin-left:auto;font-size:11.5px;color:#8FA3C8}
.rail .me .out:hover{color:#fff}

.main{flex:1;display:flex;flex-direction:column;min-width:0}
.topbar{background:var(--surface);border-bottom:1px solid var(--line);height:48px;
  padding:0 18px;display:flex;align-items:center;gap:12px;flex:none}
.crumb{font-size:12px;color:var(--ink-3)}
.crumb b{color:var(--ink);font-weight:600}
/* 返回上一步。没有可退的地方时整个隐藏（hidden 属性），
   免得摆一个点了没反应的按钮在那 */
.crumb-back{display:inline-flex;align-items:center;gap:4px;
  padding:3px 8px 3px 6px;font:inherit;font-size:11.5px;line-height:1;
  color:var(--ink-2);background:var(--surface-2);
  border:1px solid var(--line);border-radius:var(--r-s);
  cursor:pointer;transition:background .15s,border-color .15s,color .15s}
.crumb-back:hover{color:var(--ink);background:var(--surface-3);border-color:var(--line-2)}
.crumb-back:active{background:var(--line)}
.crumb-back:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.crumb-back[hidden]{display:none}
.spacer{flex:1}
.page{flex:1;overflow:auto;padding:16px 18px 40px}
/* 「一屏铺满」型页面（配送方案、全国客户地图）：
   两栏区自动吃掉标题行之后的全部剩余高度。
   以前是 height:calc(100vh - 一个魔数)，那个魔数要把 topbar、页面内边距、
   标题行高度、外边距折叠全算对才准——两个页面的标题行还不一样高，
   多减少减都会在底部留下一条空白。交给 flex 就不用算了 */
/* 标题行上下留白拉平：上面是 .page 的 padding-top 16，下面是两栏区的
   margin-top 25，差着 9px，标题行连同右边那排控件就整体偏上。
   两边都取 20/21，那条灰底上标题和控件才在正中间 */
.page.fill{display:flex;flex-direction:column;padding-top:20px}
.page.fill>.cols,.page.fill>.plan-wrap{flex:1 1 auto;height:auto;margin-top:21px}
/* flex 容器里相邻子项的外边距不再折叠。标题行的 margin-bottom 会和两栏区的
   margin-top 直接相加，间距从想要的 25px 变成 38px，所以在这里把上面那半清零，
   间距只由两栏区的 margin-top 说了算 */
.page.fill>.phead,.page.fill>.banner{margin-bottom:0}

/* ── 通用零件 ── */
/* align-items 用 center：右边那排控件只有 28px 高，标题块有 48px，
   贴顶对齐的话控件会吊在标题行上沿，和下面卡片之间空一大块。
   居中之后控件正好落在标题行的中线上 */
.phead{display:flex;align-items:center;gap:12px;margin-bottom:13px;flex-wrap:wrap}
.phead h2{font-size:18px;font-weight:650;letter-spacing:-.01em}
.phead .sub{font-size:12px;color:var(--ink-2);margin-top:3px}
/* 页头右侧的工具条：分段开关、下拉、按钮三种控件各有各的默认高度
   （实测 39.5 / 31 / 32.8），并排摆一行就是高低不齐的。
   这里按住 28px —— 全站其它页面按钮就是这个尺寸，跨页看着才是一套东西。
   高度写死而不是靠上下内边距凑：三种控件的行高基准不一样，凑不准 */
.phead .switch{height:28px;padding:2px;margin-bottom:0;align-items:center}
.phead .switch button{height:24px;padding:0 12px;font-size:12px;line-height:24px}
.phead select,.phead input{height:28px;padding:0 8px;font-size:12px}
.phead .btn{height:28px;padding:0 12px;font-size:12px;
  display:inline-flex;align-items:center;justify-content:center}
/* 页头里的状态胶囊也跟按钮并排站着（地图页的「本厂已定位」），
   默认 22.4px 比按钮矮一圈。只在页头拉平，表格里的状态标签不受影响 */
.phead .pill{height:28px;padding:0 11px}
.btn{border:1px solid var(--line-2);background:var(--surface);color:var(--brand);
  padding:6px 13px;border-radius:var(--r-s);font-size:12.5px;white-space:nowrap;
  transition:border-color .12s,color .12s}
.btn:hover{border-color:var(--brand)}
.btn:disabled{opacity:.45;cursor:not-allowed}
.btn.primary{background:var(--brand);border-color:var(--brand);color:var(--brand-ink);font-weight:500}
.btn.primary:hover{background:var(--brand-2);border-color:var(--brand-2)}
.btn.ghost{border-color:transparent;color:var(--ink-2)}
.btn.ghost:hover{color:var(--signal);border-color:var(--signal)}
.btn.sm{padding:4px 10px;font-size:12px}
/* 只有一个字符的键（比如待办后面那个「不再提醒」的叉）：
   压成方的，别让它跟旁边的文字键一样宽 */
/* 两三个互斥的挡位挤成一条，比摆两个独立按钮更像「切换视角」而不是「两个动作」 */
.seg{display:inline-flex;border:1px solid var(--line-2);border-radius:var(--r-s);
  overflow:hidden}
.seg button{padding:4px 11px;font-size:12px;background:var(--surface);
  color:var(--ink-2);border:0;border-left:1px solid var(--line-2);white-space:nowrap}
.seg button:first-child{border-left:0}
.seg button.on{background:var(--brand);color:#fff;font-weight:600}
.seg button:not(.on):hover{background:var(--surface-3)}

.btn.icon{padding:4px 8px;font-size:12px;color:var(--ink-3);line-height:1}
.btn.icon:hover{color:var(--crit);border-color:var(--crit)}

/* ── 资质材料 ── */
/* 一份材料一张卡，图片直接铺出来。审的人本来就是在「看证」，
   让他先点开一个个文件再回来按通过，多半就不点了 */
.cert-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:10px}
.cert-card{display:block;border:1px solid var(--line);border-radius:9px;
  background:var(--surface);overflow:hidden;text-decoration:none;color:var(--ink);
  transition:border-color .15s}
.cert-card:hover{border-color:var(--brand)}
.cert-card .ct-h{padding:8px 10px 6px;font-size:12.5px;display:flex;
  align-items:baseline;gap:6px}
.cert-card .ct-h b{font-weight:600;flex:1;min-width:0}
.cert-card .ct-h .pill{font-size:10px;padding:1px 7px;font-style:normal}
.cert-card img{display:block;width:100%;height:150px;object-fit:cover;
  background:var(--surface-3);border-top:1px solid var(--line);
  border-bottom:1px solid var(--line)}
.cert-card .ct-file{height:150px;display:flex;align-items:center;justify-content:center;
  background:var(--surface-3);border-top:1px solid var(--line);
  border-bottom:1px solid var(--line);font-size:12.5px;color:var(--ink-2)}
/* 图片打不开时别留一块空灰——那看着像「这份材料是空的」，
   实际只是没取到。换成一句话，人知道还能点开看 */
.cert-card .ct-file.fb{display:none}
.cert-card img.bad{display:none}
.cert-card img.bad + .ct-file.fb{display:flex}
.cert-card .ct-m{padding:6px 10px 8px;font-size:11px;color:var(--ink-3);line-height:1.5}
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:var(--shadow);overflow:hidden}
.card+.card{margin-top:12px}
.card-h{padding:10px 14px;border-bottom:1px solid var(--line);display:flex;
  align-items:center;gap:10px;flex-wrap:wrap}
.card-h h3{font-size:13.5px;font-weight:600}
.card-b{padding:14px}
/* 车牌行上的里程与油耗。标签压小压灰、数字留原色，
   一行里塞四五个数才不至于糊成一片 */
.tcell{font-size:11.5px;color:var(--ink);display:inline-flex;align-items:baseline;
  gap:4px;flex-wrap:wrap;font-variant-numeric:tabular-nums}
.tcell i{font-style:normal;color:var(--ink-3);font-size:10.5px;margin-left:6px}
.tcell i:first-child{margin-left:0}
.eyebrow{font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;
  color:var(--ink-3);font-weight:600}
.muted{color:var(--ink-3)}
.grid{display:grid;gap:12px}

/* 状态标签：白底描边胶囊，颜色+文字双编码 */
.pill{display:inline-flex;align-items:center;gap:5px;padding:1px 9px;border-radius:99px;
  font-size:11.5px;line-height:1.6;white-space:nowrap;background:var(--surface);
  border:1px solid var(--line-2);color:var(--ink-2)}
.pill::before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor;flex:none}
.pill.ok{border-color:var(--ok);color:var(--ok)}
.pill.warn{border-color:var(--signal);color:var(--signal)}
.pill.crit{border-color:var(--crit);color:var(--crit)}
.pill.info{border-color:var(--accent-line);color:var(--accent)}
.pill.hold{border-color:var(--line-2);color:var(--hold)}
.pill.plain::before{display:none}

/* 待办/预警列表。工作台和预警中心共用。
   这几个类之前只写了 HTML 没写样式，所以文字贴着卡片左边缘、
   严重度色条不显示、分类和按钮还掉到下一行去了。 */
.alerts .alert-row{display:flex;align-items:center;gap:10px;
  padding:10px 14px;border-bottom:1px solid var(--line)}
.alerts .alert-row:last-child{border-bottom:none}
/* 左侧色条，跟卡片标题的 14px 左边距对齐 */
.alerts .sev{flex:none;width:3px;align-self:stretch;min-height:26px;
  border-radius:2px;background:var(--line-2)}
.alerts .sev.c{background:var(--crit)}
.alerts .sev.w{background:var(--signal)}
.alerts .sev.i{background:var(--line-2)}
.alerts .txt{flex:1 1 auto;min-width:0}
.alerts .txt b{font-size:13px;font-weight:600}
/* 整行可点：待办本来就是「点一下去办」，只有右边那颗小键能点的话，
   人得先瞄准 */
.alerts .alert-row.go{cursor:pointer}
.alerts .alert-row.go:hover{background:var(--surface-2)}
/* 这活归谁。管理层的工作台上摆着全公司的待办，不标岗位就不知道该催谁；
   自己岗位的活不标——那是废话 */
.alerts .txt .who{font-size:10.5px;color:var(--ink-2);background:var(--surface-3);
  border:1px solid var(--line);border-radius:20px;padding:1px 8px;margin-left:8px;
  white-space:nowrap}
/* 卡了多久。等半天和等五天，催的力度不一样 */
.alerts .when{flex:0 0 auto;font-size:11.5px;color:var(--ink-3);
  font-variant-numeric:tabular-nums;white-space:nowrap}
/* 从工作台点进来时，把该办的那一行点一下亮给人看，省得自己在几十行里找 */
@keyframes todo-flash{
  0%,100%{box-shadow:0 0 0 0 rgba(232,118,15,0)}
  15%,60%{box-shadow:0 0 0 3px rgba(232,118,15,.35)}
}
.flash{animation:todo-flash 2.4s ease-out;border-radius:10px}
.alerts .txt .meta{font-size:12px;color:var(--ink-2);margin-top:2px;line-height:1.5}
/* 窄屏一行排不下：分类和按钮换到文字下面，别横向挤成一团 */
@media(max-width:768px){
  .alerts .alert-row{flex-wrap:wrap;gap:6px 8px}
  .alerts .txt{flex:1 0 100%}
}

/* 表格 */
.tw{overflow-x:auto}
table.dt{width:100%;border-collapse:separate;border-spacing:0;font-size:12.5px}
table.dt th{background:var(--surface-2);color:var(--ink-2);font-weight:500;font-size:11.5px;
  text-align:left;padding:7px 10px;border-bottom:1px solid var(--line);white-space:nowrap;
  position:sticky;top:0;z-index:2}
table.dt td{padding:0 10px;height:33px;border-bottom:1px solid var(--line);
  white-space:nowrap;vertical-align:middle}
table.dt tbody tr:hover td{background:var(--surface-3)}
table.dt tbody tr:last-child td{border-bottom:none}
table.dt td.wrap{white-space:normal;min-width:170px}
table.dt tfoot td{background:var(--surface-2);font-weight:650;border-top:1px solid var(--line)}
/* ── 地图客户点：圆点 + 放大后挂的简称牌 ── */
.cmk{display:flex;flex-direction:column;align-items:center;cursor:pointer}
.cmk-dot{display:block;border-radius:50%;box-sizing:border-box;
  box-shadow:0 2px 6px rgba(0,0,0,.3);transition:transform .15s}
.cmk:hover .cmk-dot{transform:scale(1.28)}
/* 名牌默认藏着，zoom 到市级（容器带 show-names）才亮出来。
   白底描边压得住底图的路网灰，看着跟高德自己的 POI 牌一个待遇 */
.cmk-name{display:none;margin-top:3px;padding:1px 6px;border-radius:4px;
  font-size:11px;font-weight:600;line-height:1.5;color:#142D59;
  background:rgba(255,255,255,.94);border:1px solid rgba(20,45,89,.18);
  box-shadow:0 1px 4px rgba(0,0,0,.18);white-space:nowrap}
.show-names .cmk-name{display:block}
/* 睡着的客户名牌也跟着灰，不然点是灰的牌是精神的，对不上 */
.cmk.sleep .cmk-name{color:#5C6675;background:rgba(244,245,247,.94)}

/* ── 订单中心：进度点与行内选车 ── */
.ostep{display:inline-flex;align-items:center;gap:3px;font-size:11.5px;color:var(--ink-2)}
.ostep i{width:8px;height:8px;border-radius:50%;background:var(--line-2)}
.ostep i.done{background:var(--ok)}
.ostep i.now{background:var(--signal);box-shadow:0 0 0 3px rgba(232,118,15,.18)}
.ostep b{margin-left:5px;font-weight:600;color:var(--ink)}
.ostep.crit{color:var(--crit);font-weight:600}
.osel{width:150px;padding:3px 6px;font-size:12px;margin-right:4px}
/* 订单详情里的流转记录：一行一环，办过的亮绿点 */
.oline{display:flex;align-items:baseline;gap:8px;padding:4px 0;font-size:12.5px}
.oline i{width:8px;height:8px;border-radius:50%;background:var(--line-2);flex:none;
  align-self:center}
.oline.done i{background:var(--ok)}
.oline b{font-weight:600;min-width:96px}
.oline span{color:var(--ink-2)}

/* ── 能打字搜的选择框（客户两百多家，原生 select 翻不动）── */
.pick{position:relative}
.pick-in{padding-right:26px}
.pick-caret{position:absolute;right:9px;top:50%;transform:translateY(-50%);
  color:var(--ink-3);font-size:11px;pointer-events:auto;cursor:pointer}
.pick-menu{position:absolute;top:calc(100% + 3px);left:0;right:0;z-index:40;
  max-height:min(60vh,420px);overflow:auto;background:var(--surface);
  border:1px solid var(--line-2);border-radius:var(--r-s);
  box-shadow:0 10px 28px rgba(20,45,89,.14)}
.pick-i{display:flex;gap:10px;align-items:baseline;padding:7px 10px;
  font-size:12.5px;cursor:pointer;border-bottom:1px solid var(--line)}
.pick-i:last-child{border-bottom:none}
.pick-i:hover,.pick-i.on{background:var(--accent-tint)}
.pick-i .m{margin-left:auto;color:var(--ink-3);font-size:11px;white-space:nowrap}
.pick-empty{padding:11px 12px;color:var(--ink-3);font-size:11.5px;line-height:1.6}

/* 长期没进货的客户：名字后面一个橙点，列表里画一条分界线 */
.dot-sleep{display:inline-block;width:7px;height:7px;border-radius:50%;
  background:var(--signal);margin-left:6px;vertical-align:1px;cursor:help}
table.dt tr.split td{background:var(--surface-2);color:var(--ink-3);font-size:11.5px;
  height:28px;border-top:2px solid var(--signal);white-space:normal}
table.dt tbody tr.split:hover td{background:var(--surface-2)}
.sub-td{color:var(--ink-3);font-size:11px}
.link{color:var(--brand);cursor:pointer}
.link:hover{text-decoration:underline}
.hi{background:var(--accent-tint)}

/* 筛选条 */
.filters{display:flex;gap:8px;flex-wrap:wrap;align-items:center;padding:10px 14px;
  border-bottom:1px solid var(--line);background:var(--surface-2)}
.filters input,.filters select{width:auto;min-width:120px;height:29px;padding:4px 9px;
  border-radius:99px;font-size:12px}
.filters input.q{min-width:200px}

/* 指标卡 */
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px}
.kpi{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:11px 13px;box-shadow:var(--shadow)}
.kpi .lab{font-size:11.5px;color:var(--ink-2)}
.kpi .val{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:22px;
  font-weight:600;letter-spacing:-.02em;margin-top:4px;line-height:1.15}
.kpi .foot{font-size:11px;color:var(--ink-3);margin-top:2px}
.kpi.sig{border-left:3px solid var(--signal)} .kpi.sig .val{color:var(--signal)}
.kpi.bad{border-left:3px solid var(--crit)} .kpi.bad .val{color:var(--crit)}

/* 表单 */
.fgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(215px,1fr));gap:12px 16px}
.fld label{display:block;font-size:11.5px;color:var(--ink-2);margin-bottom:3px}
.fld label .req{color:var(--crit)}
.fld .hint{font-size:11px;color:var(--ink-3);margin-top:3px}
.fld .hint.bad{color:var(--crit)} .fld .hint.good{color:var(--ok)}
.row-inline{display:flex;gap:8px;align-items:center}

/* 提示条：左边线为主 */
.banner{display:flex;gap:9px;padding:9px 12px;border:1px solid var(--line);
  border-left-width:3px;border-radius:var(--r-s);font-size:12.5px;align-items:flex-start;
  background:var(--surface);margin-bottom:12px}
.banner b{font-weight:650;flex:none}
.banner .body{color:var(--ink);flex:1}
.banner.warn{border-left-color:var(--signal);color:var(--signal)}
.banner.crit{border-left-color:var(--crit);color:var(--crit)}
.banner.info{border-left-color:var(--accent);color:var(--accent);background:var(--accent-tint)}
.banner.ok{border-left-color:var(--ok);color:var(--ok)}

/* 弹层 */
/* 全站层级，从低到高：
     地图工具条 60 ／ 下拉菜单 130 ／ 全屏层 900 ／ 弹层 1000 ／ toast 1100
   弹层必须压过全屏层。全屏看地图时点客户点位照样会弹这个框，
   层级低了就被那块不透明的全屏底盖住——界面上什么都不发生，
   像点了个死点，连点几下叠几层，一退出全屏全糊脸上。
   （2026-08-15 踩过一次：全屏层从 120 提到 900，忘了同步这里） */
.mask{position:fixed;inset:0;background:rgba(20,36,48,.34);z-index:1000;
  display:flex;align-items:flex-start;justify-content:center;padding:5vh 16px;overflow:auto}
/* 面板可拖右下角缩放。宽度封死时内容放不下只能左右滚，
   一滚左边的字段就滚出视野——录入报价那种四列表单必踩。
   max-width 放到 96vw 是为了让 resize 拉得动：CSS resize 突破不了 max-width。 */
.modal{background:var(--surface);border-radius:var(--r);box-shadow:0 18px 50px rgba(0,0,0,.25);
  width:760px;max-width:96vw;min-width:340px;max-height:92vh;min-height:180px;
  display:flex;flex-direction:column;overflow:hidden;resize:both}
.modal.wide{width:1080px}
.modal-h{padding:13px 16px;border-bottom:1px solid var(--line);display:flex;
  align-items:center;gap:10px;flex:0 0 auto}
.modal-h h3{font-size:14.5px;font-weight:650}
/* flex:1 + min-height:0 让内容区吃掉剩余高度并自己滚，
   高度改由 .modal 统一管，这样拖大面板时内容区跟着变大 */
.modal-b{padding:16px;overflow:auto;flex:1 1 auto;min-height:0}
.modal-f{padding:11px 16px;border-top:1px solid var(--line);display:flex;
  gap:8px;justify-content:flex-end;background:var(--surface-2);flex:0 0 auto;
  position:relative}
/* 原生 resize 手柄压在圆角里不显眼，右下角补一个可见的斜纹 */
.modal-f::after{content:'';position:absolute;right:3px;bottom:3px;width:12px;height:12px;
  pointer-events:none;opacity:.45;
  background:linear-gradient(135deg,transparent 0 45%,var(--ink-3) 45% 55%,transparent 55% 70%,
    var(--ink-3) 70% 80%,transparent 80%)}
/* 手机上没有鼠标，拖拽手柄纯属碍事 */
@media(max-width:768px){
  .modal{resize:none;width:100%;max-width:100%}
  .modal.wide{width:100%}
  .modal-f::after{display:none}
}

/* 登录 */
.login{height:100%;display:flex;align-items:center;justify-content:center;
  background:var(--nav-bg)}
.login .box{background:#fff;border-radius:14px;padding:30px 32px;width:340px;
  box-shadow:0 20px 60px rgba(0,0,0,.3)}
.login h1{font-size:19px;color:var(--brand);margin-bottom:4px}
.login p{font-size:12.5px;color:var(--ink-2);margin-bottom:18px}
.login .btn{width:100%;justify-content:center;margin-top:12px;padding:9px}

/* 提示气泡 */
.toast{position:fixed;left:50%;bottom:34px;transform:translateX(-50%);z-index:1100;
  background:var(--ink);color:#fff;padding:9px 16px;border-radius:99px;font-size:13px;
  box-shadow:0 8px 26px rgba(0,0,0,.28);max-width:80vw}
.toast.bad{background:var(--crit)}
.toast.ok{background:var(--ok)}

.empty{padding:40px 16px;text-align:center;color:var(--ink-3);font-size:13px}
.pager{display:flex;gap:8px;align-items:center;justify-content:flex-end;
  padding:9px 14px;border-top:1px solid var(--line);font-size:12px;color:var(--ink-2)}

@media (max-width:820px){
  .shell{flex-direction:column}
  .rail{width:100%;flex-direction:row;overflow-x:auto;align-items:center;height:auto}
  .rail .brand,.rail .grp-t,.rail .me{display:none}
  .rail .grp{display:flex;padding:0}
  .rail nav{display:flex}
  .rail nav button{margin:6px 4px;width:auto;white-space:nowrap;border-radius:99px}
  .page{padding:12px}
  .fgrid{grid-template-columns:1fr}
}

/* ── 系统对话 ── */
.ask-wrap{display:flex;flex-direction:column;height:calc(100vh - 140px);max-width:1020px}
.ask-log{flex:1;overflow-y:auto;padding:2px 2px 12px}
.ask-msg{margin-bottom:14px;display:flex;gap:9px}
.ask-msg .who{width:26px;height:26px;border-radius:50%;flex:none;display:grid;
  place-items:center;font-size:11px;font-weight:600}
.ask-msg.me .who{background:var(--brand);color:#fff}
.ask-msg.sys .who{background:var(--surface-3);color:var(--brand);border:1px solid var(--line)}
.ask-msg .bubble{flex:1;min-width:0}
.ask-msg.me .bubble{background:var(--accent-tint);border:1px solid var(--accent-line);
  border-radius:var(--r);padding:9px 12px;font-size:13px}
.ask-msg.sys .bubble{background:var(--surface);border:1px solid var(--line);
  border-radius:var(--r);padding:11px 13px;box-shadow:var(--shadow)}
.ask-answer{font-size:13.5px;line-height:1.65;margin-bottom:9px}
.ask-sql{background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r-s);
  padding:8px 10px;font-family:var(--mono);font-size:11.5px;color:var(--ink-2);
  white-space:pre-wrap;word-break:break-word;margin-top:8px;line-height:1.5}
.ask-sql-t{font-size:11px;color:var(--ink-3);cursor:pointer;user-select:none;margin-top:8px}
.ask-sql-t:hover{color:var(--brand)}
.ask-meta{font-size:11px;color:var(--ink-3);margin-top:7px}
.ask-bad{color:var(--crit);font-size:13px;line-height:1.7;white-space:pre-wrap}
.ask-in{display:flex;gap:8px;padding:11px 0 0;border-top:1px solid var(--line);flex:none}
.ask-in input{flex:1;height:38px;border-radius:99px;padding:0 16px;font-size:13.5px}
.ask-in button{border-radius:99px;padding:0 20px;height:38px}
.ask-tips{display:flex;gap:7px;flex-wrap:wrap;margin-bottom:12px}
.ask-tip{border:1px solid var(--line-2);background:var(--surface);border-radius:99px;
  padding:5px 12px;font-size:12px;color:var(--ink-2);cursor:pointer}
.ask-tip:hover{border-color:var(--brand);color:var(--brand)}
.ask-hint{background:var(--surface-2);border:1px solid var(--line);
  border-left:3px solid var(--signal);border-radius:var(--r-s);padding:10px 13px;
  font-size:12.5px;color:var(--ink-2);line-height:1.7;margin-bottom:14px}
.ask-hint b{color:var(--ink)}
.dots span{display:inline-block;width:5px;height:5px;border-radius:50%;
  background:var(--ink-3);margin-right:3px;animation:blink 1.2s infinite}
.dots span:nth-child(2){animation-delay:.2s}
.dots span:nth-child(3){animation-delay:.4s}
@keyframes blink{0%,80%,100%{opacity:.25}40%{opacity:1}}
.ask-exp{display:flex;gap:7px;margin-top:10px;flex-wrap:wrap}

/* ── 机会雷达 ── */
.dim{color:var(--ink-3);font-size:12px}
.num.warn{color:var(--signal)} .num.bad{color:var(--crit)}
.note{background:var(--surface-3);border-radius:var(--r-s);padding:10px 12px;
  font-size:13px;line-height:1.65;border-left:2px solid var(--line-2)}
.note.ok{border-left-color:var(--ok)}
.fgrid.ro .f label{font-size:11.5px;color:var(--ink-3);display:block;margin-bottom:3px}
.fgrid.ro .f .v{font-size:13.5px}
/* 对话回放：客户在左、我方在右，跟聊天工具的方向一致，扫一眼就知道谁在说 */
.chat{max-height:46vh;overflow-y:auto;background:var(--paper);border:1px solid var(--line);
  border-radius:var(--r-s);padding:12px}
.chat .msg{margin-bottom:11px;display:flex;flex-direction:column;align-items:flex-start}
.chat .msg.me{align-items:flex-end}
.chat .bub{max-width:78%;background:var(--surface);border:1px solid var(--line);
  border-radius:10px;padding:8px 11px;font-size:13px;line-height:1.6;
  white-space:pre-wrap;word-break:break-word}
.chat .msg.me .bub{background:var(--brand);color:#fff;border-color:var(--brand)}
.chat .bub .tr{margin-top:5px;padding-top:5px;border-top:1px dashed var(--line-2);
  font-size:12px;color:var(--ink-2)}
.chat .msg.me .bub .tr{border-top-color:rgba(255,255,255,.28);color:#C9D2E6}
.chat .ts{font-size:10.5px;color:var(--ink-3);margin-top:3px}
/* 表格内联输入：发货明细这类边看边填的场景，不另开弹窗 */
.tin{width:100%;padding:5px 7px;font-size:13px;border:1px solid var(--line-2);
  border-radius:var(--r-s);background:var(--surface)}
.tin[type=number]{font-family:var(--mono);text-align:right}
/* 页内分段切换：同一页里切两组同级数据（返修单/报废单），比开两个菜单项轻 */
.switch{display:inline-flex;background:var(--surface-3);border-radius:var(--r-s);
  padding:3px;margin-bottom:12px;gap:2px}
.switch button{padding:7px 16px;border-radius:calc(var(--r-s) - 1px);font-size:13px;
  color:var(--ink-2);white-space:nowrap}
.switch button.on{background:var(--surface);color:var(--brand);font-weight:600;
  box-shadow:0 1px 3px rgba(20,45,89,.12)}
/* 对话里的工具调用过程：默认折叠，展开能逐步看每步做了什么、SQL 是什么 */
.ask-steps{margin-bottom:8px}
.ask-step{padding:6px 0;border-bottom:1px dashed var(--line);font-size:12.5px}
.ask-step:last-child{border-bottom:none}
.ask-step.bad b{color:var(--crit)}
.ask-step .ask-sql{margin-top:4px;font-size:11.5px}

/* ══════════════ EO 专属：一键计算与地图 ══════════════ */
/* 计算页：左边选，右边看结果。业务员的动线是从左到右一遍过，
   不要做成"填完表再点提交跳转"——参数一改结果就要跟着变。 */
.calc-wrap{display:grid;grid-template-columns:minmax(340px,420px) 1fr;gap:14px;
  align-items:start}
@media(max-width:1000px){.calc-wrap{grid-template-columns:1fr}}
/* 格子默认不肯缩到内容以下：气雾罐预览那张五列表格会把整列撑出屏幕，
   连左边的输入表一起被截。放开之后表格在自己的框里横着滚 */
.calc-wrap>*{min-width:0}

/* 明细行：一行一种产品+瓶型+数量 */
.line-row{border:1px solid var(--line);border-radius:var(--r-s);padding:10px 11px;
  margin-bottom:9px;background:var(--surface-2)}
.line-row .lh{display:flex;align-items:center;gap:8px;margin-bottom:8px}
.line-row .lh b{font-size:12.5px}
.line-row .del{margin-left:auto;color:var(--ink-3);font-size:12px}
.line-row .del:hover{color:var(--crit)}
.line-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px 10px}
.line-grid .full{grid-column:1/-1}

/* 结果分区：产品/包装/库存/运输/路线/费用/报价，各占一块 */
.res-sec{border-bottom:1px solid var(--line);padding:11px 14px}
.res-sec:last-child{border-bottom:none}
.res-sec .st{font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;
  color:var(--ink-3);font-weight:600;margin-bottom:7px}
.res-kv{display:grid;grid-template-columns:repeat(auto-fit,minmax(128px,1fr));gap:8px 14px}
.res-kv .k{font-size:11.5px;color:var(--ink-2)}
.res-kv .v{font-family:var(--mono);font-variant-numeric:tabular-nums;
  font-size:15px;font-weight:600;margin-top:1px;line-height:1.2}
.res-kv .v.big{font-size:19px}
.res-kv .v.sig{color:var(--signal)}
.res-kv .v.ok{color:var(--ok)}
.res-kv .v.bad{color:var(--crit)}
.res-kv .u{font-size:11px;color:var(--ink-3);font-weight:400;
  font-family:var(--sans);margin-left:2px}
/* 没配参数时不显示 0，显示"待配置"——0 会被当成真值用来做决策 */
.res-kv .v.na{font-size:12.5px;font-weight:500;color:var(--ink-3);font-family:var(--sans)}

/* 待配置清单：告诉业务员缺什么、为什么缺了不行 */
.pend{background:var(--signal-tint);border:1px solid var(--signal);
  border-left-width:3px;border-radius:var(--r-s);padding:10px 12px;margin-bottom:12px}
.pend .pt{font-size:12.5px;font-weight:650;color:var(--signal);margin-bottom:6px}
.pend ul{margin:0;padding-left:17px}
.pend li{font-size:12px;color:var(--ink-2);line-height:1.75}
.pend li b{color:var(--ink)}

/* 阻断项：会挡住下单的硬问题 */
.blocks{background:var(--crit-tint);border:1px solid var(--crit);border-left-width:3px;
  border-radius:var(--r-s);padding:10px 12px;margin-bottom:12px}
.blocks .pt{font-size:12.5px;font-weight:650;color:var(--crit);margin-bottom:6px}
.blocks li{font-size:12px;color:var(--ink);line-height:1.75}

/* 计算链：把气体→瓶→框→毛重这条链摆出来，业务员才信这个数 */
.chain{display:flex;flex-wrap:wrap;gap:6px;align-items:center;font-size:11.5px;
  color:var(--ink-2);background:var(--surface-2);border-radius:var(--r-s);
  padding:8px 11px;margin-bottom:10px}
.chain b{font-family:var(--mono);color:var(--ink);font-weight:600}
.chain .arw{color:var(--ink-3)}

/* 客户地图（14.4）：点位高亮的四种状态 */
.map-box{height:min(62vh,560px);border-radius:var(--r);overflow:hidden;
  border:1px solid var(--line);background:var(--surface-3);position:relative}
.map-ph{position:absolute;inset:0;display:grid;place-items:center;text-align:center;
  padding:24px;color:var(--ink-3);font-size:13px;line-height:1.8}
.legend{display:flex;gap:12px;flex-wrap:wrap;padding:9px 14px;font-size:11.5px;
  color:var(--ink-2);border-top:1px solid var(--line);background:var(--surface-2)}
.legend i{display:inline-block;width:9px;height:9px;border-radius:50%;
  margin-right:5px;vertical-align:-1px}
.lg-ok{background:var(--brand)} .lg-warn{background:var(--signal)}
.lg-crit{background:var(--crit)} .lg-hold{background:var(--hold)}
.lg-veh{background:var(--ok);border-radius:3px!important}
/* 客户地图专用：正常=橙、临近缺货=琥珀黄。
   lg-ok/lg-warn 在配送方案页另有含义，不能共用 */
.lg-cok{background:var(--signal)} .lg-cwarn{background:#F5B301}
.lg-sleep{background:#454F5E}

/* ── 地图上的车 ── */
.veh-mk{display:flex;flex-direction:column;align-items:center;cursor:pointer}
.veh-mk.off{opacity:.5;filter:grayscale(1)}
/* 车图直接贴原图（带透明底），不再套色块。状态色落在车底那团光晕上：
   照片染不了色，但「在途 / 返程 / 待命」的语义要留住 */
.veh-ico{position:relative;line-height:0;
  filter:drop-shadow(0 2px 5px rgba(0,0,0,.35))}
.veh-ico img{display:block;width:52px;height:auto}
/* 车轮位置那道弧光，颜色跟状态走 */
.veh-ico::after{content:'';position:absolute;left:12%;right:12%;bottom:-3px;height:7px;
  border-radius:50%;background:var(--vc,#142D59);opacity:.55;filter:blur(2.5px)}

/* 本厂：白底卡片衬公司徽标，在一堆彩色圆点里一眼认出来。
   徽标原图自带白底，padding 给小一点免得四周留白太宽 */
.depot-mk{background:#fff;border-radius:10px;padding:2px;line-height:0;
  border:1px solid rgba(20,45,89,.18);box-shadow:0 3px 10px rgba(0,0,0,.28);
  cursor:default}
.depot-mk img{display:block;border-radius:8px}
/* 在跑的车底下那团光晕一呼一吸，静止的不动——扫一眼就知道哪辆在路上。
   动画作用在光晕上而不是整张图：图是照片，套 box-shadow 会框出一个方角 */
.veh-mk:not(.off) .veh-ico::after{animation:eo-veh 2.4s infinite}
@keyframes eo-veh{0%,100%{opacity:.55;transform:scaleX(1)}
  50%{opacity:.25;transform:scaleX(1.25)}}
.veh-tag{margin-top:4px;color:#fff;font-size:10.5px;
  line-height:1;padding:3px 6px;border-radius:4px;white-space:nowrap;
  font-weight:600;letter-spacing:.2px;box-shadow:0 1px 4px rgba(0,0,0,.28)}
.veh-tag b{color:var(--signal);margin-left:4px}

/* ── 点小车弹出来的窗：车上剩什么、还有谁没送到 ── */
.veh-pop{width:272px;background:var(--surface);border-radius:9px;overflow:hidden;
  box-shadow:0 10px 32px rgba(15,23,42,.26);font-size:12px}
.veh-pop-h{display:flex;align-items:center;gap:7px;padding:8px 10px;color:#fff}
.veh-pop-h b{font-size:13px;letter-spacing:.3px}
.veh-pop-h span{font-size:10.5px;opacity:.9}
.veh-pop-h i{margin-left:auto;cursor:pointer;font-style:normal;font-size:16px;
  line-height:1;opacity:.85;padding:0 2px}
.veh-pop-h i:hover{opacity:1}
.veh-pop-b{max-height:340px;overflow-y:auto;padding:9px 10px 10px}
.veh-pop-sum{display:flex;flex-wrap:wrap;gap:4px 12px;padding-bottom:8px;
  border-bottom:1px solid var(--line);color:var(--ink-2);font-size:11.5px}
.veh-pop-sum b{color:var(--ink);font-size:13px;margin:0 1px}
.veh-pop-st{margin:9px 0 5px;font-size:10.5px;color:var(--ink-3);
  letter-spacing:.5px;font-weight:600}
.veh-pop-row{display:flex;align-items:baseline;gap:6px;padding:3px 0;line-height:1.5}
.veh-pop-row span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.veh-pop-row b{color:var(--brand);font-size:12px;white-space:nowrap}
.veh-pop-row em{font-style:normal;font-size:10.5px;color:var(--ink-3);white-space:nowrap}
.veh-pop-row.done span,.veh-pop-row.done b{color:var(--ink-3);font-weight:400}
.veh-pop-empty{padding:6px 0;color:var(--ink-3);font-size:11.5px}
.veh-pop-ft{margin-top:9px;padding-top:7px;border-top:1px solid var(--line);
  font-size:10.5px;color:var(--ink-3)}

/* ── 右侧车辆卡片 ── */
.veh-row{padding:8px 9px;border:1px solid var(--line);border-radius:7px;
  margin-bottom:7px;cursor:pointer;background:var(--surface)}
.veh-row:hover{border-color:var(--brand)}
.veh-row.on{border-color:var(--brand);box-shadow:0 0 0 2px rgba(20,45,89,.12)}
.veh-row-h{display:flex;align-items:center;gap:6px;font-size:12.5px}
.veh-row-h i{width:8px;height:8px;border-radius:2px;flex:0 0 auto}
.veh-bar{height:6px;border-radius:3px;background:var(--surface-2);overflow:hidden;
  margin:7px 0 5px}
.veh-bar span{display:block;height:100%;border-radius:3px;transition:width .3s}
.veh-nums{display:flex;flex-wrap:wrap;gap:4px 10px;font-size:11px;color:var(--ink-2)}
.veh-nums b{color:var(--ink);font-variant-numeric:tabular-nums}
.veh-next{font-size:11px;color:var(--ink-2);margin-top:5px}
.veh-next b{color:var(--ink)}
/* 已缺货客户的脉冲：最该被看见的点，聚合时也要保留标记 */
@keyframes eo-pulse{0%{box-shadow:0 0 0 0 rgba(226,59,59,.55)}
  70%{box-shadow:0 0 0 11px rgba(226,59,59,0)}
  100%{box-shadow:0 0 0 0 rgba(226,59,59,0)}}
.pt-crit{animation:eo-pulse 1.9s infinite}

/* 客户卡片：地图点开后的详情（14.4.5）*/
.cust-card{width:330px;max-width:92vw}
.cust-card .cc-h{padding:11px 13px;border-bottom:1px solid var(--line)}
.cust-card .cc-h b{font-size:13.5px}
.cust-card .cc-b{padding:11px 13px;max-height:56vh;overflow:auto}
/* 近12个月用量趋势，纯 CSS 柱子，不引图表库 */
.spark{display:flex;align-items:flex-end;gap:3px;height:44px;margin:8px 0 4px}
.spark i{flex:1;background:var(--accent-tint);border-top:2px solid var(--brand);
  border-radius:2px 2px 0 0;min-height:2px}
.spark i.hi{background:var(--signal-tint);border-top-color:var(--signal)}
.spark-x{display:flex;justify-content:space-between;font-size:10px;color:var(--ink-3)}

/* ── 左主右辅两栏 ──
   左边一张铺满高度的大卡（地图），右边一条独立滚动的边栏。
   要点是右栏的底边和左边那张卡对齐：右栏内容再长也只在自己里面滚，
   不会把页面撑长，也不会比地图矮一截、下面露出一段空地。
   配送方案页与全国客户地图页共用这一套数值，两页来回切版式不跳。 */
.cols{display:flex;align-items:stretch;margin-top:25px;min-height:520px}
.cols>.col-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column}
/* 卡片本身也得是 flex 容器，否则里面的 map-wrap 拿 flex:1 要不到高度，
   地图会塌成一条缝 */
.cols>.col-main>.card{display:flex;flex-direction:column;min-height:0;height:100%}
.cols>.col-main .card-h,.cols>.col-main .legend{flex:0 0 auto}
.cols>.col-main .legend{padding:6px 14px}
.cols>.col-main .map-wrap{flex:1 1 auto;min-height:0}
.cols>.col-main .map-box{height:100%;border-radius:0}
.cols>.col-side{flex:0 0 auto;width:345px;margin-left:18px;
  display:flex;flex-direction:column;gap:18px;
  overflow-y:auto;overflow-x:hidden}
/* 边栏里的卡片一律不许被压缩：内容一长就会把上面的卡挤成一条线，
   那张卡上的按钮就点不到了。超出的部分交给边栏自己滚 */
.cols>.col-side>*{flex:0 0 auto}
/* 边栏用 gap 控制间距，全局那条 .card+.card{margin-top:12px} 会再叠一层，
   卡与卡之间就变成 30px 了 */
.cols>.col-side>.card+.card{margin-top:0}
@media(max-width:1100px){
  .cols{flex-direction:column;height:auto}
  .cols>.col-side{width:auto;margin-left:0;margin-top:18px;overflow:visible}
  .cols>.col-main>.card{height:auto}
  .cols>.col-main .map-box{height:60vh}
}

/* 标注模式：整块地图套一圈橙框、光标变十字、顶上压一条提示。
   这是个有进有出的「模式」，不能只靠卡片标题上改行小字——
   人眼睛盯着地图，那行字根本不进视线 */
.map-wrap.picking{box-shadow:inset 0 0 0 3px var(--signal)}
/* 高德在容器里自己铺了好几层 DOM，各自带 cursor，
   只写在外层会被它们盖掉，所以要点名压过去 */
.map-wrap.picking .map-box,
.map-wrap.picking .amap-maps,
.map-wrap.picking .amap-drags,
.map-wrap.picking .amap-layers,
.map-wrap.picking .map-box canvas{cursor:crosshair !important}
.pick-bar{position:absolute;left:0;right:0;top:0;z-index:30;
  background:var(--signal);color:#fff;padding:7px 12px;font-size:12.5px;
  display:flex;align-items:center;gap:9px}
.pick-bar b{font-weight:650}
.pick-bar .btn{height:24px;padding:0 10px;font-size:11.5px;
  background:rgba(255,255,255,.16);border-color:rgba(255,255,255,.45);color:#fff}
.pick-bar .btn:hover{background:rgba(255,255,255,.28);border-color:#fff}
/* 提示条压在工具条上面，搜索框和全屏按钮往下让一让 */
.map-wrap.picking .map-tools{top:46px}

/* 地图工具条上的区域下拉。跟搜索框、全屏按钮同高，
   并排一行才不会高低不齐 */
.map-tools select{width:auto;min-width:104px;height:30px;padding:0 8px;
  font-size:12px;background:var(--surface);border:1px solid var(--line-2);
  box-shadow:0 1px 4px rgba(20,45,89,.12)}

/* ── 地图：全屏与地点搜索 ── */
/* 全屏用 CSS 覆盖而非 Fullscreen API：飞书 WebView 里原生全屏常被容器拦掉 */
.map-wrap{position:relative}
/* 同上：权重要压得住外面那层的 margin，否则全屏会被推下来漏边 */
.map-wrap.map-full{position:fixed;inset:0;z-index:900;background:var(--surface);
  width:100vw;padding:0;margin:0 !important;border-radius:0}
.map-full .map-box{height:100vh !important;border-radius:0;border:none}

/* 工具条浮在地图左上角。右上角是高德自带的缩放控件，别抢位置 */
.map-tools{position:absolute;top:10px;left:10px;z-index:60;display:flex;gap:8px;
  align-items:center}
.map-tools .btn{background:var(--surface);box-shadow:0 2px 8px rgba(20,45,89,.16)}

.map-search{position:relative}
.map-search input{width:230px;height:29px;padding:4px 11px;border-radius:99px;
  font-size:12px;background:var(--surface);border:1px solid var(--line-2);
  box-shadow:0 2px 8px rgba(20,45,89,.16)}
@media(max-width:820px){.map-search input{width:150px}}
/* 建议列表要压在地图之上，否则会被高德画布盖住 */
.map-sug{position:absolute;top:34px;left:0;width:320px;max-width:80vw;z-index:130;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-s);
  box-shadow:0 10px 30px rgba(20,45,89,.16);overflow:hidden;max-height:300px;
  overflow-y:auto}
.map-sug-i{padding:8px 11px;cursor:pointer;border-bottom:1px solid var(--line)}
.map-sug-i:last-child{border-bottom:none}
.map-sug-i:hover{background:var(--accent-tint)}
.map-sug-i b{display:block;font-size:12.5px;font-weight:600}
.map-sug-i span{display:block;font-size:11px;color:var(--ink-3);margin-top:2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ── 配送方案页 ── */
/* 地图铺满左侧、右栏贴边，中间一条可拖的分隔线。
   用 flex 不用 grid：拖动时只需改右栏的 flex-basis，
   grid 得改整条 template，写起来绕。 */
/* 标题行和卡片之间留够气口。这一页顶部控件多，贴太近会显得挤。
   这里的 margin 会和 .phead 的 margin-bottom 折叠、取大的那个，
   所以要写成最终想要的间距值本身，不是差值 */
.plan-wrap{display:flex;align-items:stretch;margin-top:25px;min-height:520px}
.plan-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column}
/* 卡片自己也得是 flex 容器，否则里面的 map-wrap 拿 flex:1 要不到高度，
   地图会塌成一条 2px 的缝 */
.plan-main>.card{display:flex;flex-direction:column;min-height:0}
.plan-main .card-h,.plan-main .legend{flex:0 0 auto}
.plan-main .legend{padding:6px 14px}
.plan-main .map-wrap{flex:1 1 auto;min-height:0}
.plan-main .map-box{height:100%;border-radius:0}

/* 分隔线：平时是条淡灰细线，鼠标移上去变藏青加粗，拖动中保持高亮。
   命中区 18px，跟两栏之间的间距同一个值；线本身只有 2px——太细了拖不住 */
.plan-split{flex:0 0 18px;cursor:col-resize;display:flex;align-items:center;
  justify-content:center;position:relative;touch-action:none}
.plan-split::before{content:'';width:2px;height:100%;background:var(--line);
  border-radius:2px;transition:background .12s,width .12s}
.plan-split:hover::before,.plan-split.on::before{background:var(--brand);width:3px}
/* 中间加三个点，让人一眼看出这条线是能拖的 */
.plan-split::after{content:'';position:absolute;width:4px;height:26px;
  background:var(--line-2);border-radius:3px;opacity:0;transition:opacity .12s}
.plan-split:hover::after,.plan-split.on::after{opacity:1;background:var(--brand)}

/* 右栏跟左边地图卡一样高、底边齐平：自己不滚，高度由两个子块分。
   客户列表是主角，吃掉剩余的全部高度；下面的方案结果按内容占位，
   没出方案时就是一张小提示卡，别让它占着大片空白把列表挤成几行。
   出了方案内容变长，最多占到六成，再多它自己滚 */
.plan-side{flex:0 0 auto;width:var(--plan-side,316px);min-width:280px;
  display:flex;flex-direction:column;gap:18px;min-height:0;overflow:hidden}
.plan-side>.card{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}
.plan-side>.card>.card-h,.plan-side>.card>.pk-search{flex:0 0 auto}
/* 出了方案之后 #pRight 里塞进方案卡加一长串行程明细，
   它自己滚，不去挤上面那张选客户卡——出完方案改必带客户重算是最常做的一步 */
/* 不许收缩（flex-shrink:0）：设成可收缩的话，没方案时这张提示卡
   会被压成一条 9px 的缝。最多占六成，超出自己滚 */
.plan-side>#pRight{flex:0 0 auto;min-height:0;max-height:60%;
  overflow-y:auto;overflow-x:hidden}
/* 拖动过程中禁掉子元素的鼠标事件，否则划过按钮会卡住不跟手 */
.plan-wrap.dragging *{pointer-events:none;user-select:none}
.plan-wrap.dragging .plan-split{pointer-events:auto}

@media(max-width:1100px){
  /* 窄屏两栏叠成上下，就没有「底边齐平」这回事了：
     右栏放开高度限制，跟着页面一起滚，否则列表被压成一条缝 */
  .plan-wrap{flex-direction:column;height:auto}
  .plan-split{display:none}
  .plan-side{width:auto !important;overflow:visible}
  .plan-side>.card{max-height:none}
  .plan-side>.card,.plan-side>#pRight{flex:0 0 auto;overflow:visible}
  .pk-scroll{max-height:46vh}
  .plan-main .map-box{height:60vh}
}
/* 方案卡片挤在窄栏里，横排会被压扁，改成竖排一行一张 */
.plan-wrap .plan-cards{grid-template-columns:1fr}
.plan-wrap .plan-card{padding:9px 11px}
.plan-wrap .plan-card.on{padding:8px 10px}
.plan-wrap .plan-card .pv{font-size:17px}
/* 客户勾选行：勾选框、名字、瓶数、期望、最晚。
   右栏收窄后五样一行摆不开，「最晚」会掉到第二行——这是预期内的，
   所以表头用了跟数据行一模一样的列宽和换行规则：
   表头的「最晚」跟着掉下去，正好落在那个输入框上面，标题和数字始终对得上。
   两边任何一个列宽改了，另一边必须同步改 */
.pk-row,.pk-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.pk-row{padding:8px 10px;row-gap:8px;border-bottom:1px solid var(--line);font-size:12.5px}
.pk-row:hover{background:var(--surface-2)}
.pk-row.on{background:var(--accent-tint)}
.pk-row input[type=checkbox]{width:16px;height:16px;flex:none;margin:0}
.pk-row .nm{flex:1 1 80px;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
/* 三个数字框统一 34px：一车装不到四位数的瓶（8t 车按 40L 瓶算也就九十来只），
   三位数够用；期望/最晚本来就是一到两位的天数。
   原来 63/53 是照着表头文字宽度给的，白占了三十多像素——
   收窄之后五列正好能挤进一行，行高从 79px 降到 45px，
   一屏能看到的客户数差不多翻倍，客户名反而还宽了 */
/* 数字框：白底圆角方框、数字居中。字保持小号——
   这一栏是拿来扫的，不是拿来读的，字大了一屏看不到几家 */
.pk-row .qi,.pk-row .di{width:32px;height:27px;padding:0 2px;font-size:12.5px;
  text-align:center;font-family:var(--mono);border-radius:8px}
.pk-row .tag{font-size:10px;padding:0 5px;border-radius:99px;flex:none}
/* ── 多选下拉（自动组车的省份圈定）── */
.msel{position:relative;display:inline-block}
.msel-menu{position:absolute;top:calc(100% + 4px);right:0;z-index:60;
  min-width:186px;max-height:320px;overflow:auto;background:var(--surface);
  border:1px solid var(--line-2);border-radius:var(--r-s);
  box-shadow:0 10px 28px rgba(20,45,89,.16);padding:4px 0}
.msel-i label{display:flex;align-items:center;gap:7px;padding:6px 11px;
  font-size:12.5px;cursor:pointer;white-space:nowrap}
.msel-i label:hover{background:var(--accent-tint)}
.msel-i input{width:14px;height:14px;flex:none;margin:0}
.msel-i .n{margin-left:auto;color:var(--ink-3);font-size:11px;font-family:var(--mono)}
.msel-i.all{border-bottom:1px solid var(--line);margin-bottom:3px;padding-bottom:2px}

/* 头行统计胶囊；搜索框整行、深描边圆角 */
#pSum{font-size:12px;padding:2px 11px;margin-left:9px}
.pk-search{padding:7px 10px 8px}
.pk-search input{width:100%;height:34px;padding:0 12px;font-size:12.5px;
  border:1.5px solid var(--accent);border-radius:9px}

/* 候选列表自己滚，方案结果别被 200 家客户顶出屏幕；
   表头 sticky 在滚动容器内，滚到哪儿标题都压着数字 */
/* 列表吃掉选客户卡里除头部、搜索框之外的全部高度，自己滚 */
.pk-scroll{flex:1 1 auto;min-height:0;overflow:auto;overscroll-behavior:contain}
.pk-scroll .pk-head{position:sticky;top:0;z-index:3;background:var(--surface)}
.pk-head{padding:7px 10px;row-gap:3px;font-size:11px;color:var(--ink-3);
  border-bottom:1px solid var(--line);background:var(--surface)}
/* 表头里跟数据行对位的三个格子，宽度必须跟上面的 .qi/.di 一致 */
.pk-head .h-ck{width:16px;flex:none}
.pk-head .h-nm{flex:1 1 80px;min-width:0}
.pk-head .h-q{width:32px;text-align:center}
/* 去掉数字框的原生上下箭头：一来它会在右边占掉一截，数字歪掉跟表头对不上；
   二来这几个框挨得近，鼠标一滑就点到箭头把瓶数改了 */
.pk-row .qi::-webkit-outer-spin-button,.pk-row .qi::-webkit-inner-spin-button,
.pk-row .di::-webkit-outer-spin-button,.pk-row .di::-webkit-inner-spin-button{
  -webkit-appearance:none;margin:0}
.pk-row .qi,.pk-row .di{-moz-appearance:textfield;appearance:textfield}
.pk-head .h-d{width:32px;text-align:center}

/* 方案卡片：并排比较，选中的高亮 */
.plan-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));
  gap:10px;margin-bottom:12px}
.plan-card{border:1px solid var(--line);border-radius:var(--r);padding:11px 12px;
  cursor:pointer;background:var(--surface);transition:border-color .15s}
.plan-card:hover{border-color:var(--line-2)}
.plan-card.on{border-color:var(--brand);border-width:2px;padding:10px 11px;
  box-shadow:0 3px 12px rgba(20,45,89,.13)}
.plan-card .pt{font-size:12.5px;font-weight:650;margin-bottom:6px}
.plan-card .pv{font-family:var(--mono);font-size:20px;font-weight:600;
  letter-spacing:-.02em}
.plan-card .pu{font-size:11px;color:var(--ink-3);margin-top:1px}
.plan-card .pl{display:flex;gap:10px;margin-top:8px;font-size:11px;color:var(--ink-2);
  flex-wrap:wrap}
.plan-card .best{background:var(--ok);color:#fff;font-size:10px;padding:1px 6px;
  border-radius:99px;margin-left:5px}

/* 行程表：按天分组 */
.leg-day{font-size:11px;font-weight:650;color:var(--brand);background:var(--accent-tint);
  padding:4px 10px;border-radius:var(--r-s);margin:10px 0 5px;display:inline-block}
.leg{display:flex;align-items:center;gap:9px;padding:6px 10px;font-size:12.5px;
  border-bottom:1px solid var(--line)}
.leg .sq{width:20px;height:20px;border-radius:50%;background:var(--brand);color:#fff;
  font-size:11px;display:grid;place-items:center;flex:none;font-family:var(--mono)}
.leg .tm{font-family:var(--mono);font-size:11.5px;color:var(--ink-2);width:44px;flex:none}
.leg .nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.leg .kg{font-family:var(--mono);font-size:11.5px;color:var(--ink-2)}

/* 协商清单：这是拿去打电话的 */
.neg{border:1px solid var(--signal);border-left-width:3px;border-radius:var(--r-s);
  background:var(--signal-tint);padding:11px 13px;margin-top:12px}
.neg-i{padding:7px 0;border-bottom:1px dashed rgba(232,118,15,.3);font-size:12.5px}
.neg-i:last-child{border-bottom:none}
.neg-i b{font-weight:650}
.neg-i .why{color:var(--ink-2);font-size:11.5px;margin-top:2px;line-height:1.6}

/* 路线总距离：压在地图左上角。切方案时这个数最先要看，
   放在卡片外面还得来回挪视线 */
.route-stat{position:absolute;left:12px;top:12px;z-index:60;
  background:rgba(255,255,255,.94);border:1px solid var(--line);
  border-radius:var(--r);padding:9px 14px;box-shadow:0 3px 14px rgba(20,45,89,.18)}
.route-stat .rs-main{font-family:var(--mono);font-size:26px;font-weight:600;
  color:var(--brand);line-height:1;letter-spacing:-.02em}
.route-stat .rs-u{font-size:13px;font-weight:400;color:var(--ink-2);margin-left:3px}
.route-stat .rs-sub{font-size:11.5px;color:var(--ink-2);margin-top:4px}

/* 配送方案页全屏：地图和右栏一起铺满，方案卡片仍然看得见。
   只全屏地图的话，全屏后就没法对着路线看方案了。
   margin 必须 !important：「.page.fill>.plan-wrap{margin-top:21px}」是
   三个类（page+fill+plan-wrap），权重压过这里的两个类，
   fixed 之后照样把整块往下推 21px，顶上就漏出后面的页面 */
.plan-wrap.plan-full{position:fixed;inset:0;z-index:900;background:var(--paper);
  width:100vw;height:100vh !important;padding:0;margin:0 !important}
.plan-full .card{border-radius:0;border-left:none;border-top:none}
.plan-full .plan-side{padding:0 10px 10px 0}

/* ── 导航栏品牌区 ── */
/* 覆盖 bok-erp 里「整张品牌图铺满」的写法：这边是小图标 + 两行文字，
   图标自带深色底，加圆角让它跟导航栏融得自然些 */
.rail .brand{display:flex;align-items:center;gap:11px;
  padding:16px 14px 15px;border-bottom:1px solid rgba(255,255,255,.09);
  line-height:normal}
.rail .brand img{width:44px;height:44px;border-radius:9px;flex:none;display:block}
.rail .brand .bt{min-width:0}
.rail .brand b{display:block;font-size:16px;color:#fff;font-weight:650;
  letter-spacing:.01em;line-height:1.25;white-space:nowrap}
.rail .brand span{display:block;font-size:11px;color:#8FA3C8;margin-top:2px;
  letter-spacing:.05em;white-space:nowrap;padding-left:2px}
/* 登录页品牌：白底卡片上，文字要用深色 */
.login-brand{display:flex;align-items:center;gap:10px;margin-bottom:16px}
.login-brand img{width:40px;height:40px;border-radius:8px;flex:none}
.login-brand b{display:block;font-size:15px;color:var(--brand);font-weight:650;line-height:1.25}
.login-brand span{display:block;font-size:10.5px;color:var(--ink-3);letter-spacing:.05em}

/* 数值列表头要跟数字一起右对齐。
   继承来的 table.dt th 里写死了 text-align:left，权重(0,1,1)压过 .r 的(0,1,0)，
   结果表头贴左、数字贴右，看着错位。这里补一条权重更高的规则。 */
table.dt th.r{text-align:right}
table.dt th.c{text-align:center}
/* 单元格里的数字输入框跟着右对齐，和纯数字列排成一条线 */
table.dt td.r .tin{display:inline-block;float:none}

/* 按进价一键推算那条工具带（系统参数 → 产品定价） */
.derive-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  margin:10px 12px 0;padding:9px 12px;background:var(--accent-tint);
  border:1px solid var(--accent-line);border-radius:var(--r-s);font-size:12.5px}
.derive-bar label{display:inline-flex;align-items:center;gap:6px;color:var(--ink-2)}
.derive-bar input[type=number]{height:26px;padding:0 7px;font-size:12.5px;
  font-family:var(--mono);text-align:right}
.derive-bar .btn{height:26px;padding:0 11px;font-size:12px;
  display:inline-flex;align-items:center}
.derive-bar .sub-td{margin-left:auto}

/* 危险动作（删除这类不可逆的）：平时是低调的描边，鼠标移上去才变红。
   不做成常驻红底——一排按钮里最扎眼的应该是「通过」，不是「删除」 */
.btn.danger{color:var(--ink-2)}
.btn.danger:hover{color:var(--crit);border-color:var(--crit);background:var(--crit-tint)}

/* 行程表里的停留行标黄：一眼看出时间都花在哪儿了 */
.dt tr.tp-stay > td{background:#FFF8EE}

/* ── 选定运输公司：一行一家，左边公司右边钱 ──
   原先塞的是内联样式，公司名被挤成竖排、每公斤那行也断了。
   要点：右侧金额固定不压缩（flex:0 0 auto + nowrap），
   左侧可伸缩但要 min-width:0，否则长公司名会把右边顶出去 */
.fq-pick{display:flex;align-items:center;gap:12px;padding:11px 13px;
  border:1px solid var(--line);border-radius:8px;margin-bottom:8px;
  cursor:pointer;background:var(--surface);transition:border-color .15s}
.fq-pick:hover{border-color:var(--brand)}
.fq-pick:has(input:checked){border-color:var(--brand);
  box-shadow:0 0 0 2px rgba(20,45,89,.1);background:var(--surface-2)}
.fq-pick input{flex:0 0 auto;margin:0;width:16px;height:16px;cursor:pointer}
.fq-who{flex:1 1 auto;min-width:0;display:flex;flex-wrap:wrap;
  align-items:center;gap:4px 7px;line-height:1.45}
.fq-who b{font-size:13.5px;white-space:nowrap}
.fq-who .pill{font-size:10px;font-style:normal;padding:1px 6px;flex:0 0 auto}
.fq-who em{flex:1 0 100%;font-style:normal;font-size:11.5px;color:var(--ink-3)}
.fq-money{flex:0 0 auto;text-align:right;white-space:nowrap;line-height:1.35}
.fq-money b{font-size:17px;letter-spacing:-.2px}
.fq-money .fq-unit{font-size:11.5px;color:var(--ink-2)}
.fq-money em{display:block;font-style:normal;font-size:11px;color:var(--ink-3)}

/* ══════════════ 订单列表 ══════════════
   原来是十列的表格，客户名被挤成两行、单价和运费叠在一格里，看着乱。
   改成一单一条，跟配送方案的车辆卡、报价选择是同一套语言。
   压成两行：上行「谁的什么单、走到哪、多少钱」，下行「细节」和操作按钮。
   一屏能扫完更多单子，比每张单排得开更要紧。 */
.ord-list{display:flex;flex-direction:column;gap:6px}
.ord{display:grid;gap:2px 14px;padding:8px 12px;background:var(--surface);
  border:1px solid var(--line);border-radius:7px;
  grid-template-columns:minmax(0,1fr) auto;
  grid-template-areas:"main money" "meta act";
  transition:border-color .15s,box-shadow .15s}
.ord:hover{border-color:var(--brand);box-shadow:0 2px 8px rgba(15,23,42,.06)}
.ord.rej{border-left:3px solid var(--crit)}

/* 上行：单号 · 客户 · 进度，一条线上排开 */
.ord-main{grid-area:main;min-width:0;display:flex;align-items:center;
  flex-wrap:wrap;gap:2px 10px;line-height:1.35}
.ord-no{font-family:var(--mono);font-size:11.5px;color:var(--ink-2);
  cursor:pointer;letter-spacing:-.2px;flex:0 0 auto}
.ord-no:hover{color:var(--brand);text-decoration:underline}
.ord-cust{font-size:13.5px;font-weight:650;color:var(--ink);cursor:pointer;
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ord-cust:hover{color:var(--brand)}
.ord-step{display:inline-flex;align-items:center;gap:6px;flex:0 0 auto}
.ord-step em{font-style:normal;font-size:10.5px;color:var(--ink-3)}

/* 金额和款项状态同一行，不再各占一行 */
.ord-money{grid-area:money;text-align:right;white-space:nowrap;
  display:flex;align-items:baseline;justify-content:flex-end;gap:3px}
.ord-money b{font-family:var(--mono);font-variant-numeric:tabular-nums;
  font-size:16px;letter-spacing:-.3px}
.ord-money > span{font-size:11px;color:var(--ink-2)}
.ord-money .pill{font-size:9.5px;font-style:normal;padding:1px 6px;margin-left:5px;
  align-self:center}

/* 下行：细节小字 + 操作按钮 */
.ord-meta{grid-area:meta;display:flex;flex-wrap:wrap;gap:0 12px;
  font-size:11px;color:var(--ink-2);line-height:1.5;min-width:0}
.ord-meta .pill{font-size:9px;font-style:normal;padding:0 4px;margin-left:2px}
.ord-act{grid-area:act;display:flex;align-items:center;justify-content:flex-end;
  gap:5px;flex-wrap:wrap}
.ord-act .btn.sm{padding:3px 10px;font-size:11.5px}
.ord-act .osel{max-width:140px;height:24px;font-size:11.5px}

/* 窄屏（飞书手机端）：金额挪到客户名下面，按钮铺满一行好点 */
@media (max-width:640px){
  .ord{grid-template-columns:1fr;
    grid-template-areas:"main" "money" "meta" "act";gap:3px}
  .ord-money{justify-content:flex-start}
  .ord-act{justify-content:flex-start;margin-top:3px}
}

/* 台账里用负数记的退货月：柱子按绝对值画但标红，
   否则负高度会把柱子画没，看着像那个月压根没发货 */
.spark i.neg{background:var(--crit);opacity:.55}

/* ── 司机送货任务：一站一行 ── */
.dstop{display:flex;align-items:flex-start;gap:10px;padding:9px 10px;
  border:1px solid var(--line);border-radius:7px;margin-bottom:7px;
  background:var(--surface)}
.dstop.done{opacity:.62;background:var(--surface-2)}
.dstop-seq{flex:0 0 auto;width:22px;height:22px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--brand);color:#fff;font-size:11.5px;font-weight:650}
.dstop.done .dstop-seq{background:var(--ok)}
.dstop-main{flex:1 1 auto;min-width:0;line-height:1.5}
.dstop-main b{font-size:13px}
.dstop-qty{margin-left:8px;font-size:11.5px;color:var(--ink-2)}
.dstop-qty b{font-size:13.5px;color:var(--signal)}
.dstop-main em{display:block;font-style:normal;font-size:11px;color:var(--ink-3);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dstop-act{flex:0 0 auto;display:flex;gap:5px;flex-wrap:wrap;justify-content:flex-end}
.dstop-act .btn.sm{padding:3px 9px;font-size:11.5px}
@media (max-width:640px){
  .dstop{flex-wrap:wrap}
  .dstop-act{width:100%;justify-content:flex-start;margin-top:6px}
}

/* 候选客户行里的「什么气、什么瓶」：小一号灰字挂在企业名下面。
   这两项是按历史记录推的，不是客户确认过的，所以标记要克制——
   写得跟企业名一样重，人会当成定数 */
.pk-row .pk-spec{display:block;font-style:normal;font-size:10.5px;color:var(--ink-3);
  line-height:1.5;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:1px}
.pk-row .pk-multi{display:inline-block;margin-left:4px;padding:0 4px;border-radius:3px;
  background:var(--signal);color:#fff;font-size:9px;font-weight:700;vertical-align:1px}

/* 批量下单表里算不出来的那几行标红底，一眼看得出哪家卡住了 */
.dt tr.bad-row > td{background:#FFF1F1}

/* 只有一套方案时（手动选客户就是这种），卡片不做「选中」的强调——
   没得挑就别摆出一副让人挑的样子 */
.plan-card.only{cursor:default}
.plan-card.only:hover{border-color:var(--line)}

/* 批量单那一条：左边一道竖线跟单张的区分开 */
.ord.ord-batch{border-left:3px solid var(--brand)}
.ord.ord-batch .ord-cust{color:var(--brand)}

/* 自动配上的瓶型/瓶架，在标签后面小字标出依据。
   自动填的东西必须说清是按什么填的，不然人不知道该不该信 */
.fld label .mt{font-style:normal;font-size:10.5px;color:var(--ink-3);
  font-weight:400;margin-left:6px}
.fld label .mt.warn{color:var(--signal)}

/* 候选行里的瓶架列。比数字框宽一点——架子名再短也要放得下，
   而且它是下拉不是输入框，太窄点不中 */
.pk-head .h-f{width:74px;text-align:center}
.pk-row .fi{width:74px;flex:0 0 auto;font-size:11px;padding:2px 4px;
  text-align:center}
.pk-row .fi.none{display:inline-flex;align-items:center;justify-content:center;
  color:var(--ink-3);border:1px dashed var(--line-2);border-radius:4px;
  background:transparent;height:24px}

/* ── 送货任务：一车里同一张批量单的几家折成一组 ── */
/* 十家平铺开来占满一屏，要找某一家得一路划下去。
   批量单本来就是一件事，界面上也该是一条 */
.dgrp{border:1px solid var(--line);border-radius:8px;margin-bottom:7px;
  overflow:hidden}
.dgrp-h{display:flex;align-items:center;gap:8px;padding:8px 11px;
  background:var(--surface-2);cursor:pointer}
.dgrp-h b{font-family:var(--mono);font-size:11.5px;color:var(--ink-2)}
.dgrp-h span{flex:1;min-width:0;font-size:12px}
.dgrp-h i{font-style:normal;font-size:11.5px;color:var(--brand)}
.dgrp-b{padding:7px 7px 0}
.dgrp-b .dstop{margin-bottom:7px}
.dgrp.fold .dgrp-b{display:none}

/* 折叠行尾部的单号：等宽字体、淡一档，认单号的人找得到，不认的人不碍眼 */
.dgrp-h .dgrp-no{font-style:normal;color:var(--ink-3);font-family:var(--mono);
  font-size:11px}

/* ══════════════ 销售打卡 ══════════════ */
/* 筛选条：一行放下几个下拉和日期，窄屏自动折行 */
.vbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:12px;font-size:12px}
.vbar select,.vbar input{width:auto;padding:4px 8px;font-size:12px}
.vbar #vQ,.vbar #pQ{min-width:150px}

.vday{display:flex;align-items:baseline;gap:10px;margin:16px 2px 7px;font-size:12.5px}
.vday b{font-size:13.5px;font-weight:650}
.vday:first-of-type{margin-top:4px}

/* 一次拜访一张卡。缺项的左边一条红线，一眼扫得出哪几次不算数 */
.vcard{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:10px 13px;margin-bottom:8px}
.vcard.bad{border-left:3px solid var(--crit);padding-left:11px}
.vc-h{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.vc-h b{font-size:14px;font-weight:650}
.vc-h .muted{font-size:11.5px}
.vc-t{margin-left:auto;font-size:11.5px;color:var(--ink-3);font-variant-numeric:tabular-nums}
.vc-m{display:flex;flex-wrap:wrap;gap:3px 16px;font-size:12px;color:var(--ink-2);margin-top:5px}
.vc-p{font-size:12.5px;margin-top:6px;line-height:1.6}
.vc-p i{font-style:normal;font-size:10.5px;color:var(--ink-3);background:var(--surface-3);
  border-radius:4px;padding:0 5px;margin-right:6px}
.vc-l{font-size:11.5px;color:var(--ink-2);margin-top:6px;display:flex;flex-wrap:wrap;gap:4px 10px;
  align-items:baseline}
.vc-l .far{color:var(--crit);font-weight:600}
.vc-l .ok{color:var(--ok)}
.vc-ph{display:flex;gap:6px;margin-top:8px;flex-wrap:wrap}
.vc-ph img{width:74px;height:74px;object-fit:cover;border-radius:6px;cursor:zoom-in;
  background:var(--surface-3);border:1px solid var(--line)}
.vc-ph img.bad{opacity:.4}
.vc-miss{font-size:11.5px;color:var(--crit);margin-top:7px}

/* 打卡单：电脑上是普通弹窗，手机上从底部弹起占满屏——
   业务员站在客户门口单手填，居中的小弹窗点不准 */
@media (max-width:640px){
  .sheet-mask{padding:0;align-items:flex-end}
  .modal.sheet{width:100% !important;max-width:100%;min-width:0;max-height:94vh;
    border-radius:14px 14px 0 0;resize:none}
  .modal.sheet .modal-f{padding-bottom:calc(11px + env(safe-area-inset-bottom,0px))}
  .modal.sheet .modal-f::after{display:none}
  .modal.sheet .fgrid{grid-template-columns:1fr 1fr}
}
.modal.sheet{width:560px}

.vloc{background:var(--surface-3);border-radius:var(--r-s);padding:9px 11px;font-size:12.5px;
  margin-bottom:12px;line-height:1.6}
.vloc.on{background:var(--ok-tint);color:var(--ink)}
.vloc.bad{background:#FDF0F0;color:var(--crit)}
.vloc .link{margin-left:6px;font-size:12px}
.vloc .hint{color:var(--ink-3);margin-top:2px}

.vsug{margin-top:4px}
.vsug:empty{display:none}
.vs-t{font-size:10.5px;color:var(--ink-3);margin:6px 2px 3px;letter-spacing:.05em}
.vs-i{display:flex;align-items:baseline;gap:8px;padding:8px 10px;border:1px solid var(--line);
  border-radius:var(--r-s);margin-bottom:4px;cursor:pointer;background:var(--surface)}
.vs-i:hover{border-color:var(--brand)}
.vs-i b{font-size:13px;font-weight:600;flex:1;min-width:0}
.vs-i .muted{font-size:11.5px;white-space:nowrap}

.vph{display:flex;gap:8px;flex-wrap:wrap}
.vph:empty{display:none}
.vph-i{position:relative;width:78px;height:78px}
.vph-i img{width:100%;height:100%;object-fit:cover;border-radius:7px;border:1px solid var(--line)}
.vph-i .x{position:absolute;top:-6px;right:-6px;width:20px;height:20px;border-radius:50%;
  background:var(--ink);color:#fff;font-size:11px;display:grid;place-items:center;cursor:pointer}

/* 底栏左边念「还差什么」，右边是提交键 */
.vmiss{font-size:12px;color:var(--ink-2);margin-right:auto;align-self:center;line-height:1.5}
.vmiss b{color:var(--crit)}

/* 客户推进阶段：一个小色块，在列表里扫一眼就看得出谁到了哪一步 */
.stage{display:inline-block;font-size:11px;font-weight:600;color:var(--brand);
  background:var(--accent-tint,#EEF2FA);border:1px solid var(--accent-line,#D7E3FA);
  border-radius:20px;padding:0 9px;line-height:1.7;white-space:nowrap}

.rcard{margin-bottom:10px}
.r-sec{display:grid;grid-template-columns:76px 1fr;gap:10px;font-size:13px;line-height:1.7;
  padding:5px 0}
.r-sec + .r-sec{border-top:1px dashed var(--line)}
.r-sec > i{font-style:normal;font-size:11px;color:var(--ink-3);padding-top:2px}
.r-prog{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.r-prog b{font-weight:600}
.r-prog .muted{font-size:12px}
@media (max-width:640px){ .r-sec{grid-template-columns:1fr;gap:2px} }

.rp-row{display:grid;grid-template-columns:1.2fr 104px 1.6fr 22px;gap:6px;align-items:center;
  margin-bottom:6px}
.rp-row input,.rp-row select{padding:5px 8px;font-size:12.5px}
.rp-row .x{color:var(--ink-3);cursor:pointer;text-align:center}
.rp-row .x:hover{color:var(--crit)}
@media (max-width:640px){
  .rp-row{grid-template-columns:1fr 100px 22px}
  .rp-row .rp-t{grid-column:1 / 3}
}

/* 一家客户的来龙去脉：左边时间，右边这一次发生了什么 */
.tl-i{display:grid;grid-template-columns:86px 1fr;gap:10px;margin-bottom:6px}
.tl-d{font-size:11.5px;color:var(--ink-3);padding-top:11px;font-variant-numeric:tabular-nums}
.tl-p{background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r);
  padding:9px 12px;font-size:12.5px;line-height:1.7}
.tl-p > i{font-style:normal;font-size:10.5px;color:var(--ink-3);margin-right:6px}
@media (max-width:640px){ .tl-i{grid-template-columns:1fr;gap:2px} .tl-d{padding-top:0} }

tr.dim td{color:var(--ink-3)}

/* 看大图。点哪儿都关，手机上找不着关闭键的人最多 */
.lightbox{position:fixed;inset:0;z-index:2000;background:rgba(10,16,24,.88);display:flex;
  flex-direction:column;align-items:center;justify-content:center;gap:10px;padding:16px;
  cursor:zoom-out}
.lightbox img{max-width:100%;max-height:88vh;object-fit:contain;border-radius:6px}
.lightbox span{color:#fff;opacity:.6;font-size:12px}
