/* ==========================================================================
   云控设备认证管理系统 —— 样式表
   零外部依赖（不引任何 CDN / 字体 / 图标库），全内联 SVG + CSS 变量
   支持浅色 / 深色双主题：<html data-theme="light|dark">
   ========================================================================== */

/* ------------------------------------------------------------------ *
 *  设计令牌
 * ------------------------------------------------------------------ */
:root {
    color-scheme: light;

    --bg:            #f2f5fa;
    --bg-tint-1:     #dbe7ff;
    --bg-tint-2:     #ece2ff;

    --surface:       #ffffff;
    --surface-2:     #f7f9fc;
    --surface-3:     #eef2f8;
    --surface-hover: #f5f8fd;

    --border:        #e3e9f2;
    --border-2:      #cfd9e8;

    --text:          #0f172a;
    --text-2:        #4a5a72;
    --text-3:        #8896ab;

    --brand:         #2563eb;
    --brand-600:     #1d4ed8;
    --brand-700:     #1e40af;
    --brand-soft:    #e8f0ff;
    --brand-soft-2:  #d6e4ff;
    --on-brand:      #ffffff;

    --ok:            #0d9a5b;
    --ok-soft:       #e4f7ed;
    --ok-border:     #b7e7ce;
    --danger:        #dc2f38;
    --danger-soft:   #fdecec;
    --danger-border: #f7c9cb;
    --warn:          #d97706;
    --warn-soft:     #fdf3e2;
    --warn-border:   #f5dcae;
    --violet:        #7c3aed;
    --violet-soft:   #f1e9ff;
    --violet-border: #ddd0fb;

    --shadow-1: 0 1px 2px rgba(15, 23, 42, .06), 0 1px 3px rgba(15, 23, 42, .04);
    --shadow-2: 0 4px 14px rgba(15, 23, 42, .07), 0 1px 3px rgba(15, 23, 42, .04);
    --shadow-3: 0 18px 44px rgba(15, 23, 42, .16);
    --ring:     0 0 0 3px rgba(37, 99, 235, .18);

    --r-xs: 6px;
    --r-sm: 8px;
    --r-md: 12px;
    --r-lg: 16px;
    --r-pill: 999px;

    --topbar-h: 58px;
    --wrap: 1660px;

    --font: "PingFang SC", "HarmonyOS Sans SC", "Microsoft YaHei UI", "Microsoft YaHei",
            -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --mono: ui-monospace, SFMono-Regular, "SF Mono", "Cascadia Mono", Menlo, Consolas,
            "Liberation Mono", "Courier New", monospace;
}

html[data-theme="dark"] {
    color-scheme: dark;

    --bg:            #0a0f1a;
    --bg-tint-1:     #14213d;
    --bg-tint-2:     #1b1633;

    --surface:       #101a2b;
    --surface-2:     #16223a;
    --surface-3:     #1c2a45;
    --surface-hover: #17243c;
    --border:        #1e2c45;
    --border-2:      #2b3c5c;

    --text:          #e8eefb;
    --text-2:        #9fb0c9;
    --text-3:        #6b7e9b;

    --brand:         #4f8cff;
    --brand-600:     #3b7bf0;
    --brand-700:     #2f66d0;
    --brand-soft:    rgba(79, 140, 255, .14);
    --brand-soft-2:  rgba(79, 140, 255, .22);
    --on-brand:      #ffffff;

    --ok:            #34d17f;
    --ok-soft:       rgba(52, 209, 127, .13);
    --ok-border:     rgba(52, 209, 127, .3);
    --danger:        #ff6b73;
    --danger-soft:   rgba(255, 107, 115, .13);
    --danger-border: rgba(255, 107, 115, .3);
    --warn:          #f5b544;
    --warn-soft:     rgba(245, 181, 68, .13);
    --warn-border:   rgba(245, 181, 68, .3);
    --violet:        #a78bfa;
    --violet-soft:   rgba(167, 139, 250, .14);
    --violet-border: rgba(167, 139, 250, .3);

    --shadow-1: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-2: 0 6px 20px rgba(0, 0, 0, .45);
    --shadow-3: 0 22px 50px rgba(0, 0, 0, .6);
    --ring:     0 0 0 3px rgba(79, 140, 255, .25);
}

/* ------------------------------------------------------------------ *
 *  基础
 * ------------------------------------------------------------------ */
* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    padding: 0;
    font-family: var(--font);
    font-size: 14px;
    line-height: 1.55;
    color: var(--text);
    background-color: var(--bg);
    background-image:
        radial-gradient(1100px 520px at 8% -8%, var(--bg-tint-1) 0%, transparent 58%),
        radial-gradient(820px 460px at 102% -6%, var(--bg-tint-2) 0%, transparent 52%);
    background-attachment: fixed;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

a { color: var(--brand); text-decoration: none; }
a:hover { color: var(--brand-600); }

code, .mono { font-family: var(--mono); font-size: .92em; }

::selection { background: var(--brand-soft-2); color: var(--text); }

/* 滚动条 */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
    background: var(--border-2);
    border-radius: 999px;
    border: 2px solid transparent;
    background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--text-3); background-clip: content-box; }

/* ------------------------------------------------------------------ *
 *  页面骨架：左侧栏 + 内容区
 * ------------------------------------------------------------------ */
.shell {
    display: flex;
    align-items: flex-start;
    min-height: 100vh;
}

.main-col {
    flex: 1 1 auto;
    min-width: 0;             /* 允许表格横向滚动而不撑破布局 */
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.sidebar {
    position: sticky;
    top: 0;
    flex: 0 0 244px;
    width: 244px;
    height: 100vh;
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 16px 14px;
    border-right: 1px solid var(--border);
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    backdrop-filter: saturate(170%) blur(12px);
    -webkit-backdrop-filter: saturate(170%) blur(12px);
    z-index: 950;
}

.sidebar .brand { font-size: 14px; }
.sidebar .brand-mark { width: 30px; height: 30px; border-radius: 8px; }
.sidebar .brand-text small { font-size: 10px; }

.side-nav-label {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .8px;
    text-transform: uppercase;
    color: var(--text-3);
    padding: 0 8px 6px;
}

.side-nav {
    display: flex;
    flex-direction: column;
    gap: 3px;
    flex: 1 1 auto;
}

.side-nav a {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 10px;
    border-radius: var(--r-sm);
    color: var(--text-2);
    font-size: 13.5px;
    font-weight: 500;
    transition: background-color .16s, color .16s;
}
.side-nav a:hover { background: var(--surface-3); color: var(--text); }
.side-nav a.active-nav {
    background: linear-gradient(90deg, var(--brand-soft) 0%, color-mix(in srgb, var(--brand-soft) 45%, transparent) 100%);
    color: var(--brand-600);
    font-weight: 600;
    box-shadow: inset 0 0 0 1px var(--brand-soft-2);
}
.side-nav a span { flex: 1 1 auto; }
.nav-badge {
    font-style: normal;
    font-size: 11px;
    font-weight: 700;
    padding: 1px 7px;
    border-radius: var(--r-pill);
    background: var(--surface-3);
    color: var(--text-2);
    font-variant-numeric: tabular-nums;
}
.side-nav a.active-nav .nav-badge { background: var(--brand); color: var(--on-brand); }

.side-foot {
    border-top: 1px solid var(--border);
    padding-top: 12px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.side-rows { display: flex; flex-direction: column; gap: 5px; }
.side-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 12.5px;
    color: var(--text-3);
    padding: 0 8px;
}
.side-row b { color: var(--text); font-variant-numeric: tabular-nums; }
.side-row b.is-ok { color: var(--ok); }
.side-row b.is-violet { color: var(--violet); }
.side-row b.is-warn { color: var(--warn); }

.side-bar {
    height: 5px;
    margin: 2px 8px;
    border-radius: 999px;
    background: var(--surface-3);
    overflow: hidden;
}
.side-bar span {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--ok) 0%, var(--brand) 100%);
}

