/* ─────────────────────────────────────────────────────────
   合生雅居DBSync — 设计系统
   浅色为默认主题：门店与办公环境多为明亮场景，浅色更贴合日常；
   深色保留给夜间值守与长时间盯盘。
   ───────────────────────────────────────────────────────── */
:root {
  --rail-w: 212px;
  --topbar-h: 60px;
  --r-sm: 7px;
  --r-md: 11px;
  --r-lg: 15px;

  --bg: #090b0f;
  --bg-elev: #0e1218;
  --surface: #11161d;
  --surface-2: #161c25;
  --surface-3: #1c232e;
  --border: #242d39;
  --border-soft: #1a212b;
  --border-hover: #344152;
  --border-strong: #2f3a49;
  --line: #1e2531;

  --text: #eaf0f8;
  --text-2: #9aa7b8;
  --text-3: #66727f;

  --accent: #5b8cff;
  --accent-2: #7c5bff;
  --accent-soft: rgba(91, 140, 255, 0.13);
  --accent-line: rgba(91, 140, 255, 0.42);

  --ok: #42c46a;
  --ok-soft: rgba(66, 196, 106, 0.12);
  --warn: #e0a63e;
  --warn-soft: rgba(224, 166, 62, 0.12);
  --err: #f2555a;
  --err-soft: rgba(242, 85, 90, 0.13);
  --ins: #42c46a;
  --upd: #5b8cff;
  --del: #f2555a;

  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-2: 0 8px 28px -8px rgba(0, 0, 0, 0.55);
  --shadow-3: 0 28px 70px -18px rgba(0, 0, 0, 0.72);

  --mono: "JetBrains Mono", "Cascadia Mono", Consolas, "Courier New", monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei", "PingFang SC", sans-serif;

  --ease: cubic-bezier(0.22, 0.7, 0.3, 1);
}

[data-theme="light"] {
  --bg: #f4f6fb;
  --bg-elev: #ffffff;
  --surface: #ffffff;
  --surface-2: #f5f8fd;
  --surface-3: #eaf0f9;
  --border: #d9e1ee;
  --border-soft: #e8eef7;
  --border-hover: #b9c8de;
  --border-strong: #c3cfdf;
  --line: #e6ebf2;
  --text: #101827;
  --text-2: #4d5b6e;
  --text-3: #8b97a8;
  --accent: #2f6bf0;
  --accent-2: #6a4df0;
  --accent-soft: rgba(47, 107, 240, 0.085);
  --accent-line: rgba(47, 107, 240, 0.35);
  --ok: #17924a;
  --ok-soft: rgba(23, 146, 74, 0.1);
  --warn: #b37508;
  --warn-soft: rgba(179, 117, 8, 0.11);
  --err: #d6343c;
  --err-soft: rgba(214, 52, 60, 0.09);
  --ins: #17924a;
  --upd: #2f6bf0;
  --del: #d6343c;
  --shadow-1: 0 1px 2px rgba(16, 24, 40, 0.05);
  --shadow-2: 0 10px 26px -14px rgba(16, 24, 40, 0.2);
  --shadow-3: 0 24px 64px -20px rgba(16, 24, 40, 0.24);
}

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
  font-family: var(--sans);
  background: var(--bg);
  color: var(--text);
  font-size: 13.5px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
  position: relative;
}

/* 环境光：两团极淡的品牌色晕染，避免纯黑背景的死板 */
body::before {
  content: "";
  position: fixed; inset: 0; pointer-events: none; z-index: 0;
  background:
    radial-gradient(720px 420px at 82% -8%, rgba(124, 91, 255, 0.075), transparent 62%),
    radial-gradient(820px 480px at -6% 4%, rgba(91, 140, 255, 0.065), transparent 60%);
}
[data-theme="light"] body::before {
  background:
    radial-gradient(720px 420px at 82% -8%, rgba(106, 77, 240, 0.05), transparent 62%),
    radial-gradient(820px 480px at -6% 4%, rgba(47, 107, 240, 0.045), transparent 60%);
}
.app { position: relative; z-index: 1; }

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; }
a { color: var(--accent); text-decoration: none; }

:focus-visible { outline: 2px solid var(--accent-line); outline-offset: 1px; border-radius: 4px; }

::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 8px; border: 2px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background: var(--border-strong); background-clip: content-box; }
[data-theme="light"] ::-webkit-scrollbar-thumb { background: #c9d2df; background-clip: content-box; }

@keyframes rise { from { opacity: 0; transform: translateY(7px); } }
@keyframes fadeIn { from { opacity: 0; } }

/* ── 布局 ───────────────────────────────────────────── */
.app { display: flex; height: 100vh; }

.rail {
  width: var(--rail-w);
  flex: 0 0 var(--rail-w);
  background: var(--bg-elev);
  border-right: 1px solid var(--border-soft);
  display: flex;
  flex-direction: column;
  padding: 0 10px 12px;
  -webkit-app-region: drag;
}
.brand {
  height: var(--topbar-h);
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 0 8px;
  font-weight: 650;
  letter-spacing: -0.2px;
  font-size: 15px;
}
/* 品牌 LOGO：浅色主题用深色标记，深色主题切品牌金（双 img 由 CSS 切换，避免 JS 参与） */
.brand-mark { width: 23px; height: auto; display: block; }
.brand-mark-gold { display: none; }
[data-theme="dark"] .brand-mark { display: none; }
[data-theme="dark"] .brand-mark-gold { display: block; }
.brand-text { display: flex; flex-direction: column; line-height: 1.15; }
.brand-text b {
  font-size: 14.5px; font-weight: 680; letter-spacing: -0.1px;
  background: linear-gradient(92deg, var(--text) 20%, var(--text-2));
  -webkit-background-clip: text; -webkit-text-fill-color: transparent;
}
.brand-text small { font-size: 10.5px; font-weight: 600; letter-spacing: 1.1px; color: var(--text-3); text-transform: uppercase; }

/* 版本类型徽标（Win7 专用版）：贴在品牌下方，侧栏常驻可见。
   rail 顶部是窗口拖拽区，徽标不可交互，保持继承 drag 即可。 */
.edition-line { padding: 0 9px 8px; }
.edition-line[hidden] { display: none; }
.edition-tag {
  height: 20px; padding: 0 8px;
  font-size: 10.5px; font-weight: 650; letter-spacing: .3px;
}

.nav { display: flex; flex-direction: column; gap: 3px; margin-top: 8px; -webkit-app-region: no-drag; }
.nav-item {
  position: relative;
  display: flex; align-items: center; gap: 10px;
  height: 37px; padding: 0 11px; border-radius: var(--r-sm);
  color: var(--text-2); font-size: 13px; text-align: left;
  transition: background .15s var(--ease), color .15s var(--ease);
}
.nav-item:hover { background: var(--surface-2); color: var(--text); }
.nav-item.active { background: var(--accent-soft); color: var(--accent); font-weight: 550; }
.nav-item.active::before {
  content: ""; position: absolute; left: -10px; top: 9px; bottom: 9px; width: 3px;
  border-radius: 0 3px 3px 0; background: var(--accent);
}
.nav-item i { display: flex; width: 16px; height: 16px; }
.nav-item svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }

.rail-foot { margin-top: auto; -webkit-app-region: no-drag; }
.rail-copy { text-align: center; font-size: 10.5px; color: var(--text-3); padding-top: 8px; letter-spacing: .2px; }
.engine-state {
  display: flex; gap: 9px; align-items: center; width: 100%; text-align: left; cursor: pointer;
  padding: 10px 11px; border-radius: var(--r-md);
  background: var(--surface-2); border: 1px solid var(--border-soft);
  transition: border-color .15s var(--ease), background .15s;
}
.engine-state:hover { border-color: var(--border-hover); background: var(--surface-3); }
.engine-state .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 0 3px var(--ok-soft); flex: 0 0 7px; }
.engine-state.busy .dot { background: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); animation: pulse 1.4s infinite; }
.engine-state b { display: block; font-size: 12px; font-weight: 550; }
.engine-state small { color: var(--text-3); font-size: 11px; }
@keyframes pulse { 50% { opacity: .45; } }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; background: var(--bg); }

.topbar {
  height: var(--topbar-h); flex: 0 0 var(--topbar-h);
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 26px;
  border-bottom: 1px solid var(--border-soft);
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: blur(10px);
  -webkit-app-region: drag;
}
.topbar h1 { font-size: 16px; margin: 0; font-weight: 600; letter-spacing: -0.2px; }
.topbar p { margin: 1px 0 0; font-size: 12px; color: var(--text-3); }
.topbar-actions { display: flex; gap: 8px; align-items: center; -webkit-app-region: no-drag; }

.view { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 24px 26px 40px; }
.view > * { animation: rise .32s var(--ease) both; }

/* ── 通用控件 ────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  height: 32px; padding: 0 13px; border-radius: var(--r-sm);
  border: 1px solid var(--border); background: var(--surface-2);
  color: var(--text); font-size: 12.5px; font-weight: 500;
  transition: background .15s var(--ease), border-color .15s var(--ease), transform .08s, box-shadow .15s var(--ease);
  white-space: nowrap;
}
.btn:hover { background: var(--surface-3); border-color: var(--border-hover); }
.btn:active { transform: translateY(1px); }
.btn svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
/* 兜底：icon() 默认 size 是 14，但历史上的 16px 属性若漏改也要强制回 14。
   之前空状态按钮里的 + 被这条类似的 .empty svg {40} 误伤过 —— 现在保留更细的边界。 */
.btn svg[width="16"], .btn svg[width="18"] { width: 14px; height: 14px; }
.btn.primary {
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  border-color: transparent; color: #fff;
  box-shadow: 0 4px 14px -4px rgba(91, 140, 255, 0.45);
}
.btn.primary:hover { filter: brightness(1.07); box-shadow: 0 6px 18px -4px rgba(91, 140, 255, 0.55); }
.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(--err); border-color: rgba(242, 85, 90, .35); background: transparent; }
.btn.danger:hover { background: var(--err-soft); }
.btn.sm { height: 27px; padding: 0 10px; font-size: 12px; }
/* 更小的一档：卡片右上角这类窄位置放「编辑」「删除」这类带文字按钮时用。
   之前 history.js 的「7 天 / 30 天 / 90 天」用了 btn xs 但 CSS 里没定义这一档，
   实际渲染成了默认 32px 的大按钮，与旁边的小控件明显不齐。 */
.btn.xs { height: 23px; padding: 0 8px; font-size: 11.5px; gap: 4px; border-radius: var(--r-sm); }
.btn.xs svg { width: 12px; height: 12px; }
.btn:disabled { opacity: .45; pointer-events: none; }

.icon-btn {
  width: 28px; height: 28px; border-radius: var(--r-sm);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--text-3); transition: background .14s, color .14s;
}
.icon-btn:hover { background: var(--surface-2); color: var(--text); }
.icon-btn svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }

.card {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
}
.card-head { padding: 15px 18px; border-bottom: 1px solid var(--border-soft); display: flex; align-items: center; justify-content: space-between; }
.card-head h3 { margin: 0; font-size: 13.5px; font-weight: 600; }
.card-body { padding: 16px 18px; }

