Files
NexusGate/public/styles.css
T
aaaamoooo 18bbd388ea feat(web): topbar/nav cleanup batch (items 10-13)
Item 10: remove the disabled decorative topbar search input (each page
has its own working search); CSS rule and media-query reference removed.
Item 11: menu/title renames — 服务器 -> 节点管理, 客户与订阅 -> 用户订阅,
转发与节点 -> 入站&出站, 设置与运维 -> 设置 (nav, TITLES/breadcrumb and
cross-references synced); the chains page add button is now 添加入站 and
its count reads N 个入站; the 安装与命令 page is merged into 设置
(commandsHTML block between the settings grid and the jobs table) and
the page itself is removed from nav, PAGES, TITLES, load() and the view
map — an old #commands hash now lands on the SPA's standard overview
fallback.
Item 12: remove the system page's 最近活动 panel (rendering and its
audit label map plus orphaned CSS); backend audit records untouched.
Item 13: the settings jobs table gets the w-jobs treatment — ID, status
and time cells never wrap, compact row padding, and the error column is
capped at 22% width so an empty error column no longer balloons.

Also fixes a class collision from the item-8 batch: the exit-mode
segmented control is renamed .seg -> .segctl so it no longer draws a
border box around the system page info-bar segments.
Golden re-captured: the only diff is the served index HTML inside
errors.badSubscription, audited character by character as exactly these
renames and removals.
2026-10-21 11:18:00 +08:00

