Files
holesail-browser/extension/dashboard/dashboard.css
T
Raven Scott 5e40b14a91
CI / Build & Test (push) Successful in 2m55s
fix(overview): center empty state messages and disable scroll when list is empty
Add ov-empty CSS class to .ov-scroll-area when an overview list has no
items — disables overflow scrolling and uses flexbox to vertically and
horizontally center the empty message. Class is removed automatically
when data is present. Keeps the normal scrollable layout intact for
populated lists.
2026-03-01 02:23:59 -05:00

933 lines
30 KiB
CSS

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #09090b;
--surface: #111113;
--card: #18181b;
--elevated: #1f1f23;
--border: #27272a;
--border2: #3f3f46;
--text: #fafafa;
--text2: #a1a1aa;
--text3: #71717a;
--text4: #52525b;
--cyan: #22d3ee;
--cyan-dim: rgba(34,211,238,.12);
--cyan-mid: rgba(34,211,238,.25);
--green: #4ade80;
--green-dim: rgba(74,222,128,.12);
--amber: #fbbf24;
--amber-dim: rgba(251,191,36,.12);
--red: #f43f5e;
--red-dim: rgba(244,63,94,.12);
--red-mid: rgba(244,63,94,.25);
--radius-sm: 6px;
--radius: 10px;
--radius-lg: 14px;
--sidebar-w: 224px;
--transition: 0.15s ease;
}
[data-theme="light"] {
--bg: #f4f4f5;
--surface: #ffffff;
--card: #ffffff;
--elevated: #f9f9fb;
--border: #e4e4e7;
--border2: #d4d4d8;
--text: #18181b;
--text2: #3f3f46;
--text3: #71717a;
--text4: #a1a1aa;
--cyan: #0891b2;
--cyan-dim: rgba(8,145,178,.10);
--cyan-mid: rgba(8,145,178,.20);
--green: #16a34a;
--green-dim: rgba(22,163,74,.10);
--amber: #d97706;
--amber-dim: rgba(217,119,6,.10);
--red: #e11d48;
--red-dim: rgba(225,29,72,.10);
--red-mid: rgba(225,29,72,.20);
}
html, body {
height: 100%;
background: var(--bg);
color: var(--text);
font-family: 'Inter', system-ui, sans-serif;
font-size: 14px;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
/* ── Scrollbar ─────────────────────────────────── */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 99px; }
::-webkit-scrollbar-thumb:hover { background: var(--text4); }
/* ── Layout ────────────────────────────────────── */
.layout { display: flex; height: 100vh; overflow: hidden; }
/* ── Sidebar ───────────────────────────────────── */
.sidebar {
width: var(--sidebar-w);
flex-shrink: 0;
background: var(--surface);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
overflow: hidden;
}
.sidebar-logo {
padding: 20px 18px 16px;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
gap: 10px;
}
.sidebar-logo-icon {
width: 32px;
height: 32px;
border-radius: var(--radius-sm);
overflow: hidden;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
.sidebar-logo-icon img {
width: 32px;
height: 32px;
display: block;
}
.sidebar-logo-text { line-height: 1.2; }
.sidebar-logo-name { font-size: 15px; font-weight: 700; color: var(--text); letter-spacing: -0.02em; }
.sidebar-logo-version { font-size: 11px; color: var(--text4); margin-top: 1px; }
.sidebar-nav { flex: 1; padding: 8px 0; overflow-y: auto; }
.nav-item {
display: flex;
align-items: center;
gap: 10px;
padding: 9px 14px;
margin: 1px 8px;
border-radius: var(--radius-sm);
color: var(--text3);
font-size: 13.5px;
font-weight: 500;
cursor: pointer;
transition: background var(--transition), color var(--transition);
user-select: none;
}
.nav-item:hover { background: var(--border); color: var(--text2); }
.nav-item.active { background: var(--cyan-dim); color: var(--cyan); }
.nav-item svg { width: 16px; height: 16px; flex-shrink: 0; }
.nav-badge {
margin-left: auto;
font-size: 11px;
font-weight: 600;
padding: 1px 7px;
border-radius: 99px;
background: var(--elevated);
color: var(--text3);
min-width: 20px;
text-align: center;
}
.nav-item.active .nav-badge { background: var(--cyan-mid); color: var(--cyan); }
.sidebar-footer {
padding: 12px 16px;
border-top: 1px solid var(--border);
}
.status-pill {
display: flex;
align-items: center;
gap: 7px;
font-size: 12px;
color: var(--text3);
}
.status-dot {
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--text4);
flex-shrink: 0;
}
.status-dot.connected { background: var(--green); box-shadow: 0 0 6px var(--green); animation: pulse 2.5s infinite; }
.status-dot.disconnected { background: var(--red); }
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.45; }
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* ── Main ──────────────────────────────────────── */
.main {
flex: 1;
overflow-y: auto;
display: flex;
flex-direction: column;
}
/* Top bar */
.topbar {
position: sticky;
top: 0;
z-index: 10;
background: var(--bg);
border-bottom: 1px solid var(--border);
padding: 0 28px;
height: 52px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.topbar-title { font-size: 15px; font-weight: 600; color: var(--text); }
.topbar-actions { display: flex; align-items: center; gap: 8px; }
.content { padding: 24px 28px; flex: 1; min-height: 0; display: flex; flex-direction: column; }
/* ── Page visibility ───────────────────────────── */
.page { display: none; }
.page.active { display: block; }
/* Overview page fills the content area as a flex column so Quick Actions
sticks to the bottom and the list cards share all remaining space. */
#page-dashboard.active {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
overflow: hidden;
}
/* ── Cards ─────────────────────────────────────── */
.card {
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
overflow: hidden;
margin-bottom: 16px;
}
.card-header {
padding: 14px 18px;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.card-title { font-size: 13.5px; font-weight: 600; color: var(--text); }
.card-subtitle { font-size: 12px; color: var(--text3); margin-top: 2px; }
.card-body { padding: 16px 18px; }
.card-body.flush { padding: 0; }
/* ── Stats grid ────────────────────────────────── */
.stats-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
margin-bottom: 16px;
}
@media (max-width: 1100px) { .stats-grid { grid-template-columns: repeat(3, 1fr) !important; } }
@media (max-width: 700px) { .stats-grid { grid-template-columns: repeat(2, 1fr) !important; } }
.stat-card {
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 16px 18px;
display: flex;
flex-direction: column;
gap: 8px;
}
.stat-icon {
width: 32px;
height: 32px;
border-radius: var(--radius-sm);
display: flex;
align-items: center;
justify-content: center;
}
.stat-icon svg { width: 16px; height: 16px; }
.stat-icon.cyan { background: var(--cyan-dim); color: var(--cyan); }
.stat-icon.green { background: var(--green-dim); color: var(--green); }
.stat-icon.amber { background: var(--amber-dim); color: var(--amber); }
.stat-icon.red { background: var(--red-dim); color: var(--red); }
.stat-value { font-size: 26px; font-weight: 700; color: var(--text); letter-spacing: -0.03em; line-height: 1; }
.stat-label { font-size: 11.5px; font-weight: 500; color: var(--text3); text-transform: uppercase; letter-spacing: 0.06em; }
/* ── Buttons ───────────────────────────────────── */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
padding: 7px 14px;
border-radius: var(--radius-sm);
font-size: 13px;
font-weight: 500;
font-family: inherit;
cursor: pointer;
border: none;
transition: all var(--transition);
white-space: nowrap;
text-decoration: none;
}
.btn svg { width: 14px; height: 14px; flex-shrink: 0; }
.btn:disabled { opacity: 0.45; cursor: not-allowed; pointer-events: none; }
.btn-primary { background: var(--cyan); color: #09090b; }
.btn-primary:hover { background: #06b6d4; }
.btn-secondary {
background: var(--elevated);
color: var(--text2);
border: 1px solid var(--border);
}
.btn-secondary:hover { background: var(--border); color: var(--text); }
.btn-ghost { background: transparent; color: var(--text3); }
.btn-ghost:hover { background: var(--border); color: var(--text2); }
.btn-danger { background: var(--red-dim); color: var(--red); border: 1px solid var(--red-mid); }
.btn-danger:hover { background: var(--red-mid); }
.btn-icon {
padding: 6px;
border-radius: var(--radius-sm);
background: transparent;
color: var(--text3);
border: none;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
transition: all var(--transition);
}
.btn-icon:hover { background: var(--border); color: var(--text2); }
.btn-icon svg { width: 14px; height: 14px; }
.btn-sm { padding: 4px 10px; font-size: 12px; }
.btn-sm svg { width: 12px; height: 12px; }
.btn-xs { padding: 3px 8px; font-size: 11px; }
/* ── Badges / Tags ─────────────────────────────── */
.badge {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 8px;
border-radius: 99px;
font-size: 11.5px;
font-weight: 500;
}
.badge-cyan { background: var(--cyan-dim); color: var(--cyan); }
.badge-green { background: var(--green-dim); color: var(--green); }
.badge-amber { background: var(--amber-dim); color: var(--amber); }
.badge-red { background: var(--red-dim); color: var(--red); }
.badge-neutral { background: var(--elevated); color: var(--text3); }
/* ── Latency badges ─────────────────────────────── */
.latency-badge {
transition: color 0.4s ease, opacity 0.3s ease;
display: inline-block;
min-width: 32px;
text-align: right;
}
.latency-badge.pinging {
opacity: 0.45;
}
/* ── Overview list cards ────────────────────────── */
.ov-list-card {
display: flex;
flex-direction: column;
min-height: 0;
/* Cards fill the grid cell height set by the flex grid rows */
height: 100%;
}
/* The scroll area grows to fill whatever height the card has after the
header and search input. No max-height — the grid rows control height. */
.ov-scroll-area {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
min-height: 0;
}
/* When the list is empty, disable scrolling and center the message */
.ov-scroll-area.ov-empty {
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.ov-scroll-area.ov-empty table {
width: 100%;
height: 100%;
}
.ov-scroll-area.ov-empty .table .empty {
padding: 0;
}
.ov-table thead th {
position: sticky;
top: 0;
background: var(--card);
z-index: 1;
}
.ov-sentinel { height: 1px; }
/* ── Tables ────────────────────────────────────── */
.table { width: 100%; border-collapse: collapse; }
.table th {
padding: 10px 16px;
text-align: left;
font-size: 11px;
font-weight: 600;
color: var(--text4);
text-transform: uppercase;
letter-spacing: 0.07em;
background: var(--elevated);
border-bottom: 1px solid var(--border);
}
.table td {
padding: 11px 16px;
font-size: 13px;
color: var(--text2);
border-bottom: 1px solid var(--border);
vertical-align: middle;
}
.table tbody tr:last-child td { border-bottom: none; }
.table tbody tr:hover td { background: rgba(255,255,255,.025); }
.table .mono {
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
color: var(--cyan);
}
.table .empty {
text-align: center;
color: var(--text4);
padding: 36px 16px;
font-size: 13px;
}
/* ── Mono chip ─────────────────────────────────── */
.mono-chip {
display: inline-flex;
align-items: center;
gap: 6px;
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
color: var(--cyan);
background: var(--cyan-dim);
border: 1px solid rgba(34,211,238,.15);
padding: 3px 8px;
border-radius: var(--radius-sm);
}
/* ── Form inputs ───────────────────────────────── */
.input {
background: var(--elevated);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
color: var(--text);
font-family: inherit;
font-size: 13px;
padding: 8px 11px;
outline: none;
transition: border-color var(--transition);
width: 100%;
}
.input:focus { border-color: var(--cyan); }
.input::placeholder { color: var(--text4); }
.input.mono { font-family: 'JetBrains Mono', monospace; font-size: 12px; }
.form-group { display: flex; flex-direction: column; gap: 5px; }
.form-label { font-size: 12px; font-weight: 500; color: var(--text3); }
.form-error { font-size: 12px; color: var(--red); margin-top: 4px; display: none; }
/* ── Toggle ────────────────────────────────────── */
.toggle {
position: relative;
width: 40px;
height: 22px;
background: var(--border2);
border-radius: 99px;
cursor: pointer;
transition: background var(--transition);
flex-shrink: 0;
}
.toggle.active { background: var(--cyan); }
.toggle::after {
content: '';
position: absolute;
top: 3px;
left: 3px;
width: 16px;
height: 16px;
background: #fff;
border-radius: 50%;
transition: transform var(--transition);
box-shadow: 0 1px 3px rgba(0,0,0,.3);
}
.toggle.active::after { transform: translateX(18px); }
/* ── Settings rows ─────────────────────────────── */
.setting-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
padding: 13px 0;
border-bottom: 1px solid var(--border);
}
.setting-row:last-child { border-bottom: none; }
.setting-info { flex: 1; min-width: 0; }
.setting-label { font-size: 13.5px; color: var(--text); font-weight: 500; }
.setting-desc { font-size: 12px; color: var(--text3); margin-top: 2px; }
.setting-control { flex-shrink: 0; }
/* ── Section heading ───────────────────────────── */
.section-heading {
font-size: 11px;
font-weight: 600;
color: var(--text4);
text-transform: uppercase;
letter-spacing: 0.08em;
margin-bottom: 10px;
margin-top: 20px;
}
.section-heading:first-child { margin-top: 0; }
/* ── Logs ──────────────────────────────────────── */
.logs-toolbar {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 12px;
flex-wrap: wrap;
}
.logs-filter {
flex: 1;
min-width: 180px;
max-width: 280px;
}
.logs-container {
background: #0a0a0c;
border: 1px solid var(--border);
border-radius: var(--radius);
height: calc(100vh - 220px);
overflow-y: auto;
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
}
.log-entry {
display: flex;
gap: 12px;
padding: 5px 14px;
border-bottom: 1px solid rgba(255,255,255,.03);
}
.log-entry:hover { background: rgba(255,255,255,.025); }
.log-time { color: var(--text4); flex-shrink: 0; font-size: 11px; padding-top: 1px; }
.log-msg { color: var(--text2); word-break: break-all; line-height: 1.5; }
.log-msg.is-error { color: var(--red); }
.log-msg.is-warn { color: var(--amber); }
.log-msg.is-info { color: var(--cyan); }
/* ── Proxy/CA page ─────────────────────────────── */
.info-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.info-item {
background: var(--elevated);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 14px 16px;
}
.info-item-label { font-size: 11px; font-weight: 600; color: var(--text4); text-transform: uppercase; letter-spacing: 0.07em; margin-bottom: 6px; }
.info-item-value { font-size: 20px; font-weight: 700; color: var(--text); font-family: 'JetBrains Mono', monospace; }
/* ── Empty state ───────────────────────────────── */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 10px;
padding: 48px 24px;
color: var(--text4);
text-align: center;
}
.empty-state svg { width: 36px; height: 36px; opacity: 0.4; }
.empty-state-title { font-size: 14px; font-weight: 600; color: var(--text3); }
.empty-state-desc { font-size: 13px; }
/* ── Modals ────────────────────────────────────── */
.modal-backdrop {
position: fixed;
inset: 0;
background: rgba(0,0,0,.7);
backdrop-filter: blur(4px);
z-index: 100;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: opacity 0.2s ease;
}
.modal-backdrop.open {
opacity: 1;
pointer-events: all;
}
.modal {
background: var(--card);
border: 1px solid var(--border2);
border-radius: var(--radius-lg);
width: 100%;
max-width: 440px;
margin: 16px;
box-shadow: 0 24px 64px rgba(0,0,0,.6);
transform: translateY(12px) scale(0.98);
transition: transform 0.2s ease;
}
.modal-backdrop.open .modal { transform: translateY(0) scale(1); }
.modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px;
border-bottom: 1px solid var(--border);
}
.modal-title { font-size: 15px; font-weight: 600; color: var(--text); }
.modal-body { padding: 20px; display: flex; flex-direction: column; gap: 14px; }
.modal-desc { font-size: 13px; color: var(--text2); line-height: 1.6; }
.modal-footer {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 8px;
padding: 14px 20px;
border-top: 1px solid var(--border);
}
.modal-error { font-size: 12px; color: var(--red); display: none; }
/* ── Confirm inline ────────────────────────────── */
.confirm-inline {
display: none;
align-items: center;
gap: 6px;
font-size: 12px;
color: var(--text2);
}
.confirm-inline.show { display: inline-flex; }
/* ── Toast ─────────────────────────────────────── */
.toast {
position: fixed;
bottom: 24px;
right: 24px;
background: var(--elevated);
border: 1px solid var(--border2);
border-radius: var(--radius);
padding: 10px 16px;
font-size: 13px;
color: var(--text);
box-shadow: 0 8px 24px rgba(0,0,0,.4);
z-index: 200;
transform: translateY(8px);
opacity: 0;
pointer-events: none;
transition: all 0.2s ease;
max-width: 320px;
}
.toast.show { opacity: 1; transform: translateY(0); }
.toast.success { border-color: rgba(74,222,128,.3); color: var(--green); }
.toast.error { border-color: var(--red-mid); color: var(--red); }
/* ── Divider ───────────────────────────────────── */
.divider { height: 1px; background: var(--border); margin: 16px 0; }
/* ── Copy feedback ─────────────────────────────── */
.copy-btn { position: relative; }
.copy-tooltip {
position: absolute;
bottom: calc(100% + 6px);
left: 50%;
transform: translateX(-50%);
background: var(--elevated);
border: 1px solid var(--border2);
border-radius: 4px;
padding: 3px 8px;
font-size: 11px;
color: var(--green);
white-space: nowrap;
pointer-events: none;
opacity: 0;
transition: opacity 0.15s;
}
.copy-btn.copied .copy-tooltip { opacity: 1; }
/* ── Page headers ──────────────────────────────── */
/* ── Inline row layout ─────────────────────────── */
.row { display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap; }
.row .form-group { flex: 1; min-width: 120px; }
/* ── Checkbox ──────────────────────────────────── */
.checkbox-row {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
user-select: none;
}
.checkbox-row input[type="checkbox"] {
width: 15px;
height: 15px;
accent-color: var(--cyan);
cursor: pointer;
}
.checkbox-row label { font-size: 13px; color: var(--text2); cursor: pointer; }
/* ── Radio ──────────────────────────────────────── */
.radio-row {
display: flex;
align-items: center;
gap: 6px;
cursor: pointer;
user-select: none;
padding: 6px 12px;
border: 1px solid var(--border);
border-radius: 6px;
font-size: 13px;
color: var(--text2);
transition: border-color 0.15s, background 0.15s;
}
.radio-row:has(input:checked) {
border-color: var(--cyan);
background: color-mix(in srgb, var(--cyan) 10%, transparent);
color: var(--cyan);
}
.radio-row input[type="radio"] {
accent-color: var(--cyan);
cursor: pointer;
}
/* ── Remote Desktop page ────────────────────────── */
.rdp-conn-card {
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 14px 16px;
display: flex;
flex-direction: column;
gap: 10px;
transition: border-color var(--transition), background var(--transition);
cursor: default;
}
.rdp-conn-card:hover { border-color: var(--border2); background: var(--elevated); }
.rdp-conn-card-top {
display: flex;
align-items: center;
gap: 12px;
min-width: 0;
}
.rdp-conn-icon {
width: 38px;
height: 38px;
border-radius: var(--radius-sm);
background: var(--cyan-dim);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--cyan);
}
.rdp-conn-icon svg { width: 18px; height: 18px; }
.rdp-conn-info { flex: 1; min-width: 0; }
.rdp-conn-label { font-size: 14px; font-weight: 600; color: var(--text); word-break: break-word; }
.rdp-conn-actions { display: flex; gap: 6px; flex-shrink: 0; margin-left: auto; }
.rdp-conn-meta {
font-size: 11px;
color: var(--text3);
font-family: 'JetBrains Mono', monospace;
word-break: break-all;
line-height: 1.5;
padding: 6px 8px;
background: var(--base);
border-radius: var(--radius-sm);
border: 1px solid var(--border);
}
.rdp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 12px; }
/* ── RDP Viewer modal ───────────────────────────── */
.modal-rdp-viewer {
max-width: 95vw;
width: 95vw;
height: 90vh;
padding: 0;
display: flex;
flex-direction: column;
overflow: hidden;
}
.rdp-viewer-toolbar {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 14px;
background: var(--elevated);
border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
.rdp-viewer-statusbar {
display: flex;
align-items: center;
gap: 12px;
padding: 6px 14px;
background: var(--elevated);
border-top: 1px solid var(--border);
flex-shrink: 0;
font-size: 11px;
color: var(--text4);
}
.rdp-viewer-statusbar span { color: var(--text3); }
#rdpViewerContainer {
flex: 1;
background: #000;
overflow: hidden;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
#rdpViewerContainer canvas { max-width: 100%; max-height: 100%; display: block; }
/* noVNC injects its own canvas — make it fill the container */
#rdpViewerContainer > :first-child { width: 100% !important; height: 100% !important; }
/* ── SSH page ───────────────────────────────────── */
.ssh-conn-card {
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 16px 18px;
display: flex;
flex-direction: column;
gap: 10px;
transition: border-color var(--transition), background var(--transition);
cursor: default;
}
.ssh-conn-card:hover { border-color: var(--border2); background: var(--elevated); }
.ssh-conn-card-top {
display: flex;
align-items: center;
gap: 14px;
min-width: 0;
}
.ssh-conn-icon {
width: 38px;
height: 38px;
border-radius: var(--radius-sm);
background: var(--cyan-dim);
border: 1px solid var(--cyan-mid);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--cyan);
}
.ssh-conn-icon svg { width: 18px; height: 18px; }
.ssh-conn-info { flex: 1; min-width: 0; }
.ssh-conn-label { font-size: 14px; font-weight: 600; color: var(--text); word-break: break-word; }
.ssh-conn-actions { display: flex; gap: 6px; flex-shrink: 0; margin-left: auto; }
.ssh-conn-meta {
font-size: 11px;
color: var(--text3);
font-family: 'JetBrains Mono', monospace;
word-break: break-all;
line-height: 1.5;
padding: 6px 8px;
background: var(--base);
border-radius: var(--radius-sm);
border: 1px solid var(--border);
}
.ssh-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 12px; }
/* ── SSH Terminal modal ──────────────────────────── */
.modal-terminal {
max-width: 95vw;
width: 95vw;
height: 90vh;
margin: 0;
display: flex;
flex-direction: column;
}
.terminal-toolbar {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 16px;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
background: var(--surface);
border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.terminal-conn-label {
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
color: var(--cyan);
background: var(--cyan-dim);
border: 1px solid var(--cyan-mid);
border-radius: var(--radius-sm);
padding: 3px 10px;
flex-shrink: 0;
max-width: 220px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.terminal-status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--green);
box-shadow: 0 0 6px var(--green);
flex-shrink: 0;
animation: pulse 2.5s infinite;
}
.terminal-status-dot.disconnected { background: var(--red); box-shadow: 0 0 6px var(--red); animation: none; }
.terminal-spacer { flex: 1; }
.terminal-statusbar {
display: flex;
align-items: center;
gap: 12px;
padding: 6px 16px;
border-top: 1px solid var(--border);
background: var(--surface);
border-radius: 0 0 var(--radius-lg) var(--radius-lg);
flex-shrink: 0;
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
color: var(--text4);
}
.terminal-statusbar span { color: var(--text3); }
#terminalContainer {
flex: 1;
background: #0d0d0f;
overflow: hidden;
padding: 8px;
}
/* Override xterm defaults to match our palette */
#terminalContainer .xterm { height: 100%; }
#terminalContainer .xterm-viewport { background: transparent !important; }
#terminalContainer .xterm-screen { background: transparent !important; }