.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
.field label { font-size: 12px; color: var(--text-2); font-weight: 500; }
.field .hint { font-size: 11.5px; color: var(--text-3); }
.input, .select, textarea.input {
  height: 34px; padding: 0 11px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text); font-size: 13px;
  outline: none;
  transition: border-color .15s, box-shadow .15s, background .15s;
  width: 100%;
}
.input:hover, .select:hover, textarea.input:hover { border-color: var(--border-hover); }
[data-theme="light"] .input:hover, [data-theme="light"] .select:hover { border-color: #c7d1e0; }
textarea.input { height: auto; padding: 9px 11px; resize: vertical; font-family: var(--mono); font-size: 12.5px; line-height: 1.5; }
.input:focus, .select:focus, textarea.input:focus { border-color: var(--accent-line); box-shadow: 0 0 0 3px var(--accent-soft); }
.input::placeholder { color: var(--text-3); }
.select {
  appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238b96a5' stroke-width='2.4' stroke-linecap='round'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat: no-repeat; background-position: right 10px center;
  padding-right: 30px;
}
.row { display: grid; gap: 12px; }
.row.c2 { grid-template-columns: 1fr 1fr; }
.row.c3 { grid-template-columns: 1fr 1fr 1fr; }

.switch { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; }
.switch input { display: none; }
.switch .track { width: 32px; height: 18px; border-radius: 999px; background: var(--surface-3); border: 1px solid var(--border); position: relative; transition: background .18s var(--ease), border-color .18s; flex: 0 0 32px; }
.switch .track::after { content: ""; position: absolute; width: 12px; height: 12px; border-radius: 50%; background: var(--text-3); top: 2px; left: 2px; transition: transform .18s var(--ease), background .18s; }
.switch input:checked + .track { background: var(--accent); border-color: var(--accent); }
.switch input:checked + .track::after { transform: translateX(14px); background: #fff; }
.switch span.lbl { font-size: 12.5px; color: var(--text-2); }

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  height: 21px; padding: 0 8px; border-radius: 999px;
  font-size: 11px; font-weight: 550; letter-spacing: .2px;
  background: var(--surface-3); color: var(--text-2);
}
.badge.ok { background: var(--ok-soft); color: var(--ok); }
.badge.err { background: var(--err-soft); color: var(--err); }
.badge.warn { background: var(--warn-soft); color: var(--warn); }
.badge.accent { background: var(--accent-soft); color: var(--accent); }
.badge i { width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
.badge svg { vertical-align: -2px; margin-right: 3px; }

.muted { color: var(--text-3); }
.mono { font-family: var(--mono); font-size: 12px; }
.nowrap { white-space: nowrap; }

.empty { text-align: center; padding: 60px 20px; color: var(--text-3); }
/* 只命中空状态的装饰图标（直接子元素），不能影响内部按钮里的图标 */
.empty > svg {
  width: 28px; height: 28px; padding: 14px;
  box-sizing: content-box;
  border-radius: 15px;
  background: var(--accent-soft);
  stroke: var(--accent);
  fill: none; stroke-width: 1.5; opacity: 1;
  margin-bottom: 14px;
}
.empty h4 { margin: 0 0 4px; font-size: 14px; color: var(--text); font-weight: 560; }
.empty p { margin: 0 0 16px; font-size: 12.5px; }
.empty .btn svg { width: 14px; height: 14px; opacity: 1; }
.empty.loading > svg { animation: spin 1.1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ── 概览 ───────────────────────────────────────────── */
.stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 18px; }
.stat {
  background: var(--surface); border: 1px solid var(--border-soft);
  border-radius: var(--r-lg); padding: 15px 16px;
  transition: border-color .15s, transform .15s var(--ease), box-shadow .15s;
}
.stat:hover { border-color: var(--border-hover); transform: translateY(-1px); box-shadow: var(--shadow-2); }
.stat .k { font-size: 11.5px; color: var(--text-3); display: flex; align-items: center; gap: 6px; }
.stat .v {
  font-size: 26px; font-weight: 620; letter-spacing: -0.8px; margin-top: 6px;
  font-variant-numeric: tabular-nums;
  /* 数字改成精确值后位数变多（1.2万 → 1,234,567），必须能收：
     clamp() 让它随视口收缩，而不是撑破卡片把「来自 N 次运行」挤出去 */
  font-size: clamp(17px, 2.1vw, 26px);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.stat .v small { font-size: 12px; font-weight: 400; color: var(--text-3); margin-left: 4px; }
.stat .sub { font-size: 11.5px; color: var(--text-3); margin-top: 2px; }
.stat-grid .stat:nth-child(2) { animation-delay: .04s; }
.stat-grid .stat:nth-child(3) { animation-delay: .08s; }
.stat-grid .stat:nth-child(4) { animation-delay: .12s; }

.two-col { display: grid; grid-template-columns: 1.45fr 1fr; gap: 14px; align-items: start; }

/* ── 连接卡 ─────────────────────────────────────────── */

/* 列表工具条：搜索框 + 计数。搜索时不重绘输入框，避免丢焦点 */
.list-toolbar {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 12px; flex-wrap: wrap;
}
.search-box { position: relative; display: flex; align-items: center; min-width: 260px; flex: 0 1 300px; }
.search-box > svg {
  position: absolute; left: 10px; color: var(--text-3); pointer-events: none;
}
.search-box .input { padding-left: 31px; width: 100%; }

/* 只读数据源标记（Excel 只能作源） */
.src-only-tag {
  font-size: 10px; font-weight: 600; letter-spacing: .3px;
  color: var(--accent); background: var(--accent-soft);
  border-radius: 5px; padding: 1px 5px; align-self: flex-start; margin-top: 1px;
}

.conn-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 12px; }
.conn-card {
  background: var(--surface); border: 1px solid var(--border-soft);
  border-radius: var(--r-lg); padding: 15px 16px;
  transition: border-color .16s var(--ease), transform .16s var(--ease), box-shadow .16s;
  position: relative;
}
.conn-card:hover { border-color: var(--border-hover); transform: translateY(-2px); box-shadow: var(--shadow-2); }
.conn-top { display: flex; align-items: flex-start; gap: 11px; }
.conn-ico {
  width: 34px; height: 34px; border-radius: 10px; flex: 0 0 34px;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--accent-soft), transparent), var(--surface-3);
  color: var(--accent);
}
.conn-ico svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.7; }
.conn-name { font-weight: 550; font-size: 13.5px; }
.conn-sub { font-size: 11.5px; color: var(--text-3); margin-top: 1px; word-break: break-all; }
.conn-actions { display: flex; gap: 4px; margin-left: auto; }
.conn-foot { display: flex; align-items: center; gap: 8px; margin-top: 13px; padding-top: 12px; border-top: 1px solid var(--border-soft); }

.type-tag { font-size: 10.5px; font-weight: 600; letter-spacing: .3px; text-transform: uppercase; color: var(--text-3); }

/* ── 运行历史筛选 ───────────────────────────────────── */
.hist-bar { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; }
.chip-row { display: flex; gap: 6px; flex-wrap: wrap; }

/* 分页条：翻页按钮 + 区间说明 */
.pager {
  display: flex; align-items: center; gap: 10px;
  margin-top: 12px; flex-wrap: wrap;
}
.pager .btn.sm { height: 28px; padding: 0 10px; }
.pager .btn.sm:disabled { opacity: .4; cursor: not-allowed; }
.pager .btn.sm svg { margin: 0 -1px; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 28px; padding: 0 11px; border-radius: 999px;
  border: 1px solid var(--border-soft); background: var(--surface);
  font-size: 12px; color: var(--text-2);
  transition: border-color .14s, background .14s, color .14s;
}
.chip:hover { border-color: var(--border-hover); color: var(--text); }
.chip b {
  font-size: 10.5px; font-weight: 600; font-variant-numeric: tabular-nums;
  color: var(--text-3); background: var(--surface-3);
  padding: 1px 5px; border-radius: 999px;
}
.chip.on { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent); font-weight: 550; }
.chip.on b { background: transparent; color: var(--accent); }
.search-box { position: relative; display: flex; align-items: center; width: 210px; }
.search-box svg { position: absolute; left: 10px; color: var(--text-3); pointer-events: none; }
.search-box .input { padding-left: 31px; height: 30px; font-size: 12.5px; }

/* ── 任务列表 ───────────────────────────────────────── */
.job-list { display: flex; flex-direction: column; gap: 8px; }
.job-row {
  display: grid;
  /* 首列要放下「名称 + 三层信息」，末列要放下 5 个控件（开关 + 运行 + 试运行 + 编辑 + 更多） */
  grid-template-columns: minmax(230px, 1.75fr) minmax(150px, 1.35fr) 96px 128px auto;
  align-items: center; gap: 12px;
  background: var(--surface); border: 1px solid var(--border-soft);
  border-radius: var(--r-md); padding: 12px 15px;
  transition: border-color .15s var(--ease), transform .15s var(--ease), box-shadow .15s;
}
.job-row:hover { border-color: var(--border-hover); transform: translateY(-1px); box-shadow: var(--shadow-2); }
/* 运行中的行整体压暗一点，一眼能扫出「哪些正在跑」 */
.job-row.is-busy { border-color: var(--accent-line); background: color-mix(in srgb, var(--accent) 4%, var(--surface)); }
.job-row.is-off .job-name { color: var(--text-2); }
.job-actions { display: flex; gap: 5px; justify-content: flex-end; align-items: center; flex-wrap: nowrap; }
.job-actions .btn { white-space: nowrap; }
.job-actions .switch { margin-right: 2px; }
/* 运行中锁定开关：用户去点它只会以为坏了 */
.job-actions .switch input:disabled + .track { opacity: .45; cursor: not-allowed; }

/* 行内「更多」菜单 */
.row-menu {
  position: fixed; z-index: 80; min-width: 168px;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-3);
  padding: 5px; animation: rise .14s var(--ease);
}
.menu-item {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 8px 10px; border-radius: 7px;
  font-size: 12.5px; color: var(--text-2); text-align: left;
  transition: background .12s, color .12s;
}
.menu-item:hover { background: var(--accent-soft); color: var(--text); }
.menu-item svg { flex: 0 0 14px; }
.menu-item.danger { color: var(--err); }
.menu-item.danger:hover { background: var(--err-soft); color: var(--err); }
/* 禁用项：置灰且不响应 hover，title 说明原因 */
.menu-item.disabled { color: var(--text-3); opacity: .6; cursor: not-allowed; }
.menu-item.disabled:hover { background: transparent; color: var(--text-3); }
.menu-sep { height: 1px; background: var(--border-soft); margin: 4px 6px; }
.job-name { font-weight: 550; font-size: 13px; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }

/* 任务行的第二层：模式 / 执行方式 / 字段数 / 分片 … 合成一排小标签 */
.job-meta { display: flex; flex-wrap: wrap; gap: 4px 10px; margin-top: 5px; }
.job-meta .jm {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 10.5px; color: var(--text-3); line-height: 1;
}
.job-meta .jm svg { opacity: .8; }
/* 自动 vs 手动：这是用户最关心的「会不会自己跑」，给点颜色区分 */
.job-meta .jm.auto { color: var(--accent); }
.job-meta .jm.auto.off { color: var(--text-3); text-decoration: line-through; }
.job-meta .jm.manual { color: var(--text-2); }

/* 「自动运行」开关：放在名称行，带文字标签
   —— 单独一个滑块夹在按钮堆里，用户会以为是「运行」的一部分 */
.job-auto { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; }
.job-auto .lbl { font-size: 10.5px; color: var(--text-2); white-space: nowrap; }
.job-auto:hover .lbl { color: var(--text); }
.job-auto input:disabled ~ .track { opacity: .45; }
.job-auto input:disabled ~ .lbl { color: var(--text-3); cursor: not-allowed; }

/* 第三层：下次运行 */
.job-row .next-run { font-size: 10.5px; margin-top: 5px; }
.job-row .next-run.muted { color: var(--text-3); }

