/* @@SPLIT_HEADER@@
   css/pages/editor.css —— 发货单模板管理 / 编辑器
      由 redesign2.html 拆分而来（原行号 1958-2362），业务逻辑原样搬运；加载顺序见 index.html / README.md */
/* ==========================================================================
   14. 发货单模板管理 / 编辑器（2026-10-25 第三期：画布拖拽编辑器）
   --------------------------------------------------------------------------
   ★ 为什么两个面板都自己写样式、不复用 #mask/.modal：
     .modal 是 380px 一句话弹窗；模板管理要 900+px 两栏，编辑器要「左中右」
     三栏 + 标尺 + 画布。硬塞进 .modal 会把那条通用弹窗的样式改坏。
   ★ 编辑器的三栏是 grid（190 / 1fr / 300）：中间那栏 `minmax(0,1fr)` 是关键 ——
     不写 minmax(0,...) 时，画布里一个很宽的表格字段会把整栏撑开，
     于是**主界面出现横向滚动条**（用户红线：不许横向滚动）。
   ★ 所有尺寸都用毫米换算后的像素（TPLE.pxmm），CSS 里不写死任何纸张大小。
   ========================================================================== */
#tplMgrMask,#tplEdMask{position:fixed;inset:0;z-index:340;background:rgba(15,23,42,.38);
  display:none;align-items:center;justify-content:center;backdrop-filter:blur(1px)}
#tplMgrMask.show,#tplEdMask.show{display:flex}
.tm-box{width:min(960px,94vw);height:min(640px,86vh);background:var(--card);border-radius:12px;
  box-shadow:0 24px 64px rgba(15,23,42,.24);display:flex;flex-direction:column;overflow:hidden}
.tm-hd{flex:none;display:flex;align-items:center;gap:10px;height:46px;padding:0 16px;
  border-bottom:1px solid var(--line);font-size:14px;font-weight:600;color:var(--text)}
.tm-hd .sub{font-size:12px;color:var(--mut);font-weight:400}
.tm-x{margin-left:auto;width:26px;height:26px;display:inline-flex;align-items:center;
  justify-content:center;border:0;background:none;border-radius:6px;color:var(--faint);
  cursor:pointer;padding:0;font-size:16px;line-height:1}
