/* Polaris Admin — modernized UI tokens */
:root {
  --bg: #0a0a0c;
  --bg-elev: #111114;
  --bg-elev-2: #18181b;
  --border: #27272a;
  --border-strong: #3f3f46;
  --fg: #fafafa;
  --fg-muted: #a1a1aa;
  --fg-subtle: #71717a;
  --accent: #6366f1;
  --accent-hover: #818cf8;
  --success: #10b981;
  --warning: #f59e0b;
  --danger: #ef4444;
  --radius: 8px;
  --radius-sm: 6px;
  --radius-lg: 12px;
  --shadow: 0 1px 3px rgba(0,0,0,.3), 0 1px 2px rgba(0,0,0,.2);
  --shadow-lg: 0 10px 30px rgba(0,0,0,.5);
  --transition: 150ms cubic-bezier(.4,0,.2,1);
  --sidebar-w: 220px;
  --topbar-h: 56px;
  --font: ui-sans-serif, system-ui, -apple-system, "SF Pro Text", "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, monospace;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; font-family: var(--font); color: var(--fg); background: var(--bg); font-size: 14px; line-height: 1.5; -webkit-font-smoothing: antialiased; touch-action: manipulation; }  /* manipulation：iOS Safari 尊重此条→禁用双击缩放（viewport user-scalable=no 被 iOS 忽略） */
a { color: inherit; text-decoration: none; }
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; border: 0; background: transparent; }