/* 源/目标表：上下两行，表名与连接名分开，比挤在一行可读 */
.job-flow { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-2); min-width: 0; }
.job-flow .tf { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.job-flow .tf b {
  font-family: var(--mono); font-size: 11.5px; font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.job-flow .tf .muted { font-size: 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.job-flow .arrow { color: var(--text-3); flex: 0 0 auto; }
.job-ops { display: flex; gap: 3px; justify-content: flex-end; }
.op-pill { font-size: 10.5px; padding: 1px 6px; border-radius: 4px; background: var(--surface-3); color: var(--text-3); font-weight: 600; }
.op-pill.on.i { background: var(--ok-soft); color: var(--ok); }
.op-pill.on.u { background: var(--accent-soft); color: var(--accent); }
.op-pill.on.d { background: var(--err-soft); color: var(--err); }

/* 「上次运行」列：状态 + 时间 + 变更量 + 失败提示，三层信息一眼看完 */
.job-last { min-width: 0; }
.job-delta { display: flex; gap: 6px; font-size: 10.5px; margin-top: 3px; }
.job-delta .i { color: var(--ins); }
.job-delta .u { color: var(--upd); }
.job-delta .d { color: var(--del); }
.job-failed { font-size: 10.5px; color: var(--err); margin-top: 3px; }

/* ── 表格 ───────────────────────────────────────────── */
.table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.table th {
  text-align: left; font-weight: 500; color: var(--text-3); font-size: 11.5px;
  padding: 9px 12px; border-bottom: 1px solid var(--border-soft);
  position: sticky; top: 0; background: var(--surface); z-index: 1;
}
.table td { padding: 10px 12px; border-bottom: 1px solid var(--border-soft); vertical-align: middle; }
.table tr:last-child td { border-bottom: none; }
.table tbody tr { transition: background .12s; }
.table tbody tr:hover { background: var(--surface-2); }
.table .num { font-variant-numeric: tabular-nums; font-family: var(--mono); font-size: 12px; }
/* 数字改成精确值后位数变长，表格列必须能收：超出就省略，完整值走 title。
   不换回「X万」——对不上账的时候，用户要的是能照着去查的准数。 */
.table td.num, .table th.num { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── 向导步骤 ───────────────────────────────────────── */
.steps { display: flex; align-items: center; gap: 0; margin-bottom: 22px; }
.step { display: flex; align-items: center; gap: 8px; color: var(--text-3); font-size: 12.5px; transition: color .15s; }
.step .n {
  width: 23px; height: 23px; border-radius: 50%; display: grid; place-items: center;
  border: 1px solid var(--border); font-size: 11px; font-weight: 600; background: var(--surface-2);
  transition: all .2s var(--ease);
}
.step.active { color: var(--text); font-weight: 550; }
.step.active .n { background: linear-gradient(135deg, var(--accent), var(--accent-2)); border-color: transparent; color: #fff; box-shadow: 0 3px 10px -2px rgba(91, 140, 255, .5); }
.step.done { color: var(--text-2); }
.step.done .n { background: var(--ok-soft); border-color: transparent; color: var(--ok); }
.step-line { flex: 1; height: 1px; background: var(--border); margin: 0 12px; min-width: 20px; position: relative; overflow: hidden; }
.step-line::after {
  content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, var(--ok), var(--accent));
  transform: scaleX(0); transform-origin: left; transition: transform .35s var(--ease);
}
.steps.all-started .step-line::after { transform: scaleX(1); }

/* 字段映射 */
/* 6 列：拖拽手柄 / 勾选 / 源字段 / 箭头 / 目标字段 / 类型 / 删除 */
.map-head, .map-row { display: grid; grid-template-columns: 18px 26px 1.15fr 30px 1fr 96px 62px 26px; gap: 8px; align-items: center; padding: 0 10px; }
.map-head { padding-bottom: 8px; font-size: 11px; color: var(--text-3); }
.map-row { padding-top: 7px; padding-bottom: 7px; border-radius: var(--r-sm); transition: background .12s; }
.map-row:hover { background: var(--surface-2); }

/* 拖拽手柄：平时低调，hover 整行才显形 */
.map-grip { display: grid; place-items: center; color: var(--text-3); cursor: grab; opacity: 0; transition: opacity .12s, color .12s; }
.map-row:hover .map-grip { opacity: .55; }
.map-grip:hover { opacity: 1 !important; color: var(--text-2); }
.map-grip:active { cursor: grabbing; }
.map-row.dragging { opacity: .4; }
/* 插入位置指示线 */
.map-row.drop-before { box-shadow: inset 0 2px 0 var(--accent); }
.map-row.drop-after { box-shadow: inset 0 -2px 0 var(--accent); }

.map-del { opacity: 0; color: var(--text-3); }
.map-row:hover .map-del { opacity: 1; }
.map-del:hover { color: var(--err); background: var(--err-soft); }
.map-row .arrow { text-align: center; color: var(--text-3); }
.map-row svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 1.8; }
.map-src { font-family: var(--mono); font-size: 12px; min-width: 0; }
.map-src > div:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── 字段占用标记（v0.8.2） ──────────────────────────────
   诉求：客户在一长串下拉里要能一眼分出「哪些字段已经用过了」。
   手段分三层，由弱到强：
     1) option.opt-taken —— 下拉里的已占用项（原生 select 对 option 样式支持有限，
        所以同时在文字里带了「（已被 X 使用）」，颜色是锦上添花而非唯一线索）；
     2) select.sel-taken —— 当前选中的目标列被别人占了，下拉框描红；
     3) .map-row.row-taken / .row-dup —— 整行左侧色条与角标。 */
.map-row.row-taken { background: var(--warn-soft); }
.map-row.row-taken::before {
  content: ''; position: absolute; left: 0; top: 4px; bottom: 4px; width: 3px;
  border-radius: 0 3px 3px 0; background: var(--warn);
}
.map-row { position: relative; overflow: hidden; }
.map-row.row-dup { background: var(--warn-soft); }
.map-row.row-dup::before {
  content: ''; position: absolute; left: 0; top: 4px; bottom: 4px; width: 3px;
  border-radius: 0 3px 3px 0; background: var(--err);
}
/* 目标列不存在：历史配置残留，必须显眼到不能错过（v0.8.6） */
.map-row.row-bad { background: var(--err-soft, var(--warn-soft)); }
.map-row.row-bad::before {
  content: ''; position: absolute; left: 0; top: 4px; bottom: 4px; width: 3px;
  border-radius: 0 3px 3px 0; background: var(--err);
}
.map-row.row-bad select { border-color: var(--err) !important; }
select.sel-taken { border-color: var(--warn) !important; color: var(--warn); }
option.opt-taken { color: var(--text-3); font-style: italic; }
/* 本行自己选的目标列：与「被别人占用」区分开 —— 前者是正常的，后者是冲突 */
option.opt-self { color: var(--accent); font-weight: 600; }

/* 源字段角标：已映射（常规）/ 重复（警示） */
.map-tag {
  display: inline-block; height: 15px; line-height: 15px; padding: 0 5px;
  border-radius: 3px; font-size: 9.5px;
  vertical-align: 1px; margin-left: 3px;
  background: var(--ok-soft); color: var(--ok);
  border: 1px solid transparent;
}
.map-tag.warn { background: var(--warn-soft); color: var(--warn); border-color: var(--warn); }
/* 停用的行不参与「占用」判定，别给它上警示底色制造误报 */
.map-row.disabled.row-taken, .map-row.disabled.row-dup { background: none; }
.map-row.disabled.row-taken::before, .map-row.disabled.row-dup::before { display: none; }
.map-src .type { color: var(--text-3); font-family: var(--sans); font-size: 10.5px; margin-left: 6px; }
.map-comment {
  font-family: var(--sans); font-size: 10.5px; color: var(--text-3);
  margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.map-row.disabled .map-src, .map-row.disabled .select { opacity: .4; }
.check { width: 15px; height: 15px; accent-color: var(--accent); cursor: pointer; }

/* 表结构信息卡（向导步骤 1） */
.tbl-info {
  background: var(--surface-2); border: 1px solid var(--border-soft);
  border-radius: 9px; padding: 9px 11px; font-size: 11.5px;
}
.tbl-comment {
  display: flex; align-items: center; gap: 6px;
  color: var(--accent); font-size: 11.5px; margin-bottom: 5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ── 可搜索下拉 ─────────────────────────────────────── */
.combo { position: relative; }
.combo-caret {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  display: flex; color: var(--text-3); pointer-events: auto; cursor: pointer;
}
.combo .input { padding-right: 30px; }
.combo-panel {
  position: absolute; top: calc(100% + 5px); left: 0; right: 0; z-index: 70;
  max-height: 320px; overflow-y: auto; overscroll-behavior: contain;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-3);
  padding: 5px;
  animation: rise .16s var(--ease);
}
.combo-item {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 9px; border-radius: 7px; cursor: pointer;
  transition: background .1s;
}
.combo-item:hover, .combo-item.active { background: var(--accent-soft); }
.ci-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.ci-name { font-family: var(--mono); font-size: 12px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.combo-item.active .ci-name { color: var(--accent); }
.ci-comment { font-size: 10.5px; color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ci-meta { flex: 0 0 auto; font-size: 10.5px; color: var(--text-3); }
.combo-empty { padding: 12px; text-align: center; font-size: 12px; color: var(--text-3); }

/* ── 运行面板 ───────────────────────────────────────── */
.runpanel {
  position: fixed; top: 0; right: 0; bottom: 0; width: 460px;
  background: var(--bg-elev); border-left: 1px solid var(--border);
  transform: translateX(102%); transition: transform .28s var(--ease);
  display: flex; flex-direction: column; z-index: 40;
  box-shadow: var(--shadow-3);
}
.runpanel.open { transform: none; }
.runpanel-head { height: 56px; flex: 0 0 56px; display: flex; align-items: center; justify-content: space-between; padding: 0 16px; border-bottom: 1px solid var(--border-soft); }
.runpanel-head strong { font-size: 13px; }
.run-status { margin-left: 8px; font-size: 10.5px; font-weight: 700; letter-spacing: .4px; color: var(--text-3); }
.run-status.RUNNING, .run-status.SCANNING, .run-status.APPLYING { color: var(--accent); }
.run-status.DONE { color: var(--ok); }
.run-status.PARTIAL { color: var(--warn); }
.run-status.FAILED, .run-status.CANCELLED { color: var(--err); }

.run-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--border-soft); border-bottom: 1px solid var(--border-soft); }
.run-stats > div { background: var(--bg-elev); padding: 10px 8px; text-align: center; }
.run-stats .k { font-size: 10.5px; color: var(--text-3); }
.run-stats .v { font-size: 16px; font-weight: 600; font-variant-numeric: tabular-nums; margin-top: 1px; }
.run-stats .v.i { color: var(--ins); }
.run-stats .v.u { color: var(--upd); }
.run-stats .v.d { color: var(--del); }

.progress { height: 2px; background: var(--surface-3); overflow: hidden; }
.progress-bar { height: 100%; width: 0; background: linear-gradient(90deg, var(--accent), var(--accent-2)); transition: width .3s; }
.progress-bar.indet { width: 35%; animation: slide 1.2s infinite ease-in-out; }
@keyframes slide { 0% { margin-left: -35%; } 100% { margin-left: 100%; } }

.run-log {
  flex: 1; overflow-y: auto; padding: 10px 14px;
  font-family: var(--mono); font-size: 11.5px; line-height: 1.75;
  background: var(--bg);
}
.run-log div { display: flex; gap: 8px; padding: 0 4px; border-radius: 4px; transition: background .1s; }
.run-log div:hover { background: var(--surface-2); }
.run-log .ts { color: var(--text-3); flex: 0 0 auto; }
.run-log .lv { flex: 0 0 38px; }
.run-log .lv.info { color: var(--text-3); }
.run-log .lv.warn { color: var(--warn); }
.run-log .lv.error { color: var(--err); }
.run-log .msg { color: var(--text-2); word-break: break-word; }
.run-log .lv.error + .msg { color: var(--err); }
/* 运行结束后的失败行清单 —— 直接摊在面板里，配「重放失败行」按钮 */
.run-errors {
  flex: 0 0 auto; max-height: 132px; overflow: auto;
  border-top: 1px solid var(--border-soft);
  background: var(--err-soft); padding: 8px 12px;
}
.run-err-head {
  display: flex; align-items: center; gap: 6px;
  font-size: 12.5px; font-weight: 600; color: var(--err); margin-bottom: 6px;
}
.run-err-head svg { flex: 0 0 auto; }
.run-err-row {
  display: flex; align-items: flex-start; gap: 7px;
  font-size: 11.5px; line-height: 1.5; padding: 2px 0;
}
.run-err-row .pk { color: var(--text-2); flex: 0 0 auto; max-width: 42%; word-break: break-all; }
.run-err-row .msg { color: var(--text-2); word-break: break-word; }

.runpanel-foot { height: 52px; flex: 0 0 52px; display: flex; align-items: center; gap: 10px; padding: 0 14px; border-top: 1px solid var(--border-soft); }
.runpanel-foot #runHint { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 运行详情里的回滚提示条：可回 / 已回 / 不可回 三态一色 */
.undo-note {
  display: flex; gap: 9px; align-items: flex-start;
  margin-bottom: 14px; padding: 11px 13px;
  border-radius: var(--r-sm); font-size: 12.5px; line-height: 1.55;
}
.undo-note svg { flex: 0 0 auto; margin-top: 1px; }
.undo-note.ok { background: var(--ok-soft); color: var(--ok); }
.undo-note.warn { background: var(--warn-soft); color: var(--text-1); border: 1px solid var(--border-soft); }
.undo-note.muted { background: var(--surface-2); color: var(--text-2); }
.undo-note .mono { font-family: var(--mono); font-size: 11.5px; }

/* ── 审计区块（历史详情里的日志与变更明细） ───────────── */
.audit-log {
  max-height: 300px; overflow: auto; border: 1px solid var(--border-soft); border-radius: var(--r-md);
  background: var(--bg); padding: 8px 6px; font-family: var(--mono);
  font-size: 11.5px; line-height: 1.75; margin-bottom: 16px;
}
.audit-log .alog { display: flex; gap: 8px; padding: 1px 6px; border-radius: 4px; }
.audit-log .alog:hover { background: var(--surface-2); }
.audit-log .ts { color: var(--text-3); flex: 0 0 auto; }
.audit-log .lv { flex: 0 0 38px; color: var(--text-3); }
.audit-log .lv.warn { color: var(--warn); }
.audit-log .lv.error { color: var(--err); }
.audit-log .msg { color: var(--text-2); word-break: break-word; }
.audit-log .lv.error + .msg { color: var(--err); }
.audit-note {
  font-size: 11.5px; color: var(--warn); background: var(--warn-soft, rgba(200,140,20,.1));
  border: 1px solid var(--border-soft); border-radius: 8px; padding: 7px 10px; margin-bottom: 10px;
}

/* 留存设置行：数字输入 + 单位，一行排开 */
.ret-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.ret-row label { font-size: 12.5px; color: var(--text-3); }
.ret-row .input { width: 92px; }
.ret-row .unit { font-size: 11.5px; color: var(--text-3); margin-right: 12px; }

/* 告警通道卡片 */
.alert-ch-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.alert-ch {
  border: 1px solid var(--border-soft); border-radius: var(--r-md);
  padding: 10px 12px; background: var(--bg-2);
}
.alert-ch .field { margin-bottom: 0; }
.alert-ch .field label { font-size: 12px; }
.alert-ch .input { font-size: 12px; }
.alert-ch-head {
  display: flex; align-items: center; gap: 6px;
  font-size: 12.5px; font-weight: 600; color: var(--text-2);
  margin-bottom: 8px;
}
.alert-ch-head svg { color: var(--accent); }
.smtp-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 12px; }
.smtp-grid .field { margin-bottom: 0; }