.side-status {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 11.5px;
    color: var(--text-3);
    padding: 0 8px;
}

/* 面包屑 */
.crumb {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--text-3);
    min-width: 0;
}
.crumb a { color: var(--text-3); }
.crumb a:hover { color: var(--brand); }
.crumb .sep { color: var(--border-2); }
.crumb b { color: var(--text); font-weight: 600; }

/* ------------------------------------------------------------------ *
 *  顶栏
 * ------------------------------------------------------------------ */
.topbar {
    position: sticky;
    top: 0;
    z-index: 900;
    background: color-mix(in srgb, var(--surface) 88%, transparent);
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
    border-bottom: 1px solid var(--border);
}

.topbar-inner {
    max-width: var(--wrap);
    margin: 0 auto;
    min-height: var(--topbar-h);
    padding: 8px 20px;
    display: flex;
    align-items: center;
    gap: 18px;
}

/* 品牌 */
.brand {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 0 0 auto;
    color: var(--text);
    font-weight: 700;
    font-size: 15px;
    letter-spacing: .2px;
}
.brand:hover { color: var(--text); }
.brand:hover .brand-mark { transform: rotate(-6deg) scale(1.05); }

.brand-mark {
    width: 32px;
    height: 32px;
    border-radius: 9px;
    display: grid;
    place-items: center;
    color: var(--on-brand);
    background: linear-gradient(140deg, var(--brand) 0%, var(--violet) 118%);
    box-shadow: 0 3px 10px rgba(37, 99, 235, .32);
    transition: transform .25s cubic-bezier(.3, 1.4, .5, 1);
}

.brand-text { display: flex; flex-direction: column; line-height: 1.15; }
.brand-text small {
    font-size: 10.5px;
    font-weight: 500;
    color: var(--text-3);
    letter-spacing: .5px;
}

/* 主导航 */
.nav {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    gap: 4px;
    flex-wrap: wrap;
    min-width: 0;
    background: none;
    box-shadow: none;
    padding: 0;
    margin: 0;
    border-radius: 0;
}

.nav a {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 7px 13px;
    border-radius: var(--r-sm);
    font-weight: 500;
    font-size: 13.5px;
    color: var(--text-2);
    transition: background-color .16s, color .16s;
}
.nav a:hover { background: var(--surface-3); color: var(--text); }
.nav a.active-nav {
    background: var(--brand-soft);
    color: var(--brand-600);
    font-weight: 600;
    box-shadow: inset 0 0 0 1px var(--brand-soft-2);
}
.nav a svg { opacity: .8; }

.topbar-right {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 8px;
}

/* 图标按钮（主题切换等） */
.icon-btn {
    width: 34px;
    height: 34px;
    display: grid;
    place-items: center;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-2);
    border-radius: var(--r-sm);
    cursor: pointer;
    padding: 0;
    transition: background-color .16s, color .16s, border-color .16s;
}
.icon-btn:hover { background: var(--surface-3); color: var(--text); border-color: var(--border-2); }
.icon-btn .icon-moon { display: none; }
html[data-theme="dark"] .icon-btn .icon-sun  { display: none; }
html[data-theme="dark"] .icon-btn .icon-moon { display: block; }

/* 用户胶囊 */
.user-chip {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 4px 12px 4px 4px;
    border: 1px solid var(--border);
    background: var(--surface);
    border-radius: var(--r-pill);
    font-size: 12.5px;
    white-space: nowrap;
}

.avatar {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-size: 11.5px;
    font-weight: 700;
    color: var(--on-brand);
    background: linear-gradient(140deg, var(--brand) 0%, var(--violet) 120%);
    flex: 0 0 auto;
    text-transform: uppercase;
}

.user-meta { display: flex; flex-direction: column; line-height: 1.25; }
.user-meta b { font-weight: 600; color: var(--text); font-size: 12.5px; }
.user-meta .remaining-time {
    font-size: 11px;
    color: var(--warn);
    font-variant-numeric: tabular-nums;
}
.user-meta .remaining-time.is-low { color: var(--danger); font-weight: 600; }

.login-info { display: flex; align-items: center; }

/* 兼容旧标记（.login-time / .username 单独用时） */
.login-info span { font-size: 12.5px; color: var(--text-2); white-space: nowrap; }
.login-info .username { color: var(--text); font-weight: 600; }

.logout-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 12px !important;
    color: var(--danger) !important;
    border-radius: var(--r-sm);
    font-weight: 500;
}
.logout-btn:hover { background: var(--danger-soft) !important; color: var(--danger) !important; }

/* ------------------------------------------------------------------ *
 *  主内容容器
 * ------------------------------------------------------------------ */
.wrap {
    /* width:100% 不能省。它是 .main-col（column flex）的子项，而 margin:0 auto
       会让 align-items:stretch 失效（flex 规范：交叉轴有 auto 外边距时不拉伸），
       于是宽度退回 min-content = 955px —— 实测视口 876/696 时整页横向溢出。
       显式给 width:100%（全局 border-box）即可，窄屏交给表格自己滚。 */
    width: 100%;
    min-width: 0;
    max-width: var(--wrap);
    margin: 0 auto;
    padding: 22px 20px 40px;
}

/* 页头（标题 + 副标题 + 右侧动作） */
.page-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin: 0 0 18px;
}

.page-title {
    margin: 0;
    font-size: 21px;
    font-weight: 700;
    letter-spacing: -.2px;
    color: var(--text);
    display: flex;
    align-items: center;
    gap: 10px;
}

