/* ============================================================
   智造ERP · 设计系统（现代简约 · 响应式 · 深/浅主题）
   ============================================================ */
/* ⭐ 色彩与形状令牌：全站唯一改色入口。想换主题色调，只改本区块即可。 */
:root{
  /* 色彩（低饱和 · 扁平） */
  --bg:#f4f5f8; --surface:#ffffff; --surface-2:#f1f3f7; --surface-3:#e9ecf3;
  --border:#e4e7ee; --border-2:#d5dae5;
  --text:#242833; --text-2:#616978; --text-3:#949baa;
  --primary:#5b6ba8; --primary-hover:#4e5d97; --primary-soft:#eceff8; --primary-ink:#ffffff;
  --ring:rgba(91,107,168,.30);
  --success:#4f8a63; --success-soft:#eaf4ee;
  --warn:#a97c3c;    --warn-soft:#f8f1e5;
  --danger:#b25c5e;  --danger-soft:#f9ecec;
  --info:#4a7f9c;    --info-soft:#e9f2f7;
  /* 形状与层级（扁平：极浅阴影 + 细边框） */
  --radius:12px; --radius-sm:8px; --radius-lg:16px;
  --shadow:0 1px 2px rgba(23,29,44,.05);
  --shadow-md:0 2px 8px rgba(23,29,44,.07);
  --shadow-lg:0 14px 40px rgba(23,29,44,.14);
  /* 动效 */
  --ease:cubic-bezier(.22,.61,.36,1); --ease-out:cubic-bezier(.16,1,.3,1);
  --dur-fast:.14s; --dur:.22s; --dur-slow:.34s;
  --sidebar-w:240px; --sidebar-w-min:68px;
  /* 未增强 select 的兜底箭头（正常情况会被自绘控件接管） */
  --arrow:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23616978' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  --font:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"PingFang SC","Microsoft YaHei",sans-serif;
}
[data-theme="dark"]{
  --bg:#111318; --surface:#181b22; --surface-2:#1f232c; --surface-3:#262b36;
  --border:#2b303b; --border-2:#3a4150;
  --text:#e4e7ee; --text-2:#98a0af; --text-3:#6b7280;
  /* ⭐ 深色主题的主色是「亮色」，因此主按钮文字必须用深色（primary-ink）
     才能保证对比度：亮紫#7d8ac9 配白字只有 3.3:1，配深字 5.7:1；
     钢青#7fadc4 配白字只有 2.4:1（几乎看不清），配深字 7.8:1。 */
  --primary:#7d8ac9; --primary-hover:#8c98d4; --primary-soft:#242838; --primary-ink:#0e1319;
  --ring:rgba(125,138,201,.36);
  --success:#63a97c; --success-soft:#1a2620;
  --warn:#c79a5c;    --warn-soft:#262115;
  --danger:#d4787a;  --danger-soft:#2a1d1e;
  --info:#6aa6c2;    --info-soft:#16242c;
  --shadow:0 1px 2px rgba(0,0,0,.30);
  --shadow-md:0 2px 10px rgba(0,0,0,.32);
  --shadow-lg:0 18px 46px rgba(0,0,0,.50);
  --arrow:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2398a0af' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}

/* ------------------------------------------------------------
   ⭐ 主题色预设（系统设置 › 外观 里切换，写入 html[data-accent]）
   默认（不写属性 / indigo）= 上面 :root 与 dark 里的靛蓝配色。
   钢青（steel）= 参考图色。**注意**：参考图的 #76a4bf / #19242b 在系统里
   的身份是「提示色(info)」——就是「已确认 / 已发货」那类胶囊的颜色。
   若直接拿它当主色，主按钮与这些胶囊会糊成一片，因此钢青主题下把
   primary 与 info **整体对调**：主色变钢青，提示色回到靛蓝。
   ------------------------------------------------------------ */
html[data-accent="steel"]{
  --primary:#45788f; --primary-hover:#3d6b80; --primary-soft:#e9f2f7; --primary-ink:#ffffff;
  --ring:rgba(69,120,143,.30);
  --info:#5b6ba8; --info-soft:#eceff8;
}
html[data-theme="dark"][data-accent="steel"]{
  --primary:#7fadc4; --primary-hover:#8fbcd2; --primary-soft:#17242c; --primary-ink:#0e1319;
  --ring:rgba(127,173,196,.36);
  --info:#8b97d4; --info-soft:#242838;
}
/* ------------------------------------------------------------
   ⭐ 账套主题色（v1.46.0 方案 C）：进入账套后 data-accent 由账套决定，
   用于「一眼区分在哪个账套」。只换 primary 系令牌，全站组件自动跟随；
   info/success/warn/danger 保持不动（状态胶囊语义全平台一致）。
   色相刻意拉开：靛蓝228° / 钢青200° / 青碧165° / 黛绿105° / 绛紫300° / 赭石18°。
   ------------------------------------------------------------ */
html[data-accent="teal"]{
  --primary:#3f8a74; --primary-hover:#357a66; --primary-soft:#e8f3ef; --primary-ink:#ffffff;
  --ring:rgba(63,138,116,.30);
}
html[data-theme="dark"][data-accent="teal"]{
  --primary:#6fb3a0; --primary-hover:#7fc2b0; --primary-soft:#16261f; --primary-ink:#0e1319;
  --ring:rgba(111,179,160,.36);
}
html[data-accent="forest"]{
  --primary:#5f8a52; --primary-hover:#527a46; --primary-soft:#edf4e9; --primary-ink:#ffffff;
  --ring:rgba(95,138,82,.30);
}
html[data-theme="dark"][data-accent="forest"]{
  --primary:#8ab377; --primary-hover:#98c088; --primary-soft:#1d2716; --primary-ink:#0e1319;
  --ring:rgba(138,179,119,.36);
}
html[data-accent="plum"]{
  --primary:#8a5b85; --primary-hover:#7a4d75; --primary-soft:#f5ecf4; --primary-ink:#ffffff;
  --ring:rgba(138,91,133,.30);
}
html[data-theme="dark"][data-accent="plum"]{
  --primary:#b281ad; --primary-hover:#c092bb; --primary-soft:#281c27; --primary-ink:#0e1319;
  --ring:rgba(178,129,173,.36);
}
html[data-accent="rust"]{
  --primary:#a5654f; --primary-hover:#955742; --primary-soft:#f8efe9; --primary-ink:#ffffff;
  --ring:rgba(165,101,79,.30);
}
html[data-theme="dark"][data-accent="rust"]{
  --primary:#c9907a; --primary-hover:#d5a08c; --primary-soft:#2b1e16; --primary-ink:#0e1319;
  --ring:rgba(201,144,122,.36);
}
/* 侧栏底部账套标识条（方案 C，v1.46.1 对齐效果图）：
   顶部一条账套色横条（就是效果图中那根圆角粗条）+ 下面「色点 + 账套名」一行 */
.set-bar{display:flex;flex-direction:column;gap:7px;padding:10px 0 2px;border-top:1px solid var(--border);margin-top:6px}
.set-bar .accent-bar{display:block;height:4px;border-radius:99px;background:var(--primary);opacity:.92;flex-shrink:0}
.set-bar .row{display:flex;align-items:center;gap:7px;min-width:0}
.set-bar .dot{width:9px;height:9px;border-radius:50%;background:var(--primary);flex-shrink:0;box-shadow:0 0 0 3px var(--primary-soft)}
.set-bar .txt{font-size:11.5px;color:var(--text-2);font-weight:650;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* 进入账套的全屏色彩过渡（方案 C）：enterSet 成功后触发一次。
   v1.46.2：对齐效果图 —— 135° 渐变（左上角色浓、往右下 70% 处透明），
   透明度 .9→0，色彩从左上角斜向铺入再褪去，不是全屏纯色闪一下。 */
#wash{position:fixed;inset:0;z-index:300;pointer-events:none;opacity:0;background:linear-gradient(135deg,var(--primary) 0%,transparent 70%)}
#wash.go{animation:erpWash .8s ease forwards}
@keyframes erpWash{0%{opacity:.9}100%{opacity:0}}
/* 面包屑前的账套色圆点（方案 C）：顶栏任意页面都能看到自己身处哪个账套。
   v1.46.1：crumbPre 是 topbar(flex) 的子项，中文的 min-content 宽 = 一个字，
   顶栏一挤它就被压成竖排（「设/置」摞着）—— nowrap + 禁收缩钉死。 */
#crumbPre{display:flex;align-items:center;flex-shrink:0;white-space:nowrap}
.crumb-dot{display:inline-block;width:9px;height:9px;border-radius:50%;background:var(--primary);margin-right:9px;flex-shrink:0}
/* 账套内主题色被锁定：色卡置灰不可点 */
.acc-card:disabled{opacity:.45;cursor:not-allowed}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{font-family:var(--font);background:var(--bg);color:var(--text);font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased}
.hidden{display:none!important}
button{font-family:inherit;cursor:pointer}
input,select,textarea{font-family:inherit;font-size:14px;color:var(--text)}
::-webkit-scrollbar{width:9px;height:9px}
::-webkit-scrollbar-thumb{background:var(--border);border-radius:6px}

/* ---------- 按钮 ---------- */
.btn{border:1px solid var(--border);background:var(--surface);color:var(--text);padding:8px 14px;border-radius:var(--radius-sm);font-weight:500;transition:.15s;display:inline-flex;align-items:center;gap:6px}
.btn:hover{border-color:var(--primary);color:var(--primary)}
.btn-primary{background:var(--primary);border-color:var(--primary);color:var(--primary-ink)}
.btn-primary:hover{filter:brightness(1.07);color:#fff}
.btn-ghost{background:transparent;border-color:transparent;color:var(--text-2)}
.btn-ghost:hover{background:var(--surface-2);color:var(--text)}
.btn-danger{color:var(--danger);border-color:transparent;background:transparent}
.btn-danger:hover{background:var(--danger-soft)}
.btn-sm{padding:5px 10px;font-size:13px}
/* v1.46.3：行高缩小 1/4 的配套 —— 表格行内的操作按钮改紧凑形制（28px→22px），
   否则按钮把行高顶回 41px，td 减了 padding 也白减 */
.tbl .btn-sm{padding:1px 9px;font-size:12px;line-height:1.5}
.btn-block{width:100%;justify-content:center;padding:11px}
.icon-btn{background:transparent;border:none;color:var(--text-2);font-size:18px;width:38px;height:38px;border-radius:10px;display:inline-flex;align-items:center;justify-content:center;transition:.15s}
.icon-btn:hover{background:var(--surface-2);color:var(--text)}

/* ---------- 登录 ---------- */
.login-wrap{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:radial-gradient(1200px 600px at 70% -10%,var(--primary-soft),transparent),var(--bg)}
.login-card{width:380px;max-width:92vw;background:var(--surface);border:1px solid var(--border);border-radius:20px;box-shadow:var(--shadow-lg);padding:36px 30px;text-align:center}
/* 品牌标志：统一用 public/icon.svg（原创母版，见 _build_icon.py）。
   ⚠ 标志是「品牌资产」，不参与「emoji / 扁平线性」图标风格切换，因此走 <img> 而不是 Icon.of()。 */
.login-logo{width:72px;height:72px;display:inline-block;vertical-align:top}
.login-card h1{font-size:22px;margin:8px 0 2px;letter-spacing:1px}
.login-sub{color:var(--text-2);font-size:13px;margin-bottom:22px}
.login-form{text-align:left;display:flex;flex-direction:column;gap:6px}
.login-form label{font-size:12px;color:var(--text-2);margin-top:8px}
.login-form input{background:var(--surface-2);border:1px solid var(--border);border-radius:10px;padding:11px 12px;outline:none;transition:.15s}
.login-form input:focus{border-color:var(--primary);background:var(--surface)}
.login-hint{margin-top:14px;font-size:12px;color:var(--text-3)}
.login-err{color:var(--danger);font-size:13px;margin-top:10px;min-height:18px}
/* 公司 / 平台管理员两种入口：正文小字 + 一个文字按钮，不做成第二个主按钮（会抢登录按钮的注意力） */
.login-modes{display:flex;align-items:center;justify-content:center;gap:10px;margin-top:12px;min-height:18px;font-size:12px;line-height:18px}
.login-modehint{color:var(--text-2)}
.login-link{background:none;border:0;padding:0;font:inherit;font-size:12px;color:var(--primary);cursor:pointer;text-decoration:underline;text-underline-offset:3px;opacity:.9;transition:.15s}
.login-link:hover{opacity:1}
.login-modes:has(.login-modehint:empty) .login-link{color:var(--text-3)}
.login-modes:has(.login-modehint:empty) .login-link:hover{color:var(--primary)}

/* ---------- 布局 ---------- */
.app{display:flex;height:100vh;overflow:hidden}
/* margin-right 也参与过渡：收起态悬停临时展开靠「宽度增加 + 等量负 margin」抵消占位（见下方 mini 段），
   两者必须同曲线同时长，动画过程中主内容区才不会随宽度抖动。 */
.sidebar{width:var(--sidebar-w);background:var(--surface);border-right:1px solid var(--border);display:flex;flex-direction:column;transition:width .2s,margin-right .2s,box-shadow .2s;flex-shrink:0}
.side-head{display:flex;align-items:center;justify-content:space-between;gap:6px;padding:16px 16px 10px}
.logo{display:flex;align-items:center;gap:9px;min-width:0;font-weight:700;font-size:16px;white-space:nowrap;overflow:hidden}
.brand-mark{width:24px;height:24px;display:block;flex-shrink:0}
.logo .txt{overflow:hidden;text-overflow:ellipsis}
.side-collapse{font-size:14px}
.nav{flex:1;overflow-y:auto;padding:6px 10px}
.nav-group{margin-bottom:10px}
.nav-group-title{font-size:11px;color:var(--text-3);text-transform:uppercase;letter-spacing:.6px;padding:10px 12px 4px}
.nav-item{display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:10px;color:var(--text-2);cursor:pointer;transition:.13s;font-weight:500;white-space:nowrap}
.nav-item:hover{background:var(--surface-2);color:var(--text)}
.nav-item.active{background:var(--primary-soft);color:var(--primary)}
.nav-item .ic{font-size:17px;width:22px;text-align:center;flex-shrink:0}
/* v1.45.0：账套内侧栏底部的「设置」单入口 —— 描边强调，和业务模块视觉区分 */
.nav-item.solo{margin-top:6px;border:1px solid var(--border);background:var(--surface-2)}
.nav-item.solo:hover{border-color:var(--border-2)}
.nav-item.solo.active{border-color:var(--primary);background:var(--primary-soft);color:var(--primary)}
/* v1.45.0：设置中心聚合页（组织 / 集成 / 系统 三类卡片） */
.hub-head{margin-bottom:16px}
.hub-title{font-size:20px;font-weight:700}
.hub-sub{font-size:12.5px;color:var(--text-2);margin-top:4px}
/* v1.46.3：grid-auto-rows:1fr —— 跨行的所有卡片也等高（不止同一行）；
   标题栏与条目保持原高，多余空间由卡片本体吸收 */
.hub-grid{display:grid;grid-template-columns:repeat(3,1fr);grid-auto-rows:1fr;gap:14px}
.hub-cat{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);box-shadow:var(--shadow);overflow:hidden}
.hub-cat-t{display:flex;align-items:center;gap:8px;padding:12px 14px;border-bottom:1px solid var(--border);font-size:13px;font-weight:600}
.hub-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
.hub-dot.is-org{background:var(--primary)}
.hub-dot.is-integ{background:var(--warn)}
.hub-dot.is-sysc{background:var(--text-3)}
.hub-n{margin-left:auto;font-size:11px;color:var(--text-3);font-weight:400}
.hub-entry{display:flex;align-items:center;gap:12px;padding:12px 14px;cursor:pointer;transition:.13s;border-bottom:1px solid var(--border)}
.hub-entry:last-child{border-bottom:0}
.hub-entry:hover{background:var(--surface-2)}
.hub-ic{width:34px;height:34px;border-radius:9px;background:var(--surface-3);display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0}
.hub-tx{min-width:0}
.hub-t{font-size:13.5px;font-weight:500}
.hub-d{font-size:11.5px;color:var(--text-3);margin-top:2px;line-height:1.5}
.hub-go{margin-left:auto;color:var(--text-3);font-size:15px;opacity:0;transition:.13s}
.hub-entry:hover .hub-go{opacity:1;color:var(--primary)}
@media(max-width:1000px){ .hub-grid{grid-template-columns:1fr} }
.side-foot{padding:10px 16px;border-top:1px solid var(--border);font-size:11px;color:var(--text-3)}
/* 收起态（mini）：只剩图标。品牌标志**保留**（只藏文字），头部改竖排以容纳标志 + 收起按钮。
   ⚠ 宽屏下「悬停临时展开」是**纯 CSS**：把这组收起规则整体挂在 :not(:hover) 上 —— 鼠标一进侧栏
     规则就失效，自然回到上面的展开态样式，不必逐个写恢复值（也就不用维护两份「反规则」）。
   ⚠ 必须限 min-width：窄屏（≤860px）侧栏是抽屉式、且下方媒体查询把 mini 强制成展开态，
     若这里也用 :not(:hover)，窄屏会因「手指没有 hover」而恒真，直接把抽屉样式打坏。 */
@media (min-width:861px){
  .sidebar.mini{ position:relative; z-index:40; }
  /* 头部高度两态钉死同一个值：悬停展开只换排列方向与尺寸，**高度不变**。
     否则头部一高一矮，下面的导航图标会跟着上下跳，鼠标就「指不准」了（实测差 4.5px）。
     收起态用**横排一行**（标志 + 收起按钮），不用竖排：68px 窄栏里竖排两个元素会各占一段、
     中间留一条空缝，看着像两个孤立控件；横排后是一组紧凑的「品牌 + 操作」，视觉上才成立。 */
  .sidebar.mini .side-head{ height:60px; padding:0 6px; gap:4px; flex-direction:row; justify-content:center; }
  /* 标志尺寸两态一致（不缩放），只把收起按钮缩小 —— 品牌不该比操作按钮还弱，缩小标志会主次颠倒 */
  .sidebar.mini .side-collapse{ width:28px; height:28px; }
  /* 分组标题：**完全收起**时藏起来（68px 栏宽放不下「客户与供应商」这种中文分组名）。
     ⚠ 悬停临时展开时**必须显示** —— 展开出来的是一整列图标，没有分组标题就分不清哪个模块属于哪一组
     （用户反馈：展开态有分组名，收起后悬停展开，分组名没了）。
     代价是临时展开比收起态高几个标题的高度，但侧栏本身可滚动，不影响命中。 */
  .sidebar.mini .nav-group-title{ display:none; }
  .sidebar.mini:hover .nav-group-title{ display:block; }
}
/* 悬停临时展开 = 视觉浮层，不是布局变化：
   `width` 增加多少，就用等量负 margin-right 抵消掉多少占位 ⇒ 侧栏在 flex 里占的宽度恒为 68px，
   主内容区（含表格列宽）绝不位移；又因 z-index 高于 .main，展开的部分直接盖在内容之上。 */
@media (min-width:861px) and (hover:hover){
  .sidebar.mini:hover{
    width:var(--sidebar-w);
    margin-right:calc(var(--sidebar-w-min) - var(--sidebar-w));
    box-shadow:var(--shadow-lg);
  }
  .sidebar.mini:hover .side-head{ flex-direction:row; padding:0 12px; justify-content:space-between; }
  /* 悬停展开时按钮恢复展开态尺寸 —— 由小变大的「胀开」正是展开该有的反馈 */
  .sidebar.mini:hover .side-collapse{ width:34px; height:34px; }
}
/* 收起态几何（写在这一段，是为了压在「:hover 展开」之后生效）：
   ① 未悬停时；② 刚点过「收起」、鼠标还赖在按钮上时（.nopeek）—— 后者若不管，侧栏会被自身的
   :hover 立刻重新撑开，用户看到的就是「点了收起没反应」。鼠标真正离开侧栏后由 JS 摘掉 .nopeek。 */
@media (min-width:861px){
  .sidebar.mini:not(:hover),
  .sidebar.mini.nopeek{ width:var(--sidebar-w-min); margin-right:0; box-shadow:none; }
  .sidebar.mini.nopeek .side-head{ flex-direction:row; padding:0 6px; }
  .sidebar.mini:not(:hover) .logo,
  .sidebar.mini.nopeek .logo{ justify-content:center; }
  .sidebar.mini:not(:hover) .logo .txt,
  .sidebar.mini:not(:hover) .nav-item span.txt,
  .sidebar.mini.nopeek .logo .txt,
  .sidebar.mini.nopeek .nav-item span.txt{ display:none; }
  .sidebar.mini:not(:hover) .nav-item,
  .sidebar.mini.nopeek .nav-item{ justify-content:center; }
  /* 「刚点过收起、鼠标还赖在收起按钮上」时侧栏仍是收起态，但 :hover 成立 ⇒ 上面的
     `.mini:hover .nav-group-title{display:block}` 会误开。这一条靠「同特异性、后来者胜」压住它。 */
  .sidebar.mini.nopeek .nav-group-title{ display:none; }
  /* 底部版本说明在 68px 栏宽里会被切碎 —— 收起态藏起来，悬停临时展开时再出现
     （版本号在顶栏徽标上一直可见，不影响查版本）。
     v1.46.1：账套标识条**不再整体隐藏** —— 效果图口径是「收起态只剩色点」：
     横条与账套名藏起、只留色点居中；悬停临时展开时整条恢复。 */
  .sidebar.mini:not(:hover) .side-foot .ver,
  .sidebar.mini.nopeek .side-foot .ver{ display:none; }
  .sidebar.mini:not(:hover) .set-bar,
  .sidebar.mini.nopeek .set-bar{ padding:10px 0 4px; }
  .sidebar.mini:not(:hover) .set-bar .accent-bar,
  .sidebar.mini.nopeek .set-bar .accent-bar,
  .sidebar.mini:not(:hover) .set-bar .row .txt,
  .sidebar.mini.nopeek .set-bar .row .txt{ display:none; }
  .sidebar.mini:not(:hover) .set-bar .row,
  .sidebar.mini.nopeek .set-bar .row{ justify-content:center; }
}

.main{flex:1;display:flex;flex-direction:column;min-width:0}
.topbar{height:60px;display:flex;align-items:center;gap:12px;padding:0 18px;background:var(--surface);border-bottom:1px solid var(--border)}
.menu-btn{display:none}
/* v1.46.2：ui-kit.css 在本文件之后又声明了一次 .icon-btn{display:inline-flex}，
   同特异性下后者胜出，把上一行覆盖掉 —— 汉堡按钮在桌面端空占 34px+间距，
   面包屑被挤到中间。用 .topbar 前缀提特异性钉死隐藏（手机端媒体查询里同样加前缀放行）。 */
.topbar .menu-btn{display:none}
.page-title{font-size:17px;font-weight:650;flex-shrink:0}
/* v1.45.1 设置中心子页面包屑：「设置」可点回中心 */
.crumb-back{color:var(--primary);cursor:pointer;border-bottom:1px dashed transparent;transition:border-color .15s,color .15s}
.crumb-back:hover{border-bottom-color:var(--primary)}
.crumb-sep{color:var(--text-3);margin:0 7px;font-weight:400}
.top-actions{margin-left:auto;display:flex;align-items:center;gap:8px}
.search-input{background:var(--surface-2);border:1px solid var(--border);border-radius:10px;padding:8px 12px;width:200px;outline:none}
.search-input:focus{border-color:var(--primary);background:var(--surface)}
.user-chip{display:flex;align-items:center;gap:8px;padding:4px 10px 4px 4px;border-radius:30px;background:var(--surface-2);cursor:pointer}
.avatar{width:30px;height:30px;border-radius:50%;background:var(--primary);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:13px}
.uname{font-weight:600;font-size:13px}
/* v1.46.3：四周间距缩小 1/3（22→15px）；单卡片视图撑满内容区，
   让底边距与另外三边永远一致（以前卡片按内容自然收高，底部空隙忽大忽小） */
.content{flex:1;overflow-y:auto;padding:15px}
.content > .card:only-child{min-height:100%;display:flex;flex-direction:column}
.content > .card:only-child .tbl-wrap{flex:1 1 auto;min-height:0;max-height:none}
.content > .card:only-child .list-more{flex-shrink:0}

/* ---------- 卡片/通用 ---------- */
.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);box-shadow:var(--shadow);padding:18px}
.card-title{font-weight:650;font-size:15px;margin-bottom:14px;display:flex;align-items:center;justify-content:space-between}
.row{display:flex;gap:14px;flex-wrap:wrap}
.grid{display:grid;gap:14px}
.muted{color:var(--text-2)}
.tiny{font-size:12px;color:var(--text-3)}