/* Layout */
.app { display: grid; grid-template-columns: var(--sidebar-w) 1fr; grid-template-rows: var(--topbar-h) 1fr; min-height: 100vh; transition: grid-template-columns 200ms; }
.app.collapsed { grid-template-columns: 60px 1fr; }
.sidebar { grid-row: 1 / 3; background: var(--bg-elev); border-right: 1px solid var(--border); padding: 18px 12px; display: flex; flex-direction: column; gap: 4px; overflow: hidden; }
.sidebar-brand { padding: 6px 10px 22px; display: flex; align-items: center; gap: 10px; }
.sidebar-brand .logo { width: 28px; height: 28px; min-width: 28px; border-radius: 7px; background: linear-gradient(135deg, var(--accent), #a855f7); display: grid; place-items: center; font-weight: 700; font-size: 13px; color: #fff; }
.sidebar-brand .name { font-weight: 600; font-size: 15px; letter-spacing: -.01em; white-space: nowrap; }
.sidebar-section { font-size: 11px; font-weight: 500; color: var(--fg-subtle); text-transform: uppercase; letter-spacing: .06em; padding: 14px 10px 6px; white-space: nowrap; }
.nav-link { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: var(--radius-sm); color: var(--fg-muted); transition: var(--transition); font-size: 13.5px; white-space: nowrap; }
.nav-link:hover { background: var(--bg-elev-2); color: var(--fg); }
.nav-link.active { background: var(--bg-elev-2); color: var(--fg); }
.nav-link.active::before { content: ""; display: block; width: 3px; height: 14px; background: var(--accent); border-radius: 3px; margin-left: -10px; margin-right: 7px; }
.nav-link svg { width: 16px; height: 16px; min-width: 16px; stroke-width: 2; }
.app.collapsed .sidebar-brand .name,
.app.collapsed .sidebar-section,
.app.collapsed .nav-link span { display: none; }
.app.collapsed .nav-link { justify-content: center; padding: 8px 0; }
.app.collapsed .nav-link.active::before { display: none; }
.app.collapsed .nav-link.active { background: rgba(99,102,241,.2); color: var(--accent-hover); }
.sidebar-backdrop { display: none; }

.topbar { background: var(--bg); border-bottom: 1px solid var(--border); padding: 0 24px; display: flex; align-items: center; gap: 16px; }
.topbar h1 { font-size: 15px; font-weight: 600; letter-spacing: -.01em; }
.topbar .spacer { flex: 1; }
.topbar-toggle { background: transparent; border: 0; color: var(--fg-muted); padding: 6px; cursor: pointer; border-radius: var(--radius-sm); display: grid; place-items: center; order: 0; }
.topbar-toggle:hover { background: var(--bg-elev-2); color: var(--fg); }
.topbar-toggle svg { width: 18px; height: 18px; }
.topbar .user { display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: var(--radius-sm); color: var(--fg-muted); font-size: 13px; }
.topbar .user-avatar { width: 26px; height: 26px; border-radius: 50%; background: var(--bg-elev-2); display: grid; place-items: center; font-weight: 600; font-size: 11px; color: var(--fg); }
.topbar .logout { display: inline-flex; align-items: center; gap: 6px; color: var(--fg-muted); padding: 6px 12px; border-radius: var(--radius-sm); transition: var(--transition); font-size: 13px; cursor: pointer; border: 1px solid var(--border); }
.topbar .logout:hover { background: var(--bg-elev-2); color: var(--fg); border-color: var(--border-strong); }
.topbar .logout svg { width: 14px; height: 14px; }

.main { padding: 24px; overflow: auto; }

/* Card */
.card { background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px; }
.card-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
.card-header h2 { font-size: 14px; font-weight: 600; letter-spacing: -.005em; }
.card-header .desc { font-size: 12px; color: var(--fg-subtle); margin-top: 2px; }
.card-grid { display: grid; gap: 16px; }
.card-grid.cols-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.card-grid.cols-3 { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.card-grid.cols-4 { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }

/* Stat card */
.stat { display: flex; flex-direction: column; gap: 4px; }
.stat-label { font-size: 12px; color: var(--fg-subtle); text-transform: uppercase; letter-spacing: .04em; font-weight: 500; }
.stat-value { font-size: 28px; font-weight: 600; letter-spacing: -.02em; }
.stat-sub { font-size: 12px; color: var(--fg-muted); }

/* Button */
.btn { display: inline-flex; align-items: center; gap: 6px; padding: 7px 13px; border-radius: var(--radius-sm); font-size: 13px; font-weight: 500; transition: var(--transition); background: var(--bg-elev-2); color: var(--fg); border: 1px solid var(--border); }
.btn:hover { background: var(--border); border-color: var(--border-strong); }
.btn:disabled { opacity: .4; cursor: not-allowed; }
.btn-primary { background: var(--accent); color: #fff; border-color: var(--accent); }
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn-danger { background: var(--danger); color: #fff; border-color: var(--danger); }
.btn-danger:hover { opacity: .9; }
.btn-sm { padding: 4px 10px; font-size: 12px; }
.btn svg { width: 14px; height: 14px; stroke-width: 2; }

/* Input */
.input { width: 100%; padding: 9px 12px; background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--fg); transition: var(--transition); }
.input:focus { outline: 0; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(99, 102, 241, .15); }
.input::placeholder { color: var(--fg-subtle); }
.label { display: block; font-size: 12px; font-weight: 500; color: var(--fg-muted); margin-bottom: 6px; }

/* Table */
.card > div[id*="-table"], .card > #table, .card > #tbl, .card > #env-table, .card > #matrix {
  overflow-x: auto;  /* 表格容器横向滚动，移动端不再溢出 */
  -webkit-overflow-scrolling: touch;
}
table { width: 100%; border-collapse: collapse; min-width: 600px; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border); font-size: 13px; }
th { font-weight: 500; color: var(--fg-muted); font-size: 12px; white-space: nowrap; }
tr:last-child td { border-bottom: 0; }
tr:hover td { background: var(--bg-elev-2); }
.mono { font-family: var(--font-mono); font-size: 12px; }

/* 响应式：移动端 / 手机（≤ 768px）
   sidebar 完全隐藏 → 抽屉模式覆盖；toggle 按钮浮到右上 */
@media (max-width: 768px) {
  .app { grid-template-columns: 1fr; grid-template-rows: var(--topbar-h) 1fr; }
  .app.collapsed { grid-template-columns: 1fr; }
  .sidebar { position: fixed; top: 0; left: 0; bottom: 0; width: var(--sidebar-w); transform: translateX(-100%); transition: transform 220ms cubic-bezier(.4,0,.2,1); z-index: 100; box-shadow: 4px 0 16px rgba(0,0,0,.4); }
  .app.drawer-open .sidebar { transform: translateX(0); }
  .sidebar-backdrop { display: block; position: fixed; inset: 0; background: rgba(0,0,0,.55); opacity: 0; pointer-events: none; transition: opacity 220ms; z-index: 99; backdrop-filter: blur(2px); }
  .app.drawer-open .sidebar-backdrop { opacity: 1; pointer-events: auto; }
  /* 折叠的 PC 状态在移动端无意义，强制覆盖 */
  .app.collapsed .sidebar { transform: translateX(-100%); }
  .app.collapsed.drawer-open .sidebar { transform: translateX(0); }
  .app.collapsed .sidebar-brand .name,
  .app.collapsed .sidebar-section,
  .app.collapsed .nav-link span { display: block; }
  .app.collapsed .nav-link { justify-content: flex-start; padding: 8px 10px; }
  .app.collapsed .nav-link.active::before { display: block; }

  /* topbar 紧凑 + toggle 浮到右侧 */
  .topbar { padding: 0 12px; }
  .topbar h1 { font-size: 14px; flex: 1; }
  .topbar .spacer { display: none; }
  .topbar .user { display: none; }
  /* 手机端退出：顶栏保留退出按钮（图标-only、去文字），放标题右侧——侧栏无退出，这是手机唯一入口 */
  .topbar .logout { padding: 9px 11px; }   /* 触摸目标加大 (~36px)，比顶栏汉堡稍大、好点 */
  .topbar .logout .logout-text { display: none; }
  /* 移动端 toggle 留在左侧（与侧栏同侧，affordance 一致） */
  .topbar-toggle { order: 0; }

  .main { padding: 14px; }
  .card { padding: 14px; }
  .card-header { flex-wrap: wrap; gap: 8px; }
  .card-grid.cols-4, .card-grid.cols-3, .card-grid.cols-2 { grid-template-columns: 1fr 1fr; }
  table { min-width: 700px; }  /* 触发横向滚动 */
}
@media (max-width: 480px) {
  /* cols-3/cols-2（settings 等）单列；但概览 4 个 stat 卡保持 2×2，参考 PC 横向不竖堆 */
  .card-grid.cols-3, .card-grid.cols-2 { grid-template-columns: 1fr; }
  .card-grid.cols-4 { grid-template-columns: 1fr 1fr; gap: 10px; }
  .card.stat { padding: 12px; }
  .stat-value { font-size: 22px; }
  .stat-label { font-size: 11px; }
}
/* ── 全局移动端卡片头工具条：标题与操作分两行，操作组整行换行不挤压；搜索/输入框占满整行 ── */
@media (max-width: 640px) {
  .card-header { flex-wrap: wrap; gap: 10px; align-items: flex-start; }
  .card-header > h2, .card-header > div:first-child { min-width: 0; }
  /* 操作区（按钮/搜索 容器，通常是 .flex）整行、内部换行 */
  .card-header > .flex { width: 100%; flex-wrap: wrap; gap: 8px; align-items: center; }
  /* 卡片头里的搜索/输入框占满一行（flex-basis 覆盖内联固定宽度） */
  .card-header > .flex .input { flex: 1 1 100%; min-width: 0; }
  /* 工具条按钮：触摸目标够大、不被压扁 */
  .card-header > .flex .btn { flex: 0 1 auto; }
  /* 任何内联固定宽度的输入在窄屏不溢出视口 */
  .input { max-width: 100%; }
}

/* Badge */
.badge { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: 999px; font-size: 11px; font-weight: 500; background: var(--bg-elev-2); color: var(--fg-muted); border: 1px solid var(--border); }
.badge-success { background: rgba(16, 185, 129, .12); color: var(--success); border-color: rgba(16, 185, 129, .3); }
.badge-warning { background: rgba(245, 158, 11, .12); color: var(--warning); border-color: rgba(245, 158, 11, .3); }
.badge-danger { background: rgba(239, 68, 68, .12); color: var(--danger); border-color: rgba(239, 68, 68, .3); }
.badge-accent { background: rgba(99, 102, 241, .12); color: var(--accent-hover); border-color: rgba(99, 102, 241, .3); }
.dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

/* Dialog */
dialog { background: var(--bg-elev); color: var(--fg); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 0; max-width: 90vw; box-shadow: var(--shadow-lg); position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); margin: 0; }
dialog::backdrop { background: rgba(0,0,0,.6); backdrop-filter: blur(4px); }
dialog .dlg-header { padding: 16px 20px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; }
dialog .dlg-body { padding: 16px 20px; max-height: 60vh; overflow: auto; }
dialog .dlg-footer { padding: 12px 20px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 8px; }

/* 历史版本：右侧全高抽屉浮窗（覆盖 dialog 居中），而非居中对话框 */
#hist-dialog { top: 0; right: 0; left: auto; bottom: 0; transform: none; margin: 0; width: 380px; max-width: 92vw; height: 100vh; max-height: 100vh; border-radius: 0; border-top: none; border-right: none; border-bottom: none; }
#hist-dialog[open] { animation: histSlideIn .22s ease; }
#hist-dialog .dlg-body { max-height: calc(100vh - 57px); }
@keyframes histSlideIn { from { transform: translateX(100%); } to { transform: translateX(0); } }
@media (max-width: 480px) { #hist-dialog { width: 92vw; } }

/* Status bar */
.status-bar { padding: 8px 16px; font-size: 12px; color: var(--fg-subtle); font-family: var(--font-mono); border-top: 1px solid var(--border); background: var(--bg); }
.status-bar.status-err { color: var(--danger); }
.status-bar.status-ok { color: var(--success); }

/* Empty state */
.empty { padding: 60px 20px; text-align: center; color: var(--fg-subtle); }
.empty svg { width: 40px; height: 40px; margin-bottom: 12px; opacity: .5; }

/* SVC v4/v6 dot pair（dashboard 矩阵 + nodes 详情）
   状态视觉：on=绿(实)；off=红(实)；na=灰(未上报，虚)。off 必须比 na 明显，三态可区分 */
.svc-pair { display: inline-flex; gap: 2px; padding: 2px; border-radius: 6px; border: 1px solid transparent; }
.svc-pair.mixed { border-color: rgba(245,158,11,.35); background: rgba(245,158,11,.05); }  /* 单栈通的整 cell 框 */
.svc-dot { width: 18px; height: 18px; border-radius: 4px; display: grid; place-items: center; font-size: 9.5px; font-weight: 600; font-family: var(--font-mono); background: var(--bg-elev-2); color: var(--fg-subtle); border: 1px solid var(--border); }
.svc-dot.on { background: rgba(16,185,129,.25); color: #34d399; border-color: rgba(16,185,129,.5); }
.svc-dot.off { background: rgba(239,68,68,.22); color: #fca5a5; border-color: rgba(239,68,68,.45); }
.svc-dot.na { background: transparent; color: var(--fg-subtle); border-color: var(--border); border-style: dashed; opacity: .65; }

/* Toast */
#toast-container { position: fixed; top: 20px; left: 50%; transform: translateX(-50%); z-index: 9999; display: flex; flex-direction: column; gap: 8px; pointer-events: none; }
.toast { background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 16px; font-size: 13.5px; box-shadow: var(--shadow-lg); display: flex; align-items: center; gap: 10px; min-width: 200px; max-width: 480px; pointer-events: auto; opacity: 0; transform: translateY(-8px); transition: opacity 200ms, transform 200ms; }
.toast.show { opacity: 1; transform: translateY(0); }
.toast.toast-ok { border-color: rgba(16,185,129,.5); }
.toast.toast-ok::before { content: "✓"; color: var(--success); font-weight: 700; }
.toast.toast-err { border-color: rgba(239,68,68,.5); }
.toast.toast-err::before { content: "!"; color: var(--danger); font-weight: 700; width: 18px; height: 18px; background: rgba(239,68,68,.15); border-radius: 50%; display: grid; place-items: center; font-size: 11px; }
.toast.toast-info::before { content: "ⓘ"; color: var(--accent-hover); }

/* Switch */
.switch { position: relative; display: inline-block; width: 36px; height: 20px; }
.switch input { opacity: 0; width: 0; height: 0; }
.switch::after { content: ""; position: absolute; inset: 0; background: var(--border); border-radius: 20px; transition: var(--transition); cursor: pointer; }
.switch::before { content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; background: var(--fg); border-radius: 50%; transition: var(--transition); z-index: 1; cursor: pointer; }
.switch input:checked ~ ::before { transform: translateX(16px); }
.switch:has(input:checked)::after { background: var(--accent); }
.switch:has(input:checked)::before { transform: translateX(16px); background: #fff; }

/* Utility */
.flex { display: flex; align-items: center; gap: 8px; }
.text-muted { color: var(--fg-muted); }
.text-subtle { color: var(--fg-subtle); }
.text-sm { font-size: 12px; }
.mt-2 { margin-top: 8px; }
.mt-4 { margin-top: 16px; }
.mb-2 { margin-bottom: 8px; }
.mb-4 { margin-bottom: 16px; }
.gap-2 { gap: 8px; }
.gap-4 { gap: 16px; }
.hidden { display: none !important; }

/* 信息提示横幅 — 跟 card 视觉对齐 */
.info, .info-bar, .note {
  padding: 14px 18px;
  background: rgba(99,102,241,.06);
  border: 1px solid rgba(99,102,241,.22);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  color: var(--fg-muted);
  font-size: 13px;
  line-height: 1.6;
  margin-bottom: 20px;
}
.info b, .info-bar b, .note b,
.info strong, .info-bar strong, .note strong { color: var(--fg); font-weight: 600; }
.info a, .info-bar a, .note a { color: var(--accent-hover); }
.note.warning {
  background: rgba(245,158,11,.06);
  border-color: rgba(245,158,11,.25);
  border-left-color: #f59e0b;
  color: #fbbf24;
}
.note.warning b, .note.warning strong { color: #fde68a; }

/* macOS 风格 overlay 滚动条：默认透明，滚动/hover 时显示，500ms 后淡出（layout-polaris.js 注入 .scrolling class） */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-corner { background: transparent; }
::-webkit-scrollbar-thumb {
  background: transparent;
  border-radius: 4px;
  transition: background 0.3s;
}
::-webkit-scrollbar-thumb:hover { background: var(--border-strong); }
.scrolling::-webkit-scrollbar-thumb { background: var(--border); }
/* Firefox：thin + 默认透明；scrolling / hover 时显示灰 */
* { scrollbar-width: thin; scrollbar-color: transparent transparent; }
.scrolling { scrollbar-color: var(--border) transparent; }
*:hover { scrollbar-color: var(--border) transparent; }

/* toggle 按钮 active 状态（如模板编辑器「换行」按钮）— 用 outline + accent 颜色，不跟 btn-primary 同色 */
.btn[aria-pressed="true"] {
  background: rgba(99,102,241,.12);
  border-color: var(--accent);
  color: var(--accent-hover);
}

/* 模板对比视图工具条（Monaco diff editor 上方） */
.diff-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-elev-2);
  flex-shrink: 0;
}
.diff-bar .spacer { flex: 1; }
.diff-bar .diff-label { font-size: 12px; color: var(--fg-subtle); font-family: var(--font-mono); }