.page-sub {
    margin: 5px 0 0;
    color: var(--text-3);
    font-size: 12.5px;
}

/* 通用卡片 */
.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-1);
    overflow: hidden;
}

.card + .card { margin-top: 16px; }

.card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    padding: 13px 16px;
    border-bottom: 1px solid var(--border);
    background: linear-gradient(180deg, var(--surface-2) 0%, var(--surface) 100%);
}

.card-head h2 {
    margin: 0;
    font-size: 14px;
    font-weight: 650;
    color: var(--text);
    display: flex;
    align-items: center;
    gap: 8px;
}

.card-head .card-hint { font-size: 12px; color: var(--text-3); }

.card-body { padding: 16px; }

/* ------------------------------------------------------------------ *
 *  统计卡
 * ------------------------------------------------------------------ */
.stats {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 14px;
    margin-bottom: 18px;
}

.stat {
    position: relative;
    display: flex;
    align-items: center;
    gap: 13px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    padding: 15px 16px;
    box-shadow: var(--shadow-1);
    overflow: hidden;
    transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}

.stat::after {
    content: "";
    position: absolute;
    inset: auto 0 0 0;
    height: 3px;
    background: linear-gradient(90deg, var(--brand), transparent 85%);
    opacity: .85;
}

.stat:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); border-color: var(--border-2); }

.stat-icon {
    width: 42px;
    height: 42px;
    border-radius: 11px;
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    color: var(--brand);
    background: var(--brand-soft);
}

.stat-meta { min-width: 0; }
.stat .k {
    font-size: 12px;
    color: var(--text-3);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.stat .v {
    font-size: 24px;
    font-weight: 700;
    color: var(--text);
    line-height: 1.15;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.5px;
}

.stat.ok::after     { background: linear-gradient(90deg, var(--ok), transparent 85%); }
.stat.ok .stat-icon { color: var(--ok); background: var(--ok-soft); }
.stat.bad::after    { background: linear-gradient(90deg, var(--danger), transparent 85%); }
.stat.bad .stat-icon{ color: var(--danger); background: var(--danger-soft); }
.stat.warn::after   { background: linear-gradient(90deg, var(--warn), transparent 85%); }
.stat.warn .stat-icon { color: var(--warn); background: var(--warn-soft); }
.stat.violet::after { background: linear-gradient(90deg, var(--violet), transparent 85%); }
.stat.violet .stat-icon { color: var(--violet); background: var(--violet-soft); }

/* 统计卡片里的补充小字（如「已授权」下面的「其中临时 3」）。
 * ⚠ 卡片高度由内容撑开，加了这行会让那一张比旁边略高一点点 ——
 *   .stats 是 grid，同一行的卡片会自动等高，所以不会参差。 */
.stat .sub {
    font-size: 11.5px;
    line-height: 1.4;
    color: var(--text-3);
    margin-top: 1px;
    white-space: nowrap;
}
.stat .sub b { color: var(--warn); font-weight: 700; }

/* ------------------------------------------------------------------ *
 *  工具栏
 * ------------------------------------------------------------------ */
.toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}

.search-container {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 1 1 320px;
    max-width: 520px;
    position: relative;
}

.search-container .search-icon {
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-3);
    pointer-events: none;
    display: grid;
    place-items: center;
}

.search-container input[type="text"] {
    flex: 1;
    padding: 10px 14px 10px 38px;
    border: 1px solid var(--border-2);
    background: var(--surface);
    color: var(--text);
    border-radius: var(--r-sm);
    font-size: 14px;
    font-family: inherit;
    transition: border-color .16s, box-shadow .16s;
    min-width: 0;
}

.search-container input[type="text"]::placeholder { color: var(--text-3); }

.search-container input[type="text"]:focus {
    outline: none;
    border-color: var(--brand);
    box-shadow: var(--ring);
}

.batch-container {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.batch-container select {
    padding: 10px 14px;
    border: 1px solid var(--border-2);
    background: var(--surface);
    color: var(--text);
    border-radius: var(--r-sm);
    font-size: 14px;
    font-family: inherit;
    cursor: pointer;
    min-width: 150px;
}
.batch-container select:focus { outline: none; border-color: var(--brand); box-shadow: var(--ring); }

.action-btns { display: flex; gap: 8px; flex-wrap: wrap; }

/* 工具栏右侧动作组：导出 / 批量操作 / 新增 统一在一行，窄屏自动换行 */
.toolbar-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.export-form { display: inline-flex; }

/* 导出是次要动作（ghost 风格）—— 不跟「执行 / 添加设备」抢视觉焦点 */
.export-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 10px 16px;
    background: var(--surface);
    color: var(--text-2);
    border: 1px solid var(--border-2);
    border-radius: var(--r-sm);
    cursor: pointer;
    font-size: 14px;
    font-weight: 550;
    font-family: inherit;
    line-height: 1.2;
    white-space: nowrap;
    transition: background-color .16s, border-color .16s, color .16s, transform .1s;
}

.export-btn:hover { background: var(--surface-3); color: var(--text); border-color: var(--brand); }
.export-btn:active { transform: translateY(1px); }

/* ------------------------------------------------------------------ *
 *  按钮体系
 * ------------------------------------------------------------------ */
.btn,
.search-container button,
.batch-container button,
.action-btns button,
.submit-btn,
.jump-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 10px 18px;
    background: var(--brand);
    color: var(--on-brand);
    border: 1px solid transparent;
    border-radius: var(--r-sm);
    cursor: pointer;
    font-size: 14px;
    font-weight: 550;
    font-family: inherit;
    line-height: 1.2;
    white-space: nowrap;
    transition: background-color .16s, box-shadow .16s, transform .1s, border-color .16s;
}

.btn:hover,
.search-container button:hover,
.batch-container button:hover,
.action-btns button:hover,
.submit-btn:hover,
.jump-btn:hover {
    background: var(--brand-600);
    color: var(--on-brand);
}

.btn:active,
.search-container button:active,
.batch-container button:active,
.submit-btn:active,
.jump-btn:active { transform: translateY(1px); }

.btn:focus-visible,
button:focus-visible,
a:focus-visible { outline: none; box-shadow: var(--ring); }