/* KPI */
/* ⚠ 数值别再放大：25px 的金额在 10 张卡铺满一屏时太抢眼，和下面的表格抢注意力。
   21px + 常规字距，金额仍然清晰可读，但整屏视觉重心回到表格上。 */
/* ⚠ 固定 6 列、共 12 张 ⇒ 永远是「2 行 × 6 个」（v1.28.8：卡数从 10 涨到 12 后
   5 列会折成三行 5+5+2，用户点名要两行；同时卡片支持拖拽重排，顺序存 localStorage）。
   侧边栏收起/展开只改变内容区宽度，1fr 会让卡片自己变宽变窄，行数不跳。
   用 minmax(0,1fr) 而不是裸 1fr：金额很长时裸 1fr 的最小内容宽会把列撑破。 */
.kpi-grid{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:14px;margin-bottom:6px}
/* KPI 拖拽重排：抓起半透明 + 虚线描边示意落点 */
.kpi[draggable="true"]{cursor:grab}
.kpi.dragging{opacity:.4;outline:2px dashed var(--primary);outline-offset:-2px}
.kpi{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:15px 18px;box-shadow:var(--shadow);position:relative;overflow:hidden}
.kpi .k-label{font-size:12.5px;color:var(--text-2)}
.kpi .k-val{font-size:21px;font-weight:650;margin-top:5px;letter-spacing:0;white-space:nowrap}
/* 窗口变窄时先收字号，别让金额被截断（5 列平分后每张卡只剩 ~170px） */
@media(max-width:1400px){ .kpi .k-val{font-size:19px} }
@media(max-width:1200px){ .kpi .k-val{font-size:17px} .kpi{padding:13px 14px} }
.kpi .k-ic{position:absolute;right:14px;top:14px;font-size:22px;opacity:.5}
/* 保留结构（历史遗留）：仪表盘已不再给单张卡加 accent，全部 KPI 一视同仁 */
.kpi.accent{background:linear-gradient(135deg,var(--primary),#7c79f0);color:#fff;border:none}
.kpi.accent .k-label{color:rgba(255,255,255,.85)}
.kpi.accent .k-ic{opacity:.9}

/* 表格 */
.toolbar{display:flex;align-items:center;gap:10px;margin-bottom:14px;flex-wrap:wrap}
.toolbar .spacer{flex:1}
/* ⭐ 数据表 = 自带滚动容器：表头吸顶 + 横向滚动条常驻可视区底部。
   以前 `.tbl-wrap` 只有 overflow-x，按规范另一轴的 visible 会被算成 auto 且高度不设限 ⇒
   它虽然是滚动容器，却永远没有纵向可滚空间，<th> 的 sticky 也就从不生效（用户反馈的「上滚表头跟着跑」）。
   现在给它一个高度上限（主列表由 UI.fitTables() 精确撑满剩余视口，其余表格 66vh），
   sticky 才有意义，横向滚动条也正好停在盒子底边 = 屏幕底部。 */
.tbl-wrap{overflow:auto;border:1px solid var(--border);border-radius:var(--radius);background:var(--surface);max-height:66vh}
/* 弹窗里的表格不钉高度：弹窗自带滚动容器，再钉一层会出现两条竖滚动条 */
.modal-body .tbl-wrap{max-height:none;overflow:visible}
/* ⚠ 弹窗宽度通常只有 620px 出头，而 .tbl 有 min-width:640px 的下限；
   配合上面的 overflow:visible，表格会比容器宽出 ~14px 并从圆角边框右侧「戳出去」，
   表现为明细表头右边悬着一小块凸出的色块（销售/采购订单详情的履约明细表最明显）。
   弹窗里的详情表列数少，按容器宽度自适应即可；真放不下时 nowrap 内容仍会自然撑开。 */
.modal-body .tbl-wrap > table.tbl{min-width:0}
table.tbl{width:100%;border-collapse:collapse;font-size:13.5px;min-width:640px}
/* 带冻结列的表必须用分离边框：collapse + sticky 单元格是 Chrome 的绘制怪癖组合 ——
   钉住投影（box-shadow）会被吞掉不渲染，而伪元素亮条反而正常，极具误导性。
   separate + border-spacing:0 与 collapse 视觉一致（单元格只有 border-bottom，无列边框）。 */
table.tbl.has-frz{border-collapse:separate;border-spacing:0}
/* 表格落在窄容器里（报表/仪表盘的半宽卡片等）时，640px 的下限会把表格顶出容器，
   表现为右侧列被裁 + 底部多条横向滚动条；这些表格按容器宽度自适应即可。 */
table.tbl.tbl-fit{min-width:0}
table.tbl.tbl-fit th,table.tbl.tbl-fit td{padding-left:12px;padding-right:12px}
/* v1.46.3：行高缩小约 1/4（43px→33px），一屏能多容 1/4 的行 */
.tbl th,.tbl td{text-align:left;border-bottom:1px solid var(--border);white-space:nowrap}
/* v1.46.4：行高回调到 38px（v1.46.3 的 35px 略挤，用户定稿 38） */
.tbl th{padding:8px 14px}
.tbl td{padding:7.5px 14px}
/* 吸顶表头：必须不透明 + 高一层 z-index；border-collapse 下边框会随内容滚走，
   所以下边线改用 inset 阴影画（否则滚动时表头与首行之间会「漏」出一条 1px 的缝）。 */
.tbl th{background:var(--surface-2);color:var(--text-2);font-weight:600;font-size:12.5px;position:sticky;top:0;z-index:2;box-shadow:inset 0 -1px 0 var(--border)}
.tbl tr:hover td{background:var(--surface-2)}
/* 可排序表头：三态（升/降/取消），未选中时不显示箭头，避免每列表头都挂个符号显得吵 */
.th-sort{cursor:pointer;user-select:none}
.th-sort:hover{color:var(--text);background:var(--surface-3)}
.th-sort .sort-ind{font-style:normal;font-size:9px;margin-left:5px;opacity:.75;display:inline-block;min-width:7px}
.th-sort.asc,.th-sort.desc{color:var(--primary)}
.th-sort:focus-visible{outline:2px solid var(--ring);outline-offset:-2px}
/* 长文本列（名称/描述/地址）允许换行，但必须给最小宽度：
   表格在窄屏下会把「可换行」的中文列压到只剩 1 个字宽（表现为逐字竖排），
   min-width 让浏览器宁可横向滚动也不压瘪内容。表头同列一起给。 */
/* 所有列表表格一律不换行（v1.18.0 用户要求）：长文本列靠拖宽/横向滚动看。
   保留 .wrap 这个类名只为了兼容老代码，行为已经和普通单元格一致。 */
.tbl th.wrap,.tbl td.wrap{white-space:nowrap}
.budget-badge{display:inline-block;padding:2px 9px;border-radius:20px;font-size:12px;font-weight:600}
.b-money{background:var(--success-soft);color:var(--success)}
.b-success{background:var(--success-soft);color:var(--success)}
.b-info{background:var(--info-soft);color:var(--info)}
.b-warn{background:var(--warn-soft);color:var(--warn)}
.b-default{background:var(--surface-2);color:var(--text-2)}
.b-danger{background:var(--danger-soft);color:var(--danger)}
.empty{padding:50px;text-align:center;color:var(--text-3)}

/* 列表底栏：「已显示 x / 共 N 条」+ 加载更多。
   ⚠ 必须放在 .tbl-wrap 外面 —— 放在表格里做最后一行时，表格一横向滚动
     它就跟着跑到视口右边、被裁成「共 422 条 · 已…」，按钮更是看不见。 */
.list-more{margin-top:10px;display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  padding:9px 14px;border:1px solid var(--border);border-radius:var(--radius-sm);
  background:var(--surface-2);font-size:12.5px;color:var(--text-3);line-height:1.6}
.list-more[hidden]{display:none}
.list-more .lm-info b,.list-more .lm-done b{color:var(--text-2);font-weight:650}
.list-more .lm-spacer{flex:1 1 auto;min-width:8px}
.list-more .btn{margin:0}
.list-more.is-done{justify-content:center;padding:7px 14px}

/* 表单 */
.field{margin-bottom:14px;display:flex;flex-direction:column;gap:5px}
.field label{font-size:12.5px;color:var(--text-2);font-weight:500}
.field input,.field select,.field textarea{background:var(--surface-2);border:1px solid var(--border);border-radius:10px;padding:9px 11px;outline:none;width:100%}
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--primary);background:var(--surface)}
.field textarea{min-height:70px;resize:vertical}
/* 字段行内说明（v1.64.0）：所属公司为什么必选 / 为什么选不了，直接写在字段下面 */
.field-hint{font-size:11.5px;line-height:1.5;color:var(--text-3);margin-top:-1px}
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 16px}
.form-grid .field.full{grid-column:1/-1}