/* 导入预览 */
.imp-table { border: 1px solid var(--border-soft); border-radius: var(--r-md); overflow: hidden; }
.imp-row {
  display: grid; grid-template-columns: 1.4fr 100px 1.8fr;
  align-items: center; gap: 10px;
  padding: 9px 12px; font-size: 12.5px;
  border-bottom: 1px solid var(--border-soft);
}
.imp-row:last-child { border-bottom: 0; }
.imp-row:hover { background: var(--surface-2); }
.imp-name { font-weight: 500; word-break: break-all; }
.imp-status {
  font-size: 11.5px; padding: 2px 8px; border-radius: 999px; text-align: center;
}
.imp-row.imp-new .imp-status { background: var(--ok-soft, rgba(40, 180, 110, .12)); color: var(--ok); }
.imp-row.imp-over .imp-status { background: var(--warn-soft, rgba(200, 140, 20, .12)); color: var(--warn); }
.imp-dst { font-size: 11.5px; }

/* ── 抽屉 ───────────────────────────────────────────── */
.drawer-mask {
  position: fixed; inset: 0; background: rgba(2, 5, 10, .55); opacity: 0; pointer-events: none;
  transition: opacity .24s var(--ease); z-index: 50; backdrop-filter: blur(2px);
}
.drawer-mask.show { opacity: 1; pointer-events: auto; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: 640px; max-width: 92vw;
  background: var(--bg-elev); border-left: 1px solid var(--border);
  transform: translateX(101%); transition: transform .28s var(--ease);
  z-index: 51; display: flex; flex-direction: column; box-shadow: var(--shadow-3);
}
.drawer.open { transform: none; }
.drawer-head { height: 58px; flex: 0 0 58px; display: flex; align-items: center; justify-content: space-between; padding: 0 20px; border-bottom: 1px solid var(--border-soft); }
.drawer-head h2 { margin: 0; font-size: 14px; font-weight: 600; }
.drawer-body { flex: 1; overflow-y: auto; padding: 20px; }
.drawer-foot { height: 60px; flex: 0 0 60px; display: flex; align-items: center; justify-content: flex-end; gap: 10px; padding: 0 20px; border-top: 1px solid var(--border-soft); background: var(--bg-elev); }
.drawer.wide { width: 880px; }

/* ── 模态 ───────────────────────────────────────────── */
.modal-mask { position: fixed; inset: 0; background: rgba(2, 5, 10, .55); opacity: 0; pointer-events: none; transition: opacity .18s; z-index: 60; backdrop-filter: blur(2px); }
.modal-mask.show { opacity: 1; pointer-events: auto; }
.modal {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -46%) scale(.97);
  width: 440px; max-width: 92vw; background: var(--bg-elev);
  border: 1px solid var(--border); border-radius: var(--r-lg);
  opacity: 0; pointer-events: none; transition: opacity .18s, transform .18s var(--ease);
  z-index: 61; box-shadow: var(--shadow-3); overflow: hidden;
}
.modal.show { opacity: 1; pointer-events: auto; transform: translate(-50%, -50%) scale(1); }
.modal-body { padding: 22px 22px 8px; }
.modal-body h3 { margin: 0 0 6px; font-size: 15px; }
.modal-body p { margin: 0 0 8px; color: var(--text-2); font-size: 12.5px; }
.modal-foot { padding: 14px 22px; display: flex; justify-content: flex-end; gap: 8px; }

/* ── Toast ──────────────────────────────────────────── */
.toasts { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); display: flex; flex-direction: column; gap: 8px; z-index: 90; align-items: center; }
.toast {
  display: flex; align-items: center; gap: 9px;
  background: color-mix(in srgb, var(--surface-3) 88%, transparent);
  backdrop-filter: blur(10px);
  border: 1px solid var(--border);
  padding: 9px 15px; border-radius: 999px; font-size: 12.5px;
  box-shadow: var(--shadow-2); animation: toastIn .22s var(--ease);
}
.toast.ok { border-color: rgba(66, 196, 106, .35); }
.toast.err { border-color: rgba(242, 85, 90, .4); }
.toast .i { width: 6px; height: 6px; border-radius: 50%; background: var(--text-2); }
.toast.ok .i { background: var(--ok); }
.toast.err .i { background: var(--err); }
@keyframes toastIn { from { opacity: 0; transform: translateY(8px); } }

/* ── 错误卡片（结论 + 建议 + 可展开原始信息）───────────────
   与普通 toast 分开：普通 toast 是圆角药丸 + 单行 + 3 秒消失，
   错误信息有三层内容，用户要读完并决定下一步，必须给足时间与空间。 */
.toast.err-card {
  display: block; border-radius: 12px; padding: 12px 16px;
  max-width: 520px; min-width: 320px; text-align: left; line-height: 1.6;
}
.toast.err-card .err-title { font-size: 13px; font-weight: 600; color: var(--err); }
.toast.err-card .err-hint { font-size: 12px; color: var(--text-2); margin-top: 5px; }
.toast.err-card .err-more {
  margin-top: 8px; background: none; border: none; padding: 0;
  font-size: 11.5px; color: var(--text-3); cursor: pointer; text-decoration: underline;
}
.toast.err-card .err-more:hover { color: var(--text-2); }
.toast.err-card .err-detail {
  margin: 8px 0 0; padding: 8px 10px; font-size: 11px; line-height: 1.5;
  background: var(--surface-2); border: 1px solid var(--border-soft);
  border-radius: 8px; max-height: 160px; overflow: auto;
  white-space: pre-wrap; word-break: break-all; color: var(--text-2);
  font-family: var(--mono, ui-monospace, monospace);
}

/* ── 预检结果 ───────────────────────────────────────── */
.chk { display: flex; gap: 9px; padding: 8px 0; border-bottom: 1px solid var(--border-soft); font-size: 12.5px; }
.chk:last-child { border-bottom: none; }
.chk .dot { width: 6px; height: 6px; border-radius: 50%; margin-top: 7px; flex: 0 0 6px; }
.chk.ok .dot { background: var(--ok); }
.chk.warn .dot { background: var(--warn); }
.chk.error .dot { background: var(--err); }
.chk .code { color: var(--text-3); font-family: var(--mono); font-size: 11px; flex: 0 0 auto; }
/* 语义配色：错误红 / 提醒橙 / 正常正文色 */
.chk .msg { color: var(--text); }
.chk.warn .msg { color: var(--warn); }
.chk.error .msg { color: var(--err); }
.chk.warn .code { color: var(--warn); opacity: .75; }
.chk.error .code { color: var(--err); opacity: .75; }
/* 带 fix 的行：右侧「方案」角标，整行可悬停 */
.chk.has-fix { cursor: help; }
.chk .fix-tag {
  flex: 0 0 auto; margin-left: auto; align-self: center;
  font-size: 10.5px; line-height: 16px; padding: 0 6px;
  color: var(--accent); border: 1px solid var(--accent-line); border-radius: 4px;
  opacity: .55; transition: opacity .15s;
}
.chk.has-fix:hover .fix-tag { opacity: 1; }
.chk.has-fix:hover { background: var(--accent-soft); border-radius: 6px; }
/* 悬停方案弹层（全局唯一，挂 body） */
#fixPop {
  position: fixed; display: none; z-index: 1200; max-width: 620px;
  background: var(--bg-elev); border: 1px solid var(--border-hover); border-radius: 10px;
  box-shadow: var(--shadow-2); padding: 12px 14px; font-size: 12px; color: var(--text);
}
#fixPop .fix-head {
  display: flex; align-items: center; gap: 6px; font-weight: 600; font-size: 12px;
  color: var(--accent); margin-bottom: 6px;
}
#fixPop .fix-sum { line-height: 1.65; color: var(--text); }
#fixPop .fix-sql {
  margin: 8px 0 0; padding: 9px 11px; border-radius: 7px; overflow: auto;
  max-height: 220px; background: color-mix(in srgb, var(--bg) 55%, var(--bg-elev));
  border: 1px solid var(--border-soft);
  font-family: var(--mono); font-size: 11.5px; line-height: 1.6; color: var(--text);
}
#fixPop .fix-actions { display: flex; justify-content: flex-end; align-items: center; gap: 8px; margin-top: 8px; }
/* 执行位置徽标：跨库任务里必须让人一眼看出这段 SQL 该在哪跑 */
#fixPop .fix-where {
  display: inline-flex; align-items: center; gap: 4px; font-weight: 600; font-size: 11px;
  padding: 2px 7px; border-radius: 999px; color: var(--accent);
  background: var(--accent-soft); border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
}
#fixPop .fix-head .fix-where { margin-left: auto; }
#fixPop .fix-actions .fix-where { margin-right: auto; }
#fixPop .fix-step + .fix-step { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--border-soft); }
#fixPop .fix-step-t { font-size: 11.5px; color: var(--text-2); margin-bottom: 2px; }
#fixPop .fix-caution {
  display: flex; gap: 6px; align-items: flex-start; margin-top: 10px; padding: 7px 9px;
  border-radius: 7px; font-size: 11.5px; line-height: 1.6;
  color: var(--warn); background: color-mix(in srgb, var(--warn) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--warn) 28%, transparent);
}