.action-btns .add-btn { background: var(--ok); }
.action-btns .add-btn:hover { background: color-mix(in srgb, var(--ok) 84%, #000); }
.action-btns .batch-btn { background: var(--violet); }
.action-btns .batch-btn:hover { background: color-mix(in srgb, var(--violet) 84%, #000); }

.btn-primary { width: 100%; padding: 12px; font-size: 15px; font-weight: 650; border-radius: var(--r-sm); }

.btn-ghost {
    background: var(--surface);
    color: var(--text-2);
    border-color: var(--border-2);
}
.btn-ghost:hover { background: var(--surface-3); color: var(--text); }

.cancel-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 9px 16px;
    background: var(--surface-3);
    color: var(--text-2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    cursor: pointer;
    font-size: 13px;
    font-family: inherit;
    font-weight: 500;
    white-space: nowrap;
}
.cancel-btn:hover { background: var(--border); color: var(--text); }

/* ------------------------------------------------------------------ *
 *  面板卡片（机型分布 / 最近变动）
 * ------------------------------------------------------------------ */
.panel-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 16px;
    margin: 18px 0;
    /* 两张卡高宽一致：宽度由 1fr/1fr 保证，高度靠 stretch 拉平。
       这里原先写的是 align-items:start（各按内容取高），实测「设备机型分布」
       h=322.69 比「最近授权变动」h=435.75 矮 113px，两张卡底边参差、不好看。
       拉伸出来的空白不硬摊在卡底 —— 见下方把列表撑满、信息行顶到卡底。 */
    align-items: stretch;
}

/* 只作用于概览这两张卡：.card 在 change_password.php 也单独用着，别动它 */
.panel-grid > .card {
    display: flex;
    flex-direction: column;
    margin: 0;
}
.panel-grid > .card > .card-body {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
}
/* 列表占满剩余高度，末尾的 .kv-row 信息行自然被顶到卡底。
   等价于给列表后面塞一个自动外边距，但这样写意图更直白。 */
.panel-grid > .card > .card-body > .bar-list,
.panel-grid > .card > .card-body > .feed {
    flex: 1 1 auto;
}

.muted-sm { color: var(--text-3); font-size: 12.5px; margin: 6px 0; }

/* 横向条形列表 */
.bar-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 11px; }
.bar-list li { display: flex; align-items: center; gap: 11px; font-size: 12.5px; }
.bar-name {
    flex: 0 0 108px;
    color: var(--text-2);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.bar-track {
    flex: 1 1 auto;
    height: 7px;
    border-radius: 999px;
    background: var(--surface-3);
    overflow: hidden;
}
.bar-track i {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--brand) 0%, var(--violet) 100%);
}
.bar-val {
    flex: 0 0 34px;
    text-align: right;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

/* 变动流 */
.feed { list-style: none; margin: 0 0 12px; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.feed li { display: flex; align-items: center; gap: 10px; font-size: 12.5px; }
.feed-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; background: var(--text-3); }
.feed-dot.is-ok  { background: var(--ok);     box-shadow: 0 0 0 3px var(--ok-soft); }
.feed-dot.is-bad { background: var(--danger); box-shadow: 0 0 0 3px var(--danger-soft); }
.feed-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; line-height: 1.3; }
.feed-main b { font-size: 12.5px; color: var(--text); }
.feed-main small { color: var(--text-3); font-size: 11.5px; }
.feed-time { flex: 0 0 auto; color: var(--text-3); font-size: 11.5px; }

.kv-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    font-size: 12.5px;
    color: var(--text-3);
    padding: 7px 0;
    border-top: 1px dashed var(--border);
}
.kv-row b { color: var(--text-2); font-weight: 600; }

/* ------------------------------------------------------------------ *
 *  列表单元（设备 / 时间）
 * ------------------------------------------------------------------ */
/* 设备格：只剩 IMEI 和「白名单」角标，横向并排。
 * 认证序号与设备型号已各自独立成列，不再挤在这格里当小字。
 * ⚠ 这里刻意**没有** flex-wrap: wrap —— 一旦允许换行，这一列的 min-content
 *   就只按「最宽的那一个子项」算（IMEI），列会被压到角标折行。
 *   窄屏靠 .table-container 横向滚动，不要靠折行。 */
.dev-cell {
    display: flex;
    align-items: center;
    gap: 7px;
    min-width: 0;
}
/* flex 子项默认 flex-shrink:1，列一窄 IMEI 就被压扁 —— 钉住 */
.dev-cell > .dev-id,
.dev-cell > .whitelist-badge { flex: 0 0 auto; }
.dev-id {
    font-family: var(--mono);
    font-size: 15px;
    font-weight: 600;
    color: var(--text);
    letter-spacing: -.2px;
}

/* 认证序号列。等宽数字让 #1 / #10 / #100 纵向对齐。
 * ⚠ 这一条只在这里定义一次 —— 别再用 table tbody td:first-child 去选它，
 *   第一列现在是勾选框，序号已经独立成列（踩过这个坑）。 */
.seq-cell {
    font-size: 14px;
    color: var(--text-3);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* 设备型号列 */
.model-cell {
    display: inline-block;
    font-size: 14px;
    color: var(--text-2);
    white-space: nowrap;
}
.model-cell.is-empty { color: var(--text-3); opacity: .7; }

/* ⚠ 白名单角标曾经被定义在两处（这里一份 + 下方一份），后面的盖掉前面的，
 * 正是「底框被文字撑爆」那个 bug 的温床。现在全文件只有下方唯一一份
 * .whitelist-badge 定义，别再往这里加第二份。 */

.time-cell { display: flex; flex-direction: column; gap: 2px; }
.time-cell span { display: inline-flex; align-items: center; gap: 6px; color: var(--text-2); font-size: 14.5px; }
.time-cell small { font-size: 12px; color: var(--text-3); }

/* 详情按钮 */
.view-btn { background: var(--surface-3); color: var(--text-2); border-color: var(--border); }
.view-btn:hover { background: var(--brand-soft); color: var(--brand-600); border-color: var(--brand-soft-2); }

/* 详情弹层 */
.modal-lg { max-width: 620px; width: 92vw; }
.detail-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 0 14px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 14px;
}
.detail-head b { font-size: 15px; letter-spacing: -.2px; }
.detail-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px 18px;
}
.detail-item { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.detail-item span { font-size: 11.5px; color: var(--text-3); }
.detail-item b {
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    word-break: break-all;
}
.detail-wide { grid-column: 1 / -1; }

/* 详情弹层脚注：只放「数据库内部编号」这类排查用信息 ——
   它不属于设备属性，不该和上面的字段并排（也免得占掉半行让网格留空）。 */
.detail-foot {
    margin: 14px 0 0;
    font-size: 11.5px;
    color: var(--text-3);
    word-break: break-all;
}
.detail-foot b { font-weight: 600; color: var(--text-2); }

/* ------------------------------------------------------------------ *
 *  表格
 * ------------------------------------------------------------------ */
.table-container {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-1);
    overflow-x: auto;
    overflow-y: visible;
}

table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 15px;
}