406 lines
30 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* amo 控制台样式 — 按 3x-ui 风格样张落地。浅色默认,[data-theme="dark"] 深色。
字体为系统字体栈,零外部依赖(路由器可离线部署)。 */
:root{
--bg:#f0f2f5; --sider:#ffffff; --card:#ffffff; --card-hover:#fafafa;
--border:#d9dce1; --border-soft:#e8eaed;
--text:#20242a; --text-2:#5a6068; --text-3:#8a8f98;
--primary:#1668dc; --primary-hover:#3c89e8; --primary-soft:rgba(22,104,220,.10); --primary-text:#0958d9;
--green:#52c41a; --green-text:#237804; --green-soft:rgba(82,196,26,.13);
--red:#ff4d4f; --red-text:#cf1322; --red-soft:rgba(255,77,79,.08);
--orange:#faad14; --orange-text:#975a00; --orange-soft:rgba(250,173,20,.14);
--purple:#9254de; --purple-text:#722ed1; --purple-soft:rgba(146,84,222,.10);
--cyan:#13c2c2; --cyan-text:#096f74; --cyan-soft:rgba(19,194,194,.10);
--pink-text:#c41d7f; --pink-soft:rgba(235,47,150,.09);
--sky-text:#0958d9; --sky-soft:rgba(22,104,220,.09);
--gray-soft:rgba(0,0,0,.05); --pill-bg:rgba(0,0,0,.045);
--hover-bg:rgba(0,0,0,.04); --row-hover:rgba(0,0,0,.02); --th-bg:#fafafa;
--dot-off:#c2c6cc; --tgl-off:#c9ccd3; --track:rgba(0,0,0,.08);
--pop-bg:#ffffff; --pop-shadow:0 12px 32px rgba(0,0,0,.16);
--trans-bg:rgba(82,196,26,.14); --trans-text:#237804;
--chart-2:#6f757f;
--radius:8px;
--font:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
--mono:"SF Mono",SFMono-Regular,Consolas,"Liberation Mono",monospace;
}
[data-theme="dark"]{
--bg:#1a1b1f; --sider:#1e2024; --card:#23252b; --card-hover:#282a31;
--border:#33363e; --border-soft:#2b2d34;
--text:#e9eaee; --text-2:#a2a7b1; --text-3:#6f757f;
--primary-soft:rgba(22,104,220,.16); --primary-text:#69a7ff;
--green-text:#73d13d;
--red-text:#ff7875; --red-soft:rgba(255,77,79,.13);
--orange-text:#ffc53d; --orange-soft:rgba(250,173,20,.13);
--purple-text:#b37feb; --purple-soft:rgba(146,84,222,.17);
--cyan-text:#36cfc9; --cyan-soft:rgba(19,194,194,.13);
--pink-text:#ff85c0; --pink-soft:rgba(235,47,150,.16);
--sky-text:#8dbdff; --sky-soft:rgba(105,167,255,.15);
--gray-soft:rgba(255,255,255,.07); --pill-bg:rgba(255,255,255,.06);
--hover-bg:rgba(255,255,255,.05); --row-hover:rgba(255,255,255,.025); --th-bg:rgba(255,255,255,.02);
--dot-off:#5a5e66; --tgl-off:#3c404a; --track:rgba(255,255,255,.09);
--pop-bg:#2e3038; --pop-shadow:0 12px 32px rgba(0,0,0,.55);
--trans-bg:rgba(82,196,26,.12); --trans-text:#95de64;
--chart-2:#8a8f98;
}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--text);font-family:var(--font);font-size:14px;line-height:1.55;-webkit-font-smoothing:antialiased}
a{color:inherit;text-decoration:none}
.hidden{display:none !important}
button{font-family:var(--font)}
input,select,textarea{font-family:var(--font);color:var(--text)}
:focus-visible{outline:2px solid var(--primary-hover);outline-offset:1px}
/* ---------- 布局 ---------- */
.layout{display:flex;min-height:100vh}
.sider{flex:0 0 224px;width:224px;background:var(--sider);border-right:1px solid var(--border-soft);position:sticky;top:0;height:100vh;display:flex;flex-direction:column;z-index:30}
.brand{display:flex;align-items:center;height:58px;padding:0 20px;border-bottom:1px solid var(--border-soft);font-size:19px;font-weight:700;letter-spacing:.4px}
.menu{padding:12px 10px;flex:1;overflow-y:auto}
.mi{display:flex;align-items:center;gap:10px;padding:8px 10px;margin:2px 0;border-radius:6px;color:var(--text-2);cursor:pointer}
.mi svg{width:16px;height:16px;flex:none}
.mi:hover{background:var(--hover-bg);color:var(--text)}
.mi.active{background:var(--primary-soft);color:var(--primary-text);font-weight:500}
.sider-foot{padding:12px 20px;border-top:1px solid var(--border-soft);color:var(--text-2);font-size:12.5px;display:flex;justify-content:space-between;align-items:center;gap:8px}
.sider-foot .foot-right{display:inline-flex;align-items:center;gap:6px;color:var(--text-3)}
.main{flex:1;min-width:0;display:flex;flex-direction:column}
.topbar{height:58px;display:flex;align-items:center;gap:12px;padding:0 24px;border-bottom:1px solid var(--border-soft);background:var(--bg);position:sticky;top:0;z-index:20}
.crumb{color:var(--text-3);font-size:13px;white-space:nowrap}
.crumb b{color:var(--text);font-weight:600;font-size:15px}
.topbar .sp{flex:1}
.theme-btn{border:1px solid var(--border);background:var(--card);color:var(--text-2);border-radius:6px;padding:5px 11px;font-size:12.5px;cursor:pointer;white-space:nowrap}
.theme-btn:hover{border-color:var(--primary);color:var(--primary-text)}
.content{padding:24px;width:100%}
.panel{background:var(--card);border:1px solid var(--border-soft);border-radius:var(--radius);margin-bottom:16px}
.panel-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 16px;border-bottom:1px solid var(--border-soft)}
.panel-head h2{font-size:14.5px;font-weight:600}
.panel-body{padding:14px 16px}
.toolbar{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.page-tools{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:14px}
.search{background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);padding:6px 12px;font-size:13px;width:260px}
select.search{width:auto}
.btn{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);background:var(--card-hover);color:var(--text);border-radius:6px;padding:5px 14px;font-size:13px;cursor:pointer;white-space:nowrap}
.btn:hover{border-color:var(--primary);color:var(--primary-text)}
.btn.primary{background:var(--primary);border-color:var(--primary);color:#fff}
.btn.primary:hover{background:var(--primary-hover);color:#fff}
.btn.danger{color:var(--red-text)}
.btn.danger:hover{border-color:var(--red);color:var(--red-text);background:var(--red-soft)}
.btn.small{padding:2px 10px;font-size:12px}
.btn.full{width:100%;justify-content:center;padding:8px 14px}
.btn:disabled{opacity:.55;cursor:default}
/* ---------- 系统状态 ---------- */
.stat-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:16px}
.stat{background:var(--card);border:1px solid var(--border-soft);border-radius:var(--radius);padding:14px 16px 10px;overflow:hidden}
.stat .hd{display:flex;align-items:center;gap:7px;color:var(--text-2);font-size:13px}
.stat .hd svg{width:15px;height:15px;color:var(--primary);flex:none}
.stat .hd .scope{margin-left:auto;color:var(--text-3);font-size:11.5px}
.stat .big{font-size:30px;font-weight:600;line-height:1.25;margin-top:4px;font-variant-numeric:tabular-nums}
.stat .big small{font-size:15px;font-weight:500;color:var(--text-2);margin-left:2px}
.stat .det{color:var(--text-2);font-size:12.5px;font-variant-numeric:tabular-nums}
.stat .mm{display:flex;justify-content:space-between;color:var(--text-3);font-size:12px;margin-top:8px;font-variant-numeric:tabular-nums}
.spark{display:block;width:100%;height:44px;margin-top:4px}
.mid-grid{display:grid;grid-template-columns:2fr 1fr;gap:16px;margin-bottom:16px;align-items:stretch}
.chart-card{padding:14px 18px 12px;display:flex;flex-direction:column;margin-bottom:0}
.chart-hd{display:flex;align-items:flex-start;gap:12px}
.chart-hd h2{font-size:14.5px;font-weight:600}
.chart-hd .legend{margin-left:auto;display:flex;gap:18px;font-size:13px;white-space:nowrap;font-variant-numeric:tabular-nums}
.legend .up{color:var(--primary-text);font-weight:600}
.legend .dn{color:var(--text-2);font-weight:600}
.legend .lb{color:var(--text-3);font-weight:400;font-size:12px;margin-right:3px}
.chart{flex:1;width:100%;margin-top:8px}
.stat3{display:flex;border-top:1px solid var(--border-soft);margin-top:10px;padding-top:11px}
.stat3>div{flex:1;padding:0 14px}
.stat3>div:first-child{padding-left:0}
.stat3>div+div{border-left:1px solid var(--border-soft)}
.stat3 .k{color:var(--text-3);font-size:12px}
.stat3 .v{font-size:16.5px;font-weight:600;margin-top:1px;font-variant-numeric:tabular-nums}
.conn .big{font-size:34px;font-weight:600;line-height:1.2;font-variant-numeric:tabular-nums}
.conn .big span{font-size:13px;font-weight:400;color:var(--text-3);margin-left:6px}
.conn .proto-row{display:flex;gap:26px;margin-top:8px;font-size:13px;font-variant-numeric:tabular-nums}
.conn .proto-row b{font-weight:600;margin-left:5px}
.swatch{display:inline-block;width:16px;height:0;border-top:2.5px solid var(--primary);border-radius:2px;vertical-align:middle}
.swatch.g{border-top-color:var(--chart-2)}
.info-bar{display:flex;gap:0;padding:14px 18px}
.info-bar .seg{flex:1;padding:0 18px;min-width:0}
.info-bar .seg:first-child{padding-left:0}
.info-bar .seg+.seg{border-left:1px solid var(--border-soft)}
.info-bar .cap{color:var(--text-3);font-size:12.5px;display:flex;align-items:center;gap:6px;margin-bottom:7px}
.info-bar .cap svg{width:14px;height:14px}
.kv{display:flex;gap:22px;flex-wrap:wrap}
.kv .item .k{display:block;color:var(--text-3);font-size:11px;letter-spacing:.6px}
.kv .item .v{font-size:16px;font-weight:600;font-variant-numeric:tabular-nums}
.kv .item .v.mono{font-family:var(--mono);font-size:13px;font-weight:500;word-break:break-all}
.ln-up{stroke:var(--primary);fill:none;stroke-width:1.8;stroke-linejoin:round;stroke-linecap:round}
.ln-dn{stroke:var(--chart-2);fill:none;stroke-width:1.8;stroke-linejoin:round;stroke-linecap:round}
.mean{stroke:var(--primary);stroke-width:1;stroke-dasharray:4 4;opacity:.55;fill:none}
.mean-g{stroke:var(--chart-2);stroke-width:1;stroke-dasharray:4 4;opacity:.6;fill:none}
.grid-ln{stroke:var(--border-soft);stroke-width:1;stroke-dasharray:3 5;fill:none}
.stop-up-a{stop-color:var(--primary);stop-opacity:.26}
.stop-up-b{stop-color:var(--primary);stop-opacity:0}
.notice{border:1px solid var(--orange);background:var(--orange-soft);color:var(--orange-text);border-radius:6px;padding:8px 12px;font-size:13px;margin-bottom:16px}
/* ---------- 表格通用 ---------- */
.table-wrap{overflow-x:auto}
.table-wrap.visible{overflow:visible}
table{width:100%;border-collapse:collapse}
table.w-servers{min-width:1390px}
table.w-customers{min-width:1120px}
table.w-nodes{min-width:1180px}
table.w-jobs td{white-space:nowrap;padding-top:5px;padding-bottom:5px}
table.w-jobs th:last-child{width:22%}
table.w-jobs td:last-child{white-space:normal;min-width:120px;word-break:break-word}
thead th{text-align:left;font-size:12.5px;font-weight:600;color:var(--text-2);letter-spacing:.3px;padding:7px 12px;border-bottom:1px solid var(--border-soft);background:var(--th-bg);white-space:nowrap}
thead th .sarr{color:var(--text-3);font-size:10px;margin-left:3px}
thead th.ctr,tbody td.ctr{text-align:center}
tbody td{padding:6px 12px;border-bottom:1px solid var(--border-soft);vertical-align:middle;font-size:13.5px}
tbody tr:last-child td{border-bottom:none}
tbody tr:hover{background:var(--row-hover)}
tbody tr.dragging{opacity:.4}
tbody tr.drag-over td{border-top:2px solid var(--primary)}
.badge{display:inline-flex;align-items:center;gap:5px;padding:1px 8px;border-radius:5px;font-size:12px;line-height:20px;white-space:nowrap}
.badge.green{background:var(--green-soft);color:var(--green-text)}
.badge.red{background:var(--red-soft);color:var(--red-text)}
.badge.orange{background:var(--orange-soft);color:var(--orange-text)}
.badge.blue{background:var(--primary-soft);color:var(--primary-text)}
.badge.gray{background:var(--gray-soft);color:var(--text-2)}
.num{font-variant-numeric:tabular-nums;white-space:nowrap}
.mut{color:var(--text-3)}
.dot{width:8px;height:8px;border-radius:50%;display:inline-block;flex:none}
.dot.on{background:var(--green);animation:pulse 2s infinite}
.dot.off{background:var(--dot-off)}
.dot.bad{background:var(--red)}
@keyframes pulse{0%{box-shadow:0 0 0 0 rgba(82,196,26,.45)}70%{box-shadow:0 0 0 6px rgba(82,196,26,0)}100%{box-shadow:0 0 0 0 rgba(82,196,26,0)}}
.op-cell{display:flex;align-items:center;gap:1px;white-space:nowrap}
.op-cell input[type="checkbox"]{margin-right:7px}
.icon-btn{width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;border:none;background:transparent;color:var(--text-2);border-radius:6px;cursor:pointer;padding:0;vertical-align:middle}
.icon-btn svg{width:17px;height:17px;display:block}
.icon-btn:hover{color:var(--primary-text);background:var(--hover-bg)}
.icon-btn.del{color:var(--red-text)}
.icon-btn.del:hover{background:var(--red-soft);color:var(--red-text)}
/* 图标悬停提示气泡(3x-ui 式:黑底白字圆角 + 小尖角,挂 body 避免被表格滚动容器裁剪) */
.tip-bubble{position:fixed;z-index:200;pointer-events:none;background:#141414;color:#fff;font-size:12px;line-height:1.25;padding:6px 9px;border-radius:6px;white-space:nowrap;opacity:0;transition:opacity .12s;box-shadow:0 4px 14px rgba(0,0,0,.25)}
.tip-bubble.show{opacity:1}
.tip-bubble::after{content:"";position:absolute;top:100%;left:var(--tip-arrow-left,50%);transform:translateX(-50%);border:5px solid transparent;border-top-color:#141414;border-bottom:0}
.tgl{position:relative;display:inline-block;width:38px;height:21px;vertical-align:middle;flex:none}
.tgl input{opacity:0;width:0;height:0;position:absolute}
.tgl .tr{position:absolute;inset:0;background:var(--tgl-off);border-radius:99px;transition:background .2s;cursor:pointer}
.tgl .tr::before{content:"";position:absolute;width:17px;height:17px;border-radius:50%;background:#fff;top:2px;left:2px;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.35)}
.tgl input:checked + .tr{background:var(--primary)}
.tgl input:checked + .tr::before{transform:translateX(17px)}
.tgl input:focus-visible + .tr{outline:2px solid var(--primary-hover);outline-offset:2px}
.tgl input:disabled + .tr{opacity:.5;cursor:default}
.pill{display:inline-flex;align-items:center;gap:7px;background:var(--pill-bg);color:var(--text);border-radius:999px;padding:3px 11px;font-size:12.5px;white-space:nowrap;font-variant-numeric:tabular-nums}
.pill.green{background:var(--green-soft);color:var(--green-text);font-weight:600}
.pill.red{background:var(--red-soft);color:var(--red-text);font-weight:600}
.pill.gray{background:var(--gray-soft);color:var(--text-2)}
.pill.mut{color:var(--text-3)}
.mini-bar{width:62px;height:6px;border-radius:99px;background:var(--track);overflow:hidden;display:inline-block;flex:none}
.mini-bar i{display:block;height:100%;background:var(--primary);border-radius:99px}
.pill.warn .mini-bar i{background:var(--orange)}
.pill.danger .mini-bar i{background:var(--red)}
.pager{display:flex;justify-content:flex-end;align-items:center;gap:6px;padding:9px 16px;border-top:1px solid var(--border-soft);color:var(--text-2);font-size:13px}
.pg-btn{min-width:28px;height:28px;padding:0 7px;border:1px solid var(--border);background:var(--card);border-radius:6px;color:var(--text-2);cursor:pointer;font-size:13px}
.pg-btn.active{border-color:var(--primary);color:var(--primary-text)}
.pg-btn:disabled{opacity:.45;cursor:default}
.empty{padding:28px 16px;text-align:center;color:var(--text-3);font-size:13px}
.empty b{display:block;color:var(--text-2);font-size:14px;margin-bottom:2px}
/* ---------- 服务器页 ---------- */
.stats{display:grid;grid-template-columns:repeat(3,1fr);background:var(--card);border:1px solid var(--border-soft);border-radius:var(--radius);margin-bottom:14px}
.stats.six{grid-template-columns:repeat(6,1fr)}
.stats .stat{padding:14px 22px;border:none;background:transparent}
.stats .stat .lab{color:var(--text-2);font-size:12.5px;margin-bottom:3px}
.stats .stat .val{display:flex;align-items:center;gap:8px;font-size:20px;font-weight:600;font-variant-numeric:tabular-nums}
.stats .stat .val svg{width:19px;height:19px;flex:none}
.ic-dim{color:var(--text-2)} .ic-green{color:var(--green)} .ic-red{color:var(--red)} .ic-bolt{color:var(--orange)}
.exp{display:inline-flex;width:20px;height:20px;align-items:center;justify-content:center;border:1px solid var(--border);border-radius:5px;color:var(--text-2);font-size:14px;line-height:1;background:var(--card);cursor:pointer;padding:0}
.eye-btn{width:24px;height:24px;vertical-align:-6px;margin-left:4px}
.eye-btn svg{width:15px;height:15px}
.dev-name{font-weight:600;font-size:13.5px;white-space:nowrap}
.addr{font-family:var(--mono);font-size:12.5px;color:var(--text-2);white-space:nowrap}
.status{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;font-weight:500}
.status.on{color:var(--green-text)}
.status.off{color:var(--red-text)}
.warn-ic{width:15px;height:15px;color:var(--orange);flex:none;vertical-align:-2px}
.ver-cell{display:inline-flex;align-items:center;gap:7px;white-space:nowrap}
.ver{font-family:var(--mono);font-size:12.5px}
.clients-cell{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;font-variant-numeric:tabular-nums}
.clients-cell svg{width:16px;height:16px;color:var(--text-3);flex:none}
.clients-cell .on-n{color:var(--green-text);font-weight:600}
.hb{white-space:nowrap;color:var(--text-2)}
.detail-row td{background:var(--th-bg);padding:12px 16px}
.detail-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:8px 22px;font-size:13px}
.detail-grid .k{color:var(--text-3);font-size:11.5px;display:block}
.detail-grid .v{font-weight:500}
.detail-grid .v.err{color:var(--red-text)}
.detail-actions{display:flex;gap:8px;margin-top:12px;flex-wrap:wrap}
/* ---------- 客户页 ---------- */
.pres{display:inline-flex;align-items:center;gap:6px;border-radius:999px;padding:2px 11px;font-size:12.5px;font-weight:600;white-space:nowrap}
.pres.on{background:var(--green-soft);color:var(--green-text)}
.pres.off{background:var(--gray-soft);color:var(--text-3);font-weight:400}
.paused-note{display:block;color:var(--red-text);font-size:12px;font-weight:500;margin-top:4px;white-space:nowrap}
.cust-name{font-weight:600;font-size:13.5px;white-space:nowrap}
.cust-note{display:block;color:var(--text-3);font-size:12px;margin-top:1px;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.in-chip{display:inline-flex;padding:2px 9px;border-radius:6px;background:var(--primary-soft);color:var(--primary-text);font-size:12.5px;font-weight:500;line-height:20px;white-space:nowrap}
.in-chip.more{background:var(--gray-soft);color:var(--text-2);margin-left:5px;cursor:pointer;border:none;font-family:var(--font)}
.in-chip.more:hover{color:var(--primary-text);background:var(--primary-soft)}
.in-chip.ss{background:var(--pink-soft);color:var(--pink-text)}
.in-chip.mixed{background:var(--orange-soft);color:var(--orange-text)}
.speed{font-variant-numeric:tabular-nums;white-space:nowrap}
.speed.mut{color:var(--text-3)}
.filter-chip{display:inline-flex;align-items:center;gap:6px;background:var(--primary-soft);color:var(--primary-text);border-radius:999px;padding:3px 6px 3px 11px;font-size:12.5px}
.filter-chip button{border:none;background:transparent;color:inherit;cursor:pointer;font-size:14px;line-height:1;padding:2px}
/* ---------- 节点页 ---------- */
.grip{display:inline-flex;padding:3px 2px;border-radius:4px;color:var(--text-3);cursor:grab;vertical-align:middle}
.grip svg{width:13px;height:13px;display:block}
.grip:hover{color:var(--text);background:var(--hover-bg)}
.grip:active{cursor:grabbing}
td.menu-td{white-space:nowrap}
.node-name{font-weight:600;font-size:13.5px;white-space:nowrap}
.srv-chip{display:inline-flex;padding:2px 10px;border-radius:6px;font-size:12.5px;font-weight:500;line-height:20px;white-space:nowrap}
.srv-chip.online{background:var(--primary-soft);color:var(--primary-text)}
.srv-chip.offline{background:var(--red-soft);color:var(--red-text)}
.srv-chip.degraded{background:var(--orange-soft);color:var(--orange-text)}
.port{font-variant-numeric:tabular-nums}
.proto{display:inline-flex;padding:0 6px;border-radius:5px;font-size:11.5px;font-weight:600;line-height:18px;white-space:nowrap}
.proto.vless{background:var(--purple-soft);color:var(--purple-text)}
.proto.ss{background:var(--cyan-soft);color:var(--cyan-text)}
.proto.mixed{background:var(--orange-soft);color:var(--orange-text)}
.proto.other{background:var(--gray-soft);color:var(--text-2)}
.trans{display:inline-flex;padding:0 6px;border-radius:5px;font-size:11.5px;line-height:18px;white-space:nowrap;background:var(--trans-bg);color:var(--trans-text)}
.sec{display:inline-flex;padding:0 6px;border-radius:5px;font-size:11.5px;line-height:18px;white-space:nowrap;background:var(--sky-soft);color:var(--sky-text)}
.sec.plain{background:var(--gray-soft);color:var(--text-2)}
.badge-stack{display:inline-flex;gap:4px;flex-wrap:nowrap;align-items:center}
.clients{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;cursor:pointer}
.clients>svg{width:17px;height:17px;color:var(--text-3);flex:none}
.online-num{color:var(--green-text);font-weight:600;padding:1px 2px}
.online-num.zero{color:var(--text-3);font-weight:400}
/* ---------- 浮层(挂 body) ---------- */
.float-pop{position:fixed;z-index:90;background:var(--pop-bg);border:1px solid var(--border);border-radius:8px;box-shadow:var(--pop-shadow);min-width:176px;max-width:320px;padding:6px 0}
.float-pop .pop-head{display:flex;justify-content:space-between;align-items:center;padding:6px 12px;border-bottom:1px solid var(--border-soft);font-size:12px;color:var(--text-2)}
.float-pop .pop-head b{color:var(--text);font-size:13px}
.float-pop .pop-item{display:flex;align-items:center;gap:8px;padding:5px 12px;color:var(--text);font-size:13px}
.float-pop .pop-item .in-chip{margin:2px 0}
.float-pop .pop-foot{padding:6px 12px;border-top:1px solid var(--border-soft);font-size:11px;color:var(--text-3)}
.float-pop .menu-item{display:flex;width:100%;align-items:center;gap:8px;padding:7px 12px;border:none;background:transparent;color:var(--text);font-size:13px;cursor:pointer;text-align:left}
.float-pop .menu-item:hover{background:var(--hover-bg)}
.float-pop .menu-item.danger{color:var(--red-text)}
.float-pop .chip-list{padding:8px 12px;display:flex;flex-direction:column;gap:6px;align-items:flex-start}
/* ---------- 弹窗与表单 ---------- */
.modal-overlay{position:fixed;inset:0;background:rgba(10,12,16,.45);z-index:80;display:flex;align-items:flex-start;justify-content:center;overflow-y:auto;padding:36px 16px}
.modal{width:640px;max-width:100%;margin:0}
.modal.wide{width:820px}
.modal-head{display:flex;align-items:center;justify-content:space-between;padding:13px 18px;border-bottom:1px solid var(--border-soft)}
.modal-head h2{font-size:15.5px;font-weight:600}
.modal-body{padding:16px 18px}
.stack{display:flex;flex-direction:column;gap:12px}
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px 16px}
.form-grid .wide{grid-column:1 / -1}
label{display:flex;flex-direction:column;gap:5px;font-size:13px;color:var(--text-2)}
label>input,label>select,label>textarea,.field>input{border:1px solid var(--border);background:var(--card);border-radius:6px;padding:6px 10px;font-size:13.5px;color:var(--text)}
label>textarea{min-height:56px;resize:vertical}
label>input:focus,label>select:focus,label>textarea:focus{border-color:var(--primary);outline:none}
.form-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}
.form-actions .left{margin-right:auto}
.inline-fields{display:flex;gap:8px}
.inline-fields>*{flex:1;min-width:0}
.pair-fields{display:flex;gap:10px;align-items:flex-end}
.pair-fields label{flex:1}
.form-error{color:var(--red-text);font-size:13px;min-height:18px}
.codebox{background:var(--bg);border:1px solid var(--border-soft);border-radius:6px;padding:10px 12px;font-family:var(--mono);font-size:12.5px;white-space:pre-wrap;word-break:break-all;color:var(--text)}
.section-title{grid-column:1 / -1;font-size:13px;font-weight:600;color:var(--text);border-top:1px solid var(--border-soft);padding-top:12px}
.kv-table{width:100%;border-collapse:collapse}
.kv-table td{padding:5px 8px;border-bottom:1px solid var(--border-soft);font-size:13px;vertical-align:top}
.kv-table td.k{color:var(--text-3);width:130px;white-space:nowrap}
.mono{font-family:var(--mono);font-size:12.5px;word-break:break-all}
/* 页签 */
.segctl{display:inline-flex;border:1px solid var(--border);border-radius:8px;overflow:hidden}
.segctl button{padding:6px 16px;background:var(--card);border:none;color:var(--text-2);cursor:pointer;font:inherit;font-size:13px}
.segctl button.active{background:var(--primary);color:#fff}
.tabs{display:flex;gap:2px;border-bottom:1px solid var(--border-soft);margin-bottom:14px}
.tabs button{border:none;background:transparent;padding:7px 14px;font-size:13.5px;color:var(--text-2);cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px}
.tabs button.active{color:var(--primary-text);border-bottom-color:var(--primary);font-weight:500}
.tab-pane.hidden{display:none}
/* 凭据行 */
.cred-row{display:flex;align-items:center;gap:8px;padding:7px 0;border-bottom:1px solid var(--border-soft)}
.cred-row:last-child{border-bottom:none}
.cred-row .k{width:110px;flex:none;color:var(--text-3);font-size:12.5px}
.cred-row .v{flex:1;min-width:0;font-family:var(--mono);font-size:12.5px;word-break:break-all}
.cred-group{margin-bottom:14px}
.cred-group .g-head{display:flex;align-items:center;gap:8px;font-weight:600;font-size:13.5px;margin-bottom:2px}
/* 链接页签条目 */
.link-item{border:1px solid var(--border-soft);border-radius:8px;padding:10px 12px;display:flex;flex-direction:column;gap:8px}
.link-item .row{display:flex;gap:8px;align-items:center}
.link-item input[type="text"],.link-item input:not([type]){flex:1;border:1px solid var(--border);background:var(--card);border-radius:6px;padding:6px 10px;font-size:13px;min-width:0}
.link-item .remark{flex:0 0 150px}
.link-item .status-line{font-size:12px;color:var(--text-3)}
.link-item .status-line .err{color:var(--red-text)}
.links-head{display:flex;align-items:center;justify-content:space-between;margin:14px 0 8px}
.links-head h3{font-size:13.5px;font-weight:600}
.links-note{font-size:13px;color:var(--text-2)}
.links-empty{color:var(--text-3);font-size:13px;padding:6px 0}
/* 关联入站选择器 */
.picker{position:relative}
.picker-box{display:flex;flex-wrap:wrap;gap:6px;align-items:center;border:1px solid var(--border);border-radius:6px;padding:5px 8px;min-height:34px;cursor:text;background:var(--card)}
.picker-box .chip{display:inline-flex;align-items:center;gap:5px;background:var(--primary-soft);color:var(--primary-text);border-radius:5px;padding:1px 4px 1px 8px;font-size:12.5px}
.picker-box .chip button{border:none;background:transparent;color:inherit;cursor:pointer;font-size:13px;line-height:1;padding:2px}
.picker-box .ph{color:var(--text-3);font-size:13px}
.picker-box .search-ic{margin-left:auto;color:var(--text-3);flex:none}
.picker-panel{position:absolute;left:0;right:0;top:calc(100% + 4px);z-index:40;background:var(--pop-bg);border:1px solid var(--border);border-radius:8px;box-shadow:var(--pop-shadow);padding:6px}
.picker-tools{display:flex;gap:8px;align-items:center;padding:2px 4px 6px}
.picker-tools input{flex:1;border:1px solid var(--border);border-radius:6px;padding:5px 9px;font-size:13px;background:var(--card)}
.picker-list{max-height:220px;overflow-y:auto}
.picker-opt{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;cursor:pointer;font-size:13.5px;color:var(--text)}
.picker-opt:hover{background:var(--hover-bg)}
.picker-opt.sel{background:var(--primary-soft)}
.picker-opt .ck{margin-left:auto;color:var(--primary-text);font-weight:700;visibility:hidden}
.picker-opt.sel .ck{visibility:visible}
.picker-opt small{color:var(--text-3)}
/* 订阅弹窗 */
.subscription-row{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--border-soft)}
.subscription-row>div:first-child{flex:1;min-width:0}
.subscription-row b{display:block;font-size:13.5px}
.subscription-row code{font-family:var(--mono);font-size:11.5px;color:var(--text-2);word-break:break-all}
.subscription-actions{display:flex;gap:6px;flex:none}
.subscription-qr{padding:10px 0;text-align:center}
.subscription-qr svg{max-width:180px;height:auto}
.warn-note{border:1px solid var(--orange);background:var(--orange-soft);color:var(--orange-text);border-radius:6px;padding:8px 12px;font-size:13px}
/* 命令页 / 运维页 */
.command-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px;margin-bottom:16px}
.command-grid .panel{margin-bottom:0}
.command-item{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--border-soft)}
.command-item:last-child{border-bottom:none}
.command-item>div{flex:1;min-width:0}
.command-item b{display:block;font-size:13.5px}
.command-item code{font-family:var(--mono);font-size:12.5px;color:var(--primary-text)}
.grid-3{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px}
.grid-3 .panel{margin-bottom:0}
.health-row{display:flex;align-items:center;justify-content:space-between;padding:7px 0;border-bottom:1px solid var(--border-soft);font-size:13.5px}
.health-row:last-child{border-bottom:none}
.health-row span{color:var(--text-3);font-size:12.5px;display:block}
.tag{display:inline-flex;padding:1px 8px;border-radius:5px;background:var(--gray-soft);color:var(--text-2);font-size:12px;line-height:20px}
/* 登录 */
.login-shell{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:20px}
.login-card{width:360px;max-width:100%;padding:26px 26px 18px;position:relative;margin:0}
.login-brand{font-size:26px;font-weight:700;letter-spacing:.4px;margin-bottom:18px}
.login-theme{position:absolute;top:14px;right:14px}
.login-card label{margin-bottom:12px}
.login-card label>input{width:100%}
/* toast */
#toasts{position:fixed;right:18px;bottom:18px;z-index:120;display:flex;flex-direction:column;gap:8px}
.toast{background:var(--pop-bg);border:1px solid var(--border);border-left:3px solid var(--green);color:var(--text);border-radius:8px;box-shadow:var(--pop-shadow);padding:9px 14px;font-size:13px;max-width:360px}
.toast.error{border-left-color:var(--red)}
@media (max-width:1100px){.stat-grid{grid-template-columns:repeat(2,1fr)}.mid-grid{grid-template-columns:1fr}.info-bar{flex-direction:column;gap:14px}.info-bar .seg{padding:0}.info-bar .seg+.seg{border-left:none}.stats{grid-template-columns:repeat(2,1fr)}.stats.six{grid-template-columns:repeat(3,1fr)}}
@media (max-width:760px){.sider{display:none}.form-grid{grid-template-columns:1fr}.content{padding:8px}}