.split { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.section-title { font-size: 11px; text-transform: uppercase; letter-spacing: .6px; color: var(--text-3); font-weight: 600; margin: 20px 0 10px; }
.section-title:first-child { margin-top: 0; }

.hr { height: 1px; background: var(--border-soft); margin: 18px 0; }

.kv { display: grid; grid-template-columns: 120px 1fr; gap: 8px 12px; font-size: 12.5px; }
.kv .k { color: var(--text-3); }
.kv .v { word-break: break-all; }

/* ── 连接类型选择 ───────────────────────────────────── */
.type-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.type-card {
  display: flex; flex-direction: column; align-items: flex-start; gap: 3px;
  padding: 11px 12px; border-radius: var(--r-md);
  border: 1px solid var(--border); background: var(--surface-2);
  text-align: left; transition: border-color .15s var(--ease), background .15s, transform .1s;
}
.type-card:hover { border-color: var(--border-hover); background: var(--surface-3); transform: translateY(-1px); }
.type-card.active { border-color: var(--accent-line); background: var(--accent-soft); }
.type-card b { font-size: 12.5px; font-weight: 550; }
.type-card small { font-size: 10.5px; color: var(--text-3); }
.tc-ico { color: var(--accent); display: flex; margin-bottom: 2px; }

.test-ok, .test-err {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 11px 13px; border-radius: var(--r-md); font-size: 12.5px;
  animation: rise .25s var(--ease);
}
.test-ok { background: var(--ok-soft); color: var(--ok); }
.test-err { background: var(--err-soft); color: var(--err); }
.test-ok b, .test-err b { font-size: 12.5px; display: block; color: var(--text); }
.test-ok .muted, .test-err .muted { color: var(--text-3); }

/* ── 同步模式卡 ─────────────────────────────────────── */
.mode-list { display: flex; flex-direction: column; gap: 7px; }
.mode-card {
  padding: 10px 13px; border-radius: var(--r-md);
  border: 1px solid var(--border-soft); background: var(--surface-2);
  cursor: pointer; transition: border-color .15s var(--ease), background .15s, transform .1s;
}
.mode-card:hover { border-color: var(--border-hover); transform: translateY(-1px); }
.mode-card.active { border-color: var(--accent-line); background: var(--accent-soft); }
.mc-title { font-size: 12.5px; font-weight: 550; display: flex; align-items: center; gap: 6px; }
.mc-title svg { color: var(--accent); }
.mc-desc { font-size: 11.5px; color: var(--text-3); margin-top: 2px; line-height: 1.5; }

/* Electron 无边框窗口：给右上角系统按钮（约 140px 宽）留出空隙，避免与「刷新/新建」贴在一起 */
html.electron .topbar { padding-right: 164px; }
/* 运行面板/抽屉也是 top:0 right:0，头部的关闭按钮会被 Electron 原生窗口控制按钮
   （min/max/close 覆盖层，宽约 164px）整个盖住 —— 不预留空间就永远点不到 */
html.electron .runpanel-head { padding-right: 172px; }
html.electron .drawer-head { padding-right: 184px; }
html.electron .rail { padding-top: 4px; }

/* 浅色主题微调 */
[data-theme="light"] .topbar { background: rgba(255, 255, 255, 0.76); }
[data-theme="light"] .toast { background: rgba(255, 255, 255, 0.94); }
[data-theme="light"] .rail { background: linear-gradient(180deg, #ffffff 0%, #fbfcff 100%); }
[data-theme="light"] .btn { background: #ffffff; }
[data-theme="light"] .btn:hover { background: var(--surface-2); }
[data-theme="light"] .nav-item:hover { background: #f1f5fd; }
[data-theme="light"] .btn.primary { background: linear-gradient(135deg, #3a78ff, #6a4df0); box-shadow: 0 6px 16px -8px rgba(47, 107, 240, 0.65); }
[data-theme="light"] .btn.primary:hover { box-shadow: 0 8px 20px -8px rgba(47, 107, 240, 0.75); }
[data-theme="light"] .drawer-mask, [data-theme="light"] .modal-mask { background: rgba(16, 24, 40, 0.32); }
[data-theme="light"] .run-log { background: #fbfcff; }

/* ── 更新提示条 ─────────────────────────────────────── */
.banner {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px; margin-bottom: 16px;
  border-radius: var(--r-md);
  border: 1px solid var(--accent-line);
  background: linear-gradient(100deg, var(--accent-soft), transparent 70%), var(--surface);
  animation: rise .3s var(--ease) both;
}
.banner .bi { width: 30px; height: 30px; flex: 0 0 30px; border-radius: 9px; display: grid; place-items: center; background: var(--accent-soft); color: var(--accent); }
.banner .bt { flex: 1; min-width: 0; }
.banner .bt b { font-size: 12.5px; display: block; }
.banner .bt span { font-size: 11.5px; color: var(--text-2); }

/* ── 版本与关于 ─────────────────────────────────────── */
.about-head { display: flex; align-items: center; gap: 13px; }
.about-logo {
  width: 44px; height: 44px; flex: 0 0 44px; border-radius: 13px; overflow: hidden;
  border: 1px solid var(--border-soft);
}
.about-logo img { width: 100%; height: 100%; display: block; }
.about-name { font-size: 15px; font-weight: 650; letter-spacing: -0.2px; }
.about-meta { font-size: 11.5px; color: var(--text-3); margin-top: 2px; }
.ver-chip {
  display: inline-flex; align-items: center; gap: 5px;
  height: 22px; padding: 0 9px; border-radius: 999px;
  font-size: 11px; font-weight: 650; font-family: var(--mono);
  background: var(--accent-soft); color: var(--accent);
}
.ver-chip.dot::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--err); }

.upd-row { display: flex; align-items: center; gap: 12px; }
.upd-row .info { flex: 1; min-width: 0; }
.upd-row .info b { font-size: 13px; display: block; }
.upd-row .info span { font-size: 11.5px; color: var(--text-3); }
.upd-notes {
  margin-top: 12px; padding: 11px 13px; border-radius: var(--r-md);
  background: var(--surface-2); border: 1px solid var(--border-soft);
  font-size: 12px; color: var(--text-2); line-height: 1.7; white-space: pre-wrap;
  max-height: 220px; overflow-y: auto;
}
.upd-progress { height: 4px; border-radius: 999px; background: var(--surface-3); overflow: hidden; margin-top: 12px; }
.upd-progress > i { display: block; height: 100%; background: linear-gradient(90deg, var(--accent), var(--accent-2)); transition: width .25s; }
.upd-tip { margin-top: 8px; font-size: 11.5px; color: var(--text-3); }

/* ── 「发现新版本」弹窗 ─────────────────────────────────── */
/*
 * 色调类：之前只有 update.html 内联样式里有，app.css 里根本没有 ——
 * 弹窗里所有分类标签都是「透明边框、无底色」，修复/新增/其它长得一模一样，
 * 用户根本分不出这一版到底是加了功能还是修了 bug。这里补齐同一套语义色。
 * 底色用 soft 色 + 同色系描边：soft 色透明度只有 0.1~0.13，
 * 光靠底色在浅色主题下几乎看不出差别，加描边才立得住。
 */
.upd-tag.t-ok { background: var(--ok-soft); color: var(--ok); border-color: color-mix(in srgb, var(--ok) 34%, transparent); }
.upd-tag.t-warn { background: var(--warn-soft); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 34%, transparent); }
.upd-tag.t-err { background: var(--err-soft); color: var(--err); border-color: color-mix(in srgb, var(--err) 34%, transparent); }
.upd-tag.t-accent { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-line); }
.upd-tag.t-muted { background: var(--surface-3); color: var(--text-3); border-color: var(--border-soft); }

/* 版本对比条：一眼看清「从哪升到哪」 */
.upd-hero {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 14px 16px; margin-bottom: 14px; border-radius: var(--r-md);
  background: linear-gradient(135deg, var(--accent-soft), rgba(122, 91, 240, .07));
  border: 1px solid var(--accent-line);
}
.upd-v { display: flex; align-items: center; gap: 10px; }
.upd-vlbl { font-size: 11.5px; color: var(--text-3); margin-right: -4px; }
.upd-from { font: 600 14px/1 ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--text-3); }
.upd-arrow { color: var(--accent); display: flex; }
.upd-to { font: 700 22px/1 ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--accent); letter-spacing: -.5px; }
.upd-when { margin-left: auto; font-size: 11.5px; color: var(--text-3); flex: 0 0 auto; }

/* 变更量统计：让用户先知道「这次改动有多大」再决定要不要细看 */
.upd-stats { display: flex; align-items: center; gap: 8px; margin-bottom: 13px; }
.upd-stat {
  display: flex; align-items: baseline; gap: 5px;
  padding: 5px 11px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border-soft);
  font-size: 11.5px; color: var(--text-3);
}
.upd-stat b { font: 700 13.5px/1 var(--mono); color: var(--text); }

/* 分类筛选条：34 条变更堆在一起没法看，按类型筛一下 */
.upd-filters { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }
.upd-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 10px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 11.5px; line-height: 1.5;
  background: var(--surface-2); border: 1px solid var(--border-soft); color: var(--text-2);
  transition: border-color .12s var(--ease), background .12s var(--ease), color .12s var(--ease);
}
.upd-chip:hover { border-color: var(--border-hover); color: var(--text); }
.upd-chip.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.upd-chip.on .upd-chip-n { color: rgba(255, 255, 255, .75); }
.upd-chip-n { font: 600 10.5px/1 var(--mono); color: var(--text-3); }

/* 滚动区：外层负责渐隐提示还有内容 */
.upd-scroll { position: relative; }
.upd-scroll::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 24px;
  background: linear-gradient(to top, var(--bg-elev) 30%, transparent);
  pointer-events: none; opacity: 0; transition: opacity .18s;
}
.upd-scroll.has-more::after { opacity: 1; }
/* 底部留白：最后一条要能完整滚出渐隐区（滚到底时渐隐自动消失） */
.upd-cats { max-height: min(52vh, 460px); overflow-y: auto; padding-right: 4px; padding-bottom: 22px; }