table thead th {
    background: var(--surface-2);
    color: var(--text-2);
    font-weight: 600;
    font-size: 13px;
    letter-spacing: .3px;
    text-align: left;
    padding: 12px 18px;
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
    user-select: none;
}

table thead th a {
    color: inherit;
    display: inline-flex;
    align-items: center;
    gap: 5px;
}
table thead th a:hover { color: var(--brand); }

th.th-sort.is-active { color: var(--brand); }
th.th-sort.is-active a { color: var(--brand); font-weight: 700; }

.caret {
    display: inline-flex;
    flex-direction: column;
    gap: 2px;
    margin-left: 3px;
    opacity: .3;
}
.caret::before,
.caret::after {
    content: "";
    display: block;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
}
.caret::before { border-bottom: 4px solid currentColor; }
.caret::after  { border-top: 4px solid currentColor; }
th.th-sort.is-active .caret { opacity: 1; }
th.th-sort.is-active.asc  .caret::after  { opacity: .22; }
th.th-sort.is-active.desc .caret::before { opacity: .22; }

table tbody td {
    padding: 12px 18px;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
    white-space: nowrap;
    color: var(--text-2);
}

table tbody tr { transition: background-color .13s; }
table tbody tr:nth-child(even) { background: color-mix(in srgb, var(--surface-2) 55%, transparent); }
table tbody tr:hover { background: var(--surface-hover); }
table tbody tr:hover td { color: var(--text); }
table tbody tr:last-child td { border-bottom: none; }

/* ------------------------------------------------------------------ *
 *  列表表格：尺寸与列宽
 *
 * 一、尺寸。舒总 2026-09-25 反馈「整体默认的显示比例太小」——
 *     原表格 13px / 单元格 padding 11x13 确实偏小，整表放大一档到
 *     15px / 12x18，表内相关小字同步 +1~2px（大表格里嵌小字只会更乱）。
 *
 * 二、列宽。舒总反馈「列表还不均衡，最后上报和操作之间很大的空」。
 *     实测（1576 视口，容器 1290px，用 edge_layout_probe 量的真实几何）：
 *       table{width:100%} 下浏览器把富余宽度按「列声明比例」乱摊，
 *       结果「最后上报」一列独吞约 245px 空白，列间距在 36~119px 之间跳。
 *
 *     现在的做法：给每列一个显式百分比，取值 =
 *         (该列内容需求 + 等量余量) / 表宽
 *       内容需求 = max(表头含排序箭头, 单元格内容) + 左右 padding；
 *       等量余量 = (表宽 - 各列需求之和) / 列数。
 *     每一列拿到的「额外空白」完全相同，列与列之间读起来才齐。
 *
 *     ⚠ 两个坑：
 *     1) 表头文字参与列宽计算，所以标签要短 —— 「序号」而不是「认证序号」，
 *        多两个字那列就白多出 26px 空白；
 *     2) th 上不要再写 inline width（如 style="width:42px"）：
 *        inline 优先级高于样式表，会把这里的分配整个顶掉（踩过）。
 *
 *     操作列 right 对齐：按钮贴表格右边缘、右端收口，
 *     「最后上报」与按钮之间不再是一片空。
 * ------------------------------------------------------------------ */
.tbl-devices { width: 100%; }
.tbl-devices th:nth-child(1) { width: 5.6%; }   /* 勾选框 */
/* 序号：改成连续行号后最长只到 #88（3 字符），原先给 #18004（6 字符）留的
   8.4% 会剩一大块空白。收窄到 6.4%，省下的 2% 补给最挤的 IMEI 列。 */
.tbl-devices th:nth-child(2) { width: 6.4%; }   /* 序号 */
.tbl-devices th:nth-child(3) { width: 22.7%; }  /* 设备 IMEI */
.tbl-devices th:nth-child(4) { width: 8.4%; }   /* 型号 */
.tbl-devices th:nth-child(5) { width: 12.2%; }  /* MAC 地址 */
.tbl-devices th:nth-child(6) { width: 9.9%; }   /* 状态 */
.tbl-devices th:nth-child(7) { width: 14.8%; }  /* 最后上报 */
.tbl-devices th:nth-child(8) { width: 20.0%; }  /* 操作 */

.tbl-devices th:nth-child(6),
.tbl-devices td:nth-child(6) { text-align: center; }
.tbl-devices th:nth-child(8),
.tbl-devices td:nth-child(8) { text-align: right; }
.tbl-devices td:nth-child(8) .action-buttons { justify-content: flex-end; }

/* 白名单表：同法。字段更短更稀疏（6 列），余量摊到 6 列。 */
.tbl-whitelist { width: 100%; }
.tbl-whitelist th:nth-child(1) { width: 13.6%; }  /* 序号 */
.tbl-whitelist th:nth-child(2) { width: 17.4%; }  /* MAC 地址 */
.tbl-whitelist th:nth-child(3) { width: 15.6%; }  /* 设备名称 */
.tbl-whitelist th:nth-child(4) { width: 13.6%; }  /* 备注 */
.tbl-whitelist th:nth-child(5) { width: 20.4%; }  /* 添加时间 */
.tbl-whitelist th:nth-child(6) { width: 19.4%; }  /* 操作 */
.tbl-whitelist th:nth-child(6),
.tbl-whitelist td:nth-child(6) { text-align: right; }
.tbl-whitelist td:nth-child(6) .action-buttons { justify-content: flex-end; }

/* 设备标识类字段用等宽字体 */
td.cell-mono,
.tooltip.cell-mono { font-family: var(--mono); font-size: 14px; letter-spacing: -.2px; }

.tooltip { max-width: 200px; overflow: hidden; text-overflow: ellipsis; }

/* 复选框 */
input[type="checkbox"] {
    width: 16px;
    height: 16px;
    accent-color: var(--brand);
    cursor: pointer;
    vertical-align: middle;
}

/* 空状态 */
.empty-row td { padding: 0 !important; border: none !important; }
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 46px 20px 50px;
    color: var(--text-3);
    text-align: center;
    white-space: normal;
}
.empty-state svg { opacity: .5; }
.empty-state b { color: var(--text-2); font-weight: 600; font-size: 14px; }
.empty-state span { font-size: 12.5px; }

/* ------------------------------------------------------------------ *
 *  状态标记
 * ------------------------------------------------------------------ */
.status {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px 3px 8px;
    border-radius: var(--r-pill);
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
    border: 1px solid transparent;
}
.status::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    flex: 0 0 auto;
}

.status.authorized   { background: var(--ok-soft);     color: var(--ok);     border-color: var(--ok-border); }
.status.unauthorized { background: var(--danger-soft); color: var(--danger); border-color: var(--danger-border); }

