/* 配置备份 Web 管理 - 默认浅色主题 */
:root {
    --bg: #f6f8fa;
    --bg-card: #ffffff;
    --bg-elevated: #f0f2f5;
    --bg-soft: #eef2f7;
    --border: #d0d7de;
    --text: #1f2328;
    --text-muted: #656d76;
    --primary: #0969da;
    --primary-hover: #0550ae;
    --success: #1a7f37;
    --error: #cf222e;
    --warn: #9a6700;
    --radius: 12px;
    --radius-lg: 18px;
    --shadow: var(--shadow-1);
    --shadow-card: var(--shadow-2);
    --glass: rgba(255,255,255,.9);
    --accent: var(--primary);
    --page-pad-x: clamp(1rem, 2vw, 2rem);
    --page-pad-y: clamp(1rem, 1.8vw, 1.75rem);
    --shell-max: none;
    --card-pad: clamp(1rem, 1.35vw, 1.35rem);
    /* 字体层级（全站统一字号，避免各页面大小不一） */
    /* 2026-07-25 方案A：全站字号 ≈-20% 并整数化（用户要求整数 px、无小数）。
       sm/base/md 比严格 ×0.8 各上浮 1px——四舍五入会让相邻档撞值丢层级，
       这是「整数 + 保持八档单调」的唯一解。px 不随浏览器默认字号偏好缩放，
       属整数化的已知代价（内网运维平台可接受）。 */
    --fs-2xs: 9px;         /* 极小标注/角标（原11px） */
    --fs-xs: 10px;         /* 次要说明（原12px） */
    --fs-sm: 11px;         /* 表格/小字/紧凑控件（原13px） */
    --fs-base: 12px;       /* 正文/表单控件（原14px） */
    --fs-md: 13px;         /* 强调正文/小节标题（原15px） */
    --fs-lg: 14px;         /* 卡片标题（原17px） */
    --fs-xl: 16px;         /* 区块标题（原20px） */
    --fs-2xl: 19px;        /* 页面标题（原24px） */
    /* 字体族（此前 --font-mono/--mono/--font-sans 被多处引用却从未定义，
       等宽列一直落在浏览器默认 monospace 上；在此统一定义，旧引用自动生效） */
    --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
                 "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
    --font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas,
                 "Liberation Mono", "Courier New", monospace;
    --mono: var(--font-mono);    /* 历史别名，旧规则仍在引用 */
    /* 行高层级。1.2/1.4 未设令牌：1.4 与 --control-h 的控件高度计算耦合，
       1.2 多用于图形组件内部，均属刻意值，勿归一。 */
    --lh-single: 1;      /* 单行按钮/徽标 */
    --lh-display: 1.1;   /* 大数字统计/KPI 展示 */
    --lh-tight: 1.3;     /* 紧凑说明/标签 */
    --lh-normal: 1.5;    /* 正文/多行提示 */
    /* 表单控件统一规格 */
    --control-h: 30px;               /* 控件统一高度（方案A随字号同步 36→30，整数） */
    --control-pad-y: 5px;
    --control-pad-x: 8px;
    --control-radius: 8px;           /* 控件/按钮统一圆角 */
    --control-bg: var(--bg);
    --focus-ring: 0 0 0 3px rgba(9,105,218,.16);

    /* ---- 间距网格（Phase 1）----
       此前全站 padding 有 152 种取值、gap 有 55 种，每个模块作者各拍各的
       0.35/0.4/0.45/0.6rem。这里定一套 4px 基准网格，所有间距只能取这 8 档。
       档位是按**实测最常用值**选的，不是照搬 8pt 网格：加了 6px 和 20px 两档，
       是为了让原来的 0.35~0.4rem 和 1.2rem 能就近落位、误差不超过 2px，
       从而在收敛的同时**保持既有信息密度不变**（这是本次的硬要求）。 */
    --space-1: 0.25rem;    /*  4px  紧贴：图标与文字、徽标内边距 */
    --space-2: 0.375rem;   /*  6px  紧凑控件内边距 */
    --space-3: 0.5rem;     /*  8px  控件内边距、表格单元纵向 */
    --space-4: 0.75rem;    /* 12px  控件横向内边距、表格单元横向 */
    --space-5: 1rem;       /* 16px  卡片内边距、区块间距 */
    --space-6: 1.25rem;    /* 20px  卡片内边距（宽松） */
    --space-7: 1.5rem;     /* 24px  区块之间 */
    --space-8: 2rem;       /* 32px  页面级分隔 */

    /* ---- 圆角（Phase 1）：22 种取值收敛到 5 档 + 药丸 + 正圆 ---- */
    --radius-xs: 4px;      /* 进度条、细条、微型标记 */
    --radius-sm: 6px;      /* 小徽标、内嵌块 */
    --radius-md: 8px;      /* 表单控件与按钮（= --control-radius） */
    --radius-lg: 12px;     /* 卡片、面板（= --radius） */
    --radius-xl: 18px;     /* 大容器、模态框 */
    --radius-pill: 999px;  /* 标签、状态胶囊 */

    /* ---- 阴影（Phase 1）：53 种取值收敛到 3 档 ----
       只收敛"投影"，机柜 3D 可视化用的 inset 内阴影是功能性立体效果，未动。
       刻意做得比原来轻：原先多处用 0 8px 24px rgba(0,0,0,.15) 这类重投影，
       在浅色界面上显脏。Apple 系统界面的分层主要靠 1px 边框 + 极轻投影。 */
    --shadow-1: 0 1px 2px rgba(0,0,0,.06);      /* 贴边：输入框、内联块 */
    --shadow-2: 0 4px 12px rgba(0,0,0,.08);     /* 抬起：卡片、下拉 */
    --shadow-3: 0 12px 32px rgba(0,0,0,.14);    /* 浮层：模态框、气泡 */
    /* 顶栏是 position:sticky top:0，表头吸顶要让开它，否则会被盖住 */
    --app-header-h: 57px;

    /* ---- 操作列色板（Phase 2）----
       表格操作列按动作类型区分色相是既有规范（见 .device-actions），保留。
       但原来四种色相全是硬编码 hex，其中"主操作"用的是 #0071e3——旧 Apple 蓝，
       与 --primary(#0969da) 不是同一个颜色，于是同一屏里出现三种蓝。
       改为令牌后色相统一由这里定义，深色主题可整体提亮。 */
    --act-primary: var(--primary);
    --act-neutral: #0d9488;
    --act-success: var(--success);
    --act-info:    var(--act-info);
}

* { box-sizing: border-box; }
body {
    margin: 0;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    font-family: var(--font-sans);
    /* 基础字号必须落在 body：此前从未设置，未显式定字号的元素一直吃浏览器
       默认 16px，--fs-base 对它们形同虚设——补上这行才是真正的全站生效 */
    font-size: var(--fs-base);
    background:
        radial-gradient(circle at top left, rgba(9, 105, 218, 0.06), transparent 28rem),
        var(--bg);
    color: var(--text);
    line-height: var(--lh-normal);
    font-weight: 400;
    letter-spacing: -0.022em;
}
a { color: var(--primary); text-decoration: none; transition: color .2s ease; }
a:hover { color: var(--primary-hover); }

/* ===== 全站统一：表单控件基础样式（让所有搜索框/输入框/下拉框一致） ===== */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]),
select,
textarea {
    font-family: inherit;
    font-size: var(--fs-base);
    color: var(--text);
    /* 背景走变量：搜索框要在框内画放大镜，而这条基础规则的 background 简写
       特异性(0,5,1) 压过任何 [data-search-input] 选择器，直接写 background-image
       会被它重置掉。改成由这里读 --input-icon，图标就能由低特异性规则注入。 */
    background: var(--control-bg) var(--input-icon, none) no-repeat left var(--space-3) center;
    border: 1px solid var(--border);
    border-radius: var(--control-radius);
    /* 左内边距同样走变量：搜索框要给放大镜让位，而直接写 padding-left
       会被这条高特异性规则压掉（与背景图同一个原因） */
    padding: var(--control-pad-y) var(--control-pad-x) var(--control-pad-y) var(--input-pad-left, var(--control-pad-x));
    min-height: var(--control-h);
    box-sizing: border-box;
    transition: border-color .15s ease, box-shadow .15s ease;
}
/* 单行控件锁死同一高度。此前 input 走 min-height+padding、
   而设置页/弹窗/筛选栏那条规则走 height+padding:0，两套机制并存，
   在选择器不重叠的页面就出现"输入框和下拉框不一样高"（实测 6.4px vs 4.8px）。
   统一到一套：单行控件用固定高度，textarea 例外（要能撑高）。 */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]),
select { height: var(--control-h); }
textarea { min-height: 4.5rem; height: auto; line-height: var(--lh-normal); }
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):focus,
select:focus,
textarea:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: var(--focus-ring);
}
input::placeholder, textarea::placeholder { color: var(--text-muted); opacity: 0.8; }

/* 标题字重：浏览器 UA 默认给 h1~h6 是 bold(700)，而全站字重已收敛到
   400/500/600 三档。不覆盖的话页面里会混进 700，在 13~14px 的密集界面上
   与 600 几乎分辨不出，只是让版面变吵。字号仍由各处的 --fs-* 决定，这里只管字重。 */
h1, h2, h3, h4, h5, h6, b, strong { font-weight: 600; }

/* 登录页 - Apple 风格：大标题、留白、简洁表单 */
.login-page {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 3rem 1.5rem;
    background: var(--bg);
}
.login-wrapper {
    max-width: 400px;
    width: 100%;
    text-align: center;
}
.login-card {
    background: var(--bg-card);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
    padding: 3rem 2.5rem;
    border: 1px solid var(--border);
}
.login-header {
    margin-bottom: 2rem;
}
.login-logo {
    width: 48px;
    height: 48px;
    margin: 0 auto var(--space-5);
    border-radius: var(--radius-lg);
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, var(--act-primary) 0%, #00c7be 100%);
    color: #fff;
    font-size: var(--fs-2xl);
    font-weight: 400;
}
.login-header h1 {
    margin: 0;
    font-size: 22px;
    font-weight: 600;
    letter-spacing: -0.025em;
    color: var(--text);
}
.login-tagline,
.login-header p {
    margin: var(--space-2) 0 0;
    color: var(--text-muted);
    font-size: var(--fs-md);
    font-weight: 400;
}
.login-form .form-row {
    margin-bottom: 1.25rem;
    text-align: left;
}
.login-form label {
    display: block;
    margin-bottom: 0.4rem;
    font-size: var(--fs-base);
    font-weight: 500;
    color: var(--text);
}
.login-form input {
    width: 100%;
    padding: var(--space-4) var(--space-5);
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--bg-card);
    color: var(--text);
    font-size: var(--fs-md);
    transition: border-color .2s ease, box-shadow .2s ease;
}
.login-form input:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: var(--shadow-1);
}
.login-btn {
    width: 100%;
    margin-top: 0.75rem;
    padding: var(--space-4) var(--space-7);
    font-size: var(--fs-md);
    font-weight: 500;
    border-radius: var(--radius);
}
.login-error {
    margin-top: 1rem;
    color: var(--error);
    font-size: var(--fs-base);
    min-height: 1.2em;
}
.login-divider {
    margin: var(--space-7) 0 var(--space-5);
    text-align: center;
    font-size: var(--fs-sm);
    color: var(--text-muted);
}
.login-oauth {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.login-oauth-btn {
    width: 100%;
}
.login-footer {
    margin-top: 1.5rem;
    font-size: var(--fs-sm);
    color: var(--text-muted);
    line-height: var(--lh-normal);
}

/* 顶栏 - 与 main 同宽，系统名与运维概览左对齐 */
.app-header {
    min-height: 56px;
    background: var(--glass);
    backdrop-filter: saturate(180%) blur(20px);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 90;
}
.app-header-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: clamp(0.75rem, 1.2vw, 1.25rem);
    padding: 0 var(--page-pad-x);
    min-height: 56px;
    max-width: var(--shell-max);
    margin: 0 auto;
    width: 100%;
}
.header-right { display: flex; align-items: center; gap: var(--space-3); flex: 0 0 auto; }
/* 顶栏 Web 终端按钮：设备 CLI 的唯一入口，独立窗口打开 */
.header-webterm {
    display: flex; align-items: center; gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    border-radius: var(--control-radius);
    border: 1px solid var(--border);
    background: var(--bg-elevated, var(--bg));
    color: var(--text);
    font-size: var(--fs-sm);
    cursor: pointer;
    transition: border-color .2s ease, color .2s ease;
}
.header-webterm:hover { border-color: var(--primary); color: var(--primary); }
.header-webterm:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* icon 加个方框 = 一块终端屏幕，里面是提示符。
   用 flex 居中而不是 line-height 对齐：▸_ 两个字形基线差很大，line-height 会把它顶偏。 */
.header-webterm-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.15rem;
    height: 1.15rem;
    border: 1px solid currentColor;
    border-radius: var(--radius-xs);
    color: var(--primary);
    font-family: var(--font-mono);
    font-size: var(--fs-2xs);
    letter-spacing: -0.05em;   /* ▸ 和 _ 挤紧一点，像一个提示符而不是两个字 */
}
.theme-switcher { position: relative; }
.theme-btn {
    padding: var(--space-2) var(--space-4);
    font-size: var(--fs-sm);
    color: var(--text-muted);
    background: transparent;
    border: none;
    border-radius: var(--radius);
    cursor: pointer;
    transition: color .2s ease;
}
.theme-btn:hover { color: var(--text); }
/* 外观下拉使用固定配色，确保在各主题下文字都清晰可读 */
.theme-dropdown {
    display: none;
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 6px;
    min-width: 160px;
    background: #ffffff;
    border: 1px solid #d0d7de;
    border-radius: var(--radius);
    box-shadow: var(--shadow-3);
    z-index: 50;
    overflow: hidden;
}
.theme-switcher.open .theme-dropdown { display: block; }
.theme-dropdown button.active { font-weight: 600; }