/* 分类分组：左侧色条按类型着色，扫一眼就知道这块是什么 */
.upd-cat { margin-bottom: 14px; padding-left: 11px; border-left: 2px solid var(--line); }
.upd-cat:last-child { margin-bottom: 0; }
.upd-cat[data-tone="ok"] { border-left-color: var(--ok); }
.upd-cat[data-tone="warn"] { border-left-color: var(--warn); }
.upd-cat[data-tone="err"] { border-left-color: var(--err); }
.upd-cat[data-tone="accent"] { border-left-color: var(--accent); }
.upd-cat[data-tone="muted"] { border-left-color: var(--border-hover); }
.upd-cat-h {
  display: flex; align-items: center; gap: 8px; margin-bottom: 6px;
  width: 100%; padding: 0; border: 0; background: transparent; cursor: pointer;
  text-align: left; font: inherit; color: inherit;
}
.upd-cat-h:hover .upd-cat-t { color: var(--accent); }
.upd-tag {
  font-size: 10.5px; font-weight: 600; padding: 2px 8px; border-radius: 999px;
  border: 1px solid transparent; letter-spacing: .3px; flex: 0 0 auto;
}
.upd-cat-t { font-size: 12.5px; color: var(--text); font-weight: 600; min-width: 0; transition: color .12s; }
.upd-n { margin-left: auto; font-size: 10.5px; color: var(--text-3); flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.upd-fold { color: var(--text-3); display: flex; flex: 0 0 auto; transition: transform .18s var(--ease); }
.upd-cat.closed .upd-fold { transform: rotate(-90deg); }
.upd-items { margin: 0; padding: 0; list-style: none; }
.upd-cat.closed .upd-items { display: none; }
.upd-items li {
  position: relative; padding: 3px 0 3px 16px; font-size: 12.5px;
  color: var(--text-2); line-height: 1.72;
}
.upd-items li::before {
  content: ''; position: absolute; left: 3px; top: 11px;
  width: 4px; height: 4px; border-radius: 50%; background: var(--border-hover);
}
.upd-items li b { color: var(--text); font-weight: 600; }
.upd-items li code {
  font: 11.5px/1.5 var(--mono); background: var(--surface-2);
  border-radius: 4px; padding: 1px 5px; color: var(--text);
}
.upd-plain {
  margin: 0; padding: 12px 14px; border-radius: var(--r-md);
  background: var(--surface-2); border: 1px solid var(--border-soft);
  font-size: 12.5px; color: var(--text-2); line-height: 1.75; white-space: pre-wrap;
}

/* 底部：次要操作靠左，主操作靠右 */
.upd-foot { display: flex; align-items: center; gap: 8px; width: 100%; }
.upd-foot-later { margin-right: auto; }

/* 更新卡被定位到时闪一下，用户不会「跳过来却不知道看哪儿」 */
.upd-focus { animation: updFocus 1.5s var(--ease); }
@keyframes updFocus {
  0%, 100% { box-shadow: none; }
  15%, 60% { box-shadow: 0 0 0 3px var(--accent-line); }
}
.formula { font-family: var(--mono); font-size: 11.5px; background: var(--surface-2); border: 1px solid var(--border-soft); border-radius: 6px; padding: 1px 6px; }
.kbd {
  display: inline-block; padding: 0 5px; margin: 0 1px;
  border: 1px solid var(--border); border-bottom-width: 2px; border-radius: 5px;
  background: var(--surface-2); font-family: var(--mono); font-size: 10.5px; line-height: 16px;
  color: var(--text-2);
}

/* ── 主题预览卡 ─────────────────────────────────────── */
.theme-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; max-width: 420px; }
.theme-card {
  border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 8px; background: var(--surface-2); text-align: left;
  transition: border-color .15s var(--ease), transform .1s;
}
.theme-card:hover { border-color: var(--border-hover); transform: translateY(-1px); }
.theme-card.active { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.theme-preview { height: 62px; border-radius: 6px; display: flex; overflow: hidden; border: 1px solid rgba(0, 0, 0, .08); }
.theme-preview .tp-rail { width: 26%; }
.theme-preview .tp-body { flex: 1; padding: 7px; display: flex; flex-direction: column; gap: 4px; }
.theme-preview .tp-line { height: 5px; border-radius: 3px; }
.tp-light { background: #f4f6fb; }
.tp-light .tp-rail { background: #fff; border-right: 1px solid #e3e9f3; }
.tp-light .tp-line.a { width: 62%; background: #2f6bf0; opacity: .75; }
.tp-light .tp-line.b { width: 88%; background: #dfe6f2; }
.tp-light .tp-line.c { width: 72%; background: #e8edf6; }
.tp-dark { background: #0b0e13; }
.tp-dark .tp-rail { background: #111720; border-right: 1px solid #222b38; }
.tp-dark .tp-line.a { width: 62%; background: #5b8cff; opacity: .8; }
.tp-dark .tp-line.b { width: 88%; background: #232c39; }
.tp-dark .tp-line.c { width: 72%; background: #1c242f; }
.theme-card .tc-name { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 550; margin-top: 7px; }
.theme-card .tc-sub { font-size: 10.5px; color: var(--text-3); }

/* 下次运行 */
.next-run { font-size: 11px; color: var(--text-3); display: flex; align-items: center; gap: 4px; }
.next-run.due { color: var(--accent); }


/* ── 设置页布局 ─────────────────────────────────────── */
.settings-grid { display: grid; grid-template-columns: 1.02fr 1fr; gap: 14px; align-items: start; max-width: 1200px; }
@media (max-width: 1100px) { .settings-grid { grid-template-columns: 1fr; } }

/* ── 设置页顶部分类页签（v0.8.3） ────────────────────────
   原来设置页把 8 张卡塞进两列滚动，一屏看不全、也不知道哪张卡归哪类。
   改成按大类分页签：每个页签自己是一套布局，切换不重新请求（数据已预取）。
   页签本身吸顶，滚到下面也还在。 */
.settings-tabs {
  display: flex; gap: 4px; margin-bottom: 16px; max-width: 1200px;
  border-bottom: 1px solid var(--border-soft); position: sticky; top: 0; z-index: 5;
  background: var(--bg); padding-top: 2px;
}
.settings-tab {
  display: flex; align-items: center; gap: 7px;
  padding: 9px 15px 11px; border: none; background: none; cursor: pointer;
  font-size: 13px; font-weight: 500; color: var(--text-2); font-family: var(--sans);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color .12s, border-color .12s;
}
.settings-tab:hover { color: var(--text-1); }
.settings-tab.active { color: var(--accent); border-bottom-color: var(--accent); }
.settings-tab svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 1.8; }
.settings-tab .tab-badge {
  min-width: 17px; height: 17px; line-height: 17px; padding: 0 5px; border-radius: 9px;
  background: var(--accent); color: #fff; font-size: 10px; text-align: center; font-weight: 600;
}
/* 单页签场景（如只有配置备份）不用两列 */
.settings-grid.single { grid-template-columns: 1fr; max-width: 900px; }
/* 数据页签里两张卡并排放，窄屏自动堆叠 */
.settings-grid.data2 { grid-template-columns: 1fr 1fr; max-width: 1200px; }
@media (max-width: 1100px) { .settings-grid.data2 { grid-template-columns: 1fr; } }

/* ── 每周选择 ───────────────────────────────────────── */
.week-pick { display: flex; gap: 5px; }
.week-day {
  width: 32px; height: 32px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--bg-elev);
  font-size: 12px; color: var(--text-2);
  transition: all .14s var(--ease);
}
.week-day:hover { border-color: var(--border-hover); }
.week-day.on { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; box-shadow: 0 3px 10px -4px var(--accent); }

/* ── 高级折叠 ───────────────────────────────────────── */
.adv { border: 1px solid var(--border-soft); border-radius: var(--r-md); background: var(--surface-2); padding: 0 12px; }
.adv > summary {
  cursor: pointer; list-style: none; padding: 9px 0;
  font-size: 12px; color: var(--text-2); font-weight: 500;
  display: flex; align-items: center; gap: 6px;
}
.adv > summary::-webkit-details-marker { display: none; }
.adv > summary::before { content: "›"; font-size: 14px; color: var(--text-3); transition: transform .15s; }
.adv[open] > summary::before { transform: rotate(90deg); }
.adv-body { padding: 4px 0 12px; }

/* ── 通用对话框 ─────────────────────────────────────── */
.dlg-body { max-height: 62vh; overflow-y: auto; margin: 10px 0 4px; }
.dlg-body .sqlbox {
  font-family: var(--mono); font-size: 11.5px; line-height: 1.65;
  background: var(--surface-2); border: 1px solid var(--border-soft);
  border-radius: var(--r-md); padding: 12px 14px; white-space: pre-wrap;
  word-break: break-word; color: var(--text-2); max-height: 300px; overflow: auto;
}
.dlg-body .warn-list { margin: 10px 0 0; padding-left: 18px; color: var(--warn); font-size: 11.5px; line-height: 1.7; }

/* ── 兼容性提示条 ───────────────────────────────────── */
.compat-bar {
  display: flex; gap: 9px; align-items: flex-start;
  padding: 10px 12px; border-radius: var(--r-md);
  border: 1px solid rgba(228, 168, 62, .32); background: rgba(228, 168, 62, .08);
  font-size: 11.5px; line-height: 1.6; color: var(--text-2); margin-bottom: 12px;
}
.compat-bar.err { border-color: rgba(242, 85, 90, .35); background: rgba(242, 85, 90, .08); }
.compat-bar b { color: var(--text); }
.compat-bar ul { margin: 4px 0 0; padding-left: 16px; }

/* ── 高级连接选项 ───────────────────────────────────── */
.switch-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 2px; font-size: 12px; color: var(--text-2); cursor: pointer;
}
.switch-row input { width: 15px; height: 15px; accent-color: var(--accent); }
.switch-row em { width: 100%; padding-left: 23px; font-style: normal; color: var(--text-3); font-size: 11px; line-height: 1.5; }
.conn-detail { font-size: 11px; color: var(--text-3); line-height: 1.55; margin: 4px 0 3px; word-break: break-all; }

/* ── 近 7 天趋势 ─────────────────────────────────────── */
/* ── 概览趋势图 ─────────────────────────────────────── */
/* 柱子按列数自适应宽度：7 天时又宽又疏，60 天（按周 9 根）时也不会挤成线 */
.trend { display: grid; grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); gap: 8px; align-items: end; }
.trend-col { display: flex; flex-direction: column; align-items: center; gap: 6px; min-width: 0; }
.trend-val {
  font-size: 10.5px; color: var(--text-3); font-variant-numeric: tabular-nums;
  height: 14px; line-height: 14px; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.trend-col.today .trend-val { color: var(--accent); font-weight: 600; }
.trend-bar {
  position: relative; width: 100%; max-width: 54px; height: 104px;
  display: flex; align-items: flex-end; overflow: hidden;
  border-radius: 8px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--surface-2) 60%, transparent), var(--surface-2));
  border: 1px solid var(--border-soft);
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}
.trend-col:hover .trend-bar {
  border-color: var(--accent-line);
  box-shadow: 0 2px 10px color-mix(in srgb, var(--accent) 14%, transparent);
}
/* 柱体顶部那道亮边去掉：它会让每根柱子顶端都有一条横线，
   30 根并排时读起来像一张横线密排的表格，反而干扰「比高低」这件事。 */
.trend-bar > i {
  display: block; width: 100%; border-radius: 7px 7px 0 0;
  background: linear-gradient(180deg, var(--accent), color-mix(in srgb, var(--accent) 46%, transparent));
  transition: height .4s var(--ease);
}
.trend-col.today .trend-bar { border-color: var(--accent); border-style: solid; }
/* 「今天」这一格底色要看得出来：周汇总时最后一根常常不足 7 天、柱子明显矮，
   不加底色用户会以为数据漏了一天 */
.trend-col.today .trend-x {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border-radius: 4px; padding: 1px 5px; margin-top: -1px;
}
.trend-col.zero .trend-bar { background: repeating-linear-gradient(135deg, var(--surface-2) 0 5px, transparent 5px 10px); }
.trend-bar.has-err::after {
  content: ""; position: absolute; top: 4px; right: 4px;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--err); box-shadow: 0 0 0 2px var(--err-soft);
}
.trend-x {
  font-size: 10.5px; color: var(--text-3); font-variant-numeric: tabular-nums;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.trend-col.today .trend-x { color: var(--accent); font-weight: 600; }
/* 按周汇总时列数少，标签带日期区间，宽度要放宽 */
.trend.weekly { gap: 12px; }
.trend.weekly .trend-x { font-size: 10px; }

/* 趋势图顶部的汇总指标条 */
.trend-kpis {
  display: flex; flex-wrap: wrap; gap: 6px 22px; align-items: baseline;
  padding: 0 2px 14px; margin-bottom: 12px;
  border-bottom: 1px solid var(--border-soft);
}
.trend-kpis > div { display: flex; align-items: baseline; gap: 5px; }
.trend-kpis span { font-size: 11px; color: var(--text-3); }
.trend-kpis b {
  font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums;
  color: var(--text); letter-spacing: -.2px;
}
.trend-kpis i { font-style: normal; font-size: 10.5px; color: var(--text-3); }

/* ── 批量建任务 ─────────────────────────────────────── */
.batch-bar { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.batch-list {
  max-height: 44vh; overflow-y: auto; padding: 4px;
  border: 1px solid var(--border-soft); border-radius: var(--r-md); background: var(--surface-2);
}
.batch-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: var(--r-sm); cursor: pointer; }
.batch-item:hover { background: var(--surface-3); }
.batch-item.off { cursor: default; opacity: .6; }
.batch-item.off:hover { background: transparent; }
.batch-item.on { background: var(--accent-soft); }
.bi-main { flex: 1; min-width: 0; }
.bi-name {
  display: flex; align-items: center; gap: 7px;
  font-family: var(--mono); font-size: 12px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bi-sub { font-size: 10.5px; color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bi-state { flex: 0 0 auto; font-size: 10.5px; padding: 1px 7px; border-radius: 999px; }
.bi-state.ok { color: var(--accent); background: var(--accent-soft); }
.bi-state.no { color: var(--text-3); background: var(--surface-3); max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── 数据预览表 ─────────────────────────────────────── */
.pv-table th { white-space: nowrap; vertical-align: bottom; }
.pv-table .pv-type { font-size: 9.5px; color: var(--text-3); font-weight: 400; text-transform: none; letter-spacing: 0; }
.pv-table td {
  max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--mono); font-size: 11.5px;
}
.pv-table td.pv-null { color: var(--text-3); font-style: italic; }

/* ── 变更明细：旧值 → 新值 ─────────────────────────────── */
/* 只看变更后无法判断「这次更新对不对」：状态 3 是从 0 变来的还是本来就是 3？
   前后并排才看得清。变化的字段用颜色区分，没变的保持灰色以免干扰。 */
.chg-fields { display: flex; flex-wrap: wrap; gap: 3px 6px; }
.cf {
  display: inline-flex; align-items: baseline; gap: 3px;
  padding: 1px 5px; border-radius: 4px;
  background: var(--surface-2); font-size: 11px; line-height: 1.5;
}
.cf-k { color: var(--text-3); }
.cf-v { color: var(--text-2); font-family: var(--mono); word-break: break-all; }
/* 有变化的字段：浅底 + 新值高亮，一眼扫出「哪几个真变了」 */
.cf:has(.cf-old) { background: var(--accent-soft); }
.cf-old {
  color: var(--text-3); font-family: var(--mono);
  text-decoration: line-through; text-decoration-thickness: 1px; opacity: .8;
  word-break: break-all;
}
.cf-arrow { color: var(--text-3); font-size: 10px; }
.cf-new { color: var(--text); font-weight: 550; font-family: var(--mono); word-break: break-all; }

/* ── 今日逐小时折线图 ───────────────────────────────── */
.trend-line { position: relative; margin-top: 4px; }
.trend-line svg { display: block; width: 100%; height: auto; }
.tl-grid { stroke: var(--border-soft); stroke-width: 1; }
.tl-ylab, .tl-xlab {
  fill: var(--text-3); font-size: 9.5px;
  font-variant-numeric: tabular-nums; font-family: var(--mono);
}
.tl-ylab { text-anchor: end; }
.tl-xlab { text-anchor: middle; }
.tl-now { stroke: var(--accent); stroke-width: 1; stroke-dasharray: 3 4; opacity: .45; }
.tl-nowlab { fill: var(--accent); font-size: 9px; text-anchor: middle; opacity: .8; }
.tl-line {
  fill: none; stroke: var(--accent); stroke-width: 2;
  stroke-linejoin: round; stroke-linecap: round;
}
/* 数据点描边用卡片底色：折线穿过圆点时不会糊成一团 */
.tl-dot { fill: var(--accent); stroke: var(--surface); stroke-width: 1.6; }
.tl-dot.bad { fill: var(--err); }
.tl-hot { fill: transparent; cursor: crosshair; }
.tl-hot:hover { fill: color-mix(in srgb, var(--accent) 8%, transparent); }
.tl-tip {
  position: absolute; z-index: 5; transform: translateY(-100%);
  pointer-events: none; min-width: 176px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: 8px 10px;
  box-shadow: var(--shadow-2); font-size: 11.5px;
}
.tl-tip-h {
  font-weight: 600; font-size: 12px; margin-bottom: 5px;
  font-variant-numeric: tabular-nums;
}
.tl-tip-r { display: flex; justify-content: space-between; gap: 14px; line-height: 1.75; }
.tl-tip-r span { color: var(--text-3); }
.tl-tip-r b { font-weight: 550; font-variant-numeric: tabular-nums; }

/* ── 概览美化 ────────────────────────────────────────── */
/* 统计卡的图标加浅底纹：四张卡一字排开时，图标是唯一的视觉锚点，
   纯线条图标在浅色背景下太轻，扫一眼抓不住「这张卡说的是什么」。 */
.stat .k svg {
  box-sizing: content-box; padding: 5px; margin: -2px 2px -2px -3px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  color: var(--accent);
}
.stat { position: relative; overflow: hidden; }
/* 顶部一道极细的高光：卡片之间有了层次，不再是四块同样的灰底 */
.stat::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--accent) 55%, transparent), transparent 72%);
  opacity: .75;
}
/* 趋势 KPI 改成等宽卡片：原来是一行挤在一起的「标签 值 单位」，
   数字位数不同就对不齐，扫读时眼睛要不断重新定位 */
.trend-kpis {
  gap: 8px; padding: 0 0 14px;
}
.trend-kpis > div {
  flex-direction: column; align-items: flex-start; gap: 1px;
  padding: 7px 12px; border-radius: var(--r-md);
  background: color-mix(in srgb, var(--surface-2) 70%, transparent);
  border: 1px solid var(--border-soft);
  min-width: 84px;
}
.trend-kpis > div > span { font-size: 10.5px; letter-spacing: .2px; }
/* 第二行：数值与单位同行，单位和数值共用基线 */
.trend-kpis .tv { display: flex; align-items: baseline; gap: 3px; }
.trend-kpis .tv b { font-size: 16px; letter-spacing: -.3px; }
.trend-kpis .tv i { font-size: 10px; opacity: .9; }

/* ── 设置页 · 帮助 ───────────────────────────────────── */
.help-grid { display: grid; grid-template-columns: 232px 1fr; gap: 14px; align-items: start; }
.help-list { display: flex; flex-direction: column; gap: 6px; }
.help-item {
  text-align: left; padding: 11px 13px; cursor: pointer;
  background: var(--surface); border: 1px solid var(--border-soft);
  border-radius: var(--r-md); transition: border-color .14s var(--ease), background .14s var(--ease);
}
.help-item:hover { border-color: var(--border-hover); }
.help-item.on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 7%, transparent); }
.help-item b { display: block; font-size: 12.5px; font-weight: 550; margin-bottom: 3px; }
.help-item span { font-size: 11px; color: var(--text-3); line-height: 1.5; }
.help-item.off { opacity: .5; cursor: not-allowed; }
.help-doc {
  background: var(--surface); border: 1px solid var(--border-soft);
  border-radius: var(--r-lg); padding: 20px 24px;
  /* 撑满可用高度：184 = topbar 60 + view 上边距 24 + 页签行 60 + view 下边距 40。
     长文档在此高度内内部滚动（不留卡片下方死区），短文档自然收缩不留卡内空白。 */
  max-height: calc(100vh - 184px); overflow: auto;
}
/* 文档正文：markdown 渲染后的排版 */
.md h1, .md h2, .md h3, .md h4 { margin: 20px 0 10px; line-height: 1.35; scroll-margin-top: 12px; }
.md > h1:first-child, .md > h2:first-child { margin-top: 0; }
.md h1 { font-size: 19px; font-weight: 650; padding-bottom: 8px; border-bottom: 1px solid var(--border-soft); }
.md h2 { font-size: 15.5px; font-weight: 620; }
.md h3 { font-size: 13.5px; font-weight: 600; }
.md h4 { font-size: 12.5px; font-weight: 600; color: var(--text-2); }
.md p, .md li { font-size: 12.5px; line-height: 1.78; color: var(--text-2); }
.md p { margin: 9px 0; }
.md ul, .md ol { margin: 8px 0; padding-left: 22px; }
.md li { margin: 3px 0; }
.md li > ul, .md li > ol { margin: 2px 0; }
.md strong { font-weight: 640; color: var(--text); }
.md a { color: var(--accent); text-decoration: none; }
.md a:hover { text-decoration: underline; }
.md code {
  font-family: var(--mono); font-size: 11.5px;
  background: var(--surface-2); border: 1px solid var(--border-soft);
  border-radius: 4px; padding: 1px 5px;
}
.md pre {
  background: var(--surface-2); border: 1px solid var(--border-soft);
  border-radius: var(--r-md); padding: 11px 13px; margin: 10px 0;
  overflow-x: auto;
}
.md pre code { background: none; border: 0; padding: 0; font-size: 11.5px; line-height: 1.65; }
.md blockquote {
  margin: 10px 0; padding: 8px 14px;
  border-left: 3px solid color-mix(in srgb, var(--accent) 45%, transparent);
  background: color-mix(in srgb, var(--accent) 5%, transparent);
  border-radius: 0 var(--r-md) var(--r-md) 0;
}
.md blockquote p { margin: 4px 0; font-size: 12px; color: var(--text-2); }
.md hr { border: 0; border-top: 1px solid var(--border-soft); margin: 18px 0; }
.md table { width: 100%; border-collapse: collapse; margin: 10px 0; font-size: 12px; }
.md th, .md td { border: 1px solid var(--border-soft); padding: 6px 10px; text-align: left; }
.md th { background: var(--surface-2); font-weight: 600; }
.md td code { font-size: 11px; }
@media (max-width: 900px) {
  .help-grid { grid-template-columns: 1fr; }
}

/* ─────────────────────────────────────────────────────────
   登录页（Web 版）
   桌面版不会出现这一屏：只有需要登录的 Web 版才会渲染。
   样式复用现有设计变量，深浅色主题自动跟随。
   ───────────────────────────────────────────────────────── */
body.login-body {
  background: var(--bg);
  min-height: 100vh;
  margin: 0;
  font-family: var(--sans);
}
.login-wrap {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  /* 极淡的光晕，避免整屏纯色显得死板（不干扰文字对比度） */
  background:
    radial-gradient(1100px 520px at 50% -12%, var(--accent-soft), transparent 68%),
    var(--bg);
}
.login-card {
  width: 100%;
  max-width: 360px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-3);
  padding: 30px 28px 26px;
  display: flex;
  flex-direction: column;
  gap: 15px;
}
.login-brand { text-align: center; margin-bottom: 6px; }
.login-title {
  font-size: 20px; font-weight: 650; color: var(--text);
  letter-spacing: 0.2px;
}
.login-sub { font-size: 12.5px; color: var(--text-3); margin-top: 4px; }
.login-field { display: flex; flex-direction: column; gap: 6px; }
.login-field > span { font-size: 12px; color: var(--text-2); }
.login-field input {
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  color: var(--text);
  font-size: 13.5px;
  font-family: inherit;
  padding: 10px 12px;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.login-field input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.login-msg {
  display: none;
  font-size: 12.5px;
  line-height: 1.5;
  padding: 8px 11px;
  border-radius: var(--r-sm);
  border: 1px solid var(--err);
  background: var(--err-soft);
  color: var(--err);
}
.login-msg.ok { border-color: var(--ok); background: var(--ok-soft); color: var(--ok); }
.login-submit {
  width: 100%;
  margin-top: 3px;
  background: var(--accent);
  color: #fff;
  border: 0;
  border-radius: var(--r-md);
  font-size: 13.5px;
  font-weight: 600;
  font-family: inherit;
  padding: 10px 12px;
  cursor: pointer;
  transition: filter 0.15s var(--ease), opacity 0.15s var(--ease);
}
.login-submit:hover:not(:disabled) { filter: brightness(1.08); }
.login-submit:disabled { opacity: 0.6; cursor: default; }

/* ─────────────────────────────────────────────────────────
   账号页签（Web 版）
   ───────────────────────────────────────────────────────── */
.acct-wrap { display: flex; flex-direction: column; gap: 14px; }
.acct-me {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding-bottom: 14px; margin-bottom: 14px;
  border-bottom: 1px solid var(--border-soft);
}
.acct-me b { font-size: 14px; color: var(--text); }
.acct-pwd h4 { margin: 0 0 9px; font-size: 12.5px; color: var(--text-2); font-weight: 600; }
.acct-pwd-row { display: flex; gap: 8px; flex-wrap: wrap; }
.acct-pwd-row input {
  flex: 1 1 160px; min-width: 130px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); color: var(--text);
  font-size: 13px; font-family: inherit; padding: 8px 11px;
}
.acct-pwd-row input:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
.acct-ops { display: flex; gap: 6px; justify-content: flex-end; }
.acct-pwd-input {
  width: 100%;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); color: var(--text);
  font-size: 13px; font-family: inherit; padding: 9px 12px; margin-top: 10px;
}
.acct-pwd-input:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}