/* 临时授权（新上线客户的 N 天试用）—— 用琥珀色，和绿色的「正式授权」
 * 拉开距离，管理员扫一眼就能分清哪些还没确认。
 *
 * 三档：
 *   is-temp         试用期内，还剩几天
 *   is-temp-urgent  只剩 1 天或今日到期 —— 反白加粗，别让管理员错过最后窗口
 *   is-expired      已到期并被自动取消（断网中），红色 */
.status.is-temp        { background: var(--warn-soft);   color: var(--warn);   border-color: var(--warn-border); }
.status.is-temp-urgent { background: var(--warn);        color: #fff;          border-color: transparent; }
.status.is-expired     { background: var(--danger-soft); color: var(--danger); border-color: var(--danger-border); }

/* 「★白名单」角标。
 *
 * ⚠ 这里原来是 width/height: 20px 的**固定方框** —— 那一版角标里只有一颗星图标，
 *   尺寸够用。后来角标加了「白名单」三个字，固定尺寸没跟着改，文字直接顶出底框
 *   （2026-09-25 舒总反馈「底框太小，不匹配」）。
 *   凡是「图标 + 文字」的标签都不能给固定宽高，必须按内容自适应。
 */
.whitelist-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 2px 8px;
    min-height: 20px;
    margin-right: 5px;
    border-radius: var(--r-pill);
    background: var(--warn-soft);
    color: var(--warn);
    border: 1px solid var(--warn-border);
    font-size: 12px;
    font-weight: 600;
    line-height: 1.5;
    white-space: nowrap;
    cursor: help;
    vertical-align: middle;
}
.whitelist-badge svg { display: block; flex: 0 0 auto; }

.dot-online, .dot-offline {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-right: 6px;
    vertical-align: middle;
}
.dot-online  { background: var(--ok); box-shadow: 0 0 0 3px var(--ok-soft); }
.dot-offline { background: var(--text-3); opacity: .55; }

/* ------------------------------------------------------------------ *
 *  行内操作按钮
 * ------------------------------------------------------------------ */
.action-buttons { display: flex; gap: 6px; flex-wrap: nowrap; }

.action-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 6px 12px;
    border-radius: var(--r-xs);
    font-size: 13px;
    font-weight: 550;
    white-space: nowrap;
    border: 1px solid transparent;
    background: var(--surface-3);
    color: var(--text-2);
    transition: background-color .15s, color .15s, border-color .15s;
}

