* { box-sizing: border-box; margin: 0; padding: 0; }
:root {
  --primary: #2563eb;
  --primary-dark: #1d4ed8;
  --bg: #f3f5f9;
  --card: #ffffff;
  --border: #e3e8f0;
  --text: #1e293b;
  --muted: #64748b;
  --danger: #dc2626;
  --success: #16a34a;
  --warning: #d97706;
}
body { font-family: "Microsoft YaHei", "PingFang SC", system-ui, sans-serif; background: var(--bg); color: var(--text); font-size: 14px; }
.hidden { display: none !important; }

/* ---------- 登录 ---------- */
.login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, #1e3a8a 0%, #2563eb 60%, #3b82f6 100%); }
.login-card { background: #fff; width: 380px; padding: 36px 32px; border-radius: 14px; box-shadow: 0 20px 50px rgba(0,0,0,.25); }
.login-card h1 { font-size: 22px; text-align: center; margin-bottom: 6px; }
.login-card .sub { text-align: center; color: var(--muted); font-size: 12px; margin-bottom: 22px; }
.tabs { display: flex; gap: 8px; margin-bottom: 18px; }
.tab { flex: 1; padding: 9px; border: 1px solid var(--border); background: #f8fafc; border-radius: 8px; cursor: pointer; font-size: 14px; }
.tab.active { background: var(--primary); color: #fff; border-color: var(--primary); }
/* 页签旁的 ⧉：把这个子栏目单独开成一个窗口（两个子栏目要对着看时用） */
.tabw { position: relative; display: flex; flex: 1; }
.tabw .tab { flex: 1; }
.tab-new { display: none; position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  width: 18px; height: 18px; line-height: 18px; text-align: center; border-radius: 4px;
  font-size: 12px; color: var(--muted); background: rgba(255,255,255,.75); cursor: pointer; }
.tabw:hover .tab-new { display: block; }
.tab-new:hover { color: var(--primary); background: #fff; }
/* 全站统一二级页导航条（2026-11-01 需求六-下）：单行 pill 条，置于搜索栏前、自适应宽。
 * 只有 ≥2 个子栏目时才由 renderSubNavBar 渲染；<2 档不渲染，避免孤条占空间。 */
.subnav-bar { display: flex; gap: 8px; margin: 4px 0 10px; flex-wrap: wrap; }
.subnav { padding: 6px 14px; border: 1px solid var(--border); background: #f8fafc; border-radius: 999px;
  cursor: pointer; font-size: 13px; color: var(--text); transition: background .15s, color .15s, border-color .15s; }
.subnav:hover { border-color: var(--primary); color: var(--primary); }
.subnav.active { background: var(--primary); color: #fff; border-color: var(--primary); }
label { display: block; margin: 12px 0 6px; color: var(--muted); font-size: 13px; }
input, select, textarea { width: 100%; padding: 9px 11px; border: 1px solid var(--border); border-radius: 8px; font-size: 14px; outline: none; background: #fff; }
input:focus, select:focus, textarea:focus { border-color: var(--primary); }
textarea { resize: vertical; min-height: 64px; }
.hint { margin-top: 14px; font-size: 12px; color: var(--muted); text-align: center; }
/* 搜索框后面那句「筛出 N / M 行」：跟着框走，不换行、不占高度，免得工具栏被顶歪 */
.kw-count { margin: 0 0 0 6px; font-size: 12px; color: var(--muted); white-space: nowrap; }

/* ---------- 外壳：左侧主栏目 + 右侧内容 ----------
 * 为什么改：原先主栏目是顶部一横排，屏幕越宽它越空、内容区还被 1280 卡住。
 * 现在竖排到左侧并支持收缩（只剩图标 64px），编辑单据时能多出近两百像素。
 * 深色侧栏是刻意的：与浅色内容区形成边界，扫一眼就知道哪边是导航。 */
#view-app { display: flex; height: 100vh; overflow: hidden; }
.app-body { flex: 1; min-width: 0; display: flex; flex-direction: column; overflow: auto; }

/* ---------- 侧栏（主栏目） ---------- */
.side {
  /* 宽度可以是"拖出来的"（--side-w，2026-10-28），没拖过就是 196px */
  flex: 0 0 var(--side-w, 196px); width: var(--side-w, 196px); background: #1e293b; color: #cbd5e1;
  display: flex; flex-direction: column; transition: flex-basis .16s ease, width .16s ease;
  position: relative;
}
/* 可拖的分隔条：贴在手栏右边缘，平时透明、鼠标上去才亮一条线——
 * 常显一条竖线会让深色侧栏看起来像"没闭合"，视觉上很毛躁。 */
.side-split {
  position: absolute; top: 0; right: -3px; bottom: 0; width: 6px; cursor: col-resize; z-index: 30;
  background: transparent;
}
.side-split:hover, body.side-dragging .side-split { background: rgba(37,99,235,.55); }
/* 拖动时禁掉选中与过渡：光标滑过文字会整片蓝，宽度动画还会让人眼看着跟手不一样 */
body.side-dragging { user-select: none; cursor: col-resize; }
body.side-dragging .side { transition: none; }
.side-head {
  display: flex; align-items: center; gap: 10px; padding: 12px;
  min-height: 54px; border-bottom: 1px solid rgba(255,255,255,.08);
}
.sh-logo {
  flex: 0 0 30px; width: 30px; height: 30px; border-radius: 8px; overflow: hidden;
  background: var(--primary); color: #fff; display: flex; align-items: center; justify-content: center;
}
.sh-logo img { width: 100%; height: 100%; object-fit: contain; background: #fff; }
.sh-name { color: #fff; font-weight: 700; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

#nav { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 8px; display: flex; flex-direction: column; gap: 3px; }
#nav::-webkit-scrollbar { width: 6px; }
#nav::-webkit-scrollbar-thumb { background: rgba(255,255,255,.18); border-radius: 3px; }
.nav-item {
  display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 8px;
  cursor: pointer; color: #cbd5e1; font-size: 14px; white-space: nowrap; user-select: none;
}
.nav-item:hover { background: rgba(255,255,255,.08); color: #fff; }
.nav-item.active { background: var(--primary); color: #fff; }
.nav-item .ni { flex: 0 0 18px; width: 18px; height: 18px; }
.nav-item .nv { overflow: hidden; text-overflow: ellipsis; }

/* ---------- 侧栏二级栏目（2026-10-28，学金蝶左侧导航） ----------
 * 主栏目下面缩进一层，用一根淡竖线串起来：看得出"这几个属于上面那个"，
 * 又不用给每个主栏目套一个方框（十几个框叠下来满屏都是边线）。 */
.nav-block { display: flex; flex-direction: column; }
.nav-sub { display: flex; flex-direction: column; gap: 1px; margin: 1px 0 3px 17px; padding-left: 9px; border-left: 1px solid rgba(255,255,255,.13); }
.nav-sub-item {
  padding: 6px 8px; border-radius: 6px; font-size: 13px; color: #94a3b8; cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; user-select: none;
}
.nav-sub-item:hover { background: rgba(255,255,255,.08); color: #fff; }
.nav-sub-item.active { background: rgba(37,99,235,.28); color: #fff; font-weight: 600; }
.nv-caret {
  /* 箭头放大到 25px（原 10px 太小看不清）；line-height:1 是必须的，
     否则 25px 的字号会把行高撑起来、把栏目标题挤出去。 */
  flex: 0 0 18px; width: 18px; text-align: center; font-size: 25px; line-height: 1;
  opacity: .45; transition: transform .14s ease; display: inline-block; border-radius: 4px;
}
.nv-caret:hover { opacity: 1; background: rgba(255,255,255,.12); }
.nv-caret.open { transform: rotate(90deg); opacity: .8; }
/* 收缩态只有图标：二级栏目整块隐藏（没地方放文字） */
#view-app.side-mini .nav-sub, #view-app.side-mini .nv-caret { display: none; }

.side-fold {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center; gap: 7px;
  margin: 8px; height: 36px; border: 0; border-radius: 8px; cursor: pointer;
  background: rgba(255,255,255,.06); color: #94a3b8; font-size: 13px;
}
.side-fold:hover { background: rgba(255,255,255,.13); color: #fff; }
/* 「使用手册」按钮：顶栏那个「?」去掉后，入口挪到侧栏底部（收缩后只剩图标） */
#side-help { margin-bottom: 0; }
.side-fold svg { transition: transform .16s ease; }

/* 收缩态：只剩图标，靠 title 提示。宽度从 196 → 64 */
#view-app.side-mini .side { flex-basis: 64px; width: 64px; }
/* 收缩态下分隔条没用了（拖动会立刻退出收缩），藏起来免得误触 */
#view-app.side-mini .side-split { display: none; }
#view-app.side-mini .side-head { justify-content: center; padding: 12px 0; }
#view-app.side-mini .sh-name { display: none; }
#view-app.side-mini .nav-item { justify-content: center; padding: 10px 0; }
#view-app.side-mini .nav-item .nv { display: none; }
#view-app.side-mini .side-fold .nf { display: none; }
#view-app.side-mini #side-arrow { transform: rotate(180deg); }

/* ---------- 第一栏 = 窗口页签 + 用户信息（顶栏已删除，2026-10-22） ----------
 * 原来单独一行 48px 只放「栏目名 + 用户名 + 退出」，一行高度白占。
 * 现在把登录信息并到页签条的右端，一栏两用：左边开着的窗口，右边是谁在用。 */
.workbar {
  flex: 0 0 auto; display: flex; align-items: stretch; gap: 10px;
  background: #fff; border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 50; padding-right: 14px;
}
.brand { font-weight: 700; font-size: 17px; color: var(--primary); white-space: nowrap; }
.user-box { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; padding-left: 10px; border-left: 1px solid var(--border); }
.ub-name { font-size: 13px; font-weight: 600; color: var(--text); max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.badge { background: #eef2ff; color: var(--primary); font-size: 12px; padding: 3px 10px; border-radius: 20px; }

/* ---------- 需要补货报警铃铛 ----------
 * 低于安全库存是"再不管就要断料"的事，不能藏在报表里等人去翻，
 * 所以在顶栏常驻一个铃铛：有数就晃一下提醒，点了直接到「需要补货」。 */
.bell-btn {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border: 1px solid var(--border); border-radius: 9px;
  background: var(--card); cursor: pointer; padding: 0; font-size: 16px; line-height: 1;
}
.bell-btn:hover { background: #f1f5f9; }
.bell-btn .bell-ico { display: block; transform-origin: 50% 2px; animation: bell-shake 2.4s ease-in-out infinite; }
.bell-badge {
  position: absolute; top: -6px; right: -6px; min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 9px; background: var(--danger); color: #fff;
  font-size: 11px; line-height: 17px; text-align: center; font-weight: 700;
  box-shadow: 0 0 0 2px var(--card);
}
.bell-badge::before { content: '!'; margin-right: 1px; }
@keyframes bell-shake {
  0%, 62%, 100% { transform: rotate(0); }
  66% { transform: rotate(13deg); }
  70% { transform: rotate(-11deg); }
  74% { transform: rotate(8deg); }
  78% { transform: rotate(-6deg); }
  82% { transform: rotate(0); }
}

/* ---------- 布局 ---------- */
/* 内容区不再限宽 1280：单据明细动辄十几列，宽屏上被卡在中间一条很浪费。
   现在跟着侧栏走满剩余宽度，左右各留 20px 呼吸。 */
/* 多窗口：main-host 是窗口的容器，里面每个 .tabpane 是一个窗口的内容。
   活动的那个 id 会被设成 main（那 25 处 $('#main') 照旧生效），其余隐藏。 */
main, .tabpane { max-width: none; margin: 0; padding: 16px 20px 40px; }
.tabpane { display: block; }
.tabpane.hidden { display: none; }
/* 子页面面包屑：只在停在子页面时出现（销售订单 › 合同管理），点前面那段回本栏目主页。
   它挂在窗口容器内部，所以永远嵌在主框里，不会盖住侧栏或页签条。 */
.subbar { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); margin: -4px 0 10px; }
.sb-link { color: var(--primary); text-decoration: none; }
.sb-link:hover { text-decoration: underline; }
.sb-sep { color: #cbd5e1; }
.sb-cur { color: var(--text); font-weight: 600; }
/* 窗口页签条：在 .workbar 里靠左，右侧留给用户信息；点一下切窗口，× 关掉 */
.worktabs {
  display: flex; gap: 6px; align-items: stretch; flex: 1 1 auto; min-width: 0;
  padding: 6px 0 0 14px; overflow-x: auto; overflow-y: hidden;
}
.wtab {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer; user-select: none;
  padding: 7px 10px 7px 14px; border: 1px solid var(--border); border-bottom: none;
  border-radius: 8px 8px 0 0; background: #f8fafc; color: var(--muted);
  font-size: 13px; white-space: nowrap; max-width: 240px;
}
.wtab:hover { background: #f1f5f9; color: var(--text); }
.wtab.active { background: var(--card); color: var(--primary); font-weight: 600; box-shadow: inset 0 2px 0 var(--primary); }
.wtab-t { overflow: hidden; text-overflow: ellipsis; }
.wtab-x { font-size: 15px; line-height: 1; padding: 0 2px; border-radius: 4px; color: var(--muted); }
.wtab-x:hover { background: #fee2e2; color: var(--danger); }
/* 统一筛选条：关键词 + 时间区间，对当前窗口的所有表格生效 */
.filterbar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; flex: 0 0 auto;
  background: var(--card); border-bottom: 1px solid var(--border); padding: 8px 14px;
  position: sticky; top: 40px; z-index: 39;   /* 钉在页签条下面（那一栏约 40px 高） */
}
.filterbar input[type=text] { flex: 1 1 260px; min-width: 180px; }
.filterbar input[type=date] { width: auto; }
.fb-lb { font-size: 12px; color: var(--muted); }
/* 通用商品选择浮层：输入编码/名称/型号即时过滤商品库，点一行带出整行 */
.gp-pop { position: fixed; z-index: 3000; max-height: 360px; overflow: auto;
  background: #fff; border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 12px 32px rgba(15,23,42,.18); padding: 4px; }
.gp-pop.hidden { display: none; }
.gp-row { padding: 6px 8px; border-radius: 7px; cursor: pointer; line-height: 1.35; }
.gp-row + .gp-row { border-top: 1px solid #f1f5f9; }
.gp-row:hover, .gp-row.on { background: #eff6ff; }
.gp-main { display: flex; align-items: baseline; gap: 6px; font-size: 13px; }
/* 名称过长时省略，别把编码和价格挤掉 */
.gp-main b { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gp-code { flex: none; font-size: 12px; color: var(--muted); font-family: ui-monospace, Consolas, monospace; }
.gp-sub { font-size: 12px; color: #475569; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gp-meta { flex: none; margin-left: auto; font-size: 11px; color: var(--muted); }
/* 型号 / 品牌 */
.gp-tags { margin-top: 1px; font-size: 11px; color: #64748b; }
.gp-sep { margin: 0 4px; color: #cbd5e1; }
/* 规格/参数：最多两行，超出省略，全文在 title 里 */
.gp-spec { margin-top: 1px; font-size: 12px; color: #334155; word-break: break-all;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.gp-spec-none { color: #94a3b8; }
.gp-tip { padding: 6px 8px 4px; font-size: 11px; color: var(--muted); border-top: 1px solid var(--border); margin-top: 2px; }
td .gp-in { min-width: 0; }
/* 全流程跟踪：一条横链，每站显示状态点 + 进度，整块可点 */
.flow-bar { display: flex; align-items: stretch; gap: 4px; margin: 12px 0 8px; flex-wrap: wrap; }
.flow-arrow { display: flex; align-items: center; color: #cbd5e1; font-size: 15px; }
.flow-step { flex: 1 1 132px; min-width: 118px; border: 1px solid var(--border); border-radius: 10px;
  padding: 8px 10px; background: #fff; cursor: pointer; position: relative; transition: .15s; }
.flow-step:hover { border-color: var(--primary); box-shadow: 0 4px 14px rgba(37,99,235,.12); }
.flow-step.todo { background: #f8fafc; color: #94a3b8; }
.flow-step.doing { border-color: #fcd34d; background: #fffbeb; }
.flow-step.done { border-color: #86efac; background: #f0fdf4; }
.fs-dot { width: 8px; height: 8px; border-radius: 50%; background: #cbd5e1; margin-bottom: 4px; }
.flow-step.doing .fs-dot { background: #f59e0b; }
.flow-step.done .fs-dot { background: #22c55e; }
.fs-t { font-size: 13px; font-weight: 600; }
.fs-tag { font-size: 12px; color: var(--muted); }
.fs-num { font-size: 12px; font-variant-numeric: tabular-nums; }
.page-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; flex-wrap: wrap; gap: 10px; }
.page-head h2 { font-size: 19px; }
/* 页头搬进筛选条之后（2026-10-30）：标题当分隔符，查询条件顺着排开，省掉一整行。
 * 标题右侧那条竖线是视觉分隔——不然「经营核算」会和后面的筛选框粘成一串。 */
.filterbar.has-head { align-items: center; }
.filterbar .page-head { flex: 0 0 auto; margin: 0; gap: 8px; flex-wrap: nowrap; }
.filterbar .page-head h2 {
  font-size: 14px; font-weight: 700; margin: 0; white-space: nowrap;
  padding-right: 10px; border-right: 1px solid var(--border);
}
.filterbar .page-head .toolbar { gap: 6px; flex-wrap: nowrap; }
.toolbar { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.toolbar input, .toolbar select { width: auto; }

.card { background: var(--card); border: 1px solid var(--border); border-radius: 12px; padding: 20px; margin-bottom: 18px; }
.card h3 { font-size: 15px; margin-bottom: 14px; color: var(--text); }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px 18px; }
.field label { margin-top: 0; }

/* ---------- 按钮 ---------- */
.btn { padding: 9px 16px; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; background: #e2e8f0; color: var(--text); }
.btn:hover { filter: brightness(.96); }
.btn.primary { background: var(--primary); color: #fff; }
.btn.primary:hover { background: var(--primary-dark); filter: none; }
.btn.success { background: var(--success); color: #fff; }
.btn.danger { background: var(--danger); color: #fff; }
.btn.warn { background: var(--warning); color: #fff; }
.btn.ghost { background: transparent; border: 1px solid var(--border); }
.btn.sm { padding: 4px 10px; font-size: 12px; border-radius: 6px; }
/* 单据明细表里「删除本行」的 × 按钮：放大到约 2 倍，方便点（生产任务/领料/订单等明细表通用） */
.btn.danger.sm.row-x { width: 32px; height: 32px; padding: 0; font-size: 18px; line-height: 1; display: inline-flex; align-items: center; justify-content: center; }
.btn.block { width: 100%; margin-top: 18px; }
.btn:disabled { opacity: .5; cursor: not-allowed; }

/* ---------- 表格 ---------- */
.table-wrap { overflow-x: auto; background: var(--card); border: 1px solid var(--border); border-radius: 12px; }
/* 宽表把「操作」列钉在右边：列多到要横向滚动时，最常用的按钮不该被滚出屏幕。
   表格行没有 hover 底色，单元格用卡片底色就能和表体无缝衔接。
   只在明确需要的表上加 .tbl-pin，不全局套——统计表最后一列是数字，钉住反而怪。 */
.tbl-pin th:last-child, .tbl-pin td:last-child {
  position: sticky; right: 0; z-index: 1; background: var(--card);
  box-shadow: -8px 0 8px -8px rgba(15, 23, 42, .16);
}
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th { background: #f8fafc; text-align: left; padding: 11px 12px; color: var(--muted); font-weight: 600; border-bottom: 1px solid var(--border); white-space: nowrap; }
td { padding: 10px 12px; border-bottom: 1px solid #f1f5f9; vertical-align: middle; }
tr:last-child td { border-bottom: none; }
td input, td select { padding: 6px 8px; font-size: 13px; }
.td-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* 经营核算概览表：数量 / 收入 / 成本 / 毛利 / 毛利率 / 价税合计 一律居中。
 * 数字右对齐是给几十行的长表对位用的；这张表只有 7 列、每格都短，
 * 右对齐反而让「成本、毛利」两列贴着右边栏、与左边那列商品名断开。首列商品名仍左对齐。 */
.pf-table th, .pf-table td { text-align: center; }
.pf-table th:first-child, .pf-table td:first-child { text-align: left; }
.td-actions { white-space: nowrap; }
/* 销售订单「操作」：按钮本来被 .td-actions 的 nowrap 撑成一整列、极高，
   非常难看。这里改成固定 2 列网格，按钮自然宽度、左对齐，自动折成若干行，
   形成紧凑的方块而不是一根竖条。列宽给到 176px 保证「生成生产订单」这种长
   按钮也能和旁边的短按钮并排成两列；其它表的 .td-actions 保持原样。 */
.so-acts-cell { white-space: normal; min-width: 176px; }
.so-acts { display: grid; grid-template-columns: repeat(2, max-content); gap: 4px 6px; justify-content: start; align-items: center; }
.so-acts > * { margin: 0; white-space: nowrap; }
/* 产品名称 / 数量 逐行对位：两列共用同一套行高，第 i 行就是第 i 个商品，全部显示不截断 */
.so-lines { display: flex; flex-direction: column; gap: 2px; }
.so-line { line-height: 18px; white-space: nowrap; }
.so-line.td-num { text-align: right; }
.empty { padding: 40px; text-align: center; color: var(--muted); }

/* ---------- 状态 ---------- */
.status { display: inline-block; padding: 3px 10px; border-radius: 20px; font-size: 12px; }
.status-draft { background: #f1f5f9; color: var(--muted); }
.status-pending { background: #fef3c7; color: var(--warning); }
.status-approved { background: #dcfce7; color: var(--success); }
.status-rejected { background: #fee2e2; color: var(--danger); }

/* ---------- 报价编辑器 ---------- */
.quote-items td { vertical-align: top; }
.item-comp { min-width: 180px; }
.totals-row { display: flex; justify-content: flex-end; gap: 24px; padding: 14px 12px; font-size: 15px; align-items: baseline; flex-wrap: wrap; }
.totals-row .big { font-size: 20px; font-weight: 700; color: var(--primary); }
.cap-line { text-align: right; padding: 0 12px 12px; color: var(--muted); }

/* ---------- 弹窗 ---------- */
/* ---------- 弹窗：一律全屏 ----------
 * 为什么改：新增客户 / 新建销售订单这类单据编辑原来只是中间一个小卡片，
 * 十几列的明细挤在 900px 里来回横向滚，填一单要拖好几次滚动条。
 * 现在铺满整个内容区（左侧主栏目保留，随时能切栏目），顶栏常驻「关闭 + 主操作」，
 * 不用滚到页面最底才能保存。
 * 做法上不逐个改那 25 个弹窗的写法，而是用 CSS 把它们一起放大、
 * 由 app.js 的 decorateModal 统一补一条顶栏——以后新增的弹窗自动也是全屏。
 * 左侧留出侧栏宽度：mask 挂在 body 下，用兄弟选择器跟随 #view-app 的收缩状态。 */
.modal-mask {
  /* left 跟侧栏宽度走（拖过侧栏的话弹窗不能还从 196 开始，否则会压在侧栏上） */
  position: fixed; top: 0; right: 0; bottom: 0; left: var(--side-w, 196px);
  background: var(--bg); overflow-y: auto; z-index: 100;
}
#view-app.side-mini ~ .modal-mask { left: 64px; }
.modal {
  background: var(--card); border-radius: 0; padding: 16px 22px 36px;
  width: 100%; max-width: none; min-height: 100%; max-height: none; overflow: visible;
}
.modal > h3.modal-h3, .modal .modal-h3 { display: none; }   /* 标题已挪到顶栏，不重复显示 */
/* 全屏之后要防「一个输入框横跨 1.5 米」：按字段多少自动配列数，
   单行文字也读得下来；字段少的单据不会被拉成一整片空白。
   表格明细（.acc-editor）不受影响，它自己就是横向滚动的。 */
.modal .grid {
  display: grid; gap: 12px 18px; align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); max-width: 1180px;
}
.modal .grid > .field { grid-column: auto !important; }   /* 模板里写死的 span 2 在全屏下反而拉太长 */
.modal .grid > .field textarea { min-height: 70px; }
/* 单据类弹窗的头部用的是 .grid2（.grid 是后半段自动匹配，.grid2 之前没定义）。
   补上之后，单据头也变成自适应多列，不再一个输入框占满一整行。 */
.modal .grid2 {
  display: grid; gap: 12px 18px; align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); max-width: 1180px;
}
.modal .grid2 > .field { min-width: 0; }
/* 正文整体限宽居中：阅读宽度舒服，又不是原来那个小卡片 */
.modal > h3 + *, .modal > .grid { max-width: 1180px; }
.modal-bar {
  position: sticky; top: 0; z-index: 2; display: flex; align-items: center; gap: 12px;
  padding: 10px 22px; background: var(--card); border-bottom: 1px solid var(--border);
}
.mb-title { flex: 1; min-width: 0; font-size: 16px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mb-actions { flex: 0 0 auto; display: flex; gap: 8px; }
/* 底部操作条跟着滚：填长单据时不用来回找保存按钮 */
.modal .modal-actions {
  position: sticky; bottom: 0; z-index: 1; margin-top: 18px; padding: 12px 0;
  background: var(--card); border-top: 1px solid var(--border);
}
.modal h3 { margin-bottom: 16px; }
.modal-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 20px; }

/* ---------- 导出打印模板 ---------- */
/* PDF 导出画布容器：宽度由 JS 按 A4 可打印区像素设定 */
#print-area { width: 703px; padding: 0; background: #fff; margin: 0 auto; box-sizing: border-box; }
.print-page { width: 210mm; }
.pq-title { text-align: center; font-size: 24px; font-weight: 700; letter-spacing: 6px; margin-bottom: 4px; }
.pq-company { text-align: center; font-size: 15px; margin-bottom: 18px; }
.pq-meta { display: flex; justify-content: space-between; font-size: 13px; margin-bottom: 10px; }
.pq-meta table, .pq-meta td { border: none; padding: 2px 0; }
.pq-info { width: 100%; border-collapse: collapse; font-size: 13px; margin-bottom: 12px; }
.pq-info td { border: 1px solid #cbd5e1; padding: 6px 10px; }
.pq-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.pq-table th, .pq-table td { border: 1px solid #cbd5e1; padding: 7px 9px; }
.pq-table th { background: #f1f5f9; text-align: center; }
.pq-notes { font-size: 13px; margin-top: 14px; line-height: 1.8; }
.pq-sign { display: flex; justify-content: space-between; margin-top: 44px; font-size: 13px; }

@media (max-width: 860px) {
  /* 窄屏下页签条与用户信息挤一行：身份只留名字（部门级别徽标在上面被隐藏了），
     页签名字自动截断——先保「看得见开了哪几个窗口」。 */
  .workbar { gap: 6px; padding-right: 8px; }
  .worktabs { padding-left: 8px; gap: 4px; }
  .user-box { gap: 6px; padding-left: 8px; }
  .ub-name { max-width: 72px; font-size: 12px; }
  main { margin: 0; padding: 12px 12px 32px; }
  /* 窄屏一律压成图标栏：手机上横向宽度金贵，导航不该跟单据抢地。
     选择器要压过 #view-app.side-mini 那条，所以带上 id。 */
  #view-app .side, #view-app.side-mini .side { flex-basis: 56px; width: 56px; }
  #view-app .sh-name, #view-app .nav-item .nv, #view-app .side-fold .nf { display: none; }
  #view-app .side-head { justify-content: center; padding: 12px 0; }
  #view-app .nav-item { justify-content: center; padding: 10px 0; }
  #user-badge { display: none; }
  /* 窄屏弹窗同样只让出图标栏那点宽度 */
  .modal-mask, #view-app.side-mini ~ .modal-mask { left: 56px; }
  .modal { padding: 14px 14px 32px; }
  .modal-bar { padding: 10px 14px; }
}

/* ---------- 分类 chips ---------- */
.chip-bar { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.chip { padding: 6px 14px; border-radius: 20px; background: #fff; border: 1px solid var(--border); cursor: pointer; font-size: 13px; user-select: none; }
.chip:hover { border-color: var(--primary); }
.chip.active { background: var(--primary); color: #fff; border-color: var(--primary); }
.chip.add { border-style: dashed; color: var(--muted); }
.chip-cnt { font-size: 11px; opacity: .65; margin-left: 4px; }
/* 分类 chips 里有时要夹一个下拉（如「全部类型」），把它顶到行尾 */
.chip-bar select { margin: 0; padding: 5px 8px; font-size: 12px; }

/* ---------- 分类树（商品库 / 组件库，2026-10-28 学金蝶） ----------
 * 左边一列树、右边列表。为什么从横排 chips 改成竖树：
 * 分类到二级之后，横排条要么换两行、要么父子看不出关系；
 * 竖着排层级一眼看穿（CPU 下面缩进的就是它的子类），也不占横向空间。 */
.cat-layout { display: flex; gap: 14px; align-items: flex-start; }
.cat-main { flex: 1; min-width: 0; }
.cat-tree {
  flex: 0 0 208px; width: 208px; background: var(--card); border: 1px solid var(--border);
  border-radius: 10px; display: flex; flex-direction: column; max-height: calc(100vh - 190px);
  position: sticky; top: 0;
}
.ct-head { padding: 9px 12px; font-size: 13px; font-weight: 700; border-bottom: 1px solid var(--border); color: var(--text); }
.ct-head .hint { font-weight: 400; }
.ct-body { flex: 1; min-height: 0; overflow: auto; padding: 5px; }
.ct-row {
  display: flex; align-items: center; gap: 5px; padding: 5px 7px; border-radius: 6px;
  font-size: 13px; cursor: pointer; user-select: none; white-space: nowrap; color: var(--text);
}
/* 分类树按层级缩进：一层一级台阶，一个中文字符宽（13px）。
   data-depth 早就由 catTreeHTML() 渲染出来了，只是之前一直没接样式，各级才齐平。
   基础 padding 是 5px 7px，所以 depth=0 就是 7px，之后每级 +13px。 */
.ct-row[data-depth="1"] { padding-left: 20px; }
.ct-row[data-depth="2"] { padding-left: 33px; }
.ct-row[data-depth="3"] { padding-left: 46px; }
.ct-row[data-depth="4"] { padding-left: 59px; }
.ct-row:hover { background: #f1f5f9; }
.ct-row.active { background: var(--primary); color: #fff; }
.ct-row.active .ct-cnt { color: #fff; opacity: .8; }
/* 选中项的祖先节点加一条淡色底：点了「服务器」时，别人也能看出它属于 CPU */
.ct-row.on-path { background: #eff6ff; }
.ct-caret {
  /* 与 .nv-caret 同理：字号放大到 25px，用 line-height:1 锁住行高，
     槽位给到 18px，既容得下字形又不会把栏目标题挤成省略号。 */
  flex: 0 0 18px; width: 18px; text-align: center; font-size: 25px; line-height: 1;
  color: var(--muted); transition: transform .12s ease; display: inline-block;
}
.ct-caret.open { transform: rotate(90deg); }
.ct-caret.leaf { visibility: hidden; }
.ct-ico { flex: 0 0 8px; width: 8px; height: 8px; border-radius: 2px; display: inline-block; }
.ct-name { flex: 1; overflow: hidden; text-overflow: ellipsis; }
.ct-cnt { flex: 0 0 auto; font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
.ct-empty { padding: 12px; font-size: 12px; color: var(--muted); text-align: center; }
.ct-foot { border-top: 1px solid var(--border); padding: 7px 9px; display: flex; align-items: center; justify-content: space-between; gap: 6px; }
.ct-foot .chk { font-size: 12px; color: var(--muted); white-space: nowrap; }
.ct-foot .chk input { margin-right: 3px; }
/* 分类管理弹窗里的名字格：色块 + 输入框，子类靠 padding-left 缩进 */
.cat-name-cell { display: flex; align-items: center; gap: 6px; }
.cat-name-cell input { flex: 1; min-width: 0; }
.cat-mgr input.up { text-transform: uppercase; font-family: ui-monospace, Menlo, Consolas, monospace; letter-spacing: .3px; }
.cat-mgr td { vertical-align: middle; }
@media (max-width: 1180px) {
  .cat-layout { flex-direction: column; }
  .cat-tree { flex: none; width: 100%; max-height: 240px; position: static; }
}

/* ---------- 生产领料：顶部概览数字（2026-10-24） ----------
 * 一进页面先回答"今天有几件事没结"，而不是先给人一段说明文字。
 * 数字本身就是按钮：点「欠料」下面的看板只剩欠料的那几行。 */
.pick-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); gap: 12px; margin-bottom: 14px; }
.pick-stat { background: var(--card); border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px; }
.pick-stat .ps-n { font-size: 26px; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
.pick-stat .ps-t { font-size: 13px; color: var(--text); margin-top: 2px; }
.pick-stat .sb-link { display: inline-block; margin-top: 4px; }
/* 卡片标题里右浮的搜索框：一行 HEAD + 搜索，别再占一整行工具栏 */
.card h3 input[type=text] { padding: 5px 9px; font-size: 12px; border: 1px solid var(--border); border-radius: 7px; }
@media (max-width: 900px) {
  .card h3 input[type=text] { float: none !important; width: 100% !important; margin-top: 8px; }
}

/* ---------- 配件清单编辑 / 挂载 ---------- */
.acc-editor { border: 1px solid var(--border); border-radius: 8px; overflow-x: auto; background: #fff; }
.acc-editor table { min-width: 780px; }
.acc-editor th { white-space: nowrap; background: #f8fafc; }
.acc-editor td { padding: 7px 8px; }
.acc-editor td input { width: 100%; padding: 7px 9px; font-size: 13px; }
.acc-editor td input.num { text-align: right; font-variant-numeric: tabular-nums; }
.acc-editor td input.center { text-align: center; }
.qty-box { display: flex; align-items: center; justify-content: center; gap: 5px; }
.qty-box input { width: 62px !important; min-width: 62px; text-align: center; font-size: 14px; font-weight: 700; padding: 7px 4px; }
.qty-box .btn.sm { padding: 4px 9px; font-size: 14px; line-height: 1.2; }
.acc-tabs { display: flex; gap: 8px; margin: 12px 0 0; flex-wrap: wrap; }
.acc-tab { padding: 7px 14px; border: 1px solid var(--border); border-radius: 8px; cursor: pointer; font-size: 13px; background: #f8fafc; color: var(--muted); }
.acc-tab:hover { border-color: var(--primary); }
.acc-tab.active { background: var(--primary); color: #fff; border-color: var(--primary); }
tr.is-acc td { background: #fffbf0; }
.acc-mark { display: inline-block; margin-right: 6px; color: var(--warning); font-size: 12px; font-weight: 600; }
/* 报价明细「规格/参数」一格：上面规格正文（最多两行、超出省略，全文在 title 里），
   下面两个按钮。以前规格和按钮分两列，看着像两份数据。 */
.sp-spec { line-height: 1.35; white-space: pre-wrap; word-break: break-word;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }

/* 被引用的配置 / 配件就地展开（2026-10-28）：以前要点「规格/配置(n)」才知道配了什么。
   左边一根淡竖线 + 「部件名」灰字，视觉上明确是"挂在主规格下面的"，不会跟正文混在一起。 */
.sp-refs { margin-top: 3px; padding-left: 7px; border-left: 2px solid var(--border); }
.sp-ref { font-size: 12px; line-height: 1.5; color: var(--text); word-break: break-word; }
.sp-ref-k { color: var(--muted); margin-right: 4px; }
.sp-ref-k::after { content: '：'; }
.sp-ref-q { color: var(--muted); }
.sp-ref-m { color: var(--muted); font-size: 11px; }
/* 配件那条再淡一点：它是"加上去的东西"，不是这颗货本身的规格 */
.sp-acc { color: var(--muted); }
.sp-acc .sp-ref-k { color: #94a3b8; }

/* ---------- 特殊要求勾选 ---------- */
.special-box { border: 1px solid var(--border); border-radius: 8px; padding: 10px 14px; background: #fbfcfe; }
.chk-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 2px; padding: 6px 0; border-bottom: 1px dashed var(--border); }
.chk-group { font-size: 13px; color: var(--muted); min-width: 74px; font-weight: 600; }
.chk { display: inline-flex; align-items: center; gap: 2px; margin: 0 8px 0 0; font-size: 13px; color: var(--text); cursor: pointer; }
.chk input { width: 15px; height: 15px; margin: 0 4px 0 0; }

/* ---------- 导出模板设计器（类 Excel 拖拉排版） ---------- */
.tpl-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 12px; }
.tpl-bar select { width: auto; min-width: 92px; padding: 4px 8px; font-size: 12px; }
.tpl-bar .btn.sm { min-height: 28px; }
.tpl-sep { width: 1px; height: 22px; background: var(--border); margin: 0 4px; }
.tpl-grid-wrap { overflow: auto; max-height: 62vh; border: 1px solid var(--border); border-radius: 8px; background: #fff; padding: 6px; }
.tpl-grid { display: grid; gap: 0; font-size: 12px; user-select: none; }
.tg-corner { grid-column: 1; grid-row: 1; background: #f1f5f9; border: 1px solid #cbd5e1; }
.tg-ch { position: relative; background: #f1f5f9; border: 1px solid #cbd5e1; text-align: center; color: var(--muted); font-weight: 600; line-height: 22px; }
.tg-rh { background: #f1f5f9; border: 1px solid #cbd5e1; text-align: center; color: var(--muted); line-height: 30px; }
.tg-rz { position: absolute; top: 0; right: -3px; width: 6px; height: 100%; cursor: col-resize; }
.tg-rz:hover { background: var(--primary); }
.tg-cell { border: 1px solid #cbd5e1; padding: 3px 5px; overflow: hidden; white-space: pre-wrap; word-break: break-word; display: flex; align-items: center; background: #fff; cursor: cell; }
.tg-cell.sel { background: #dbeafe !important; box-shadow: inset 0 0 0 2px var(--primary); }
.tg-cell.tg-b { font-weight: 700; }
.tg-cell.tg-list { background: #fffbeb !important; }
.tg-tag { display: inline-block; font-size: 10px; background: #f59e0b; color: #fff; border-radius: 4px; padding: 0 4px; margin-right: 4px; }
.tg-f { color: var(--primary); font-weight: 600; }
.tg-f-head { background: #eff4fb; }
.tg-f-label, .tg-f-gray { background: #f1f5f9; }
.tg-f-total { background: #f4f7fc; }
.tg-f-blue { background: #eff4fb; }
.tpl-cols { display: flex; flex-wrap: wrap; gap: 10px; }
.tpl-col { border: 1px solid var(--border); border-radius: 8px; padding: 8px; width: 158px; background: #fbfcfe; }
.tpl-col-h { font-size: 12px; font-weight: 600; color: var(--muted); margin-bottom: 4px; }
.tpl-col input, .tpl-col select { margin-bottom: 4px; padding: 4px 6px; font-size: 12px; }
.tpl-table { width: 100%; }
.tpl-table td { min-width: 0; }

/* 打印预览：按 A4 纵向比例呈现（内容区 186mm ≈ PDF 实际版式）
 * 以前 max-width:100%，窗口一窄就把整张单子压扁：列宽按百分比缩水，
 * 合计金额那种长数字会被右边框裁掉末位（客户拿到少一位数，比排版难看严重得多）。
 * 现在保底 210mm，窄窗口就让外层滚动——预览看到的就是打印出来的那张。 */
.print-preview { background: #fff; border: 1px solid var(--border); border-radius: 8px; padding: 12mm; width: 210mm; min-width: 210mm; max-width: none; min-height: 150mm; margin: 0 auto; box-shadow: 0 2px 12px rgba(15,23,42,.08); }
.print-preview.landscape { width: 297mm; min-width: 297mm; min-height: 210mm; }
.print-preview .pq-title { letter-spacing: 4px; }

/* ===== 帮助使用手册（系统设置 → 使用手册）===== */
.help-wrap { display: flex; gap: 18px; align-items: flex-start; }
.help-toc { position: sticky; top: 60px; flex: 0 0 190px; display: flex; flex-direction: column; gap: 4px;
            border: 1px solid var(--border); border-radius: 10px; padding: 10px; background: #fbfcfe; }
.help-toc-item { padding: 7px 9px; border-radius: 7px; font-size: 13px; color: #334155; text-decoration: none; }
.help-toc-item:hover { background: #eef2ff; color: var(--primary); }
.help-body { flex: 1 1 auto; min-width: 0; }
.help-sec { background: #fff; border: 1px solid var(--border); border-radius: 10px; padding: 16px 18px; margin-bottom: 14px; }
.help-sec h3 { font-size: 15px; margin: 0 0 10px; padding-bottom: 8px; border-bottom: 1px solid var(--border); }
.help-sec h4 { font-size: 14px; margin: 16px 0 8px; color: var(--primary); }
.help-sec h4:first-of-type { margin-top: 4px; }
.help-sec p, .help-sec li { font-size: 13.5px; line-height: 1.85; color: #334155; }
.help-sec ul { padding-left: 20px; margin: 6px 0; }
.help-sec li { margin-bottom: 4px; }
.help-tbl { width: 100%; border-collapse: collapse; font-size: 13px; margin: 8px 0 12px; }
.help-tbl th, .help-tbl td { border: 1px solid var(--border); padding: 7px 9px; text-align: left; vertical-align: top; }
.help-tbl th { background: #f6f8fc; font-weight: 600; color: #334155; }
.help-code { background: #0f172a; color: #e2e8f0; border-radius: 8px; padding: 10px 12px; font-size: 12.5px;
             overflow-x: auto; line-height: 1.7; margin: 8px 0; font-family: Consolas, Menlo, monospace; }
.help-warn { background: #fff7ed; border-left: 3px solid #f59e0b; border-radius: 6px; padding: 9px 12px; margin: 10px 0; }
.help-tip { background: #eff6ff; border-left: 3px solid var(--primary); border-radius: 6px; padding: 9px 12px; margin: 10px 0; }
.help-flow { background: #f1f5f9; border-radius: 8px; padding: 10px 12px; font-size: 13.5px; margin: 8px 0 12px; }
@media (max-width: 900px) { .help-wrap { flex-direction: column; } .help-toc { position: static; flex: none; width: 100%; } }

/* ---------- 手机横屏（矮屏）微调（2026-11-03）----------
 * 系统响应式是按「宽度」断点的，横屏时宽度变大、高度变矮。
 * 这里只针对「横屏 + 高度 ≤ 500px」的矮屏手机补一刀：
 * 侧栏更窄、内边距更紧、可滚面板限高，避免横屏下内容被挤得大量滚动。
 * 不强制横屏（screen.orientation.lock 仅全屏可用且侵入）。 */
@media (orientation: landscape) and (max-height: 500px) {
  #view-app .side, #view-app.side-mini .side { flex-basis: 48px; width: 48px; }
  .modal-mask, #view-app.side-mini ~ .modal-mask { left: 48px; }
  main { padding: 8px 10px 18px; }
  .cat-tree { max-height: 170px; }
  .modal { max-height: 92vh; overflow: auto; }
  .tpl-grid-wrap { max-height: 52vh; }
}

/* ===== 安全锁（报价/合同/订单 防误删） 2026-11-04 by general-purpose-2 ===== */
/* 锁定提示与已退回/已作废徽标：以行内 style 为主，这里统一字号与轻微描边，避免各页写法不一致 */
.td-actions .hint[style*="var(--danger)"] {
  display: inline-block;
  font-weight: 600;
  margin-left: 4px;
  white-space: nowrap;
}
.badge[style*="b91c1c"] { /* 已作废 / 已锁 */
  border: 1px solid currentColor;
}
.badge[style*="15803d"] { /* 已退回 / 已拆解 */
  border: 1px solid currentColor;
}
/* 销售订单「已拆解」状态下整行轻微弱化，提示已清账 */
tr td .badge { font-size: 11px; padding: 1px 6px; border-radius: 4px; }
/* 编辑生产任务：下级配件行整体缩进两个字符，父行前的箭头可收展 */
.pt-arrow { cursor: pointer; display: inline-block; width: 1.2em; margin-right: 4px; color: var(--primary); font-weight: 700; user-select: none; }
.pt-acc-sub > td { padding-left: 2em; background: #fffbf0; }
.pt-acc-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 3px 0; }
.pt-acc-mark { color: var(--warning); font-weight: 700; }