/* ─────────────────────────────────────────────────────────
   账号与权限（1.0.4 起，2026-10-28 重做）

   重做的起因：老版把「权限矩阵」横排 6 组，每组被压成一条窄柱，
   「删除任务配置」「恢复整库」这类标签全被截断 —— 看得见却读不懂；
   横向扫 6 列对比角色，认知负担也过大。

   现在的结构：
     · 页签切换（我的账号 / 用户管理 / 角色与权限），每块独立、密度均衡
     · 身份区横向排布，头像 + 名字 + 角色 + 关键数字一行放下
     · 「我能做什么」按功能分组平铺罗列，不再折叠
     · 权限改成「左侧角色列表 + 右侧单角色权限」，标签永不截断
     · 横向对比收进抽屉，按需展开，不占默认版面
   ───────────────────────────────────────────────────────── */

.acct-wrap { display: flex; flex-direction: column; gap: 14px; max-width: 1200px; }

/* ── 页签 ──────────────────────────────────────────────── */
.acct-tabs {
  display: flex; gap: 3px; padding: 3px;
  background: var(--surface-2); border: 1px solid var(--border-soft);
  border-radius: var(--r-md); width: fit-content; max-width: 100%;
}
.acct-tab {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 14px; border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--text-2);
  font-size: 12.5px; font-family: inherit; font-weight: 500;
  cursor: pointer; transition: background .13s, color .13s, box-shadow .13s;
  white-space: nowrap;
}
.acct-tab svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 1.8; }
.acct-tab:hover { color: var(--text); background: var(--surface-3); }
.acct-tab.active {
  background: var(--surface); color: var(--accent);
  box-shadow: var(--shadow-1); font-weight: 600;
}
.acct-tab-badge {
  min-width: 17px; height: 17px; padding: 0 5px; border-radius: 9px;
  background: var(--surface-3); color: var(--text-3);
  font-size: 10.5px; font-weight: 600; line-height: 17px; text-align: center;
}
.acct-tab.active .acct-tab-badge { background: var(--accent-soft); color: var(--accent); }

.acct-panel { display: block; }

/* ── 卡片通用 ──────────────────────────────────────────── */
.acct-card .card-body { padding: 20px 22px; }
.acct-card .card-head { padding: 14px 22px; }
.acct-card .card-head h3 { display: inline-flex; align-items: center; gap: 7px; font-size: 14px; }
.acct-card .card-head h3 svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 1.8; }
.acct-head-right { display: flex; align-items: center; gap: 10px; }
.acct-count { font-size: 12px; }

/* ── 身份区 ────────────────────────────────────────────── */
.acct-id { display: flex; align-items: center; gap: 16px; }
.acct-avatar {
  width: 34px; height: 34px; flex: 0 0 34px;
  display: grid; place-items: center;
  border-radius: 10px;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #fff; font-size: 14px; font-weight: 600; letter-spacing: .3px;
}
.acct-avatar-lg {
  width: 54px; height: 54px; flex: 0 0 54px;
  border-radius: 15px; font-size: 21px; font-weight: 600;
  box-shadow: 0 8px 20px -10px var(--accent);
}
.acct-id-main { flex: 1; min-width: 0; }
.acct-id-name { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.acct-id-name b { font-size: 16px; font-weight: 600; color: var(--text); }
.acct-id-sub { margin-top: 3px; font-size: 12px; color: var(--text-3); }
.acct-id-stats { display: flex; gap: 26px; padding-left: 22px; border-left: 1px solid var(--border-soft); }
.acct-stat { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; }
.acct-stat-num { font-size: 19px; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; line-height: 1.2; }
.acct-stat-label { font-size: 11px; color: var(--text-3); }

.acct-actions { display: flex; gap: 8px; margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border-soft); }