.tm-x:hover{background:var(--bg);color:var(--text)}
.tm-main{flex:1 1 auto;min-height:0;display:grid;grid-template-columns:minmax(0,1fr) 300px}
.tm-list{overflow:auto;padding:12px 14px;border-right:1px solid var(--line)}
.tm-row{display:flex;align-items:center;gap:10px;padding:9px 12px;border:1px solid var(--line);
  border-radius:10px;margin-bottom:8px;background:#fff}
.tm-row.on{border-color:var(--accent-line);box-shadow:0 0 0 2px var(--accent-weak)}
.tm-radio{width:14px;height:14px;border-radius:50%;border:1.5px solid var(--line-strong);flex:none}
.tm-row.on .tm-radio{border-color:var(--accent);
  background:radial-gradient(circle,var(--accent) 0 3.4px,#fff 4px)}
.tm-nm{font-size:13px;font-weight:600;color:var(--text);min-width:0}
.tm-meta{font-size:12px;color:var(--mut);white-space:nowrap}
.tm-def{font-size:11px;color:var(--green);background:var(--green-bg);border:1px solid #bbf7d0;
  border-radius:var(--r-pill);padding:1px 7px;white-space:nowrap}
.tm-ops{margin-left:auto;display:flex;gap:6px;flex:none}
.tm-new{padding:12px 14px;overflow:auto;background:#fbfcfe}
.tm-new h4{margin:0 0 10px;font-size:13px;font-weight:600}
.tm-field{display:flex;align-items:center;gap:8px;margin-bottom:9px;font-size:12px;color:var(--text-2)}
.tm-field .k{flex:none;width:56px;color:var(--mut)}
.tm-field input[type=text],.tm-field input[type=number],.tm-field select{
  flex:1 1 auto;min-width:0;height:30px;border:1px solid var(--line-strong);border-radius:8px;
  padding:0 8px;font:inherit;font-size:12px;color:var(--text);background:#fff}
.tm-field label{display:flex;align-items:center;gap:5px;font-size:12px;white-space:nowrap}
.tm-tip{margin:10px 0 12px;font-size:11px;color:var(--mut);line-height:1.7;
  background:var(--card);border:1px dashed var(--line-strong);border-radius:8px;padding:8px 10px}
.tm-empty{padding:24px 6px;text-align:center;color:var(--faint);font-size:12px}

/* ---------------- 编辑器外壳：标题条 / 参数条 / 三栏 / 状态条 ---------------- */
.te-box{position:relative;width:min(1340px,98vw);height:min(880px,94vh);background:var(--card);
  border-radius:12px;box-shadow:0 24px 64px rgba(15,23,42,.24);
  display:flex;flex-direction:column;overflow:hidden}
.te-bar{flex:none;display:flex;align-items:center;gap:10px;row-gap:6px;flex-wrap:wrap;
  padding:8px 14px;border-bottom:1px solid var(--line);background:#fbfcfe}
.te-bar .te-f{display:flex;align-items:center;gap:4px;font-size:12px;color:var(--mut);
  white-space:nowrap}
.te-bar input[type=text],.te-bar input[type=number]{height:26px;border:1px solid var(--line-strong);
  border-radius:6px;padding:0 6px;font:inherit;font-size:12px;color:var(--text);background:#fff}
.te-bar input[type=text]{width:132px}
.te-bar input[type=number]{width:62px;text-align:right}
.te-bar .te-x{color:var(--faint);font-size:12px}
.te-bar .grow{flex:1 1 auto}
.te-cb{display:inline-flex;align-items:center;gap:4px;font-size:12px;color:var(--text-2);
  cursor:pointer;white-space:nowrap}
.te-main{flex:1 1 auto;min-height:0;display:grid;
  grid-template-columns:190px minmax(0,1fr) 300px}

/* ---------------- 左栏：添加字段 / 常用字段 / 字段列表 ---------------- */
.te-left{overflow:auto;border-right:1px solid var(--line);padding:9px 8px;background:#fbfcfe}
.te-palette{display:grid;grid-template-columns:1fr 1fr;gap:4px}
.te-pal{height:26px;border:1px solid var(--line-strong);border-radius:6px;background:var(--card);
  font:inherit;font-size:12px;color:var(--text-2);cursor:pointer;padding:0}
.te-pal:hover{border-color:var(--accent-line);color:var(--accent);background:var(--accent-weak)}
/* ---------------- 左栏：添加项目（8 分类 + 配置面板；2026-10-26） ----------------
   ★ 为什么分类按钮要点两下（先选分类、再点面板里的「添加」）：
     用户对着「我打」的截图逐项要求过「图片要填地址、线条要选 4 种、二维码要填内容
     和尺寸、表格要选边框+勾列、水印要选类型+文字+角度」。点了就放一个空字段，
     用户还得去右边再改一遍，等于每次多三步。 */
.te-pal.on{border-color:var(--accent);color:var(--accent);background:var(--accent-weak);
  font-weight:600}
.te-palcfg{margin-top:7px;padding:7px;border:1px solid var(--line);border-radius:8px;
  background:#fff}
.te-palcfg:empty{display:none}
.te-palcfg-hd{font-size:12px;font-weight:600;color:var(--text);margin-bottom:5px}
/* 配置面板里的行（.te-f 全局样式是属性面板那套，这里补一个纵向变体） */
.te-f{display:flex;align-items:center;gap:6px;font-size:11.5px;color:var(--text-2);
  margin:4px 0}
.te-f > span:first-child{flex:none;width:52px;color:var(--mut)}
.te-f input[type=text],.te-f input[type=number],.te-f select{flex:1 1 auto;min-width:0;
  height:24px;border:1px solid var(--line-strong);border-radius:5px;padding:0 5px;
  font:inherit;font-size:11.5px;background:var(--card);box-sizing:border-box}
.te-f input[type=color]{flex:none;width:34px;height:24px;border:1px solid var(--line-strong);
  border-radius:5px;padding:1px;background:#fff}
.te-fcol{display:block}
.te-fcol > span:first-child{display:block;width:auto;margin-bottom:3px}
.te-radios,.te-colchk{display:flex;flex-wrap:wrap;gap:3px 8px}
.te-rd{display:inline-flex;align-items:center;gap:3px;font-size:11.5px;color:var(--text-2);
  cursor:pointer}
.te-rd input{margin:0;width:12px;height:12px}
/* 二维码实时预览：白底 + 细边，图是后端真算出来的码 */
.te-qrprev{margin:6px 0 2px;padding:5px;border:1px solid var(--line);border-radius:6px;
  background:var(--card);text-align:center}
.te-qrprev img{width:96px;height:96px;display:inline-block;image-rendering:pixelated}
.te-qrprev img[src=""]{display:none}
.te-cfgadd{width:100%;margin-top:6px;height:26px;font-size:12px}
/* 预设行（组合类）：和变量行区分 —— 左侧一条淡蓝色竖线 */
.te-vrow.preset{padding-left:8px;border-left:2px solid var(--accent-line);margin-left:4px}
/* ---------------- 左栏：变量清单（搜索 + 可折叠分组） ----------------
   ★ 190px 的窄栏里要放下 65 个变量：靠「分组折叠 + 搜索」而不是把按钮铺开。
     列表自己有 max-height 和滚动条，否则「字段列表」会被顶到看不见的地方。 */
.te-vsearch input{width:100%;height:26px;border:1px solid var(--line-strong);border-radius:6px;
  padding:0 7px;font:inherit;font-size:12px;color:var(--text);background:var(--card);box-sizing:border-box}
.te-vars{max-height:40vh;overflow:auto;margin-top:5px;border:1px solid var(--line);
  border-radius:8px;background:#fff}
.te-vg{border-bottom:1px solid var(--line)}
.te-vg:last-child{border-bottom:0}
.te-vgh{display:flex;align-items:center;gap:4px;width:100%;padding:5px 7px;border:0;
  background:#f6f8fb;font:inherit;font-size:12px;color:var(--text-2);cursor:pointer;text-align:left}
.te-vgh:hover{background:var(--hover)}
.te-vgh .cx{flex:none;width:9px;color:var(--faint);font-size:10px;line-height:1}
.te-vgh .gt{flex:1 1 auto;min-width:0;font-weight:600;color:var(--text);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.te-vgh .gc{flex:none;font-size:11px;color:var(--mut)}
.te-vgl{padding:2px 0 3px}
.te-vrow{display:flex;align-items:center;gap:4px;padding:3px 5px 3px 9px;font-size:12px}
.te-vrow:hover{background:var(--accent-weak)}
.te-vrow .vn{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;color:var(--text-2)}
/* 旧版别名（收件人 / 省 / 市 …现存模板在用）：灰一点，和推荐写法区分开 */
.te-vrow.legacy .vn{color:var(--faint)}
/* 拿不到的变量/字段：灰显（2026-10-26 用户明确要求「给不了也加，文字弄灰」）。
   ★ 用 #94a3b8 而不是原来的橙色：橙色像「出错警告」，灰色才像「不可用但可加」；
     右侧短标签（微信不提供/需抖音/微信无此项）负责说清原因，悬停有完整 reason。 */
.te-vrow.off .vn{color:#94a3b8}
.te-vrow.off .vb{flex:none;font-size:10px;line-height:15px;padding:0 4px;border-radius:4px;
  color:var(--mut);background:var(--bg);border:1px solid var(--line);white-space:nowrap}
.te-vrow .vp{flex:none;width:18px;height:18px;border:1px solid var(--line-strong);border-radius:4px;
  background:var(--card);font:inherit;font-size:13px;line-height:1;color:var(--accent);cursor:pointer;
  padding:0;display:inline-flex;align-items:center;justify-content:center}
.te-vrow .vp:hover{background:var(--accent-weak);border-color:var(--accent-line)}
.te-fields{margin-top:2px}
.te-frow{display:flex;align-items:center;gap:6px;padding:5px 6px;border-radius:8px;
  cursor:pointer;font-size:12px;color:var(--text-2);border:1px solid transparent}
.te-frow:hover{background:var(--hover)}
.te-frow.on{background:var(--sel);border-color:var(--accent-line);color:var(--text);font-weight:600}
.te-frow .ty{flex:none;font-size:10px;color:var(--mut);border:1px solid var(--line-strong);
  border-radius:4px;padding:0 4px;line-height:15px}
.te-frow.on .ty{color:var(--accent);border-color:var(--accent-line)}
.te-frow .nm2{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.te-frow .mv{display:flex;gap:1px;flex:none}
.te-frow .mv button{width:16px;height:16px;border:1px solid var(--line-strong);background:var(--card);
  border-radius:3px;font-size:10px;line-height:1;color:var(--text-2);cursor:pointer;padding:0}
.te-frow .mv button:hover{color:var(--accent);background:var(--hover)}
.te-frow .mv button:disabled{opacity:.3;cursor:not-allowed}

/* ---------------- 中栏：标尺 + 画布 ---------------- */
.te-stage{position:relative;min-width:0;min-height:0;background:var(--accent-weak);overflow:hidden}
.te-scroll{position:absolute;inset:0;overflow:auto;padding:14px}
.te-sheet{display:grid;grid-template-columns:18px auto;grid-template-rows:18px auto;
  width:max-content;margin:0 auto}
.te-corner{grid-column:1;grid-row:1;width:18px;height:18px;background:var(--bg);
  border-right:1px solid var(--line-strong);border-bottom:1px solid #d8dfe8}
.te-rx{grid-column:2;grid-row:1;position:sticky;top:0;z-index:9;height:18px;
  background:var(--hover);border-bottom:1px solid var(--line-strong);overflow:hidden}
.te-ry{grid-column:1;grid-row:2;position:sticky;left:0;z-index:9;width:18px;
  background:var(--hover);border-right:1px solid var(--line-strong);overflow:hidden}
.te-tick{position:absolute;background:#9aa8ba}
.te-rx .te-tick{top:0;width:1px}
.te-ry .te-tick{left:0;height:1px}
.te-tick.lbl{background:#5b6b80}
.te-rlbl{position:absolute;font-size:9px;color:var(--mut);line-height:10px;
  font-family:ui-monospace,Consolas,monospace;white-space:nowrap}
.te-rx .te-rlbl{top:1px}
.te-ry .te-rlbl{left:0;writing-mode:vertical-rl;transform:scale(.92);transform-origin:0 0}
.te-paper{grid-column:2;grid-row:2;position:relative;background:var(--card);
  box-shadow:0 2px 10px rgba(15,23,42,.14);overflow:hidden}
/* 网格：1mm 细线 + 5mm 稍深。--mm1/--mm5 由 JS 按缩放写进 style。 */
.te-paper.grid{background-image:
  repeating-linear-gradient(to right,#eef2f7 0 1px,transparent 1px var(--mm1,6px)),
  repeating-linear-gradient(to bottom,#eef2f7 0 1px,transparent 1px var(--mm1,6px)),
  repeating-linear-gradient(to right,#dbe3ee 0 1px,transparent 1px var(--mm5,30px)),
  repeating-linear-gradient(to bottom,#dbe3ee 0 1px,transparent 1px var(--mm5,30px))}
/* 纸张边界：虚线画在纸内侧（画在外面会被 overflow:hidden 裁掉） */
.te-paper.bound::after{content:"";position:absolute;inset:0;pointer-events:none;
  border:1px dashed #94a3b8;z-index:2}
.te-fldlayer{position:absolute;inset:0}

/* ---------------- 画布上的字段（绝对定位 div） ---------------- */
/* ★ overflow 必须留在**内层 .te-body**：字段框自己不能裁内容，
   否则选中标签（top:-19px）和 8 个把手（-4px 出框）会被一起裁掉 ——
   表现是「选中了但没有标签、把手只剩半个」，实测 2026-10-25 踩过。 */
.te-fld{position:absolute;box-sizing:border-box;overflow:visible;cursor:move;
  outline:1px dashed rgba(100,116,139,.35);outline-offset:-1px}
.te-fld:hover{outline-color:rgba(37,99,235,.55)}
.te-fld.sel{outline:1.5px solid var(--accent);z-index:6;
  box-shadow:0 0 0 3px rgba(37,99,235,.14)}
/* 超出纸张边界：整个框变红（位置由后端 validate 给出同样的判定口径） */
.te-fld.out{outline-color:var(--danger);outline-style:dashed;
  background:rgba(220,38,38,.05)}
.te-fld.sel.out{outline-style:solid}
.te-body{position:absolute;inset:0;overflow:hidden;pointer-events:none}
.te-tag{position:absolute;left:-1px;top:-19px;max-width:280px;height:17px;line-height:17px;
  padding:0 6px;border-radius:4px;background:rgba(37,99,235,.92);color:#fff;
  font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  pointer-events:none;backdrop-filter:blur(2px);z-index:7}
.te-fld.tagl .te-tag{top:auto;bottom:-19px}
.te-h{position:absolute;width:8px;height:8px;background:var(--card);border:1.5px solid var(--accent);
  border-radius:2px;z-index:8;box-sizing:border-box}
.te-h[data-h="nw"]{left:-4px;top:-4px;cursor:nwse-resize}
.te-h[data-h="n"]{left:calc(50% - 4px);top:-4px;cursor:ns-resize}
.te-h[data-h="ne"]{right:-4px;top:-4px;cursor:nesw-resize}
.te-h[data-h="e"]{right:-4px;top:calc(50% - 4px);cursor:ew-resize}
.te-h[data-h="se"]{right:-4px;bottom:-4px;cursor:nwse-resize}
.te-h[data-h="s"]{left:calc(50% - 4px);bottom:-4px;cursor:ns-resize}
.te-h[data-h="sw"]{left:-4px;bottom:-4px;cursor:nesw-resize}
.te-h[data-h="w"]{left:-4px;top:calc(50% - 4px);cursor:ew-resize}

/* 画布内各类型的「示意图」（真正的成品是后端 PNG，这里只求位置/大小准确） */
.te-tb{display:block;width:100%;height:100%;font-size:inherit;line-height:1.25}
.te-tb .hd,.te-tb .rw{display:flex;width:100%}
.te-tb .hd{background:#f2f2f2;border-bottom:1px solid #b8c2cf;font-weight:700}
.te-tb .rw{border-bottom:1px dotted var(--line-strong);color:#94a3b8}
.te-tb i{display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;
  border-right:1px solid var(--line-strong);padding:0 1px;font-style:normal;box-sizing:border-box}
.te-tb i:last-child{border-right:0}
/* 边框线型示意（2026-10-25 第五期）：画布上先让用户看出「我选的是虚线/无框」，
   真正的线宽/节奏由后端 PNG 和后端打印决定 —— 前端不做排版计算。 */
.te-tb.b-dashed .hd,.te-tb.b-dashed .rw{border-bottom-style:dashed}
.te-tb.b-dashed i{border-right-style:dashed}
.te-tb.b-none .hd,.te-tb.b-none .rw{border-bottom:0}
.te-tb.b-none i{border-right:0}
.te-tb.b-honly i{border-right:0}
.te-tb.b-honly .hd,.te-tb.b-honly .rw{border-bottom-style:solid}
.te-tb.b-vonly .hd,.te-tb.b-vonly .rw{border-bottom:0}
.te-tb.b-vonly i{border-right-style:solid}

/* ---------------- 表格列宽把手（2026-10-25 第五期） ----------------
   ★ 为什么是「一条 6px 宽的透明热区 + 里面 1px 竖线 + 上下两个 6px 蓝点」：
     · 只有 6px 宽 → 不会挡住点表格中间区域（选中/拖动字段照常）；
     · 热区贯穿整个表格高度 → 不用非得点中那个小方点才能拖；
     · z-index 9 高于 8 个缩放手把（.te-h=8）和选中标签（.te-tag=7），
       这样在字段边缘和标签重叠处也点得到列宽把手。 */
.te-tbl-h{position:absolute;top:0;bottom:0;width:6px;margin-left:-3px;z-index:9;
  cursor:col-resize;pointer-events:auto}
.te-tbl-h.edge{cursor:default}
.te-tbl-h .l{position:absolute;left:2px;top:0;bottom:0;width:1px;
  background:rgba(37,99,235,.5)}
.te-tbl-h .dot{position:absolute;left:0;width:6px;height:6px;border-radius:2px;
  background:var(--accent);box-shadow:0 0 0 1px #fff}
.te-tbl-h .dot.t{top:-3px}
.te-tbl-h .dot.b{bottom:-3px}
.te-tbl-h:hover .l{background:rgba(37,99,235,.95);width:2px;left:2px}
.te-tbl-h:hover .dot{background:#1d4ed8}
/* 拖动中的「当前列宽」气泡：挂在 #tePaper 上（不在 #teFldLayer 里，
   否则每帧重画字段层会把它一起删掉） */
.te-tbl-tip{position:absolute;z-index:30;padding:2px 7px;border-radius:6px;
  background:rgba(37,99,235,.95);color:#fff;font-size:11px;line-height:16px;
  white-space:nowrap;pointer-events:none;display:none;transform:translate(-50%,0)}
.te-tbl-tip.show{display:block}
.te-line{position:absolute;left:0;right:0;top:50%;height:25%;min-height:1px;background:#111}
.te-line.dash{background:none;border-top:1px dashed #111}
.te-bc{position:absolute;inset:0;background:repeating-linear-gradient(90deg,
  #111 0 1px,transparent 1px 3px);opacity:.8}
/* 旋转 90/-90 的条码：条改成横向（沿 y 排列）。
   ★ 和 PNG 预览同一套口径：旋转后长度轴沿「高」方向，所以画布上看到的就是
     一条条横杠摞起来 —— 用户不用点预览就能确认方向对不对。 */
.te-bc.rot{background:repeating-linear-gradient(0deg,#111 0 1px,transparent 1px 3px)}
.te-ph{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  border:1px dashed #94a3b8;color:var(--faint);font-size:10px;background:rgba(148,163,184,.06)}
.te-wm{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  font-weight:700;pointer-events:none}

/* ---------------- 右栏：属性面板 ---------------- */
.te-props{overflow:auto;padding:10px 12px;border-left:1px solid var(--line)}
.te-sec{font-size:12px;font-weight:600;color:var(--text);margin:12px 0 6px}
.te-sec:first-child{margin-top:0}
.te-hint{font-size:11px;color:var(--mut);line-height:1.7}
.te-grid2{display:grid;grid-template-columns:1fr 1fr;gap:6px}
.te-pf{display:flex;flex-direction:column;gap:2px;font-size:11px;color:var(--mut);min-width:0}
.te-pf input[type=number],.te-pf input[type=text],.te-pf select{
  height:24px;border:1px solid var(--line-strong);border-radius:6px;padding:0 5px;
  font:inherit;font-size:12px;color:var(--text);background:var(--card);min-width:0;width:100%}
.te-pf input[type=color]{height:24px;width:100%;border:1px solid var(--line-strong);
  border-radius:6px;padding:1px 2px;background:var(--card);cursor:pointer}
.te-pchk{display:flex;align-items:center;gap:5px;font-size:12px;color:var(--text-2);
  margin:5px 0;cursor:pointer}
/* 单选组（条码的「旋转 / 条码文字 / 条码类型」）：
   一行排开、可换行，别挤成竖着一长串 —— 12 个字的标签 + 4 个选项在 250px 宽的
   面板里竖排会把「位置与尺寸」推到看不见。 */
.te-pf-radio{margin:6px 0}
.te-radio-row{display:flex;flex-wrap:wrap;gap:4px 10px;margin-top:3px}
.te-radio{display:inline-flex;align-items:center;gap:3px;font-size:12px;
  color:var(--text-2);cursor:pointer;white-space:nowrap}
.te-radio input[type=radio]{margin:0;width:13px;height:13px;cursor:pointer}
.te-radio i{font-style:normal}
/* 条码体检结果：可编码绿、不合规红（红字就是「这个条码扫不出来」的唯一提示） */
.te-bc-err{font-size:11px;line-height:1.6;margin:4px 0 0;min-height:0}
.te-bc-err.ok{color:#15803d}
.te-bc-err.bad{color:var(--danger);background:var(--danger-bg);border:1px solid var(--danger-line);
  border-radius:6px;padding:4px 6px}
.te-btns{display:flex;align-items:center;gap:4px;margin:8px 0;flex-wrap:wrap}
.te-btns .sp{flex:1 1 auto}
.te-tg{width:26px;height:24px;border:1px solid var(--line-strong);border-radius:6px;
  background:var(--card);font:inherit;font-size:12px;color:var(--text-2);cursor:pointer;padding:0}
.te-tg:hover{background:var(--hover)}
.te-tg.on{background:var(--accent-weak);border-color:var(--accent-line);color:var(--accent);
  font-weight:700}
.te-tg.wide{width:auto;padding:0 7px}
.te-cols{margin-top:4px}
/* ★ 2026-10-25 第五期：多了一列给「✎ 每列属性」按钮（原来 4 列 → 5 列）。
   宽度只给 20px，不抢列名/宽度的空间。 */
.te-col{display:grid;grid-template-columns:16px minmax(0,1fr) 58px 40px 20px;gap:6px;
  align-items:center;padding:4px 6px;border-radius:8px;border:1px solid transparent}
.te-col.on{background:var(--accent-weak);border-color:var(--accent-line)}
.te-col .nm{font-size:12px;color:var(--text-2);overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.te-col.on .nm{color:var(--text);font-weight:600}
.te-col .w{height:24px;width:100%;border:1px solid var(--line-strong);border-radius:6px;
  padding:0 4px;font:inherit;font-size:11px;text-align:right}
.te-col .w:disabled{background:var(--bg);color:var(--faint)}
/* ✎：展开这一列的详细设置（对齐/字号/加粗/超宽）。展开时按钮变蓝，用户知道点过 */
.te-col .ed{width:18px;height:18px;border:1px solid var(--line-strong);background:var(--card);
  border-radius:4px;font-size:11px;line-height:1;color:var(--text-2);cursor:pointer;
  padding:0}
.te-col .ed:hover{background:var(--hover);color:var(--accent)}
.te-col .ed.on{background:var(--accent-weak);border-color:var(--accent-line);
  color:var(--accent);font-weight:700}
/* 每列详细设置块：缩进一点，视觉上属于上面那一列 */
.te-cdetail{margin:-2px 0 6px 22px;padding:7px 8px;border:1px solid var(--line);
  border-radius:8px;background:var(--card);display:grid;
  grid-template-columns:1fr 1fr;gap:6px 8px}
.te-cdetail .full{grid-column:1 / -1}
.te-cdetail .te-pf span{font-size:10px}
.te-cdetail .te-pchk{margin:0;font-size:11px}
.te-mv{display:flex;gap:2px;justify-content:flex-end}
.te-mv button{width:18px;height:18px;border:1px solid var(--line-strong);background:var(--card);
  border-radius:4px;font-size:11px;line-height:1;color:var(--text-2);cursor:pointer;padding:0}
.te-mv button:hover{background:var(--hover);color:var(--accent)}
.te-mv button:disabled{opacity:.35;cursor:not-allowed}
.te-sum{margin-top:8px;font-size:12px;color:var(--text-2);line-height:1.6}
.te-sum.bad{margin-top:8px;font-size:12px;color:var(--danger);background:var(--danger-bg);
  border:1px solid var(--danger-line);border-radius:8px;padding:7px 9px;line-height:1.6}
.te-parts{margin-top:2px}
.te-part{display:flex;align-items:center;gap:6px;padding:5px 7px;border:1px solid var(--line);
  border-radius:8px;margin-bottom:5px;background:var(--card);font-size:12px}
.te-part .tag{flex:none;font-size:10px;border-radius:4px;padding:0 5px;line-height:16px}
.te-part.lit .tag{color:var(--warn);background:var(--warn-bg);border:1px solid #fde68a}
.te-part.var .tag{color:var(--accent-hover);background:var(--accent-weak);border:1px solid var(--accent-line)}
.te-part .v{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:pre}
.te-part input.v{border:1px solid var(--line-strong);border-radius:6px;height:22px;
  padding:0 6px;font:inherit;font-size:12px;background:#fff}
.te-add{display:flex;gap:8px;margin-top:8px;position:relative}
.te-varmenu{position:absolute;top:32px;left:92px;z-index:3;width:228px;max-height:250px;
  overflow:auto;background:var(--card);border:1px solid var(--line);border-radius:8px;
  box-shadow:0 12px 30px rgba(15,23,42,.14);padding:4px;display:none}
.te-varmenu.show{display:block}
.te-varmenu button{display:block;width:100%;text-align:left;border:0;background:none;
  font:inherit;font-size:12px;padding:5px 8px;border-radius:6px;cursor:pointer;color:var(--text-2)}
.te-varmenu button:hover{background:var(--hover);color:var(--accent)}

/* ---------------- 状态条 + 预览浮层 ---------------- */
.te-ft{flex:none;display:flex;align-items:center;gap:10px;height:34px;padding:0 14px;
  border-top:1px solid var(--line);background:#fff}
.te-ft .grow{flex:1 1 auto}
.te-status{font-size:12px;color:var(--mut);min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.te-status.bad{color:#b91c1c}
.te-tip{font-size:11px;color:var(--faint);white-space:nowrap}
.te-warnbar{flex:none;display:none;padding:5px 14px;background:var(--warn-bg);
  border-top:1px solid var(--warn-line);font-size:12px;color:var(--danger);line-height:1.6;
  max-height:58px;overflow:auto}
.te-warnbar.show{display:block}
.te-warnbar b{color:#c2410c}
.te-prevbox{position:absolute;inset:0;z-index:30;background:rgba(15,23,42,.45);
  display:none;align-items:center;justify-content:center;padding:18px}
.te-prevbox.show{display:flex}
.te-prevcard{background:var(--card);border-radius:10px;max-width:94%;max-height:94%;
  display:flex;flex-direction:column;overflow:hidden}
.te-prevhd{flex:none;display:flex;align-items:center;gap:8px;padding:8px 12px;
  border-bottom:1px solid var(--line);font-size:12px;color:var(--text-2)}
.te-prevhd .grow{flex:1 1 auto}
.te-prevbody{overflow:auto;padding:14px;background:var(--bg);text-align:center}
.te-prevbody img{background:var(--card);box-shadow:0 2px 10px rgba(0,0,0,.15);display:inline-block}

/* ---------------- 发货人（寄件人）信息面板（2026-10-25 本轮） ----------------
   入口：设置 ▾ → 常用发货人。z-index 比编辑器高一层：
   用户可能在编辑器开着的时候去填发货人（填完回来「添加变量」才看得到值）。 */
#senderMask{position:fixed;inset:0;z-index:350;background:rgba(15,23,42,.38);
  display:none;align-items:center;justify-content:center;backdrop-filter:blur(1px)}
#senderMask.show{display:flex}
.snd-box{width:min(520px,94vw);max-height:92vh;background:var(--card);border-radius:12px;
  box-shadow:0 24px 64px rgba(15,23,42,.24);display:flex;flex-direction:column;overflow:hidden}
.snd-body{padding:14px 16px;display:flex;flex-direction:column;gap:9px;overflow:auto}
.snd-f{display:flex;align-items:center;gap:10px;font-size:12px;color:var(--text-2)}
.snd-f .k{flex:none;width:60px;color:var(--mut)}
.snd-f input{flex:1 1 auto;min-width:0;height:30px;border:1px solid var(--line-strong);
  border-radius:8px;padding:0 8px;font:inherit;font-size:12px;color:var(--text);background:#fff}
.snd-tip{font-size:11px;color:var(--mut);line-height:1.7;background:var(--hover);
  border:1px dashed var(--line-strong);border-radius:8px;padding:8px 10px}
.snd-ft{flex:none;display:flex;align-items:center;gap:8px;padding:10px 16px;
  border-top:1px solid var(--line);background:#fbfcfe}
.snd-ft .grow{flex:1 1 auto}
.snd-hint{font-size:11px;color:var(--mut)}
.snd-hint.bad{color:#b91c1c}