/* 明细 repeater */
.items-tbl{width:100%;border-collapse:collapse}
.items-tbl th{font-size:12px;color:var(--text-2);text-align:left;padding:6px 8px}
.items-tbl td{padding:4px 6px}
.items-tbl input{width:100%;background:var(--surface-2);border:1px solid var(--border);border-radius:8px;padding:7px 8px}
.items-actions{margin-top:8px;display:flex;justify-content:space-between;align-items:center}

/* 进度条 */
.bar{height:8px;background:var(--surface-2);border-radius:6px;overflow:hidden;min-width:80px;display:inline-block;width:120px;vertical-align:middle}
.bar > i{display:block;height:100%;background:var(--primary);border-radius:6px}

/* 弹窗遮罩（v1.28.8 方案B）：去掉磨砂模糊，改纯变暗 —— 细看仍能辨认背景内容，
   焦点完全交给弹窗，且零 backdrop-filter 开销（低配机开弹窗不再掉帧）。 */
.scrim-bg{position:fixed;inset:0;background:rgba(15,23,42,.45);display:flex;align-items:center;justify-content:center;z-index:50;padding:20px}
[data-theme="dark"] .scrim-bg{background:rgba(4,7,13,.62)}
.modal{background:var(--surface);border-radius:18px;box-shadow:var(--shadow-lg);width:680px;max-width:100%;max-height:90vh;display:flex;flex-direction:column;animation:pop .15s ease}
@keyframes pop{from{transform:translateY(8px) scale(.98);opacity:0}to{transform:none;opacity:1}}
.modal-head{padding:18px 22px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between}
.modal-head h3{font-size:16px}
.modal-body{padding:20px 22px;overflow-y:auto}
.modal-foot{padding:14px 22px;border-top:1px solid var(--border);display:flex;justify-content:flex-end;gap:10px}
/* 输入弹框（UI.prompt）表单排版，沿用登录框视觉 */
.form-stack{display:flex;flex-direction:column;gap:14px}
.form-row{display:flex;flex-direction:column;gap:6px}
.form-row label{font-size:12px;color:var(--text-2)}
.form-row .login-input{background:var(--surface-2);border:1px solid var(--border);border-radius:10px;padding:11px 12px;outline:none;transition:.15s;color:var(--text);width:100%;box-sizing:border-box}
.form-row .login-input:focus{border-color:var(--primary);background:var(--surface)}
/* 外部同步（wolai / Notion 两条独立入站通道） */
.ext-note{background:var(--surface-2);border:1px solid var(--border);border-left:3px solid var(--primary);border-radius:10px;padding:10px 12px;font-size:13px;line-height:1.65;color:var(--text-2)}
.ext-pill{display:inline-block;padding:2px 9px;border-radius:999px;font-size:12px;font-weight:500;background:var(--surface-2);color:var(--text-2);border:1px solid var(--border);white-space:nowrap}
.ext-pill.ok{background:var(--success-soft);color:var(--success);border-color:transparent}
.ext-pill.err{background:var(--danger-soft);color:var(--danger);border-color:transparent}
.ext-pill.warn{background:var(--warn-soft);color:var(--warn);border-color:transparent}
/* v1.44.1 徽标语义着色：info=跟随上级/跟随全局（蓝）、acc=公司级覆盖（主题色） */
/* ⚠ var(--accent) 从未定义过（v1.44.1 踩坑）：acc 一度整条失效回退灰色，改用 --primary */
.ext-pill.info{background:var(--info-soft);color:var(--info);border-color:transparent}
.ext-pill.acc{background:color-mix(in srgb,var(--primary) 16%,transparent);color:var(--primary);border-color:color-mix(in srgb,var(--primary) 42%,transparent)}
code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px;background:var(--surface-2);border:1px solid var(--border);padding:1px 5px;border-radius:6px}

/* tabs */
.tabs{display:flex;gap:4px;border-bottom:1px solid var(--border);margin-bottom:16px;flex-wrap:wrap}
.tab{padding:9px 14px;cursor:pointer;color:var(--text-2);border-bottom:2px solid transparent;font-weight:500}
.tab.active{color:var(--primary);border-bottom-color:var(--primary)}

/* toast：样式已统一收到 ui-kit.css（v1.59.0 改成底部居中浮条）。
   这里曾经也有一份「顶部居中 + 实心色块」的定义，两处并存时谁后加载谁生效，
   改一处不动另一处就会「改了没反应」—— 所以直接删掉，只留一个来源。 */

/* 权限 checkbox */
.perm-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px}
.perm-item{display:flex;align-items:center;gap:8px;padding:8px 10px;border:1px solid var(--border);border-radius:9px;font-size:13px}
/* ⚠ ui-kit 的 .field input{width:100%} 与本条同权重但后加载 ⇒ 不加 !important 复选框会被撑满整行，
   把后面的说明文字挤成「一字一行」（v1.24.1 改文案时才暴露：实测 input 606px、b 25px×150px）。 */
.perm-item input{width:16px!important;height:16px!important;flex:0 0 16px!important}
/* v1.51.6：权限行内「开合」语义的圆形勾选改胶囊开关——.switch 需盖过上面 16px !important 钉死 */
.perm-item input.switch,.perm-sel input.switch{width:38px!important;height:21px!important;flex:0 0 38px!important}
.perm-item b{flex:1 1 auto;min-width:0}

/* ------------------------------------------------------------
   角色页 · 批量换绑（v1.76.0）
   ------------------------------------------------------------ */