/* ── 分区标题 ──────────────────────────────────────────── */
.acct-sec { margin-top: 22px; }
.acct-sec-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 11px; }
.acct-sec-head h4 {
  margin: 0; font-size: 13px; font-weight: 600; color: var(--text);
  display: inline-flex; align-items: center; gap: 7px;
}
.acct-sec-head h4 svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 1.8; }
.acct-sec-head .muted { font-size: 11.5px; }

/* ── 「我能做什么」：按功能分组平铺 ────────────────────── */
.mine-groups { display: grid; grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); gap: 12px; }
.mine-group {
  border: 1px solid var(--border-soft); border-radius: var(--r-md);
  background: var(--surface); padding: 14px 15px;
}
.mine-group-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 9px; }
.mine-group-name { font-size: 12.5px; font-weight: 600; color: var(--text); }
.mine-group-count { font-size: 11px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.mine-list { display: flex; flex-wrap: wrap; gap: 5px; }
.mine-item {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 8px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--border-soft);
  font-size: 11.5px; color: var(--text-2); line-height: 1.5;
}
.mine-item svg { width: 11px; height: 11px; stroke: var(--ok); fill: none; stroke-width: 2.4; flex: 0 0 11px; }

/* ── 改密码 ────────────────────────────────────────────── */
.acct-pwd-sec {
  border: 1px solid var(--border-soft); border-radius: var(--r-md);
  background: var(--surface-2); padding: 16px 18px;
}
.acct-pwd-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
  gap: 12px; align-items: end;
}
.acct-pwd-item { display: flex; flex-direction: column; gap: 5px; }
.acct-pwd-item > span { font-size: 11.5px; color: var(--text-2); }
.acct-pwd-item input {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-sm); color: var(--text);
  font-size: 13px; font-family: inherit; padding: 8px 11px; width: 100%;
}
.acct-pwd-item input:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
.acct-pwd-act { justify-content: flex-end; }

/* ── 提示条 ────────────────────────────────────────────── */
.acct-tip {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 11px 13px; margin-bottom: 14px;
  background: var(--accent-soft); border: 1px solid var(--accent-line);
  border-radius: var(--r-md);
  font-size: 12px; line-height: 1.65; color: var(--text-2);
}
.acct-tip svg { width: 14px; height: 14px; flex: 0 0 14px; margin-top: 2px; stroke: var(--accent); fill: none; stroke-width: 1.8; }
.acct-tip strong { color: var(--text); font-weight: 600; }
.acct-hint { font-size: 11.5px; line-height: 1.7; }
.acct-empty { text-align: center; padding: 26px 0 !important; font-size: 12.5px !important; }

/* ── 用户表格 ──────────────────────────────────────────── */
.acct-users td { white-space: nowrap; }
.acct-users th { font-size: 11.5px !important; }
.acct-u-cell { display: flex; align-items: center; gap: 10px; }
.u-cell-txt { min-width: 0; }
.u-name { font-size: 12.5px; color: var(--text); display: flex; align-items: center; gap: 6px; }
.u-sub { font-size: 11px; color: var(--text-3); margin-top: 1px; }
.acct-when { font-size: 12px; color: var(--text-2); }
.u-role-sel {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-sm); color: var(--text);
  font-size: 12px; font-family: inherit; padding: 4px 8px; min-width: 88px;
  cursor: pointer;
}
.u-role-sel:hover { border-color: var(--border-hover); }
.u-role-sel:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.u-role-sel:disabled { opacity: .55; cursor: not-allowed; }
.acct-u-ops { text-align: right; width: 46px; }
.acct-u-ops .btn.xs { padding: 0 6px; }

/* ── 角色与权限：左列表 + 右详情 ───────────────────────── */
.role-layout { display: grid; grid-template-columns: 232px minmax(0, 1fr); gap: 18px; align-items: start; }
@media (max-width: 940px) { .role-layout { grid-template-columns: 1fr; } }

.role-side { display: flex; flex-direction: column; gap: 7px; }
.role-side-label {
  font-size: 11px; font-weight: 600; color: var(--text-3);
  letter-spacing: .06em; text-transform: uppercase; padding-left: 3px;
}
.role-item {
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  padding: 12px 14px; width: 100%; text-align: left;
  background: var(--surface); border: 1px solid var(--border-soft);
  border-radius: var(--r-md); cursor: pointer; font-family: inherit;
  transition: border-color .13s, background .13s, box-shadow .13s;
}
.role-item:hover { border-color: var(--border-hover); background: var(--surface-3); }
.role-item.active {
  border-color: var(--accent); background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent-line);
}
.role-item .ri-top { display: flex; align-items: center; gap: 7px; }
.role-item .ri-name { font-size: 13.5px; font-weight: 600; color: var(--text); }
.role-item.active .ri-name { color: var(--accent); }
.role-item .ri-desc {
  font-size: 11.5px; color: var(--text-3); line-height: 1.55;
  /* 描述可能两行；超过两行截断并给省略号 —— 不截断会让列表高度忽高忽低 */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.role-item .ri-meta { display: flex; gap: 7px; font-size: 11px; color: var(--text-3); margin-top: 1px; }

.role-main { min-width: 0; }
.role-main-head { margin-bottom: 14px; }
.role-main-title { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.role-main-title h4 { margin: 0; font-size: 15px; font-weight: 600; color: var(--text); }
.role-main-desc { margin: 5px 0 0; font-size: 12.5px; color: var(--text-2); line-height: 1.6; }

.perm-groups { display: flex; flex-direction: column; gap: 10px; }
.perm-group {
  border: 1px solid var(--border-soft); border-radius: var(--r-md);
  background: var(--surface); overflow: hidden;
}
.perm-group-head {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px; border-bottom: 1px solid var(--border-soft);
}
.pg-title { display: flex; align-items: baseline; gap: 8px; flex: 0 0 auto; }
.pg-name { font-size: 13px; font-weight: 600; color: var(--text); }
.pg-count {
  font-size: 11px; color: var(--text-3); font-variant-numeric: tabular-nums;
  background: var(--surface-3); padding: 1px 7px; border-radius: 999px;
}
.pg-desc { flex: 1; font-size: 11.5px; color: var(--text-3); min-width: 0; }
.perm-group-head .btn.xs { flex: 0 0 auto; }

.perm-list { display: flex; flex-direction: column; padding: 3px 0; }
/* 权限项：标签占主位、键名靠右 —— 两者都不截断，
   键名是给开发者看的，标签是给使用者看的，都必须完整。 */
.perm-item {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 14px; cursor: pointer; transition: background .1s;
}
.perm-item:hover { background: var(--surface-3); }
.perm-item.is-locked { cursor: not-allowed; opacity: .72; }
.perm-item input { position: absolute; opacity: 0; width: 0; height: 0; }
.perm-box {
  width: 16px; height: 16px; flex: 0 0 16px; border-radius: 5px;
  border: 1px solid var(--border-hover); background: var(--surface);
  display: grid; place-items: center; color: transparent;
  transition: background .12s, border-color .12s, color .12s;
}
.perm-box svg { width: 12px; height: 12px; stroke: currentColor; fill: none; stroke-width: 2.6; }
.perm-item input:checked + .perm-box { background: var(--accent); border-color: var(--accent); color: #fff; }
.perm-item input:focus-visible + .perm-box { box-shadow: 0 0 0 3px var(--accent-soft); }
/* 超管的勾选框：保持「已授权」的蓝色对勾，只是点不动。
   灰色方块会被读成「半选 / 没生效」—— 实际上超管是全选的。 */
.perm-item.is-locked input:checked + .perm-box { background: var(--accent); border-color: var(--accent); color: #fff; opacity: .62; }
.perm-label { flex: 1; font-size: 12.5px; color: var(--text); min-width: 0; }
.perm-key { flex: 0 0 auto; font-size: 11px; color: var(--text-3); opacity: .72; }

/* ── 角色对比（抽屉内）─────────────────────────────────── */
.cmp-wrap { display: flex; flex-direction: column; gap: 16px; max-height: 68vh; overflow-y: auto; }
.cmp-group-name {
  font-size: 12.5px; font-weight: 600; color: var(--text); margin-bottom: 7px;
}
.cmp-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.cmp-table th {
  text-align: center; font-weight: 600; color: var(--text-2);
  padding: 7px 10px; border-bottom: 1px solid var(--border);
  background: var(--surface-2); position: sticky; top: 0;
}
.cmp-table th:first-child { text-align: left; }
.cmp-table td { padding: 6px 10px; border-bottom: 1px solid var(--border-soft); }
.cmp-perm { color: var(--text-2); }
.cmp-cell { text-align: center; }
.cmp-cell.on { color: var(--ok); }
.cmp-cell svg { width: 13px; height: 13px; stroke: currentColor; fill: none; stroke-width: 2.4; }
.cmp-off { color: var(--text-3); opacity: .5; }

/* ── 角色徽标 ──────────────────────────────────────────── */
.role-badge {
  display: inline-flex; align-items: center;
  padding: 2px 9px; border-radius: 999px;
  font-size: 11px; line-height: 1.7; font-weight: 500;
  border: 1px solid var(--border-strong); color: var(--text-2);
  background: var(--surface-2); white-space: nowrap;
}
.role-badge.danger { color: var(--err); border-color: rgba(242, 85, 90, .38); background: var(--err-soft); }
.role-badge.accent { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }
.role-badge.ok { color: var(--ok); border-color: rgba(66, 196, 106, .35); background: var(--ok-soft); }
.role-badge.muted { color: var(--text-2); }

/* ── 通用小标签 ────────────────────────────────────────── */
.tag {
  display: inline-block; padding: 1px 7px; border-radius: 999px;
  font-size: 10.5px; line-height: 1.7; border: 1px solid var(--border);
  color: var(--text-2); background: var(--surface-2); white-space: nowrap;
}
.tag.ok { color: var(--ok); border-color: rgba(66, 196, 106, .35); background: var(--ok-soft); }
.tag.warn { color: var(--warn); border-color: rgba(224, 166, 62, .38); background: var(--warn-soft); }
.tag.accent { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }

/* ── 保存区 ────────────────────────────────────────────── */
.role-save-wrap { display: flex; align-items: center; gap: 8px; }
.role-dirty {
  font-size: 11px; color: var(--warn); background: var(--warn-soft);
  border: 1px solid rgba(224, 166, 62, .38);
  padding: 2px 9px; border-radius: 999px;
}

/* ── 新建用户：表单 ────────────────────────────────────── */
.nu-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 560px) { .nu-grid { grid-template-columns: 1fr; } }
.fld { display: flex; flex-direction: column; gap: 5px; }
.fld > span { font-size: 12px; color: var(--text-2); font-weight: 500; }
.fld > span i { color: var(--err); font-style: normal; }
.fld input, .fld select {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); color: var(--text);
  font-size: 13px; font-family: inherit; padding: 8px 11px; width: 100%;
}
.fld input:focus, .fld select:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
.fld input::placeholder { color: var(--text-3); }

/* ── 新建用户：角色单选卡片 ────────────────────────────── */
.role-choices { display: flex; flex-direction: column; gap: 7px; }
.role-choice {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 13px; border-radius: var(--r-md); cursor: pointer;
  background: var(--surface); border: 1px solid var(--border);
  transition: border-color .13s, background .13s;
}
.role-choice:hover { border-color: var(--border-hover); }
.role-choice.on { border-color: var(--accent); background: var(--accent-soft); }
.role-choice input { position: absolute; opacity: 0; width: 0; height: 0; }
.rc-radio {
  width: 16px; height: 16px; flex: 0 0 16px; margin-top: 2px;
  border-radius: 50%; border: 1.5px solid var(--border-hover);
  background: var(--surface); transition: border-color .13s, box-shadow .13s;
}
.role-choice.on .rc-radio { border-color: var(--accent); border-width: 5px; }
.rc-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.rc-top { display: flex; align-items: baseline; gap: 8px; }
.rc-name { font-size: 13px; font-weight: 600; color: var(--text); }
.rc-count { font-size: 11px; color: var(--text-3); }
.rc-desc { font-size: 11.5px; color: var(--text-3); line-height: 1.55; }