.auth-btn    { background: var(--ok-soft);     color: var(--ok);     border-color: var(--ok-border); }
.auth-btn:hover    { background: var(--ok);     color: #fff; border-color: transparent; }
.unauth-btn  { background: var(--warn-soft);   color: var(--warn);   border-color: var(--warn-border); }
.unauth-btn:hover  { background: var(--warn);   color: #fff; border-color: transparent; }
.edit-btn    { background: var(--brand-soft);  color: var(--brand-600); border-color: var(--brand-soft-2); }
.edit-btn:hover    { background: var(--brand);  color: #fff; border-color: transparent; }
.wl-btn      { background: var(--violet-soft); color: var(--violet); border-color: var(--violet-border); }
.wl-btn:hover      { background: var(--violet); color: #fff; border-color: transparent; }
/* 「转正式」：把临时授权确认为长期有效。用品牌蓝当主操作色 ——
   它和同行的「加入白名单」（紫）、「取消授权」（橙）、「删除」（红）都不撞。 */
.promote-btn { background: var(--brand-soft);  color: var(--brand-600); border-color: var(--brand-soft-2); }
.promote-btn:hover { background: var(--brand); color: #fff; border-color: transparent; }
.delete-btn  { background: var(--danger-soft); color: var(--danger); border-color: var(--danger-border); }
.delete-btn:hover  { background: var(--danger); color: #fff; border-color: transparent; }

/* 行内动作按钮现在用 <button>（token 走 POST 表单，不再放 URL 里）：
   按钮默认不继承字体/光标，这里补齐，保持和 <a> 版本一致的外观 */
button.action-btn {
    font-family: inherit;
    cursor: pointer;
    line-height: 1.2;
    text-align: center;
}

/* ------------------------------------------------------------------ *
 *  分页
 * ------------------------------------------------------------------ */
.pagination {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    margin: 16px 0 10px;
    padding: 10px 12px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-1);
}

.pagination a,
.pagination .current,
.pagination .gap {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 36px;
    height: 36px;
    padding: 0 11px;
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--text-2);
    font-size: 14px;
    font-weight: 550;
    border: 1px solid var(--border);
    transition: background-color .15s, color .15s, border-color .15s;
}

.pagination a:hover { background: var(--surface-3); color: var(--text); border-color: var(--border-2); }
.pagination a.pagination-btn { padding: 0 13px; }

.pagination .current {
    background: var(--brand);
    color: var(--on-brand);
    border-color: transparent;
    font-weight: 700;
    box-shadow: 0 2px 8px rgba(37, 99, 235, .3);
}

.pagination .gap { border: none; background: transparent; color: var(--text-3); }

.page-jump { display: flex; align-items: center; gap: 6px; margin-left: auto; }
.page-separator { color: var(--text-3); font-size: 14px; white-space: nowrap; }

.page-input {
    width: 66px;
    height: 34px;
    padding: 0 8px;
    border: 1px solid var(--border-2);
    background: var(--surface);
    color: var(--text);
    border-radius: var(--r-sm);
    font-size: 13px;
    font-family: inherit;
    text-align: center;
}
.page-input:focus { outline: none; border-color: var(--brand); box-shadow: var(--ring); }

.jump-btn { height: 34px; padding: 0 13px; }

.per-page {
    color: var(--text-3);
    font-size: 12.5px;
    padding: 0 4px 6px;
}

.per-page select {
    vertical-align: middle;
    margin: 0 3px;
    padding: 6px 10px;
    border: 1px solid var(--border-2);
    background: var(--surface);
    color: var(--text);
    border-radius: var(--r-xs);
    font-size: 12.5px;
    font-family: inherit;
    cursor: pointer;
}
.per-page select:focus { outline: none; border-color: var(--brand); box-shadow: var(--ring); }

/* ------------------------------------------------------------------ *
 *  提示 / Toast
 * ------------------------------------------------------------------ */
#toast-container {
    position: fixed;
    top: 74px;
    right: 20px;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    gap: 10px;
    pointer-events: none;
}

.toast {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 240px;
    max-width: 400px;
    padding: 12px 16px 12px 14px;
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    border-left: 3px solid var(--brand);
    box-shadow: var(--shadow-2);
    font-size: 13px;
    animation: toast-in .28s cubic-bezier(.2, 1.2, .4, 1);
    pointer-events: auto;
    overflow: hidden;
}
.toast::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    height: 2px;
    width: 100%;
    background: currentColor;
    opacity: .35;
    transform-origin: left;
    animation: toast-bar 3s linear forwards;
}

.toast-success { border-left-color: var(--ok); }
.toast-success::before { content: "✓"; color: var(--ok); font-weight: 700; }
.toast-error { border-left-color: var(--danger); }
.toast-error::before { content: "!"; color: var(--danger); font-weight: 800; }
.toast-info { border-left-color: var(--brand); }
.toast-info::before { content: "i"; color: var(--brand); font-weight: 700; font-style: italic; }

.toast.fade-out { opacity: 0; transform: translateX(14px); transition: opacity .3s, transform .3s; }

@keyframes toast-in {
    from { transform: translateX(24px); opacity: 0; }
    to   { transform: translateX(0);    opacity: 1; }
}
@keyframes toast-bar {
    from { transform: scaleX(1); }
    to   { transform: scaleX(0); }
}

/* 页面内联提示 */
.flash-success, .flash-error, .flash-info,
.message, .error {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 12px 15px;
    border-radius: var(--r-sm);
    margin-bottom: 16px;
    font-size: 13px;
    border: 1px solid transparent;
}
.flash-success, .message { background: var(--ok-soft);     color: var(--ok);     border-color: var(--ok-border); }
.flash-error, .error     { background: var(--danger-soft); color: var(--danger); border-color: var(--danger-border); }
.flash-info              { background: var(--brand-soft);  color: var(--brand-600); border-color: var(--brand-soft-2); }

.flash-success::before { content: "✓"; font-weight: 700; }
.flash-error::before   { content: "!"; font-weight: 800; }
.flash-info::before    { content: "i"; font-weight: 700; font-style: italic; }
.message::before       { content: "✓"; font-weight: 700; }
.error::before         { content: "!"; font-weight: 800; }

/* ------------------------------------------------------------------ *
 *  模态框
 * ------------------------------------------------------------------ */
.modal-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(10, 16, 28, .55);
    backdrop-filter: blur(3px);
    z-index: 9000;
    align-items: center;
    justify-content: center;
    padding: 20px;
}
html[data-theme="dark"] .modal-overlay { background: rgba(0, 0, 0, .68); }

.modal-overlay.show { display: flex; animation: overlay-in .18s ease; }

@keyframes overlay-in { from { opacity: 0; } to { opacity: 1; } }

.modal {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    padding: 22px 24px;
    width: 100%;
    max-width: 470px;
    box-shadow: var(--shadow-3);
    max-height: 90vh;
    overflow-y: auto;
    animation: modal-in .24s cubic-bezier(.2, 1.1, .4, 1);
}

@keyframes modal-in {
    from { transform: translateY(10px) scale(.985); opacity: 0; }
    to   { transform: translateY(0)    scale(1);    opacity: 1; }
}

.modal h3 {
    margin: 0 0 18px;
    font-size: 16px;
    font-weight: 650;
    color: var(--text);
    padding-bottom: 13px;
    border-bottom: 1px solid var(--border);
}

.form-group { margin-bottom: 15px; }
.form-group label {
    display: block;
    margin-bottom: 6px;
    font-size: 12.5px;
    color: var(--text-2);
    font-weight: 550;
}

.form-group input[type="text"],
.form-group input[type="password"],
.form-group input[type="file"],
.form-group textarea,
.form-group select {
    width: 100%;
    padding: 10px 13px;
    border: 1px solid var(--border-2);
    background: var(--surface);
    color: var(--text);
    border-radius: var(--r-sm);
    font-size: 13px;
    font-family: inherit;
    transition: border-color .16s, box-shadow .16s;
}

.form-group input::placeholder,
.form-group textarea::placeholder { color: var(--text-3); }

.form-group textarea { resize: vertical; min-height: 76px; }

.form-group input:focus,
.form-group textarea:focus,
.form-group select:focus {
    outline: none;
    border-color: var(--brand);
    box-shadow: var(--ring);
}

.form-group small { color: var(--text-3); font-size: 12px; display: block; margin-top: 6px; line-height: 1.7; }
.form-group small code {
    background: var(--surface-3);
    padding: 1px 5px;
    border-radius: 4px;
    font-size: 11.5px;
}

/* 强调型提示（如「这个 MAC 原值别改，改了设备掉线」） */
.form-group small.is-warn {
    color: var(--text-2);
    background: var(--warn-soft);
    border-left: 3px solid var(--warn);
    border-radius: 0 6px 6px 0;
    padding: 9px 12px;
    margin-top: 8px;
}
.form-group small.is-warn strong { color: var(--warn); }

.modal-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px; }

/* 文件选择控件 */
input[type="file"] {
    padding: 9px 12px;
    cursor: pointer;
}
input[type="file"]::file-selector-button {
    margin-right: 10px;
    padding: 6px 12px;
    border: 1px solid var(--border-2);
    background: var(--surface-3);
    color: var(--text-2);
    border-radius: var(--r-xs);
    font-family: inherit;
    font-size: 12.5px;
    cursor: pointer;
}
input[type="file"]::file-selector-button:hover { background: var(--border); color: var(--text); }

/* ------------------------------------------------------------------ *
 *  登录 / 改密页
 * ------------------------------------------------------------------ */
body.center-page {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    padding: 24px;
}

body.center-page::before {
    content: "";
    position: fixed;
    inset: 0;
    background:
        radial-gradient(700px 400px at 50% 0%, var(--brand-soft) 0%, transparent 65%);
    pointer-events: none;
    z-index: 0;
}

.auth-card {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: 404px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    padding: 34px 32px 28px;
    box-shadow: var(--shadow-3);
}

.auth-brand {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    margin-bottom: 24px;
    text-align: center;
}

.auth-brand .brand-mark {
    width: 50px;
    height: 50px;
    border-radius: 14px;
}

.auth-brand h1 {
    margin: 0;
    font-size: 19px;
    font-weight: 700;
    color: var(--text);
    letter-spacing: -.2px;
    padding: 0;
    background: none;
    box-shadow: none;
}

.auth-brand p {
    margin: 0;
    font-size: 12.5px;
    color: var(--text-3);
}

.login-box,
.change-password-box { /* 兼容旧标记 */ }

.login-box h2,
.change-password-box h2 {
    margin: 0 0 20px;
    font-size: 18px;
    font-weight: 650;
    color: var(--text);
    text-align: center;
}

.field-icon { position: relative; }
.field-icon > svg {
    position: absolute;
    left: 13px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-3);
    pointer-events: none;
}
.field-icon > .form-control { padding-left: 40px !important; }