.bulk-note{margin:0 0 12px;font-size:12.5px;line-height:1.7;color:var(--text-2)}
.bulk-note b{color:var(--text);font-weight:600}
.bulk-tools{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.bulk-tools .mod-q{flex:1 1 auto;min-width:0}
.bulk-hit{font-size:12px;color:var(--text-3);white-space:nowrap}
.bulk-count{font-size:12.5px;font-weight:600;color:var(--primary);white-space:nowrap}
/* ⚠ 必须带 .modal-body 前缀：`.modal-body .tbl-wrap{max-height:none;overflow:visible}`
   特异性更高，光写 .bulk-wrap 盖不住 ⇒ 列表无限长、表头 sticky 也不生效 */
.modal-body .bulk-wrap{max-height:46vh;overflow:auto}
.bulk-tbl{min-width:0}
/* hidden 属性对 tr 会被 .tbl 的 display 规则顶掉，这里显式写死 */
.bulk-tbl tr[hidden]{display:none}
.bulk-tbl th.bulk-chk,.bulk-tbl td.bulk-chk{width:38px;padding-right:0}
.bulk-tbl .bulk-chk input{margin:0;display:block}
/* v1.77.0：角色列统一改用 .rtag 徽标，旧的 .bulk-role 纯文字样式已弃用；
   这里改成目标角色下拉旁那枚颜色预览的容器 */
.bulk-prev{display:inline-flex;align-items:center;gap:5px;flex:0 0 auto}
.bulk-prev-hint{font-size:12px;color:var(--text-3)}
.bulk-dept{color:var(--text-2)}
.bulk-target{display:flex;align-items:center;gap:10px;margin-top:12px;padding-top:12px;border-top:1px solid var(--border);flex-wrap:wrap}
.bulk-target label{font-size:13px;color:var(--text-2);flex:none}
/* ⚠ 宽度必须写在**.ui-sel 外层容器**上：select 会被控件增强器包进 <div class="ui-sel">，
   而 .ui-sel 默认 display:block;width:100% —— 只给 select 设宽度时视觉上照样占满整行，
   「换到」被挤到上一行、右侧留一大片空白（实测第一版就是这样） */
.bulk-target .ui-sel{width:240px;flex:0 0 240px;max-width:100%}
.bulk-target select{width:100%;max-width:100%}
.bulk-warn{font-size:12px;color:var(--warn)}
/* 手机端去掉「部门」列：五列在 390px 下必然横向溢出、右侧被硬裁成「内容缺一块」的观感，
   而部门在手机上是最次要的信息（同名用户主要靠用户名区分） */
@media(max-width:560px){
  .bulk-tbl th:nth-child(5),.bulk-tbl td:nth-child(5){display:none}
}

/* 字段只读态（列级权限不可写） */
.field-ro input,.field-ro select,.field-ro textarea{background:var(--surface-2)!important;color:var(--text-2);opacity:.85;cursor:not-allowed}
.ro-tag{font-size:11px;color:var(--text-2);background:var(--surface-2);border:1px solid var(--border);border-radius:6px;padding:1px 6px;margin-left:4px}
/* wolai 同步来源标记：与「只读（权限）」区分开 —— 一个是口径以外部为准，一个是没权限 */
.ro-tag.sync{color:var(--accent);border-color:color-mix(in srgb,var(--accent) 40%,transparent);background:color-mix(in srgb,var(--accent) 10%,transparent)}
/* wolai 同步提示条（v1.63.2 分四档 / v1.63.3 加重）：按「这次改动到底会不会真的上 wolai」配色。
   绿=会推；红=确定不会推（闸门关着，要人动手去开）；蓝=单向只读（本地改了会被覆盖）；红虚线=状态没法确认。
   v1.63.3：用户反馈橙色「不会推送」不够醒目（改动真的丢了），改成红色系并加重底色与左缘；
   与「状态未知」用**实心 vs 虚线**区分：确定不会推 = 红实线 + 加粗胶囊；无法确认 = 红虚线 + 浅胶囊。
   颜色仍只上左缘细条 + 状态胶囊 + 关键字，正文用常规文字色，避免整块染色导致可读性下降。 */
.sync-note{
  --sn:var(--accent);
  margin:0 0 14px;padding:10px 12px;border-radius:10px;font-size:12.5px;line-height:1.6;color:var(--text-2);
  background:color-mix(in srgb,var(--sn) 8%,transparent);
  border-left:3px solid var(--sn);
}
.sync-note.is-ok{--sn:var(--success)}
.sync-note.is-info{--sn:var(--info)}
/* 确定不会推送：红实线 + 更重的底 + 加粗胶囊（四档里最"扎眼"的一档） */
.sync-note.is-stop{--sn:var(--danger);background:color-mix(in srgb,var(--danger) 13%,transparent);border-left-width:4px}
.sync-note.is-stop .sn-tag{font-weight:700;border-color:var(--danger);background:color-mix(in srgb,var(--danger) 26%,transparent)}
/* 状态无法确认：同为红色但虚线左缘 + 浅胶囊，表示"不确定"而非"确定不行" */
.sync-note.is-danger{--sn:var(--danger)}
.sync-note.is-danger{border-left-style:dashed}
/* 兼容旧类名（历史上 is-warn 就是"闸门关着"那一档，勿再新增使用） */
.sync-note.is-warn{--sn:var(--danger)}
/* 同步范围的单元横幅（v1.63.3）：原来用内联 style + 未定义变量，深色主题会落回浅蓝底，
   与整页深色界面割裂；收敛成主题变量驱动的类，wolai / Notion 两处共用。 */
.sync-banner{
  background:color-mix(in srgb,var(--info) 12%,transparent);
  color:var(--text-2);border-left:3px solid var(--info);
  border-radius:0 10px 10px 0;padding:8px 12px;font-size:12px;line-height:1.75;margin-bottom:12px;
}
.sync-banner b{color:var(--text)}
.sync-banner .sb-hl{color:var(--info);font-weight:600}
.sync-note b{color:var(--text)}
/* 状态胶囊：小圆点 + 短语，第一眼就知道「会 / 不会」 */
.sync-note .sn-tag{
  display:inline-flex;align-items:center;gap:5px;margin-right:7px;padding:1px 8px;
  border-radius:999px;font-size:11.5px;font-weight:600;line-height:1.7;white-space:nowrap;vertical-align:1px;
  color:var(--sn);border:1px solid color-mix(in srgb,var(--sn) 42%,transparent);
  background:color-mix(in srgb,var(--sn) 15%,transparent);
}
.sync-note .sn-tag::before{content:'';width:6px;height:6px;border-radius:50%;background:var(--sn);flex:0 0 6px}
/* 关键字（「不会被推送」「不上传」…）跟着状态色走，比加粗更醒目 */
.sync-note .sn-hl{color:var(--sn);font-weight:600}
.sync-note .sn-hl-u{border-bottom:1px dashed color-mix(in srgb,var(--sn) 55%,transparent)}

/* 同步方向分段单选（v1.35.2 按方向配色）：深色轨道 + 选中项为「方向色」胶囊（拉=蓝 / 推=橙 / 双向=绿），一眼读出当前方向 */
.dir-seg{display:inline-flex;gap:2px;padding:3px;border:1px solid var(--border);border-radius:999px;background:color-mix(in srgb,var(--text) 6%,var(--surface-2));vertical-align:middle}
.dir-btn{appearance:none;border:0;background:transparent;color:var(--text-2);font-size:13px;line-height:1.4;padding:4px 14px;border-radius:999px;cursor:pointer;transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.dir-btn:hover:not(:disabled):not(.on){background:var(--surface-3);color:var(--text)}
.dir-btn.on{color:#fff;font-weight:500}
.dir-btn.on[data-dir="pull"]{background:var(--info)}
.dir-btn.on[data-dir="push"]{background:var(--warn)}
.dir-btn.on[data-dir="both"]{background:var(--success)}
.dir-btn:disabled{opacity:.4;cursor:not-allowed;pointer-events:none}
.dir-btn.busy{opacity:.6;pointer-events:none}
/* 卡标题右侧的一键批量分段：动作按钮没有选中态，悬停时文字亮起对应方向色作预览 */
.dir-btn-sm{font-size:12px;padding:3px 10px}
.dir-batch .dir-btn[data-dir="pull"]:hover:not(:disabled){color:var(--info)}
.dir-batch .dir-btn[data-dir="push"]:hover:not(:disabled){color:var(--warn)}
.dir-batch .dir-btn[data-dir="both"]:hover:not(:disabled){color:var(--success)}
/* 卡头方向示意（A2 形态 + 方向配色）：「账套库 ← wolai」两端写明，颜色随方向（蓝拉/橙推/绿双向） */
.dir-arrow{display:inline-flex;align-items:center;gap:7px;margin-left:10px;padding:3px 12px;border-radius:999px;font-weight:500;font-size:13px;white-space:nowrap;border:1px solid transparent}
.dir-arrow.a-pull{color:var(--info);background:color-mix(in srgb,var(--info) 14%,transparent);border-color:color-mix(in srgb,var(--info) 45%,transparent)}
.dir-arrow.a-push{color:var(--warn);background:color-mix(in srgb,var(--warn) 14%,transparent);border-color:color-mix(in srgb,var(--warn) 45%,transparent)}
.dir-arrow.a-both{color:var(--success);background:color-mix(in srgb,var(--success) 14%,transparent);border-color:color-mix(in srgb,var(--success) 45%,transparent)}
/* v1.44.1 三态补色：noline=中性灰（连接可用但没实体参与）；off=黄（已停用/未启用）；broken=红（未配置令牌，连不上） */
.dir-arrow.a-noline{color:var(--text-2);background:var(--surface-2);border-color:var(--border)}
.dir-arrow.a-off{color:var(--warn);background:color-mix(in srgb,var(--warn) 14%,transparent);border-color:color-mix(in srgb,var(--warn) 45%,transparent)}
.dir-arrow.a-broken{color:var(--danger);background:var(--danger-soft);border-color:transparent}
/* v1.44.2 连接卡卡头：标题+徽标紧邻在左、说明文字居中、方向徽标贴右缘（原先被 space-between 均匀撑散） */
.conn-head{flex-wrap:wrap;row-gap:6px}
.conn-head .ch-l{display:inline-flex;align-items:center;min-width:0;gap:8px}
.conn-head .ch-l .ext-pill{font-weight:400}
.conn-head .ch-m{flex:1;text-align:center;font-weight:400;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.conn-head .ch-r{margin-left:auto}
/* v1.44.2 同步进行中徽章：页签行里一眼可见（裸 7px 圆点太隐蔽，用户实测「看不见」） */
.run-badge{display:inline-flex;align-items:center;gap:7px;margin-left:12px;align-self:center;padding:3px 12px;border-radius:999px;font-size:12.5px;font-weight:500;color:var(--warn);background:var(--warn-soft);border:1px solid color-mix(in srgb,var(--warn) 40%,transparent);white-space:nowrap}
.run-badge .run-dot{margin-left:0}
.dir-arrow-name{font-weight:400;opacity:.85}
/* 数据同步页（modules/sync.js） */
.sync-top{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-bottom:14px}
.sync-kv{display:flex;flex-direction:column;gap:8px}
.sync-kv>div{display:flex;justify-content:space-between;gap:12px;align-items:baseline}
.sync-kv>div>span{color:var(--text-2);font-size:12.5px;flex-shrink:0}
.sync-kv b{font-weight:600;text-align:right;min-width:0;overflow:hidden;text-overflow:ellipsis}
/* 下拉不能被右侧的 flex 压缩：给最小宽度并禁止收缩，否则「每 15 分钟」会被截成「每 1…」 */
.sync-kv b .sync-sel{flex-shrink:0}
.sync-acts{margin-top:12px}
.sync-sel{height:30px;min-width:118px;border:1px solid var(--border);border-radius:8px;background:var(--surface);color:var(--text);padding:0 8px;font:inherit;font-size:12.5px}
.sync-tbl td.num,.sync-tbl th.num{text-align:right;font-variant-numeric:tabular-nums}
/* 凭据 + 令牌掩码同一行（v1.63.1）：原来掩码是块级 div，会把「公司级令牌」挤成两行、行高忽高忽低 */
.sync-cred{display:inline-flex;align-items:center;gap:6px;flex-wrap:nowrap;white-space:nowrap;max-width:100%}
.sync-cred>.ext-pill{flex:0 0 auto}
.sync-cred>.muted{overflow:hidden;text-overflow:ellipsis}
.sync-plus{color:var(--success);font-weight:600}
.sync-chg{color:var(--warn);font-weight:600}
.sync-del{color:var(--danger);font-weight:600}
.sync-warn{color:var(--warn)}
.sync-err{color:var(--danger);font-size:12px;white-space:normal}
.sync-sum{padding:4px 0 10px;font-size:13px;color:var(--text-2)}
.sync-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.sync-chk{ display:inline-flex; align-items:center; cursor:pointer }
.sync-chk input{width:16px;height:16px;cursor:pointer}
/* 胶囊开关（ui-kit.css .switch）的行内对齐：开关与文字基线对齐，不撑行高 */
.switch-line{ display:inline-flex; align-items:center; gap:9px; cursor:pointer; }
.switch-line input[type="checkbox"].switch{ flex:none; }
/* 关系列「有名字、但 ERP 还没建档」：显示原名（虚线下划线提示可点查/待建档），不吞成 — */
.rel-raw{color:var(--text-2);border-bottom:1px dashed var(--border);cursor:help}
/* 「同步执行」页签上的进行中圆点（v1.44.0）：在任何页签都能看到正在跑，不用切回去确认 */
.run-dot{width:7px;height:7px;border-radius:50%;background:var(--warn);margin-left:7px;flex:none;animation:runDot 1.2s var(--ease) infinite}
@keyframes runDot{0%,100%{opacity:1}50%{opacity:.25}}
@media (prefers-reduced-motion:reduce){ .run-dot{animation:none} }
@media(max-width:860px){ .sync-top{grid-template-columns:1fr} }

/* ============ 履约看板（跨合同的「本周待办」） ============ */
.bd-top{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:14px;padding:11px 16px}
.bd-week{font-size:13.5px;color:var(--text-2);white-space:nowrap}
.bd-week b{color:var(--text);margin-right:6px}
/* 口径说明：强调块（左 3px 主题色条 + 主题色 8% 淡底），与全站其它「关键口径」块同一套语言 */
.bd-note{margin:-2px 0 14px;padding:10px 13px;border-radius:10px;font-size:12.5px;line-height:1.7;color:var(--text-2);
  background:color-mix(in srgb,var(--accent) 8%,transparent);border-left:3px solid var(--accent)}
.bd-note b{color:var(--text);font-weight:600}
.bd-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.bd-card{padding:14px 16px;display:flex;flex-direction:column;min-width:0}
.bd-head{display:flex;align-items:center;gap:8px;font-size:14px}
.bd-ic{display:inline-flex;color:var(--primary);font-size:16px;line-height:1}
.bd-side{margin-left:auto;font-size:11.5px;color:var(--text-3)}
.bd-kpi{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin:10px 0 12px}
.bd-kpi b{font-size:21px;font-weight:700;letter-spacing:.2px;font-variant-numeric:tabular-nums}
.bd-kpi span{font-size:12px;color:var(--text-2)}
.bd-hot{color:var(--danger);font-style:normal;font-weight:600}
/* 看板里的表不占满屏：四张卡并排，单卡内滚动，不把页面拉长 */
.bd-card .tbl-wrap{max-height:32vh}
.bd-tbl{min-width:0}
.bd-tbl th,.bd-tbl td{padding:8px 10px;font-size:12.5px}
.bd-tbl .num{text-align:right;font-variant-numeric:tabular-nums}
.bd-code{font-variant-numeric:tabular-nums}
.bd-party{max-width:190px;overflow:hidden;text-overflow:ellipsis}
.bd-due{white-space:nowrap;font-variant-numeric:tabular-nums}
.bd-late{display:inline-block;margin-left:6px;font-size:11px;color:var(--danger);background:var(--danger-soft);border-radius:6px;padding:0 5px}
.bd-row{cursor:pointer}
/* 分段行：本周 / 逾期两段的标题，压暗一点，不抢明细的注意力 */
.bd-sep td{padding:6px 10px;font-size:11px;color:var(--text-3);background:var(--surface-2);letter-spacing:.3px;font-weight:600}
.bd-sep:hover td{background:var(--surface-2)}
.bd-foot{margin-top:8px;font-size:11.5px;color:var(--text-3);line-height:1.55}
@media(max-width:980px){ .bd-grid{grid-template-columns:1fr} }

/* 订单详情 · 履约区块（三张子表的汇总 + 明细） */.fv-sum{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-top:4px}
.fv-kpi{border:1px solid var(--border);border-radius:10px;padding:10px 12px;background:var(--surface-2)}
.fv-kpi-t{font-size:12px;color:var(--text-2);display:flex;align-items:center;gap:6px}
.fv-kpi-v{font-size:17px;font-weight:600;margin-top:3px;font-variant-numeric:tabular-nums;display:flex;align-items:baseline;gap:6px}
.fv-kpi-p{font-size:11.5px;font-weight:400;color:var(--text-2);margin-left:auto;font-variant-numeric:tabular-nums}
.fv-kpi-s{margin-top:5px;display:flex;align-items:center;gap:8px}
.fv-kpi-bar{height:4px;border-radius:3px;background:var(--border);margin-top:7px;overflow:hidden}
.fv-kpi-bar i{display:block;height:100%;background:var(--primary);border-radius:3px}
/* wolai 手工状态与子表推导不一致：标题行右侧亮警示图标（不常显文字），悬停看合并提示 */
.fv-kpi-d{margin-left:auto;color:var(--warn);cursor:help;display:inline-flex;align-items:center}
.fv-kpi-d:hover{filter:brightness(1.25)}
@media(max-width:760px){ .fv-sum{grid-template-columns:1fr} }

/* 角色 · 列级权限编辑器 */
.perm-super{margin-top:6px}
.perm-modules{display:flex;flex-direction:column;gap:10px;max-height:46vh;overflow-y:auto;padding-right:4px}
/* ⚠ 必须 flex:0 0 auto：.perm-modules 是「限高 + 滚动」的纵向 flex 容器，
   不加这一条时各模块会被压扁到 18px（实测 head 58px 被 overflow:hidden 裁掉，整块权限矩阵只剩一条条细边）。
   正确表现＝模块保持自然高度、容器自己滚动。 */
.perm-mod{flex:0 0 auto;border:1px solid var(--border);border-radius:12px;overflow:hidden}
.perm-mod-head{display:flex;align-items:center;gap:8px;padding:10px 12px;background:var(--surface-2);flex-wrap:wrap}
.perm-mod-head .ic{font-size:16px}
.perm-mod-head b{margin-right:auto}
/* 标签不许折行：模块头是 flex + flex-wrap，挤压时「查看 / 编辑 / 范围」会被拆成一字一行，
   宁可整组换到下一行。 */
.perm-sel{font-size:12.5px;color:var(--text-2);display:flex;align-items:center;gap:5px;white-space:nowrap;flex:0 0 auto}
.perm-sel select{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:5px 8px;font-size:12.5px;color:var(--text)}
/* 面层文字带箭头留白，宽度跟原生 select 等宽时「全部数据」会被截成「全…」⇒ 给包裹层兜底最小宽 */
.perm-sel .ui-sel{min-width:112px}
/* v1.52.1：说明文字独立行（原挤在 head 里会把开关顶得不靠右）——head 内只留 图标+标题+开关 */
.perm-mod-note{padding:2px 12px 9px;font-size:11.5px;color:var(--text-3);line-height:1.5}
.link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:12.5px;padding:2px 4px}
.link:hover{text-decoration:underline}
.perm-cols{padding:8px 12px;display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:4px 18px}
/* ⚠ 类选择器的 display 会盖掉浏览器对 [hidden] 的默认 display:none（UA 样式优先级更低），
   于是「列权限 ▾」这个折叠按钮点了没反应、每个模块的列清单一直摊开，表单长得没法用。 */
.perm-cols[hidden]{display:none}
.col-row{display:flex;align-items:center;gap:10px;padding:4px 0;font-size:13px;border-bottom:1px dashed var(--border)}
.col-name{flex:1;color:var(--text)}
.col-chk{display:flex;align-items:center;gap:4px;font-size:12px;color:var(--text-2)}

/* 应收应付对账页 */
.kpi-mini{display:flex;flex-direction:column;background:var(--surface-2);border:1px solid var(--border);border-radius:10px;padding:8px 14px}
.kpi-mini span{font-size:12px;color:var(--text-2)}
.kpi-mini b{font-size:18px;margin-top:2px}
.fin-row{cursor:pointer}
.fin-row:hover{background:var(--surface-2)}
.b-warn-t{color:var(--warn);font-weight:700}
.b-info-t{color:var(--info);font-weight:700}
.fin-detail{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px}
.fin-detail-col .tbl-wrap{border:none}
@media(max-width:760px){ .fin-detail{grid-template-columns:1fr} }
.b-danger-t{color:var(--danger);font-weight:700}
.row-danger{background:var(--danger-soft)}
.row-danger:hover{filter:brightness(1.03)}
/* 应开应收（v1.70.0）：明细区的小计行与「这张合同还没有发票」说明 */
.id-empty{padding:10px 2px;font-size:12.5px;color:var(--text-3)}
.id-total{padding:8px 2px 2px;font-size:12.5px;color:var(--text-2)}
/* 账龄分段 */
.age-buckets{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;margin:14px 0}
.age-bk{display:flex;flex-direction:column;gap:4px;background:var(--surface-2);border:1px solid var(--border);border-radius:10px;padding:10px 12px}
.age-bk span{font-size:12px;color:var(--text-2)}
.age-bk b{font-size:17px}
.age-bk.hot{border-color:var(--danger);background:var(--danger-soft)}
.age-bk.hot b{color:var(--danger)}
@media(max-width:760px){ .age-buckets{grid-template-columns:repeat(2,1fr)} }

/* 移动端抽屉 */
.scrim{display:none;position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:40}
@media(max-width:860px){
  .topbar .menu-btn{display:inline-flex}
  .sidebar{position:fixed;left:0;top:0;bottom:0;z-index:45;transform:translateX(-100%);transition:transform .2s;width:var(--sidebar-w)!important}
  .sidebar.open{transform:none}
  .scrim.show{display:block}
  .sidebar.mini{width:var(--sidebar-w)!important}
  .sidebar.mini .side-head{flex-direction:row;padding:16px 16px 10px}
  .sidebar.mini .logo{display:flex;justify-content:flex-start}
  .sidebar.mini .logo .txt,.sidebar.mini .nav-group-title,.sidebar.mini .nav-item span.txt{display:block}
  .sidebar.mini .nav-item{justify-content:flex-start}
  .search-input{width:120px}
  .uname{display:none}
  /* 窄屏（平板/手机）5 列会挤到看不清金额，退回 2 列 */
  .kpi-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .content{padding:10px}
  .form-grid{grid-template-columns:1fr}
}
@media(max-width:520px){
  .search-input{display:none}
  .kpi-grid{grid-template-columns:1fr 1fr}
  .kpi .k-val{font-size:17px}
}

/* ===== 账套相关 ===== */
.set-chip{display:inline-flex;align-items:center;gap:6px;padding:5px 11px;border-radius:20px;background:var(--surface-2);border:1px solid var(--border);color:var(--text-2);font-size:13px;font-weight:500;white-space:nowrap}
.set-chip:hover{color:var(--text);border-color:var(--primary)}
.login-form select{width:100%;padding:11px 13px;border:1px solid var(--border);border-radius:10px;background:var(--surface);color:var(--text);font-size:14px;margin-bottom:4px;outline:none}
.login-form select:focus{border-color:var(--primary)}
.set-mg-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:14px;flex-wrap:wrap}
.set-mg-head h2{margin:0;font-size:18px}

/* ===== 合同附件（订单详情区块 + 批量归档）=====
   附件是「看/取文件」的场景，视觉上要比履约 KPI 更安静：
   不用彩色大块，只用细边框分组 + 状态胶囊表达进度。 */
.at-wrap{margin:14px 0}
.at-sec{border:1px solid var(--border);border-radius:var(--radius);background:var(--surface);padding:14px 16px}
.at-hd{display:flex;align-items:center;gap:10px;margin-bottom:12px;flex-wrap:wrap}
.at-hd .spacer{flex:1}
.at-t{font-size:14px;font-weight:600;color:var(--text);letter-spacing:.2px}
.at-sec .btn-sm{display:inline-flex;align-items:center;gap:5px}

/* wolai 侧期望的文件名：唯一能说明「应该有哪份文件」的线索，如实并列 */
.at-wolai{display:flex;align-items:center;gap:10px;padding:8px 11px;border-radius:var(--radius-sm);
  background:var(--surface-2);border:1px solid var(--border);margin-bottom:10px;flex-wrap:wrap}
.at-wolai.at-miss{border-left:3px solid var(--warn);background:var(--warn-soft)}
.at-wolai.at-none{opacity:.75}
.at-k{font-size:12px;color:var(--text-3);white-space:nowrap;flex:0 0 auto}
.at-v{font-size:12.5px;color:var(--text);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.at-tag{font-size:11.5px;padding:1px 7px;border-radius:999px;background:var(--surface-3);color:var(--text-2);
  border:1px solid var(--border);white-space:nowrap;flex:0 0 auto}
.at-miss .at-tag{background:var(--warn-soft);color:var(--warn);border-color:var(--warn)}

/* 文件行 */
.at-list{display:flex;flex-direction:column;gap:1px;border:1px solid var(--border);border-radius:var(--radius-sm);overflow:hidden}
.at-item{display:flex;align-items:center;gap:10px;padding:9px 11px;background:var(--surface)}
.at-item + .at-item{border-top:1px solid var(--border)}
.at-item:hover{background:var(--surface-2)}
.at-item.at-lost{background:var(--danger-soft)}
.at-lost .f-ico{opacity:.55}
/* 文件类型图标（v1.70.0）：纸页 + 右上折角 + 左下品牌色徽块 + 徽块内矢量字形。
   构图照真图标来（Windows 资源管理器 / Notion 里那套），不再是「彩色方块 + 白色类型字」；
   字形是 path/circle/rect，没有一个 <text> 依赖字体。
   切「经典 emoji」时整体换成对应的书本/图片 emoji（由全站 data-icons 开关驱动）。 */
.f-ico{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:30px;height:34px;line-height:0}
.f-ico .f-s{display:block;width:30px;height:34px}
.f-ico .f-pg{fill:var(--f-paper,#f2f5f9);stroke:rgba(15,23,32,.14);stroke-width:.7}
.f-ico .f-fold{fill:var(--f-fold,#ccd6e2);stroke:rgba(15,23,32,.10);stroke-width:.5}
.f-ico .f-tile{fill:var(--f-c,#6b7785)}
.f-ico .f-e{display:none;font-size:17px;line-height:1;font-style:normal}
html[data-icons="emoji"] .f-ico{width:auto}
html[data-icons="emoji"] .f-ico .f-s{display:none}
html[data-icons="emoji"] .f-ico .f-e{display:inline}
/* 深色主题：纸页压暗一点点，避免一排白块在深底上发白刺眼（仍保持「白纸」的辨识度） */
html[data-theme="dark"] .f-ico{--f-paper:#e6ecf4;--f-fold:#bfcbda}
/* 品牌色：PDF 红 / Word 蓝 / Excel 绿 / PPT 橙 / 图片紫 / 压缩包金 / 视频紫 / 音频琥珀 / 文本灰 */
.f-ico-pdf{--f-c:#d5342a}
.f-ico-doc{--f-c:#2b579a}
.f-ico-xls{--f-c:#1e7145}
.f-ico-ppt{--f-c:#c43e1c}
.f-ico-img{--f-c:#7c5cbf}
.f-ico-zip{--f-c:#a07a2b}
.f-ico-vid{--f-c:#8e44ad}
.f-ico-aud{--f-c:#b9761c}
.f-ico-txt{--f-c:#5b6773}
.f-ico-file{--f-c:#6b7785}

.at-main{flex:1;min-width:0}
.at-nm{font-size:13px;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.at-mt{font-size:11.5px;color:var(--text-3);margin-top:2px}
.at-warn{color:var(--danger)}
/* v1.71.0：附件 ↔ 远端同步状态。四态用「中性/弱强调」区分，不用四种高饱和色 ——
   这里是状态说明，不是告警；只有「被保护跳过」才值得让人停下来看一眼。 */
.at-sync{display:inline-block;margin-left:6px;padding:0 6px;border-radius:20px;font-size:10.5px;
  line-height:16px;vertical-align:1px;border:1px solid transparent;white-space:nowrap}
.at-sync-ok{color:var(--success);border-color:color-mix(in srgb,var(--success) 38%,transparent);
  background:var(--success-soft)}
.at-sync-wait{color:var(--text-2);border-color:var(--border);background:var(--surface-2)}
.at-sync-remote{color:var(--text-3);border-color:var(--border);background:transparent}
.at-sync-skip{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 42%,transparent);
  background:var(--warn-soft);cursor:help}
.at-acts{flex:0 0 auto;display:flex;gap:2px}
.at-btn{background:none;border:0;color:var(--text-2);font-size:12.5px;padding:4px 8px;border-radius:6px;cursor:pointer;font-family:inherit}
.at-btn:hover{background:var(--surface-3);color:var(--text)}
.at-btn.at-del:hover{background:var(--danger-soft);color:var(--danger)}
.at-empty{font-size:12.5px;color:var(--text-3);padding:14px 4px;text-align:center}
/* v1.74.0：已忽略的远端文件（删除墓碑）。中性一条，不用警示色 ——
   它不是错误，是用户自己做的决定；只有「恢复」按钮需要可点。 */
.at-tomb{display:flex;align-items:center;gap:8px;margin-top:6px;padding:6px 10px;
  border-radius:8px;background:var(--surface-2);font-size:12.5px;color:var(--text-3);min-width:0}
.at-tomb-t{display:inline-flex;align-items:center;gap:5px;flex:0 0 auto;color:var(--text-2)}
.at-tomb-t .ico-e,.at-tomb-t svg{width:13px;height:13px;opacity:.8}
.at-tomb-n{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;cursor:help}
.at-tomb .at-btn{flex:0 0 auto;color:var(--text-2)}
.at-tomb .at-btn:hover{background:var(--surface-3);color:var(--text)}
/* ============ v1.75.0：附件保护（锁定 / 解锁） ============
   配色约定：
     锁定   = 中性（var(--text-3)）—— 「常态」，不需要引起注意；
     已解锁 = 琥珀（var(--warn)）  —— 「临时状态」，需要一眼看出现在可以改；
     到期   = 回到中性            —— 与锁定同色，因为语义已经回到锁定。
   不要用红色表示锁定：红色在这套界面里专指危险/失败，锁定是保护措施，不是错误。 */
.at-guard{display:inline-flex;align-items:center;gap:5px;margin-right:8px;padding:0 8px;
  height:22px;border-radius:20px;font-size:11.5px;white-space:nowrap;border:1px solid transparent}
.at-guard .ico-e,.at-guard svg{width:12.5px;height:12.5px;opacity:.85}
.at-guard-lock{color:var(--text-3);border-color:var(--border);background:var(--surface-2)}
.at-guard-open{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 42%,transparent);
  background:var(--warn-soft)}
.at-guard-open b{font-weight:500;font-variant-numeric:tabular-nums;font-family:ui-monospace,monospace}
.at-guard-exp{color:var(--text-3);border-color:var(--border);background:var(--surface-2)}
.at-btn-xs{padding:2px 7px;font-size:11.5px;border:1px solid var(--border)}
.at-btn-xs:hover{border-color:var(--border-2,var(--border))}
.at-lock-note{display:flex;align-items:center;gap:6px;margin-top:6px;padding:6px 10px;
  border-radius:8px;background:var(--surface-2);font-size:11.5px;color:var(--text-3)}
.at-lock-note .ico-e,.at-lock-note svg{width:12.5px;height:12.5px;flex:0 0 auto;opacity:.75}
.ff-guard{display:flex;align-items:center;gap:8px;margin-bottom:8px}
/* 解锁对话框：字段用表单原样式会太宽，这里收窄并按「说明 → 原因 → 补充」的顺序排 */
.at-unlock{min-width:320px}
.at-ul-tip{font-size:12.5px;color:var(--text-2);line-height:1.65;margin-bottom:4px}
.at-ul-lb{display:block;font-size:12px;color:var(--text-2);margin:12px 0 5px}
.at-ul-lb i{color:var(--danger);font-style:normal;margin-left:2px}
.at-ul-sel,.at-ul-ta{width:100%;box-sizing:border-box;background:var(--surface-2);
  border:1px solid var(--border);border-radius:7px;padding:7px 10px;font-size:12.5px;
  color:var(--text);font-family:inherit}
.at-ul-ta{resize:vertical;line-height:1.55}
.at-ul-foot{margin-top:10px;font-size:11.5px;color:var(--text-3)}
/* v1.72.0：附件卡片嵌在「编辑表单」末尾时（订单 / 发票共用），与上方字段区之间
   要有一条明确的分区边界 —— 否则最后一个输入框下面紧接一张带标题的卡片，
   看起来像「某个字段的附属控件」，用户找不到它是独立的一块。
   这是分区边界，不是表格行间线（后者一律不要）。 */
.at-form-card{border-top:1px solid var(--border);padding-top:14px;margin-top:20px}

/* 字段级附件（v1.67.0）：「文件和媒体」类型的字段控件
   —— 编辑表单里跟输入框同宽同高节奏，详情页里跟在其它字段块下面 */
.ff-host{min-width:0}
.ff-host .ff-list{margin-bottom:8px}
.ff-host .ff-list .at-item{padding:7px 9px}
.ff-acts{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.ff-acts .tiny{color:var(--text-3)}
.field-ro .ff-acts{display:none}

/* 批量归档弹窗 */
/* ⚠ 不能写 min-width:680px —— .modal 只有 680 宽、减掉两侧 22px 内边距后内容区更窄，
   min-width 会把内容顶出弹窗右边界（表现为「开始归档」旁边的「取消」被裁掉一半）。 */
.at-batch{width:100%;min-width:0}
.at-note{background:var(--surface-2);border:1px solid var(--border);border-left:3px solid var(--primary);
  border-radius:var(--radius-sm);padding:11px 13px;font-size:12.5px;line-height:1.7;color:var(--text-2);margin-bottom:14px}
.at-note b{color:var(--text)}
/* 只有开头那句小标题独占一行；正文里的 <b> 是强调，必须保持内联，
   否则「文件名」这类词会被 display:block 切成独立一行，整段读起来支离破碎。 */
.at-note>b:first-child{display:block;margin-bottom:3px}
.at-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:12px}
.at-bar-end{margin-top:16px;margin-bottom:0;justify-content:flex-end}
.at-kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-bottom:14px}
.at-kpi{background:var(--surface-2);border:1px solid var(--border);border-radius:var(--radius-sm);padding:9px 11px;text-align:center}
.at-kpi b{display:block;font-size:18px;color:var(--text);line-height:1.3}
.at-kpi span{font-size:11.5px;color:var(--text-3)}
.at-kpi.at-kpi-warn{border-color:var(--warn);background:var(--warn-soft)}
.at-kpi.at-kpi-warn b{color:var(--warn)}
.at-sub{font-size:12.5px;font-weight:600;color:var(--text-2);margin:14px 0 8px}
.at-sub-warn{color:var(--warn)}
.at-tbl-wrap{max-height:280px;overflow:auto;border:1px solid var(--border);border-radius:var(--radius-sm)}
.at-tbl-wrap table.tbl{min-width:0}
.at-fn{max-width:380px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.at-un{font-size:12px;color:var(--text-3);background:var(--surface-2);border:1px solid var(--border);
  border-radius:var(--radius-sm);padding:9px 11px;max-height:160px;overflow:auto;line-height:1.8}

@media(max-width:760px){
  .at-kpis{grid-template-columns:repeat(2,1fr)}
  .at-batch{min-width:0}
  .at-item{flex-wrap:wrap}
  .at-acts{width:100%;justify-content:flex-end}
  .at-fn{max-width:180px}
}

/* ============================================================
   顶栏：全局筛选（所属公司 / 年份）+ 全局搜索面板（v1.18.0）
   ============================================================ */
/* 宽度必须给死，而且要抬一级优先级：ui-kit.css 在 styles.css **之后**引入，
   它里面的 .search-input{width:100%} 会盖掉单纯 .gfilter 的宽度（现象是下拉只剩「全部…」）。
   select.gfilter 是 (0,1,1)，比 .search-input 的 (0,1,0) 高一级，稳定生效。 */
select.gfilter{width:112px;max-width:none;flex:0 0 auto;font-size:13px;padding:7px 9px;cursor:pointer}
/* ⚠ widgets.js 的 enhanceSelect 把 <select> 包成 .ui-sel + 面层，真正占位的是**外层 wrap**：
   只给 select 设宽度，wrap 仍按 flex 收缩，面层文字就被压成「202…」。必须同时钉住 wrap。 */
.ui-sel:has(> select.gfilter){width:112px;max-width:none;flex:0 0 auto}
/* 年份要多放两个字「（当年）」：单独加宽，别把公司下拉一起撑胖 */
select#gYear{width:130px}
.ui-sel:has(> #gYear){width:130px;max-width:none;flex:0 0 auto}
.ui-sel:has(> select.gfilter) > .ui-sel-face{padding:0 26px 0 9px;font-size:13px}
.gsearch{position:relative;flex-shrink:1}
.gsearch .search-input{width:230px}
.gs-pop{position:absolute;top:calc(100% + 8px);right:0;width:min(480px,86vw);max-height:min(66vh,540px);overflow:auto;
  background:var(--surface);border:1px solid var(--border);border-radius:12px;
  box-shadow:0 16px 40px rgba(0,0,0,.18);padding:6px;z-index:80}
.gs-hd{padding:8px 10px 4px;font-size:12px;color:var(--text-3)}
.gs-hd b{color:var(--text);font-size:13px}
.gs-grp{margin-top:2px}
.gs-gt{display:flex;align-items:center;gap:6px;padding:8px 10px 4px;font-size:11.5px;font-weight:700;
  color:var(--text-3);letter-spacing:.02em}
.gs-cnt{margin-left:auto;font-weight:600;background:var(--surface-2);border-radius:20px;padding:1px 8px;font-size:11px}
/* 选中态：贴左缘 3px 强调条 + 淡底，不画多余的线、不圆角（与表格选中态同一套规矩） */
.gs-item{position:relative;display:flex;flex-direction:column;gap:2px;padding:7px 10px;border-radius:8px;cursor:pointer}
.gs-item:hover{background:var(--surface-2)}
.gs-item.on{background:var(--surface-2);box-shadow:inset 3px 0 0 var(--primary)}
.gs-t{font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gs-s{font-size:11.5px;color:var(--text-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gs-more{padding:4px 10px 8px;font-size:11.5px;color:var(--text-3)}
.gs-empty{padding:14px 12px;font-size:12.5px;color:var(--text-3);line-height:1.7}

/* ---------- 列表状态条：任何过滤都要看得见 ---------- */
.list-state{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:8px 14px;
  border-bottom:1px solid var(--border);background:var(--surface-2);font-size:12.5px;color:var(--text-2)}
.list-state[hidden]{display:none}
.list-state .ls-k{font-weight:700;color:var(--primary)}
.list-state .ls-c{background:var(--surface);border:1px solid var(--border);border-radius:20px;padding:1px 9px}
.list-state .ls-sep{color:var(--text-3)}
.list-state .ls-n{margin-left:2px;color:var(--text-3)}
.list-state .ls-n b{color:var(--text);font-variant-numeric:tabular-nums}
/* 顶栏筛选对本表不适用时的说明：中性色，不用主题色 —— 这不是「在筛」 */
.list-state .ls-na{color:var(--text-2)}
.list-state .ls-na b{color:var(--text);font-variant-numeric:tabular-nums}
.list-state .ls-clear{margin-left:auto}
/* 仪表盘 / 报表 顶部的「统计范围」：同样的状态条外观，但要自己独立成块 */
.list-state.state-note{border:1px solid var(--border);border-radius:10px;margin-bottom:12px}

/* 全局搜索命中的关键字：主体文字不变色，只给淡底 + 下划线，深浅主题都读得清 */
mark.kw{background:color-mix(in srgb, var(--primary) 30%, transparent);
  color:inherit;border-radius:3px;padding:0 1px;font-weight:600;
  box-shadow:inset 0 -1px 0 color-mix(in srgb, var(--primary) 65%, transparent)}

/* ---------- 筛选 / 排序 / 分组 浮层 ---------- */
.fpop{position:fixed;z-index:120;min-width:210px;max-width:290px;max-height:min(60vh,460px);overflow:auto;
  background:var(--surface);border:1px solid var(--border);border-radius:12px;
  box-shadow:0 16px 40px rgba(0,0,0,.18);padding:6px}
.fp-hd{display:flex;align-items:center;gap:6px;padding:7px 9px 6px;font-size:12.5px;font-weight:700;color:var(--text)}
.fp-hd span{font-weight:400;font-size:11px;color:var(--text-3);margin-left:auto}
.fp-back{border:none;background:none;color:var(--text-2);cursor:pointer;font-size:14px;padding:0 2px;line-height:1}
.fp-list{display:flex;flex-direction:column}
.fp-i{display:flex;align-items:center;gap:8px;width:100%;text-align:left;border:none;background:none;
  color:var(--text);font:inherit;font-size:13px;padding:7px 9px;border-radius:8px;cursor:pointer}
.fp-i:hover{background:var(--surface-2)}
.fp-i.on{background:var(--surface-2);box-shadow:inset 3px 0 0 var(--primary)}
.fp-i .fp-v{margin-left:auto;font-size:11px;color:var(--text-3);white-space:nowrap}
.fp-empty{padding:12px 10px;font-size:12px;color:var(--text-3)}

/* ---------- 分组行 ---------- */
.tbl tr.grp-row td{background:var(--surface-2);font-weight:700;position:sticky;z-index:1;
  border-top:1px solid var(--border);padding-top:8px;padding-bottom:8px}
.tbl tr.grp-row .grp-t{color:var(--text)}
.tbl tr.grp-row .grp-n{margin-left:8px;font-weight:500;font-size:11.5px;color:var(--text-3)}

@media(max-width:960px){
  select.gfilter{display:none}    /* 窄屏顶栏放不下：先让搜索框占住位置 */
  .ui-sel:has(> select.gfilter){display:none}   /* 自绘面层要一起藏，否则留下个空壳 */
  .gsearch .search-input{width:150px}
  .gs-pop{width:min(420px,92vw)}
}

/* ============================================================
   列宽 / 列序拖拽（v1.18.0）
   ------------------------------------------------------------
   ① 只有用户拖过之后才切 table-layout:fixed —— 没拖过的表仍按内容自适应。
   ② fixed 下内容必须 overflow:hidden，否则长文本会从单元格里横着穿出去。
   ③ min-width:100%：列宽总和不足容器时按比例撑满，避免右侧留一条空白。
   ============================================================ */
table.tbl.tbl-fixed{table-layout:fixed;min-width:100%}
table.tbl.tbl-fixed th,table.tbl.tbl-fixed td{overflow:hidden;text-overflow:ellipsis}
/* 表头右缘的调宽热区：默认不可见，悬停/拖拽时露出一条细线（交互反馈，不是装饰线） */
.colgrip{position:absolute;top:0;right:-3px;width:8px;height:100%;cursor:col-resize;z-index:3}
.colgrip::after{content:'';position:absolute;left:6px;top:24%;width:1px;height:52%;
  background:var(--border-2);opacity:0;transition:opacity var(--dur-fast) var(--ease)}
.tbl th:hover .colgrip::after{opacity:1}
.tbl.col-resizing{cursor:col-resize;user-select:none}
.col-resizing .colgrip::after{opacity:1;background:var(--primary)}
/* 拖列序：被拖的表头淡出，落点用左缘 2px 竖条标记 */
.tbl.col-dragging th{user-select:none}
.tbl th.col-drag-src{opacity:.45}
.tbl th.col-drop{box-shadow:inset 2px 0 0 var(--primary)}

/* ============================================================
   自由冻结列（方案 A · v1.47.0）· sticky 原生钉住
   ------------------------------------------------------------
   冻结列 = position:sticky; left:0（表头+全部数据格）：横向滚动时该列滑到
   最左钉住，前面的列滚出界、后面的列从它下面穿过。
   ① 背景必须不透明（--surface/--surface-2 都是不透明色），否则后面列的文字穿透；
   ② 悬停行 hover 规则 (0,2,1) 天然压过 td.frz (0,1,1)，冻结格悬停变色照常；
   ③ 钉住投影 = 每个冻结格右缘各自的窄投影（v1.47.6 用户定稿）：**只有右侧**，
      上下边零外溢 —— 技巧是扩散半径 = -模糊半径（垂直延伸 = 模糊+扩散 = 0，
      右侧延伸 = 偏移量 10px）；前提是分离边框（collapse + sticky 会吞 box-shadow）；
      不画冻结格右边框网格线；
   ④ thead th.frz 要盖过普通 sticky 表头（z2）和组头（z1），给 z4。
   ============================================================ */
th.frz, td.frz{position:sticky;left:0;z-index:2;background:var(--surface)}
thead th.frz{z-index:4;background:var(--surface-2)}
th.frz.pinned,td.frz.pinned{box-shadow:10px 0 10px -10px rgba(0,0,0,.55)}

/* 固定布局（拖过列宽/列序的表）所有列都能拖窄：表宽由 cols.js 按列宽之和显式设定
   （不能用 width:max-content —— 那会让表宽跟着内容走，列设多窄都被撑回内容宽，
   这就是「名称列拖不窄」的元凶）；超出部分省略号截断，悬停完整内容由 cols.js 补 title。
   冻结格同样截断（overflow:hidden 全格一致），不画任何网格线。 */
/* 列头 📌 开关：悬停浮现，冻结中常亮（主色） */th .pin{display:inline-block;margin-left:6px;cursor:pointer;opacity:0;transition:opacity var(--dur-fast) var(--ease);font-size:11px;color:var(--text-3)}
.tbl th:hover .pin{opacity:1}
th .pin:hover{color:var(--primary)}
th .pin.on{opacity:1;color:var(--primary)}

/* ============================================================
   报表 · 销售汇总「前 N 客户」下拉（v1.18.2）
   ------------------------------------------------------------
   ① 下拉放在卡片标题右侧：用 flex 的标题 + 工具区两段结构，别让 select
      直接当 flex item（会和标题挤在一起、换行后错位）。
   ② 表格限高内滚：以前 131 家客户把左卡撑到几千像素，右卡被拉出一大片空白。
   ============================================================ */
.card-title .rep-tools{display:inline-flex;align-items:center;gap:8px;font-weight:400}
/* ⚠ 宽度必须钉在**包裹层**（.ui-sel）上：
   ① 不能配 .is-inline —— 进入页面时包裹层还只有 70px 宽，widgets.js 的
      isFullWidth() 会因此判定「它撑满了父级」，反而不加 .is-inline；
   ② 也不能只给 select 设宽度 —— ui-kit.css 在后面加载，`.ui-sel > select.ui-native
      {width:100%}`(0,2,0) 会把它压成父级宽度，面层只剩「前…」。
   所以用 (0,3,0) 直接把包裹层定宽 132px，select 反过来吃 100%。 */
.card-title .rep-tools .ui-sel{width:132px;vertical-align:middle}
.card-title .rep-tools .ui-sel-face{font-size:13px}
#repTopN{width:100%;height:30px;font-size:13px}
.rep-scroll{max-height:calc(100vh - 330px);min-height:200px;overflow:auto}
/* 用视口高度算而不是写死 px：1080p 下能多露几行，笔记本小屏也不会把整页撑出滚动条 */
.rep-foot{margin-top:10px;font-size:12px;color:var(--text-3);line-height:1.7}
.rep-foot b{color:var(--text-2);font-weight:600}

/* ---- 多公司权限（v1.21.0）：用户表单的公司多选 + 用户列表的公司标签 ---- */
.co-chks{ display:flex; flex-wrap:wrap; gap:8px 14px; padding:4px 0 2px; }
.co-chk{ display:inline-flex; align-items:center; gap:6px; padding:3px 10px; border:1px solid var(--border); border-radius:999px; cursor:pointer; font-size:13px; }
.co-chk:hover{ border-color:var(--primary); }
/* ⚠ 必须 !important：ui-kit 里有一条 `.field input,...{width:100%}` 与
   `input[type=checkbox]{width:17px}` 同权重、但排在后面 ⇒ 勾选框会被撑成整行宽，
   把旁边的公司名挤成竖排（实测 80×20，标签变成一个大圆饼） */
.co-chk input[type="checkbox"]{ width:15px!important; height:15px!important; flex:0 0 15px!important; margin:0; padding:0!important; cursor:pointer; }
.co-chk .tiny{ margin-left:2px; }
.co-tag{ display:inline-flex; align-items:center; gap:3px; margin:1px 4px 1px 0; padding:1px 7px; border-radius:999px; background:var(--surface-2); border:1px solid var(--border); font-size:12px; white-space:nowrap; }
/* ⚠ 修饰类必须带模块前缀：写成 .co-tag.main 会撞上全局 .main 容器
   （它带 display:flex + flex-direction:column）⇒ 标签被竖着排，名字和「主」分两行 */
.co-tag.is-main{ border-color:var(--primary); color:var(--primary); }
.co-tag i{ font-style:normal; font-size:10px; padding:0 3px; border-radius:6px; background:var(--primary); color:#fff; }

/* ------------------------------------------------------------
   账套管理 · 删除确认（两步，必须非常醒目）
   ① 红色警示块 + 「里面有什么」的统计   ② 手抄账套名称才解锁删除
   ------------------------------------------------------------ */
.danger-panel{ display:flex; flex-direction:column; gap:12px; min-width:0; }
.danger-head{ display:flex; gap:14px; align-items:flex-start; padding:16px 18px;
  border-radius:var(--radius); background:var(--danger-soft); border:1px solid var(--danger); }
.danger-ico{ font-size:26px; line-height:1; flex:0 0 auto; }
.danger-title{ font-size:16px; font-weight:750; color:var(--danger); margin-bottom:4px; }
.danger-sub{ font-size:13px; line-height:1.6; color:var(--text-2); }
.danger-sub b{ color:var(--danger); }
.danger-stat{ border:1px solid var(--border); border-radius:var(--radius); padding:12px 14px; background:var(--surface-2); }
.danger-total{ font-size:13px; color:var(--text-2); margin-bottom:8px; }
.danger-total b{ color:var(--text); font-size:15px; }
.danger-chips{ display:flex; flex-wrap:wrap; gap:6px; }
.danger-chip{ font-size:12px; color:var(--text-2); background:var(--surface);
  border:1px solid var(--border); border-radius:999px; padding:3px 9px; }
.danger-chip b{ color:var(--text); }
.danger-tip{ font-size:12.5px; line-height:1.6; color:var(--warn);
  background:var(--warn-soft); border-radius:var(--radius-sm); padding:10px 12px; }
/* ⚠ 必须把外观写全：ui-kit 里全局 `input{appearance:none}` 只关掉了原生外观，
   这类「不在 .form-row 里」的输入框拿不到任何配色 —— 实测渲染成一条黑条，字看不见 */
.danger-input{ display:block; width:100%; height:46px; box-sizing:border-box;
  padding:0 14px; font-size:15px; letter-spacing:.3px;
  background:var(--surface); color:var(--text);
  border:1px solid var(--border-2); border-radius:var(--radius-sm); outline:none;
  transition:border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease); }
.danger-input::placeholder{ color:var(--text-3); font-size:13.5px; }
.danger-input:focus{ border-color:var(--danger); box-shadow:0 0 0 3px var(--danger-soft); }
.danger-input.is-ok{ border-color:var(--danger); box-shadow:0 0 0 3px var(--danger-soft); }
.danger-hint{ font-size:12px; color:var(--text-3); }
.danger-hint.ok{ color:var(--danger); font-weight:600; }
.set-ops{ white-space:nowrap; }
/* 账套管理表格（tbl-xl）· 2026-10-23：仅此页行高约 2 倍 + 正文文字放大，表头照旧。
   行高口径：td 24px 上下内边距 + 17px 字号（行框 25.5px）+ 1px 底边 ≈ 75px（普通行 38px 的 2 倍） */
table.tbl.tbl-xl{ font-size:17px; }
.tbl-xl th{ font-size:12.5px; }               /* 表头文字保持原样 */
.tbl-xl td{ padding:24px 14px; }
.tbl-xl .tiny{ font-size:14px; }              /* 「已改名」/ 代号跟随放大 */
.tbl-xl .btn-sm{ font-size:13.5px; padding:5px 16px; }  /* 行内按钮配套放大，别让 22px 小按钮卡在 75px 大行里 */

/* ------------------------------------------------------------
   审计日志
   ------------------------------------------------------------ */
.aud-head{ display:flex; justify-content:space-between; align-items:flex-start; gap:16px; margin-bottom:10px; }
.aud-head h2{ margin:0 0 4px; font-size:17px; }
.aud-head .muted{ margin:0; font-size:12.5px; line-height:1.6; }
/* 视角说明：两个审计视角互不包含 —— 与全站「关键口径」块同一套语言（左 3px 色条 + 8% 淡底） */
.aud-scope{ margin:0 0 10px; padding:9px 13px; border-radius:10px;
  font-size:12.5px; line-height:1.7; color:var(--text-2);
  background:color-mix(in srgb,var(--accent) 8%,transparent); border-left:3px solid var(--accent); }
.aud-scope b{ color:var(--text); font-weight:600; }
/* 本账套里看不见平台管理员的代管记录：这句必须读得到，否则用户会当成「日志缺了」 */
.aud-hidesys{ display:block; margin-top:7px; padding-top:7px; border-top:1px dashed var(--border); color:var(--text-2); }
.aud-hidesys b{ color:var(--primary); }
.is-sys .aud-scope,.aud-scope.is-sys{ background:color-mix(in srgb,var(--primary) 8%,transparent); border-left-color:var(--primary); }
.aud-bar{ display:flex; flex-wrap:wrap; align-items:center; gap:8px;
  padding:10px 12px; background:var(--surface-2); border:1px solid var(--border);
  border-radius:var(--radius); margin-bottom:10px; }
/* ⚠ flex:0 0 auto 不能省：默认 flex-shrink:1 会把「账套 / 类型」这类 select
   压成几十像素宽（实测只剩「全...」），看着像下拉坏了 */
.aud-f{ display:inline-flex; align-items:center; gap:6px; font-size:12px; color:var(--text-3); flex:0 0 auto; }
/* 标签不许折行：被挤窄时「开始 / 搜索」会竖着排成一列（实测过） */
.aud-f > span{ white-space:nowrap; }
.aud-f input,.aud-f select{ height:30px; font-size:12.5px; padding:0 8px;
  border:1px solid var(--border-2); border-radius:var(--radius-sm);
  background:var(--surface); color:var(--text); }
.aud-f select{ min-width:124px; }
.aud-f .aud-in{ width:130px; }
.aud-f-wide .aud-in{ width:210px; }
.aud-summary{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin-bottom:8px;
  font-size:12px; color:var(--text-2); }
.aud-count b{ color:var(--text); }
.aud-chips{ display:flex; flex-wrap:wrap; gap:6px; }
.aud-chip{ background:var(--surface-2); border:1px solid var(--border); border-radius:999px;
  padding:2px 9px; color:var(--text-3); }
.aud-chip b{ color:var(--text-2); }
.aud-tbl td{ vertical-align:middle; }
.aud-ts{ font-variant-numeric:tabular-nums; color:var(--text-2); font-size:12.5px; }
.aud-target{ font-weight:600; }
.aud-kind{ display:inline-block; font-size:11.5px; padding:2px 8px; border-radius:999px;
  background:var(--surface-2); color:var(--text-2); border:1px solid var(--border); }
.aud-kind.k-create{ color:var(--success); border-color:var(--success); background:var(--success-soft); }
.aud-kind.k-update{ color:var(--info); border-color:var(--info); background:var(--info-soft); }
.aud-kind.k-delete{ color:var(--danger); border-color:var(--danger); background:var(--danger-soft); }
.aud-kind.k-login{ color:var(--primary); border-color:var(--primary); background:var(--primary-soft); }
.aud-kind.k-set{ color:var(--warn); border-color:var(--warn); background:var(--warn-soft); }
.aud-kind.k-perm{ color:var(--primary); border-color:var(--primary); background:var(--primary-soft); }
.aud-pill{ display:inline-block; font-size:11.5px; padding:2px 8px; border-radius:999px; font-weight:600; }
.aud-pill.ok{ color:var(--success); background:var(--success-soft); border:1px solid var(--success); }
.aud-pill.fail{ color:var(--danger); background:var(--danger-soft); border:1px solid var(--danger); }
.aud-detail{ margin:0; padding:12px; background:var(--surface-2); border:1px solid var(--border);
  border-radius:var(--radius-sm); font-size:12px; line-height:1.6; white-space:pre-wrap;
  word-break:break-all; max-height:320px; overflow:auto;
  font-family:ui-monospace,Consolas,"Courier New",monospace; color:var(--text-2); }
.aud-ua{ font-size:11.5px; color:var(--text-3); word-break:break-all; line-height:1.6; }

.empty .empty-hint{ margin-left:8px; white-space:nowrap; opacity:.85; }
/* ============================================================
   组织结构（部门树）
   ------------------------------------------------------------
   形态对齐 Zoho「职位与共享」：折叠方块 + 层级虚线 + 全部展开/折叠。
   ⚠ 虚线不用 border-style:dashed —— 每行都从自己的顶端重新起相位，
     行与行接缝处会出现半截空白，看着像断线。改用 repeating-linear-gradient
     钉住 3px 实 / 4px 空的固定节拍，竖线才是一整条。
   ============================================================ */
/* 连线颜色：--border-2 在深色主题下几乎与背景同色（对比 2:1），
   虚线整个看不见；改用 --text-3 作基准，深浅两套主题都在 3:1 上下，看得清又不抢主体。 */
.org-card{ --line-org: color-mix(in srgb, var(--text-3) 82%, transparent); }
.org-card{ padding:0; overflow:hidden; }
.org-head{ padding:16px 18px 0; }
.org-head-l{ display:flex; align-items:baseline; gap:10px; flex-wrap:wrap; }
.org-h{ margin:0; font-size:16px; font-weight:650; letter-spacing:.2px; }
.org-sum{ font-size:12.5px; color:var(--text-3); font-variant-numeric:tabular-nums; }
.org-tip{ margin:6px 0 0; font-size:12.5px; line-height:1.65; color:var(--text-2); }
/* 顶栏筛选与本页口径不一致时的提示：只改变一个「胶囊」的底色，不新增整块说明（不占版面） */
.org-tip .org-gf{ display:inline-block; margin-left:6px; padding:1px 8px; border-radius:999px;
  background:var(--primary-soft); color:var(--primary); }
.org-tip .org-gf b{ font-weight:650; }
.org-card .toolbar{ margin:0; padding:12px 18px; border-bottom:1px solid var(--border); }
.org-tree{ padding:8px 18px 10px; overflow-x:auto; }

/* ---- 节点 ---- */
.org-node{ position:relative; }
.org-row{
  position:relative; display:flex; align-items:center; gap:8px;
  min-height:36px; padding:3px 6px 3px 3px; border-radius:8px;
  transition:background var(--dur-fast) var(--ease);
}
.org-row:hover{ background:var(--surface-2); }
.org-row:focus-visible{ outline:2px solid var(--ring); outline-offset:-2px; }

/* ---- 层级连线 ----
   折叠方块宽 16 + 行左内边距 3 ⇒ 方块中心落在行的 11px 处。
   子层要**缩进 26px**、同时把连线起点对回 11px：margin 15 + padding 11 = 26，
   连线 left 取 -15 ⇒ 26-15 = 11，正好压在方块中心，上下两级连线才对得齐。
   ⚠ 改缩进必须同时改 left/width，否则连线会跑偏到方块外面。 */
.org-kids{ margin-left:15px; padding-left:11px; }
/* 竖段：从本行顶端画到中线。每个节点各画自己那半截 ⇒ 连成整条，
   最后一个子节点自然停在自身中线，不会多拖出一段空线。 */
.org-kids > .org-node > .org-row::before{
  content:''; position:absolute; left:-15px; top:0; width:1px; height:50%;
  background:repeating-linear-gradient(to bottom, var(--line-org) 0 3px, transparent 3px 7px);
}
/* 横段：中线往右接到节点 */
.org-kids > .org-node > .org-row::after{
  content:''; position:absolute; left:-15px; top:50%; width:15px; height:1px;
  background:repeating-linear-gradient(to right, var(--line-org) 0 3px, transparent 3px 7px);
}

/* ---- 折叠方块 ---- */
.org-tw{
  flex:0 0 16px; width:16px; height:16px; padding:0;
  display:grid; place-items:center;
  border:1px solid var(--border-2); border-radius:3px; background:var(--surface);
  color:var(--text-2); font-size:12px; line-height:1;
  font-family:var(--font); cursor:pointer;
  transition:background var(--dur-fast), border-color var(--dur-fast), color var(--dur-fast);
}
.org-tw:hover{ background:var(--primary-soft); border-color:var(--primary); color:var(--primary); }
.org-tw.is-leaf{ border-color:transparent; background:transparent; cursor:default; }

/* ---- 文字与标记 ---- */
.org-name{ font-size:13.5px; font-weight:500; color:var(--text); white-space:nowrap; }
.org-node.is-cycle .org-name{ color:var(--warn); }
.org-code{
  font-size:11px; color:var(--text-3); border:1px solid var(--border); border-radius:4px;
  padding:0 5px; line-height:1.6; font-variant-numeric:tabular-nums; white-space:nowrap;
}
.org-mgr{ font-size:12px; color:var(--text-3); white-space:nowrap; }
.org-mgr::before{ content:'负责人 '; opacity:.65; }
.org-n{
  font-size:10.5px; color:var(--text-3); background:var(--surface-3); border-radius:9px;
  padding:1px 6px; min-width:18px; text-align:center; font-variant-numeric:tabular-nums;
}
.org-flag{
  font-size:11px; color:var(--warn); background:var(--warn-soft);
  border-radius:4px; padding:0 5px; line-height:1.7; white-space:nowrap;
}

/* ---- 行内操作 ----
   ⚠ 只在**支持悬停**的设备上默认隐藏。写成「默认隐藏 + hover 显示」的话，
     触摸屏永远等不到 hover ⇒ 按钮彻底用不了。 */
.org-act{ margin-left:auto; display:flex; gap:2px; padding-left:10px; }
@media (hover:hover){ .org-act{ opacity:0; transition:opacity var(--dur-fast); } }
.org-row:hover .org-act, .org-row:focus-within .org-act{ opacity:1; }
.org-ab{
  width:22px; height:22px; border:0; border-radius:5px; background:transparent;
  color:var(--text-3); cursor:pointer; font-size:12px; line-height:1;
  display:grid; place-items:center; padding:0;
  transition:background var(--dur-fast), color var(--dur-fast);
}
.org-ab:hover{ background:var(--surface-3); color:var(--text); }
.org-ab.danger:hover{ background:var(--danger-soft); color:var(--danger); }

/* ---- 根节点：经营主体 ----
   根就是公司，字号比部门略大、带「经营主体」标签；它的折叠方块与部门同一套尺寸，
   所以根下面的虚线仍然对齐方块中心（缩进口径不变）。 */
/* 多公司：每家经营主体的树之间加一条分割线。
   不加线时，上一家公司最深的那层部门会紧贴下一家的公司名，
   读起来像「这些部门属于下面那家公司」—— 多主体账套尤其容易看错。
   ⚠ 用相邻兄弟选择器：搜索时没有可见部门的公司根本不生成 DOM，
     所以不会留下「孤零零一条线」；也不影响第一家上面。 */
.org-node.is-root + .org-node.is-root{
  border-top:1px solid var(--border);
  margin-top:10px; padding-top:10px;
}
.org-row-root{ min-height:40px; }
.org-cname{ font-size:15px; font-weight:650; letter-spacing:.2px; }
.org-row-root .org-tag{ margin-left:2px; }
.org-tag{
  font-size:10.5px; color:var(--text-3); background:var(--surface-2);
  border:1px solid var(--border); border-radius:4px; padding:0 5px; line-height:1.7; white-space:nowrap;
}
.org-sub{ font-size:12px; color:var(--text-3); white-space:nowrap; }
.org-node.is-void > .org-row .org-cname{ color:var(--warn); }
.org-node.is-off > .org-row .org-cname{ color:var(--text-3); }
.org-none{ padding:4px 0 8px 2px; font-size:12.5px; color:var(--text-3); }
.org-link{
  border:0; background:none; padding:0; cursor:pointer; font-size:12.5px;
  color:var(--primary); text-decoration:underline; text-underline-offset:2px;
}
.org-link:hover{ color:var(--primary-hover); }

/* ---- 图例 / 空态 ---- */
.org-legend{
  display:flex; align-items:center; flex-wrap:wrap; gap:6px;
  padding:10px 18px 14px; border-top:1px solid var(--border);
  font-size:12px; color:var(--text-3);
}
.org-lg-tw{
  display:inline-grid; place-items:center; width:15px; height:15px;
  border:1px solid var(--border-2); border-radius:3px;
  font-size:11px; line-height:1; color:var(--text-2); margin-left:6px;
}
.org-lg-tw:first-child{ margin-left:0; }
.org-empty{ display:flex; flex-direction:column; align-items:center; gap:10px; }
.org-empty .tiny{ color:var(--text-3); }

/* 窄屏：负责人收进第二行，别把部门名挤成一列字 */
@media (max-width:760px){
  .org-mgr{ display:none; }
  .org-tree{ padding-left:12px; padding-right:12px; }
  .org-card .toolbar{ padding:10px 12px; }
  .org-card .toolbar .search-input{ width:100%!important; }
}

/* ============================================================
   v1.28.7
   ============================================================ */
/* 分组头吸附：上滚时当前分组名停在表头正下方（th 高 ≈ 11+11padding + 17.5行高 ≈ 40px） */
.tbl tr.grp-row td{ top:40px; }
/* KPI 卡片宽度统一：财务流水页与应收应付/账龄页的 kpi-mini 同一视觉宽度 */
.kpi-mini{ min-width:150px; }
/* KPI 数字语义色（收=绿良性 / 付=红流出 / 应收=橙待催 / 应付=蓝待付），与徽章配色同源 */
.kpi .k-val.c-success{ color:var(--success); }
.kpi .k-val.c-danger{ color:var(--danger); }
.kpi .k-val.c-warn{ color:var(--warn); }
.kpi .k-val.c-info{ color:var(--info); }
.kpi-mini b.c-success{ color:var(--success); }
.kpi-mini b.c-danger{ color:var(--danger); }
/* v1.28.8：应收合计/应付合计改纯文字色（之前误用徽章类 b-warn/b-info，数字带了一块背景底色） */
.kpi-mini b.c-warn{ color:var(--warn); }
.kpi-mini b.c-info{ color:var(--info); }
/* 组织结构图上的用户胶囊：部门/公司节点下显示归属用户 */
.org-users{ display:flex; flex-wrap:wrap; gap:4px 6px; padding:2px 0 4px 26px; }
.org-user{ display:inline-flex; align-items:center; gap:5px; padding:2px 9px 2px 3px;
  border:1px solid var(--border); border-radius:999px; background:var(--surface-2);
  font-size:12px; color:var(--text-2); line-height:1.5; white-space:nowrap; }
.org-user i{ font-style:normal; width:18px; height:18px; border-radius:50%;
  display:inline-flex; align-items:center; justify-content:center;
  background:var(--primary-soft); color:var(--primary); font-size:11px; font-weight:700; flex:none; }
.org-user.is-off{ opacity:.45; }
.org-user.is-off i{ background:var(--surface-3); color:var(--text-3); }
@media (max-width:760px){ .org-users{ padding-left:18px; } }


/* —— v1.37.1 设表弹窗 · 远端表选择面板（主题化：搜索框/行悬停/当前使用） —— */
.rt-search{display:flex;align-items:center;gap:8px;padding:8px 10px;border-bottom:1px solid var(--border);background:var(--surface-2)}
.rt-search .rt-lens{font-size:13px;color:var(--text-3);flex:none}
.rt-search input{flex:1;min-width:0;background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:8px 10px;color:var(--text);outline:none;font-size:13px;transition:border-color .15s}
.rt-search input:focus{border-color:var(--primary)}
.rt-search input::placeholder{color:var(--text-3)}
.rt-row{display:flex;gap:9px;align-items:flex-start;padding:9px 12px;border-bottom:1px solid var(--border);cursor:pointer;transition:background .12s}
.rt-row:last-child{border-bottom:none}
.rt-row:hover{background:color-mix(in srgb,var(--primary) 8%,transparent)}
.rt-row.rt-cur,
.rt-row.rt-cur:hover{background:color-mix(in srgb,var(--primary) 14%,transparent)}
.rt-name{font-size:13.5px}
.rt-row.rt-cur .rt-name{color:var(--primary)}
.rt-path{color:var(--text-3);font-size:11px;margin-left:6px}
.rt-id{color:var(--text-3);font-size:10.5px;word-break:break-all;margin-top:2px;opacity:.85}
.rt-tag{flex:none;margin-left:auto;color:var(--primary);font-size:11px;font-weight:600;align-self:center}

/* ===== Notion 字段映射编辑器（v1.48.0）行尾徽标 ===== */
.nmap-auto-b{color:var(--primary);font-size:11px;background:var(--primary-soft);border-radius:99px;padding:1px 8px}
.nmap-ovr-b{color:var(--warn);font-size:11px;background:var(--warn-soft,rgba(201,134,47,.14));border-radius:99px;padding:1px 8px}
.nmap-warn-b{color:var(--warn);font-size:11px;background:var(--warn-soft,rgba(201,134,47,.14));border-radius:99px;padding:1px 8px;font-weight:600}
/* 多列合成字段的锁定徽标（v1.49.0）：中性灰，不参与映射 */
.nmap-lock-b{color:var(--text-3);font-size:11px;background:rgba(255,255,255,.05);border-radius:99px;padding:1px 8px}
/* 待接入新列「新」徽标（v1.50.0）：绿色系 */
.nmap-new-b{color:#4fae7e;font-size:11px;background:rgba(79,174,126,.15);border-radius:99px;padding:1px 8px;font-weight:700}
/* 远端已删该列「远端已缺」徽标（v1.50.0）：红色系 */
.nmap-miss-b{color:var(--err,#c25b5b);font-size:11px;background:rgba(194,91,91,.14);border-radius:99px;padding:1px 8px;font-weight:600}
/* 字段来源徽标（v1.51.6）：内置映射 / ERP独有 / 远端动态列 */
/* v1.65.0：底色改用主题变量 —— 原来写死 rgba(255,255,255,.05) 只适合深色，
   浅色主题下等于白底白字（徽标看不见）。字段管理弹窗的分组标题也复用这几个类。 */
.nmap-map-b{color:var(--text-3);font-size:11px;background:var(--surface-3);border-radius:99px;padding:1px 8px}
.nmap-only-b{color:var(--warn,#c9862f);font-size:11px;background:var(--warn-soft,rgba(201,134,47,.14));border-radius:99px;padding:1px 8px;font-weight:600}
.nmap-dyn-b{color:#4fae7e;font-size:11px;background:rgba(79,174,126,.12);border-radius:99px;padding:1px 8px}
.nmap-cust-b{color:var(--primary);font-size:11px;background:var(--primary-soft);border-radius:99px;padding:1px 8px;font-weight:600}

/* ---- 自定义字段：类型设置面板 + 多选标签（v1.55.0） ---- */
/* 说明文字（字段名/类型下方的提示） */
.cf-hint{font-size:12px;color:var(--text-3);line-height:1.55;margin-bottom:10px}
/* 类型设置面板：虚线框，随类型切换内容 */
.cf-panel{border:1px dashed var(--border);border-radius:10px;padding:8px 12px;background:rgba(255,255,255,.015)}
.cf-line{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:7px 0}
.cf-line + .cf-line{border-top:1px solid var(--border)}
.cf-line-t{font-size:12.5px;color:var(--text);line-height:1.45;flex:1;min-width:0}
.cf-line-t span{display:block;font-size:11.5px;color:var(--text-3);margin-top:2px}
/* ⚠ 特异性必须压过 .form-row .login-input{width:100%}（0,2,0）——
   否则输入框吃满整行、左侧说明被挤成 0 宽（「默认值」竖排成一字一行）。
   故这里用 (0,3,0)，且 input 也要显式 width。 */
.cf-panel .cf-line .cf-inp{width:170px;max-width:170px;flex:none;box-sizing:border-box}
/* 下拉换肤后真正占位的是 .ui-sel 包裹层（默认 block/width:100%），
   不钉住它就会把同一行左侧的说明文字挤成一字一行。
   同理数字框（.ui-num）、日期框（.ui-date）也会被包一层，三个一起钉。 */
.cf-panel .cf-line .ui-sel,
.cf-panel .cf-line .ui-num,
.cf-panel .cf-line .ui-date{width:170px;max-width:170px;flex:none;min-width:0}
.cf-panel .cf-line .ui-sel > select.ui-native,
.cf-panel .cf-line .ui-num > input,
.cf-panel .cf-line .ui-date > input{width:100%}
/* 实体切换下拉（v1.56.0）：钉住高度，与弹窗底部按钮同高 37px
   （v1.55.0 为了对齐浮层宽度把 select 的 padding 清成 0，高度塌到 21px） */
.cf-entrow{display:flex;align-items:center;gap:8px;margin-bottom:10px}
.cf-entrow .ui-sel{display:inline-flex;width:auto;max-width:none;vertical-align:middle}
.cf-entrow .ui-sel > select.ui-native{height:37px;box-sizing:border-box;padding:0 10px;border:0;background:transparent}
.cf-entrow .ui-sel-face{font-size:13px}
.cf-none{font-size:12px;color:var(--text-3);padding:2px 0;line-height:1.7}
/* 多选标签组：编辑表单可点选；列表 / 详情里 pointer-events:none 只做展示 */
.cf-chips{display:flex;flex-wrap:wrap;gap:6px;padding-top:2px}
.cf-chip{border:1px solid var(--border);background:transparent;border-radius:14px;padding:3px 11px;
  font-size:12.5px;line-height:1.5;color:var(--text-2);cursor:pointer;transition:.14s;white-space:nowrap}
.cf-chip:not(:disabled):hover{border-color:var(--border-2);color:var(--text)}
.cf-chip.on{background:var(--primary-soft);border-color:var(--primary);color:var(--primary);font-weight:600}
.cf-chip:disabled{cursor:default;opacity:.85}
/* 列表单元格里的标签收紧一点（行高固定，不换行） */
td .cf-chips{gap:4px;padding-top:0;flex-wrap:nowrap;overflow:hidden}
td .cf-chip{padding:1px 8px;font-size:11.5px;pointer-events:none}

/* ------------------------------------------------------------
   v1.61.0 推送失败明细（modules/sync.js）
   就地展开在待推清单那一行下方。底色刻意比外层卡片「沉一层」（surface-2、无边框），
   读起来像卡片里嵌的一块，不会和主表格抢层次；展开行本身不带下边框，避免
   「表格线」和「嵌入块」两种视觉语言打架。
   ------------------------------------------------------------ */
.linkbtn{
  appearance:none;border:0;background:none;padding:0;margin:0;
  color:var(--primary);font:inherit;font-size:inherit;cursor:pointer;
  text-decoration:underline;text-decoration-style:dotted;text-underline-offset:2px;
}
.linkbtn:hover{color:var(--primary-hover)}
.linkbtn.err{color:var(--danger);text-decoration-style:solid}
.linkbtn.err:hover{opacity:.82}
.linkbtn[aria-expanded="true"]{font-weight:600;text-decoration-style:solid}

.fail-detail-row>td{padding:0 0 10px !important;border-bottom:0 !important}
.fail-holder{margin-top:10px}
.failbox{background:var(--surface-2);border:1px solid var(--border);border-radius:10px;padding:12px 14px}
.fail-hd{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:10px}
.fail-hd b{font-size:12.5px;font-weight:600}
.fail-grp+.fail-grp{margin-top:12px;padding-top:12px;border-top:1px solid var(--border)}
.fg-hd{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin-bottom:6px}
.fg-tri{
  width:0;height:0;flex-shrink:0;
  border-left:4px solid transparent;border-right:4px solid transparent;
  border-bottom:7px solid var(--warn);
}
.fg-reason{font-size:12px;color:var(--warn);word-break:break-word}
.tbl-sm{font-size:11.5px}
.tbl-sm th,.tbl-sm td{padding:5px 8px}
/* 除首列外一律压到内容宽度：行名吃掉全部剩余空间，
   否则时间戳会把列撑得很散，几行字浮在很宽的格子里很难扫。 */
.tbl-sm th+th,.tbl-sm td+td{width:1px;white-space:nowrap}
/* 行名列给个上限：不设的话它会吃掉八成这样宽，通道/次数被顶到最右边，
   中间一大片空白反而不好扫。 */
.tbl-sm th:first-child,.tbl-sm td:first-child{width:38%}
/* 操作列与「最后失败」拉开：否则「09:12:00 重推」会糊成一串 */
.tbl-sm th:last-child,.tbl-sm td:last-child{padding-left:16px}
.tbl-sm th{font-size:11px}
.tbl-sm tbody tr:hover{background:transparent}
.fail-ft{margin-top:10px;padding-top:9px;border-top:1px solid var(--border);font-size:11px;color:var(--text-3);line-height:1.7}
/* 组头的「重推这一类」：换行后也要贴右，否则会掉到原因文字左下方，看着像标题的一部分 */
.fg-hd .linkbtn{margin-left:auto}
.failbox .tbl-wrap{margin:0 -4px}
/* 手机上「最后失败」这一列可以不要：时间不是关键，行名/次数/重推才是要点的。
   去掉它之后列宽刚好收进 375px，不用左右滑。 */
@media (max-width:560px){
  /* 手机上只留「行名 / 次数 / 重推」：通道、时间都不是动手时需要的，
     留着只会把行名挤成一条缝、还得左右滑。 */
  .tbl-sm .c-t,.tbl-sm .c-ch{display:none}
  .tbl-sm th:first-child,.tbl-sm td:first-child{width:auto}
  /* ⚠ 关键：待推清单主表在手机上有 6 列、总宽 650px 左右（靠 .tbl-wrap 横滚）。
     展开行是主表的一行，td 自然也是 650px —— 明细块如果不钉住，就得横滑才能
     看见「次数」和「重推」。所以这里把它 sticky 在视口左侧并对齐视口宽度。 */
  .fail-detail-row>td{padding:0 0 10px !important}
  .failbox{
    position:sticky;left:0;box-sizing:border-box;
    width:calc(100vw - 30px);max-width:100%;
    padding:10px;
  }
}

/* ============ v1.75.0：设置 · 附件保护 ============
   与「角色与权限」的 perm-mod 不同：那里是逐项勾选，这里是三个互斥档 + 两个数值，
   所以用分段按钮而不是下拉 —— 三档的差别需要人一眼看完，不该藏在展开项里。 */
.set-guard{max-width:780px}
.sg-hd{display:flex;flex-direction:column;gap:3px;margin-bottom:14px}
.sg-hd b{font-size:14px;font-weight:500}
.sg-row{display:flex;align-items:center;gap:12px;padding:11px 0;border-top:1px solid var(--border)}
.sg-lb{flex:0 0 92px;font-size:13px;color:var(--text)}
.sg-desc{font-size:11.5px;color:var(--text-3);line-height:1.6;padding:0 0 12px 104px;margin-top:-3px}
.sg-seg{display:inline-flex;background:var(--surface-2);border:1px solid var(--border);border-radius:8px;padding:2px;gap:2px}
.sg-opt{background:none;border:0;font:inherit;font-size:12.5px;color:var(--text-2);
  padding:4px 15px;border-radius:6px;cursor:pointer}
.sg-opt:hover:not(.on){color:var(--text)}
.sg-opt.on{background:var(--primary);color:var(--primary-ink)}
.sg-in{display:inline-flex;align-items:center;gap:6px;flex:0 0 auto}
.sg-in input{width:76px;background:var(--surface-2);border:1px solid var(--border);
  border-radius:7px;padding:5px 9px;font-size:12.5px;color:var(--text);font-family:inherit}
.sg-in input:focus{outline:none;border-color:var(--primary)}
/* ⚠ 单位必须 nowrap：默认会按单字换行，「分钟」被拆成上下两行（实测过） */
.sg-in em{font-style:normal;font-size:12px;color:var(--text-3);white-space:nowrap;flex:0 0 auto}
.sg-foot{display:flex;align-items:center;gap:10px;margin-top:16px;padding-top:14px;border-top:1px solid var(--border)}
/* .spacer 只在 .toolbar / .at-hd 下带 flex:1，这里要自己给，否则保存按钮会贴在文字后面 */
.sg-foot .spacer{flex:1}

/* ============ 角色徽标（v1.77.0）============
   一个角色一个固定颜色，凡是显示角色的地方都用它（用户表 / 角色表 / 批量换绑 /
   用户详情 / 审计详情 / 编辑弹窗预览）。取色规则见 ui.js 的 UI.roleTagColor。
   形态取「淡底 + 同色圆点 + 同色文字」这一档：
     · 只给文字染色 —— 一列排下来太弱，扫不出区别；
     · 实心色块 —— 太吵，会和「状态/成功失败」那类语义标签抢注意力；
   淡底 pill 在深浅两套主题下都能一眼分开，又不遮挡内容。 */
.rtag{
  --rc:#475569; --rc-rgb:100,116,139;
  display:inline-flex; align-items:center; gap:5px;
  padding:1px 8px 1px 7px; border-radius:20px;
  font-size:12px; font-weight:600; line-height:18px; white-space:nowrap;
  vertical-align:middle;
  color:var(--rc);
  background:rgba(var(--rc-rgb),.10);
  border:1px solid rgba(var(--rc-rgb),.22);
}
/* 圆点用 currentColor：换主题 / 换色只改 --rc，圆点自动跟随 */
.rtag::before{content:''; width:6px; height:6px; border-radius:50%;
  background:currentColor; opacity:.9; flex:0 0 auto}
.rtag.rt-violet{--rc:#6d28d9; --rc-rgb:139,92,246}
.rtag.rt-teal  {--rc:#0f766e; --rc-rgb:20,184,166}
.rtag.rt-blue  {--rc:#1d4ed8; --rc-rgb:59,130,246}
.rtag.rt-amber {--rc:#b45309; --rc-rgb:245,158,11}
.rtag.rt-slate {--rc:#475569; --rc-rgb:100,116,139}
.rtag.rt-pink  {--rc:#be185d; --rc-rgb:236,72,153}
.rtag.rt-green {--rc:#15803d; --rc-rgb:34,197,94}
.rtag.rt-orange{--rc:#c2410c; --rc-rgb:249,115,22}
/* 未分配：不参与配色，虚线灰圈，明确表示「这里什么都没有」而不是某个颜色 */
.rtag.rt-none{--rc:var(--text-3); --rc-rgb:148,163,184;
  background:transparent; border-style:dashed}
.rtag.rt-none::before{display:none}
/* 深色主题：文字换成亮色版（浅色版在深底上会糊成一团），底色略提一档补对比 */
[data-theme="dark"] .rtag{background:rgba(var(--rc-rgb),.18); border-color:rgba(var(--rc-rgb),.32)}
[data-theme="dark"] .rtag.rt-violet{--rc:#c4b5fd}
[data-theme="dark"] .rtag.rt-teal  {--rc:#5eead4}
[data-theme="dark"] .rtag.rt-blue  {--rc:#93c5fd}
[data-theme="dark"] .rtag.rt-amber {--rc:#fcd34d}
[data-theme="dark"] .rtag.rt-slate {--rc:#cbd5e1}
[data-theme="dark"] .rtag.rt-pink  {--rc:#f9a8d4}
[data-theme="dark"] .rtag.rt-green {--rc:#86efac}
[data-theme="dark"] .rtag.rt-orange{--rc:#fdba74}
[data-theme="dark"] .rtag.rt-none  {--rc:var(--text-3); background:transparent}
/* 编辑弹窗里的角色预览：贴着下拉框下方一行，说明「你现在选的是哪个颜色」 */
.role-prev{display:flex; align-items:center; gap:6px; margin-top:5px; font-size:11.5px; color:var(--text-3)}