/* 自绘文件选择控件（原生按钮文案无法 i18n） */
.file-pick-native {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    min-height: 0 !important;
    padding: 0 !important;
    opacity: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    pointer-events: none;
}
.file-pick-name {
    color: var(--text-muted);
    font-size: var(--fs-sm);
    margin-left: 0.5rem;
    max-width: 16rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: inline-block;
    vertical-align: middle;
}
.file-pick-name.file-pick-selected { color: var(--text); }
.theme-dropdown button {
    display: block;
    width: 100%;
    padding: var(--space-3) var(--space-5);
    text-align: left;
    border: none;
    background: none;
    color: #1f2328;
    cursor: pointer;
    font-size: var(--fs-base);
    transition: background .15s ease;
}
.theme-dropdown button:hover { background: #f0f2f5; color: #1f2328; }
.theme-dropdown button:focus { outline: none; background: #f0f2f5; }
.brand {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    font-weight: 600;
    font-size: var(--fs-xl);
    color: var(--text);
    letter-spacing: -0.02em;
    flex: 0 0 auto;
    min-width: max-content;
}
.brand:hover { text-decoration: none; color: var(--text); opacity: .9; }
.brand-icon {
    color: var(--primary);
    font-size: var(--fs-lg);
    font-weight: 400;
}
.brand-logo {
    width: 48px;
    height: 48px;
    object-fit: contain;
    border-radius: var(--radius-xs);
}
.nav-tabs {
    display: flex;
    gap: var(--space-1);
    align-items: center;
    flex: 1 1 auto;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: thin;
    padding: var(--space-2) 0;
}
.nav-tabs::-webkit-scrollbar { height: 4px; }
.nav-tabs::-webkit-scrollbar-thumb { background: var(--border); border-radius: var(--radius-pill); }
/* 窄屏导航横向滚动时，在溢出的一侧把菜单渐隐为透明，提示还有更多项。
   用 mask-image 而非彩色遮罩：与主题无关、透出下方玻璃背景。类由 JS 按滚动位置切换。 */
.nav-tabs.nav-ovl:not(.nav-ovr) {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 32px);
    mask-image: linear-gradient(to right, transparent, #000 32px);
}
.nav-tabs.nav-ovr:not(.nav-ovl) {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent);
}
.nav-tabs.nav-ovl.nav-ovr {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 32px, #000 calc(100% - 32px), transparent);
    mask-image: linear-gradient(to right, transparent, #000 32px, #000 calc(100% - 32px), transparent);
}
/* 授权状态全局横幅（评估/临期/宽限/过期） */
.license-banner {
    padding: 0.5rem var(--page-pad-x);
    text-align: center;
    font-size: var(--fs-sm);
    border-bottom: 1px solid var(--border);
}
.license-banner-info { background: rgba(59, 130, 246, 0.12); color: var(--text); }
.license-banner-warn { background: rgba(245, 158, 11, 0.16); color: #d97706; }
.license-banner-error { background: rgba(239, 68, 68, 0.16); color: #ef4444; }
[data-theme="dark"] .license-banner-warn { color: #fbbf24; }
[data-theme="dark"] .license-banner-error { color: #f87171; }
/* 授权状态卡片 */
.license-status-grid { display: grid; gap: var(--space-3); }
.license-status-row { display: flex; justify-content: space-between; gap: var(--space-5); align-items: baseline; }
.license-status-label { color: var(--text-muted); font-size: var(--fs-sm); }
.license-status-value { font-weight: 500; text-align: right; }
/* 授权/MFA/变更工单状态徽章：统一状态 pill 配方（同 .state-pill） */
.license-badge { display: inline-flex; align-items: center; justify-content: center; min-width: 38px; padding: 0.12rem 0.5rem; border-radius: var(--radius-pill); font-size: var(--fs-xs); font-weight: 600; white-space: nowrap; }
.license-badge-ok { background: rgba(34, 197, 94, 0.14); color: #39d98a; }
.license-badge-warn { background: rgba(245, 158, 11, 0.16); color: #f59e0b; }
.license-badge-err { background: rgba(239, 68, 68, 0.16); color: #ff6b6b; }
.nav-dropdown {
    position: relative;
    display: inline-flex;
    align-items: center;
}
.nav-dropdown-toggle {
    border: 0;
    background: transparent;
    cursor: pointer;
}
.nav-dropdown-toggle::after {
    content: '▾';
    margin-left: 0.25rem;
    font-size: var(--fs-2xs);
    color: var(--text-muted);
}
.nav-dropdown-menu {
    position: absolute;
    top: calc(100% + 0.35rem);
    left: 0;
    z-index: 80;
    display: none;
    min-width: 132px;
    padding: var(--space-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-card);
    box-shadow: var(--shadow);
}
.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown:focus-within .nav-dropdown-menu {
    display: grid;
    gap: var(--space-1);
}
.nav-dropdown-menu .tab {
    display: block;
    white-space: nowrap;
}
.tab {
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius);
    color: var(--text);
    font-size: var(--fs-base);
    transition: background .15s ease, color .15s ease;
    white-space: nowrap;
}
.tab:hover { background: var(--bg-elevated); color: var(--text); text-decoration: none; }
.tab.active { color: var(--primary); font-weight: 500; background: transparent; }
.tab.active:hover { background: var(--bg-elevated); }
.header-user {
    font-size: var(--fs-sm);
    color: var(--text-muted);
}
.header-user strong { color: var(--text); font-weight: 500; }
.header-logout { font-size: var(--fs-sm); color: var(--primary); }
.header-logout:hover { text-decoration: none; }

.main {
    flex: 1;
    padding: var(--page-pad-y) var(--page-pad-x) 2rem;
    width: 100%;
    max-width: var(--shell-max);
    margin: 0 auto;
    box-sizing: border-box;
}

/* 页脚 - Apple 风格：简洁一行、小字、灰色 */
.app-footer {
    margin-top: auto;
    min-height: 2rem;
    padding: 0.85rem var(--page-pad-x);
    border-top: 1px solid var(--border);
    font-size: var(--fs-xs);
    color: var(--text-muted);
    background: var(--bg);
    flex-shrink: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: var(--space-1);
    visibility: visible;
}
.app-footer-sep { margin: 0 var(--space-2); opacity: 0.6; }
.app-footer-custom,
.app-footer-time,
.app-footer-ip { white-space: nowrap; }

.panel { display: none; }
.panel.active { display: block; }
.panel-actions { display: flex; align-items: center; justify-content: flex-end; gap: var(--space-3); flex-wrap: wrap; }
/* 设备列表搜索框：拉长，支持全表内容搜索 */
.device-search-input { flex: 1 1 420px; min-width: 320px; max-width: 640px; }
/* 启用列可点击的是/否切换按钮 */
.device-enabled-toggle { min-width: 2.6rem; font-weight: 600; }
.device-enabled-toggle.is-on { background: rgba(18,209,80,.14); color: #12d150; border: 1px solid rgba(18,209,80,.45); }
.device-enabled-toggle.is-off { background: rgba(148,163,184,.12); color: var(--text-muted); border: 1px solid var(--border); }
/* ICMP/SSH/Telnet 连通性测试结果 */
.conn-test-list { display: flex; flex-direction: column; gap: var(--space-3); margin: var(--space-4) 0; }
.conn-test-row { display: flex; align-items: center; gap: var(--space-4); }
.conn-test-name { width: 4.5rem; font-weight: 600; }
.conn-test-badge { padding: var(--space-1) var(--space-3); border-radius: var(--radius-sm); font-size: var(--fs-sm); font-weight: 600; white-space: nowrap; }
.conn-test-badge.ok { background: rgba(18,209,80,.15); color: #12d150; }
.conn-test-badge.fail { background: rgba(255,45,45,.15); color: #ff6b6b; }
.conn-test-extra { color: var(--text-muted); font-size: var(--fs-sm); }
.filters-bar {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    padding: var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-soft);
}
.log-fail-filter-wrap { display: inline-flex; align-items: center; gap: var(--space-3); margin-left: 0.75rem; }
.log-fail-filter-wrap .log-fail-date-label { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--fs-base); color: var(--text-muted); }
.log-fail-filter-wrap .log-fail-date { padding: var(--space-2) var(--space-3); border-radius: var(--control-radius); border: 1px solid var(--border); background: var(--bg); color: var(--text); font-size: var(--fs-base); }
.log-fail-count-link { cursor: pointer; text-decoration: underline; }
.log-fail-count-link:hover { color: var(--primary); }
/* ============================================================
   筛选栏与分页：组件级统一（不改模板结构，在样式层归一）
   ------------------------------------------------------------
   【为什么要这一层】令牌统一了取值，但组件结构没统一。实测各页搜索框宽度：
     库存 1059px / DCIM 813px / 资源索引 360px / 配置备份 320px / IPAM 300px /
     邻居 280px / 备份任务 260px / 自动发现 229px / 配置变动 175px
   最宽是最窄的 6 倍。根因是每个模块自造了一个工具栏类
   （filters-bar / devices-toolbar / rack-list-toolbar / user-list-toolbar /
     inv-toolbar / ipam-toolbar / resource-summary-toolbar / rpt-toolbar /
     topology-toolbar / traffic-graph-toolbar …至少 10 种），
   各写各的布局，`.filters-bar input{width:180px}` 只管到其中一种。
   这里把它们全部并入同一规格：一处改，全站生效。
   ============================================================ */
.filters-bar,
.devices-toolbar,
.rack-list-toolbar,
.user-list-toolbar,
.inv-toolbar,
.ipam-toolbar,
.resource-summary-toolbar,
.rpt-toolbar,
.topology-toolbar,
.traffic-graph-toolbar,
.system-status-toolbar {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
}

/* 搜索/筛选输入：统一伸缩规格。
   用 flex 而不是固定 width——固定宽度在窄屏会溢出，纯 flex:1 又会像库存页
   那样撑到 1059px。基准 260px、可压到 200、最多长到 320，各页宽度差再也不会
   超过 120px，视觉上就是"同一个搜索框"。 */
.filters-bar input[type="text"],
.filters-bar input[type="search"],
.devices-toolbar input[type="text"],
.rack-list-toolbar input[type="text"],
.user-list-toolbar input[type="text"],
.inv-toolbar input[type="text"],
.ipam-toolbar input[type="text"],
.resource-summary-toolbar input[type="text"],
.rpt-toolbar input[type="text"],
.topology-toolbar input[type="text"],
.traffic-graph-toolbar input[type="text"] {
    flex: 1 1 260px;
    min-width: 200px;
    max-width: 320px;
    width: auto;
}
/* 搜索框与搜索按钮永远相邻且排在最右：用 flex/grid 的 order 实现，
   不需要改任何模板的 DOM 顺序。其余筛选控件保持默认 order:0，自然落到左侧。
   这样"中间夹着别的过滤框"的情况全站消失，而且以后新增筛选项也不会插进来。 */
.filters-bar > *,
.devices-toolbar > *,
.rack-list-toolbar > *,
.user-list-toolbar > *,
.inv-toolbar > *,
.ipam-toolbar > *,
.resource-summary-toolbar > * { order: 0; }
.filters-bar [data-search-input],
.devices-toolbar [data-search-input],
.rack-list-toolbar [data-search-input],
.user-list-toolbar [data-search-input],
.inv-toolbar [data-search-input],
.ipam-toolbar [data-search-input],
.resource-summary-toolbar [data-search-input] { order: 90; }
.filters-bar [data-search-btn],
.devices-toolbar [data-search-btn],
.rack-list-toolbar [data-search-btn],
.user-list-toolbar [data-search-btn],
.inv-toolbar [data-search-btn],
.ipam-toolbar [data-search-btn],
.resource-summary-toolbar [data-search-btn] { order: 91; }
/* 「按当前结果执行」的动作按钮排在搜索按钮之后：它们作用的对象就是搜索结果，
   排在搜索框左侧会读成"与筛选并列的另一个条件"，语义是反的。 */
.filters-bar [data-after-search],
.devices-toolbar [data-after-search],
.rack-list-toolbar [data-after-search] { order: 92; }

/* 搜索框内嵌放大镜：placeholder 文案已按要求全部去掉，用图标保留"这是搜索框"的
   可识别性，同时保持框内干净。图标随主题变色（currentColor 取不到，用两套 URL）。 */
[data-search-input] {
    --input-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 16 16'><g fill='none' stroke='%23999' stroke-width='1.6'><circle cx='7' cy='7' r='4.5'/><path d='M10.5 10.5L14 14' stroke-linecap='round'/></g></svg>");
    --input-pad-left: 1.9rem;
}

/* 分页条：左侧信息+翻页、右侧每页条数，全站同一布局（截图指定的标准） */
.devices-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-5);
    flex-wrap: wrap;
    margin-top: var(--space-3);
}
.devices-footer .page-total,
.devices-footer .pagination .page-total { order: -1; color: var(--text-muted); font-size: var(--fs-sm); }
.devices-footer .per-page { display: flex; align-items: center; gap: var(--space-2); font-size: var(--fs-sm); color: var(--text-muted); flex: 0 0 auto; }
.devices-footer .per-page select { min-width: 5rem; }

/* 下拉不参与拉伸，按内容走，避免筛选栏里下拉被拉得比搜索框还长 */
.filters-bar select,
.devices-toolbar select,
.rack-list-toolbar select,
.user-list-toolbar select,
.inv-toolbar select,
.ipam-toolbar select,
.resource-summary-toolbar select { flex: 0 0 auto; min-width: 8rem; }

/* 筛选栏里的按钮一律不拉伸、不换行，紧跟输入框——DCIM 的搜索按钮此前被
   父容器拉伸成与别处不同的尺寸，就是因为没有这条 */
.filters-bar .btn,
.devices-toolbar .btn,
.rack-list-toolbar .btn,
.user-list-toolbar .btn,
.inv-toolbar .btn,
.ipam-toolbar .btn,
.resource-summary-toolbar .btn,
.rpt-toolbar .btn,
.topology-toolbar .btn,
.traffic-graph-toolbar .btn {
    flex: 0 0 auto;
    min-height: var(--control-h);
    height: var(--control-h);
    white-space: nowrap;
}
.filters-bar select { /* 控件样式由全局 input/select 基础规则统一 */ }
.toolbar-sep { color: var(--text-muted); margin: 0 var(--space-1); }
.alert-filters-bar { flex-wrap: nowrap; }
.alert-filters-bar select { max-width: 180px; }
.alert-filters-bar .btn { white-space: nowrap; }

/* 仪表盘 - Apple 风格：大标题、留白、轻卡片 */
.dashboard-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-7);
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
    padding: var(--space-1) 0;
}
.dashboard-header-left { flex: 1; min-width: 0; }
.dashboard-title { margin: 0 0 var(--space-2); font-size: clamp(1.45rem, 1.7vw, 1.9rem); font-weight: 600; letter-spacing: -0.025em; }
.dashboard-desc { margin: 0; color: var(--text-muted); font-size: var(--fs-md); }
.dashboard-quick-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }
.dashboard-quick-actions .btn { flex-shrink: 0; }
.dashboard-footer { margin-top: 2rem; padding-top: 1.25rem; border-top: 1px solid var(--border); font-size: var(--fs-sm); color: var(--text-muted); }
.dashboard-current-time { margin-right: 0.5rem; }
.dashboard-footer-sep { margin: 0 var(--space-3); opacity: 0.7; }
.dashboard-visitor-ip { }
.stats-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
    gap: var(--space-4);
    margin-bottom: 1.25rem;
}
.stat-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-left-width: 4px;
    border-left-color: var(--border);
    border-radius: var(--radius);
    padding: var(--card-pad);
    box-shadow: var(--shadow);
    transition: transform .2s ease, box-shadow .2s ease;
    min-width: 0;
}
.stat-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-3); }
.stat-card.stat-success { border-left: 4px solid var(--success); }
.stat-card.stat-danger { border-left: 4px solid var(--error); }
.stat-card.stat-warn { border-left: 4px solid var(--warn); }
.stats-cards .stat-card:nth-child(1) { border-left-color: var(--act-primary); } /* 设备总数 - 蓝 */
.stats-cards .stat-card:nth-child(2) { border-left-color: var(--act-neutral); } /* 已启用 - 青 */
/* 第 3/4/5 个卡片使用 stat-success/stat-danger/stat-warn 自带色 */
.stats-cards .stat-card:nth-child(6) { border-left-color: #7c3aed; } /* 24h 达标率 - 紫 */
.stat-value { font-size: clamp(1.45rem, 1.7vw, 2rem); font-weight: 600; letter-spacing: -0.03em; min-width: 0; overflow-wrap: anywhere; }
/* SNMP 模块等较长的文本型卡片值：缩小字号并允许换行，避免溢出 */
#traffic-stat-module { font-size: var(--fs-lg); line-height: 1.25; word-break: break-all; }

/* 监控设置：卡片式分组布局 */
.settings-cards { display: flex; flex-direction: column; gap: var(--space-5); max-width: none; }
/* 堡垒概览：会话用户/资产排名双卡 + 时间分段切换 */
.bst-rank-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-5); margin: var(--space-5) 0; }
@media (max-width: 900px) { .bst-rank-grid { grid-template-columns: 1fr; } }
.bst-rank-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.5rem; gap: var(--space-3); flex-wrap: wrap; }
.bst-rank-head h4 { margin: 0; font-size: var(--fs-md); }
.bst-seg { display: inline-flex; border: 1px solid var(--border); border-radius: var(--control-radius); overflow: hidden; }
.bst-seg-btn { padding: var(--space-1) var(--space-3); font-size: var(--fs-xs); color: var(--text-muted); background: transparent; border: 0; border-left: 1px solid var(--border); cursor: pointer; }
.bst-seg-btn:first-child { border-left: 0; }
.bst-seg-btn:hover { color: var(--text); }
.bst-seg-btn.active { background: var(--primary); color: #fff; }
.bst-rank-no { width: 2.5rem; color: var(--text-muted); text-align: center; }
.bst-rank-cnt { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }

.settings-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: var(--space-5) var(--space-6);
    box-shadow: var(--shadow-1);
}
.settings-card-head {
    display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-5);
    padding-bottom: 14px; margin-bottom: 16px; border-bottom: 1px solid var(--border);
}
.settings-card-head-main { min-width: 0; }
.settings-card-head h4 {
    margin: 0; font-size: var(--fs-lg); font-weight: 600;
    display: flex; align-items: center; gap: var(--space-3);
}
.settings-card-desc { margin: var(--space-2) 0 0; font-size: var(--fs-sm); color: var(--text-muted); font-weight: 400; line-height: var(--lh-normal); }
.settings-card-icon {
    width: 30px; height: 30px; border-radius: var(--radius-md); flex: 0 0 auto;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: var(--fs-md); color: #fff; box-shadow: var(--shadow-2);
}
.settings-card-icon.ic-topo { background: linear-gradient(135deg, #3b82f6, var(--act-info)); }
.settings-card-icon.ic-neigh { background: linear-gradient(135deg, #06b6d4, #0ea5e9); }
.settings-card-icon.ic-lat { background: linear-gradient(135deg, #f59e0b, #f97316); }
.settings-card-icon.ic-traf { background: linear-gradient(135deg, #10b981, #22c55e); }
.settings-card-icon.ic-filter { background: linear-gradient(135deg, #8b5cf6, #a855f7); }
.settings-card .form-row { margin-bottom: 14px; }
.settings-card .form-row:last-child,
.settings-card .form-grid-compact:last-child,
.settings-card .settings-card-foot:last-child { margin-bottom: 0; }
.settings-card .form-grid-compact { margin-bottom: 14px; }
.settings-card-foot { margin-top: 14px; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.priority-order-list { list-style: none; margin: var(--space-2) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); max-width: 420px; }
.priority-order-item {
    display: flex; align-items: center; gap: var(--space-3);
    padding: var(--space-2) var(--space-3); border-radius: var(--radius-md);
    background: var(--bg-hover, rgba(255,255,255,.03)); border: 1px solid var(--border);
    font-size: var(--fs-sm);
    cursor: grab;
    user-select: none;
}
.priority-order-item.dragging { opacity: .55; cursor: grabbing; }
.priority-order-item.drag-over { border-color: var(--primary); background: rgba(0, 181, 255, .08); }
.priority-order-item .priority-order-drag { width: 16px; color: var(--text-muted); font-size: var(--fs-xs); line-height: var(--lh-single); }
.priority-order-item .priority-order-rank { width: 20px; text-align: center; color: var(--text-muted); font-weight: 600; }
.priority-order-item .priority-order-name { flex: 1; font-weight: 600; }
.priority-order-item .priority-order-btns { display: flex; gap: var(--space-1); }
.priority-order-item .priority-order-btns button {
    width: 22px; height: 22px; line-height: var(--lh-single); border-radius: var(--radius-sm); border: 1px solid var(--border);
    background: transparent; color: var(--text); cursor: pointer; font-size: var(--fs-xs);
}
.priority-order-item .priority-order-btns button:disabled { opacity: .3; cursor: not-allowed; }
.priority-order-item.disabled { opacity: .5; }
.priority-order-item.disabled .priority-order-name::after { content: " (规划中)"; font-weight: 400; color: var(--text-muted); }
.settings-card-head .switch-inline,
.switch-inline {
    display: inline-flex; align-items: center; gap: var(--space-2); flex: 0 0 auto;
    font-size: var(--fs-base); font-weight: 600; white-space: nowrap; cursor: pointer; color: var(--text-muted);
}

/* 接口流量图弹窗：链路信息面板 */
.neighbor-traffic-info {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: var(--space-3) var(--space-5);
    padding: var(--space-4) var(--space-5);
    margin-bottom: 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg-card);
}
@media (max-width: 820px) {
    .neighbor-traffic-info { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.neighbor-traffic-info .ntl-item { display: flex; align-items: baseline; gap: var(--space-3); min-width: 0; font-size: var(--fs-base); }
.neighbor-traffic-info .ntl-k { color: var(--text-muted); flex: 0 0 auto; min-width: 54px; }
.neighbor-traffic-info .ntl-v { color: var(--text); font-weight: 600; word-break: break-all; }
/* 弹窗内可点击接口：点击切换显示该接口流量图 */
.ntl-iface-btn {
    font: inherit; font-weight: 600; color: var(--primary);
    background: rgba(9, 105, 218, 0.1); border: 1px solid transparent;
    border-radius: var(--radius-sm); padding: 0.05rem 0.4rem; cursor: pointer; word-break: break-all;
}
.ntl-iface-btn:hover { background: rgba(9, 105, 218, 0.2); }
.ntl-iface-btn.active { background: var(--primary); color: #fff; border-color: var(--primary); }

/* 接口流量图弹窗：右上角时间周期选择 */
.neighbor-traffic-actions { display: flex; align-items: center; gap: var(--space-3); }
.neighbor-traffic-ranges { display: inline-flex; gap: var(--space-1); flex-wrap: wrap; }
.neighbor-traffic-ranges .btn.active {
    background: var(--accent, #2563eb);
    border-color: var(--accent, #2563eb);
    color: #fff;
}
.stat-label { font-size: var(--fs-sm); color: var(--text-muted); margin-top: 0.4rem; }
#panel-neighbors .stats-cards {
    grid-template-columns: repeat(6, minmax(150px, 1fr));
    gap: var(--space-4);
}
#panel-neighbors .stat-card {
    min-width: 0;
    min-height: 116px;
    padding: var(--space-6) var(--space-6);
}
#panel-neighbors .stat-value {
    font-size: clamp(1.45rem, 2.1vw, 1.95rem);
    line-height: 1.25;
    overflow-wrap: anywhere;
    word-break: normal;
}
.dashboard-meta { margin-bottom: 0.5rem; }
.dashboard-running { margin-bottom: 0.5rem; }
.dashboard-hint { font-size: var(--fs-base); color: var(--text-muted); margin-bottom: 1rem; }
.dashboard-hint a { color: var(--primary); }
.dashboard-settings {
    margin-bottom: 1.25rem;
    padding: var(--space-4) var(--space-5);
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    font-size: var(--fs-base);
    color: var(--text-muted);
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4) var(--space-7);
}
.dashboard-settings-item {
    display: flex;
    gap: var(--space-2);
    align-items: baseline;
}
.dashboard-settings-item .label {
    color: var(--text-muted);
}
.dashboard-settings-item .value {
    color: var(--text);
}

.traffic-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(320px, 0.9fr);
    gap: var(--space-5);
    margin: var(--space-5) 0;
}

/* 采集链路体检（取代旧的「采集架构」装饰图 + 「配置入口」复读卡） */
.traffic-health { margin-top: 0.75rem; border: 1px solid var(--border); border-radius: var(--radius-md);
    background: var(--bg-elevated); padding: var(--space-3) var(--space-4); }
.traffic-health.hidden { display: none; }
.traffic-health-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) 0;
    border-bottom: 1px solid var(--border); font-size: var(--fs-sm); flex-wrap: wrap; }
.traffic-health-dot { flex: 0 0 auto; width: 8px; height: 8px; border-radius: 50%; background: var(--text-muted); }
.traffic-health-row.ok .traffic-health-dot { background: var(--success, var(--act-success)); }
.traffic-health-row.bad .traffic-health-dot { background: var(--error, #ef4444); }
.traffic-health-name { flex: 0 0 8.5rem; font-weight: 600; }
.traffic-health-target { flex: 0 0 auto; color: var(--text-muted); }
.traffic-health-detail { flex: 1 1 auto; min-width: 0; }
.traffic-health-row.bad .traffic-health-detail { color: var(--error, #ef4444); }
.traffic-health-ms { flex: 0 0 auto; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.traffic-health-stats { display: flex; flex-wrap: wrap; gap: var(--space-5); padding-top: 0.55rem;
    font-size: var(--fs-sm); color: var(--text-muted); }
.traffic-health-stats b { color: var(--text); margin-left: 0.2rem; }
.traffic-health-stats code { color: var(--text); }

.traffic-link {
    color: var(--accent);
    font-weight: 600;
}

.traffic-metric-link {
    display: inline-flex;
    text-decoration: none;
    cursor: pointer;
}

.traffic-metric-link:hover .status-badge {
    box-shadow: 0 0 0 1px var(--accent);
}

.traffic-filters,
.traffic-graph-list-filters,
.traffic-graph-toolbar {
    display: grid;
    gap: var(--space-3);
    align-items: center;
    margin: var(--space-4) 0;
}
.traffic-filters {
    grid-template-columns: minmax(260px, 1fr) repeat(4, minmax(120px, 0.45fr)) auto;
}

.traffic-graph-list-filters {
    display: flex;
    /* 单行布局：下拉按内容自适应收缩、搜索框弹性填充，整行不换行 */
    flex-wrap: nowrap;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg-soft);
}

.traffic-graph-toolbar {
    grid-template-columns: minmax(220px, 1.2fr) minmax(170px, 0.9fr) minmax(130px, 0.35fr) 110px 130px auto;
    gap: var(--space-4);
    margin: var(--space-5) 0;
}

.traffic-filters input,
.traffic-filters select,
.traffic-graph-list-filters input,
.traffic-graph-list-filters select,
.traffic-graph-toolbar input,
.traffic-graph-toolbar select {
    min-width: 0;
    width: 100%;
}

.traffic-graph-list-filters input {
    flex: 1 1 200px;
    min-width: 140px;
}

.traffic-graph-list-filters select {
    flex: 0 1 auto;
    width: auto;
    min-width: 0;
}

.traffic-graph-list-filters .btn { flex: 0 0 auto; white-space: nowrap; }

/* 表格上方操作行：提示居左、按钮右对齐 */
.table-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-3);
    margin: var(--space-3) 0;
}
.table-actions .form-hint { margin-right: auto; }

.traffic-graph-list-filters #traffic-graph-filter-description,
.traffic-graph-list-filters #traffic-graph-filter-graph-status {
    flex-basis: 150px;
}

.traffic-graph-list-filters #traffic-graph-filter-ip {
    flex-basis: 120px;
}

.traffic-graph-list-filters .btn {
    flex: 0 0 auto;
    min-width: 76px;
}

.traffic-view-tabs {
    display: inline-flex;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.traffic-view-tabs .btn.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

.device-performance-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-5);
}

@media (max-width: 980px) {
    .device-performance-grid {
        grid-template-columns: 1fr;
    }
}

.traffic-graph-list-table {
    min-width: max-content;
}

.traffic-graph-list-table th,
.traffic-graph-list-table td {
    white-space: nowrap;
    font-size: var(--fs-sm);
}

/* 接口描述列（第10列）超长省略 */
.traffic-graph-list-table td:nth-child(10) {
    max-width: 360px;
    overflow: hidden;
    text-overflow: ellipsis;
}

.native-traffic-chart-wrap {
    padding: var(--space-4);
    background: var(--bg-card);
    position: relative;
}

.native-traffic-chart {
    display: block;
    width: 100%;
    height: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-card);
    cursor: crosshair;
}

.traffic-chart-zoom-reset {
    position: absolute; top: 1.1rem; right: 1.1rem; z-index: 3;
    padding: var(--space-1) var(--space-3); font-size: var(--fs-xs); cursor: pointer;
    color: var(--primary); background: var(--bg-card);
    border: 1px solid var(--primary); border-radius: var(--control-radius);
}

.traffic-live-button.active {
    color: #05202c;
    background: #38bdf8;
    border-color: #38bdf8;
}

/* Rack Management / DCIM */
.rack-workspace {
    display: grid;
    grid-template-columns: 150px minmax(0, 1fr);
    gap: var(--space-5);
    align-items: start;
}
/* 备份管理组：共享固定左侧导航，子页显示在右侧 */
#backup-side-nav { display: none; }
.main.backup-mode { display: flex; gap: var(--space-5); align-items: flex-start; }
.main.backup-mode > #backup-side-nav {
    display: flex;
    flex: 0 0 150px;
    position: sticky;
    top: 74px;
    align-self: flex-start;
}
.main.backup-mode > .panel.active { flex: 1 1 auto; min-width: 0; }
/* 监控组：图形/拓扑/邻居 共享固定左侧导航 */
#monitor-side-nav { display: none; }
.main.monitor-mode { display: flex; gap: var(--space-5); align-items: flex-start; }
.main.monitor-mode > #monitor-side-nav {
    display: flex;
    flex: 0 0 150px;
    position: sticky;
    top: 74px;
    align-self: flex-start;
}
.main.monitor-mode > .panel.active { flex: 1 1 auto; min-width: 0; }
#ipam-side-nav { display: none; }
.main.ipam-mode { display: flex; gap: var(--space-5); align-items: flex-start; }
.main.ipam-mode > #ipam-side-nav {
    display: flex;
    flex: 0 0 150px;
    position: sticky;
    top: 74px;
    align-self: flex-start;
}
.main.ipam-mode > .panel.active { flex: 1 1 auto; min-width: 0; }
/* IPAM 概览统计卡片 */
.ipam-stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--space-4); margin: var(--space-4) 0 var(--space-6); }
.ipam-stat-card { border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-4) var(--space-5); background: var(--bg-elevated); }
.ipam-stat-card .num { font-size: var(--fs-2xl); font-weight: 600; line-height: var(--lh-display); font-variant-numeric: tabular-nums; }
.ipam-stat-card .lbl { font-size: var(--fs-sm); color: var(--text-muted); margin-top: 0.15rem; }
.ipam-stat-card.clickable { cursor: pointer; transition: border-color .15s ease, transform .1s ease; }
.ipam-stat-card.clickable:hover { border-color: var(--primary); transform: translateY(-1px); }
/* 对账差异种类色标 */
.ipam-kind { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--fs-sm); font-weight: 600; }
.ipam-kind::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: currentColor; }
.ipam-kind.conflict, .ipam-kind.duplicate { color: var(--danger, #c23a22); }
.ipam-kind.orphaned { color: #6d3ff0; }
.ipam-kind.missing { color: var(--warning, #a86610); }
.ipam-kind.insync { color: var(--success, #157f4b); }
/* 利用率条 */
.ipam-util { display: inline-flex; align-items: center; gap: var(--space-2); min-width: 90px; }
.ipam-util-bar { flex: 1 1 auto; height: 6px; border-radius: var(--radius-xs); background: var(--border); overflow: hidden; min-width: 48px; }
.ipam-util-bar > i { display: block; height: 100%; background: var(--primary); }
.ipam-util-bar.hot > i { background: var(--danger, #c23a22); }
.ipam-util-bar.warm > i { background: var(--warning, #a86610); }
.ipam-util-txt { font-size: var(--fs-sm); color: var(--text-muted); font-variant-numeric: tabular-nums; min-width: 34px; text-align: right; }
/* nowrap 必须有：CJK 允许字符间断行，表格一挤「发现」就被掰成两行竖排 */
.ipam-prov { display: inline-block; white-space: nowrap; font-size: var(--fs-2xs); padding: 1px 6px; border-radius: var(--radius-pill); border: 1px solid var(--border); color: var(--text-muted); }
.ipam-prov.observed { color: #6d3ff0; border-color: #6d3ff0; }
.ipam-prov.both { color: var(--success, #157f4b); border-color: var(--success, #157f4b); }
.ipam-toolbar { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; margin-bottom: 0.75rem; }
.ipam-toolbar .spacer { flex: 1 1 auto; }
/* IPAM 轻量弹窗 */
.ipam-modal-mask { position: fixed; inset: 0; background: rgba(0,0,0,.45); display: flex; align-items: center; justify-content: center; z-index: 2000; }
.ipam-modal { background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius); width: min(460px, 92vw); max-height: 88vh; overflow: auto; padding: var(--space-6) var(--space-7); }
.ipam-modal h3 { margin: 0 0 var(--space-4); font-size: var(--fs-lg); }
.ipam-modal .fld { margin-bottom: 0.7rem; }
.ipam-modal .fld label { display: block; font-size: var(--fs-sm); color: var(--text-muted); margin-bottom: 0.2rem; }
.ipam-modal .fld input, .ipam-modal .fld select, .ipam-modal .fld textarea { width: 100%; }
.ipam-modal-actions { display: flex; justify-content: flex-end; gap: var(--space-3); margin-top: 1rem; }
/* 只读信息弹窗（操作日志）：比表单弹窗宽，内容区自己滚动 */
.ipam-modal.ipam-modal-wide { width: min(1000px, 94vw); }
.ipam-modal-body { max-height: 66vh; overflow: auto; }
/* 变更日志：动作徽标 + 字段级 旧值→新值 */
.ipam-chg-act { display: inline-block; padding: 1px 7px; border-radius: var(--radius-pill); font-size: var(--fs-2xs);
    border: 1px solid var(--border); color: var(--text-muted); white-space: nowrap; }
.ipam-chg-act.create { color: var(--success, #157f4b); border-color: var(--success, #157f4b); }
.ipam-chg-act.update { color: var(--primary); border-color: var(--primary); }
.ipam-chg-act.delete { color: var(--error, #ef4444); border-color: var(--error, #ef4444); }
.ipam-chg-f { display: flex; align-items: baseline; gap: var(--space-2); padding: 1px 0; font-size: var(--fs-2xs); }
.ipam-chg-k { flex: 0 0 auto; color: var(--text-muted); min-width: 5.5em; }
.ipam-chg-o { color: var(--text-muted); text-decoration: line-through; overflow-wrap: anywhere; }
.ipam-chg-ar { color: var(--text-muted); flex: 0 0 auto; }
.ipam-chg-n { color: var(--text); overflow-wrap: anywhere; }
/* 网段树布局：左目录树 + 右网段树 */
.ipam-tree-layout { display: flex; gap: var(--space-5); align-items: flex-start; }
.ipam-folder-tree { flex: 0 0 250px; max-height: calc(100vh - 220px); overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-3); background: var(--bg-elevated); }
.ipam-prefix-pane { flex: 1 1 auto; min-width: 0; }
.ipam-fnode { display: flex; align-items: center; gap: var(--space-1); padding: var(--space-1) var(--space-2); border-radius: var(--control-radius); cursor: pointer; font-size: var(--fs-sm); white-space: nowrap; }
.ipam-fnode:hover { background: var(--border); }
.ipam-fnode.active { background: var(--primary); color: #fff; }
.ipam-fnode.active .ipam-fcount { color: #fff; }
.ipam-ftoggle { width: 14px; display: inline-flex; justify-content: center; color: var(--text-muted); flex: 0 0 14px; }
.ipam-fname { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; }
.ipam-fcount { color: var(--text-muted); font-size: var(--fs-2xs); font-variant-numeric: tabular-nums; }
.ipam-fadd, .ipam-fedit, .ipam-fdel { opacity: 0; color: var(--text-muted); padding: 0 var(--space-1); flex: 0 0 auto; }
.ipam-fnode:hover .ipam-fadd, .ipam-fnode:hover .ipam-fedit, .ipam-fnode:hover .ipam-fdel { opacity: 0.85; }
.ipam-fadd:hover, .ipam-fedit:hover { color: var(--primary); opacity: 1; }
.ipam-fdel:hover { color: var(--danger, #e5484d); opacity: 1; }
.ipam-fnode.active .ipam-fadd, .ipam-fnode.active .ipam-fedit, .ipam-fnode.active .ipam-fdel { color: #fff; }
/* 网段树行 */
.ipam-ptree { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.ipam-prow { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--border); font-size: var(--fs-sm); }
.ipam-prow:last-child { border-bottom: 0; }
.ipam-prow:hover { background: var(--bg-elevated); }
.ipam-prow .cidr { font-family: var(--font-mono); font-weight: 600; }
.ipam-prow .cidr.pool { color: var(--primary); }
.ipam-prow .meta { color: var(--text-muted); font-size: var(--fs-xs); }
.ipam-prow .grow { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ipam-prow .acts { display: flex; gap: var(--space-1); flex: 0 0 auto; }
.ipam-ptoggle { width: 14px; flex: 0 0 14px; color: var(--text-muted); cursor: pointer; text-align: center; }
.ipam-thead { display: flex; gap: var(--space-3); padding: var(--space-2) var(--space-3); background: var(--bg-elevated); border: 1px solid var(--border); border-bottom: 0; border-radius: var(--radius) var(--radius) 0 0; font-size: var(--fs-sm); font-weight: 600; }
.ipam-sorth { cursor: pointer; user-select: none; }
.ipam-sorth:hover { color: var(--primary); }
/* IPAM 区块标题：走全局字号阶梯（h2 由 .panel-header h2 统一，此处只管小节标题） */
#ipam-content h3 { font-size: var(--fs-md); }
#ipam-content h4 { font-size: var(--fs-base); }
.ipam-sec-title { margin: var(--space-5) 0 var(--space-2); }
.ipam-sec-title:first-child { margin-top: 0; }
.ipam-sec-block { margin-top: 0.5rem; }
.panel-header .form-hint { margin-top: 0.25rem; }
/* 详情属性卡（子网详情 / IP 计算器结果）：统一的 key-value 行 */
.ipam-kv-card { border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-3) var(--space-5);
    margin-bottom: 0.8rem; background: var(--bg-elevated); max-width: 640px; }
.ipam-kv { display: flex; gap: var(--space-3); padding: var(--space-1) 0; font-size: var(--fs-sm); }
.ipam-kv.wide { padding: var(--space-2) var(--space-1); border-bottom: 1px solid var(--border); }
.ipam-kv-k { flex: 0 0 110px; color: var(--text-muted); }
.ipam-kv.wide .ipam-kv-k { flex: 0 0 200px; }
.ipam-kv-v { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.ipam-detail-head { display: flex; align-items: center; gap: var(--space-3); margin-bottom: 0.6rem; flex-wrap: wrap; }
.ipam-detail-head h3 { margin: 0; }
.ipam-detail-head .spacer { flex: 1 1 auto; }
.ipam-avail-row { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3);
    padding: var(--space-1) 0; border-bottom: 1px solid var(--border); font-size: var(--fs-sm); }
/* 表单卡（迁移页）：复用系统设置的 .settings-card */
.ipam-form-card { max-width: 560px; margin-bottom: 1rem; }
.ipam-form-card .fld { margin-bottom: 0.7rem; }
.ipam-form-card .fld label { display: block; font-size: var(--fs-sm); color: var(--text-muted); margin-bottom: 0.2rem; }
.ipam-form-card .fld input, .ipam-form-card .fld select { width: 100%; }
.ipam-check { display: flex; gap: var(--space-2); align-items: center; }
.ipam-check input { width: auto !important; }
.ipam-form-actions { display: flex; gap: var(--space-3); margin-top: 0.75rem; flex-wrap: wrap; }
/* ===== IPAM 工具页（IP 计算器）：phpIPAM 式，每个工具一张独立卡片 =====
   宽屏并排、窄屏堆叠；卡片自身限宽，不做「一根柱子顶到底 + 右半屏全空」。 */
/* align-items: stretch（默认）→ 同一行的卡片自动等高 */
.ipam-tools { display: grid; gap: var(--space-5); grid-template-columns: minmax(0, 1fr); }
/* 宽屏并排：速查表卡按表格内容取宽（auto，不拉伸），计算卡吃掉剩余宽度 */
@media (min-width: 1180px) {
    .ipam-tools { grid-template-columns: minmax(21rem, 1fr) auto; }
}
.ipam-tool { background: var(--bg-card); border: 1px solid var(--border);
    border-radius: var(--radius); overflow: hidden; min-width: 0;
    display: flex; flex-direction: column; }
.ipam-tool-head { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
    padding: var(--space-3) var(--space-5); background: var(--bg-elevated); border-bottom: 1px solid var(--border); }
.ipam-tool-head h3 { margin: 0; margin-right: auto; font-size: var(--fs-md); }
.ipam-tool-ctl { display: flex; align-items: center; gap: var(--space-2); }
.ipam-tool-ctl .form-hint { margin: 0; white-space: nowrap; }
.ipam-tool-body { padding: var(--space-4) var(--space-5); flex: 1 1 auto; min-height: 0; }
.ipam-tool-body-flush { padding: 0; display: flex; }
/* 计算输入 */
.ipam-calc-form { display: flex; gap: var(--space-3); margin-bottom: 0.6rem; }
.ipam-calc-form input { flex: 1 1 auto; min-width: 0; }
.ipam-calc-form .btn { flex: 0 0 auto; }
/* 结果标注：卡片内的一条小标题，不再是浮着的带框条 */
.ipam-calc-cap { display: flex; align-items: baseline; gap: var(--space-2); margin-bottom: 0.2rem;
    font-size: var(--fs-xs); font-weight: 600; color: var(--text-muted); }
.ipam-calc-cap .mono { color: var(--primary); font-size: var(--fs-sm); }
.ipam-kv:last-child { border-bottom: 0; }
.table td.ipam-bin { font-size: var(--fs-2xs); }  /* 特异性需压过 .table td 的 --fs-sm */
.ipam-num-input { width: 4.5rem; }
/* 掩码速查表：33 行很长，卡片内自己滚（撑满等高后的可用高度），表头吸顶 */
#ipam-mask-table { flex: 1 1 auto; min-height: 0; max-height: 28rem; overflow: auto; }
/* 表按内容取宽，不被 .table{width:100%} 拉伸得七零八落 */
#ipam-mask-table .table { width: auto; min-width: 100%; }
#ipam-mask-table .table th, #ipam-mask-table .table td { padding: var(--space-1) var(--space-2); font-size: var(--fs-2xs); white-space: nowrap; }
#ipam-mask-table .table td.ipam-bin { letter-spacing: -0.02em; }
#ipam-mask-table .table th { white-space: nowrap; position: sticky; top: 0; }
/* 子网/VRF/ASN 目录：并入左侧导航的手风琴（Zabbix 式），列表上方只留面包屑 */
.ipam-folder-bar { margin: var(--space-1) 0 var(--space-3); }
.ipam-nav-folders { max-height: 42vh; overflow-y: auto; overflow-x: hidden; }
.ipam-navf-item {
    display: flex; align-items: center; gap: var(--space-1); padding: var(--space-1) var(--space-3) var(--space-1) 0;
    font-size: var(--fs-sm); color: var(--text-muted); cursor: pointer; border-radius: var(--radius-xs); white-space: nowrap;
}
.ipam-navf-item:hover { background: var(--bg-elevated); color: var(--text); }
.ipam-navf-item.active { background: var(--primary); color: #fff; }
.ipam-navf-caret { flex: 0 0 0.8rem; text-align: center; font-size: var(--fs-2xs); }
.ipam-navf-name { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; }
/* 目录行内操作（＋新建子目录 / ✎重命名 / ✕删除）：常态隐藏，悬停/选中该目录时才出现 */
.ipam-navf-act { flex: 0 0 auto; padding: 0 var(--space-1); opacity: 0; font-size: var(--fs-2xs); }
.ipam-navf-item:hover .ipam-navf-act,
.ipam-navf-item.active .ipam-navf-act { opacity: 0.75; }
.ipam-navf-act:hover { opacity: 1; }
.ipam-navf-item:hover .ipam-navf-del:hover { color: var(--error); }
/* 一级菜单（子网/VRF/ASN）右侧三角形：▸ 有下级目录，▾ 已展开 */
.rack-nav-btn.has-folders { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.ipam-nav-caret { flex: 0 0 auto; font-size: var(--fs-2xs); opacity: 0.65; }
.ipam-fcrumbs { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2); font-size: var(--fs-sm);
    padding: var(--space-2) var(--space-3); background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius-sm); }
.ipam-crumb { cursor: pointer; color: var(--primary); }
.ipam-crumb:hover { text-decoration: underline; }
.ipam-crumb.active { color: var(--text); font-weight: 600; cursor: default; }
.ipam-crumb-sep { color: var(--text-muted); }
.ipam-fbar-acts { margin-left: auto; display: inline-flex; gap: var(--space-1); }
.ipam-fbar-acts span { cursor: pointer; color: var(--text-muted); padding: 0 var(--space-1); }
.ipam-fbar-acts .ipam-fadd:hover, .ipam-fbar-acts .ipam-fedit:hover { color: var(--primary); }
.ipam-fbar-acts .ipam-fdel:hover { color: var(--danger, #e5484d); }
td.mono, .mono { font-family: var(--font-mono); }
.ipam-batchbar { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); margin-bottom: 0.45rem; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius-sm); font-size: var(--fs-sm); }
.ipam-batchbar #ipam-pf-batch-n { font-weight: 600; margin-right: auto; }
.ipam-selc { width: 36px; text-align: center; }
.ipam-selc input { cursor: pointer; }
.ipam-pf-table tbody tr.sel { background: var(--bg-elevated); }

/* 关键字高亮表：排序按钮、色块、状态、选中行 —— 统一走全站 token */
.ipam-batchbar #bst-hl-seln { font-weight: 600; margin-right: auto; }
.hl-table tbody tr.row-selected { background: var(--bg-elevated); }
.hl-table .hl-ordc { width: 3.2rem; white-space: nowrap; text-align: center; }
/* 排序上下箭头：轻量图标按钮，不用大号描边按钮（原来那样又粗又挤） */
.hl-ord {
    width: 1.35rem; height: 1.35rem; padding: 0; margin: 0 1px;
    display: inline-flex; align-items: center; justify-content: center;
    background: transparent; border: 1px solid transparent; border-radius: var(--radius-xs);
    color: var(--text-muted); font-size: var(--fs-2xs); line-height: var(--lh-single); cursor: pointer;
    transition: color .15s, border-color .15s, background .15s;
}
.hl-ord:hover:not(:disabled) { color: var(--primary); border-color: var(--border); background: var(--bg-card); }
.hl-ord:disabled { opacity: .3; cursor: default; }
.hl-swatch { display: inline-block; width: 1.4rem; height: 0.9rem; border-radius: var(--radius-xs); vertical-align: middle; margin-right: 0.4rem; border: 1px solid var(--border); }
.hl-pat { max-width: 26rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hl-state { font-size: var(--fs-2xs); padding: 0.05rem 0.4rem; border-radius: var(--radius-pill); }
.hl-state.on { color: var(--success); background: color-mix(in srgb, var(--success) 15%, transparent); }
.hl-state.off { color: var(--text-muted); background: var(--bg-elevated); }
.ipam-pf-table .ipam-ptoggle { cursor: pointer; display: inline-block; min-width: 1em; color: var(--text-muted); }
/* 可视化子网：地址方块网格 */
.ipam-ipgrid { display: flex; flex-wrap: wrap; gap: var(--space-1); margin: var(--space-1) 0 var(--space-5); }
.ipam-ipbox { display: inline-flex; align-items: center; justify-content: center; min-width: 42px; height: 22px; padding: 0 var(--space-1); border-radius: var(--radius-xs); font-size: var(--fs-xs); font-variant-numeric: tabular-nums; cursor: pointer; border: 1px solid transparent; transition: transform .08s ease; }
.ipam-ipbox:hover { transform: scale(1.12); z-index: 1; }
.ipam-ipbox.free { background: var(--border); color: var(--text-muted); }
.ipam-ipbox.used { background: var(--success, #157f4b); color: #fff; }
.ipam-ipbox.gw { background: var(--primary); color: #fff; font-weight: 600; }
.ipam-ipbox.reserved { background: var(--warning, #a86610); color: #fff; }
.ipam-ipbox.offline { background: var(--danger, #c23a22); color: #fff; }
.ipam-ipbox.sel { outline: 2px solid var(--primary); outline-offset: -1px; box-shadow: 0 0 0 2px var(--primary); }
.ipam-ipgrid { user-select: none; }
/* 与系统设置左侧栏保持一致 */
.rack-side-nav {
    position: sticky;
    top: 74px;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-3) var(--space-3);
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--bg-elevated);
}
/* 左侧边栏统一铺满整个左侧高度（系统设置/机柜管理/备份管理一致） */
.settings-sidebar,
.rack-side-nav,
#backup-side-nav,
#monitor-side-nav {
    min-height: calc(100vh - 120px);
}
.rack-nav-btn {
    display: block;
    width: 100%;
    text-align: left;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--control-radius);
    border: none;
    background: transparent;
    color: var(--text);
    font-size: var(--fs-base);
    cursor: pointer;
    transition: background .15s ease, color .15s ease;
}
.rack-nav-btn:hover {
    background: var(--border);
    color: var(--text);
}
.rack-nav-btn.active {
    background: var(--primary);
    color: #fff;
}
.rack-nav-note {
    border-top: 1px solid var(--border);
    color: var(--text-muted);
    font-size: var(--fs-xs);
    line-height: var(--lh-normal);
    padding-top: 0.65rem;
    margin-top: 0.2rem;
}
.rack-main-area { min-width: 0; }
.rack-section-page { display: none; }
.rack-section-page.active { display: block; }
.rack-page-head {
    display: flex;
    justify-content: space-between;
    gap: var(--space-5);
    align-items: flex-start;
    margin-bottom: 1rem;
}
.rack-page-head h3 { margin: 0 0 var(--space-1); font-size: var(--fs-xl); }
.rack-page-actions { display: flex; gap: var(--space-3); flex-wrap: wrap; justify-content: flex-end; }
.rack-view-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-card);
}
.rack-view-toggle button {
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--text-muted);
    font-weight: 600;
    padding: var(--space-2) var(--space-4);
    cursor: pointer;
}
.rack-view-toggle button.active {
    background: var(--primary);
    color: #fff;
}
.rack-modal-content {
    width: min(860px, 92vw);
    max-height: 88vh;
    overflow: auto;
}
.rack-modal-head {
    display: flex;
    justify-content: space-between;
    gap: var(--space-5);
    align-items: center;
    margin-bottom: 0.9rem;
}
.rack-modal-head h3 { margin: 0; }
.rack-modal-form { box-shadow: none; }
.rack-crud-layout {
    display: grid;
    grid-template-columns: minmax(280px, 0.45fr) minmax(0, 1fr);
    gap: var(--space-5);
    align-items: start;
}
.rack-edit-card,
.rack-table-card,
.rack-rack-table-wrap {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-card);
    box-shadow: var(--shadow);
}
.rack-edit-card {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4);
    padding: var(--space-4);
}
.rack-edit-card label {
    display: grid;
    gap: var(--space-1);
    color: var(--text-muted);
    font-size: var(--fs-sm);
}
.rack-edit-card .span-2,
.rack-edit-card button { grid-column: 1 / -1; }
.rack-rack-edit {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    margin-bottom: 1rem;
}
/* 【不能用 overflow:hidden】它只是为了让圆角裁掉表格直角，但 overflow 非 visible
   的祖先会切断 position:sticky 对页面滚动的响应，DCIM 的表头因此吸不住。
   改用 clip-path 之外最简单的办法：给内部表格自己加圆角，容器保持 visible。 */
.rack-table-card { overflow: visible; }
.rack-table-card > .table-wrap:last-child { border-bottom-left-radius: var(--radius); border-bottom-right-radius: var(--radius); overflow: clip visible; }
/* 【DCIM 搜索按钮宽 813px 的真凶】此前这里是
       display:grid; grid-template-columns: repeat(auto-fit, minmax(180px,1fr));
   等分栅格会把每个子元素都拉到同一宽度——两个子元素在 1658px 容器里各分 829px，
   于是一个"搜索"两字的按钮被撑成 813px，和搜索框一样长。
   （配置变动页早就单独打过 flex 补丁绕开它，但没人回来修全局，
     所以只有那一个页面是正常的。）
   改为与其它所有工具栏一致的 flex：按内容排布，按钮不再被拉伸。 */
.rack-list-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: center;
    margin-bottom: 0.75rem;
}
.rack-table-card .rack-list-toolbar { padding: var(--space-4); margin-bottom: 0; border-bottom: 1px solid var(--border); }
.rack-crud-table th,
.rack-crud-table td { white-space: nowrap; }
.rack-grid-view {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: var(--space-6);
    align-items: start;
}
.rack-grid-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg-card);
    box-shadow: var(--shadow);
    padding: var(--space-4);
    cursor: pointer;
}
.rack-grid-card:hover { border-color: var(--primary); }
.rack-grid-title { text-align: center; font-weight: 600; color: var(--text); font-size: var(--fs-md, 1rem); }
.rack-grid-cab { max-width: 300px; width: 100%; margin: 0 auto; }
/* 概览机柜底部脚轮（与详情 3D 脚轮同款造型的 2D 版） */
.rack-grid-wheels {
    max-width: 300px;
    width: 100%;
    margin: -16px auto 0;   /* 抵消卡片间距并让支架嵌入机柜底部，无间隙 */
    position: relative;
    z-index: 1;
    display: flex;
    justify-content: space-between;
    padding: 0 var(--space-8);       /* 两个脚轮靠近机柜左右底角 */
}
.rack-grid-wheels i {
    position: relative;
    width: 14px;
    height: 18px;
    flex: 0 0 auto;
}
.rack-grid-wheels i::before {
    content: '';
    position: absolute;
    top: 0; left: 50%;
    transform: translateX(-50%);
    width: 9px; height: 8px;
    border-radius: var(--radius-xs) var(--radius-xs) 0 0;
    background: linear-gradient(180deg, #7b8390 0%, #4a515b 60%, #333941 100%);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.3);
}
.rack-grid-wheels i::after {
    content: '';
    position: absolute;
    bottom: 0; left: 50%;
    transform: translateX(-50%);
    width: 14px; height: 14px;
    border-radius: 50%;
    background: radial-gradient(circle at 50% 50%,
        #aeb6c2 0 9%, #444b55 9% 17%, #6b7280 17% 26%,
        #2b3038 26% 60%, #0c0e12 60% 80%, #040507 80% 100%);
    box-shadow: 0 2px 4px rgba(0,0,0,0.6), inset -1px -1px 3px rgba(0,0,0,0.6), inset 1px 1px 2px rgba(255,255,255,0.12);
}
.rack-grid-loading { text-align: center; color: var(--text-muted); padding: var(--space-8) 0; font-size: var(--fs-sm); }
/* 机柜顶部横梁：整条与两侧导轨同色的金属条，机柜号刻在中间 */
.rack-nameplate {
    display: flex;
    align-items: center;
    justify-content: center;
    margin: -6px -4px 0;
    height: 22px;
    /* 哑光金属，与机柜同色系（低对比、无强反光） */
    background: linear-gradient(180deg, #333d4c 0%, #2a3340 50%, #262e3a 100%);
    border-bottom: 1px solid rgba(0,0,0,0.35);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
}
.rack-nameplate-center {
    display: flex;
    align-items: center;
    justify-content: center;
}
.rack-nameplate span {
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: #ffffff;
    text-shadow: 0 1px 1px rgba(0,0,0,0.55);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.rack-grid-cabinet {
    display: flex;
    flex-direction: column;
    width: 100%;
    height: 100%;
    border: 6px solid #1f2937;
    border-radius: var(--radius-md);
    background: #0b1220;
    padding: var(--space-1);
    gap: 1px;
    box-shadow: inset 0 0 0 1px rgba(148, 163, 184, 0.35);
}
[data-theme="light"] .rack-grid-cabinet { border-color: #475569; background: #cbd5e1; }
/* 空 U 位：细槽线 */
.rack-grid-cabinet .rack-grid-u {
    flex-grow: 1;
    min-height: 2px;
    border-radius: var(--radius-xs);
    background: rgba(148, 163, 184, 0.14);
    box-shadow: inset 0 0 0 0.5px rgba(148, 163, 184, 0.28);
}
/* 已上架设备块：按类型着色，纵向居中显示设备名 */
.rack-grid-cabinet .rack-grid-dev {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 8px;
    border-radius: var(--radius-xs);
    color: #e8edf5;
    font-size: 10px;
    line-height: var(--lh-single);
    font-weight: 600;
    padding: 0 var(--space-1);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /* 与详情机柜一致的拟物化金属面板 */
    background: linear-gradient(180deg, #4a5568 0%, #333d4e 46%, #232b38 54%, #2c3543 100%);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.22), inset 0 -1px 0 rgba(0,0,0,0.4), 0 1px 2px rgba(0,0,0,0.4);
}
.rack-grid-meta {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    text-align: center;
    color: var(--text-muted);
    font-size: var(--fs-xs);
}
.rack-grid-meta span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.rack-toolbar {
    display: grid;
    grid-template-columns: minmax(180px, 1fr) 120px minmax(220px, 1.4fr) repeat(4, auto) minmax(140px, 0.6fr);
    gap: var(--space-3);
    align-items: center;
    margin: var(--space-5) 0;
}
.rack-toolbar select,
.rack-toolbar input,
.rack-mini-form input,
.rack-mini-form select {
    width: 100%;
    min-height: var(--control-h);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg);
    color: var(--text);
    padding: var(--space-2) var(--space-3);
}
.rack-zoom-label { display: flex; gap: var(--space-3); align-items: center; color: var(--text-muted); white-space: nowrap; }
.rack-name-extras { display: inline-flex; gap: var(--space-3); align-items: center; color: var(--text-muted); font-size: var(--fs-sm); white-space: nowrap; }
.rack-name-extras label { display: inline-flex; gap: var(--space-1); align-items: center; cursor: pointer; }
/* 紧凑指标：置于右侧详情栏顶部（原顶部大卡片已移除，腾出高度给机柜图） */
.rack-stats {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin-bottom: 0.8rem;
    padding-bottom: 0.7rem;
    border-bottom: 1px solid var(--border);
}
.rack-stat-item { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); font-size: var(--fs-sm); }
.rack-stat-lbl { color: var(--text-muted); }
.rack-stat-val { font-weight: 600; color: var(--text); }
.rack-stat-val small { color: var(--text-muted); font-weight: 400; }
.rack-layout {
    display: grid;
    /* 待上架列比原来加宽约 10%（min 200→220，占比 0.55→0.61fr） */
    grid-template-columns: minmax(220px, 0.61fr) minmax(520px, 2fr) minmax(240px, 0.75fr);
    gap: var(--space-5);
    align-items: start;
}
.rack-device-palette,
.rack-view-shell,
.rack-detail-panel {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-card);
    box-shadow: var(--shadow);
}
/* 详情栏内部滚动；机柜图区按正常高度完整绘制、不裁剪，超屏由页面滚动查看 */
.rack-detail-panel { padding: var(--space-4); max-height: calc(100vh - 200px); overflow: auto; }
.rack-view-shell { padding: var(--space-4); overflow: visible; }
/* 待上架栏高度由 JS 同步为机柜图区高度，内部列表自身滚动 */
.rack-device-palette { padding: var(--space-4); display: flex; flex-direction: column; overflow: hidden; }
.rack-pane-title { font-weight: 600; color: var(--text); margin-bottom: 0.7rem; }
.rack-device-actions { margin-bottom: 0.7rem; }
.rack-device-list { display: grid; gap: var(--space-3); flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.rack-palette-device {
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg);
    padding: var(--space-3) var(--space-4);
    cursor: grab;
}
.rack-palette-device:active { cursor: grabbing; }
.rack-palette-device strong { display: block; color: var(--text); }
.rack-palette-device small { display: block; color: var(--text-muted); margin-top: 0.16rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rack-view-head {
    display: flex;
    justify-content: space-between;
    gap: var(--space-5);
    margin-bottom: 0.75rem;
}
.rack-view {
    --rack-unit-h: 14px;
    position: relative;
    width: 100%;
    max-width: 240px;
    min-width: 0;
    margin: 0 auto;
    border: 8px solid #111827;
    border-radius: var(--radius-lg);
    background: linear-gradient(90deg, #1f2937 0 12px, transparent 12px calc(100% - 12px), #1f2937 calc(100% - 12px)), var(--bg);
    box-shadow: inset 0 0 0 2px rgba(148, 163, 184, 0.32), 0 18px 45px rgba(0,0,0,0.22);
    padding: var(--space-3) var(--space-5);
}
/* ===== 立体 3D 机柜 ===== */
.rack-view.rack-view-3d {
    border: 0; background: transparent; box-shadow: none; padding: 0;
    max-width: none; overflow: visible;
}
.rack3d-scene {
    perspective: 1500px;
    /* 机柜在场景内垂直居中：场景高度=机柜高度+约80px，上下各留约 40px 空白 */
    display: flex; align-items: center; justify-content: center;
    width: 100%;
    cursor: grab;
    touch-action: none;
    user-select: none;
}
.rack3d-scene.rack-rotating { cursor: grabbing; }
.rack3d {
    position: relative;
    transform-style: preserve-3d;
    transition: transform 0.06s linear;
    will-change: transform;
}
.rack3d-scene.rack-rotating .rack3d { transition: none; }
.rack3d-face {
    position: absolute;
    left: 50%; top: 50%;
    backface-visibility: hidden;
    box-sizing: border-box;
}
/* 前面板：承载 U 位与设备，深色磨砂金属边框 + 内发光 */
.rack3d-face.r3d-front {
    border: 6px solid #0f172a;
    border-radius: var(--radius-md);
    background:
        linear-gradient(90deg, #1e293b 0 10px, transparent 10px calc(100% - 10px), #1e293b calc(100% - 10px)),
        #0a1120;
    box-shadow: inset 0 0 0 1px rgba(148,163,184,0.25), inset 0 0 40px rgba(56,189,248,0.08);
    padding: var(--space-2) var(--space-1);
    overflow: hidden;
}
[data-theme="light"] .rack3d-face.r3d-front {
    border-color: #475569;
    background: linear-gradient(90deg, #64748b 0 10px, transparent 10px calc(100% - 10px), #64748b calc(100% - 10px)), #e2e8f0;
}
/* 背板：与正面一样显示 U 位（后侧机架导轨） */
.rack3d-face.r3d-back {
    border: 6px solid #0f172a;
    border-radius: var(--radius-md);
    background:
        linear-gradient(90deg, #1e293b 0 10px, transparent 10px calc(100% - 10px), #1e293b calc(100% - 10px)),
        #0a1120;
    box-shadow: inset 0 0 0 1px rgba(148,163,184,0.2), inset 0 0 30px rgba(0,0,0,0.5);
    padding: var(--space-2) var(--space-1);
    overflow: hidden;
}
.rack3d-face.r3d-back .rack-u-row { border-color: rgba(148,163,184,0.18); }
.rack3d-face.r3d-back .rack-mounted-device { left: 1px; right: 1px; opacity: 0.92; }
/* 侧板：拉丝金属 */
.rack3d-face.r3d-side {
    background: repeating-linear-gradient(90deg, #263243 0 2px, #1a2434 2px 5px);
    box-shadow: inset 0 0 0 2px #0f172a, inset 0 0 24px rgba(0,0,0,0.5);
}
/* 顶/底盖 */
.rack3d-face.r3d-cap {
    background: linear-gradient(135deg, #334155, #0f172a);
    box-shadow: inset 0 0 0 2px #0f172a;
}
/* 底部万向轮：广告牌（始终正对观察者），支架 + 带胎面/轮辋/轮毂的轮子 */
.rack3d-wheel {
    position: absolute;
    left: 50%; top: 50%;
    width: 22px; height: 30px;
}
/* 顶部金属支架/叉架 */
.rack3d-wheel .caster-fork {
    position: absolute;
    top: 0; left: 50%;
    transform: translateX(-50%);
    width: 13px; height: 13px;
    border-radius: var(--radius-xs) var(--radius-xs) 0 0;
    background: linear-gradient(180deg, #7b8390 0%, #4a515b 60%, #333941 100%);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 1px 2px rgba(0,0,0,0.5);
}
/* 叉架侧板延伸包住轮子两侧 */
.rack3d-wheel .caster-fork::after {
    content: '';
    position: absolute;
    left: -2px; right: -2px; bottom: -8px;
    height: 12px;
    border: 2px solid #3a414c;
    border-top: 0;
    border-radius: 0 0 var(--radius-sm) var(--radius-sm);
    background: transparent;
}
/* 轮子本体：胎面(黑) + 轮辋(金属) + 轮毂(中心螺栓) */
.rack3d-wheel .caster-tire {
    position: absolute;
    bottom: 0; left: 50%;
    transform: translateX(-50%);
    width: 22px; height: 22px;
    border-radius: 50%;
    background: radial-gradient(circle at 50% 50%,
        #aeb6c2 0 9%,     /* 轮毂螺栓高光 */
        #444b55 9% 17%,   /* 轮毂 */
        #6b7280 17% 26%,  /* 轮辋高光环 */
        #2b3038 26% 60%,  /* 轮辋盘面 */
        #0c0e12 60% 80%,  /* 胎面 */
        #040507 80% 100%);
    box-shadow: 0 3px 6px rgba(0,0,0,0.65), inset -2px -2px 5px rgba(0,0,0,0.6), inset 2px 2px 4px rgba(255,255,255,0.14);
}
/* 胎面上的高光弧，增强立体轮子感 */
.rack3d-wheel .caster-tire::after {
    content: '';
    position: absolute;
    left: 24%; top: 12%;
    width: 30%; height: 22%;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(255,255,255,0.55), rgba(255,255,255,0));
}
/* 3D 模式下 U 行铺满前面板 */
.rack3d-face.r3d-front .rack-u-row { border-color: rgba(148,163,184,0.22); }
.rack3d-face.r3d-front .rack-mounted-device {
    left: 1px; right: 1px;
    box-shadow: 0 6px 14px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.22), inset 0 -1px 0 rgba(0,0,0,0.4);
    transform: translateZ(6px);
}
/* 拖拽旋转时机柜上方显示当前朝向 */
/* 朝向标签移到机柜右侧（不再占用机柜正上方空间） */
.rack-view.rack-view-3d { position: relative; }
.rack3d-facing-badge {
    position: absolute;
    top: 6px;
    right: 6px;
    margin: 0;
    z-index: 3;
}
.rack3d-facing-badge span {
    display: inline-block;
    padding: var(--space-1) var(--space-5);
    border-radius: var(--radius-pill);
    background: rgba(56, 189, 248, 0.15);
    border: 1px solid rgba(56, 189, 248, 0.45);
    color: #38bdf8;
    font-weight: 600;
    font-size: var(--fs-sm);
    letter-spacing: 0.05em;
}
/* 2D 双面模式下 #rack-view 只作容器，去掉自身机柜边框 */
.rack-view.rack-view-dual {
    border: 0; background: transparent; box-shadow: none; padding: 0;
    max-width: none; overflow: visible;
}
/* 2D：正面 / 背面 左右并排 */
.rack-2d-dual {
    display: flex;
    gap: var(--space-7);
    justify-content: center;
    align-items: flex-start;
    flex-wrap: wrap;
}
.rack-2d-col { flex: 0 1 300px; min-width: 240px; max-width: 340px; }
.rack-2d-col-title {
    text-align: center;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 0.5rem;
    padding: var(--space-1);
    border-bottom: 2px solid var(--primary);
}
.rack-2d-col[data-side="rear"] .rack-2d-col-title { border-bottom-color: #f59e0b; }
.rack-2d-cab {
    border: 6px solid #0f172a;
    border-radius: var(--radius-md);
    background:
        linear-gradient(90deg, #1e293b 0 10px, transparent 10px calc(100% - 10px), #1e293b calc(100% - 10px)),
        #0a1120;
    box-shadow: inset 0 0 0 1px rgba(148,163,184,0.25), inset 0 0 40px rgba(56,189,248,0.06);
    padding: var(--space-2) var(--space-1);
}
[data-theme="light"] .rack-2d-cab {
    border-color: #475569;
    background: linear-gradient(90deg, #64748b 0 10px, transparent 10px calc(100% - 10px), #64748b calc(100% - 10px)), #e2e8f0;
}
.rack-alert-strip,
.rack-alert-list {
    margin: var(--space-4) 0 0;
    display: grid;
    gap: var(--space-3);
}
.rack-alert-item.info { border-left-color: #38bdf8; }
.rack-alert-item {
    border: 1px solid var(--border);
    border-left: 5px solid #38bdf8;
    border-radius: var(--radius-md);
    background: var(--bg-card);
    color: var(--text);
    padding: var(--space-3) var(--space-4);
}
.rack-alert-item.warning { border-left-color: #f59e0b; }
.rack-alert-item.critical { border-left-color: #ef4444; }
[data-theme="light"] .rack-view {
    border-color: #334155;
    background: linear-gradient(90deg, #64748b 0 12px, transparent 12px calc(100% - 12px), #64748b calc(100% - 12px)), #f8fafc;
}
.rack-u-row {
    position: relative;
    display: grid;
    grid-template-columns: 26px minmax(0, 1fr) 26px;
    height: var(--rack-unit-h);
    border-bottom: 1px solid rgba(148, 163, 184, 0.16);
    align-items: stretch;
}
.rack-u-row:first-child { border-top: 1px solid rgba(148, 163, 184, 0.16); }
/* 左侧 U 编号做成机架导轨（金属条），不占用机柜内部设备区域 */
.rack-u-num {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 8px;
    color: #7f8ea6;
    font-family: var(--font-mono);
    background: linear-gradient(90deg, #29323f, #1b2330);
    border-right: 1px solid rgba(0,0,0,0.45);
    box-shadow: inset -1px 0 0 rgba(148,163,184,0.10);
    text-shadow: 0 1px 0 rgba(0,0,0,0.5);
}
/* 右侧镜像导轨，使设备两侧间隙对称 */
.rack-u-num.rack-u-num-r {
    background: linear-gradient(90deg, #1b2330, #29323f);
    border-right: 0;
    border-left: 1px solid rgba(0,0,0,0.45);
    box-shadow: inset 1px 0 0 rgba(148,163,184,0.10);
}
.rack-u-slot {
    position: relative;
    height: 100%;
}
.rack-u-row.drop-ok .rack-u-slot { background: rgba(34, 197, 94, 0.22); }
.rack-u-row.drop-bad .rack-u-slot { background: rgba(239, 68, 68, 0.24); }
.rack-u-row.rack-u-reserved .rack-u-slot,
.rack-u-row.rack-u-blank_panel .rack-u-slot { background: rgba(234, 179, 8, 0.18); }
.rack-u-row.rack-u-disabled .rack-u-slot,
.rack-u-row.rack-u-fault .rack-u-slot { background: rgba(100, 116, 139, 0.28); }
.rack-mounted-device {
    position: absolute;
    left: 1px;
    right: 1px;
    top: 1px;
    border-radius: var(--radius-xs);
    border: 1px solid rgba(8,12,20,0.55);
    color: #e8edf5;
    padding: 0 var(--space-2);
    overflow: hidden;
    cursor: grab;
    z-index: 5;
    /* 拟物化金属面板：灰色渐变 + 顶部高光 + 底部阴影 */
    background: linear-gradient(180deg, #4a5568 0%, #333d4e 46%, #232b38 54%, #2c3543 100%);
    box-shadow: 0 2px 6px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.2), inset 0 -1px 0 rgba(0,0,0,0.45);
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
/* 面板顶部一层玻璃高光 */
.rack-mounted-device::before {
    content: '';
    position: absolute;
    left: 0; right: 0; top: 0;
    height: 45%;
    background: linear-gradient(180deg, rgba(255,255,255,0.18), rgba(255,255,255,0));
    pointer-events: none;
    z-index: 0;
}
.rack-mounted-device > * { position: relative; z-index: 1; }
.rack-mounted-device:active { cursor: grabbing; }
.rack-mounted-device strong {
    flex: 1 1 auto;
    text-align: center;
    font-size: 11px;
    font-weight: 600;
    line-height: var(--lh-display);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    letter-spacing: 0.02em;
}
/* 拟物化：面板左侧的散热孔点阵 */
.rack-dev-face-dots {
    flex: 0 0 auto;
    width: 10px;
    align-self: stretch;
    background-image: radial-gradient(rgba(255,255,255,0.28) 40%, transparent 42%);
    background-size: 3px 3px;
    opacity: 0.5;
    border-right: 1px solid rgba(255,255,255,0.12);
    margin-right: 0.15rem;
}
/* 大于 2U 设备：横向三段，两侧板卡+端口，中间设备名 */
.rack-mounted-device.rack-dev-tall {
    flex-direction: row;
    align-items: stretch;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-1);
}
.rack-dev-center {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-1);
    padding: 0 var(--space-1);
}
.rack-dev-center strong { text-align: center; font-size: 11px; font-weight: 600; white-space: nowrap; }
.rack-dev-cards { flex: 1 1 0; display: flex; flex-direction: column; gap: var(--space-1); justify-content: center; min-width: 0; }
.rack-dev-card {
    display: flex; align-items: center; gap: var(--space-1);
    background: linear-gradient(180deg, #3a434f 0%, #2b3340 55%, #232a35 100%);
    border-radius: var(--radius-xs); padding: 1px 3px;
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.08), inset 0 -1px 0 rgba(0,0,0,0.35);
}
.rack-dev-card-tab { flex: 0 0 auto; width: 5px; height: 6px; border-radius: var(--radius-xs); background: linear-gradient(180deg, #6b7280, #3a414c); }
.rack-dev-ports { display: flex; flex-wrap: wrap; gap: var(--space-1); min-width: 0; }
.rack-dev-ports i {
    width: 5px; height: 3.5px; border-radius: var(--radius-xs);
    background: #0b0d11; box-shadow: inset 0 0 0 0.5px #2b3038;
}
.rack-dev-ports i.on { background: #22c55e; box-shadow: 0 0 2px #22c55e, inset 0 0 0 0.5px #16a34a; }
/* 拟物化：右侧状态指示灯（3 颗） */
.rack-dev-leds {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: var(--space-1);
    padding-left: 0.35rem;
    border-left: 1px solid rgba(255,255,255,0.12);
}
.rack-dev-leds i {
    width: 5px; height: 5px;
    border-radius: 50%;
    background: #64748b;
    box-shadow: inset 0 0 1px rgba(0,0,0,0.5);
}
/* 在线：绿色闪烁（更亮） */
.rack-led-online i { background: #4ade80; box-shadow: var(--shadow-2); animation: rackLedSlow 0.6s infinite ease-in-out; }
.rack-led-online i:nth-child(2) { animation-delay: 0.12s; }
.rack-led-online i:nth-child(3) { animation-delay: 0.24s; }
/* 离线：红色闪烁（频率与在线一致，更亮） */
.rack-led-offline i { background: #f87171; box-shadow: var(--shadow-2); animation: rackLedSlow 0.6s infinite ease-in-out; }
.rack-led-offline i:nth-child(2) { animation-delay: 0.12s; }
.rack-led-offline i:nth-child(3) { animation-delay: 0.24s; }
/* 未知：暗灰常亮 */
.rack-led-unknown i { background: #475569; opacity: 0.6; }
@keyframes rackLedSlow { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }
.rack-dev-server { background: linear-gradient(135deg, #374151, #111827); }
.rack-dev-switch { background: linear-gradient(135deg, #2563eb, #0f766e); }
.rack-dev-router { background: linear-gradient(135deg, #7c3aed, #4c1d95); }
.rack-dev-firewall { background: linear-gradient(135deg, #dc2626, #7f1d1d); }
.rack-dev-pdu { background: linear-gradient(135deg, #f97316, #9a3412); }
.rack-dev-storage { background: linear-gradient(135deg, #16a34a, #14532d); }
.rack-dev-odf,
.rack-dev-transmission { background: linear-gradient(135deg, #0891b2, #164e63); }
.rack-dev-other { background: linear-gradient(135deg, #64748b, #334155); }
.rack-detail-content {
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg);
    padding: var(--space-4);
    margin-bottom: 0.85rem;
    min-height: 90px;
}
.rack-inline-move {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) 86px 92px auto;
    gap: var(--space-3);
    align-items: center;
    margin: var(--space-4) 0;
}
.rack-device-detail-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-3);
    margin-top: 0.7rem;
}
.rack-device-detail-grid > div {
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    background: var(--bg);
    min-height: 52px;
}
.rack-tag-link {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    color: var(--accent);
    font-weight: 600;
}
button.rack-tag-link {
    border: 0;
    background: transparent;
    cursor: pointer;
    padding: 0;
    text-decoration: underline;
    text-underline-offset: 2px;
}
.rack-form-grid { display: grid; gap: var(--space-4); }
.rack-mini-form {
    display: grid;
    gap: var(--space-3);
    border-top: 1px solid var(--border);
    padding-top: 0.75rem;
}
.rack-mini-form label { display: grid; gap: var(--space-1); color: var(--text-muted); font-size: var(--fs-sm); }
.rack-fullscreen { position: fixed; inset: 12px; z-index: 1000; background: var(--bg); padding: var(--space-5); overflow: auto; }
/* 机柜图区原生全屏：铺满屏幕、机柜图自适应填充 */
#rack-view-shell:fullscreen { background: var(--bg); padding: var(--space-6); }
#rack-view-shell:fullscreen > .rack-view { flex: 1; }
/* 机柜图形视图头部下拉框统一高度，消除高矮不一 */
/* DCIM 内所有下拉框统一为系统标准控件高度，消除与其它页面高矮不一 */
#panel-rack-mgmt select { height: var(--control-h); box-sizing: border-box; }
.rack-modal-head .rack-page-actions { flex-wrap: wrap; }
@media (max-width: 1200px) {
    .rack-workspace { grid-template-columns: 1fr; }
    .rack-side-nav { position: static; flex-direction: row; flex-wrap: wrap; }
    .rack-side-nav .rack-nav-btn { width: auto; flex: 1 1 auto; text-align: center; }
    .rack-nav-note { flex-basis: 100%; }
    .rack-crud-layout { grid-template-columns: 1fr; }
    .rack-rack-edit { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .rack-toolbar { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .rack-layout { grid-template-columns: 1fr; }
    .rack-device-palette, .rack-detail-panel { max-height: none; }
}
@media (max-width: 700px) {
    .rack-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .rack-edit-card,
    .rack-rack-edit { grid-template-columns: 1fr; }
    .rack-toolbar { grid-template-columns: 1fr; }
    .rack-list-toolbar { flex-direction: column; align-items: stretch; }
    .rack-grid-view { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); }
    .rack-page-head { flex-direction: column; }
    .rack-page-actions { justify-content: flex-start; }
    .rack-inline-move { grid-template-columns: 1fr; }
    .rack-device-detail-grid { grid-template-columns: 1fr; }
    .rack-modal-content { width: 96vw; }
}
.traffic-chart-hint { margin-top: 0.4rem; font-size: var(--fs-xs); color: var(--text-muted); }

.traffic-chart-stats {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: var(--space-2) var(--space-4);
    margin-top: 0.7rem;
    color: var(--text);
    font-size: var(--fs-sm);
    line-height: 1.4;
}

.traffic-chart-legend {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-weight: 600;
    white-space: nowrap;
}

.traffic-chart-p95-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    min-width: 0;
}

.traffic-chart-range {
    text-align: right;
    color: var(--text-muted);
    font-size: var(--fs-xs);
    white-space: nowrap;
}

.traffic-live-status {
    color: var(--accent);
    font-size: var(--fs-xs);
    font-weight: 600;
    white-space: nowrap;
}

.legend-swatch {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: var(--radius-xs);
    border: 1px solid rgba(15, 23, 42, 0.18);
}

.legend-swatch.in { background: #22c55e; }
.legend-swatch.out { background: #2563eb; }
.legend-swatch.p95 { background: #ef4444; }

.traffic-timebar {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--space-3);
    margin: -0.35rem 0 0.85rem;
    padding: var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg-card);
}

.traffic-timebar button {
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    background: var(--bg-card);
    color: var(--text);
    cursor: pointer;
    font-size: var(--fs-sm);
    font-weight: 600;
    padding: var(--space-2) var(--space-4);
}

.traffic-timebar button:hover,
.traffic-timebar button.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

[data-traffic-sort] {
    cursor: pointer;
    user-select: none;
}

[data-traffic-sort].sorted::after {
    content: attr(data-sort-dir);
    margin-left: 0.35rem;
    color: var(--primary);
    font-size: var(--fs-xs);
    text-transform: uppercase;
}

.topology-single-actions { display: contents; }

/* ===== 拓扑总览九宫格（Weathermap 风格缩略图画廊） ===== */
.topology-gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--space-5);
}
.topology-thumb-card {
    display: flex;
    flex-direction: column;
    gap: 0;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-card);
    box-shadow: var(--shadow);
    cursor: pointer;
    overflow: hidden;
    text-align: left;
    transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.topology-thumb-card:hover {
    border-color: var(--accent, #3b82f6);
    box-shadow: var(--shadow-3);
    transform: translateY(-2px);
}
.topology-thumb-card[draggable="true"] { cursor: grab; }
.topology-thumb-card.dragging {
    opacity: 0.5;
    cursor: grabbing;
    border-color: var(--accent, #3b82f6);
    box-shadow: var(--shadow-3);
}
.topology-thumb-canvas {
    aspect-ratio: 16 / 10;
    width: 100%;
    background:
        radial-gradient(circle at 30% 20%, rgba(59, 130, 246, .06), transparent 60%),
        var(--bg);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
.topology-thumb-svg { width: 100%; height: 100%; display: block; }
.topology-thumb-caption {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-top: 1px solid var(--border);
}
.topology-thumb-name {
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.topology-thumb-meta {
    flex: none;
    font-size: var(--fs-xs);
    color: var(--text-muted);
    white-space: nowrap;
}

.topology-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-4);
    margin-bottom: 1rem;
}

.topology-toolbar select {
    min-width: 240px;
}

.topology-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
    min-height: calc(100vh - 220px);
}

.topology-sidebar,
.topology-canvas-wrap {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-card);
    box-shadow: var(--shadow);
}

.topology-sidebar {
    padding: var(--space-4);
    overflow: auto;
}

.topology-sidebar h3 {
    margin: var(--space-1) 0 var(--space-3);
    color: var(--text);
    font-size: var(--fs-base);
}

.topology-map-list,
.topology-node-list {
    display: grid;
    gap: var(--space-3);
    margin-bottom: 1rem;
}

.topology-list-item {
    display: grid;
    gap: var(--space-1);
    width: 100%;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg);
    color: var(--text);
    cursor: pointer;
    padding: var(--space-3) var(--space-4);
    text-align: left;
}

.topology-list-item:hover,
.topology-list-item.active {
    border-color: var(--primary);
    background: rgba(59, 130, 246, 0.12);
}

.topology-list-item small {
    color: var(--text-muted);
}

.topology-canvas-wrap {
    position: relative;
    overflow: hidden;   /* 宽度已铺满、高度等比跟随，不会溢出，无需滚动 */
    /* 不设 min-height：高度由 svg 自己撑，图矮时容器跟着矮，不留下方空白 */
    display: block;
}

.topology-svg {
    width: auto;
    height: auto;
    display: block;
    /* 尺寸由 resizeTopologyViewport() 按容器宽度算好（宽=容器、高=等比），
       这里不要再让任何外部布局去压缩它，否则盒子比例失真 →
       svg 内部 preserveAspectRatio:meet 会把图居中缩放、四周留白。 */
    flex-shrink: 0;
    background:
        radial-gradient(circle at 24px 24px, rgba(96, 165, 250, 0.16) 1px, transparent 1px),
        var(--bg);
    background-size: 32px 32px;
}

.topology-link {
    fill: none;
    stroke: #64748b;
    stroke-width: 3.2;
    stroke-linecap: butt;
    cursor: pointer;
    opacity: 0.92;
}

.topology-editing .topology-link {
    cursor: pointer;
}

.topology-link:hover {
    stroke-width: 5;
    opacity: 1;
}

.topology-link-arrow {
    stroke: none;
    pointer-events: none;
}

/* 高利用率链路：从 POP 流向中心的流动动画 */
.topology-flow-layer { pointer-events: none; }
.topology-alert-layer { pointer-events: none; }
/* 彩虹跑车（俯视）：彩虹渐变车身沿链路匀速驶向中心（JS addTopologyCar + SVG animateMotion）。
   无拖尾，透明度 60%（内层 <g> style），轻微投影提升可见度。 */
.topology-car {
    pointer-events: none;
    filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.4));
}
.topology-car-shell {
    stroke: rgba(255, 255, 255, 0.7);
    stroke-width: 0.25;
    stroke-linejoin: round;
}
.topology-car-glass {
    fill: rgba(15, 23, 42, 0.55);
    stroke: rgba(255, 255, 255, 0.35);
    stroke-width: 0.2;
}

/* 拖拽 POP 时的对齐辅助线与间距标注 */
.topology-guide-layer { pointer-events: none; }
.topology-guide-line { stroke: #f472b6; stroke-width: 1; stroke-dasharray: 5 4; }
.topology-guide-dist {
    fill: #f472b6;
    font-size: var(--fs-xs);
    font-weight: 600;
    paint-order: stroke;
    stroke: var(--bg, #0b1220);
    stroke-width: 3px;
    stroke-linejoin: round;
}

/* 拓扑链路文字：Metric/带宽/时延/接口/供应商等统一细体等宽标注 */
.topology-link-text,
.topology-link-label,
.topology-endpoint-label {
    fill: var(--text-muted);
    font-size: var(--fs-2xs);
    font-weight: 500;
    font-family: var(--font-mono);
    paint-order: stroke;
    stroke: var(--bg);
    stroke-width: 2px;
    stroke-linejoin: round;
    pointer-events: none;
    dominant-baseline: middle;
    letter-spacing: -0.02em;
    opacity: 0.92;
}

.topology-node {
    cursor: pointer;
}

.topology-editing .topology-node {
    cursor: move;
}

.topology-node circle {
    fill: #0f274a;
    stroke: rgba(125, 211, 252, 0.85);
    stroke-width: 1.4;
    filter: drop-shadow(0 7px 13px rgba(0, 0, 0, 0.5));
}

.topology-node.core circle {
    fill: #0f2f27;
    stroke: rgba(134, 239, 172, 0.85);
}

.topology-node.overseas circle,
.topology-node.edge circle {
    fill: #3b2e08;
    stroke: rgba(252, 211, 77, 0.9);
}

.topology-node-gloss {
    pointer-events: none;
    mix-blend-mode: screen;
}

.topology-node.selected circle {
    stroke: #f97316;
    stroke-width: 2.6;
    filter: drop-shadow(0 0 6px rgba(249, 115, 22, 0.9)) drop-shadow(0 7px 13px rgba(0, 0, 0, 0.5));
}

/* 设备图标节点（路由器/交换机/防火墙/服务器）：立体渐变卡片 + 内嵌高光边框 + 玻璃反光 + 底部标签胶囊 */
.topology-node-badge-shadow {
    opacity: 0.85;
    pointer-events: none;
}

.topology-node-badge {
    stroke: rgba(255, 255, 255, 0.4);
    stroke-width: 1.2;
    filter: drop-shadow(0 8px 14px rgba(0, 0, 0, 0.55));
}

.topology-node.selected .topology-node-badge {
    stroke: #f97316;
    stroke-width: 2.6;
    filter: drop-shadow(0 0 7px rgba(249, 115, 22, 0.95)) drop-shadow(0 8px 14px rgba(0, 0, 0, 0.55));
}

.topology-node-badge-rim {
    fill: none;
    stroke: rgba(255, 255, 255, 0.35);
    stroke-width: 1;
    pointer-events: none;
}

.topology-node-badge-gloss {
    opacity: 0.55;
    mix-blend-mode: screen;
    pointer-events: none;
}

.topology-node-badge-pill {
    fill: rgba(4, 10, 22, 0.42);
    stroke: rgba(255, 255, 255, 0.22);
    stroke-width: 0.8;
    pointer-events: none;
}

.topology-node text.topology-node-badge-label {
    fill: #ffffff;
    font-weight: 600;
    text-anchor: middle;
    pointer-events: none;
    paint-order: stroke;
    stroke: rgba(0, 0, 0, 0.55);
    stroke-width: 2px;
    stroke-linejoin: round;
}

/* 中断/无流量链路：灰色线条闪烁 + 高亮红色 3D 炸弹循环提示管理员关注 */
@keyframes topoFaultBlink { 0%, 100% { opacity: 1; } 50% { opacity: 0.15; } }
.topology-link.topology-link-fault,
.topology-link-arrow.topology-link-fault { animation: topoFaultBlink 0.7s steps(1, end) infinite; }

.topology-link-alert.hidden {
    display: none;
}

.topology-link-alert.active {
    display: block;
}

.topology-bomb-shock,
.topology-bomb-burst,
.topology-bomb-shadow,
.topology-bomb-cap,
.topology-bomb-cap-highlight,
.topology-bomb-fuse,
.topology-bomb-body,
.topology-bomb-depth,
.topology-bomb-gloss,
.topology-bomb-fire-ray {
    transform-box: fill-box;
    transform-origin: center;
}

.topology-bomb-shock {
    fill: rgba(255, 38, 0, 0.22);
    stroke: rgba(255, 150, 140, 0.85);
    stroke-width: 1.4;
    filter: drop-shadow(0 0 16px rgba(255, 42, 0, 1));
    animation: topoBombShock 3s ease-out infinite;
}

.topology-bomb-burst {
    fill: #ff1a00;
    stroke: #ffb4a8;
    stroke-width: 1;
    opacity: 0;
    filter: drop-shadow(0 0 12px rgba(255, 24, 0, 1)) drop-shadow(0 0 5px rgba(255, 42, 0, 0.7));
    animation: topoBombBurst3d 3s ease-out infinite;
}

.topology-bomb-shadow {
    fill: rgba(0, 0, 0, 0.55);
    animation: topoBombBody 3s ease-in-out infinite;
}

.topology-bomb-cap {
    fill: #222832;
    stroke: #6f7b8c;
    stroke-width: 1;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.75));
    animation: topoBombBody 3s ease-in-out infinite, topoBombMetalCap 3s ease-in-out infinite;
}

.topology-bomb-cap-highlight {
    fill: rgba(210, 220, 232, 0.35);
    stroke: none;
    animation: topoBombBody 3s ease-in-out infinite;
}

.topology-bomb-fuse {
    fill: none;
    stroke: #f4c542;
    stroke-width: 1.6;
    stroke-linecap: round;
    filter: drop-shadow(0 0 3px rgba(244, 197, 66, 0.65));
    animation: topoBombBody 3s ease-in-out infinite;
}

.topology-bomb-body {
    fill: #171b22;
    stroke: #4b5563;
    stroke-width: 1.4;
    filter: drop-shadow(0 0 5px rgba(15, 23, 42, 0.85)) drop-shadow(0 2px 4px rgba(0, 0, 0, 0.68));
    animation: topoBombBody 3s ease-in-out infinite, topoBombMetalBody 3s ease-in-out infinite;
}

.topology-bomb-depth {
    fill: rgba(255, 255, 255, 0.055);
    stroke: none;
    animation: topoBombBody 3s ease-in-out infinite, topoBombDepth 3s ease-in-out infinite;
}

.topology-bomb-gloss {
    fill: rgba(180, 190, 205, 0.2);
    animation: topoBombBody 3s ease-in-out infinite, topoBombGloss 3s ease-in-out infinite;
}

.topology-bomb-fire-ray {
    stroke: #ff2a00;
    stroke-width: 2.2;
    stroke-linecap: round;
    opacity: 0;
    filter: drop-shadow(0 0 9px rgba(255, 36, 0, 1)) drop-shadow(0 0 4px rgba(255, 78, 62, 0.85));
    animation: topoBombFireRay 3s ease-out infinite;
}

@keyframes topoBombBody {
    0%, 46%, 100% { opacity: 1; transform: scale(0.84); }
    54% { opacity: 1; transform: scale(1.12); }
    60%, 86% { opacity: 0.12; transform: scale(0.32); }
    95% { opacity: 1; transform: scale(0.84); }
}

@keyframes topoBombMetalBody {
    0%, 48%, 100% { fill: #171b22; stroke: #4b5563; }
    54%, 86% { fill: #ff1600; stroke: #ffb4a8; }
}

@keyframes topoBombMetalCap {
    0%, 48%, 100% { fill: #222832; stroke: #6f7b8c; }
    54%, 86% { fill: #d23020; stroke: #ffb4a8; }
}

@keyframes topoBombDepth {
    0%, 48%, 100% { fill: rgba(255, 255, 255, 0.055); }
    54%, 86% { fill: rgba(255, 70, 55, 0.24); }
}

@keyframes topoBombGloss {
    0%, 48%, 100% { fill: rgba(180, 190, 205, 0.2); }
    54%, 86% { fill: rgba(255, 205, 205, 0.76); }
}

@keyframes topoBombShock {
    0%, 48% { opacity: 0; transform: scale(0.35); }
    56% { opacity: 0.95; transform: scale(0.72); }
    88% { opacity: 0.25; transform: scale(1.85); }
    100% { opacity: 0; transform: scale(0.35); }
}

@keyframes topoBombBurst3d {
    0%, 48%, 100% { opacity: 0; transform: scale(0.25) rotate(0deg); }
    56% { opacity: 1; transform: scale(1) rotate(8deg); }
    84% { opacity: 1; transform: scale(1.18) rotate(-4deg); }
    92% { opacity: 0; transform: scale(1.42) rotate(0deg); }
}

@keyframes topoBombFireRay {
    0%, 48%, 100% { opacity: 0; transform: scale(0.25); stroke: #ff2a00; }
    56% { opacity: 1; transform: scale(1.08); stroke: #ff3b30; }
    84% { opacity: 0.9; transform: scale(1.28); stroke: #ff2a00; }
    92% { opacity: 0; transform: scale(1.42); stroke: #ff2a00; }
}

.auto-rule-device-list {
    display: grid;
    gap: var(--space-2);
    min-height: 120px;
    max-height: 210px;
    overflow: auto;
    padding: var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--control-bg);
}

.auto-rule-device-option {
    display: grid;
    grid-template-columns: 18px minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--space-3);
    min-height: 30px;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
    color: var(--text);
    font-size: var(--fs-base);
    cursor: pointer;
}

.auto-rule-device-option:hover {
    background: var(--bg-elevated);
}

.auto-rule-device-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
}

.auto-rule-device-ip {
    color: var(--text-muted);
    font-size: var(--fs-xs);
}

.auto-rule-device-empty {
    color: var(--text-muted);
    padding: var(--space-4);
    text-align: center;
}

.topology-select-box {
    fill: rgba(56, 189, 248, 0.12);
    stroke: #38bdf8;
    stroke-width: 1;
    stroke-dasharray: 4 3;
    pointer-events: none;
}

/* 节点标签统一字体：与设备卡片标签(topology-node-badge-label)同款——白字+深色细描边，
   不随主题变化（此前用 var(--bg) 做 3px 光晕，浅色主题下呈白色描边，与其它拓扑不一致）。 */
.topology-node text {
    fill: #ffffff;
    font-weight: 600;
    text-anchor: middle;
    pointer-events: none;
    paint-order: stroke;
    stroke: rgba(0, 0, 0, 0.55);
    stroke-width: 2px;
    stroke-linejoin: round;
}

.topology-node .node-subtitle {
    fill: var(--text-muted);
    font-size: var(--fs-xs);
    font-weight: 600;
}

.topology-tooltip {
    position: absolute;
    z-index: 20;
    width: min(520px, 90%);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg-card);
    box-shadow: var(--shadow-lg);
    color: var(--text);
    padding: var(--space-4);
    pointer-events: auto;
}

.topology-tooltip.hidden {
    display: none;
}

.topology-tooltip-title {
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: 0.45rem;
    font-weight: 600;
}

.topology-tooltip-meta {
    color: var(--text-muted);
    font-size: var(--fs-sm);
    line-height: var(--lh-normal);
    margin-bottom: 0.55rem;
}

.topology-tooltip .native-traffic-chart-wrap {
    padding: 0;
}

.topology-tooltip .traffic-chart-stats {
    font-size: var(--fs-xs);
}

.traffic-graph-toolbar {
    grid-template-columns: minmax(220px, 1.1fr) minmax(170px, 0.8fr) 160px 110px 130px auto;
    margin-top: 0;
}

.traffic-device-picker-wrap {
    position: relative;
    min-width: 0;
}

.traffic-device-dropdown {
    position: absolute;
    top: calc(100% + 0.35rem);
    left: 0;
    z-index: 60;
    width: min(520px, 100vw - 2rem);
    max-height: 420px;
    overflow: auto;
    padding: var(--space-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-card);
    box-shadow: var(--shadow-card);
}

.traffic-device-dropdown button {
    width: 100%;
    display: grid;
    gap: var(--space-1);
    text-align: left;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--text);
    padding: var(--space-3) var(--space-3);
    cursor: pointer;
}

.traffic-device-dropdown button:hover,
.traffic-device-dropdown button.active {
    border-color: rgba(0, 113, 227, 0.45);
    background: rgba(0, 113, 227, 0.14);
}

.traffic-device-dropdown strong {
    font-size: var(--fs-sm);
}

.traffic-device-dropdown span {
    color: var(--text-muted);
    font-size: var(--fs-xs);
}

body.traffic-graph-mode {
    overflow: hidden;
}

body.traffic-graph-mode .main {
    overflow: hidden;
    padding-bottom: var(--page-pad-y);
}

body.traffic-graph-mode .app-footer {
    display: none;
}

.traffic-graph-page.active {
    display: flex;
    flex-direction: column;
    height: calc(100vh - 56px - var(--page-pad-y) - var(--page-pad-y));
    min-height: 0;
    overflow: hidden;
}

.traffic-graph-page .panel-header,
.traffic-graph-page .traffic-graph-toolbar,
.traffic-graph-page .traffic-timebar {
    flex: 0 0 auto;
}

.traffic-graph-layout {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr);
    gap: var(--space-5);
    flex: 1 1 auto;
    min-height: 0;
}

.traffic-graph-pane,
.traffic-graph-main {
    min-width: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-card);
    box-shadow: var(--shadow);
    overflow: hidden;
}

.traffic-graph-pane {
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.traffic-graph-main {
    background: var(--bg);
    overflow: auto;
    padding: var(--space-4);
    min-height: 0;
}

.traffic-pane-title {
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--border);
    color: var(--text-muted);
    font-size: var(--fs-sm);
    font-weight: 600;
}

.traffic-side-list {
    height: calc(100vh - 270px);
    min-height: 610px;
    overflow: auto;
    padding: var(--space-3);
    flex: 1 1 auto;
}

.traffic-graph-list {
    display: grid;
    grid-template-columns: repeat(var(--traffic-graph-columns, 1), minmax(0, 1fr));
    gap: var(--space-4);
}

.traffic-graph-card {
    min-width: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--bg-card);
}

.traffic-graph-card.active {
    border-color: rgba(0, 113, 227, 0.65);
    box-shadow: var(--shadow-1);
}

.traffic-graph-card .native-traffic-chart-wrap {
    padding: var(--space-2) var(--space-3) var(--space-2);
}

.traffic-graph-card .native-traffic-chart {
    height: 300px;
}

.traffic-graph-list.single .native-traffic-chart,
.traffic-graph-list[style*="--traffic-graph-columns: 1"] .native-traffic-chart {
    height: min(44vh, 430px);
}

.traffic-graph-card .traffic-chart-stats {
    font-size: var(--fs-xs);
    grid-template-columns: minmax(92px, 0.35fr) minmax(0, 1fr);
    gap: var(--space-1) var(--space-3);
    margin-top: 0.35rem;
}

.traffic-graph-card .traffic-chart-hint {
    display: none;
}

.traffic-graph-chart-pagination {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-3);
    margin: 0 0 var(--space-4);
    color: var(--text-muted);
    font-size: var(--fs-sm);
}

.traffic-graph-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--border);
    color: var(--text);
}

.traffic-graph-card-header strong,
.traffic-graph-card-header span {
    display: block;
}

.traffic-graph-card-header strong {
    font-size: var(--fs-sm);
    line-height: 1.35;
    overflow-wrap: anywhere;
}

.traffic-graph-card-header span {
    margin-top: 0.2rem;
    color: var(--text-muted);
    font-size: var(--fs-sm);
    overflow-wrap: anywhere;
}

.traffic-side-item {
    width: 100%;
    display: block;
    text-align: left;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--text);
    padding: var(--space-4) var(--space-4);
    cursor: pointer;
}

.traffic-side-item:hover {
    background: var(--bg-elevated);
}

.traffic-side-item.active {
    border-color: rgba(0, 113, 227, 0.35);
    background: color-mix(in srgb, var(--act-primary) 12%, transparent);
}

.traffic-side-item strong {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--fs-base);
}

.traffic-side-item span {
    display: block;
    margin-top: 0.25rem;
    color: var(--text-muted);
    font-size: var(--fs-xs);
    line-height: 1.35;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.traffic-side-item small,
.traffic-interface-status {
    display: inline-flex;
    align-items: center;
    margin-top: 0.35rem;
    color: var(--text-muted);
    font-size: var(--fs-2xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

.traffic-interface-status {
    margin-top: 0;
    white-space: nowrap;
}

/* 流量/性能页状态徽章：统一状态 pill 配方（同 .state-pill） */
.status-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 38px;
    border-radius: var(--radius-pill);
    padding: 0.12rem 0.5rem;
    font-size: var(--fs-xs);
    font-weight: 600;
    white-space: nowrap;
    background: rgba(148, 163, 184, 0.14);
    color: var(--text-muted);
}

.status-online {
    background: rgba(34, 197, 94, 0.14);
    color: #39d98a;
}

.status-offline {
    background: rgba(239, 68, 68, 0.16);
    color: #ff6b6b;
}

.status-warning {
    background: rgba(245, 158, 11, 0.16);
    color: #f59e0b;
}
/* 备份任务等状态徽章：统一状态 pill 配方（同 .state-pill） */
.badge { display: inline-flex; align-items: center; justify-content: center; min-width: 38px; padding: 0.12rem 0.5rem; border-radius: var(--radius-pill); font-size: var(--fs-xs); font-weight: 600; white-space: nowrap; background: rgba(148, 163, 184, 0.14); color: var(--text-muted); }
.badge-warn { background: rgba(245, 158, 11, 0.16); color: #f59e0b; }
.badge-ok { background: rgba(34, 197, 94, 0.14); color: #39d98a; }
.badge-muted { background: rgba(148, 163, 184, 0.14); color: var(--text-muted); }
.backup-jobs-section { margin-top: 1.5rem; }
.backup-jobs-section h3 { margin: 0 0 var(--space-4); font-size: var(--fs-md); font-weight: 600; color: var(--text-muted); }
.backup-job-running { background: rgba(210,153,34,0.08); }
.backup-jobs-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-bottom: 0.5rem;
    font-size: var(--fs-base);
    color: var(--text-muted);
}
.backup-jobs-toolbar select { min-width: 7rem; }
.backup-jobs-toolbar .pagination-info {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-3);
}
.dashboard-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(520px, 100%), 1fr)); gap: var(--space-5); margin-bottom: 1.25rem; }
@media (max-width: 900px) { .dashboard-grid { grid-template-columns: 1fr; } }
.dashboard-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: var(--card-pad);
    box-shadow: var(--shadow);
    transition: box-shadow .2s ease, opacity .15s ease;
    cursor: grab;
}
.dashboard-card:active { cursor: grabbing; }
.dashboard-card.dragging { opacity: 0.6; user-select: none; }
.dashboard-card.drag-over { border-color: var(--primary); box-shadow: var(--shadow-1); }
.dashboard-card:hover { box-shadow: var(--shadow-3); }
.dashboard-card h3,
.dashboard-card .dashboard-card-title { margin: 0 0 var(--space-5); font-size: var(--fs-md); font-weight: 600; color: var(--text); letter-spacing: -0.01em; }
/* 配置变动（重做版）：列表 +N/-N 与详情差异块 */
.cfgchg-added { color: var(--success, #22c55e); font-weight: 600; }
.cfgchg-removed { color: var(--error, #ef4444); font-weight: 600; }
.cfgchg-diff { display: grid; gap: var(--space-4); max-width: 1100px; margin-top: 0.75rem; }
.cfgchg-block { border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-card); overflow: hidden; }
.cfgchg-block-title {
    padding: var(--space-3) var(--space-4); font-weight: 600; color: var(--text);
    background: var(--bg-elevated); border-bottom: 1px solid var(--border);
    font-family: var(--font-mono); font-size: var(--fs-sm);
}
.cfgchg-pre {
    margin: 0; padding: var(--space-3) var(--space-4); overflow-x: auto;
    font-family: var(--font-mono); font-size: var(--fs-sm); line-height: var(--lh-normal);
    white-space: pre-wrap; word-break: break-all;
}
.cfgchg-line { display: block; }
.cfgchg-line.add { color: var(--success, #22c55e); }
.cfgchg-line.del { color: var(--error, #ef4444); }
.cfgchg-file-link { color: var(--primary, #3b82f6); text-decoration: none; }
.cfgchg-file-link:hover { text-decoration: underline; }
/* 配置变动页原本单独打的 flex 补丁已并入 .rack-list-toolbar 全局规则，此处不再需要 */

/* 备份任务记录：成功/失败计数可点跳转日志 */
.log-count-link, .log-fail-count-link { cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
.log-count-link:hover, .log-fail-count-link:hover { opacity: 0.8; }

/* 历史备份页头部操作区 */
.config-files-section-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-5); flex-wrap: wrap; }
.config-files-head-actions { display: flex; gap: var(--space-3); flex-wrap: wrap; }

/* ===== 独立「配置对比」页：GitHub 风格左右对齐差异 ===== */
.config-compare-controls { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; margin-bottom: 0.8rem; }
.config-compare-controls select { min-width: 16rem; max-width: 24rem; }
.compare-summary { margin-left: auto; font-family: var(--font-mono); font-weight: 600; }
.compare-summary .cmp-add { color: var(--success, #1a7f37); }
.compare-summary .cmp-del { color: var(--error, #cf222e); }
.config-compare-result {
    border: 1px solid var(--border, #d0d7de);
    border-radius: var(--radius-sm);
    overflow-x: hidden;       /* 长行换行，不横向外溢 */
    overflow-y: auto;
    max-height: 74vh;
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    line-height: var(--lh-normal);
    background: var(--bg-elevated, #fff);
}
.config-compare-table { width: 100%; }
/* 两个代码列严格各占一半(1fr=1fr)，两侧行号列固定窄；整体不超出容器宽度 */
.cmp-row { display: grid; grid-template-columns: 3.25em minmax(0, 1fr) 3.25em minmax(0, 1fr); }
.cmp-row.cmp-head {
    position: sticky; top: 0; z-index: 1;
    background: var(--bg-muted, #f6f8fa);
    font-weight: 600;
    border-bottom: 1px solid var(--border, #d0d7de);
}
.cmp-row.cmp-head .cmp-code { color: var(--text-muted, #57606a); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cmp-ln {
    text-align: right; padding: 0 0.6em;
    color: var(--text-muted, #8c959f);
    background: var(--bg-muted, #f6f8fa);
    user-select: none; -webkit-user-select: none;
    border-right: 1px solid var(--border, #eaeef2);
    white-space: nowrap;
}
/* 长行自动换行，避免右框被挤出屏幕；同一 grid 行左右自动等高、对齐不破 */
.cmp-code { padding: 0 0.7em; white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word; }
.cmp-left { border-right: 1px solid var(--border, #eaeef2); }
/* 差异用文字颜色标注，不使用背景色 */
.cmp-row.r-del .cmp-left { color: var(--error, #cf222e); }
.cmp-row.r-add .cmp-right { color: var(--success, #1a7f37); }
.cmp-row.r-chg .cmp-left { color: var(--error, #cf222e); }
.cmp-row.r-chg .cmp-right { color: var(--success, #1a7f37); }
/* 同一行内被改动的子串：加粗+下划线突出（不加背景） */
.cmp-code .di { font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
.config-compare-result.cmp-only-changed .cmp-row.eq { display: none; }
@media (prefers-color-scheme: dark) {
    .cmp-row.r-del .cmp-left, .cmp-row.r-chg .cmp-left { color: #ff7b72; }
    .cmp-row.r-add .cmp-right, .cmp-row.r-chg .cmp-right { color: #7ee787; }
}
:root[data-theme="dark"] .cmp-row.r-del .cmp-left,
:root[data-theme="dark"] .cmp-row.r-chg .cmp-left { color: #ff7b72; }
:root[data-theme="dark"] .cmp-row.r-add .cmp-right,
:root[data-theme="dark"] .cmp-row.r-chg .cmp-right { color: #7ee787; }
:root[data-theme="light"] .cmp-row.r-del .cmp-left,
:root[data-theme="light"] .cmp-row.r-chg .cmp-left { color: var(--error, #cf222e); }
:root[data-theme="light"] .cmp-row.r-add .cmp-right,
:root[data-theme="light"] .cmp-row.r-chg .cmp-right { color: var(--success, #1a7f37); }

/* 备份趋势图 - 渐变、光效、hover 动效 */
.chart-wrap {
    min-height: 200px;
    display: flex;
    flex-direction: column;
    padding: var(--space-5) var(--space-3);
    background: linear-gradient(180deg, rgba(59, 130, 246, 0.03) 0%, transparent 50%);
    border-radius: var(--radius);
    position: relative;
}
.chart-bars-row {
    flex: 1;
    display: flex;
    align-items: flex-end;
    gap: var(--space-3);
    min-height: 140px;
    position: relative;
    z-index: 1;
}
.chart-wrap::before {
    content: '';
    position: absolute;
    inset: 0;
    top: 1rem;
    bottom: 3rem;
    left: 0.5rem;
    right: 0.5rem;
    background: repeating-linear-gradient(
        90deg,
        transparent,
        transparent 1px,
        rgba(59, 130, 246, 0.04) 1px,
        rgba(59, 130, 246, 0.04) 2px
    );
    pointer-events: none;
    border-radius: var(--radius);
}
.chart-bar-wrap {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    transition: transform 0.2s ease;
}
.chart-bar-count {
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--text);
    line-height: var(--lh-single);
    min-height: 1.2em;
}
.chart-bar-wrap:hover { transform: translateY(-2px); }
.chart-bar-wrap:hover .chart-bar { opacity: 1; }
.chart-bar-group {
    display: flex;
    gap: var(--space-1);
    align-items: flex-end;
    height: 120px;
    width: 100%;
    justify-content: center;
}
.chart-bar-col {
    display: flex;
    flex-direction: column;
    align-items: center;
    flex: 1;
    min-width: 0;
}
.chart-bar-col .chart-bar-count {
    margin-bottom: 4px;
}
.chart-bar-col .chart-bar {
    width: 100%;
    flex: none;
}
.chart-bar-count-ok { color: #16a34a; }
.chart-bar-count-fail { color: #dc2626; }
.chart-bar {
    display: block;
    min-width: 8px;
    min-height: 3px;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    transition: opacity 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
    opacity: 0.92;
}
.chart-bar-wrap:hover .chart-bar {
    box-shadow: var(--shadow-2);
}
.chart-bar-ok {
    background: linear-gradient(180deg, #22c55e 0%, #16a34a 50%, #15803d 100%);
    box-shadow: var(--shadow-2);
}
.chart-bar-fail {
    background: linear-gradient(180deg, #ef4444 0%, #dc2626 50%, #b91c1c 100%);
    box-shadow: var(--shadow-2);
}
.chart-label {
    font-size: var(--fs-xs);
    font-weight: 500;
    color: var(--text-muted);
    letter-spacing: 0.02em;
}
.chart-legend {
    display: flex;
    gap: var(--space-5);
    justify-content: center;
    margin-top: 0.75rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--border);
}
.chart-legend-item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--fs-xs);
    color: var(--text-muted);
}
.chart-legend-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
}
.chart-legend-dot.ok { background: linear-gradient(135deg, #22c55e, #16a34a); }
.chart-legend-dot.fail { background: linear-gradient(135deg, #ef4444, #dc2626); }
.recent-activity {
    max-height: 280px;
    overflow-y: auto;
    text-align: left;
}
/* 最近活动：整行铺满卡片宽度，每列等比自适应，但内容保持左对齐 */
.recent-header-row,
.recent-item {
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--border);
    font-size: var(--fs-base);
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1.4fr) minmax(0, 0.9fr) minmax(0, 1.6fr); /* 主机名 / IP / 状态 / 时间 */
    column-gap: var(--space-4);
    align-items: center;
    text-align: left;
}
/* 按类型/分组成功率：3列 */
.dashboard-sla-table .recent-header-row,
.dashboard-sla-table .recent-item {
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 0.8fr);
}
.recent-item .status-warn { color: var(--warn, #eab308); }
.recent-header-row {
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--text-muted);
}
.recent-header-cell {
    text-align: left;
}
.recent-item span {
    text-align: left;
}
.recent-item:last-child { border-bottom: none; }
.recent-item .status-ok { color: var(--success); }
.recent-item .status-fail { color: var(--error); }

/* 设备类型分布 & 风险概览 */
.type-distribution {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.type-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    font-size: var(--fs-base);
}
.type-row-label {
    min-width: 72px;
    color: var(--text-muted);
}
.type-row-bar-wrap {
    flex: 1;
    background: rgba(255,255,255,0.03);
    border-radius: var(--radius-pill);
    overflow: hidden;
}
.type-row-bar {
    height: 6px;
    border-radius: var(--radius-pill);
    background: linear-gradient(90deg, rgba(0,181,255,0.8), rgba(0,181,255,0.4));
}
.type-row-count {
    min-width: 38px;
    text-align: right;
    color: var(--text-muted);
}

.risk-metrics {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-bottom: 0.75rem;
}
.risk-metric {
    display: flex;
    justify-content: space-between;
    font-size: var(--fs-base);
}
.risk-metric .label {
    color: var(--text-muted);
}
.risk-metric .value {
    color: var(--warn);
    font-weight: 600;
}
.top-fail-title {
    font-size: var(--fs-base);
    color: var(--text-muted);
    margin-bottom: 0.35rem;
}
.top-fail-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    font-size: var(--fs-base);
}
.top-fail-item {
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
}
.top-fail-item-main {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}
.top-fail-item-host {
    color: var(--text);
}
.top-fail-item-ip {
    color: var(--text-muted);
    font-size: var(--fs-sm);
}
.top-fail-item-count {
    color: var(--error);
    font-weight: 600;
    white-space: nowrap;
}

/* 最近登录列表：列宽自适应，内容少时均分，内容多时按需分配，放不下再换行 */
.recent-logins > .hint {
    grid-column: 1 / -1;
}
.recent-logins {
    max-height: 260px;
    overflow-y: auto;
    overflow-x: auto;
    font-size: var(--fs-base);
    display: grid;
    grid-template-columns: minmax(0, 0.55fr) minmax(0, 0.75fr) minmax(0, 0.65fr) minmax(7rem, 1.1fr);
    width: 100%;
    min-width: 0;
}
.login-header-row,
.login-item {
    display: contents;
}
.login-header-row .login-header-cell,
.login-item .login-item-username,
.login-item .login-item-ip,
.login-item .login-item-method,
.login-item .login-item-time {
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
    min-width: 0;
    overflow-wrap: break-word;
    word-break: break-word;
}
.login-item:last-child .login-item-username,
.login-item:last-child .login-item-ip,
.login-item:last-child .login-item-method,
.login-item:last-child .login-item-time {
    border-bottom: none;
}
.login-header-cell {
    font-size: var(--fs-sm);
    color: var(--text-muted);
    font-weight: 600;
    text-align: left;
}
.login-item-username {
    font-weight: 500;
    color: var(--text);
    text-align: left;
}
.login-item-ip,
.login-item-method,
.login-item-time {
    color: var(--text-muted);
    text-align: left;
}
.login-item-time {
    font-size: var(--fs-sm);
    white-space: nowrap;
}

/* 安全审计（最近操作）：列宽自适应，同上 */
.audit-logs > .hint {
    grid-column: 1 / -1;
}
.audit-logs {
    max-height: 260px;
    overflow-y: auto;
    overflow-x: auto;
    font-size: var(--fs-base);
    display: grid;
    grid-template-columns: minmax(0, 0.55fr) minmax(0, 0.9fr) minmax(0, 1fr) minmax(7rem, 1.1fr);
    width: 100%;
    min-width: 0;
}
.audit-header-row,
.audit-item {
    display: contents;
}
.audit-header-row .audit-header-cell,
.audit-item .audit-user,
.audit-item .audit-action,
.audit-item .audit-target,
.audit-item .audit-time {
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
    min-width: 0;
    overflow-wrap: break-word;
    word-break: break-word;
}
.audit-item:last-child .audit-user,
.audit-item:last-child .audit-action,
.audit-item:last-child .audit-target,
.audit-item:last-child .audit-time {
    border-bottom: none;
}
.audit-header-cell {
    font-size: var(--fs-sm);
    color: var(--text-muted);
    font-weight: 600;
    text-align: left;
}
.audit-user {
    font-weight: 500;
    color: var(--text);
    text-align: left;
}
.audit-action,
.audit-target,
.audit-time {
    color: var(--text-muted);
    text-align: left;
}
.audit-time {
    font-size: var(--fs-sm);
    white-space: nowrap;
}

/* Toast */
.toast-container { position: fixed; bottom: 1.5rem; right: 1.5rem; z-index: 200; display: flex; flex-direction: column; gap: var(--space-3); pointer-events: none; }
.toast { padding: var(--space-3) var(--space-5); border-radius: var(--radius); background: var(--bg-elevated); border: 1px solid var(--border); box-shadow: var(--shadow-2); font-size: var(--fs-base); pointer-events: auto; animation: toast-in 0.25s ease; }
.toast.success { border-left: 4px solid var(--success); }
.toast.error { border-left: 4px solid var(--error); }
.toast.warn { border-left: 4px solid var(--warn); }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }

/* 空状态 */
.empty-state { text-align: center; padding: var(--space-8); color: var(--text-muted); font-size: var(--fs-base); }
.loading-state { padding: var(--space-5); text-align: center; color: var(--text-muted); }

.panel-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1rem;
    flex-wrap: wrap;
    gap: var(--space-4);
}
.panel-header h2 { margin: 0; font-size: clamp(1.35rem, 1.5vw, 1.75rem); font-weight: 600; letter-spacing: -0.025em; }
.panel-header-actions { display: flex; align-items: center; gap: var(--space-3); }

/* 按钮 - Apple 风格：圆角、主色蓝、无重阴影 */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: var(--control-h);
    padding: var(--space-2) var(--space-5);
    border-radius: var(--control-radius);
    border: 1px solid transparent;
    cursor: pointer;
    font-size: var(--fs-base);
    font-weight: 500;
    line-height: 1.2;
    white-space: nowrap;
    transition: background .2s ease, transform .12s ease, border-color .2s ease;
}
.btn:active { transform: scale(0.98); }
.btn-primary { background: var(--primary); color: #fff; }
.btn-primary:hover { background: var(--primary-hover); color: #fff; }
.btn-secondary { background: var(--bg-elevated); color: var(--text); border-color: var(--border); }
.btn-secondary:hover { background: var(--border); color: var(--text); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
.btn-sm { min-height: 24px; padding: var(--space-1) var(--space-4); font-size: var(--fs-sm); }
.btn-xs { min-height: 20px; padding: var(--space-1) var(--space-3); font-size: var(--fs-xs); border-radius: var(--control-radius); }
/* ============================================================
   按钮体系（Phase 2）：三个正交维度，不再按业务命名
   ------------------------------------------------------------
   【为什么重构】原来有 17 个变体，其中 11 个按业务功能命名
   （btn-backup / btn-push / btn-test / btn-compare / btn-history / btn-edit …）。
   拆开看全是重复和错误语义：
     · btn-backup、btn-push 与 btn-primary 视觉完全相同（17 处重复定义）
     · btn-test 与 btn-compare 互相相同，且"测试/对比"并无危险后果，
       却用了警告橙——颜色应该编码"后果"，不是编码"功能"
     · btn-history 硬编码 #238636，绕过令牌
     · btn-edit 硬编码 rgba(0,113,227,…)，那是旧的 Apple 蓝，
       与当前 --primary(#0969da) 不是同一个颜色，于是"编辑"按钮和
       "主操作"按钮在同一屏里是两种蓝——这是最刺眼的不一致
   同一个"次要操作"在不同页面因为业务名不同而长得不一样，正是
   "按钮大小样式不统一"的根源。

   【新维度】层级 × 语义 × 尺寸，三者正交，组合覆盖全部场景：
     层级：primary（实心，一屏最多一个）/ secondary（默认）/ tertiary（纯文字）
     语义：danger / success / warning —— 只在需要传达后果时叠加，
           不用来区分功能。这是"克制"，也是高级感的主要来源。
     尺寸：默认 36px / .btn-sm / .btn-xs
   旧类名全部保留为别名，不需要改动 500+ 处调用点。
   ============================================================ */

/* ---- 层级 ---- */
.btn-tertiary {
    background: none;
    border-color: transparent;
    color: var(--primary);
}
.btn-tertiary:hover {
    background: color-mix(in srgb, var(--primary) 10%, transparent);
    color: var(--primary-hover);
}

/* ---- 语义（叠加在层级之上）---- */
.btn-danger { background: var(--error); color: #fff; border-color: transparent; }
.btn-danger:hover { filter: brightness(1.08); color: #fff; }
.btn-success { background: var(--success); color: #fff; border-color: transparent; }
.btn-success:hover { filter: brightness(1.08); color: #fff; }
.btn-warning { background: var(--warn); color: #fff; border-color: transparent; }
.btn-warning:hover { filter: brightness(1.08); color: #fff; }

/* ---- 旧类名 → 新体系的别名 ----
   保留是为了不动 500+ 处调用点；语义映射的取舍写在每行后面。 */
.btn-backup,
.btn-push { background: var(--primary); color: #fff; border-color: transparent; }   /* 与 primary 本就相同，去重 */
.btn-backup:hover,
.btn-push:hover { background: var(--primary-hover); color: #fff; }

/* 测试/对比/历史/编辑：都是无破坏性的常规操作，降级为 secondary。
   原来分别是橙、橙、绿、另一种蓝——四种颜色表达同一个权重，
   既没有信息量，也是廉价感的主要来源。 */
.btn-test,
.btn-compare,
.btn-history,
.btn-edit,
.btn-link { background: var(--bg-elevated); color: var(--text); border: 1px solid var(--border); }
.btn-test:hover,
.btn-compare:hover,
.btn-history:hover,
.btn-edit:hover,
.btn-link:hover { background: var(--bg-soft); border-color: var(--primary); color: var(--primary); }

.btn-delete { background: var(--error); color: #fff; border-color: transparent; }   /* 破坏性 → danger */
.btn-delete:hover { filter: brightness(1.08); }

/* 设备列表操作栏：每个按钮一种色调，不重复 */
.device-actions {
    display: flex;
    flex-wrap: nowrap;
    gap: var(--space-2);
    align-items: center;
}
/* 【操作列错位的根因】上面的 display:flex 直接套在 <td class="device-actions"> 上时，
   该单元格就不再是 table-cell —— 浏览器会在它外面再生成一个匿名单元格，于是这一列
   不参与表格的列宽计算，操作列与表头对不上。全站有十余处这么写（.col-actions-cell
   外包一层 div 才是正确写法），与其逐处改 JS，不如在这里把 td 拉回 table-cell，
   用 inline-flex 按钮 + 间距还原原来的排布效果。
   规则加在 .device-actions 之后，靠源序覆盖同特异度的 display 声明。 */
td.device-actions {
    display: table-cell;
    white-space: nowrap;
}
td.device-actions > .btn { vertical-align: middle; }
td.device-actions > .btn + .btn { margin-left: var(--space-2); }
/* 操作列全局规范：所有表格的操作列都套 .device-actions，内部任何按钮（含以后
   新增的）自动继承设备管理的尺寸+左色条风格；未标语义色时默认青色（次要操作） */
.device-actions .btn {
    min-height: 1.85rem;
    padding: var(--space-1) var(--space-4);
    font-size: var(--fs-sm);
    color: var(--text);
    border: 1px solid transparent;
    border-left-width: 3px;
    background: color-mix(in srgb, var(--act-neutral) 12%, transparent);
    border-left-color: var(--act-neutral);
}
.device-actions .btn:hover {
    background: color-mix(in srgb, var(--act-neutral) 22%, transparent);
    border-color: rgba(13, 148, 136, 0.35);
    color: var(--text);
}
.device-actions .btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}
/* 编辑 - 蓝 */
.device-actions .btn-edit {
    background: color-mix(in srgb, var(--act-primary) 12%, transparent);
    border-left-color: var(--act-primary);
}
.device-actions .btn-edit:hover {
    background: color-mix(in srgb, var(--act-primary) 22%, transparent);
    border-color: rgba(0, 113, 227, 0.35);
    color: var(--text);
}
/* 维护 - 青 */
.device-actions .btn-secondary {
    background: color-mix(in srgb, var(--act-neutral) 12%, transparent);
    border-left-color: var(--act-neutral);
}
.device-actions .btn-secondary:hover {
    background: color-mix(in srgb, var(--act-neutral) 22%, transparent);
    border-color: rgba(13, 148, 136, 0.35);
    color: var(--text);
}
/* 备份 - 绿 */
.device-actions .btn-backup {
    background: color-mix(in srgb, var(--act-success) 12%, transparent);
    border-left-color: var(--act-success);
}
.device-actions .btn-backup:hover {
    background: color-mix(in srgb, var(--act-success) 22%, transparent);
    border-color: rgba(46, 160, 67, 0.35);
    color: var(--text);
}
/* 历史备份 - 靛 */
.device-actions .btn-history {
    background: color-mix(in srgb, var(--act-info) 12%, transparent);
    border-left-color: var(--act-info);
}
.device-actions .btn-history:hover {
    background: color-mix(in srgb, var(--act-info) 22%, transparent);
    border-color: rgba(99, 102, 241, 0.35);
    color: var(--text);
}
/* 测试 - 橙 */
.device-actions .btn-test {
    background: rgba(245, 158, 11, 0.12);
    border-left-color: #f59e0b;
}
.device-actions .btn-test:hover {
    background: rgba(245, 158, 11, 0.2);
    border-color: rgba(245, 158, 11, 0.35);
    color: var(--text);
}
/* 对比配置 - 橙（与测试同色系） */
.device-actions .btn-compare {
    background: rgba(245, 158, 11, 0.12);
    border-left-color: #f59e0b;
}
.device-actions .btn-compare:hover {
    background: rgba(245, 158, 11, 0.2);
    border-color: rgba(245, 158, 11, 0.35);
    color: var(--text);
}
/* 登录 - 紫 */
.device-actions .btn-push {
    background: rgba(147, 51, 234, 0.12);
    border-left-color: #9333ea;
}
.device-actions .btn-push:hover {
    background: rgba(147, 51, 234, 0.2);
    border-color: rgba(147, 51, 234, 0.35);
    color: var(--text);
}
/* 删除 - 红 */
/* .btn-danger 一并收进来：操作列的语义色是按 .btn-delete/.btn-edit 这套类名
   定义的，写成全站通用的 .btn-danger 会落到默认的青色中性态——按钮看着像
   "次要操作"，破坏性动作却毫无警示。曾经三处这么写且一直没被发现，
   与其指望每次都用对类名，不如让这个别名也走红色。 */
.device-actions .btn-delete,
.device-actions .btn-danger {
    background: rgba(239, 68, 68, 0.12);
    border-left-color: #ef4444;
}
.device-actions .btn-danger:hover,
.device-actions .btn-delete:hover {
    background: rgba(239, 68, 68, 0.2);
    border-color: rgba(239, 68, 68, 0.4);
    color: var(--error);
}
/* 禁用/停用等软警示 - 琥珀 */
.device-actions .btn-danger-soft {
    background: rgba(245, 158, 11, 0.12);
    border-left-color: #f59e0b;
}
.device-actions .btn-danger-soft:hover {
    background: rgba(245, 158, 11, 0.2);
    border-color: rgba(245, 158, 11, 0.35);
    color: var(--text);
}
.input-with-eye { display: flex; align-items: center; gap: var(--space-1); }
.input-with-eye input { flex: 1; }
.btn-eye { padding: var(--space-2) var(--space-3); min-width: 2.2rem; background: var(--border); color: var(--text); border-radius: var(--control-radius); cursor: pointer; border: 1px solid var(--border); font-size: var(--fs-md); }
.btn-eye:hover { background: #3d4a5c; }
.devices-toolbar { margin-bottom: 0.5rem; display: flex; align-items: center; gap: var(--space-2); }
.devices-toolbar select { /* 控件样式由全局 input/select 基础规则统一 */ }
.col-check { width: 2.5rem; text-align: center; }
.col-actions { min-width: 320px; }
.table-resizable { overflow-x: auto; }
.table-resizable .resize-handle { cursor: col-resize; padding-left: 4px; user-select: none; opacity: 0.6; }
.table-resizable .resize-handle:hover { opacity: 1; }
.table-logs th { white-space: nowrap; min-width: 80px; }
.table-logs td { white-space: nowrap; }
.config-files-list { max-height: 60vh; overflow-y: auto; margin: var(--space-3) 0; }
.config-file-item { padding: var(--space-2) 0; border-bottom: 1px solid var(--border); }
.config-file-item a { color: var(--primary); }
/* 已备份配置：配置文件数为 0 的行高亮 */
.config-device-zero-files { background: rgba(248, 81, 73, 0.12) !important; }
.config-device-zero-files:hover { background: rgba(248, 81, 73, 0.18) !important; }
.hidden { display: none !important; }

/* 表格容器：完整展开，由页面整体滚动。
   【为什么不再用内层滚动】原来是 max-height: calc(100vh - 230px) + overflow-y:auto，
   实测每个列表容器都被压在 643px 而内容有 4000~5500px，于是页面里套着一个
   独立滚动区——两条滚动条、滚轮焦点还会在边界处卡住，是典型的反直觉交互。
   【顺带解决了吸顶】overflow-x:auto 会让容器在**两个轴**都变成滚动容器
   （CSS 规定一轴 auto、另一轴 visible 时，visible 计算为 auto），
   表头吸顶就只能相对这个容器生效。现在默认 overflow: visible，
   吸顶直接相对页面，偏移让开顶栏高度。
   真正超宽的表（实测 7 张表里只有邻居 2286px 超出）由 JS 打上
   .table-wrap--xscroll 单独开横向滚动，不牵连其余表格。 */
.table-wrap {
    overflow: visible;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--bg-card);
    box-shadow: var(--shadow);
    width: 100%;
}
/* 只有真正超宽的表才开横向滚动，由 JS 检测后加类（见 app.01.core.js） */
.table-wrap--xscroll { overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; }
.table th, .table td { padding: var(--space-4) var(--space-4); text-align: left; border-bottom: 1px solid var(--border); font-size: var(--fs-sm); }
/* 表头永不折行：CJK 允许字符间断行，表格被压缩时「状态/操作」会被掰成竖排 */
.table th { background: var(--bg-elevated); font-weight: 600; color: var(--text-muted); letter-spacing: -0.01em; vertical-align: middle; white-space: nowrap; }
/* 密度变体：字号仍是全局 --fs-sm，只收紧行高，供 IPAM 这类长列表在笔记本小屏上用 */
.table-compact th, .table-compact td { padding: var(--space-2) var(--space-3); }
.table-compact .device-actions { gap: var(--space-1); }
.table-compact .device-actions .btn { padding: var(--space-1) var(--space-3); min-height: 1.6rem; }
/* 数字列：等宽数字对齐（全站通用） */
.num { font-variant-numeric: tabular-nums; }
/* 表头吸顶：现在相对页面滚动生效，偏移让开顶栏。
   开了横向滚动的宽表格，其吸顶作用域是容器本身，偏移归零。 */
.table thead th { position: sticky; top: var(--app-header-h); z-index: 2; }
.table-wrap--xscroll .table thead th { top: 0; }

/* 表头列搜索：POP 名右侧一个放大镜，点击才弹出紧凑筛选框（宽度≈POP名长度） */
.th-filter { position: relative; display: inline-flex; align-items: center; gap: var(--space-1); }
.th-filter-label { cursor: pointer; }
.col-search-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 18px; height: 18px; padding: 0; border: 0; border-radius: var(--radius-xs);
    background: transparent; color: var(--text-muted); cursor: pointer; flex: 0 0 auto;
}
.col-search-toggle:hover { background: var(--border); color: var(--text); }
.col-search-toggle svg { width: 12px; height: 12px; }
.col-search-toggle.active { color: var(--primary); }
.col-search-input {
    display: none;
    position: absolute; top: calc(100% + 5px); left: 0; z-index: 6;
    width: 6.5em !important; min-width: 0 !important;
    min-height: 1.7rem !important;
    padding: 0.1rem 0.4rem !important;
    font-size: var(--fs-xs) !important; font-weight: 400;
    border-radius: var(--radius-sm) !important;
    background: var(--bg-card) !important;
    box-shadow: var(--shadow-card);
}
.th-filter.open .col-search-input { display: block; }
.col-search-input::-webkit-search-cancel-button { cursor: pointer; }
.table tbody tr { transition: background .15s ease; }
.table tbody tr:hover { background: var(--bg-elevated); }
/* 表格里"可点开下钻"的数字：看起来必须像可点的，否则没人会去点。
   用链接色 + 下划虚线而不是做成按钮——它在数值列里，按钮的边框会破坏数字对齐。 */
.btn-link-num {
    border: 0;
    background: none;
    padding: 0;
    font: inherit;
    font-variant-numeric: tabular-nums;
    color: var(--act-primary, #0a69da);
    cursor: pointer;
    border-bottom: 1px dashed currentColor;
}
.btn-link-num:hover { filter: brightness(1.15); }
/* 裸按钮：让单元格里的徽章（如级别）可点，但外观不变——不加边框/底色/内边距，
   只给指针和轻微悬停反馈，点上去像点徽章本身。 */
.btn-link-plain {
    border: 0; background: none; padding: 0; font: inherit; color: inherit;
    cursor: pointer; display: inline-flex; align-items: center;
}
.btn-link-plain:hover { filter: brightness(1.12); }
/* 整行可点：光标与悬停底色一起给，只给其中一个都会让人不确定能不能点 */
.table tbody tr.row-clickable { cursor: pointer; }
.table tbody tr.row-clickable:hover { background: var(--bg-elevated); }

/* 状态词是两到三个字的固定短语，断行后（「已启」/「用」）读起来像残缺文本。
   表格列宽由内容竞争决定，状态列很容易被同行的长文本挤窄，所以在这里直接
   禁止断行——状态列本来就该按内容宽度占位。 */
.table .status-ok,
.table .status-fail,
.table .status-muted { white-space: nowrap; }
.table .status-ok { color: var(--success); }
.table .status-fail { color: var(--error); }
.table .status-muted { color: var(--text-muted); }
/* 合规标签：统一状态 pill 配方（此前无样式规则，颜色只在 .table 作用域下生效） */
.compliance-tag {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 38px;
    padding: 0.12rem 0.5rem;
    border-radius: var(--radius-pill);
    font-size: var(--fs-xs);
    font-weight: 600;
    white-space: nowrap;
}
.compliance-tag.status-ok { color: #39d98a; background: rgba(34, 197, 94, 0.14); }
.compliance-tag.status-warn { color: #f59e0b; background: rgba(245, 158, 11, 0.16); }
.compliance-tag.status-fail { color: #ff6b6b; background: rgba(239, 68, 68, 0.16); }
.compliance-tag.status-muted { color: var(--text-muted); background: rgba(148, 163, 184, 0.14); }

/* 多云纳管：账号表 */
.cloud-table { table-layout: fixed; min-width: 940px; }
/* 彻底防外溢：固定表格布局 + 每个单元格裁剪并省略号；嵌套的两行/等宽/省略容器一律收窄到列宽内 */
.cloud-table th, .cloud-table td { vertical-align: middle; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cloud-table td > * { max-width: 100%; }
.cloud-table .cloud-ellip { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* cloud-ellip 直接用在 <td> 上时不能变 block（会破坏表格列对齐）；保持 table-cell，靠 td 自身裁剪省略号 */
.cloud-table td.cloud-ellip { display: table-cell; }
.cloud-table .cloud-2l { display: flex; flex-direction: column; min-width: 0; max-width: 100%; }
.cloud-table .cloud-2l > * { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.cloud-table .mono { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cloud-ak { display: inline-block; max-width: 184px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: middle; color: var(--text-muted); }
.cloud-dim { color: var(--text-muted); }
.cloud-err { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; margin-left: 4px; border-radius: 50%; background: rgba(239, 68, 68, 0.16); color: #ff6b6b; font-size: var(--fs-2xs); font-weight: 600; cursor: help; }
.cloud-prov { display: inline-flex; align-items: center; padding: 0.12rem 0.5rem; border-radius: var(--radius-sm); font-size: var(--fs-xs); font-weight: 600; white-space: nowrap; }
/* 云商识别徽标：与 app.14.cloud.js 的 PROV_COLOR 用同一套调和色。
   此前两处各存一份原始品牌色（这里是 CSS 徽标、那里是图表），
   饱和度从 45% 到 100% 不等，一屏摆开就是"花"。
   现在只让**色相**承载"这是哪家云"，饱和度与明度锁在同一窄带（S≈40%、L≈52%），
   并且底色只用 10% 透明度做浅色块，不再是高饱和实色。
   多色系统显得高级的关键就在这里：统一 L/S，只让 H 携带信息。 */
.cloud-prov-aliyun   { color: hsl(28 52% 46%);  background: hsl(28 52% 52% / .10); }
.cloud-prov-huawei   { color: hsl(0 46% 50%);   background: hsl(0 46% 56% / .10); }
.cloud-prov-tencent  { color: hsl(214 48% 48%); background: hsl(214 48% 54% / .10); }
.cloud-prov-volcano  { color: hsl(188 42% 40%); background: hsl(188 42% 46% / .10); }
.cloud-prov-aws      { color: hsl(268 38% 52%); background: hsl(268 38% 58% / .10); }
.cloud-prov-azure    { color: hsl(330 40% 52%); background: hsl(330 40% 58% / .10); }
.cloud-prov-gcp      { color: hsl(145 36% 40%); background: hsl(145 36% 46% / .10); }
.cloud-prov-equinix  { color: hsl(10 44% 46%);  background: hsl(10 44% 52% / .10); }
.cloud-prov-megaport { color: hsl(42 50% 40%);  background: hsl(42 50% 48% / .10); }
.cl-hit:hover { fill: rgba(120, 150, 200, 0.10) !important; }
.cloud-inline-check { display: inline-flex; align-items: center; gap: var(--space-3); cursor: pointer; }
.cloud-inline-check input { width: auto; margin: 0; }
.cloud-link { color: var(--accent); font-weight: 600; }
.cloud-layout { display: grid; grid-template-columns: 150px 1fr; gap: var(--space-5); align-items: start; }
.cloud-layout .rack-main-area { min-width: 0; }
.cloud-navbadge { display: inline-block; min-width: 18px; padding: 0 var(--space-1); margin-left: 4px; border-radius: var(--radius-md); background: var(--border); color: var(--text-muted); font-size: var(--fs-xs); font-weight: 600; text-align: center; }
.rack-nav-btn.active .cloud-navbadge { background: rgba(255,255,255,.25); color: #fff; }
/* 概览统计卡 */
.cloud-stats { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--space-4); margin-bottom: 1rem; }
.cloud-stat { border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-card); padding: var(--space-4) var(--space-5); }
.cloud-stat-val { font-size: 22px; font-weight: 600; line-height: var(--lh-display); letter-spacing: -0.02em; }
.cloud-stat-lbl { color: var(--text-muted); font-size: var(--fs-sm); margin-top: 0.25rem; }
.cloud-stat-sub { color: var(--text-muted); font-size: var(--fs-xs); margin-top: 0.15rem; }
.cloud-card { border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-card); padding: var(--space-5) var(--space-5); margin-bottom: 1rem; }
.cloud-card-h { font-weight: 600; margin-bottom: 0.7rem; }
/* 余额卡（各云商可用余额） */
.cloud-bals { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: var(--space-4); margin-bottom: 1rem; }
.cloud-bal { border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-card); padding: var(--space-4) var(--space-5); display: flex; flex-direction: column; gap: var(--space-2); }
.cloud-bal.total { border-color: var(--accent); }
.cloud-bal-hd { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
.cloud-bal-lbl { color: var(--text-muted); font-size: var(--fs-sm); font-weight: 600; }
.cloud-bal-val { font-size: var(--fs-2xl); font-weight: 600; letter-spacing: -0.02em; line-height: var(--lh-display); }
.cloud-bal-val .cur { font-size: var(--fs-base); font-weight: 600; color: var(--text-muted); margin-right: 2px; }
.cloud-bal-val.neg { color: var(--danger, #dc2626); }
.cloud-bal-val.neg .cur { color: var(--danger, #dc2626); opacity: 0.85; }
.cloud-bal.cloud-bal-neg { border-color: rgba(220, 38, 38, 0.35); }
.cloud-bal-sub { color: var(--text-muted); font-size: var(--fs-xs); }
/* 趋势图（柱状） */
.cloud-chart-wrap { width: 100%; overflow-x: auto; }
.cloud-chart { width: 100%; height: auto; }
.cloud-chart { display: block; }
.cloud-chart rect:not(.cl-hit) { fill-opacity: 0.78; }   /* 柱子降饱和：不那么鲜艳、更柔和 */
.cloud-chart .cl-grid { stroke: var(--border); stroke-width: 0.6; opacity: 0.5; }
.cloud-chart .cl-axis { fill: var(--text-muted); font-size: 7px; }
.cloud-chart .cl-tot { fill: var(--text); font-size: 6px; font-weight: 600; letter-spacing: -0.02em; }
.cloud-chart .cl-xlbl { fill: var(--text-muted); font-size: 7px; }
.cl-legend { display: flex; flex-wrap: wrap; gap: var(--space-5); margin-top: 0.5rem; }
.cl-leg { display: inline-flex; align-items: center; gap: var(--space-1); font-size: var(--fs-sm); color: var(--text-muted); }
.cl-leg i { width: 12px; height: 12px; border-radius: var(--radius-xs); display: inline-block; }
/* 各云商费用概览：固定两列 */
.cloud-cost-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-5); margin-bottom: 1rem; }
@media (max-width: 900px) { .cloud-cost-grid { grid-template-columns: 1fr; } }
.cloud-chart .cl-barlbl { fill: var(--text-muted); font-size: 6px; font-weight: 600; }
/* 列表工具栏（搜索 + 过滤下拉） */
.cloud-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin-bottom: 0.75rem; }
/* 搜索框与过滤下拉尺寸保持一致（高度、字号、盒模型统一） */
.cloud-toolbar #cloud-filters { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.cloud-search, .cloud-flt { height: var(--control-h); box-sizing: border-box; font-size: var(--fs-sm); line-height: 1.4; padding: 0 var(--space-3); }
.cloud-search { min-width: 240px; flex: 0 0 auto; }
.cloud-flt { max-width: 220px; min-width: 130px; }
.cloud-row-click { cursor: pointer; }
.cloud-row-click:hover td { background: rgba(255, 255, 255, 0.04); }
/* 可排序表头 */
/* ============================================================
   全站统一的可排序表头（基准 = 云主机表）
   点击表头即排序；只有当前排序列显示 ▲/▼；hover 变主色。
   四套旧写法（cloud-th-sort / device-sort-btn / sla-sortable / th-sortable）
   全部并到这一套，别再新增第五套。
   ============================================================ */
th.th-sort, .cloud-table th.cloud-th-sort, th.sla-sortable, th.th-sortable {
    cursor: pointer; user-select: none; white-space: nowrap;
}
th.th-sort:hover, .cloud-table th.cloud-th-sort:hover,
th.sla-sortable:hover, th.th-sortable:hover { color: var(--accent); }
th.th-sort.sorted, th.sla-sortable.sorted, th.th-sortable.sorted { color: var(--accent); }
.th-sort-ar, .cloud-sort-ar, .sla-sort-ind, .th-sort-ind {
    font-size: 10px; color: var(--accent); margin-left: 0.2rem;
}
/* 分页条 */
.cloud-pager { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); margin-top: 0.7rem; flex-wrap: wrap; }
.cloud-pg-btns { display: inline-flex; gap: var(--space-1); }
.cloud-pg-btns .btn { min-width: 30px; padding: var(--space-1) var(--space-3); }
.cloud-cost-grid .cloud-card { margin-bottom: 0; }
.cloud-cost-h { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-bottom: 0.5rem; }
.cloud-cost-bal { font-weight: 600; font-size: var(--fs-lg); }
.cloud-cost-bal .cur { font-size: var(--fs-sm); color: var(--text-muted); font-weight: 600; }
/* 两行单元格 */
.cloud-2l { display: flex; flex-direction: column; line-height: 1.35; }
.cloud-2l .cloud-sub, .cloud-sub { color: var(--text-muted); font-size: var(--fs-xs); }
/* 详情 */
.cloud-detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--space-5); margin-bottom: 1rem; }
.cloud-kv { display: flex; justify-content: space-between; gap: var(--space-5); padding: var(--space-2) 0; border-bottom: 1px dashed var(--border); font-size: var(--fs-sm); }
.cloud-kv:last-child { border-bottom: none; }
.cloud-kv-k { color: var(--text-muted); flex: 0 0 auto; }
.cloud-kv-v { text-align: right; word-break: break-all; }
.cloud-ops { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-bottom: 1rem; }
.cloud-modal-mask { position: fixed; inset: 0; background: rgba(0,0,0,.55); display: flex; align-items: center; justify-content: center; z-index: 9999; }
.cloud-modal { width: 460px; max-width: 92vw; background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; }
.cloud-modal-h { padding: var(--space-4) var(--space-5); font-weight: 600; border-bottom: 1px solid var(--border); }
.cloud-modal-b { padding: var(--space-5) var(--space-5); }
.cloud-modal-f { padding: var(--space-4) var(--space-5); display: flex; justify-content: flex-end; gap: var(--space-3); border-top: 1px solid var(--border); }
.cloud-head-actions { display: inline-flex; align-items: center; gap: var(--space-3); }
.cloud-sched-label { color: var(--text-muted); font-size: var(--fs-sm); }
.cloud-sched-sel { min-width: 96px; }

.resource-section {
    margin-top: 1rem;
    font-size: var(--fs-sm);
    width: 100%;
}
.resource-section-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-5);
    margin-bottom: 0.75rem;
}
.resource-section-header .dashboard-card-title {
    margin-bottom: 0.35rem;
}
.resource-detail-header .btn {
    margin-bottom: 0.9rem;
}
.resource-summary-toolbar {
    margin-bottom: 0.75rem;
}
.resource-summary-toolbar input[type="text"] {
    width: min(360px, 100%);
}
.resource-summary-table th,
.resource-summary-table td {
    white-space: nowrap;
    font-size: var(--fs-sm);
    padding: var(--space-3) var(--space-4);
}
.resource-summary-table td:first-child {
    font-weight: 600;
}
.resource-summary-row {
    cursor: pointer;
}
.resource-gateway-link {
    appearance: none;
    border: 0;
    background: none;
    color: var(--primary);
    cursor: pointer;
    font: inherit;
    font-weight: 600;
    padding: 0;
    text-align: left;
}
.resource-gateway-link:hover {
    text-decoration: underline;
}
.resource-filters {
    margin-bottom: 0.75rem;
    align-items: stretch;
}
.resource-filters input[type="text"] {
    width: auto;
    min-width: 150px;
    flex: 1 1 170px;
}
.resource-filters .btn {
    min-width: 72px;
}
.resource-global-form {
    display: grid;
    grid-template-columns: repeat(4, minmax(180px, 1fr));
    gap: var(--space-4) var(--space-5);
    margin-bottom: 0.75rem;
}
.resource-global-form label {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 0;
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--text-muted);
}
.resource-global-form input { width: 100%; }
.resource-global-actions {
    display: flex;
    gap: var(--space-3);
    margin: var(--space-1) 0 var(--space-4);
}
.resource-detail-table-wrap {
    max-width: 100%;
}
.resource-detail-table,
.resource-global-table {
    table-layout: fixed;
}
.resource-detail-table { min-width: 1280px; }
.resource-global-table { min-width: 1420px; }
.resource-detail-table th,
.resource-detail-table td,
.resource-global-table th,
.resource-global-table td {
    font-size: var(--fs-xs);
    padding: var(--space-3) var(--space-4);
    vertical-align: top;
    line-height: 1.38;
}
.resource-detail-table th:nth-child(1),
.resource-detail-table td:nth-child(1) { width: 150px; }
.resource-detail-table th:nth-child(2),
.resource-detail-table td:nth-child(2) { width: 260px; }
.resource-detail-table th:nth-child(3),
.resource-detail-table td:nth-child(3) { width: 120px; }
.resource-detail-table th:nth-child(4),
.resource-detail-table td:nth-child(4),
.resource-detail-table th:nth-child(5),
.resource-detail-table td:nth-child(5) { width: 130px; }
.resource-detail-table th:nth-child(6),
.resource-detail-table td:nth-child(6) { width: 72px; }
.resource-detail-table th:nth-child(7),
.resource-detail-table td:nth-child(7) { width: 120px; }
.resource-detail-table th:nth-child(8),
.resource-detail-table td:nth-child(8) { width: 160px; }
.resource-detail-table th:nth-child(9),
.resource-detail-table td:nth-child(9) { width: 240px; }
.resource-detail-table th:nth-child(10),
.resource-detail-table td:nth-child(10) { width: 190px; }
.resource-detail-table td {
    overflow-wrap: anywhere;
    word-break: break-word;
}
.resource-global-table th:nth-child(1),
.resource-global-table td:nth-child(1) { width: 130px; }
.resource-global-table th:nth-child(2),
.resource-global-table td:nth-child(2) { width: 150px; }
.resource-global-table th:nth-child(3),
.resource-global-table td:nth-child(3) { width: 250px; }
.resource-global-table th:nth-child(4),
.resource-global-table td:nth-child(4) { width: 120px; }
.resource-global-table th:nth-child(5),
.resource-global-table td:nth-child(5),
.resource-global-table th:nth-child(6),
.resource-global-table td:nth-child(6) { width: 130px; }
.resource-global-table th:nth-child(7),
.resource-global-table td:nth-child(7) { width: 72px; }
.resource-global-table th:nth-child(8),
.resource-global-table td:nth-child(8) { width: 110px; }
.resource-global-table th:nth-child(9),
.resource-global-table td:nth-child(9) { width: 90px; }
.resource-global-table th:nth-child(10),
.resource-global-table td:nth-child(10) { width: 220px; }
.resource-global-table th:nth-child(11),
.resource-global-table td:nth-child(11) { width: 180px; }
.resource-global-table td {
    overflow-wrap: anywhere;
    word-break: break-word;
}
.neighbor-filters {
    margin-bottom: 0.75rem;
    align-items: stretch;
    /* 【曾经的坑】这里原本是写死 11 列宽度的 grid：
           grid-template-columns: 96px 96px 120px 130px 108px 96px 116px minmax(180px,280px) 64px 64px 94px;
       任何增删子元素、或用 order 调整顺序，都会让每个控件落进错误的列宽——
       实际发生过：给筛选栏统一加 order 后，"重置"落进了本该给搜索框的宽列，
       搜索框反而挤进 64px 的窄列，两者大小看起来是反的。
       写死列宽的栅格对"以后还会加筛选项"的界面是不成立的假设，改为 flex。 */
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
}
.neighbor-filters input[type="text"],
.neighbor-filters select {
    /* 原来是 width:100%——在 grid 里等于"占满所在列"，换成 flex 后却变成
       "占满整个容器"，于是每个下拉都被撑到 1600 多像素。
       改为按内容自适应、给个下限，与全站其它筛选栏一致。 */
    width: auto;
    flex: 0 0 auto;
    min-width: 7rem;
    white-space: nowrap;
}
.neighbor-filters .neighbor-source-filter {
    width: 96px;
}
.neighbor-filters .btn {
    white-space: nowrap;
}
.neighbor-filter-shortcuts {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin: -0.25rem 0 0.75rem;
    padding: 0 var(--space-1);
}
.neighbor-filter-shortcuts.hidden {
    display: none;
}
.neighbor-filter-shortcuts-label {
    color: var(--text-muted);
    font-size: var(--fs-xs);
    margin-right: 0.1rem;
}
.neighbor-filter-shortcut {
    display: inline-flex;
    align-items: center;
    max-width: 260px;
    border: 1px solid var(--border);
    border-radius: var(--control-radius);
    background: var(--bg-soft);
    overflow: hidden;
}
.neighbor-filter-shortcut-apply,
.neighbor-filter-shortcut-delete {
    border: 0;
    background: transparent;
    color: var(--text);
    font-size: var(--fs-xs);
    line-height: var(--lh-single);
    cursor: pointer;
}
.neighbor-filter-shortcut-apply {
    min-width: 0;
    padding: var(--space-3) var(--space-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.neighbor-filter-shortcut-delete {
    padding: var(--space-3) var(--space-3);
    border-left: 1px solid var(--border);
    color: var(--text-muted);
}
.neighbor-filter-shortcut-apply:hover,
.neighbor-filter-shortcut-delete:hover {
    background: var(--bg-hover, rgba(255,255,255,.05));
    color: var(--primary);
}
.neighbor-table {
    min-width: max-content;
    table-layout: auto;
}
.neighbor-table th,
.neighbor-table td {
    font-size: var(--fs-xs);
    padding: var(--space-2) var(--space-3);
    vertical-align: middle;
    line-height: 1.25;
    white-space: nowrap;
    overflow-wrap: normal;
    word-break: normal;
}
/* 邻居表格内所有可点文字（POP/设备/接口/AS 链接）：与普通单元格完全同款，
   仅悬停时变主色+下划线提示可点击，避免一个表出现多种字体样式 */
.neighbor-pop-link,
.neighbor-device-link,
.neighbor-interface-link,
.as-lookup-link {
    border: 0;
    padding: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    font-weight: inherit;
    text-decoration: none;
    cursor: pointer;
}
.neighbor-pop-link:hover,
.neighbor-device-link:hover,
.neighbor-interface-link:hover:not(:disabled),
.as-lookup-link:hover {
    color: var(--primary);
    background: transparent;
    text-decoration: underline;
}
.neighbor-interface-link:disabled {
    color: inherit;
    cursor: default;
}
.neighbor-table th[data-neighbor-sort] {
    cursor: pointer;
    user-select: none;
}
.neighbor-table th[data-neighbor-sort].sorted::after {
    margin-left: 0.25rem;
    font-size: var(--fs-2xs);
    color: var(--accent);
}
.neighbor-table th[data-neighbor-sort].sorted[data-sort-dir="asc"]::after { content: "▲"; }
.neighbor-table th[data-neighbor-sort].sorted[data-sort-dir="desc"]::after { content: "▼"; }
.neighbor-table td.metric-mismatch {
    color: #ffd166;
    background: rgba(245, 158, 11, 0.16);
    font-weight: 600;
}
.neighbor-actions-cell {
    white-space: nowrap;
}
.neighbor-edit-grid {
    margin-bottom: 1rem;
}
.neighbor-table tr.state-down td {
    background: rgba(239, 68, 68, 0.08);
}
/* ===== 全站统一状态 pill 配方 =====
   .state-pill 为通用类（新代码使用）；neighbor-state-pill / inv-status-pill /
   latency-link 等历史类名映射到同一配方，保证各页面状态类样式一致。 */
.state-pill,
.neighbor-state-pill,
.inv-status-pill,
.latency-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 38px;
    padding: 0.12rem 0.5rem;
    border-radius: var(--radius-pill);
    font-size: var(--fs-xs);
    font-weight: 600;
    white-space: nowrap;
}
.state-pill.up,
.neighbor-state-pill.state-up,
.inv-status-pill.up,
.latency-link.latency-ok {
    color: #39d98a;
    background: rgba(34, 197, 94, 0.14);
}
.state-pill.down,
.neighbor-state-pill.state-down,
.latency-link.latency-bad {
    color: #ff6b6b;
    background: rgba(239, 68, 68, 0.16);
}
.state-pill.warn {
    color: #f59e0b;
    background: rgba(245, 158, 11, 0.16);
}
.state-pill.muted,
.latency-link.latency-empty {
    color: var(--text-muted);
    background: rgba(148, 163, 184, 0.14);
}
/* 时延 pill 是可点击按钮（打开时延历史），保留按钮特性与悬停提亮 */
.latency-link {
    border: 0;
    cursor: pointer;
}
.latency-link:hover {
    filter: brightness(1.2);
}
.latency-modal canvas {
    width: 100%;
    height: auto;
    border-radius: var(--radius-lg);
    border: 1px solid var(--border);
    background: var(--bg-card);
}
.latency-history-ping {
    color: #39d98a;
    font-weight: 600;
}
#latency-history-subtitle {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-5);
}
.latency-chart-summary-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: 0.4rem;
}
.latency-modal-tools {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    min-width: 130px;
}
.filter-check {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
    color: var(--text);
    font-size: var(--fs-sm);
    font-weight: 600;
    white-space: nowrap;
}
.filter-check input {
    width: 16px;
    height: 16px;
    accent-color: var(--accent);
}
.latency-timebar {
    margin: 0 0 var(--space-4);
}
.neighbor-traffic-modal {
    width: min(1000px, 94vw);
    max-width: 1000px;
}
/* 标题与图内标题统一，其余（副标题/链路信息/时间按钮/图例/提示）保持紧凑 */
.neighbor-traffic-modal h3 {
    max-width: min(820px, 62vw);
    margin: 0;
    font-size: var(--fs-xs);
    line-height: var(--lh-tight);
    font-weight: 600;
}
.neighbor-traffic-modal .form-hint,
.neighbor-traffic-modal .neighbor-traffic-info,
.neighbor-traffic-modal .neighbor-traffic-info .ntl-item,
.neighbor-traffic-modal .neighbor-traffic-ranges .btn,
.neighbor-traffic-modal .traffic-chart-stats,
.neighbor-traffic-modal .traffic-chart-stats *,
.neighbor-traffic-modal .traffic-chart-hint {
    font-size: 10px;
}
.ntl-latency-btn {
    border: 0;
    border-radius: var(--radius-md);
    padding: var(--space-1) var(--space-4);
    background: #67e8f9;
    color: #062235;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
.ntl-latency-btn:hover {
    filter: brightness(1.08);
}
.neighbor-traffic-body {
    min-height: 0;
}
.neighbor-traffic-frame {
    width: 100%;
    min-height: 620px;
    border: 0;
    border-radius: var(--radius-lg);
    background: var(--bg-card);
}
#topology-link-neighbor-search {
    margin-bottom: 0.4rem;
}
#topology-link-neighbor-id {
    min-height: 2.35rem;
}
.modal-header-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-5);
    margin-bottom: 0.75rem;
}
.range-tabs {
    display: flex;
    gap: var(--space-2);
    flex-wrap: wrap;
}
.range-tabs .active {
    background: var(--primary);
    color: #fff;
}
.latency-chart-summary {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3) var(--space-5);
    margin: var(--space-4) 0;
    color: var(--text-muted);
    font-size: var(--fs-sm);
}
.latency-chart-summary b {
    color: var(--text);
}
.form-grid-compact {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--space-4);
    margin: var(--space-4) 0 var(--space-5);
}
.form-grid-compact label {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    font-size: var(--fs-sm);
    color: var(--text-muted);
}
.form-grid-compact .checkbox-block {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    min-height: 2.5rem;
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg);
}
.form-grid-compact input,
.form-grid-compact select {
    width: 100%;
}
.form-grid-compact input[type="checkbox"] {
    width: 16px;
    height: 16px;
    min-height: 0;
}

.checkbox-inline {
    display: inline-flex !important;
    align-items: center;
    gap: var(--space-3);
    width: auto;
    margin: 0;
}

.checkbox-inline input[type="checkbox"],
#panel-settings input[type="checkbox"],
#panel-devices input[type="checkbox"] {
    width: 16px !important;
    height: 16px;
    min-height: 0;
    margin: 0;
    flex: 0 0 auto;
}

.checkbox-inline span {
    line-height: 1.4;
}

@media (max-width: 900px) {
    #panel-neighbors .stats-cards {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .resource-section-header {
        flex-direction: column;
    }
    .resource-filters input[type="text"],
    .resource-filters .btn {
        flex-basis: 100%;
        width: 100%;
    }
    .resource-global-form {
        grid-template-columns: 1fr;
    }
    .resource-global-actions {
        flex-direction: column;
    }
    .neighbor-filters {
        grid-template-columns: 1fr;
    }
    .traffic-grid,
    .traffic-filters,
    .traffic-graph-list-filters,
    .traffic-graph-toolbar,
    .traffic-graph-layout {
        grid-template-columns: 1fr;
    }
    .traffic-graph-list {
        grid-template-columns: 1fr !important;
    }
    .traffic-side-list {
        height: auto;
        max-height: 360px;
        min-height: 0;
    }
}

@media (max-width: 560px) {
    #panel-neighbors .stats-cards {
        grid-template-columns: 1fr;
    }
    #panel-neighbors .stat-card {
        min-height: auto;
    }
}

/* 设备类型管理表：字号与内边距与整体协调，操作列加宽并禁止换行 */
#device-type-table th,
#device-type-table td {
    font-size: var(--fs-sm);
    padding: var(--space-3) var(--space-4);
}
#device-type-table th:last-child,
#device-type-table td:last-child {
    white-space: nowrap;
    width: 1%;
}


/* 设备列表列头排序按钮 */
/* 设备列表原来是常驻 ▲▼ 双三角，与全站基准不一致 → 收敛为单箭头。
   保留类名是因为模板里几十处在用，改类名不如改样式。 */
.device-sort-btn {
    display: inline-block;
    margin-left: 0.2rem;
    font-size: 10px;
    color: var(--accent);
    cursor: pointer;
    user-select: none;
}
.device-sort-btn .sort-tri { display: none; }          /* 默认两个三角都不显 */
.device-sort-btn.dir-asc .sort-tri-up { display: inline; }
.device-sort-btn.dir-desc .sort-tri-down { display: inline; }
.device-sort-btn.active { color: var(--accent); }


/* 已备份配置列表排序按钮（样式与设备管理一致） */
.config-device-sort-btn {
    display: inline-block;
    margin-left: 0.2rem;
    font-size: 10px;
    color: var(--accent);
    cursor: pointer;
    user-select: none;
}
.config-device-sort-btn .sort-tri { display: none; }
.config-device-sort-btn.dir-asc .sort-tri-up { display: inline; }
.config-device-sort-btn.dir-desc .sort-tri-down { display: inline; }
.config-device-sort-btn.active { color: var(--accent); }

/* 备份日志表排序按钮 */
.log-sort-btn {
    display: inline-block;
    margin-left: 0.2rem;
    font-size: 10px;
    color: var(--accent);
    cursor: pointer;
    user-select: none;
}
.log-sort-btn .sort-tri { display: none; }
.log-sort-btn.dir-asc .sort-tri-up { display: inline; }
.log-sort-btn.dir-desc .sort-tri-down { display: inline; }
.log-sort-btn.active { color: var(--accent); }

.status-box {
    padding: var(--space-5);
    background: var(--bg-card);
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
}

/* 备份任务进度条 */
.backup-progress-wrap {
    padding: var(--space-5) var(--space-6);
    background: linear-gradient(135deg, var(--bg-card) 0%, var(--bg-elevated) 100%);
    border-radius: var(--radius-lg);
    border: 1px solid var(--border);
    box-shadow: 0 2px 12px rgba(0,0,0,.06), inset 0 1px 0 rgba(255,255,255,.04);
}
.backup-progress-bar {
    position: relative;
    height: 12px;
    background: var(--bg);
    border-radius: var(--radius-pill);
    overflow: hidden;
    box-shadow: inset 0 1px 3px rgba(0,0,0,.12);
}
.backup-progress-fill {
    height: 100%;
    min-width: 0;
    max-width: 100%;
    border-radius: var(--radius-pill);
    background: linear-gradient(90deg, #00b5ff 0%, #00d4aa 50%, #22c55e 100%);
    background-size: 200% 100%;
    transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1);
    position: relative;
    z-index: 1;
}
.backup-progress-wrap.running .backup-progress-fill {
    animation: backup-progress-glow 2s ease-in-out infinite;
}
.backup-progress-wrap.idle .backup-progress-fill {
    background: var(--border);
}
.backup-progress-wrap.completed .backup-progress-fill {
    background: linear-gradient(90deg, #22c55e 0%, #16a34a 100%);
}
@keyframes backup-progress-glow {
    0%, 100% { opacity: 1; filter: brightness(1); }
    50% { opacity: 0.9; filter: brightness(1.15); }
}
.backup-progress-shine {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 50%;
    background: linear-gradient(180deg, rgba(255,255,255,.25) 0%, transparent 100%);
    border-radius: var(--radius-pill) var(--radius-pill) 0 0;
    pointer-events: none;
}
.backup-progress-info {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 0.5rem;
    font-size: var(--fs-sm);
    color: var(--text-muted);
}
.backup-progress-pct {
    font-weight: 600;
    color: var(--primary);
    font-variant-numeric: tabular-nums;
}
.backup-progress-wrap.completed .backup-progress-pct { color: var(--success); }

.form { max-width: 400px; }
.form-row { margin-bottom: 1rem; }
.form-h4 { font-size: var(--fs-md); font-weight: 600; margin: var(--space-7) 0 var(--space-4); color: var(--text); }
.form-row-sub { margin-top: 0.5rem; margin-left: 0; padding-left: 0; }
.alert-rules-grid { display: flex; flex-direction: column; gap: var(--space-4); }
.alert-rule-row { display: flex; align-items: center; gap: var(--space-5); flex-wrap: wrap; }
.alert-rule-row .alert-rule-label { min-width: 140px; font-weight: 500; line-height: 1.4; }
.alert-rule-row label { display: inline-flex; align-items: center; gap: var(--space-2); margin: 0; line-height: 1.2; }
.alert-rule-row input[type="checkbox"] {
    width: 14px;
    height: 14px;
    margin: 0;
    flex-shrink: 0;
}
.alert-rule-row label span {
    position: relative;
    top: -13px;
}
.form-row label { display: block; margin-bottom: 0.3rem; font-size: var(--fs-base); color: var(--text-muted); }
.form-row input, .form-row select { width: 100%; }
/* select 外观统一走自绘箭头（见「表单控件统一规范」） */
.form-hint { display: block; margin-top: 0.25rem; font-size: var(--fs-sm); color: var(--text-muted); }
/* 行内弱化文本：.form-hint 是 display:block，用在一行文字中间会强制断行
   （权限概要的「不可见 N」、标题后的「· N 个用户」都栽在这上面）。
   需要跟在同一行里的弱化文字一律用这个。 */
.text-muted-inline { display: inline; font-size: var(--fs-sm); color: var(--text-muted); }
/* 云账号标签：色相由标签名哈希决定，同一标签处处同色，便于扫读 */
/* 可双击复制的列：给一点视觉暗示，否则没人知道能双击 */
table.table thead th[data-copy-col]::after { content: ' ⧉'; font-size: 0.8em; opacity: 0.45; }
table.table thead th[data-copy-col] { cursor: default; }

/* 一键复制：按钮平时隐形，悬停/聚焦才显形，避免每格都挂个图标喧宾夺主 */
.copy-wrap { display: inline-flex; align-items: center; gap: var(--space-1); max-width: 100%; }
.copy-btn {
    flex: 0 0 auto; border: 0; background: transparent; cursor: pointer; padding: 0 var(--space-1);
    color: var(--text-muted); font-size: 0.9em; line-height: var(--lh-single); opacity: 0;
    transition: opacity .12s;
}
td:hover .copy-btn, tr:hover .copy-btn, .copy-wrap:hover .copy-btn, .copy-btn:focus-visible { opacity: 1; }
/* 详情弹窗/非表格场景：悬停所在行或直接悬停值本身都显形 */
.modal .copy-wrap:hover .copy-btn, .cloud-kv:hover .copy-btn { opacity: 1; }
.copy-btn:hover { color: var(--accent, #2563eb); }
.copy-btn:focus-visible { outline: 2px solid var(--accent, #2563eb); outline-offset: 1px; }
/* IP 明细文本框：等宽、可直接全选 */
.eip-list-box {
    width: 100%; font-family: var(--font-mono); font-size: var(--fs-sm);
    resize: vertical; margin-top: 0.5rem;
}
.cloud-tag {
    display: inline-block; margin: 1px 3px 1px 0; padding: 0 var(--space-2);
    border-radius: var(--radius-xs); font-size: var(--fs-2xs, 0.72rem); line-height: 1.6;
    white-space: nowrap;
    color: hsl(var(--tag-h, 210) 70% 32%);
    background: hsl(var(--tag-h, 210) 70% 92%);
    border: 1px solid hsl(var(--tag-h, 210) 60% 82%);
}
@media (prefers-color-scheme: dark) {
    .cloud-tag { color: hsl(var(--tag-h, 210) 70% 78%); background: hsl(var(--tag-h, 210) 40% 20%); border-color: hsl(var(--tag-h, 210) 40% 32%); }
}
:root[data-theme="dark"] .cloud-tag { color: hsl(var(--tag-h, 210) 70% 78%); background: hsl(var(--tag-h, 210) 40% 20%); border-color: hsl(var(--tag-h, 210) 40% 32%); }
:root[data-theme="light"] .cloud-tag { color: hsl(var(--tag-h, 210) 70% 32%); background: hsl(var(--tag-h, 210) 70% 92%); border-color: hsl(var(--tag-h, 210) 60% 82%); }

.device-group-tags { display: flex; flex-wrap: wrap; gap: var(--space-2); min-height: 1.5rem; }
.device-group-tag { display: inline-flex; align-items: center; gap: var(--space-1); padding: var(--space-1) var(--space-3); background: var(--bg-secondary); border-radius: var(--radius-xs); font-size: var(--fs-base); }
.device-group-tag .btn-tag-delete { padding: 0 var(--space-2); font-size: var(--fs-base); line-height: 1.2; }
.form-row-inline {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--fs-base);
    color: var(--text-muted);
    line-height: var(--lh-normal);
}
.form-row-inline input[type="number"] {
    width: 4rem;
    min-height: 2rem;
    padding: var(--space-2) var(--space-3);
    font-size: var(--fs-base);
}
.form-row-checkboxes {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3) var(--space-5);
    align-items: center;
    font-size: var(--fs-base);
}
.form-row-checkboxes label {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: 0;
    white-space: nowrap;
}
.form-row-checkboxes input[type="checkbox"] {
    width: 14px;
    height: 14px;
    margin: 0;
    flex-shrink: 0;
}
.form-row-checkboxes input[type="number"] {
    width: 3.5rem;
    min-height: 2rem;
    padding: var(--space-2) var(--space-3);
    font-size: var(--fs-base);
}

.form-label-inline {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: 0;
    width: auto;
    line-height: 1.4;
}
.form-label-inline input[type="checkbox"] {
    width: 14px;
    height: 14px;
    margin: 0;
    vertical-align: middle;
}

/* 系统设置：左侧导航 + 右侧内容布局（放开宽度限制，随页面全宽铺开） */
#panel-settings .form,
#panel-devices > .form {
    max-width: none;
    width: 100%;
}

/* 用户管理弹窗：表单宽度占满弹窗内容 */
#modal-user .form {
    max-width: 100%;
}
.user-allowed-groups-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-top: 0.35rem;
}
.user-allowed-groups-chips .btn-chip {
    padding: var(--space-1) var(--space-3);
    font-size: var(--fs-sm);
    border-radius: var(--radius-xs);
    border: 1px solid var(--border);
    background: var(--bg-secondary);
    color: var(--text);
    cursor: pointer;
}
.user-allowed-groups-chips .btn-chip:hover {
    background: color-mix(in srgb, var(--act-primary) 12%, transparent);
    border-color: rgba(0, 113, 227, 0.35);
}

.form-static {
    min-height: 2.5rem;
    padding: var(--space-2) 0;
    color: var(--text);
}
.settings-layout {
    display: grid;
    grid-template-columns: 150px minmax(0, 1fr);
    gap: var(--space-7);
    align-items: stretch;
}
@media (max-width: 900px) {
    .settings-layout {
        grid-template-columns: minmax(0, 1fr);
    }
}
.settings-sidebar {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-3) var(--space-3);
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    height: 100%;
}
.settings-nav-group-title {
    font-size: var(--fs-2xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted, #8c959f);
    padding: var(--space-3) var(--space-4) var(--space-1);
    margin-top: 0.15rem;
}
.settings-nav-group-title:first-child { margin-top: 0; padding-top: 0.25rem; }
.settings-nav-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--control-radius);
    border: none;
    background: transparent;
    color: var(--text);
    font-size: var(--fs-base);
    cursor: pointer;
    transition: background .15s ease, color .15s ease;
}
.settings-nav-item:hover {
    background: var(--border);
    color: var(--text);
}
.settings-nav-item.active {
    background: var(--primary);
    color: #fff;
}
.settings-content {
    min-width: 0;
}
.settings-sections {
    margin-top: 0;
}
.settings-section {
    display: none;
}
.settings-section.active {
    display: block;
}

/* 系统设置整体排版：统一各区域字体层级（设备管理边栏页复用同一套） */
#panel-settings,
#panel-devices {
    font-size: var(--fs-base); /* 基础正文字号 */
}
#panel-settings .settings-subtitle,
#panel-devices .settings-subtitle {
    margin: 0 0 var(--space-4) 0;
    font-size: var(--fs-md);
    font-weight: 600;
    color: var(--text);
}
#panel-settings .form-row label,
#panel-devices .form-row label {
    font-size: var(--fs-base);           /* 字段名称区 */
}
#panel-settings .form-hint,
#panel-settings .hint,
#panel-devices .form-hint,
#panel-devices .hint {
    font-size: var(--fs-sm);           /* 字段描述/说明区 */
    color: var(--text-muted);
}
#panel-settings .form-row input,
#panel-settings .form-row select,
#panel-devices .form-row input,
#panel-devices .form-row select {
    font-size: var(--fs-base);         /* 用户输入区 */
}
/* 单列表单控件在宽屏下限宽，避免一个短字段配一条满宽输入框、可读性差。
   仅约束 form-row 的直接子控件；嵌套的 form-row-inline / 复选框组、以及
   设备类型/用户管理里的表格不受影响，仍占满宽。 */
#panel-settings .form-row > input:not([type="checkbox"]):not([type="radio"]),
#panel-settings .form-row > select,
#panel-settings .form-row > textarea,
#panel-devices .settings-section .form-row > input:not([type="checkbox"]):not([type="radio"]),
#panel-devices .settings-section .form-row > select,
#panel-devices .settings-section .form-row > textarea {
    max-width: 640px;
}
#panel-settings .table th,
#panel-settings .table td,
#panel-devices .table th,
#panel-devices .table td {
    font-size: var(--fs-sm);        /* 列表区 */
    padding: var(--space-3) var(--space-4);
}

.system-status-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    margin: var(--space-4) 0 var(--space-5);
}
.system-status-kpis {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: var(--space-4);
    margin-bottom: 1rem;
}
.system-status-kpi {
    padding: var(--space-5);
    min-height: 112px;
}
.system-status-kpi span,
.system-status-kpi small {
    display: block;
    color: var(--text-muted);
    font-size: var(--fs-sm);
}
.system-status-kpi strong {
    display: block;
    margin: var(--space-2) 0;
    color: var(--text);
    font-size: clamp(1.45rem, 2.6vw, 2.25rem);
    line-height: var(--lh-single);
}
.system-status-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-5);
}
.system-status-card canvas {
    width: 100%;
    height: 260px;
    display: block;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg);
}
.system-status-iface-list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--space-3);
    margin-top: 0.75rem;
}
.system-status-iface {
    padding: var(--space-4) var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-soft);
    color: var(--text);
}
/* 网卡卡片即选择器：可点、当前选中的高亮 */
.system-status-iface[role="button"] { cursor: pointer; transition: border-color .15s, background .15s; }
.system-status-iface[role="button"]:hover { border-color: var(--accent, #2563eb); background: var(--bg-elevated); }
.system-status-iface.selected {
    border-color: var(--accent, #2563eb);
    box-shadow: inset 0 0 0 1px var(--accent, #2563eb);
    background: var(--bg-elevated);
}
.system-status-iface[role="button"]:focus-visible { outline: 2px solid var(--accent, #2563eb); outline-offset: 2px; }
/* 可选组件标记：与必需服务区分，inactive 不代表故障 */
.system-status-optional {
    margin-left: 0.4rem; padding: 0 var(--space-2); border-radius: var(--radius-xs);
    background: var(--bg-elevated); color: var(--text-muted);
    font-size: 0.75em; font-style: normal; font-weight: 400;
}
.system-status-range { max-width: 9rem; padding: var(--space-1) var(--space-2); font-size: var(--fs-sm); }
/* 卡片标题行：标题在左、时间范围在右 */
.system-status-card .settings-card-head {
    display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap;
}
.system-status-card .settings-card-head h4 { margin: 0; }
/* 图上可拖拽选区 */
.system-status-card canvas { cursor: crosshair; }

.system-status-iface strong,
.system-status-iface span {
    display: block;
}
.system-status-iface span {
    margin-top: 0.2rem;
    color: var(--text-muted);
    font-size: var(--fs-xs);
}
.system-status-service-list {
    display: grid;
    gap: var(--space-3);
}
.system-status-service {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-soft);
}
.system-status-service strong,
.system-status-service span {
    display: block;
}
.system-status-service div > span {
    margin-top: 0.2rem;
    color: var(--text-muted);
    font-size: var(--fs-xs);
}
.system-status-service-status {
    flex: 0 0 auto;
    min-width: 78px;
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-pill);
    text-align: center;
    font-weight: 600;
    font-size: var(--fs-xs);
    background: rgba(148, 163, 184, 0.16);
    color: var(--text-muted);
}
.system-status-service-status.status-active {
    background: rgba(34, 197, 94, 0.14);
    color: #39d98a;
}
.system-status-service-status.status-failed {
    background: rgba(239, 68, 68, 0.16);
    color: #ff6b6b;
}
.system-status-service-status.status-inactive {
    background: rgba(245, 158, 11, 0.16);
    color: #f59e0b;
}
.system-status-service-status.status-unknown {
    background: rgba(148, 163, 184, 0.16);
    color: var(--text-muted);
}
@media (max-width: 1100px) {
    .system-status-kpis,
    .system-status-grid {
        grid-template-columns: 1fr;
    }
}

.user-list-toolbar {
    margin-bottom: 0.75rem;
    /* 列表上方的动作按钮行统一右对齐（参考设备列表），过滤/搜索条不受影响 */
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-3);
}
/* 全站按钮尺寸统一：工具栏 / 操作列 / 面板头动作区一律用与操作列相同的 sm 尺寸，
   消除 btn(默认) / btn-sm / btn-xs 之间的大小不一（.device-actions .btn 已是此尺寸） */
.filters-bar .btn,
.user-list-toolbar .btn,
.rack-list-toolbar .btn,
.table-actions .btn,
.panel-header-actions .btn,
.devices-footer .btn,
.resource-section-header .btn {
    min-height: 1.85rem;
    padding: var(--space-1) var(--space-4);
    font-size: var(--fs-sm);
    line-height: 1.2;
}
/* 用户列表表格：与整体设置区字号统一，表体与表头一致，略收紧内边距 */
#settings-section-users .table th,
#settings-section-users .table td {
    font-size: var(--fs-sm);
    padding: var(--space-3) var(--space-4);
}

.ldap-test-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
}
.ldap-test-row input[type="text"],
.ldap-test-row input[type="password"] {
    flex: 1 1 0;
    min-width: 120px;
}
.ldap-test-row .btn {
    flex: 0 0 auto;
}

#ldap-test-result.ldap-test-ok {
    color: var(--success);
}
#ldap-test-result.ldap-test-error {
    color: var(--error);
}
.filter { margin-left: 0.5rem; font-size: var(--fs-base); }
.filter input { margin-right: 0.3rem; }

.modal {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.6);
    align-items: center;
    justify-content: center;
    z-index: 100;
}
.modal.show { display: flex; animation: modalFadeIn .2s ease; }
@keyframes modalFadeIn { from { opacity: 0; } to { opacity: 1; } }
.modal-content {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--space-7);
    min-width: 440px;
    max-width: min(92vw, 1100px);
    max-height: 90vh;
    overflow-y: auto;
    box-shadow: var(--shadow-3);
    animation: modalSlideIn .25s ease;
}
@keyframes modalSlideIn { from { opacity: 0; transform: scale(0.96) translateY(-10px); } to { opacity: 1; transform: scale(1) translateY(0); } }
.modal-wide { min-width: 500px; }

/* ===== 弹窗编辑表单：统一两列（固定标签列 + 固定输入列，整齐对齐，不再一左一右），紧凑间距 ===== */
.modal .form-grid { display: flex; flex-direction: column; gap: var(--space-2); }
.modal .form-grid .form-field,
.modal .form-row {
    display: grid;
    /* 控件列 minmax(0,1fr) 铺满弹窗宽度：所有输入框/下拉等长，消除长短不一 */
    grid-template-columns: 9.5rem minmax(0, 1fr);
    align-items: center;
    column-gap: var(--space-4);
    margin: 0;   /* 间距由 .form-grid 的 gap / .form-row 的 margin-bottom 控制，避免叠加 */
}
/* 复选框行：整行铺开，勾选框在前、说明文字随后，不再挤进标签列错位 */
.modal .form-row > .form-label-inline,
.settings-section .form-row > .form-label-inline {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin: 0;
    color: var(--text);
    font-size: var(--fs-base);
}
.modal .form-row > .form-label-inline input[type="checkbox"],
.settings-section .form-row > .form-label-inline input[type="checkbox"] {
    width: 15px; height: 15px; margin: 0; flex: 0 0 auto;
}
/* 输入框+按钮组合行：占控件列，输入弹性填充，按钮不换行 */
.modal .form-row > .form-row-inline {
    grid-column: 2;
    display: flex;
    gap: var(--space-3);
    align-items: center;
    flex-wrap: wrap;
    width: 100%;
}
.modal .form-row > .form-row-inline > input { flex: 1 1 10rem; min-width: 0; }
.modal .form-row > .form-row-inline > .btn { flex: 0 0 auto; white-space: nowrap; }
.modal .form-row { margin-bottom: 0.4rem; }

/* 通用「输入 + 单位/说明后缀」控件组：紧凑输入 + 灰色后缀，占弹窗表单右列，全局统一 */
.input-suffix { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; grid-column: 2; }
.input-suffix > input { width: 5rem; flex: 0 0 auto; text-align: right; }
.input-suffix > .sfx { color: var(--text-muted); font-size: var(--fs-sm); }
.sla-dot { width: 12px; height: 12px; border-radius: var(--radius-xs); flex: 0 0 auto; box-shadow: inset 0 0 0 1px rgba(0,0,0,.25); }
.sla-dot-green { background: #12d150; }
.sla-dot-yellow { background: hsl(48, 95%, 62%); }

/* SLA 颜色阈值弹窗：窄而紧凑，说明段与阈值区用分隔线分开 */
.sla-thresh-modal { min-width: 440px; max-width: 540px; }
.sla-thresh-modal .form-grid { gap: var(--space-3); margin-top: 0.5rem; }
.sla-thresh-note { margin-top: 1rem; padding-top: 0.85rem; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: var(--space-3); }
.sla-thresh-note .form-hint { margin: 0; line-height: var(--lh-normal); }

/* 单一下拉搜索组合框（输入关键字过滤 + 点选） */
.combobox { position: relative; width: 100%; }
.combobox > input[type="text"] { width: 100%; }
.combobox-list {
    display: none; position: absolute; left: 0; right: auto; top: calc(100% + 2px); z-index: 40;
    min-width: 100%; width: max-content; max-width: calc(100vw - 4rem); max-height: 320px;
    overflow-y: auto; overflow-x: auto;
    margin: 0; padding: var(--space-1); list-style: none;
    background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--control-radius);
    box-shadow: var(--shadow-card);
}
.combobox-list.show { display: block; }
.combobox-item {
    padding: var(--space-1) var(--space-3); border-radius: var(--radius-sm); cursor: pointer;
    font-size: var(--fs-base); white-space: nowrap; line-height: var(--lh-tight);
}
.combobox-item:hover { background: var(--bg-elevated); }
.combobox-item.active { background: var(--primary); color: #fff; }
.combobox-toggle {
    position: sticky; top: -0.25rem; z-index: 1;
    display: flex; align-items: center; gap: var(--space-2);
    padding: var(--space-2) var(--space-3); margin: -0.25rem -0.25rem 0.25rem;
    background: var(--bg-elevated); border-bottom: 1px solid var(--border);
    font-size: var(--fs-sm); color: var(--text-muted); cursor: pointer;
}
.combobox-toggle input { margin: 0; flex: 0 0 auto; }
/* 编辑POP连线弹窗加宽，给关联邻居下拉框留出向右展开的空间（输入框仍与其它字段对齐在第二列） */
#modal-topology-link .modal-content { min-width: 760px; }
.combobox-toggle { white-space: nowrap; }
/* 拓扑编辑弹窗的取色器：缩小约一半 + 去掉内部留白，渲染成紧凑小色块 */
#modal-topology-map input[type="color"] {
    width: 24px;
    height: 16px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-xs);
    cursor: pointer;
    vertical-align: middle;
    flex: 0 0 auto;
    -webkit-appearance: none;
    appearance: none;
    background: none;
}
#modal-topology-map input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
#modal-topology-map input[type="color"]::-webkit-color-swatch { border: none; border-radius: var(--radius-xs); }
#modal-topology-map input[type="color"]::-moz-color-swatch { border: none; border-radius: var(--radius-xs); }
.modal .form-grid .form-field:last-child,
.modal .form-row:last-child { margin-bottom: 0; }
.modal .form-grid .form-field > label,
.modal .form-row > label {
    margin: 0; text-align: left; line-height: var(--lh-tight);
    color: var(--text-muted); font-size: var(--fs-base); font-weight: 500;
}
.modal .form-grid .form-field > input,
.modal .form-grid .form-field > select,
.modal .form-row > input,
.modal .form-row > select,
.modal .form-row > .input-with-eye { width: 100%; min-width: 0; }
/* 跨两列：多行文本 / 说明 / 内联组 / 复选 / 标签组 等不适合塞进固定输入列的内容 */
.modal .form-grid .form-field > textarea,
.modal .form-row > textarea,
.modal .form-row > .form-row-inline,
.modal .form-row > .form-row-checkboxes,
.modal .form-row > .checkbox-block,
.modal .form-row > .device-group-tags,
.modal .form-row > .user-allowed-groups-chips { grid-column: 1 / -1; width: 100%; }
.modal .form-row > .form-hint { grid-column: 2; margin-top: 0.15rem; }
.modal .form-grid .form-field > textarea,
.modal .form-row > textarea { min-height: 4.5rem; }

/* 终端弹窗：可拖拽、最大化/最小化、可调整大小 */
#modal-terminal .terminal-window {
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 800px;
    height: 520px;
    min-width: 400px;
    min-height: 280px;
    max-width: 100vw;
    max-height: 100vh;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-3);
    display: flex;
    flex-direction: column;
    z-index: 101;
    overflow: hidden;
}
#modal-terminal .terminal-window.terminal-maximized {
    left: 0 !important;
    top: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    width: 100% !important;
    height: 100% !important;
    transform: none;
    border-radius: 0;
    max-width: none;
    max-height: none;
}
#modal-terminal .terminal-window.terminal-minimized {
    height: 44px !important;
    min-height: 44px;
}
#modal-terminal .terminal-window.terminal-minimized .terminal-body {
    display: none;
}
#modal-terminal .terminal-window.terminal-minimized .terminal-resize {
    display: none;
}
#modal-terminal .terminal-titlebar {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-3) var(--space-4);
    background: var(--bg-elevated);
    border-bottom: 1px solid var(--border);
    cursor: move;
    user-select: none;
}
#modal-terminal .terminal-title {
    font-weight: 600;
    font-size: var(--fs-base);
}
#modal-terminal .terminal-titlebar-actions {
    display: flex;
    gap: var(--space-2);
    align-items: center;
}
#modal-terminal .terminal-titlebar-actions .btn { cursor: pointer; }
#modal-terminal .terminal-body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
    padding: var(--space-4);
}
#modal-terminal .terminal-hint {
    margin: 0 0 var(--space-3);
    font-size: var(--fs-sm);
}
#modal-terminal .terminal-container {
    flex: 1;
    min-height: 300px;
    background: #1e1e1e;
    border-radius: var(--control-radius);
    overflow: hidden;
}
#modal-terminal .terminal-resize {
    position: absolute;
    z-index: 2;
    background: transparent;
}
#modal-terminal .terminal-resize-e {
    right: 0;
    top: 0;
    bottom: 0;
    width: 6px;
    cursor: col-resize;
}
#modal-terminal .terminal-resize-s {
    left: 0;
    right: 0;
    bottom: 0;
    height: 6px;
    cursor: row-resize;
}
#modal-terminal .terminal-resize-se {
    right: 0;
    bottom: 0;
    width: 12px;
    height: 12px;
    cursor: nwse-resize;
}

.modal-content h3 { margin-top: 0; }
.modal-actions { margin-top: 1.5rem; display: flex; gap: var(--space-3); justify-content: flex-end; }
.modal-db-backup-list {
    margin: 0 0 var(--space-5);
    padding-left: 1.5rem;
    font-size: var(--fs-base);
    line-height: 1.6;
    color: var(--text);
}
.modal-db-backup-list li { margin-bottom: 0.35rem; }
.modal textarea {
    width: 100%;
    padding: var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--control-radius);
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-mono);
    margin: var(--space-3) 0;
}
.hint { font-size: var(--fs-base); color: var(--text-muted); }

/* 分页条：全站唯一规格。此前有 4 种结构——devices-footer(19处)、
   裸 pagination(12处)、inv-pagination、traffic-graph-chart-pagination，
   高度分别是 46/30/19px，位置也不一致。统一到同一套。 */
.pagination,
.inv-pagination,
.traffic-graph-chart-pagination { margin-top: 0; display: flex; gap: var(--space-3); align-items: center; min-height: var(--control-h); }
.inv-pagination,
.traffic-graph-chart-pagination { justify-content: flex-end; }
.pagination button { padding: var(--space-1) var(--space-3); }

/* 列表底部：分页 + 每页条数 */
.devices-footer {
    margin-top: 0.5rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-5);
}
.devices-footer .per-page {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--fs-sm);
    color: var(--text-muted);
}
.devices-footer .per-page select {
    padding: var(--space-1) var(--space-3);
    border-radius: var(--control-radius);
    border: 1px solid var(--border);
    background: var(--bg);
    color: var(--text);
    font-size: var(--fs-sm);
    min-height: 2rem;
    box-sizing: border-box;
}

.config-tree {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-5);
}
.config-group { margin-bottom: 1rem; }
.config-group .prefix { font-weight: 600; margin-bottom: 0.5rem; }
.config-host { margin-left: 1rem; margin-bottom: 0.5rem; }
.config-files { margin-left: 1.5rem; font-size: var(--fs-base); }
.config-files a { display: block; padding: var(--space-1) 0; }

.settings-logo-preview {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-width: 160px;
}
.settings-logo-img {
    max-width: 64px;
    max-height: 64px;
    width: auto;
    height: auto;
    object-fit: contain;
    border-radius: var(--radius-xs);
    border: 1px solid var(--border-subtle);
    background: var(--card-bg);
}
.settings-logo-actions {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: nowrap;
    white-space: nowrap;
}

/* 已备份配置：每页条数 + 分页（整行明显展示） */
.config-devices-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-bottom: 1rem;
    padding: var(--space-4) var(--space-5);
    font-size: var(--fs-base);
    color: var(--text);
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}
.config-devices-toolbar input[type="text"],
.config-devices-toolbar select {
    padding: var(--space-2) var(--space-3);
    border-radius: var(--control-radius);
    border: 1px solid var(--border);
    background: var(--bg-card);
    color: var(--text);
    min-width: 180px;
    min-height: 2rem;
    font-size: var(--fs-base);
    box-sizing: border-box;
}
.config-pagination-info { margin-left: 0.25rem; font-weight: 500; }
.config-toolbar-sep { margin: 0 var(--space-3); opacity: 0.6; color: var(--text-muted); }
.config-pagination-btns {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
    margin-left: 0.25rem;
}
.config-pagination-btns .btn { flex-shrink: 0; }
.config-pagination-label { font-weight: 500; color: var(--text); }
#config-prev,
#config-next { min-width: 4.5em; }

/* 已备份配置表 - 操作列换行 */
.col-actions-cell {
    white-space: normal;
    min-width: 0;
}
.config-device-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
}

/* 配置全文搜索：右侧大搜索框，高辨识度 */
.config-content-search-wrap {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-left: auto;
    flex-shrink: 0;
}
.config-content-search-input {
    width: 320px;
    min-width: 240px;
    padding: var(--space-3) var(--space-5) var(--space-3) var(--space-6);
    font-size: var(--fs-md);
    border-radius: var(--radius-pill);
    border: 2px solid var(--border);
    background: var(--bg-card);
    color: var(--text);
    transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
    outline: none;
}
.config-content-search-input::placeholder {
    color: var(--text-muted);
    opacity: 0.9;
}
.config-content-search-input:hover {
    border-color: var(--primary);
    background: var(--bg-elevated);
}
.config-content-search-input:focus {
    border-color: var(--primary);
    box-shadow: var(--shadow-1);
    background: var(--bg-card);
}
.config-content-search-btn {
    padding: var(--space-3) var(--space-6);
    font-size: var(--fs-md);
    font-weight: 600;
    border-radius: var(--radius-pill);
    border: none;
    background: linear-gradient(135deg, var(--primary) 0%, #0550ae 100%);
    color: #fff;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.2s ease, filter 0.2s ease;
    box-shadow: var(--shadow-2);
}
.config-content-search-btn:hover {
    filter: brightness(1.08);
    box-shadow: var(--shadow-2);
    transform: translateY(-1px);
}
.config-content-search-btn:active {
    transform: translateY(0);
}
.config-search-result-hint {
    margin: 0 0 var(--space-3);
    font-size: var(--fs-sm);
    color: var(--text-muted);
    line-height: 1.4;
}
.config-search-result {
    margin-bottom: 1rem;
    max-height: 260px;
    overflow-y: auto;
    border-radius: var(--radius-lg);
    border: 1px solid var(--border);
    background: var(--bg-card);
    padding: var(--space-4) var(--space-5);
}
.config-search-result.config-search-result--empty {
    display: none;
}
.config-search-item {
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--border);
}
.config-search-item:last-child {
    border-bottom: none;
}
.config-search-item-main {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: baseline;
    margin-bottom: 0.2rem;
    font-size: var(--fs-base);
}
.config-search-host {
    font-weight: 500;
}
.config-search-file {
    color: var(--primary);
    font-size: var(--fs-base);
    text-decoration: none;
    transition: color 0.2s ease, text-decoration 0.2s ease;
}
.config-search-file:hover {
    color: var(--primary-hover);
    text-decoration: underline;
}
.config-search-line {
    color: var(--text-muted);
    font-size: var(--fs-sm);
    margin-left: 0.25rem;
}
.config-search-snippet {
    font-family: var(--font-mono);
    font-size: var(--fs-sm);
    color: var(--text-muted);
    word-break: break-all;
}

/* 自动发现规则表格：自适应宽度，操作栏不换行 */
.discovery-rule-table-wrapper {
    overflow-x: auto;
}
.discovery-rule-table {
    table-layout: auto;
    width: 100%;
}
.discovery-rule-table td:last-child,
.discovery-rule-table th:last-child {
    white-space: nowrap;
}
.discovery-rule-table td:last-child .btn {
    margin-right: 0.25rem;
}
.discovery-type-keyword-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: 0.5rem;
}
.discovery-type-keyword-row select,
.discovery-type-keyword-row input[type="text"] {
    flex: 1;
    min-width: 0;
}

/* ==================== 设备盘点 ==================== */
#panel-inventory-stock .panel-body { display: flex; flex-direction: column; gap: var(--space-5); }
.inv-run-status { font-size: var(--fs-sm); color: var(--text-muted); margin-right: 0.25rem; }
#panel-inventory-stock .stats-cards { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: var(--space-4); margin-bottom: 0; }
#panel-inventory-stock .stat-card { min-height: 104px; padding: var(--space-6) var(--space-6); }
#panel-inventory-stock .stat-value { font-size: clamp(1.4rem, 2vw, 1.9rem); line-height: 1.25; overflow-wrap: anywhere; }
.inv-card-sub { font-size: var(--fs-sm); color: var(--text-muted); margin-top: 0.4rem; }
.inv-xcvr-dist { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: var(--space-5) var(--space-5); box-shadow: var(--shadow); }
.inv-xcvr-dist:empty { display: none; }
.inv-dist-title { font-size: var(--fs-base); font-weight: 600; margin-bottom: 0.7rem; }
.inv-dist-row { display: grid; grid-template-columns: 220px 1fr 48px; align-items: center; gap: var(--space-4); margin-bottom: 0.4rem; }
.inv-dist-name { font-size: var(--fs-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.inv-dist-bar { background: var(--bg-elevated); border-radius: var(--control-radius); height: 10px; overflow: hidden; }
.inv-dist-bar > span { display: block; height: 100%; background: linear-gradient(90deg, #3b82f6, var(--act-info)); border-radius: var(--control-radius); }
.inv-dist-count { font-size: var(--fs-sm); text-align: right; color: var(--text-muted); }
.inv-toolbar #inv-search { width: auto; min-width: 240px; flex: 1; /* 控件样式由全局 input/select 基础规则统一 */ }
.inv-dup-toggle { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--fs-base); color: var(--text-muted); }
.inv-table .inv-sn, .inv-table .inv-port { font-family: var(--font-mono); font-size: var(--fs-sm); }
.inv-click-filter { appearance: none; border: 0; padding: 0; margin: 0; background: transparent; color: inherit; font: inherit; font-weight: 600; text-align: left; cursor: pointer; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: middle; }
.inv-click-filter:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.inv-click-filter.inv-tag:hover { text-decoration: none; filter: brightness(1.05); }
.inv-tag { display: inline-block; padding: 0.1rem 0.5rem; border-radius: var(--radius-pill); font-size: var(--fs-xs); font-weight: 600; white-space: nowrap; }
.inv-tag-chassis { background: #ecfccb; color: #3f6212; }
.inv-tag-psu { background: #fef3c7; color: #92400e; }
.inv-tag-fan { background: #dbeafe; color: #1e40af; }
/* 盘点：规范化过的光模块型号（悬停显示原始型号） */
.inv-click-filter.inv-model-normalized { text-decoration: underline dotted; text-underline-offset: 3px; }
.inv-tag-module { background: #e0e7ff; color: #3730a3; }
.inv-tag-transceiver { background: #cffafe; color: #155e75; }
/* 盘点状态 pill：基础配方并入全站统一 .state-pill 段；空闲(down)取中性灰 */
.inv-status-pill.down { color: var(--text-muted); background: rgba(148, 163, 184, 0.14); }
.inv-status-muted { color: var(--text-muted); }
.inv-pagination { display: flex; align-items: center; gap: var(--space-4); justify-content: flex-end; }
.inv-page-info { font-size: var(--fs-sm); color: var(--text-muted); }
.inv-table .empty-cell { text-align: center; color: var(--text-muted); padding: 1.75rem 0.75rem; }
/* 全量同步邻居：手动线路冲突弹窗的当前→建议值差异 */
#modal-topology-sync-conflict .modal-content { min-width: 760px; }
#modal-topology-auto-rule .modal-content { min-width: 600px; }
/* 自动化规则弹窗内容较宽(设备列表/IX聚合预览/关键字框)：第二列占满剩余宽度，与弹窗协调 */
#modal-topology-auto-rule .form-grid .form-field { grid-template-columns: 8.5rem 1fr; }
#modal-topology-sync-conflict .table th, #modal-topology-sync-conflict .table td { font-size: var(--fs-sm); padding: var(--space-2) var(--space-3); white-space: nowrap; }
.sync-old { color: var(--text-muted); text-decoration: line-through; }
.sync-new { color: var(--success, #16a34a); font-weight: 600; }
/* 设备列表列较多：不换行，超出宽度时容器(.table-wrap)左右滑动查看 */
#device-table th, #device-table td { white-space: nowrap; }
/* 自动发现规则：IP 范围默认只显示前 2 个，点击展开 */
.disc-ip-cell .disc-ip-full { white-space: normal; word-break: break-all; }
.disc-ip-toggle { color: var(--primary, #2563eb); cursor: pointer; text-decoration: none; font-size: var(--fs-sm); white-space: nowrap; }
.disc-ip-toggle:hover { text-decoration: underline; }
/* 系统概览：KPI 卡片(可点击跳转)与模块卡片标题链接 */
.stats-cards a.stat-card { text-decoration: none; color: inherit; cursor: pointer; }
.stats-cards a.stat-card:hover { border-left-color: var(--primary, #2563eb); }
.dash-card-link { text-decoration: none; color: inherit; }
.dash-card-link:hover { color: var(--primary, #2563eb); }
#dash-modules .dashboard-card .dashboard-settings-item { display: flex; justify-content: space-between; gap: var(--space-4); padding: var(--space-1) 0; font-size: var(--fs-sm); border-bottom: 1px solid var(--border); }
#dash-modules .dashboard-card .dashboard-settings-item:last-child { border-bottom: 0; }
#dash-modules .dashboard-card .dashboard-settings-item .label { color: var(--text-muted); }

/* ===== 系统概览：彩色 KPI 卡片 + 模块卡片 ===== */
#dash-kpis { grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: var(--space-4); margin-bottom: 1.25rem; }
.dash-kpi { display: flex; align-items: center; gap: var(--space-4); text-decoration: none; cursor: pointer; border-left-width: 4px; padding: var(--space-5) var(--space-6); }
.dash-kpi:hover { transform: translateY(-2px); box-shadow: var(--shadow-3); }
.dash-kpi-icon { width: 44px; height: 44px; border-radius: var(--radius-lg); flex: 0 0 auto; display: flex; align-items: center; justify-content: center; font-size: var(--fs-xl); background: var(--bg-elevated); }
.dash-kpi-body { display: flex; flex-direction: column; min-width: 0; }
.dash-kpi-value { font-size: 22px; font-weight: 600; line-height: 1.05; letter-spacing: -0.03em; }
.dash-kpi-label { font-size: var(--fs-sm); color: var(--text-muted); margin-top: 0.15rem; }
.dash-tone-blue   { border-left-color: #2563eb } .dash-tone-blue   .dash-kpi-value { color: #2563eb } .dash-tone-blue   .dash-kpi-icon { background: rgba(37,99,235,.14) }
.dash-tone-green  { border-left-color: #16a34a } .dash-tone-green  .dash-kpi-value { color: #16a34a } .dash-tone-green  .dash-kpi-icon { background: rgba(22,163,74,.14) }
.dash-tone-amber  { border-left-color: #d97706 } .dash-tone-amber  .dash-kpi-value { color: #d97706 } .dash-tone-amber  .dash-kpi-icon { background: rgba(217,119,6,.16) }
.dash-tone-indigo { border-left-color: #4f46e5 } .dash-tone-indigo .dash-kpi-value { color: #4f46e5 } .dash-tone-indigo .dash-kpi-icon { background: rgba(79,70,229,.14) }
.dash-tone-violet { border-left-color: #7c3aed } .dash-tone-violet .dash-kpi-value { color: #7c3aed } .dash-tone-violet .dash-kpi-icon { background: rgba(124,58,237,.14) }
.dash-tone-cyan   { border-left-color: #0891b2 } .dash-tone-cyan   .dash-kpi-value { color: #0891b2 } .dash-tone-cyan   .dash-kpi-icon { background: rgba(8,145,178,.14) }
.dash-tone-teal   { border-left-color: var(--act-neutral) } .dash-tone-teal   .dash-kpi-value { color: var(--act-neutral) } .dash-tone-teal   .dash-kpi-icon { background: rgba(13,148,136,.14) }
.dash-tone-rose   { border-left-color: #e11d48 } .dash-tone-rose   .dash-kpi-value { color: #e11d48 } .dash-tone-rose   .dash-kpi-icon { background: rgba(225,29,72,.14) }

.dashboard-card.dash-mod { border-top: 3px solid var(--mod, #64748b); }
.dash-mod .dashboard-card-title { display: flex; align-items: center; margin: 0 0 var(--space-3); }
.dash-mod-icon { margin-right: 0.45rem; font-size: var(--fs-lg); }
.dash-card-arrow { margin-left: auto; color: var(--text-muted); font-weight: 600; }
.dash-accent-blue{--mod:#2563eb} .dash-accent-green{--mod:#16a34a} .dash-accent-amber{--mod:#d97706} .dash-accent-indigo{--mod:#4f46e5}
.dash-accent-violet{--mod:#7c3aed} .dash-accent-cyan{--mod:#0891b2} .dash-accent-teal{--mod:var(--act-neutral)} .dash-accent-rose{--mod:#e11d48} .dash-accent-slate{--mod:#64748b}
.dash-metric { display: flex; justify-content: space-between; align-items: center; gap: var(--space-4); padding: var(--space-2) 0; border-bottom: 1px solid var(--border); font-size: var(--fs-sm); }
.dash-metric:last-child { border-bottom: 0; }
.dash-metric-label { color: var(--text-muted); }
.dash-metric-value { font-weight: 600; color: var(--text); white-space: nowrap; text-align: right; }
.dash-metric-link { text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.dash-metric-link:hover { filter: brightness(1.15); }
.dash-metric-value.val-ok { color: var(--success, #16a34a); }
.dash-metric-value.val-fail { color: var(--error, #dc2626); }
.dash-metric-value.val-warn { color: var(--warn, #d97706); }
.dash-metric-value.val-accent { color: var(--primary, #2563eb); }
.dash-metric-value.val-strong { font-weight: 600; }
.dash-metric-value.val-muted { color: var(--text-muted); font-weight: 500; }
.dash-bar { height: 7px; border-radius: var(--control-radius); background: var(--bg-elevated); overflow: hidden; margin: var(--space-1) 0 var(--space-2); }
.dash-bar-fill { display: block; height: 100%; border-radius: var(--control-radius); background: linear-gradient(90deg, #10b981, #22c55e); }
.dash-bar-fill.val-warn { background: linear-gradient(90deg, #f59e0b, #fbbf24); }
.dash-bar-fill.val-fail { background: linear-gradient(90deg, #ef4444, #f87171); }
/* 仪表盘迷你趋势图 */
.dash-trend { margin: 0 0 var(--space-3); padding: 0.4rem 0.2rem 0.1rem; background: var(--bg-elevated); border-radius: var(--radius-md); }
.dash-trend-svg { display: block; width: 100%; height: auto; }
.dash-trend-x {
    fill: var(--text-muted);
    font: 500 10px var(--font-sans, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);
}
.dash-trend-empty { padding: var(--space-7) 0; text-align: center; color: var(--text-muted); font-size: var(--fs-sm); }
.dash-trend-legend { display: flex; justify-content: center; gap: var(--space-5); margin-top: 0.2rem; font-size: var(--fs-xs); color: var(--text-muted); }
.dash-trend-legend span { display: inline-flex; align-items: center; gap: var(--space-1); }
.dash-trend-legend i { width: 10px; height: 10px; border-radius: var(--radius-xs); display: inline-block; }

/* 拓扑底部图例：利用率配色对应 + 最近同步时间(单行，贴底边) */
.topology-legend {
    position: absolute; left: 0; right: 0; bottom: 0; z-index: 5;
    display: flex; align-items: center; flex-wrap: nowrap; gap: var(--space-3);
    padding: var(--space-1) var(--space-4);
    font-size: var(--fs-xs); line-height: var(--lh-single); color: var(--text-muted);
    background: var(--bg-card); border-top: 1px solid var(--border);
    overflow-x: auto; white-space: nowrap; pointer-events: none;
}
.topo-leg-cap { font-weight: 600; color: var(--text); flex: 0 0 auto; }
.topo-leg-item { display: inline-flex; align-items: center; gap: var(--space-1); flex: 0 0 auto; }
.topo-leg-sw { width: 16px; height: 8px; border-radius: var(--radius-xs); display: inline-block; box-shadow: 0 0 0 1px rgba(0,0,0,.15) inset; }
.topo-leg-sync { margin-left: auto; flex: 0 0 auto; color: var(--text); font-weight: 600; padding-left: 0.6rem; }

/* ===== 路径走向：工具栏控件 + 信息条 ===== */
.topology-path-trace {
    display: inline-flex; align-items: center; flex-wrap: nowrap; gap: var(--space-2);
    margin-left: auto; flex: 0 0 auto;
}
.topology-toolbar select.topology-path-select {
    min-width: 0; width: 108px; flex: 0 0 auto;
    padding: var(--space-1) var(--space-7) var(--space-1) var(--space-3); font-size: var(--fs-sm);
    border: 1px solid var(--border); border-radius: var(--control-radius);
    background-color: var(--bg-input, var(--bg-card)); color: var(--text);
}
.topology-path-arrow { color: var(--text-muted); font-weight: 600; }
.topology-path-info {
    display: none; margin: var(--space-2) 0 0; padding: var(--space-2) var(--space-4);
    font-size: var(--fs-sm); line-height: var(--lh-tight); color: var(--text);
    background: var(--bg-card); border: 1px solid var(--border);
    border-left: 3px solid #38bdf8; border-radius: var(--control-radius);
}
.topology-path-info.show { display: block; }
.topo-path-route { font-weight: 600; }
.topo-path-sep { color: #38bdf8; padding: 0 var(--space-1); }
.topo-path-stat { margin-left: 0.7rem; color: var(--text-muted); }
.topo-path-devices {
    margin-top: 0.35rem; padding-top: 0.35rem; border-top: 1px dashed var(--border);
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.1rem 0.15rem;
    font-size: var(--fs-xs); color: var(--text-muted);
}
.topo-path-cap {
    margin-right: 0.4rem; padding: 0.05rem 0.35rem; border-radius: var(--radius-xs);
    background: rgba(56, 189, 248, 0.16); color: #38bdf8; font-weight: 600;
}
.topo-path-dev { color: var(--text); font-weight: 600; }
.topo-path-mlink { color: #38bdf8; font-weight: 600; padding: 0 var(--space-1); }
.topo-path-join { color: var(--text-muted); padding: 0 var(--space-1); }

/* ===== 路径走向：SVG 叠加层与置灰 ===== */
.topology-svg.topology-path-mode .topology-link,
.topology-svg.topology-path-mode .topology-link-arrow { opacity: 0.16; }
.topology-svg.topology-path-mode .topology-car-wrap { display: none; }
.topology-svg.topology-path-mode .topology-label-layer { opacity: 0.22; }
.topology-svg.topology-path-mode .topology-node { opacity: 0.55; }
.topology-path-layer { pointer-events: none; }
.topology-path-glow {
    fill: none; stroke: #38bdf8; stroke-linecap: round; stroke-linejoin: round;
    opacity: 0.28; filter: blur(2px);
}
.topology-path-route {
    fill: none; stroke: #7dd3fc; stroke-linecap: round; stroke-linejoin: round;
    stroke-dasharray: 2 14; opacity: 0.95;
    animation: topoPathDash 1s linear infinite;
}
@keyframes topoPathDash { to { stroke-dashoffset: -16; } }
.topology-path-comet {
    fill: #ffffff; stroke: #38bdf8; stroke-width: 2;
    filter: drop-shadow(0 0 6px #38bdf8) drop-shadow(0 0 12px #0ea5e9);
}
.topology-path-endpoint { fill: none; stroke-width: 3; }
.topology-path-endpoint.is-src { stroke: #22c55e; filter: drop-shadow(0 0 5px #22c55e); }
.topology-path-endpoint.is-dst { stroke: #f97316; filter: drop-shadow(0 0 5px #f97316); }
.topology-path-hop-label { fill: #d4e8f7; font-weight: 500; }
.topology-path-hop-bg { fill: rgba(6, 17, 33, 0.94); stroke: #38bdf8; stroke-width: 1; }
.topology-path-hop-tie { stroke: rgba(56, 189, 248, 0.65); stroke-width: 1; stroke-dasharray: 2 2; }

/* ===== 全屏系统布局统一层 ===== */
body {
    overflow-x: hidden;
}

.panel.active {
    width: 100%;
    min-width: 0;
}

.panel-body,
.resource-section,
.dashboard-card,
.settings-card,
.config-files-section,
.config-diff-section,
.config-compliance-section {
    min-width: 0;
}

.panel-header,
.dashboard-header,
.resource-section-header {
    width: 100%;
}

.filters-bar,
.devices-toolbar,
.config-devices-toolbar,
.backup-jobs-toolbar,
.traffic-filters,
.traffic-graph-list-filters,
.traffic-graph-toolbar,
.inv-toolbar,
.resource-summary-toolbar,
.neighbor-filters,
.topology-toolbar {
    width: 100%;
}

.devices-toolbar,
.config-devices-toolbar,
.backup-jobs-toolbar,
.inv-toolbar {
    flex-wrap: wrap;
    gap: var(--space-3);
    padding: var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-card);
}

.filters-bar input[type="text"],
.filters-bar input[type="search"],
.devices-toolbar input[type="text"],
.config-devices-toolbar input[type="text"],
.backup-jobs-toolbar input[type="text"],
.inv-toolbar input[type="text"],
.neighbor-filters input[type="text"],
.traffic-filters input[type="text"],
.traffic-graph-list-filters input[type="text"],
.traffic-graph-toolbar input[type="text"] {
    min-width: min(260px, 100%);
}

.neighbor-filters #neighbor-filter-keyword {
    min-width: 0;
    max-width: 280px;
}

.table-wrap,
.table-resizable,
.resource-table-wrap {
    max-width: 100%;
}

.table {
    min-width: 100%;
}

.devices-footer {
    width: 100%;
    margin-top: 0.85rem;
}


.settings-layout {
    grid-template-columns: 150px minmax(0, 1fr);
    gap: var(--space-5);
}

.settings-sidebar {
    position: sticky;
    top: calc(56px + var(--page-pad-y));
    align-self: start;
    max-height: calc(100vh - 100px);
    overflow: auto;
}

.settings-content,
.settings-sections {
    min-width: 0;
    width: 100%;
}

.traffic-grid {
    grid-template-columns: minmax(0, 1fr) minmax(420px, 0.55fr);
}

.traffic-graph-layout {
    grid-template-columns: minmax(220px, 0.18fr) minmax(0, 1fr);
}

.traffic-graph-main {
    min-height: calc(100vh - 210px);
}

.traffic-graph-page.active .traffic-graph-layout {
    flex: 1 1 auto;
    min-height: 0;
}

.traffic-graph-page.active .traffic-graph-main {
    min-height: 0;
}

.traffic-graph-page.active .traffic-side-list {
    height: auto;
    min-height: 0;
}

.topology-canvas-wrap:empty {
    min-height: 360px;   /* 仅加载占位：内容渲染后由 svg 自身高度决定 */
}

.neighbor-traffic-modal {
    width: min(94vw, 1000px);
    max-width: 1000px;
}

@media (min-width: 1500px) {
    :root {
        --page-pad-x: 2rem;
        --page-pad-y: 1.5rem;
    }
    .stats-cards {
        grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    }
    #panel-dashboard .dashboard-grid,
    #panel-backup-mgmt .dashboard-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
    #panel-neighbors .stats-cards {
        grid-template-columns: repeat(6, minmax(0, 1fr));
    }
}

@media (max-width: 1180px) {
    .app-header-inner {
        flex-wrap: wrap;
        padding-top: 0.35rem;
        padding-bottom: 0.35rem;
    }
    .brand {
        flex-basis: auto;
    }
    .nav-tabs {
        order: 3;
        flex-basis: 100%;
    }
    .header-right {
        margin-left: auto;
    }
}

@media (max-width: 900px) {
    .settings-layout,
    .traffic-grid,
    .traffic-graph-layout {
        grid-template-columns: 1fr;
        min-height: 0;
    }
    .settings-sidebar {
        position: static;
        max-height: none;
        flex-direction: row;
        overflow-x: auto;
    }
    .settings-nav-item {
        white-space: nowrap;
    }
    .panel-actions,
    .dashboard-quick-actions {
        justify-content: flex-start;
    }
}

@media (max-width: 640px) {
    :root {
        --page-pad-x: 0.75rem;
        --page-pad-y: 0.9rem;
    }
    .app-header-inner {
        gap: var(--space-3);
    }
    .brand {
        font-size: var(--fs-lg);
    }
    .theme-btn,
    .header-logout,
    .header-user {
        font-size: var(--fs-xs);
    }
    .panel-header,
    .dashboard-header {
        align-items: flex-start;
    }
    .stats-cards,
    #panel-neighbors .stats-cards {
        grid-template-columns: 1fr;
    }
}

/* 拓扑节点右键菜单 */
.topology-context-menu {
    position: fixed;
    z-index: 9999;
    min-width: 160px;
    background: var(--bg-card, #1a2233);
    border: 1px solid var(--border, #33415a);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-3);
    padding: var(--space-1);
    font-size: var(--fs-sm);
}
.topology-context-item {
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-sm);
    cursor: pointer;
    color: var(--text, #e6ecf5);
    white-space: nowrap;
}
.topology-context-item:hover { background: rgba(56, 189, 248, .16); }
.topology-context-item.danger { color: #ff6b6b; }
.topology-context-item.danger:hover { background: rgba(239, 68, 68, .16); }

/* 自动化规则设备过滤：CDP/LLDP 学到的外部设备标记 */
.auto-rule-device-learned {
    display: inline-block;
    margin-left: 6px;
    padding: 0 var(--space-1);
    font-size: 10px;
    line-height: 15px;
    border-radius: var(--radius-xs);
    color: #a855f7;
    background: rgba(168, 85, 247, .14);
    vertical-align: middle;
}

/* POP 连线编辑：本端设备/接口的可搜索下拉面板 */
#modal-topology-link .form-field { position: relative; }
.topo-combo-dd {
    display: none;
    position: absolute;
    /* form-field 是 8.5rem(标签) + 0.75rem(间距) + 15rem(输入) 的两列网格；
       下拉框左缘对齐输入框、至少与输入同宽；内容更长(接口名+描述)时按需向右加宽，
       既不铺满整行/贴到标签列，也能完整展示接口描述 */
    left: calc(9.5rem + 0.75rem);
    top: 100%;
    min-width: 15rem;
    width: max-content;
    max-width: 34rem;
    z-index: 60;
    margin-top: 2px;
    max-height: 220px;
    overflow-y: auto;
    border: 1px solid var(--border, #33415a);
    border-radius: var(--radius-md);
    background: var(--bg-card, #1a2233);
    box-shadow: var(--shadow-3);
}
.topo-combo-dd.show { display: block; }

/* ===================== 表单控件统一规范 =====================
   1) 设置页每个 form-row 整体封顶 34rem：行内所有控件对齐同一右边缘，消除长短不一
   2) 输入框/下拉/密码等统一高度 2.25rem，视觉完全一致
   3) 下拉框自绘箭头（按主题配色），替换深色下看不清的原生灰箭头 */
:root { --select-arrow: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='11' height='7'><path d='M1 1l4.5 4.5L10 1' fill='none' stroke='%23cbd5e1' stroke-width='1.6' stroke-linecap='round'/></svg>"); }
[data-theme="light"] { --select-arrow: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='11' height='7'><path d='M1 1l4.5 4.5L10 1' fill='none' stroke='%23475569' stroke-width='1.6' stroke-linecap='round'/></svg>"); }

.settings-section .form-row { max-width: 34rem; }
.settings-section .form-row.form-row-wide { max-width: none; }
/* 内嵌表格/宽内容的行不封顶（结构性兜底，防止漏加 form-row-wide 再挤压表格） */
.settings-section .form-row:has(table),
.settings-section .form-row:has(.table-wrapper),
.settings-section .form-row:has(.table-wrap) { max-width: none; }
.settings-section .form-row > input:not([type="checkbox"]):not([type="radio"]),
.settings-section .form-row > select,
.settings-section .form-row > textarea,
.settings-section .form-row > .input-with-eye,
.settings-section .form-row > .form-row-inline,
.settings-section .form-row > .field-stack,
.settings-section .form-row > .form-row-sub { width: 100%; max-width: 100%; }
.settings-section .form-row > .form-row-inline { display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; }
.settings-section .form-row > .form-row-inline > input { flex: 1 1 8rem; min-width: 0; }

/* 控件统一高度（设置页 + 所有弹窗 + 筛选栏） */
.settings-section input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
.settings-section select,
.modal-content input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
.modal-content select,
.filters-bar input[type="text"],
.filters-bar select {
    height: var(--control-h);
    box-sizing: border-box;
}

/* 下拉框：自绘主题化箭头 */
.settings-section select,
.modal-content select,
.filters-bar select,
.devices-footer .per-page select {
    appearance: none;
    -webkit-appearance: none;
    background-image: var(--select-arrow);
    background-repeat: no-repeat;
    background-position: right 0.6rem center;
    padding-right: 1.9rem;
}

/* 帮助图标：长说明折叠为 ? 图标（挂在标签文字后），点击弹出说明气泡 */
.hint-collapsed { display: none !important; }
/* 带 ? 图标的标签：flex 布局让文字内部换行、图标贴在文字侧边，永不单独掉行 */
label.has-help {
    display: flex !important;
    align-items: center;
    gap: var(--space-2);
}
label.has-help > .help-icon { flex: 0 0 auto; margin-left: 0; }
.help-icon {
    width: 16px; height: 16px; border-radius: 50%;
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-muted);
    font-size: 10px; font-weight: 600; line-height: var(--lh-single);
    display: inline-flex; align-items: center; justify-content: center;
    cursor: pointer; padding: 0; user-select: none;
    margin-left: 0.4rem; vertical-align: 1px;
}
.help-icon:hover { color: var(--primary); border-color: var(--primary); }
.help-popover {
    position: fixed; z-index: 3000;
    max-width: 340px;
    padding: var(--space-3) var(--space-4);
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-card, 0 8px 30px rgba(0,0,0,.35));
    color: var(--text);
    font-size: var(--fs-sm);
    line-height: var(--lh-normal);
}
.help-popover.hidden { display: none; }

/* 拓扑切图：后台刷新期间轻微降透明度提示（缓存快照已上屏，不遮挡操作） */
.topology-canvas-wrap.topo-refreshing { opacity: .82; transition: opacity .15s; }

/* 报表中心：预览容器 */
/* 预览不再是「框里再套一层滚动条」：iframe 高度由内容撑开（JS 按 scrollHeight 拉平），
   整页往下滚即可看完整张报表。故这里不设固定高度、不设 overflow。 */
.rpt-preview-wrap { position: relative; margin-top: 0.6rem; background: transparent; }
.rpt-preview { display: block; width: 100%; height: 480px; border: 0; background: transparent;
    transition: height .15s ease; }
.rpt-preview.rpt-loading { opacity: .5; }
.rpt-placeholder { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: var(--text-muted); pointer-events: none; }
.rpt-placeholder.hidden { display: none; }
/* 报表中心（重做版）：设置风格左侧边栏 + 工具栏 + 配置编辑器 */
.rpt-layout { margin-top: 0.6rem; }
.rpt-main { min-width: 0; }
.rpt-toolbar { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.rpt-toolbar-spacer { flex: 1 1 auto; }
.rpt-new-btn { color: var(--primary); font-weight: 600; }
.rpt-editor-meta { display: flex; gap: var(--space-6); flex-wrap: wrap; margin: var(--space-5) 0; }
.rpt-editor-meta .form-row { min-width: 260px; }
.rpt-editor-grid { display: grid; grid-template-columns: minmax(280px, 1fr) minmax(320px, 1.2fr); gap: var(--space-5); align-items: start; }
.rpt-editor-col h4 { margin: 0 0 var(--space-3); color: var(--text); }
#rpt-lib, #rpt-selected {
    border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-card);
    padding: var(--space-4); max-height: calc(100vh - 360px); overflow: auto; display: grid; gap: var(--space-3);
    align-content: start;
}
.rpt-lib-cat { border-bottom: 1px dashed var(--border); padding-bottom: 0.5rem; }
.rpt-lib-cat:last-child { border-bottom: none; }
.rpt-lib-cat-title { font-weight: 600; color: var(--text); margin-bottom: 0.3rem; }
.rpt-lib-item { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-1) 0; cursor: pointer; color: var(--text); font-size: var(--fs-sm); }
.rpt-sel-item {
    display: flex; align-items: center; gap: var(--space-3); border: 1px solid var(--border); border-radius: var(--radius-md);
    background: var(--bg); padding: var(--space-2) var(--space-3); cursor: grab; font-size: var(--fs-sm);
}
.rpt-sel-item.rpt-dragging { opacity: 0.5; }
.rpt-sel-item.rpt-drag-over { border-color: var(--primary); }
.rpt-sel-drag { color: var(--text-muted); cursor: grab; }
.rpt-sel-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rpt-sel-n { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--text-muted); white-space: nowrap; }
.rpt-sel-n input { width: 4.2em; height: 1.7rem; padding: 0 var(--space-1); }
.rpt-sel-remove { border: none; background: transparent; color: var(--text-muted); cursor: pointer; font-size: var(--fs-md); }
.rpt-sel-remove:hover { color: var(--error, #ef4444); }
@media (max-width: 1000px) { .rpt-editor-grid { grid-template-columns: 1fr; } }

/* 告警中心：警告级别文字色 + 规则矩阵输入紧凑化 */
.alc-sev-warning { color: var(--warn); font-weight: 600; }
.alert-rules-table td { vertical-align: middle; }
.alert-rules-table .check-row { gap: var(--space-3); }

/* 日志中心：类别切换按钮选中态（与流量页视图切换一致） */
.logsc-category-bar { flex-wrap: wrap; }
.logsc-category-bar .btn.active {
    background: var(--primary);
    color: #fff;
    border-color: var(--primary);
}

/* 日志中心：详情列允许换行、限制宽度保持表格可读 */
.logsc-detail { display: block; max-width: 560px; white-space: normal; word-break: break-word; line-height: var(--lh-normal); }
/* 日志正文里的关键片段高亮：IP=蓝、接口=青、设备名=紫。用低饱和底色 + 语义前景，
   浅色深色都读得清。三类用不同色，扫读时一眼分得出这段是地址、口还是设备。 */
.lg-hl-ip, .lg-hl-if, .lg-hl-dev {
    border-radius: 3px; padding: 0 2px; font-weight: 600;
}
.lg-hl-ip  { background: rgba(10, 105, 218, .14);  color: #0a69da; }
.lg-hl-if  { background: rgba(13, 148, 136, .16);  color: #0d9488; }
.lg-hl-dev { background: rgba(139, 92, 246, .16);  color: #7c3aed; }
@media (prefers-color-scheme: dark) {
    .lg-hl-ip  { background: rgba(96, 165, 250, .20); color: #93c5fd; }
    .lg-hl-if  { background: rgba(45, 212, 191, .18); color: #5eead4; }
    .lg-hl-dev { background: rgba(167, 139, 250, .20); color: #c4b5fd; }
}
:root[data-theme="dark"] .lg-hl-ip  { background: rgba(96, 165, 250, .20); color: #93c5fd; }
:root[data-theme="dark"] .lg-hl-if  { background: rgba(45, 212, 191, .18); color: #5eead4; }
:root[data-theme="dark"] .lg-hl-dev { background: rgba(167, 139, 250, .20); color: #c4b5fd; }
:root[data-theme="light"] .lg-hl-ip  { background: rgba(10, 105, 218, .14); color: #0a69da; }
:root[data-theme="light"] .lg-hl-if  { background: rgba(13, 148, 136, .16); color: #0d9488; }
:root[data-theme="light"] .lg-hl-dev { background: rgba(139, 92, 246, .16); color: #7c3aed; }
/* 告警标题即跳转入口：下划虚线提示可点，避免看起来像普通文本 */
.alc-title-link { color: inherit; text-decoration: none; border-bottom: 1px dashed currentColor; cursor: pointer; }
.alc-title-link:hover { color: var(--accent, #2f80ed); border-bottom-style: solid; }
/* 类型即过滤入口 */
.alc-type-link { color: inherit; text-decoration: none; border-bottom: 1px dashed currentColor; cursor: pointer; white-space: nowrap; }
.alc-type-link:hover { color: var(--accent, #2f80ed); border-bottom-style: solid; }
/* 告警内容：合并为一行；标题超出省略号（全文在悬浮提示里看），阈值始终可见 */
.alc-content { display: flex; align-items: baseline; gap: 6px; max-width: 540px; }
.alc-content .alc-line { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.alc-thr { flex: none; color: var(--text-muted, #888); font-size: .85em; white-space: nowrap; }
/* 触发时间：不换行，避免日期时间被折成两行 */
.alc-time { white-space: nowrap; }
/* AI工单：列表行可点进详情子页 */
#aiops-table tbody tr[data-aiops-id] { cursor: pointer; }
#aiops-table tbody tr[data-aiops-id]:hover { background: var(--surface-2, rgba(127,127,127,.06)); }
.aiops-detail-topbar { display: flex; align-items: center; gap: 12px; margin: 2px 0 14px; }
.aiops-detail-title { font-weight: 600; font-size: 1.05em; }
/* 工单概要条 + 受影响对象 + 相关日志 */
.aiops-summary-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; padding-bottom: 10px; border-bottom: 1px solid var(--border, rgba(127,127,127,.2)); }
.aiops-badge-lg { font-weight: 600; }
.aiops-cust { background: var(--accent-soft, rgba(47,128,237,.12)); color: var(--accent, #2f80ed); padding: 2px 10px; border-radius: 12px; font-weight: 600; }
.aiops-sb-fp { margin-left: auto; font-size: .8em; }
.aiops-facts { display: flex; flex-wrap: wrap; gap: 6px 18px; margin: 6px 0; }
.aiops-fact-k { color: var(--text-muted, #888); margin-right: 2px; }
.aiops-cust-line { margin: 8px 0; padding: 6px 10px; background: var(--accent-soft, rgba(47,128,237,.08)); border-left: 3px solid var(--accent, #2f80ed); border-radius: 4px; }
.aiops-subtitle { font-weight: 600; margin: 12px 0 4px; font-size: .92em; }
.aiops-imp-table th, .aiops-imp-table td { font-size: .85em; padding: 4px 8px; }
.aiops-logs { max-height: 280px; overflow: auto; background: var(--code-bg, rgba(0,0,0,.35)); color: var(--code-fg, #d6d6d6); border-radius: 6px; padding: 8px 10px; font-size: .8em; line-height: 1.45; white-space: pre; margin: 6px 0 0; }
/* 点击行展开的历史时间线 */
#alc-table tbody tr:not(.alc-detail-row) { cursor: pointer; }
.alc-row-open > td { border-bottom: none; }
.alc-detail-row > td { background: var(--surface-2, rgba(127,127,127,.06)); padding: 10px 16px; }
.alc-timeline { max-width: 900px; }
.alc-tl { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.alc-tl-item { display: flex; align-items: center; gap: 10px; font-size: .9em; }
.alc-tl-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--text-muted, #888); }
.alc-tl-dot.alc-tl-fired { background: var(--danger, #e5484d); }
.alc-tl-dot.alc-tl-resolved { background: var(--ok, #30a46c); }
.alc-tl-dot.alc-tl-acked { background: var(--warn, #f5a623); }
.alc-tl-time { flex: none; color: var(--text-muted, #888); min-width: 150px; }
.alc-tl-act.alc-tl-fired { color: var(--danger, #e5484d); font-weight: 600; }
.alc-tl-act.alc-tl-resolved { color: var(--ok, #30a46c); font-weight: 600; }
.alc-tl-act.alc-tl-acked { color: var(--warn, #f5a623); font-weight: 600; }
.alc-tl-actor { color: var(--accent, #2f80ed); }
.alc-tl-more { margin-top: 10px; }
.alc-tl-foot { margin-top: 8px; color: var(--text-muted, #888); }
/* 确认人：状态旁标注谁在处理，弱化但可辨 */
.alc-ack-who { font-size: .8em; color: var(--accent, #2f80ed); white-space: nowrap; }
#alc-table td { vertical-align: top; }
#logsc-table td { vertical-align: top; }
/* AI 处置中心：行内展开的分析卡 */
#aiops-table tbody tr:not(.aiops-detail-row) { cursor: pointer; }
.aiops-detail-row > td { background: var(--surface-2, rgba(127,127,127,.06)); padding: 12px 16px; }
.aiops-detail { display: flex; flex-direction: column; gap: 12px; max-width: 1360px; }
.aiops-card { border: 1px solid var(--border, rgba(127,127,127,.25)); border-radius: 8px; padding: 10px 14px; background: var(--surface, transparent); }
.aiops-card-h { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-bottom: 6px; }
.aiops-card-title { font-weight: 600; }
.aiops-conf { font-size: .9em; }
.aiops-rc { font-size: 1.02em; line-height: 1.5; margin: 4px 0; }
.aiops-reason { color: var(--text-muted, #888); }
.aiops-opt { margin-top: 8px; padding: 8px 10px; border-left: 3px solid var(--accent, #2f80ed); background: var(--surface-2, rgba(47,128,237,.06)); border-radius: 4px; white-space: pre-wrap; line-height: 1.5; }
.aiops-opt-lbl { display: block; font-weight: 600; color: var(--accent, #2f80ed); margin-bottom: 3px; }
.aiops-steps { margin: 6px 0 0; padding-left: 20px; display: flex; flex-direction: column; gap: 4px; }
.aiops-ro { font-size: .78em; color: var(--ok, #30a46c); border: 1px solid currentColor; border-radius: 4px; padding: 0 5px; margin-left: 6px; }
.aiops-alerts { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.aiops-alerts li { display: flex; gap: 8px; align-items: baseline; font-size: .92em; }
.aiops-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.aiops-steps li { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.aiops-ev { flex-basis: 100%; }
.aiops-transcript { max-height: 340px; overflow: auto; background: var(--code-bg, rgba(0,0,0,.35)); color: var(--code-fg, #d6d6d6); border-radius: 6px; padding: 10px 12px; font-size: .82em; line-height: 1.4; white-space: pre; margin: 6px 0 2px; }
.aiops-ev-meta { font-size: .78em; }
/* 急停按钮：开启时实心红常亮，提示当前处于停摆 */
#btn-aiops-kill.is-on { background: var(--danger, #e5484d); color: #fff; border-color: var(--danger, #e5484d); font-weight: 700; }
/* 诊断命令清晰显示（不加灰）：前置 $ 提示符 */
.aiops-cmd { font-family: var(--font-mono); font-size: .9em; color: var(--text, inherit); background: var(--code-bg, rgba(127,127,127,.12)); padding: 1px 8px; border-radius: 4px; }
.aiops-cmd::before { content: "$ "; color: var(--accent, #2f80ed); }
.aiops-step-st { font-size: .85em; }
/* 复现次数徽标 */
.aiops-recur { display: inline-block; font-size: .78em; font-weight: 700; color: var(--danger, #e5484d); border: 1px solid currentColor; border-radius: 4px; padding: 0 5px; margin-left: 4px; }

/* ============ 工单详情：三栏整体紧凑版 ============ */
.aiops-dt { border: 1px solid var(--border, rgba(127,127,127,.25)); border-radius: 10px; overflow: hidden; background: var(--bg-card, transparent); font-size: 10px; }
.aiops-ic { width: 1em; height: 1em; display: inline-block; vertical-align: -0.15em; flex: 0 0 auto; }
/* 顶部工单信息条 */
.aiops-dt-top { display: flex; gap: 12px; align-items: flex-start; border-left: 3px solid var(--text-muted, #888); padding: 10px 14px; }
.aiops-dt-top.status-fail { border-left-color: var(--danger, #e5484d); }
.aiops-dt-top.alc-sev-warning { border-left-color: var(--warn, #f5a623); }
.aiops-dt-topmain { flex: 1; min-width: 0; }
.aiops-dt-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.aiops-dt-no { font-size: .82em; }
.aiops-dt-h { font-size: 12px; font-weight: 600; }
.aiops-dt-kpis { display: flex; align-items: center; gap: 14px; margin-top: 5px; flex-wrap: wrap; color: var(--text-muted, #888); font-size: 10px; }
.aiops-dt-kpi b { color: var(--text, inherit); font-weight: 600; }
.aiops-dt-kpi .aiops-ic { width: 13px; height: 13px; color: var(--accent, #2f80ed); }
.aiops-dt-topact { display: flex; align-items: center; gap: 6px; flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; }
.aiops-dt-topact .aiops-ic { width: 14px; height: 14px; }
/* 诊断结论卡（确定性解析命令输出得出，置顶于「执行」节） */
.aiops-verdict { border: 1px solid var(--border, rgba(127,127,127,.25)); border-left: 3px solid var(--text-muted, #888); border-radius: 8px; padding: 9px 12px; margin-bottom: 10px; background: var(--bg-elevated, rgba(127,127,127,.05)); }
.aiops-verdict.ok { border-left-color: var(--success, var(--ok, #30a46c)); }
.aiops-verdict.warn { border-left-color: var(--warn, #f5a623); }
.aiops-verdict.bad { border-left-color: var(--danger, #e5484d); }
.aiops-verdict.noact { border-left-color: var(--text-muted, #888); }
.aiops-verdict.noact .aiops-verdict-h { color: var(--text-muted, #888); }
.aiops-noact-tag { margin-left: 8px; font-size: 11px; font-weight: 400; padding: 0 8px; border-radius: 100px;
    background: var(--bg-elevated, rgba(127,127,127,.14)); color: var(--text, inherit); }
.aiops-verdict-h { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--text-muted, #888); }
.aiops-verdict.ok .aiops-verdict-h { color: var(--success, var(--ok, #30a46c)); }
.aiops-verdict.bad .aiops-verdict-h { color: var(--danger, #e5484d); }
.aiops-verdict-h .aiops-ic { width: 14px; height: 14px; }
.aiops-verdict-t { font-size: 13.5px; line-height: 1.55; margin-top: 4px; }
.aiops-verdict-facts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 7px; }
.aiops-fact { font-size: 11.5px; padding: 1px 8px; border-radius: 100px; border: 1px solid var(--border, rgba(127,127,127,.3)); color: var(--text-muted, #888); cursor: help; }
.aiops-fact.ok { color: var(--success, var(--ok, #30a46c)); border-color: currentColor; }
.aiops-fact.bad { color: var(--danger, #e5484d); border-color: currentColor; }
/* 根因/建议：一条一行 */
.aiops-fl-ul { margin: 4px 0 0; padding-left: 18px; display: flex; flex-direction: column; gap: 3px; }
.aiops-fl-ul li { font-size: 12.5px; line-height: 1.5; }
.aiops-dt-opt .aiops-fl-ul li { color: var(--text, inherit); }
/* 相关接口行：图标按钮/业务编码/描述 */
.aiops-imp-graph { border: 0; background: none; padding: 0 2px; color: var(--accent, #2f80ed); cursor: pointer; display: inline-flex; align-items: center; }
.aiops-imp-graph:hover { filter: brightness(1.15); }
.aiops-imp-graph .aiops-ic { width: 13px; height: 13px; }
.aiops-svc-code { font-size: 11px; padding: 0 6px; border-radius: 4px; background: var(--bg-elevated, rgba(127,127,127,.12)); color: var(--text, inherit); }
.aiops-imp-desc { font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 320px; }
.aiops-imp-more { margin-top: 4px; border: 1px dashed var(--border, rgba(127,127,127,.35)); background: none; color: var(--accent, #2f80ed); font-size: 12px; padding: 3px 10px; border-radius: 6px; cursor: pointer; }
.aiops-imp-more:hover { background: var(--accent-soft, rgba(47,128,237,.1)); }

/* 日志问答（结构化检索 RAG）：提问条 + 回答卡 */
.log-qa-bar { display: flex; gap: var(--space-3); margin: var(--space-3) 0; }
.log-qa-bar input { flex: 1; min-width: 0; }
.log-qa-card { border: 1px solid var(--border, rgba(127,127,127,.25)); border-left: 3px solid var(--accent, #2f80ed);
    border-radius: var(--radius, 8px); background: var(--bg-card, transparent);
    padding: var(--space-3) var(--space-4); margin-bottom: var(--space-4); }
.log-qa-ev { margin-top: var(--space-3); }
.log-qa-ev summary { cursor: pointer; font-size: var(--fs-xs, 12px); color: var(--text-muted, #888); }
.log-qa-ev .li-logs { margin-top: var(--space-2); }

/* 日志洞察：模板详情里的原始日志样例 */
.li-logs { max-height: 220px; overflow: auto; border: 1px solid var(--border, rgba(127,127,127,.25));
    border-radius: var(--radius-sm, 6px); padding: var(--space-2) var(--space-3); }
.li-log { display: flex; gap: var(--space-3); padding: 2px 0; font-size: var(--fs-xs, 12px); line-height: 1.5; }
.li-log > span:last-child { min-width: 0; overflow-wrap: anywhere; }

/* 日志行的「AI 分析」按钮与结果弹层 */
.logsc-ai-btn { border: 1px solid var(--border, rgba(127,127,127,.3)); background: var(--bg-elevated, transparent);
    color: var(--accent, #2f80ed); font-size: var(--fs-xs, 12px); padding: 1px 9px;
    border-radius: var(--radius-pill, 100px); cursor: pointer; white-space: nowrap; }
.logsc-ai-btn:hover { background: var(--accent-soft, rgba(47,128,237,.12)); border-color: var(--accent, #2f80ed); }
.log-ai-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 10px 0 8px; }
.log-ai-meta { font-size: var(--fs-xs, 12px); margin-left: auto; }
.log-ai-summary { font-size: var(--fs-base, 14px); line-height: 1.6; }
.log-ai-sec { font-size: 11px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase;
    color: var(--text-muted, #888); margin: 12px 0 4px; }
.log-ai-cause { font-size: var(--fs-sm, 13px); line-height: 1.55; color: var(--text-secondary, var(--text-muted)); }
.log-ai-actions { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 4px; }
.log-ai-actions li { font-size: var(--fs-sm, 13px); line-height: 1.5; }

/* ===== 工单详情：八节点单列流水线布局 ===== */
/* 顶栏 sticky 常驻（56px 为全站头高） */
.aiops-dt-flow { border: 0; background: transparent; overflow: visible; }
.aiops-dt-flow .aiops-dt-top { position: sticky; top: 56px; z-index: 30; border: 1px solid var(--border, rgba(127,127,127,.25)); border-radius: 10px; background: var(--bg-card, #fff); box-shadow: var(--shadow, 0 2px 8px rgba(0,0,0,.06)); }
/* 轻磁吸：只在详情子页打开时挂到 html 上（proximity 不绑架滚轮） */
html.aiops-snap { scroll-snap-type: y proximity; }
.aiops-node { scroll-snap-align: start; scroll-margin-top: 128px; }
/* 左轨 + 单列 */
.aiops-flow { display: grid; grid-template-columns: 148px minmax(0, 1fr); gap: var(--space-5); margin-top: var(--space-5); align-items: start; }
.aiops-flow-rail { position: sticky; top: 132px; display: flex; flex-direction: column; gap: 2px; padding-left: 18px; position: sticky; }
.aiops-flow-rail { position: relative; position: sticky; }
.aiops-flow-line { position: absolute; left: 27px; top: 12px; bottom: 12px; width: 2px; background: var(--border, rgba(127,127,127,.3)); }
.aiops-flow-node { position: relative; display: block; padding: 5px 6px 5px 24px; border-radius: 8px; text-decoration: none; color: var(--text, inherit); cursor: pointer; }
.aiops-flow-node:hover { background: var(--bg-elevated, rgba(127,127,127,.08)); }
.aiops-flow-node.current { background: var(--accent-soft, rgba(47,128,237,.12)); }
.aiops-flow-node .aiops-flow-dot { position: absolute; left: 3px; top: 7px; }
.aiops-flow-dot { width: 20px; height: 20px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 10.5px; font-weight: 700; background: var(--bg-elevated, rgba(127,127,127,.1)); border: 1.5px solid var(--border, rgba(127,127,127,.3)); color: var(--text-muted, #888); flex: none; z-index: 1; }
.aiops-flow-dot .aiops-ic { width: 11px; height: 11px; }
.aiops-flow-dot.done { background: var(--success, var(--ok, #30a46c)); border-color: transparent; color: #fff; }
.aiops-flow-dot.active { background: var(--primary, var(--accent, #2f80ed)); border-color: transparent; color: #fff; }
.aiops-flow-dot.warn { background: var(--warn, #f5a623); border-color: transparent; color: #fff; }
.aiops-flow-lbl { display: block; font-size: var(--fs-sm, 13px); line-height: 1.3; }
.aiops-flow-node.current .aiops-flow-lbl { color: var(--accent, #2f80ed); font-weight: 600; }
.aiops-flow-sub { display: block; font-size: 10.5px; color: var(--text-muted, #888); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 内容节：一张连续的工单纸——不再一节一卡。
   一条贯穿全页的阶段线(::before)把 8 个节点物理串起来，节点圆点长在线上
   (box-shadow 用底色在线上冲出缺口)，内容悬挂在线右侧。视觉上是一份文档，不是八张卡。 */
.aiops-flow-main { display: block; min-width: 0; max-width: 980px; position: relative;
    background: var(--bg-card, #fff); border: 1px solid var(--border, rgba(127,127,127,.25));
    border-radius: 12px; }
.aiops-flow-main::before { content: ""; position: absolute; left: 29px; top: 28px; bottom: 28px;
    width: 2px; background: var(--border, rgba(127,127,127,.28)); }
.aiops-node { border: 0; border-radius: 0; background: transparent; overflow: visible; position: relative; }
.aiops-node-h { display: flex; align-items: center; gap: 10px; padding: 18px 20px 4px; }
.aiops-node-h .aiops-flow-dot { box-shadow: 0 0 0 4px var(--bg-card, #fff); }
.aiops-node-t { font-size: var(--fs-base, 14px); font-weight: 600; }
.aiops-node-sub { font-size: var(--fs-xs, 12px); color: var(--text-muted, #888); }
.aiops-node-extra { margin-left: auto; display: inline-flex; align-items: center; gap: 8px; }
.aiops-node-b { padding: 6px 20px 10px 58px; }
.aiops-node:last-child .aiops-node-b { padding-bottom: 18px; }
.aiops-node-pending .aiops-node-b, .aiops-node-pending .aiops-node-t { opacity: .6; }
/* 节内构件 */
.aiops-fl-sub { font-size: 11px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase; color: var(--text-muted, #888); margin: 10px 0 6px; display: flex; align-items: center; gap: 8px; }
.aiops-fl-sub:first-child { margin-top: 0; }
.aiops-fl-kvs { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 2px 18px; }
.aiops-fl-kv { display: flex; justify-content: space-between; gap: 10px; padding: 3px 0; font-size: 12.5px; border-bottom: 1px dashed color-mix(in srgb, var(--border, #888) 55%, transparent); }
.aiops-fl-kv > span:first-child { color: var(--text-muted, #888); flex-shrink: 0; }
.aiops-fl-kv > span:last-child { min-width: 0; overflow-wrap: anywhere; text-align: right; }
.aiops-fl-empty { padding: 14px 0; font-size: 12.5px; color: var(--text-muted, #888); }
.aiops-fl-logs summary { cursor: pointer; font-size: 12.5px; color: var(--text-muted, #888); margin-top: 8px; }
.aiops-fl-fb { display: flex; align-items: center; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.aiops-fl-fbtip { font-size: 11.5px; }
.aiops-fl-act { display: flex; align-items: center; gap: 8px; padding: 4px 0; font-size: 12.5px; border-bottom: 1px solid var(--border, rgba(127,127,127,.1)); }
.aiops-fl-act:last-child { border-bottom: 0; }
.aiops-fl-actcmd { font-family: var(--font-mono, ui-monospace, monospace); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.aiops-fl-cust { font-size: 11.5px; }
/* 中屏：左轨收成纯圆点 */
@media (max-width: 1100px) {
    .aiops-flow { grid-template-columns: 44px minmax(0, 1fr); }
    .aiops-flow-lbl, .aiops-flow-sub { display: none; }
    .aiops-flow-rail { padding-left: 8px; }
    .aiops-flow-line { left: 17px; }
}
/* 窄屏：轨转顶部横向进度条，随顶栏吸顶 */
@media (max-width: 760px) {
    .aiops-flow { display: block; }
    .aiops-flow-rail { position: sticky; top: 152px; z-index: 29; flex-direction: row; gap: 0; padding: 6px 4px; margin: var(--space-3) 0 var(--space-4); background: var(--bg-card, #fff); border: 1px solid var(--border, rgba(127,127,127,.25)); border-radius: 10px; overflow-x: auto; }
    .aiops-flow-line { display: none; }
    .aiops-flow-node { flex: 1 1 0; min-width: 40px; text-align: center; padding: 4px 2px; }
    .aiops-flow-node .aiops-flow-dot { position: static; margin: 0 auto; }
    .aiops-flow-lbl { display: block; font-size: 10.5px; margin-top: 2px; }
    .aiops-flow-sub { display: none; }
    .aiops-node { scroll-margin-top: 190px; }
    .aiops-flow-main::before { left: 21px; }
    .aiops-node-h { padding: 14px 12px 4px; }
    .aiops-node-b { padding: 4px 12px 8px 42px; }
}

/* ===== 八阶段流水线进度条（采集→分析→根因→建议→执行→验证→关闭→学习） ===== */
.aiops-stagebar { display: flex; align-items: flex-start; padding: 12px 14px 8px; border-top: 1px solid var(--border, rgba(127,127,127,.2)); overflow-x: auto; }
.aiops-stage { flex: 1 1 0; min-width: 64px; text-align: center; }
.aiops-stage-dot { width: 22px; height: 22px; margin: 0 auto; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 9px; font-weight: 700; background: var(--bg-elevated, rgba(127,127,127,.1)); border: 1.5px solid var(--border, rgba(127,127,127,.3)); color: var(--text-muted, #888); }
.aiops-stage-dot .aiops-ic { width: 12px; height: 12px; }
.aiops-stage-dot.done { background: var(--success, var(--ok, #30a46c)); border-color: transparent; color: #fff; }
.aiops-stage-dot.active { background: var(--primary, var(--accent, #2f80ed)); border-color: transparent; color: #fff; }
.aiops-stage-dot.warn { background: var(--warn, #f5a623); border-color: transparent; color: #fff; }
.aiops-stage-lbl { font-size: 10px; margin-top: 4px; color: var(--text-muted, #888); }
.aiops-stage-lbl.done { color: var(--text, inherit); font-weight: 500; }
.aiops-stage-lbl.active { color: var(--primary, var(--accent, #2f80ed)); font-weight: 600; }
.aiops-stage-lbl.warn { color: var(--warn, #f5a623); font-weight: 600; }
.aiops-stage-sub { font-size: 9px; color: var(--text-muted, #888); margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.aiops-stage-line { flex: 0 0 18px; height: 2px; background: var(--border, rgba(127,127,127,.3)); margin-top: 10px; }
.aiops-stage-line.done { background: var(--success, var(--ok, #30a46c)); }
/* 诊断证据的命令来源徽标 */
.aiops-src-badge { font-size: 9px; margin-left: 6px; text-transform: none; letter-spacing: 0; font-weight: 400; }
/* 知识库：从工单跳转过来时高亮定位行 */
tr.kb-focus > td { background: var(--accent-soft, rgba(47,128,237,.12)); }

/* 两栏：主内容 + 右侧边栏 */
.aiops-dt-grid { display: grid; grid-template-columns: minmax(0,1fr) 320px; border-top: 1px solid var(--border, rgba(127,127,127,.2)); }
.aiops-dt-col { min-width: 0; }
.aiops-dt-col + .aiops-dt-col { border-left: 1px solid var(--border, rgba(127,127,127,.2)); }
/* 小节标题 */
.aiops-dt-sec { display: flex; align-items: center; gap: 6px; padding: 7px 12px 5px; font-size: 9px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase; color: var(--text-muted, #888); background: var(--surface-2, rgba(127,127,127,.05)); border-bottom: 1px solid var(--border, rgba(127,127,127,.18)); border-top: 1px solid var(--border, rgba(127,127,127,.18)); }
.aiops-dt-col > .aiops-dt-sec:first-child { border-top: 0; }
.aiops-dt-sec .aiops-ic { width: 14px; height: 14px; }
.aiops-dt-sec > span:first-of-type { flex: 0 0 auto; }
.aiops-dt-secact, .aiops-dt-model, .aiops-dt-conf { text-transform: none; letter-spacing: 0; font-weight: 400; }
.aiops-dt-model { margin-left: auto; font-size: 9px; }
.aiops-dt-conf { margin-left: 6px; }
.aiops-dt-cp { display: inline-flex; align-items: center; gap: 3px; margin-left: 6px; font-size: 9px; color: var(--text-muted, #888); cursor: pointer; padding: 1px 6px; border: 1px solid var(--border, rgba(127,127,127,.3)); border-radius: 5px; background: var(--bg-elevated, transparent); }
.aiops-dt-cp:hover { color: var(--accent, #2f80ed); border-color: var(--accent, #2f80ed); }
.aiops-dt-cp .aiops-ic { width: 12px; height: 12px; }
.aiops-dt-secact { display: inline-flex; gap: 4px; margin-left: 6px; }
.aiops-dt-fb { display: inline-flex; align-items: center; padding: 1px 6px; border: 1px solid var(--border, rgba(127,127,127,.3)); border-radius: 5px; background: var(--bg-elevated, transparent); color: var(--text-muted, #888); cursor: pointer; }
.aiops-dt-fb .aiops-ic { width: 14px; height: 14px; }
.aiops-dt-fb.is-on.ok { color: #fff; background: var(--success, var(--ok, #30a46c)); border-color: transparent; }
.aiops-dt-fb.is-on.bad { color: #fff; background: var(--danger, #e5484d); border-color: transparent; }
/* key-value 行 */
.aiops-dt-kv { display: flex; justify-content: space-between; gap: 8px; padding: 4px 12px; font-size: 10px; border-bottom: 1px solid var(--border, rgba(127,127,127,.12)); }
.aiops-dt-kv .aiops-dt-k { color: var(--text-muted, #888); flex-shrink: 0; }
.aiops-dt-kv > span:last-child { text-align: right; min-width: 0; overflow-wrap: anywhere; }
/* 中栏内容体 */
.aiops-dt-body { padding: 8px 12px; }
.aiops-dt-rc { font-size: 11px; line-height: 1.55; }
.aiops-dt-reason { color: var(--text-muted, #888); font-size: 10px; line-height: 1.5; margin-top: 6px; white-space: pre-wrap; }
.aiops-dt-opt { margin-top: 8px; font-size: 10px; color: var(--text, inherit); line-height: 1.5; padding: 7px 10px; border-left: 3px solid var(--accent, #2f80ed); background: var(--surface-2, rgba(47,128,237,.06)); border-radius: 0 6px 6px 0; }
.aiops-dt-opt b { color: var(--accent, #2f80ed); }
.aiops-dt-empty { padding: 4px 0; font-size: 10px; }
/* 诊断证据：终端块（固定深色，模拟真实 CLI，区别于普通文本） */
.aiops-cli-list { display: flex; flex-direction: column; gap: 8px; }
.aiops-cli { border: 1px solid rgba(255,255,255,.08); border-radius: 6px; overflow: hidden; background: #0d1117; }
.aiops-cli-h { display: flex; align-items: center; gap: 6px; padding: 5px 9px; background: rgba(255,255,255,.04); border-bottom: 1px solid rgba(255,255,255,.08); }
.aiops-cli-h .aiops-ic { width: 13px; height: 13px; color: #768390; flex-shrink: 0; }
.aiops-cli-h.ok .aiops-ic { color: #3fb950; }
.aiops-cli-h.bad .aiops-ic { color: #f85149; }
.aiops-cli-h.run .aiops-ic { color: #d29922; }
.aiops-cli-h.run .aiops-ic { animation: aiops-spin 1s linear infinite; }
@keyframes aiops-spin { to { transform: rotate(360deg); } }
.aiops-cli-cmd { font-family: var(--font-mono); font-size: 9px; color: #adbac7; flex: 1; min-width: 0; overflow-x: auto; white-space: nowrap; }
.aiops-cli-h .aiops-dt-cp { color: #768390; border-color: rgba(255,255,255,.12); background: rgba(255,255,255,.04); }
.aiops-cli-h .aiops-dt-cp:hover { color: #adbac7; border-color: rgba(255,255,255,.3); }
.aiops-cli-out { margin: 0; padding: 8px 12px; font-family: var(--font-mono); font-size: 9px; line-height: 1.5; color: #adbac7; background: #0d1117; overflow-x: auto; white-space: pre; max-height: 320px; overflow-y: auto; }
/* 跟单过程 */
.aiops-dt-notes { display: flex; flex-direction: column; }
.aiops-dt-note { display: flex; gap: 8px; padding: 6px 0; border-bottom: 1px solid var(--border, rgba(127,127,127,.12)); }
.aiops-dt-note:last-child { border-bottom: 0; }
.aiops-dt-av { flex-shrink: 0; width: 22px; height: 22px; border-radius: 50%; background: var(--surface-2, rgba(127,127,127,.12)); display: flex; align-items: center; justify-content: center; font-size: 9px; font-weight: 600; color: var(--text, inherit); }
.aiops-dt-av.sys { background: var(--accent-soft, rgba(47,128,237,.14)); color: var(--accent, #2f80ed); }
.aiops-dt-note-b { min-width: 0; font-size: 10px; line-height: 1.45; }
.aiops-dt-note-m { display: block; font-size: 9px; margin-top: 1px; }
.aiops-dt-noteadd { display: flex; gap: 6px; padding: 8px 0 4px; }
.aiops-dt-noteinput { flex: 1; min-width: 0; font-size: 10px; padding: 5px 9px; border: 1px solid var(--border, rgba(127,127,127,.3)); border-radius: 6px; background: var(--bg-elevated, transparent); color: var(--text, inherit); }
/* 受影响对象 / 关联告警 */
.aiops-dt-subtle { font-size: 9px; color: var(--text-muted, #888); padding: 6px 12px 3px; }
.aiops-dt-imp { display: flex; align-items: center; gap: 6px; padding: 3px 12px; font-size: 10px; }
.aiops-dt-imp-ip { margin-left: auto; }
.aiops-dt-more { font-size: 9px; color: var(--text-muted, #888); padding: 2px 12px 6px; }
.aiops-vrf-pill { font-size: 9px; padding: 0 7px; line-height: 17px; border-radius: 100px; background: var(--accent-soft, rgba(47,128,237,.12)); color: var(--accent, #2f80ed); }
.aiops-dt-al { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 12px; font-size: 10px; border-bottom: 1px solid var(--border, rgba(127,127,127,.12)); }
.aiops-dt-al:last-child { border-bottom: 0; }
.aiops-dt-al-l { display: flex; align-items: center; gap: 6px; min-width: 0; }
.aiops-dt-al-t { flex-shrink: 0; font-size: 9px; }
.aiops-dt-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; background: var(--text-muted, #888); }
.aiops-dt-dot.status-fail { background: var(--danger, #e5484d); }
.aiops-dt-dot.alc-sev-warning { background: var(--warn, #f5a623); }
/* 工单时间线（右栏） */
.aiops-dt-tl { position: relative; padding: 8px 12px 10px 26px; }
.aiops-dt-tl::before { content: ""; position: absolute; left: 16px; top: 12px; bottom: 12px; width: 2px; background: var(--border, rgba(127,127,127,.25)); }
.aiops-dt-tl-i { position: relative; margin-bottom: 10px; }
.aiops-dt-tl-i:last-child { margin-bottom: 0; }
.aiops-dt-tl-dot { position: absolute; left: -14px; top: 3px; width: 10px; height: 10px; border-radius: 50%; background: var(--text-muted, #888); border: 2px solid var(--bg-card, #fff); }
.aiops-dt-tl-dot.alc-tl-fired { background: var(--danger, #e5484d); }
.aiops-dt-tl-dot.alc-tl-resolved { background: var(--ok, #30a46c); }
.aiops-dt-tl-dot.alc-tl-acked { background: var(--warn, #f5a623); }
.aiops-dt-tl-lbl { font-size: 10px; font-weight: 500; }
.aiops-dt-tl-t { margin-left: 6px; font-size: 9px; }
.aiops-dt-tl-d { display: block; font-size: 9px; margin-top: 1px; }
/* 可跳转链接 */
.aiops-lnk { color: var(--accent, #2f80ed); text-decoration: none; cursor: pointer; display: inline-flex; align-items: center; gap: 3px; }
.aiops-lnk:hover { text-decoration: underline; }
.aiops-lnk .aiops-ic { width: 12px; height: 12px; }
/* 原始配置弹层 */
.aiops-rawcfg-body { max-height: 68vh; margin: 10px 0 0; border-radius: 6px; }
@media (max-width: 980px) {
    .aiops-dt-grid { grid-template-columns: 1fr; }
    .aiops-dt-col + .aiops-dt-col { border-left: 0; border-top: 1px solid var(--border, rgba(127,127,127,.2)); }
}
/* ===== AIOPS 工作台：左侧边栏（对齐堡垒机 rack-side-nav 风格，窄栏无图标）===== */
.aiops-workspace { display: flex; gap: var(--space-5); align-items: flex-start; min-height: 60vh; }
.aiops-rail { flex: 0 0 150px; }
/* 角标需要文字左/角标右：在 rack-nav-btn 基础上补 flex（其余样式全走 rack-nav-btn） */
.aiops-rail .rack-nav-btn { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.aiops-rail-badge { font-size: .72em; min-width: 18px; text-align: center; padding: 1px 6px; border-radius: 10px; background: var(--danger, #e5484d); color: #fff; font-weight: 700; }
.aiops-rail-badge:empty { display: none; }
.aiops-rail-badge.is-warn { background: var(--warn, #f5a623); }
.aiops-main { flex: 1; min-width: 0; }
/* 日志分类已折进 AIOPS 左栏：藏掉日志中心自带的侧栏，避免出现三栏。
   注意 .cloud-layout 是「172px+1fr」两列 grid——侧栏藏掉后主区会掉进 172px 那列
   被挤成一条（实测踩过），必须把内嵌的布局退化为单列 */
#panel-aiops #logsc-categories { display: none; }
#panel-aiops #panel-logs-center .cloud-layout { display: block; }
/* 左栏组间分隔线（Syslog 组与「系统日志」入口之间） */
.aiops-rail .rack-nav-sep { border-top: 1px solid var(--border); margin: var(--space-2) 0 var(--space-1); }
.aiops-sub { display: none; }
.aiops-sub.active { display: block; }
/* 内嵌模块面板：抵消全局 showTab 对 .panel:not(.active) 的隐藏，可见性交给 .aiops-sub 控制 */
.aiops-main .panel { display: block !important; }
@media (max-width: 760px) {
  .aiops-workspace { flex-direction: column; }
  .aiops-rail { flex-direction: row; flex: none; border-right: none; border-bottom: 1px solid var(--border, rgba(127,127,127,.2)); overflow-x: auto; padding: 4px 0; }
  .aiops-rail-item { white-space: nowrap; }
  .aiops-main { padding-left: 0; padding-top: 10px; }
}
/* LLM 设置盒 */
.aiops-llm-box { border: 1px solid var(--border, rgba(127,127,127,.25)); border-radius: 8px; padding: 12px 16px; margin: 8px 0 4px; max-width: 640px; display: flex; flex-direction: column; gap: 10px; }
.aiops-llm-row { display: flex; align-items: center; gap: 10px; }
.aiops-llm-row label { min-width: 84px; }
.aiops-llm-row input, .aiops-llm-row select, .aiops-llm-row textarea { flex: 1; max-width: 460px; }
.aiops-llm-row textarea { resize: vertical; font-size: .85em; }

/* ---- 表单/设置卡通用布局工具类（替代散落的内联样式，保证各处间距统一） ---- */
.field-stack { width: 100%; }
.field-full { width: 100%; }
.field-search { width: 100%; margin-bottom: 6px; }
.btn-row { display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; margin-bottom: 6px; }
.check-row { display: flex; gap: var(--space-5); align-items: center; flex-wrap: wrap; }
.inline-actions { display: flex; gap: var(--space-3); flex-wrap: wrap; align-items: center; }
.inline-actions-gap { margin-top: 6px; }
.scroll-box { max-height: 200px; overflow-y: auto; }
.block-check { display: block; margin-bottom: 6px; }
.sub-label { display: block; font-size: var(--fs-sm); color: var(--text-muted); }
.ix-merge-row { width: 100%; display: flex; gap: var(--space-4); align-items: flex-start; }
.ix-merge-check { flex: 0 0 auto; margin-top: 4px; }
.ix-merged-box {
    flex: 1; min-width: 0; max-height: 140px; overflow-y: auto;
    border: 1px solid var(--border); border-radius: var(--radius-md);
    padding: var(--space-2) var(--space-3); font-size: var(--fs-sm); color: var(--text-muted);
    overflow-wrap: anywhere;
}
/* 自动化规则弹窗：预览内容多时不允许把弹窗撑宽 */
#modal-topology-auto-rule .modal-content { max-width: min(92vw, 860px); }
.ix-merged-item { margin-bottom: 6px; }
.ix-merged-detail { opacity: .8; }

/* 外部邻居云朵节点：单纯一朵不规则的云 */
.topology-ext-cloud {
    fill: #ffffff;
    stroke: #7fa8d0;
    stroke-width: 1.6;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
}
.topology-ext-cloud-center { fill: #f4f9ff; stroke: #3f7fc4; stroke-width: 2; }
/* 提高特异性覆盖 .topology-node text 的 fill:var(--text)（暗色主题下为白色），
   否则白云上出现白字看不清。云标签固定用深色文字，且去掉深色描边光晕。 */
.topology-node text.topology-ext-cloud-label,
.topology-ext-cloud-label { fill: #24425f; font-weight: 600; text-anchor: middle; dominant-baseline: middle; stroke: none; paint-order: normal; }
.topology-node text.topology-ext-cloud-label-center,
.topology-ext-cloud-label-center { fill: #2563a8; font-weight: 600; stroke: none; }
/* 浅色主题：白云在白底画布上对比不足，加深描边并微调填充 */
[data-theme="light"] .topology-ext-cloud { fill: #fbfdff; stroke: #5b8ec4; stroke-width: 1.8; }
[data-theme="light"] .topology-ext-cloud-center { fill: #eef6ff; stroke: #2f6cad; }
.topo-combo-item {
    padding: var(--space-2) var(--space-4);
    cursor: pointer;
    font-size: var(--fs-sm);
    color: var(--text, #e6ecf5);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.topo-combo-item:hover { background: rgba(56, 189, 248, .16); }

/* ===== 配置下发（Config Push） ===== */
/* 下划线式子菜单（配置下发风格）——全局统一：SLA 矩阵、日志中心等复用 .subtab-bar / .subtab-item */
.cfgpush-subtabs, .subtab-bar { display: flex; gap: var(--space-3); margin-bottom: 1rem; flex-wrap: wrap; border-bottom: 1px solid var(--border); }
.cfgpush-subtab, .subtab-item {
    background: none; border: none; border-bottom: 2px solid transparent;
    padding: var(--space-3) var(--space-5); cursor: pointer; color: var(--text-muted);
    font-size: var(--fs-sm); font-weight: 600;
}
.cfgpush-subtab:hover, .subtab-item:hover { color: var(--text); }
.cfgpush-subtab.active, .subtab-item.active { color: var(--accent); border-bottom-color: var(--accent); }
.cfgpush-section { display: none; }
.cfgpush-section.active { display: block; }

/* 浮层 */
/* 全屏子页（替代弹窗） */
#cfgpush-list.hidden, .cfgpush-form-view.hidden { display: none; }

/* 通用面板内全屏子页（设备管理/邻居/DCIM 新增编辑表单，页面式版式，观感同配置下发） */
.panel-form-view.hidden { display: none; }
.panel-form-view { max-width: 1100px; }
.panel-form-head { display: flex; align-items: center; gap: var(--space-5); margin-bottom: 1rem; padding-bottom: 0.75rem; border-bottom: 1px solid var(--border); }
.panel-form-head h3 { margin: 0; font-size: var(--fs-lg); }
/* 子页打开时隐藏面板标题行的列表操作按钮（大标题保留） */
.panel:has(> .panel-form-view:not(.hidden)) > .panel-header .panel-actions { display: none; }
/* 页面式表单：标签在输入框上方（粗体），控件通铺；短字段两列并排，长内容占整行 */
.panel-form-view .form {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-1) var(--space-7);
    max-width: 1100px;
}
.panel-form-view .form-row { margin: 0 0 var(--space-5); }
.panel-form-view .form-row label {
    display: block;
    font-weight: 600;
    color: var(--text);
    font-size: var(--fs-sm);
    margin: 0 0 var(--space-2);
}
.panel-form-view .form-row input:not([type="checkbox"]):not([type="radio"]),
.panel-form-view .form-row select {
    width: 100%;
    height: 36px;
    box-sizing: border-box;
    font-weight: 400;
}
.panel-form-view textarea { width: 100%; }
/* 含长文本/提示/输入组合的行占整行 */
.panel-form-view .form-row:has(textarea),
.panel-form-view .form-row:has(.form-hint),
.panel-form-view .form-row:has(.form-row-inline),
.panel-form-view .form > .form-hint,
.panel-form-view .form > p { grid-column: 1 / -1; }
.panel-form-view .form-row .form-hint { margin-top: 0.3rem; }
/* 复选框行：勾选框+文字一行 */
.panel-form-view .form-row .form-label-inline,
.panel-form-view .form-row > .form-label-inline {
    display: flex; align-items: center; gap: var(--space-3);
    color: var(--text); font-weight: 600; font-size: var(--fs-sm); margin: 0;
}
.panel-form-view .form-row .form-label-inline input[type="checkbox"] { width: 15px; height: 15px; margin: 0; flex: 0 0 auto; }
/* 输入框+按钮组合行 */
.panel-form-view .form-row .form-row-inline { display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; }
.panel-form-view .form-row .form-row-inline > input { flex: 1 1 10rem; min-width: 0; height: 36px; box-sizing: border-box; }
.panel-form-view .form-row .form-row-inline > .btn { flex: 0 0 auto; white-space: nowrap; }
/* 底部操作按钮区（同配置下发页脚） */
.panel-form-body .modal-actions,
.panel-form-view .modal-actions {
    grid-column: 1 / -1;
    display: flex; gap: var(--space-3); justify-content: flex-start;
    margin-top: 1.2rem; padding-top: 1rem; border-top: 1px solid var(--border);
}
/* 邻居/DCIM 已是「标签在上」网格：统一为页面式（去卡片边框、标签加粗、控件 36px） */
.panel-form-view .form-grid-compact { max-width: 1100px; }
.panel-form-view .form-grid-compact label { color: var(--text); font-weight: 600; }
.panel-form-view .form-grid-compact input,
.panel-form-view .form-grid-compact select { height: 36px; box-sizing: border-box; font-weight: 400; }
.panel-form-view .rack-edit-card {
    border: none; box-shadow: none; background: transparent; padding: 0;
    gap: var(--space-5) var(--space-7); max-width: 1100px;
}
.panel-form-view .rack-edit-card label { color: var(--text); font-weight: 600; font-size: var(--fs-sm); }
.panel-form-view .rack-edit-card input,
.panel-form-view .rack-edit-card select { height: 36px; box-sizing: border-box; font-weight: 400; }
.panel-form-view .rack-edit-card button[type="submit"] {
    justify-self: start; margin-top: 0.6rem;
}
/* DCIM 表单子页在右侧内容区打开：左侧导航保持可见，仅隐藏当前列表区 */
.rack-main-area.rack-form-open .rack-section-page { display: none; }
/* 表单/机柜图形视图子页作为内容列的直接子项，铺满该列宽度（否则被 max-width 压扁在左上角） */
.rack-main-area > #rack-form-modal,
.rack-main-area > #rack-detail-modal { width: 100%; max-width: none; }
.rack-main-area > #rack-form-modal .form,
.rack-main-area > #rack-form-modal .rack-edit-card { max-width: 1000px; }
/* 机柜图形视图子页：去掉原弹窗的固定宽/居中，铺满内容区 */
.rack-detail-page { width: 100%; }
#rack-detail-modal .rack-modal-head { flex-wrap: wrap; }
.cfgpush-form-head { display: flex; align-items: center; gap: var(--space-5); margin-bottom: 1rem; padding-bottom: 0.75rem; border-bottom: 1px solid var(--border); }
.cfgpush-form-head h3 { margin: 0; font-size: var(--fs-lg); }
.cfgpush-form-body { max-width: 1100px; }
.cfgpush-form-foot { display: flex; gap: var(--space-3); margin-top: 1.2rem; padding-top: 1rem; border-top: 1px solid var(--border); flex-wrap: wrap; }

/* 设备穿梭框 */
.cfgpush-xfer { display: grid; grid-template-columns: 1fr auto 1fr; gap: var(--space-4); align-items: stretch; }
.cfgpush-xfer-side { display: flex; flex-direction: column; border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden; min-height: 260px; }
.cfgpush-xfer-filters { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: var(--space-3); border-bottom: 1px solid var(--border); background: var(--bg-elevated, rgba(0,0,0,0.12)); }
.cfgpush-xfer-filters .cfgpush-input-inline { flex: 1 1 45%; min-width: 0; }
.cfgpush-xfer-bar { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--border); font-size: var(--fs-xs); }
/* 穿梭框内的搜索框占满该栏宽度；条目不折行，超长用省略号——
   折行会让左右两栏行高错开，看起来就是"错位" */
.ext-xfer-search { width: 100%; }
/* 【必须 flex:0 0 auto】父级 .cfgpush-xfer-list 是 column flex，子项默认 flex-shrink:1；
   而 overflow:hidden 会把 flex 项的自动最小尺寸从"内容高度"变成 0，
   于是几百个条目在 320px 容器里被各自压成 0.5px —— 列表看起来是空的。
   加了 overflow 就必须同时锁死 flex-shrink。 */
.cfgpush-check { display: flex; flex: 0 0 auto; align-items: center; gap: var(--space-2); min-height: 1.6rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cfgpush-xfer-list { flex: 1; overflow-y: auto; max-height: 320px; padding: var(--space-2) var(--space-3); display: flex; flex-direction: column; gap: var(--space-1); }
.cfgpush-xfer-mid { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-3); }
.cfgpush-dev-meta { color: var(--text-muted); font-size: var(--fs-2xs); margin-left: 0.4rem; }
@media (max-width: 860px) {
    .cfgpush-xfer { grid-template-columns: 1fr; }
    .cfgpush-xfer-mid { flex-direction: row; }
}

.cfgpush-lbl { display: block; margin: var(--space-4) 0 var(--space-1); font-size: var(--fs-sm); font-weight: 600; color: var(--text); }
.cfgpush-lbl:first-child { margin-top: 0; }
.cfgpush-lbl .req { color: var(--error); margin-left: 2px; }
.cfgpush-input, .cfgpush-textarea { width: 100%; padding: var(--space-3) var(--space-3); border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-elevated, var(--bg)); color: var(--text); font-size: var(--fs-sm); }
.cfgpush-textarea { font-family: var(--font-mono); resize: vertical; }
.cfgpush-input-inline { padding: var(--space-1) var(--space-3); border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-elevated, var(--bg)); color: var(--text); font-size: var(--fs-xs); }
/* 统一「配置下发」页所有下拉框/单行输入框高度（对齐品牌筛选框），消除跨浏览器 select 高度漂移与拥挤感 */
#panel-config-push select,
#panel-config-push input:not([type="checkbox"]):not([type="radio"]) {
    height: 36px;
    box-sizing: border-box;
    line-height: 1.2;
    vertical-align: middle;
    font-size: var(--fs-sm);
}
.cfgpush-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }
.cfgpush-checklist { max-height: 180px; overflow-y: auto; border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--space-3) var(--space-4); display: flex; flex-direction: column; gap: var(--space-1); }
.cfgpush-check { display: flex; align-items: center; gap: var(--space-2); font-size: var(--fs-sm); cursor: pointer; }
.cfgpush-var { display: flex; align-items: center; gap: var(--space-3); margin: var(--space-1) 0; }
.cfgpush-var span { min-width: 120px; font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-muted); }
.cfgpush-var .cfgpush-input-inline { flex: 1; }
.cfgpush-pre { background: var(--bg-elevated, rgba(0,0,0,0.15)); border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--space-3) var(--space-4); font-family: var(--font-mono); font-size: var(--fs-xs); white-space: pre-wrap; word-break: break-all; max-height: 300px; overflow-y: auto; margin: 0; }
.cfgpush-risk-box { margin: var(--space-3) 0; padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); background: rgba(245, 158, 11, 0.12); border: 1px solid rgba(245, 158, 11, 0.3); font-size: var(--fs-sm); }
.cfgpush-risk-inline { margin: var(--space-2) 0; display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.cfgpush-detail-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-3) var(--space-5); margin-bottom: 0.8rem; }
.cfgpush-detail-grid > div { display: flex; flex-direction: column; gap: var(--space-1); }
.cfgpush-detail-grid label { font-size: var(--fs-2xs); color: var(--text-muted); }
@media (max-width: 720px) {
    .cfgpush-row, .cfgpush-detail-grid { grid-template-columns: 1fr; }
}

/* ===================== 设备详情页 ===================== */
.panel-header-left { display: flex; align-items: center; gap: var(--space-4); }
#panel-device-detail .dd-panel {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: var(--card-pad);
    box-shadow: var(--shadow);
    margin-bottom: 1rem;
}
.dd-summary-head { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; }
.dd-hostname { margin: 0; font-size: var(--fs-xl); font-weight: 600; color: var(--text); }
.dd-summary-actions { margin-left: auto; }
.dd-meta { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-7); margin-top: 0.85rem; }
.dd-meta-item { display: inline-flex; gap: var(--space-2); font-size: var(--fs-sm); }
.dd-meta-k { color: var(--text-muted); }
.dd-meta-v { color: var(--text); font-weight: 500; }
.dd-grid { display: grid; grid-template-columns: minmax(0, 420px) minmax(0, 1fr); gap: var(--space-5); align-items: start; }
@media (max-width: 1000px) { .dd-grid { grid-template-columns: minmax(0, 1fr); } }
.dd-col-right { display: flex; flex-direction: column; }
.dd-card-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); margin-bottom: 0.85rem; }
.dd-card-head h3 { margin: 0; font-size: var(--fs-md); font-weight: 600; color: var(--text); }
.dd-form .form-row { margin-bottom: 0.75rem; }
.dd-perf-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-4); }
.dd-perf-item { background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--control-radius); padding: var(--space-3) var(--space-4); }
.dd-perf-label { font-size: var(--fs-sm); color: var(--text-muted); margin-bottom: 0.25rem; }
.dd-perf-val { font-size: var(--fs-lg); font-weight: 600; color: var(--text); }
.dd-perf-actions { margin-top: 0.85rem; }
/* 列表主机名可点链接 */
.device-hostname-link {
    border: 0; background: transparent; padding: 0; color: var(--primary);
    font: inherit; cursor: pointer; text-align: left;
}
.device-hostname-link:hover { text-decoration: underline; }

/* 自动发现等 section 内的分组子卡片 */
.settings-section-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); margin-bottom: 0.5rem; }
.settings-section-head .settings-subtitle { margin: 0; }
/* 带外管理：操作按钮提到标题行右侧，两组按子标签互斥显示 */
.oob-head-actions { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.oob-head-actions[hidden] { display: none; }
/* 通用可排序表头（与 SLA 节点表同一观感，类名中性以便别处复用） */
.th-sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.th-sortable:hover { background: var(--bg-elevated); }
.th-sortable.sorted { color: var(--accent, #2563eb); }
.th-sort-ind { margin-left: 0.25rem; font-size: 0.75em; }
/* ---------------- 角色管理 ---------------- */
.role-modkey { margin-left: 0.4rem; opacity: 0.6; font-size: 0.85em; }
.link-like { color: var(--accent, #2563eb); cursor: pointer; text-decoration: none; }
.link-like:hover { text-decoration: underline; }
/* 角色列表：权限概要必须一行显示；空间不够时让「说明」列去换行 */
.role-summary { white-space: nowrap; }
#role-table td:nth-child(5) { white-space: normal; word-break: break-word; min-width: 8rem; }
/* 操作列按钮多（权限设置/复制/重命名/删除），别被挤换行 */
#role-table td.device-actions { white-space: nowrap; }


.role-perm-table th:not(:first-child), .role-perm-table td.role-cell { width: 8.5rem; text-align: center; }
.role-perm-table td.role-mod { white-space: nowrap; }
/* 子模块缩进：靠背景色而不是只靠留白，扫一眼能看出层级 */
.role-row-sub td.role-mod { padding-left: 1.5rem; }
.role-row-sub { background: color-mix(in srgb, var(--bg-elevated) 45%, transparent); }
.role-tree { opacity: 0.45; }
.role-radio { display: inline-flex; align-items: center; gap: var(--space-2); cursor: pointer; user-select: none; }
.role-radio input[disabled] { cursor: not-allowed; }
.role-radio input[disabled] + span { opacity: 0.5; }
.role-save-bar { display: flex; align-items: center; gap: var(--space-4); margin-top: 0.85rem; }



.settings-subcard {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-elevated);
    padding: var(--space-5) var(--space-6);
    margin: var(--space-4) 0;
}
.settings-subcard-title { margin: 0 0 var(--space-4); font-size: var(--fs-sm); font-weight: 600; color: var(--text-muted); text-transform: none; letter-spacing: 0.02em; }
.settings-subcard-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); margin-bottom: 0.5rem; }
.settings-subcard-head .settings-subcard-title { margin: 0; }
.settings-subcard .form-row:last-child { margin-bottom: 0; }

/* Git 版本历史（配置变动页折叠区） */
.git-history-details { margin: 0 0 var(--space-5); border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-elevated); padding: var(--space-3) var(--space-4); }
.git-history-details > summary { cursor: pointer; font-weight: 600; color: var(--text); }
.git-history-list { margin-top: 0.75rem; display: flex; flex-direction: column; gap: var(--space-2); }
.git-commit-row { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; padding: var(--space-2) var(--space-3); border-radius: var(--control-radius); background: var(--bg-card); }
.git-commit-time { color: var(--text-muted); font-size: var(--fs-sm); }
.git-commit-hash { font-size: var(--fs-xs); color: var(--primary); }
.git-commit-msg { flex: 1; min-width: 8rem; font-size: var(--fs-sm); color: var(--text); }
.git-commit-files { flex-basis: 100%; margin-top: 0.35rem; max-height: 220px; overflow: auto; font-size: var(--fs-xs); }
.git-file-row { padding: 0.1rem 0; color: var(--text-muted); }
.git-file-status { display: inline-block; width: 1.2rem; color: var(--primary); font-weight: 600; }

/* ===== 堡垒机 =====
   信息架构对齐 JumpServer，视觉一律走本站设计系统：字号用 token、
   操作列用 .device-actions + 语义色、表格用 .table.table-compact。
   不引入它的绿色 Ant Design——那会再造一处样式割裂。 */
#bastion-side-nav { display: none; }
.main.bastion-mode { display: flex; gap: var(--space-5); align-items: flex-start; }
.main.bastion-mode > #bastion-side-nav {
    display: flex;
    flex: 0 0 150px;
}
.main.bastion-mode > .panel.active { flex: 1 1 auto; min-width: 0; }

/* 会话状态徽标 */
.bst-badge { display: inline-block; padding: 1px 7px; border-radius: var(--radius-pill);
    font-size: var(--fs-2xs); border: 1px solid var(--border); color: var(--text-muted); white-space: nowrap; }
.bst-badge.active { color: var(--success, var(--act-success)); border-color: var(--success, var(--act-success)); }
.bst-badge.killed { color: var(--error, #ef4444); border-color: var(--error, #ef4444); }
.bst-badge.error { color: var(--warning, #f59e0b); border-color: var(--warning, #f59e0b); }
/* 命令风险 */
.bst-risk { display: inline-block; padding: 1px 7px; border-radius: var(--radius-pill); font-size: var(--fs-2xs);
    border: 1px solid var(--border); color: var(--text-muted); white-space: nowrap; }
.bst-risk.warning { color: var(--warning, #f59e0b); border-color: var(--warning, #f59e0b); }
.bst-risk.danger { color: var(--error, #ef4444); border-color: var(--error, #ef4444); }
.table td.bst-cmd { max-width: 42rem; overflow-wrap: anywhere; }

/* Web 终端 / 回放：全屏覆盖层。终端是「进入某台设备」的沉浸态，不该挤在列表里 */
.bastion-term-mask { position: fixed; inset: 0; background: rgba(0, 0, 0, .55);
    display: flex; align-items: center; justify-content: center; z-index: 2000; padding: 2vh 2vw; }
.bastion-term-mask.hidden { display: none; }
.bastion-term-win { width: 100%; height: 100%; display: flex; flex-direction: column;
    background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.bastion-term-head { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4);
    background: var(--bg-elevated); border-bottom: 1px solid var(--border); flex: 0 0 auto; }
.bastion-term-head .spacer { flex: 1 1 auto; }
.bastion-term-title { font-weight: 600; font-size: var(--fs-sm); }
.bastion-term-state { font-size: var(--fs-2xs); color: var(--text-muted); }
.bastion-term-state.ok { color: var(--success, var(--act-success)); }
.bastion-term-state.bad { color: var(--error, #ef4444); }
/* 终端底色固定深色：xterm 的可读性依赖它，不跟随主题（浅色终端反而难用） */
.bastion-term-body { flex: 1 1 auto; min-height: 0; padding: var(--space-2); background: #0b1020; }

/* 回放：左录像右命令，点命令跳时刻 */
.bastion-replay-body { flex: 1 1 auto; min-height: 0; display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(16rem, 22rem); }
.bastion-replay-player { min-width: 0; overflow: auto; background: #0b1020; }
.bastion-replay-cmds { border-left: 1px solid var(--border); overflow: auto; padding: var(--space-3) var(--space-3); }
.bst-replay-cmds-head { font-weight: 600; font-size: var(--fs-sm); margin-bottom: 0.4rem; }
.bst-replay-cmd { display: flex; align-items: baseline; gap: var(--space-2); padding: var(--space-1) var(--space-1);
    border-radius: var(--radius-xs); cursor: pointer; font-size: var(--fs-xs); }
.bst-replay-cmd:hover { background: var(--bg-elevated); }
.bst-replay-t { flex: 0 0 3.2rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
@media (max-width: 900px) {
    .bastion-replay-body { grid-template-columns: minmax(0, 1fr); }
    .bastion-replay-cmds { border-left: 0; border-top: 1px solid var(--border); max-height: 30vh; }
}

/* ============ SLA 矩阵：全网状时延/抖动/丢包网格 ============ */
.sla-seg { display: inline-flex; gap: var(--space-1); margin: var(--space-3) 0 var(--space-5); flex-wrap: wrap; }
.sla-seg-btn { padding: var(--space-1) var(--space-4); border: 1px solid var(--border); background: var(--surface);
    color: var(--text); border-radius: var(--radius-sm); cursor: pointer; font-size: var(--fs-base); }
.sla-seg-btn.active { background: var(--accent, #2563eb); color: #fff; border-color: var(--accent, #2563eb); }
.sla-updated { color: var(--text-muted); font-size: var(--fs-sm); margin-bottom: .5rem; }
.sla-matrix-wrap { overflow-x: auto; }
/* 极致紧凑：尽量把整张全网状矩阵塞进一屏，不靠横向滚动 */
.sla-matrix { border-collapse: collapse; font-size: 10px; font-variant-numeric: tabular-nums; line-height: var(--lh-display); }
.sla-matrix th, .sla-matrix td { border: 1px solid var(--border); padding: 0 var(--space-1); text-align: center;
    white-space: nowrap; height: 15px; }
/* 固定列宽：时延/抖动/丢包三张矩阵格子大小完全一致（不随各自数字位数变宽变窄）。 */
.sla-matrix thead th.sla-colh, .sla-matrix td.sla-cell, .sla-matrix td.sla-diag {
    width: 2.4em; min-width: 2.4em; max-width: 2.4em;
}
.sla-matrix td.sla-cell { cursor: pointer; }
.sla-matrix td.sla-cell:hover { outline: 1px solid var(--accent, #2563eb); outline-offset: -1px; }
.sla-matrix thead th { position: sticky; top: 0; background: var(--surface); z-index: 2; font-weight: 600; }
/* 列头斜排（贴表格下沿、向右上倾斜 75°）。高度随最长机房名自适应（JS 给 --sla-head-h，封顶 100px），
   列宽随数字内容自适应；保留表格线。 */
.sla-matrix thead th.sla-colh { height: var(--sla-head-h, 40px); max-height: 100px; max-width: 100px;
    padding: 0; vertical-align: bottom; position: relative; }
.sla-matrix thead th.sla-colh > span { position: absolute; bottom: 2px; left: 50%;
    transform-origin: left bottom; transform: rotate(-75deg); white-space: nowrap;
    font-size: 10px; line-height: var(--lh-single); font-weight: 600; }
.sla-matrix th.sla-corner { position: sticky; left: 0; z-index: 3; background: var(--surface);
    height: var(--sla-head-h, 40px); max-width: 100px; padding: 0 var(--space-1); white-space: nowrap;
    text-align: center; vertical-align: middle; color: var(--text-muted); font-weight: 500; font-size: 9px; }
.sla-matrix th.sla-rowhdr { position: sticky; left: 0; z-index: 1; background: var(--surface); text-align: right;
    font-weight: 600; padding: 0 var(--space-1); }
.sla-matrix td.sla-diag { background: var(--surface-2, rgba(127,127,127,.12)); color: var(--text-muted); }
.sla-matrix td.sla-na { color: var(--text-muted); }
/* 跨类型（SLA↔路由器）不互通：斜纹格，区别于「有数据」和「真正无数据」 */
.sla-matrix td.sla-xgrp {
    background: repeating-linear-gradient(45deg,
        transparent 0 3px,
        color-mix(in srgb, var(--text-muted) 30%, transparent) 3px 4px);
    cursor: default;
}
.sla-legend i.sla-xgrp-swatch {
    background: repeating-linear-gradient(45deg,
        transparent 0 3px,
        color-mix(in srgb, var(--text-muted) 45%, transparent) 3px 4px);
}
.sla-matrix td.sla-good { background: color-mix(in srgb, var(--success) 18%, transparent); }
.sla-matrix td.sla-warn { background: color-mix(in srgb, var(--warning) 22%, transparent); }
.sla-matrix td.sla-bad  { background: color-mix(in srgb, var(--danger) 24%, transparent); font-weight: 600; }
.sla-matrix td.sla-down { background: color-mix(in srgb, var(--danger) 40%, transparent); color: #fff; }
.sla-matrix .sla-approx::after { content: '~'; color: var(--text-muted); margin-left: 1px; }
.sla-legend { display: flex; gap: var(--space-5); flex-wrap: wrap; margin-top: .75rem; font-size: var(--fs-xs); color: var(--text-muted); }
.sla-legend span { display: inline-flex; align-items: center; gap: var(--space-2); }
.sla-legend i { width: 14px; height: 14px; border-radius: var(--radius-xs); border: 1px solid var(--border); display: inline-block; }
.sla-legend-note { color: var(--text-muted); font-style: italic; }
/* SLA 探测进行中横幅 */
.sla-running { display: flex; align-items: center; gap: var(--space-3); margin: var(--space-1) 0 var(--space-3); padding: var(--space-2) var(--space-4);
    border: 1px solid color-mix(in srgb, var(--accent, #2563eb) 40%, var(--border)); border-radius: var(--radius-sm);
    background: color-mix(in srgb, var(--accent, #2563eb) 10%, transparent); font-size: var(--fs-base); }
.sla-running-hint { color: var(--text-muted); font-size: var(--fs-sm); margin-left: .25rem; }
.sla-spin { width: 13px; height: 13px; border-radius: 50%; border: 2px solid var(--border);
    border-top-color: var(--accent, #2563eb); display: inline-block; animation: sla-spin 0.8s linear infinite; }
@keyframes sla-spin { to { transform: rotate(360deg); } }
.sla-running.sla-done { border-color: color-mix(in srgb, var(--success) 45%, var(--border));
    background: color-mix(in srgb, var(--success) 12%, transparent); }
.sla-running.sla-done .btn { margin-left: .4rem; }
/* SLA 历史趋势弹窗（Canvas，风格对齐接口流量图） */
.modal-content.sla-hist { max-width: 640px; width: 92vw; }
.sla-hist-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-5); margin-bottom: .5rem; }
.sla-hist-head h3 { margin: 0; }
.sla-hist-chart { margin-bottom: .35rem; }
.sla-hist-chart canvas { width: 100%; height: auto; display: block; background: var(--bg-card, transparent); border: 1px solid var(--border); border-radius: var(--radius-sm); }
.sla-hist-meta { font-size: var(--fs-2xs); color: var(--text-muted); margin-top: .4rem; font-variant-numeric: tabular-nums; }
/* SLA 节点列表：搜索框 + 可排序表头 */
.sla-node-search { display: flex; align-items: center; gap: var(--space-3); margin-bottom: .6rem; flex-wrap: wrap; }
.sla-node-search input[type="search"] { flex: 0 1 24rem; min-width: 12rem; padding: var(--space-2) var(--space-3); }
.sla-node-count { color: var(--text-muted); font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
.table th.sla-sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.table th.sla-sortable:hover { background: var(--bg-elevated); }
.table th.sla-sortable.sorted { color: var(--accent, #2563eb); }
.sla-sort-ind { display: inline-block; width: .8em; margin-left: .15rem; font-size: .8em; color: var(--accent, #2563eb); }
/* SLA 节点列表分页条 */
.sla-pager { display: flex; align-items: center; gap: var(--space-4); margin-top: .6rem; flex-wrap: wrap; font-size: var(--fs-sm); }
.sla-pager-total, .sla-pager-cur { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.sla-pager select { padding: var(--space-1) var(--space-2); }

/* 趋势弹窗：标题 + 两端设备名/IP 副标题 */
.sla-hist-titles { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.sla-hist-sub { font-size: var(--fs-xs); color: var(--text-muted); word-break: break-all; }

/* 节点列表：批量选择列 + 批量操作条 */
.sla-sel-cell { width: 2.2rem; text-align: center; }
.sla-sel-cell input[type="checkbox"] { width: 15px; height: 15px; margin: 0; cursor: pointer; vertical-align: middle; }
.table tbody tr.row-selected { background: color-mix(in srgb, var(--primary) 10%, transparent); }
.sla-batchbar {
    display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
    margin-bottom: .6rem; padding: var(--space-3) var(--space-4);
    background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--control-radius, 8px);
}
.sla-batchbar-n { color: var(--text-muted); font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }

/* 新增/编辑节点弹窗：模式分段切换 + 统一间距 */
.modal-content.sla-node-modal { min-width: 460px; max-width: min(92vw, 560px); }
.sla-modal-seg { display: inline-flex; gap: var(--space-1); margin: var(--space-1) 0 var(--space-5); flex-wrap: wrap; }
.sla-node-modal .form-grid { margin-bottom: .6rem; }
.sla-node-modal .form-grid:last-of-type { margin-bottom: 0; }
.sla-modal-hint { grid-column: 1 / -1; margin-top: .1rem; }
/* 协议+端口内联组：落在栅格第 2 列，select 弹性、端口定宽，与其它输入左对齐 */
.sla-node-modal .form-row > .sla-inline { display: flex; gap: var(--space-3); align-items: center; min-width: 0; width: 100%; }
.sla-node-modal .form-row > .sla-inline > select { flex: 1 1 auto; min-width: 0; }
.sla-node-modal .form-row > .sla-inline > input { flex: 0 0 5.5rem; min-width: 0; }

/* 多云纳管账号表：列多且窄屏必然横向滚动。把「操作」列钉在右侧，
   保证任何窗口宽度下测试/同步/编辑/删除都够得着，不必先横向拉到底。
   注意 tbody 与 thead 的背景色不同，两者要分别给，否则滚动时下层内容透出来。 */
.cloud-acc-table th.cloud-sticky-act,
.cloud-acc-table td.cloud-sticky-act {
    position: sticky;
    right: 0;
    box-shadow: var(--shadow-2);
}
.cloud-acc-table td.cloud-sticky-act { background: var(--bg-card); z-index: 1; }
.cloud-acc-table th.cloud-sticky-act { background: var(--bg-elevated); z-index: 3; }
.cloud-acc-table tbody tr:hover td.cloud-sticky-act { background: var(--bg-elevated); }
/* 单云商费用卡：取不到余额时兜底显示「负的当月消费」，与余额卡同一套红色语义 */
.cloud-cost-bal .cloud-neg { color: var(--danger, #dc2626); font-weight: 600; }
/* 带外设备表描述列：内容可能较长，截断+悬停看全文 */
.oob-desc-cell { max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 多云纳管标签列：收窄，标签多时允许换行（不再单行截断） */
.cloud-acc-table td.cloud-tags-cell { white-space: normal; }
.cloud-acc-table td.cloud-tags-cell .cloud-tag { margin: 1px 2px 1px 0; display: inline-block; }
/* 价格计算器：参数横向一行排开（与原 cloud-connection-dashboard 布局一致）。
   字段可收缩，尽量不换行；窗口实在放不下时才折行。 */
.calc-bar { display: flex; flex-wrap: wrap; gap: var(--space-4) var(--space-4); align-items: flex-end; }
.calc-field { display: flex; flex-direction: column; gap: var(--space-1); flex: 1 1 128px; min-width: 112px; }
.calc-field > label { font-size: var(--fs-xs); color: var(--text-muted); font-weight: 600; white-space: nowrap; }
.calc-field select, .calc-field input { min-width: 0; width: 100%; }
/* 计算/保存按钮不参与均分，保持自身宽度并与输入框底对齐 */
.calc-bar > .btn { flex: 0 0 auto; }
/* 折扣系数：两个输入框平分整行 */
.calc-bar-split .calc-field { flex: 1 1 0; }
/* 价格计算的卡片占满面板宽度，避免 6~7 个参数被挤到第二行 */
.calc-card { max-width: none; width: 100%; }

/* 配置洞察表：固定布局，所有列单行，超长截断为 …（title 有全文，双击复制） */
#insight-table { table-layout: fixed; width: 100%; }
#insight-table th, #insight-table td { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#insight-table td.device-actions { overflow: visible; }