.form-control {
    width: 100%;
    padding: 12px 14px;
    border: 1px solid var(--border-2);
    background: var(--surface);
    color: var(--text);
    border-radius: var(--r-sm);
    font-size: 14px;
    font-family: inherit;
    transition: border-color .16s, box-shadow .16s;
}
.form-control::placeholder { color: var(--text-3); }
.form-control:focus { outline: none; border-color: var(--brand); box-shadow: var(--ring); }

.mb-3 { margin-bottom: 13px; }

.form-label { display: block; font-size: 12.5px; color: var(--text-2); margin-bottom: 5px; font-weight: 550; }

.login-hint {
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
    text-align: center;
    color: var(--text-3);
    font-size: 12px;
    line-height: 1.8;
}
.login-hint p { margin: 2px 0; }

.auth-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: 18px;
}

.btn-secondary {
    display: block;
    width: 100%;
    padding: 11px;
    background: var(--surface-3);
    color: var(--text-2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    text-align: center;
    text-decoration: none;
    font-size: 14px;
    font-weight: 500;
}
.btn-secondary:hover { background: var(--border); color: var(--text); }

.back-btn { margin-top: 14px; }

/* ------------------------------------------------------------------ *
 *  页脚
 * ------------------------------------------------------------------ */
.foot {
    max-width: var(--wrap);
    margin: 0 auto;
    padding: 0 20px 28px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    color: var(--text-3);
    font-size: 12px;
}

/* ------------------------------------------------------------------ *
 *  响应式
 * ------------------------------------------------------------------ */
@media (max-width: 1280px) {
    .stats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 1080px) {
    .panel-grid { grid-template-columns: 1fr; }
}

@media (max-width: 720px) {
    .detail-grid { grid-template-columns: 1fr; }
}

/* 窄屏：侧栏从左侧竖排收成顶部横排 */
@media (max-width: 1080px) {
    /* 竖排时基准对齐必须是 stretch：base 里的 align-items:flex-start 会让
       .main-col 按 max-content 撑宽（实测 876 视口下撑到 955，页面横向溢出 79px，
       表格自身的 overflow-x 也失效）。stretch + min-width:0 才能让表格在卡片内滚。 */
    .shell { flex-direction: column; align-items: stretch; }
    .main-col { width: 100%; }

    .sidebar {
        position: static;
        height: auto;
        width: 100%;
        flex: 0 0 auto;
        flex-direction: row;
        align-items: center;
        gap: 10px;
        padding: 10px 14px;
        border-right: none;
        border-bottom: 1px solid var(--border);
        overflow-x: auto;
    }

    .sidebar .brand { flex: 0 0 auto; }
    .side-nav { flex-direction: row; flex: 0 1 auto; gap: 4px; }
    .side-nav-label { display: none; }
    .side-nav a { padding: 7px 11px; white-space: nowrap; }
    .side-foot { display: none; }
}

@media (max-width: 980px) {
    .topbar-inner { flex-wrap: wrap; padding: 9px 14px; }
    .nav { order: 3; width: 100%; }
    .wrap { padding: 16px 14px 32px; }
}

@media (max-width: 720px) {
    body { font-size: 13.5px; }

    .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
    .stat { padding: 12px; gap: 10px; }
    .stat-icon { width: 36px; height: 36px; border-radius: 9px; }
    .stat .v { font-size: 20px; }

    .brand-text small { display: none; }

    .page-title { font-size: 18px; }

    .toolbar { flex-direction: column; align-items: stretch; }
    .search-container, .batch-container { max-width: none; width: 100%; }
    .batch-container select { flex: 1; }

    .page-jump { margin-left: 0; width: 100%; }

    .modal { padding: 18px; border-radius: var(--r-md); }
    .auth-card { padding: 26px 20px 22px; }

    .user-meta { display: none; }
    .user-chip { padding: 0; border: none; background: none; }
}

@media (max-width: 420px) {
    .stats { grid-template-columns: 1fr; }
}

/* 打印 */
@media print {
    .topbar, .toolbar, .pagination, .per-page, .action-buttons, #toast-container, .foot { display: none !important; }
    body { background: #fff; }
    .table-container { box-shadow: none; border-color: #ddd; }
}

/* ------------------------------------------------------------------ *
 *  登录记录页（login_logs.php）
 * ------------------------------------------------------------------ */

/* 顶部态势条：累计 / 近 24 小时成功·失败 */
.log-summary {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 18px;
    padding: 11px 16px;
    margin: 0 0 14px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-1);
    font-size: 13.5px;
    color: var(--text-2);
}
.log-sum-item b {
    font-family: var(--mono);
    font-size: 14px;
    color: var(--text);
    margin-left: 2px;
}
.log-sum-item b.is-ok { color: var(--ok); }
.log-sum-item.is-alert {
    color: var(--danger);
    background: var(--danger-soft);
    border: 1px solid var(--danger-border);
    border-radius: var(--r-pill);
    padding: 2px 11px;
}
.log-sum-item.is-alert b { color: var(--danger); }
.log-sum-note { font-size: 12.5px; color: var(--warn); }

/* 结果胶囊。
 * ⚠ 只能靠 padding 撑开、绝不给固定宽高 —— 写死 width 的后果见 .whitelist-badge
 *   那次事故（文字一加长就把底框撑破）。 */
.log-badge {
    display: inline-flex;
    align-items: center;
    padding: 1px 9px;
    border-radius: var(--r-pill);
    font-size: 12px;
    font-weight: 500;
    white-space: nowrap;
    border: 1px solid transparent;
}
.log-badge.log-ok {
    color: var(--ok);
    background: var(--ok-soft);
    border-color: var(--ok-border);
}
.log-badge.log-fail {
    color: var(--danger);
    background: var(--danger-soft);
    border-color: var(--danger-border);
}

/* 失败行淡红底：滚动时一眼扫出异常 */
.tbl-logins tbody tr.row-fail,
.tbl-logins tbody tr.row-fail:hover { background: var(--danger-soft); }

/* 结果筛选（全部 / 仅成功 / 仅失败） */
.filter-btn {
    display: inline-flex;
    align-items: center;
    height: 36px;
    padding: 0 16px;
    border: 1px solid var(--border-2);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--text-2);
    font-size: 14px;
    text-decoration: none;
    white-space: nowrap;
    transition: border-color .16s, color .16s, background .16s;
}
.filter-btn:hover { border-color: var(--brand); color: var(--brand); }
.filter-btn.is-on {
    background: var(--brand);
    border-color: var(--brand);
    color: var(--on-brand);
}

/* 客户端列：显示 UA 短名，过长省略（完整值在 title 上） */
.tbl-logins .log-ua {
    color: var(--text-3);
    font-size: 13px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 130px;
}
