401 lines
21 KiB
CSS
401 lines
21 KiB
CSS
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
|
|
:root {
|
|
--border: rgba(56,189,248,0.11);
|
|
--border-h: rgba(56,189,248,0.26);
|
|
--accent-out: #38bdf8;
|
|
--accent-in: #f472b6;
|
|
--blocked: #cc2200;
|
|
--text: #dde6f0;
|
|
--text-dim: #445566;
|
|
--mono: 'JetBrains Mono', monospace;
|
|
--ui: 'Space Grotesk', sans-serif;
|
|
--green: #4ade80;
|
|
--yellow: #fbbf24;
|
|
--panel-bg: rgba(4,8,16,0.96);
|
|
}
|
|
|
|
body { color:var(--text); font-family:var(--ui); overflow:hidden; height:100vh; width:100vw; }
|
|
::-webkit-scrollbar { width:3px; } ::-webkit-scrollbar-track { background:transparent; } ::-webkit-scrollbar-thumb { background:var(--border); border-radius:2px; }
|
|
.panel { background:var(--panel-bg); border:1px solid var(--border); border-radius:12px; backdrop-filter:blur(20px); }
|
|
button { font-family:var(--ui); cursor:pointer; border:none; outline:none; }
|
|
.mono { font-family:var(--mono); }
|
|
|
|
/* ── Layout ── */
|
|
.app { position:relative; width:100vw; height:100vh; overflow:hidden; }
|
|
.world-svg { position:absolute; inset:0; width:100%; height:100%; display:block; }
|
|
|
|
/* ── Zoom ── */
|
|
.zoom-controls { position:absolute; bottom:72px; right:20px; display:flex; flex-direction:column; gap:4px; z-index:20; }
|
|
.zoom-controls button { width:32px; height:32px; background:var(--panel-bg); border:1px solid var(--border); color:var(--text-dim); border-radius:8px; font-size:17px; display:flex; align-items:center; justify-content:center; transition:all 0.15s; }
|
|
.zoom-controls button:hover { border-color:var(--border-h); color:var(--accent-out); }
|
|
.zoom-reset { font-size:12px !important; }
|
|
|
|
/* ── Clock ── */
|
|
.clock { position:absolute; top:14px; left:14px; padding:8px 14px; z-index:20; display:flex; flex-direction:column; gap:2px; }
|
|
.clock-time { font-size:18px; font-weight:600; letter-spacing:0.05em; }
|
|
.clock-date { font-size:10px; color:var(--text-dim); }
|
|
|
|
/* ── Topbar ── */
|
|
.topbar { position:absolute; top:14px; left:50%; transform:translateX(-50%); display:flex; align-items:center; gap:20px; padding:9px 18px; white-space:nowrap; z-index:20; }
|
|
.topbar-left { display:flex; align-items:center; gap:12px; }
|
|
.logo { display:flex; align-items:center; gap:7px; }
|
|
.logo-icon { font-size:16px; color:var(--accent-out); filter:drop-shadow(0 0 5px var(--accent-out)); }
|
|
.logo-text { font-size:14px; font-weight:600; letter-spacing:0.08em; }
|
|
.conn-badge { display:flex; align-items:center; gap:5px; font-size:10px; font-weight:500; padding:2px 8px; border-radius:20px; }
|
|
.conn-ok { background:rgba(74,222,128,0.08); color:var(--green); border:1px solid rgba(74,222,128,0.2); }
|
|
.conn-err { background:rgba(248,113,113,0.08); color:#f87171; border:1px solid rgba(248,113,113,0.2); }
|
|
.conn-dot { width:5px; height:5px; border-radius:50%; background:currentColor; animation:pulse 2s infinite; }
|
|
.topbar-stats { display:flex; gap:16px; }
|
|
.stat { display:flex; flex-direction:column; align-items:center; gap:1px; }
|
|
.stat-label { font-size:8px; font-weight:500; letter-spacing:0.1em; color:var(--text-dim); text-transform:uppercase; }
|
|
.stat-value { font-size:12px; font-weight:600; }
|
|
.topbar-toggles { display:flex; gap:6px; align-items:center; }
|
|
.toggle-btn { padding:4px 11px; border-radius:20px; font-size:11px; font-weight:500; background:rgba(255,255,255,0.04); border:1px solid var(--border); color:var(--text-dim); transition:all 0.2s; }
|
|
.toggle-btn:hover { color:var(--text); }
|
|
.toggle-active { background:rgba(255,255,255,0.07) !important; }
|
|
.origin-toggle { display:flex; border-radius:20px; overflow:hidden; border:1px solid var(--border); }
|
|
.origin-toggle button { padding:4px 9px; font-size:10px; font-weight:500; background:rgba(255,255,255,0.04); color:var(--text-dim); border:none; border-left:1px solid var(--border); transition:all 0.15s; }
|
|
.origin-toggle button:first-child { border-left:none; }
|
|
.origin-toggle button:hover { color:var(--text); }
|
|
.origin-toggle button.active { background:rgba(204,34,0,0.15); color:#ff6666; }
|
|
.origin-count { display:inline-block; font-size:8px; font-family:var(--mono); background:rgba(255,255,255,0.1); border-radius:8px; padding:0 4px; margin-left:3px; }
|
|
|
|
/* ── Left dock ── */
|
|
.left-dock {
|
|
position:absolute; left:0; top:50%; transform:translateY(-50%);
|
|
display:flex; flex-direction:column; gap:2px;
|
|
background:var(--panel-bg); border:1px solid var(--border);
|
|
border-left:none; border-radius:0 12px 12px 0;
|
|
padding:6px 4px; z-index:20;
|
|
}
|
|
.dock-btn {
|
|
display:flex; flex-direction:column; align-items:center; gap:3px;
|
|
padding:10px 10px; border-radius:8px; background:transparent;
|
|
color:var(--text-dim); transition:all 0.15s; min-width:54px;
|
|
border:1px solid transparent; position:relative;
|
|
}
|
|
.dock-btn:hover { background:rgba(255,255,255,0.05); color:var(--text); }
|
|
.dock-btn.dock-active { background:rgba(56,189,248,0.08); color:var(--accent-out); border-color:rgba(56,189,248,0.2); }
|
|
.dock-icon { font-size:16px; line-height:1; }
|
|
.dock-label { font-size:9px; font-weight:500; letter-spacing:0.04em; white-space:nowrap; }
|
|
.dock-count { position:absolute; top:5px; right:5px; font-size:8px; font-family:var(--mono); background:rgba(56,189,248,0.2); color:var(--accent-out); border-radius:8px; padding:0 4px; }
|
|
|
|
/* ── Panel stack ── */
|
|
.panel-stack {
|
|
position:absolute; left:70px; top:74px;
|
|
display:flex; flex-direction:row; gap:8px;
|
|
height:calc(100vh - 88px); z-index:20;
|
|
pointer-events:none;
|
|
}
|
|
.side-panel {
|
|
width:272px; height:100%; display:flex; flex-direction:column;
|
|
overflow:hidden; pointer-events:all; animation:fadeIn 0.15s ease;
|
|
flex-shrink:0;
|
|
}
|
|
.side-panel-header {
|
|
display:flex; align-items:center; gap:8px; padding:10px 12px;
|
|
border-bottom:1px solid var(--border); flex-shrink:0;
|
|
font-size:12px; font-weight:600;
|
|
}
|
|
.side-panel-header .tab-count {
|
|
background:rgba(56,189,248,0.1); color:var(--accent-out);
|
|
font-size:9px; padding:1px 5px; border-radius:8px; font-family:var(--mono);
|
|
}
|
|
.side-panel-header .close-btn { margin-left:auto; }
|
|
|
|
/* ── Search ── */
|
|
.search-wrap { display:flex; align-items:center; gap:6px; margin:7px 8px 3px; padding:6px 9px; background:rgba(255,255,255,0.03); border:1px solid var(--border); border-radius:7px; flex-shrink:0; transition:border-color 0.15s; }
|
|
.search-wrap:focus-within { border-color:var(--border-h); }
|
|
.search-icon { font-size:13px; color:var(--text-dim); flex-shrink:0; }
|
|
.search-input { flex:1; background:none; border:none; outline:none; font-family:var(--ui); font-size:11px; color:var(--text); }
|
|
.search-input::placeholder { color:var(--text-dim); }
|
|
.search-clear { background:none; color:var(--text-dim); font-size:10px; }
|
|
.search-clear:hover { color:var(--text); }
|
|
|
|
/* ── Device list ── */
|
|
.device-list { overflow-y:auto; flex:1; padding:3px 8px 8px; display:flex; flex-direction:column; gap:2px; }
|
|
.device-item { display:flex; align-items:center; gap:8px; padding:7px 8px; border-radius:7px; background:transparent; border:1px solid transparent; color:var(--text); text-align:left; width:100%; transition:all 0.12s; }
|
|
.device-item:hover { background:rgba(255,255,255,0.03); border-color:var(--border); }
|
|
.device-item.selected { background:rgba(56,189,248,0.07); border-color:rgba(56,189,248,0.28); }
|
|
.all-devices { border-style:dashed; border-color:var(--border); margin-bottom:3px; }
|
|
.all-devices.selected { border-style:solid; }
|
|
.device-icon { font-size:15px; flex-shrink:0; }
|
|
.device-info { flex:1; min-width:0; display:flex; flex-direction:column; gap:1px; }
|
|
.device-name { font-size:11px; font-weight:500; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
|
.device-sub { font-size:9px; color:var(--text-dim); }
|
|
.device-traffic { display:flex; flex-direction:column; align-items:flex-end; gap:1px; font-size:9px; font-family:var(--mono); flex-shrink:0; }
|
|
|
|
/* ── Flow log ── */
|
|
.flow-log { overflow-y:auto; flex:1; padding:5px 8px; display:flex; flex-direction:column; gap:2px; }
|
|
.flow-entry { display:flex; align-items:center; gap:7px; padding:5px 7px; border-radius:6px; background:rgba(255,255,255,0.02); border:1px solid transparent; font-size:11px; transition:background 0.1s; }
|
|
.flow-entry:hover { background:rgba(255,255,255,0.05); }
|
|
.flow-entry.flow-blocked { border-color:rgba(204,34,0,0.2); background:rgba(204,34,0,0.05); }
|
|
.flow-dir { font-size:12px; font-weight:700; flex-shrink:0; width:13px; text-align:center; }
|
|
.flow-dir.out { color:var(--accent-out); }
|
|
.flow-dir.in { color:var(--accent-in); }
|
|
.flow-dir.blocked { color:var(--blocked); }
|
|
.flow-detail { flex:1; min-width:0; display:flex; flex-direction:column; gap:1px; }
|
|
.flow-device { font-weight:500; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; font-size:11px; }
|
|
.flow-dest { font-size:9px; color:var(--text-dim); }
|
|
.flow-ip { font-size:8px; color:var(--text-dim); opacity:0.6; }
|
|
.flow-bytes { font-size:9px; color:var(--text-dim); flex-shrink:0; font-family:var(--mono); }
|
|
|
|
/* ── Top talkers ── */
|
|
.talkers-sub { font-size:9px; color:var(--text-dim); font-weight:400; }
|
|
.talker-list { padding:8px; display:flex; flex-direction:column; gap:8px; overflow-y:auto; flex:1; }
|
|
.talker-row { display:flex; align-items:center; gap:8px; }
|
|
.talker-rank { font-size:10px; color:var(--text-dim); font-family:var(--mono); width:12px; flex-shrink:0; }
|
|
.talker-info { flex:1; min-width:0; }
|
|
.talker-name { font-size:11px; font-weight:500; display:block; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; margin-bottom:4px; }
|
|
.talker-bar-wrap { height:2px; background:rgba(255,255,255,0.06); border-radius:1px; }
|
|
.talker-bar { height:100%; background:var(--accent-out); border-radius:1px; transition:width 0.5s ease; }
|
|
.talker-bytes { display:flex; flex-direction:column; align-items:flex-end; gap:1px; font-size:9px; font-family:var(--mono); flex-shrink:0; }
|
|
|
|
/* ── Arc popup ── */
|
|
.arc-popup { position:absolute; top:74px; right:14px; width:240px; padding:13px; z-index:30; animation:fadeIn 0.15s ease; }
|
|
.arc-popup-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:11px; }
|
|
.arc-popup-dir { font-size:11px; font-weight:600; letter-spacing:0.05em; }
|
|
.arc-row { display:flex; justify-content:space-between; align-items:baseline; padding:4px 0; border-bottom:1px solid rgba(255,255,255,0.04); font-size:11px; }
|
|
.arc-row:last-child { border-bottom:none; }
|
|
.arc-label { color:var(--text-dim); flex-shrink:0; margin-right:8px; }
|
|
.arc-value { font-weight:500; text-align:right; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:160px; }
|
|
|
|
/* ── Device detail ── */
|
|
.device-detail { position:absolute; bottom:14px; right:14px; width:230px; padding:13px; z-index:20; animation:fadeIn 0.15s ease; }
|
|
.detail-header { display:flex; align-items:center; gap:9px; margin-bottom:10px; }
|
|
.detail-icon { font-size:20px; }
|
|
.detail-name { font-size:12px; font-weight:600; }
|
|
.detail-mac { font-size:9px; color:var(--text-dim); font-family:var(--mono); }
|
|
.detail-grid { display:flex; flex-direction:column; gap:5px; }
|
|
.detail-row { display:flex; justify-content:space-between; align-items:center; font-size:11px; }
|
|
.detail-label { color:var(--text-dim); }
|
|
.detail-value { font-weight:500; }
|
|
|
|
/* ── Shared close btn ── */
|
|
.close-btn { background:rgba(255,255,255,0.04); border:1px solid var(--border); color:var(--text-dim); border-radius:5px; width:21px; height:21px; font-size:9px; display:flex; align-items:center; justify-content:center; transition:all 0.12s; flex-shrink:0; }
|
|
.close-btn:hover { color:var(--text); }
|
|
/* ── Color picker ── */
|
|
.color-picker { position:absolute; bottom:60px; right:14px; width:240px; padding:14px; z-index:30; animation:fadeIn 0.15s ease; }
|
|
.picker-header { display:flex; align-items:center; gap:8px; margin-bottom:12px; }
|
|
.picker-title { font-size:12px; font-weight:600; flex:1; }
|
|
.picker-reset { font-size:10px; padding:3px 8px; border-radius:6px; background:rgba(255,255,255,0.06); border:1px solid var(--border); color:var(--text-dim); }
|
|
.picker-reset:hover { color:var(--text); }
|
|
.picker-rows { display:flex; flex-direction:column; gap:8px; margin-bottom:14px; }
|
|
.color-row { display:flex; align-items:center; justify-content:space-between; }
|
|
.color-label { font-size:11px; color:var(--text-dim); }
|
|
.color-input-wrap { display:flex; align-items:center; gap:7px; }
|
|
.color-native { width:28px; height:22px; padding:0; border:1px solid var(--border); border-radius:5px; background:none; cursor:pointer; }
|
|
.color-native::-webkit-color-swatch-wrapper { padding:2px; }
|
|
.color-native::-webkit-color-swatch { border:none; border-radius:3px; }
|
|
.color-hex { font-size:10px; color:var(--text-dim); width:54px; }
|
|
.picker-preset-label { font-size:9px; text-transform:uppercase; letter-spacing:0.1em; color:var(--text-dim); display:block; margin-bottom:7px; }
|
|
.preset-btns { display:flex; flex-wrap:wrap; gap:5px; }
|
|
.preset-btn { display:flex; align-items:center; gap:5px; padding:4px 9px; border-radius:6px; font-size:10px; background:rgba(255,255,255,0.04); border:1px solid var(--border); color:var(--text-dim); transition:all 0.12s; }
|
|
.preset-btn:hover { color:var(--text); border-color:var(--border-h); }
|
|
.preset-swatch { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
|
|
|
|
/* ── Floating draggable panels ── */
|
|
.floating-panel {
|
|
position: absolute;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
z-index: 25;
|
|
animation: fadeIn 0.15s ease;
|
|
min-width: 220px;
|
|
min-height: 160px;
|
|
}
|
|
|
|
.fp-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 9px 12px;
|
|
border-bottom: 1px solid var(--border);
|
|
cursor: grab;
|
|
flex-shrink: 0;
|
|
user-select: none;
|
|
}
|
|
.fp-header:active { cursor: grabbing; }
|
|
|
|
.fp-title {
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
flex: 1; /* takes all space, pushes everything else right */
|
|
}
|
|
|
|
/* badge / sub-label next to title */
|
|
.fp-header .tab-count,
|
|
.fp-header .talkers-sub {
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* export button — same height as close btn */
|
|
.export-btn-sm {
|
|
font-size: 9px;
|
|
padding: 0 8px;
|
|
height: 21px;
|
|
line-height: 1;
|
|
border-radius: 5px;
|
|
background: rgba(255,255,255,0.05);
|
|
border: 1px solid var(--border);
|
|
color: var(--text-dim);
|
|
transition: all 0.15s;
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
.export-btn-sm:hover { color: var(--text); }
|
|
|
|
.fp-body {
|
|
flex: 1;
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.fp-resize {
|
|
position: absolute;
|
|
bottom: 2px;
|
|
right: 4px;
|
|
font-size: 14px;
|
|
color: var(--text-dim);
|
|
cursor: se-resize;
|
|
opacity: 0.4;
|
|
line-height: 1;
|
|
user-select: none;
|
|
}
|
|
.fp-resize:hover { opacity: 0.9; }
|
|
|
|
/* fp-body children that need to scroll */
|
|
.fp-body .device-list,
|
|
.fp-body .flow-log,
|
|
.fp-body .talker-list {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
/* search inside floating panel */
|
|
.fp-body .search-wrap { flex-shrink: 0; }
|
|
|
|
/* ── Protocol breakdown ── */
|
|
.proto-list { padding:10px 12px; display:flex; flex-direction:column; gap:10px; overflow-y:auto; flex:1; }
|
|
.proto-row { display:flex; flex-direction:column; gap:4px; }
|
|
.proto-name { font-size:12px; font-weight:600; }
|
|
.proto-bar-wrap { height:4px; background:rgba(255,255,255,0.06); border-radius:2px; }
|
|
.proto-bar { height:100%; border-radius:2px; transition:width 0.4s ease; }
|
|
.proto-stats { display:flex; gap:10px; font-size:10px; color:var(--text-dim); }
|
|
.proto-pct { min-width:36px; }
|
|
.proto-bytes { font-family:var(--mono); }
|
|
.proto-count { font-family:var(--mono); opacity:0.6; }
|
|
|
|
/* ── Replay bar ── */
|
|
.replay-bar {
|
|
position:absolute; bottom:20px; left:50%; transform:translateX(-50%);
|
|
padding:10px 16px; z-index:30; min-width:480px;
|
|
animation:fadeIn 0.15s ease;
|
|
}
|
|
.replay-header { display:flex; align-items:center; gap:12px; margin-bottom:8px; font-size:11px; }
|
|
.replay-label { font-weight:600; color:var(--accent-out); }
|
|
.replay-time { color:var(--text); }
|
|
.replay-count { color:var(--text-dim); flex:1; }
|
|
.replay-live { padding:3px 10px; border-radius:6px; background:rgba(56,189,248,0.1); border:1px solid rgba(56,189,248,0.3); color:var(--accent-out); font-size:10px; }
|
|
.replay-live:hover { background:rgba(56,189,248,0.2); }
|
|
.replay-controls { display:flex; align-items:center; gap:8px; }
|
|
.replay-btn { width:28px; height:28px; border-radius:6px; background:rgba(255,255,255,0.06); border:1px solid var(--border); color:var(--text); font-size:13px; display:flex; align-items:center; justify-content:center; flex-shrink:0; }
|
|
.replay-btn:hover { border-color:var(--border-h); color:var(--accent-out); }
|
|
.replay-slider { flex:1; accent-color:var(--accent-out); cursor:pointer; }
|
|
.replay-pos { font-size:10px; color:var(--text-dim); min-width:32px; text-align:right; }
|
|
|
|
/* ── Dock divider ── */
|
|
.dock-divider { height:1px; background:var(--border); margin:4px 6px; }
|
|
|
|
/* ── Heatmap legend ── */
|
|
.heatmap-legend {
|
|
position:absolute; bottom:20px; right:70px;
|
|
padding:10px 14px; z-index:20; min-width:180px;
|
|
animation:fadeIn 0.15s ease;
|
|
}
|
|
.heatmap-title { font-size:10px; font-weight:600; color:var(--text-dim); text-transform:uppercase; letter-spacing:0.08em; margin-bottom:8px; }
|
|
.heatmap-scale { display:flex; align-items:center; gap:8px; margin-bottom:6px; }
|
|
.heatmap-min, .heatmap-max { font-size:10px; font-family:var(--mono); color:var(--text-dim); flex-shrink:0; }
|
|
.heatmap-gradient {
|
|
flex:1; height:6px; border-radius:3px;
|
|
background: linear-gradient(to right, rgba(0,40,60,0.4), rgba(0,130,150,0.6), rgba(0,200,220,0.85));
|
|
}
|
|
.heatmap-top { font-size:10px; color:var(--text-dim); }
|
|
.heatmap-top strong { color:var(--accent-out); }
|
|
.heatmap-hover { font-size:10px; color:var(--text); margin-top:4px; font-family:var(--mono); }
|
|
|
|
/* ── Traffic timeline ── */
|
|
.timeline {
|
|
position:absolute; bottom:0; left:0; right:0;
|
|
padding:5px 14px 5px; z-index:15;
|
|
border-radius:0; border-left:none; border-right:none; border-bottom:none;
|
|
background:rgba(4,8,16,0.92);
|
|
user-select:none;
|
|
}
|
|
.timeline-header {
|
|
display:flex; align-items:center; gap:12px; margin-bottom:3px;
|
|
}
|
|
.timeline-label { font-size:9px; color:var(--text-dim); text-transform:uppercase; letter-spacing:0.08em; flex:1; }
|
|
.timeline-stats { display:flex; gap:12px; font-size:9px; font-family:var(--mono); }
|
|
.timeline-stat-out { color:var(--accent-out); }
|
|
.timeline-stat-in { color:var(--accent-in); }
|
|
.timeline-toggles { display:flex; gap:4px; }
|
|
.timeline-toggle {
|
|
padding:1px 7px; border-radius:10px; font-size:9px; font-weight:500;
|
|
background:rgba(255,255,255,0.04); border:1px solid var(--border);
|
|
color:var(--text-dim); transition:all 0.15s; cursor:pointer;
|
|
}
|
|
.timeline-toggle:hover { color:var(--text); }
|
|
.timeline-toggle.on-out { background:rgba(56,189,248,0.1); color:var(--accent-out); border-color:rgba(56,189,248,0.3); }
|
|
.timeline-toggle.on-in { background:rgba(244,114,182,0.1); color:var(--accent-in); border-color:rgba(244,114,182,0.3); }
|
|
.timeline-wrap { position:relative; }
|
|
.timeline-svg { display:block; width:100%; cursor:crosshair; }
|
|
.timeline-tooltip {
|
|
position:absolute; top:-36px; transform:translateX(-50%);
|
|
background:var(--panel-bg); border:1px solid var(--border);
|
|
padding:3px 8px; border-radius:6px; font-size:9px; font-family:var(--mono);
|
|
white-space:nowrap; pointer-events:none; z-index:5;
|
|
}
|
|
.timeline-cursor { position:absolute; top:0; bottom:0; width:1px; background:rgba(255,255,255,0.3); pointer-events:none; }
|
|
|
|
/* ── Country filter badge ── */
|
|
.country-badge {
|
|
position:absolute; top:74px; left:50%; transform:translateX(-50%);
|
|
display:flex; align-items:center; gap:10px;
|
|
padding:6px 12px; z-index:25; font-size:11px;
|
|
animation:fadeIn 0.15s ease;
|
|
}
|
|
.country-badge strong { color:var(--accent-out); }
|
|
.country-badge-count { color:var(--text-dim); font-size:10px; }
|
|
|
|
/* ── Device group dot ── */
|
|
.group-dot { display:inline-block; width:6px; height:6px; border-radius:50%; margin-right:5px; vertical-align:middle; flex-shrink:0; }
|
|
|
|
/* ── Groups panel ── */
|
|
.groups-body { display:flex; flex-direction:column; flex:1; overflow:hidden; }
|
|
.group-filters { display:flex; flex-wrap:wrap; gap:4px; padding:8px; flex-shrink:0; border-bottom:1px solid var(--border); }
|
|
.group-filter-btn { padding:3px 10px; border-radius:20px; font-size:10px; font-weight:500; background:rgba(255,255,255,0.04); border:1px solid var(--border); color:var(--text-dim); transition:all 0.15s; }
|
|
.group-filter-btn:hover { color:var(--text); }
|
|
.group-filter-btn.active { background:rgba(56,189,248,0.1); color:var(--accent-out); border-color:rgba(56,189,248,0.3); }
|
|
.group-count { font-size:8px; font-family:var(--mono); background:rgba(255,255,255,0.1); border-radius:8px; padding:0 4px; margin-left:3px; }
|
|
|
|
.group-device-list { overflow-y:auto; flex:1; padding:4px 8px; display:flex; flex-direction:column; gap:3px; }
|
|
.group-device-row { display:flex; align-items:center; gap:8px; padding:5px 6px; border-radius:6px; transition:background 0.1s; }
|
|
.group-device-row:hover { background:rgba(255,255,255,0.03); }
|
|
.group-device-info { flex:1; min-width:0; display:flex; flex-direction:column; gap:1px; }
|
|
.group-select {
|
|
background:rgba(255,255,255,0.06); border:1px solid var(--border);
|
|
color:var(--text-dim); border-radius:5px; font-size:9px; padding:2px 4px;
|
|
cursor:pointer; flex-shrink:0; font-family:var(--ui);
|
|
}
|
|
.group-select:hover { border-color:var(--border-h); }
|
|
.group-select option { background:#0d1829; }
|
|
|
|
/* ── Misc ── */
|
|
.geoip-warning { position:absolute; bottom:14px; left:50%; transform:translateX(-50%); padding:7px 14px; font-size:11px; color:var(--yellow); border-color:rgba(251,191,36,0.15); z-index:20; white-space:nowrap; }
|
|
.empty-state { color:var(--text-dim); font-size:11px; text-align:center; padding:24px 12px; }
|