Redesign The Hub web UI: softer dark theme, sidebar nav, status widgets

Apply the approved "The Hub" redesign to the web admin while keeping every
existing mechanic intact (polling, service-detail modals, Matrix and system
password management, NWC wallet manager, update/rebuild/backup/security/
reboot flows, feature manager, onboarding, role handling).

Layout (templates/index.html):
- Old header bar + IP bar replaced by a sidebar + topbar app shell.
  Sidebar carries the brand (The Hub / Sovran_SystemsOS version), category
  navigation with live counts, the System actions (Update System, Tech
  Support, Manual Backup, Security, node-only Upgrade), Feature Manager /
  Preferences, and the role badge.
- Topbar carries the page title, a service search box, the LAN | WAN
  network chip (external IP always visible, one line), Reboot and Sign Out.
- New widgets row: Systems Operational summary (opens the new Systems
  Operational modal) and Bitcoin Core sync progress with block/ETA.
- New Systems Operational modal: service counts, router port-forwarding
  steps (80/443 to this machine's LAN IP), the live domain diagnostics
  checklist, and which services use those ports.

New static/js/dashboard.js (namespaced IIFE, no new globals) renders the
nav, search filtering, widgets, and the Systems Operational modal; it is
driven by the existing /api/services payloads via a
window.dashboardServicesUpdated() hook called from buildTiles/updateTiles.

Visual design (static/css/*):
- New token set (softer dark surfaces, lifted contrast, Sovran green
  reserved for status and actions) with legacy variable names aliased so
  every secondary sheet re-skins automatically.
- Tiles, dialogs, buttons, inputs, toggles, tables, forms, overlays and
  the login page restyled to the GNOME/libadwaita-flavored surfaces:
  20px cards, 26px dialogs, pill buttons, libadwaita switches, mono value
  pills with Copy buttons, consistent modal anatomy.
- Inline SVG symbol set for chrome/nav icons (monochrome, currentColor);
  service icons still load from /static/icons/*.svg as before.
- Sidebar system buttons now use vector glyphs instead of emoji.

Behavioral details:
- Service detail modal header gains a status pill next to the version
  chip; credentials render with pre-wrap for multiline values.
- First-login security banner now renders as a card inside the content
  area instead of a full-width strip above the app.
- Search + category filtering hide/show sections and tiles without
  touching the polling or update logic.

Onboarding and login pages rebranded to "The Hub" with aligned palette.
This commit is contained in:
2026-09-08 15:52:49 -05:00
parent 1d46d036c0
commit 2013df55bd
18 changed files with 2784 additions and 1735 deletions
+129 -61
View File
@@ -1,6 +1,11 @@
/* Sovran_SystemsOS Hub — Web UI Stylesheet
Dark theme — near-black with green accents matching the Sovran Hub icon
v8 — Black-forward, green used for accents/borders/highlights only */
The Hub redesign — softer dark theme, GNOME 50 / libadwaita surfaces,
Sovran green reserved for status and actions.
Design tokens are defined once here. Legacy variable names from the
previous theme are aliased to the new values so every stylesheet
(support, security, domain-setup, onboarding, …) re-skins without
needing per-rule edits. */
*, *::before, *::after {
box-sizing: border-box;
@@ -9,22 +14,48 @@
}
:root {
--bg-color: #080a09;
--surface-color: rgba(14, 16, 15, 0.7);
--card-color: rgba(20, 22, 21, 0.6);
--border-color: rgba(255, 255, 255, 0.06);
--text-primary: #ecf3ef;
--text-secondary: #8aaa9a;
--text-dim: #4a6658;
--accent-color: #5EAD8A;
--green: #6DBF8B;
--yellow: #e5a50a;
--red: #e01b24;
--grey: #5E7A6A;
--radius-card: 18px;
--radius-btn: 8px;
--shadow-card: 0 4px 16px rgba(0, 0, 0, 0.4);
--shadow-hover: 0 8px 32px rgba(0, 0, 0, 0.5);
color-scheme: dark;
/* ── The Hub palette ─────────────────────────────────────────── */
--bg: #141a16;
--surface: #181f1b;
--card: #1e2621;
--card-hover: #232d27;
--elevated: #212925;
--inset: #121814;
--border: rgba(255, 255, 255, 0.07);
--border-strong: rgba(255, 255, 255, 0.14);
--text: #e3ede7;
--text-2: #a8bcb0;
--text-3: #6e8578;
--accent: #3ecf8e;
--accent-strong: #42f39a;
--accent-deep: #1aa45d;
--accent-dim: rgba(66, 243, 154, 0.12);
--amber: #e9b64a;
--red: #f66151;
--blue: #78aeed;
--mono: 'JetBrains Mono', 'Fira Code', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
--radius-card: 20px;
--radius-dialog: 26px;
--shadow-card: 0 10px 30px rgba(0, 0, 0, 0.25);
--shadow-hover: 0 16px 36px rgba(0, 0, 0, 0.38);
--shadow-pop: 0 30px 80px rgba(0, 0, 0, 0.5);
/* ── Legacy aliases (previous theme) — keep every old sheet working */
--bg-color: var(--bg);
--surface-color: var(--surface);
--card-color: var(--card);
--border-color: var(--border);
--text-primary: var(--text);
--text-secondary: var(--text-2);
--text-dim: var(--text-3);
--accent-color: var(--accent);
--green: var(--accent);
--yellow: var(--amber);
--red: var(--red);
--grey: var(--text-3);
--radius-btn: 12px;
}
html, body {
@@ -32,19 +63,39 @@ html, body {
}
body {
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background:
radial-gradient(ellipse at top, rgba(94, 173, 138, 0.04) 0%, transparent 50%),
var(--bg-color);
color: var(--text-primary);
font-family: Inter, Cantarell, 'Segoe UI', system-ui, -apple-system, 'Helvetica Neue', Arial, sans-serif;
background: var(--bg);
color: var(--text);
font-size: 15px;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
min-height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* ── Login page ──────────────────────────────────────────────────── */
/* Soft brand wash so the canvas never reads flat-black */
body::before {
content: "";
position: fixed;
inset: 0;
background:
radial-gradient(1100px 520px at 16% -12%, rgba(66, 243, 154, 0.04), transparent 60%),
radial-gradient(900px 600px at 110% 110%, rgba(26, 169, 110, 0.05), transparent 55%);
pointer-events: none;
z-index: 0;
}
button { font-family: inherit; }
::selection { background: rgba(66, 243, 154, 0.25); }
/* ── Scrollbars ─────────────────────────────────────────────────── */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.10); border-radius: 99px; border: 2px solid transparent; background-clip: padding-box; }
::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.18); background-clip: padding-box; }
::-webkit-scrollbar-track { background: transparent; }
/* ── Login page ─────────────────────────────────────────────────── */
.login-wrapper {
display: flex;
@@ -52,86 +103,103 @@ body {
justify-content: center;
min-height: 100vh;
padding: 24px;
position: relative;
z-index: 1;
}
.login-card {
background-color: rgba(14, 16, 15, 0.75);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 20px;
padding: 48px 40px;
width: 100%;
max-width: 400px;
box-shadow: 0 8px 32px rgba(0,0,0,0.5);
max-width: 402px;
text-align: center;
background: var(--elevated);
border: 1px solid var(--border-strong);
border-radius: 28px;
padding: 46px 42px 38px;
box-shadow: var(--shadow-pop);
}
.login-header {
text-align: center;
margin-bottom: 32px;
margin-bottom: 26px;
}
.login-logo {
height: 64px;
margin-bottom: 16px;
width: 78px;
height: 78px;
margin-bottom: 18px;
filter: drop-shadow(0 8px 24px rgba(28, 196, 120, 0.3));
}
.login-title {
font-size: 1.25rem;
font-weight: 700;
color: var(--text-primary);
font-size: 1.3rem;
font-weight: 800;
letter-spacing: -0.01em;
color: var(--text);
}
.login-title em { font-style: normal; color: var(--accent); }
.login-sub {
color: var(--text-2);
font-size: 0.85rem;
margin: 7px 0 0;
}
.login-form {
display: flex;
flex-direction: column;
gap: 16px;
gap: 14px;
}
.form-group label {
display: block;
font-size: 0.82rem;
font-weight: 600;
color: var(--text-secondary);
font-size: 0.8rem;
font-weight: 650;
color: var(--text-2);
margin-bottom: 6px;
text-align: left;
}
.form-group input {
width: 100%;
padding: 10px 14px;
border: 1px solid var(--border-color);
border-radius: var(--radius-btn);
background-color: var(--card-color);
color: var(--text-primary);
padding: 11px 16px;
border: 1px solid var(--border-strong);
border-radius: 14px;
background: var(--inset);
color: var(--text);
font: inherit;
font-size: 0.92rem;
outline: 0;
transition: border-color 0.15s, box-shadow 0.15s;
}
.form-group input:focus {
outline: none;
border-color: var(--accent-color);
border-color: rgba(66, 243, 154, 0.55);
box-shadow: 0 0 0 3px rgba(66, 243, 154, 0.13);
}
.btn-login {
width: 100%;
padding: 12px;
border-radius: var(--radius-btn);
background-color: var(--accent-color);
color: #0A1A10;
font-size: 0.95rem;
border-radius: 99px;
background: linear-gradient(180deg, #3fd68e, #1ea263);
color: #04220f;
font-size: 0.92rem;
font-weight: 700;
margin-top: 8px;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28), 0 6px 18px rgba(35, 199, 124, 0.22);
}
.btn-login:hover {
opacity: 0.88;
.btn-login:hover:not(:disabled) {
filter: brightness(1.08);
}
.login-error {
background-color: rgba(224, 27, 36, 0.12);
border: 1px solid var(--red);
color: #f87171;
background: rgba(246, 97, 81, 0.10);
border: 1px solid rgba(246, 97, 81, 0.35);
color: #f8a39b;
padding: 10px 14px;
border-radius: 8px;
border-radius: 12px;
font-size: 0.85rem;
display: none;
}
+123 -24
View File
@@ -5,34 +5,133 @@ button {
cursor: pointer;
border: none;
outline: none;
transition: opacity 0.15s, box-shadow 0.15s, background-color 0.15s;
transition: background 0.16s, border-color 0.16s, color 0.16s, transform 0.16s, filter 0.16s, opacity 0.15s;
}
button:disabled {
opacity: 0.45;
opacity: 0.55;
cursor: default;
pointer-events: none;
}
.btn {
padding: 7px 16px;
border-radius: var(--radius-btn);
font-size: 0.88rem;
font-weight: 600;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
border-radius: 99px;
padding: 8px 18px;
font-size: 0.84rem;
font-weight: 700;
letter-spacing: 0.01em;
cursor: pointer;
border: 1px solid transparent;
white-space: nowrap;
}
.btn svg { width: 15px; height: 15px; }
.btn:active { transform: scale(0.97); }
.btn-primary {
background-color: var(--accent-color);
color: #0A1A10;
background: linear-gradient(180deg, #3fd68e, #1ea263);
color: #04220f;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28), 0 6px 18px rgba(35, 199, 124, 0.22);
}
.btn-primary:hover:not(:disabled) {
opacity: 0.88;
filter: brightness(1.08);
transform: translateY(-1px);
}
/* Update System button: uses accent green by default */
.btn-primary:active:not(:disabled) { transform: scale(0.97); }
/* Ghost — the default secondary action (legacy: btn-close-modal / btn-save) */
.btn-ghost,
.btn-close-modal,
.btn-save {
background: transparent;
border-color: var(--border-strong);
color: var(--text-2);
}
.btn-ghost:hover:not(:disabled),
.btn-close-modal:hover:not(:disabled),
.btn-save:hover:not(:disabled) {
color: var(--text);
border-color: rgba(255, 255, 255, 0.26);
background: rgba(255, 255, 255, 0.04);
}
/* Amber — destructive-ish confirmations (restart, reboot, retry) */
.btn-amber,
.btn-reboot,
.btn-restart-amber,
.btn-warning {
background: rgba(233, 182, 74, 0.10);
border-color: rgba(233, 182, 74, 0.32);
color: #f2c45e;
}
.btn-amber:hover:not(:disabled),
.btn-reboot:hover:not(:disabled),
.btn-restart-amber:hover:not(:disabled),
.btn-warning:hover:not(:disabled) {
background: rgba(233, 182, 74, 0.18);
border-color: rgba(233, 182, 74, 0.5);
}
.btn-danger {
background: rgba(246, 97, 81, 0.10);
border-color: rgba(246, 97, 81, 0.35);
color: #f8a39b;
}
.btn-danger:hover:not(:disabled) {
background: rgba(246, 97, 81, 0.18);
border-color: rgba(246, 97, 81, 0.5);
}
.btn-sm { padding: 6px 14px; font-size: 0.77rem; }
/* ── Header / topbar buttons ────────────────────────────────────── */
.btn-header-reboot {
background: rgba(233, 182, 74, 0.10);
border: 1px solid rgba(233, 182, 74, 0.32);
color: #f2c45e;
font-size: 0.77rem;
font-weight: 700;
padding: 6px 14px;
border-radius: 99px;
}
.btn-header-reboot:hover:not(:disabled) {
background: rgba(233, 182, 74, 0.18);
border-color: rgba(233, 182, 74, 0.5);
}
.btn-logout {
background: transparent;
border: 1px solid var(--border-strong);
color: var(--text-2);
font-size: 0.77rem;
font-weight: 700;
padding: 6px 14px;
border-radius: 99px;
}
.btn-logout:hover {
color: var(--text);
border-color: rgba(255, 255, 255, 0.26);
background: rgba(255, 255, 255, 0.04);
}
/* ── Update System button (sidebar) ─────────────────────────────── */
.btn-update {
background-color: #4A9474;
color: #E0F2EA;
background: transparent;
border: 1px solid var(--border-strong);
color: var(--text-2);
position: relative;
display: flex;
align-items: center;
@@ -40,24 +139,22 @@ button:disabled {
}
.btn-update:hover:not(:disabled) {
opacity: 0.88;
color: var(--text);
border-color: rgba(255, 255, 255, 0.26);
background: rgba(255, 255, 255, 0.04);
}
/* Update System button: brighter green when updates are available */
.btn-update.has-updates {
background-color: #5EAD8A;
color: #0A1A10;
}
.btn-update.has-updates:hover:not(:disabled) {
background-color: #78C8A2;
background: rgba(66, 243, 154, 0.12);
border-color: rgba(66, 243, 154, 0.4);
color: var(--accent);
}
.update-badge {
display: none;
width: 10px;
height: 10px;
background-color: var(--yellow);
background-color: var(--amber);
border-radius: 50%;
animation: pulse-badge 1.4s ease-in-out infinite;
}
@@ -71,9 +168,11 @@ button:disabled {
50% { opacity: 0.5; transform: scale(1.35); }
}
/* ── Icon buttons ───────────────────────────────────────────────── */
.btn-icon {
background: none;
color: var(--text-secondary);
color: var(--text-2);
padding: 6px;
border-radius: 50%;
font-size: 1.1rem;
@@ -81,6 +180,6 @@ button:disabled {
}
.btn-icon:hover:not(:disabled) {
background-color: var(--border-color);
color: var(--text-primary);
background-color: rgba(255, 255, 255, 0.06);
color: var(--text);
}
@@ -18,7 +18,7 @@ domain-field-label {
domain-field-input {
width: 100%;
background-color: #0c0f0e;
background-color: var(--inset);
color: var(--text-primary);
border: 1px solid var(--border-color);
border-radius: 8px;
@@ -75,7 +75,7 @@ domain-field-actions {
.domain-field-input {
width: 100%;
background-color: #0c0f0e;
background-color: var(--inset);
color: var(--text-primary);
border: 1px solid var(--border-color);
border-radius: 8px;
@@ -198,21 +198,21 @@ domain-field-actions {
}
.port-proto-badge--tcp {
color: #6dbf8b;
background: rgba(109, 191, 139, 0.12);
border: 1px solid rgba(109, 191, 139, 0.4);
color: var(--accent);
background: rgba(66, 243, 154, 0.12);
border: 1px solid rgba(66, 243, 154, 0.4);
}
.port-proto-badge--udp {
color: #6aa9e0;
color: var(--blue);
background: rgba(106, 169, 224, 0.12);
border: 1px solid rgba(106, 169, 224, 0.4);
}
.port-proto-badge--both {
color: #e5a50a;
background: rgba(229, 165, 10, 0.12);
border: 1px solid rgba(229, 165, 10, 0.45);
color: var(--amber);
background: rgba(233, 182, 74, 0.12);
border: 1px solid rgba(233, 182, 74, 0.45);
}
.port-proto-note {
@@ -230,7 +230,7 @@ domain-field-actions {
margin-bottom: 14px;
padding: 10px 14px;
background: rgba(255, 180, 0, 0.10);
border: 1px solid var(--warning-color, #f59e0b);
border: 1px solid var(--warning-color, var(--amber));
border-radius: 8px;
font-size: 0.88rem;
line-height: 1.6;
+142 -89
View File
@@ -1,143 +1,196 @@
/* ── Feature Manager styles ──────────────────────────────────────── */
/* ── Sidebar: Feature Manager + Preferences ─────────────────────── */
.feature-manager-section {
margin-bottom: 32px;
.category-section.autolaunch-section,
.category-section.feature-manager-section {
margin-bottom: 0;
}
.feature-subcategory {
margin-bottom: 16px;
/* The old "Preferences" header + hr becomes a small sidebar label.
features.js renders: .section-header + hr.section-divider + cards */
.autolaunch-section .section-header,
.feature-manager-section .section-header {
font-size: 0.66rem;
font-weight: 750;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--text-3);
margin: 0;
padding: 14px 10px 7px;
display: block;
}
.autolaunch-section .section-divider,
.feature-manager-section .section-divider {
background: none;
height: 0;
margin: 0;
}
.feature-cards-wrap { display: flex; flex-direction: column; }
.feature-subcategory { display: flex; flex-direction: column; }
.feature-subcategory-header {
font-size: 0.78rem;
font-weight: 700;
font-size: 0.66rem;
font-weight: 750;
letter-spacing: 0.14em;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-dim);
margin-bottom: 8px;
padding-left: 4px;
}
.feature-cards-wrap {
display: flex;
flex-direction: column;
gap: 10px;
color: var(--text-3);
padding: 12px 10px 6px;
}
/* Feature card — sidebar preference row with a switch */
.feature-card {
background-color: var(--card-color);
border: 1px solid var(--border-color);
border-radius: 12px;
padding: 14px 16px;
display: flex;
gap: 10px;
align-items: flex-start;
padding: 9px 10px;
border-radius: 10px;
transition: background 0.15s;
}
.feature-card:hover { background: rgba(255, 255, 255, 0.05); }
.feature-card-top {
display: flex;
align-items: flex-start;
gap: 12px;
margin-bottom: 8px;
gap: 10px;
width: 100%;
}
.feature-card-info {
flex: 1;
min-width: 0;
}
.feature-card-info { min-width: 0; flex: 1; }
.feature-card-name {
font-size: 0.9rem;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 4px;
font-size: 0.84rem;
font-weight: 600;
color: var(--text);
line-height: 1.3;
}
.feature-card-desc {
font-size: 0.78rem;
color: var(--text-secondary);
line-height: 1.5;
margin-top: 2px;
font-size: 0.68rem;
color: var(--text-3);
line-height: 1.45;
}
.feature-card-status {
font-size: 0.72rem;
color: var(--text-dim);
font-size: 0.66rem;
font-weight: 700;
padding: 2px 8px;
border-radius: 99px;
flex-shrink: 0;
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--border);
color: var(--text-2);
}
.feature-card-status.status-on {
color: var(--accent);
background: var(--accent-dim);
border-color: rgba(66, 243, 154, 0.3);
}
.feature-conflict-warning {
margin-top: 8px;
font-size: 0.68rem;
color: var(--amber);
line-height: 1.5;
}
/* Domain badges inside feature cards */
.feature-domain-badge {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 0.64rem;
font-weight: 700;
padding: 2px 8px;
border-radius: 99px;
margin-top: 6px;
}
.feature-domain-badge.configured {
color: var(--accent);
background: var(--accent-dim);
}
.feature-domain-badge.not-configured {
color: var(--amber);
background: rgba(233, 182, 74, 0.10);
}
.feature-domain-icon { font-size: 0.8rem; }
.feature-domain-label {
display: inline-flex;
align-items: center;
gap: 5px;
font-size: 0.66rem;
font-weight: 650;
margin-top: 5px;
color: var(--text-3);
}
.feature-domain-label--ok { color: var(--accent); }
.feature-domain-label--warn { color: var(--amber); }
.feature-domain-label--error { color: var(--red); }
.feature-domain-label--checking { color: var(--blue); }
/* ── Toggle switch (libadwaita style) ───────────────────────────── */
.feature-toggle {
position: relative;
display: inline-block;
width: 44px;
height: 24px;
width: 46px;
height: 26px;
flex-shrink: 0;
margin-left: auto;
margin-top: 2px;
cursor: pointer;
}
.feature-toggle-input {
opacity: 0;
width: 0;
height: 0;
position: absolute;
inset: 0;
opacity: 0;
margin: 0;
cursor: pointer;
}
.feature-toggle-slider {
position: absolute;
inset: 0;
background-color: var(--border-color);
border-radius: 24px;
transition: background-color 0.2s;
border-radius: 99px;
background: rgba(255, 255, 255, 0.12);
border: 1px solid var(--border-strong);
transition: 0.2s;
pointer-events: none;
}
.feature-toggle-slider::before {
.feature-toggle-slider::after {
content: "";
position: absolute;
width: 18px;
height: 18px;
left: 3px;
top: 3px;
background-color: #fff;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
border-radius: 50%;
transition: transform 0.2s;
background: #cfd8d2;
transition: 0.2s cubic-bezier(0.3, 0.8, 0.4, 1.2);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
}
.feature-toggle.active .feature-toggle-slider {
background-color: var(--green);
.feature-toggle-input:checked + .feature-toggle-slider {
background: var(--accent);
border-color: transparent;
}
.feature-toggle.active .feature-toggle-slider::before {
transform: translateX(20px);
.feature-toggle-input:checked + .feature-toggle-slider::after {
left: 23px;
background: #fff;
}
.feature-domain-badge {
display: flex;
align-items: center;
gap: 6px;
margin-top: 6px;
font-size: 0.78rem;
}
.feature-domain-icon {
flex-shrink: 0;
}
.feature-domain-label {
color: var(--text-secondary);
}
.feature-domain-label--checking {
color: var(--text-dim);
font-style: italic;
}
.feature-domain-label--ok {
color: var(--green);
font-weight: 600;
}
.feature-domain-label--warn {
color: var(--yellow);
font-weight: 600;
}
.feature-domain-label--error {
color: var(--red);
font-weight: 600;
.feature-toggle-input:focus-visible + .feature-toggle-slider {
box-shadow: 0 0 0 3px rgba(66, 243, 154, 0.3);
}
+122 -111
View File
@@ -1,69 +1,147 @@
/* ── Header bar ─────────────────────────────────────────────────── */
/* ── Topbar (replaces the old header-bar + ip-bar) ──────────────── */
.header-bar {
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
background-color: rgba(10, 12, 11, 0.82);
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
padding: 8px 24px;
.topbar {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: 16px;
position: sticky;
top: 0;
z-index: 100;
}
.header-logo {
height: 80px;
width: auto;
display: block;
gap: 14px;
padding: 13px 26px;
background: var(--surface);
border-bottom: 1px solid var(--border);
flex-shrink: 0;
position: relative;
z-index: 5;
}
.header-bar .title {
font-size: 1.15rem;
font-weight: 700;
color: var(--text-primary);
.page-title {
font-size: 1.02rem;
font-weight: 800;
letter-spacing: -0.01em;
white-space: nowrap;
}
.title-group {
/* ── Search ─────────────────────────────────────────────────────── */
.search-box {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 6px 10px;
gap: 9px;
background: var(--card);
border: 1px solid var(--border);
border-radius: 99px;
padding: 8px 16px;
flex: 1;
max-width: 400px;
min-width: 140px;
margin-left: 18px;
color: var(--text-3);
transition: border-color 0.15s, box-shadow 0.15s;
}
.header-buttons {
.search-box:focus-within {
border-color: rgba(66, 243, 154, 0.35);
box-shadow: 0 0 0 3px rgba(66, 243, 154, 0.09);
}
.search-box svg { width: 15px; height: 15px; flex-shrink: 0; }
.search-box input {
background: none;
border: 0;
outline: 0;
color: var(--text);
width: 100%;
font: inherit;
font-size: 0.87rem;
}
.search-box input::placeholder { color: var(--text-3); }
/* ── Network chip — LAN + WAN always on one line ────────────────── */
.net-chip {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 17px;
border-radius: 99px;
background: var(--card);
border: 1px solid var(--border);
font-family: var(--mono);
font-size: 0.73rem;
color: var(--text-3);
white-space: nowrap;
order: 4;
}
.net-chip svg { width: 15px; height: 15px; color: var(--text-3); flex-shrink: 0; }
.net-chip .int-wrap, .net-chip .ext-wrap { display: inline-flex; align-items: center; gap: 7px; }
.net-chip .ip-label {
font-size: 0.6rem;
font-weight: 800;
letter-spacing: 0.08em;
color: var(--text-3);
margin-right: 7px;
}
.net-chip .ip-value {
color: var(--text);
font-weight: 600;
font-family: var(--mono);
}
.net-separator {
width: 1px;
height: 15px;
background: var(--border-strong);
margin: 0 3px;
flex-shrink: 0;
color: transparent;
}
.top-actions {
display: flex;
gap: 9px;
margin-left: auto;
order: 5;
}
/* Below 1160px the chip wraps to its own full-width topbar row —
it never stacks LAN over WAN and never hides the external IP. */
@media (max-width: 1160px) {
.topbar { flex-wrap: wrap; row-gap: 10px; }
.net-chip {
order: 6;
flex-basis: 100%;
justify-content: center;
}
}
/* ── Legacy badges (still used inside dialogs) ──────────────────── */
.role-badge {
background-color: var(--accent-color);
color: #0A1A10;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 7px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--border-strong);
color: var(--text-2);
font-size: 0.72rem;
font-weight: 700;
padding: 3px 10px;
border-radius: 20px;
letter-spacing: 0.03em;
font-weight: 750;
padding: 6px 12px;
border-radius: 99px;
letter-spacing: 0.02em;
}
/* ── OS Version Badge — identical styling to the version badge ────
── shown next to titles in the service modal windows ──────────── */
.os-version-badge {
background-color: rgba(255, 255, 255, 0.06);
color: var(--text-secondary);
font-size: 0.72rem;
background: rgba(255, 255, 255, 0.05);
color: var(--text-2);
font-size: 0.66rem;
font-weight: 600;
padding: 2px 10px;
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.08);
padding: 2px 9px;
border-radius: 99px;
border: 1px solid var(--border);
letter-spacing: 0.02em;
display: inline-flex;
align-items: center;
@@ -71,76 +149,9 @@
flex-shrink: 0;
}
/* ── IP bar ─────────────────────────────────────────────────────── */
.ip-bar {
background-color: rgba(10, 12, 11, 0.7);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
padding: 8px 24px;
display: flex;
align-items: center;
justify-content: center;
gap: 32px;
font-size: 0.82rem;
color: var(--text-secondary);
}
.ip-bar .ip-label {
color: var(--text-dim);
margin-right: 6px;
}
.ip-bar .ip-value {
font-family: 'JetBrains Mono', 'Fira Code', 'Source Code Pro', monospace;
color: var(--accent-color);
font-weight: 600;
}
.ip-separator {
color: var(--border-color);
}
.btn-logout {
background: transparent;
border: 1px solid rgba(255, 255, 255, 0.18);
color: var(--text-secondary);
font-size: 0.78rem;
font-weight: 600;
padding: 4px 12px;
border-radius: var(--radius-btn);
cursor: pointer;
transition: border-color 0.15s, color 0.15s;
}
.btn-logout:hover {
border-color: var(--accent-color);
color: var(--accent-color);
}
/* ── Header reboot button ───────────────────────────────────────── */
.btn-header-reboot {
background: transparent;
border: 1px solid rgba(184, 125, 0, 0.35);
color: #c98d08;
font-size: 0.78rem;
font-weight: 600;
padding: 4px 12px;
border-radius: var(--radius-btn);
cursor: pointer;
transition: border-color 0.15s, color 0.15s, background-color 0.15s;
}
.btn-header-reboot:hover {
border-color: #b87d00;
color: #e0a010;
background-color: rgba(184, 125, 0, 0.1);
}
@media (max-width: 480px) {
.btn-header-reboot {
padding: 4px 8px;
padding: 5px 10px;
font-size: 0.72rem;
}
}
+368 -80
View File
@@ -1,138 +1,367 @@
/* ── Main content ───────────────────────────────────────────────── */
/* ── App shell: sidebar + main column ───────────────────────────── */
.main-content {
.app {
display: flex;
align-items: flex-start;
height: 100vh;
position: relative;
z-index: 1;
}
.main {
flex: 1;
overflow: hidden;
max-width: 1400px;
width: 100%;
margin-left: auto;
margin-right: auto;
display: flex;
flex-direction: column;
min-width: 0;
}
.content {
flex: 1;
overflow-y: auto;
padding: 26px 30px 70px;
min-width: 0;
}
/* ── Sidebar ────────────────────────────────────────────────────── */
.sidebar {
width: 270px;
width: 250px;
flex-shrink: 0;
height: 100%;
overflow-y: auto;
border-right: 1px solid rgba(255, 255, 255, 0.06);
background-color: rgba(12, 14, 13, 0.65);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
padding: 20px 14px;
background: var(--surface);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
gap: 0;
padding: 20px 14px 14px;
overflow-y: auto;
}
/* ── Sidebar: Tech Support button ───────────────────────────────── */
.brand {
display: flex;
align-items: center;
gap: 12px;
padding: 2px 8px 20px;
}
.brand-logo {
width: 42px;
height: 42px;
flex-shrink: 0;
filter: drop-shadow(0 4px 14px rgba(28, 196, 120, 0.25));
}
.brand-text { display: flex; flex-direction: column; min-width: 0; }
.brand-title {
font-size: 1.02rem;
font-weight: 800;
letter-spacing: -0.01em;
line-height: 1.2;
}
.brand-title em { font-style: normal; color: var(--accent); }
.brand-sub {
font-size: 0.7rem;
color: var(--text-3);
font-family: var(--mono);
margin-top: 3px;
}
.nav-label {
font-size: 0.66rem;
font-weight: 750;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--text-3);
padding: 14px 10px 7px;
}
/* Category nav (dashboard.js) */
.nav-item {
display: flex;
align-items: center;
gap: 11px;
width: 100%;
padding: 8px 10px;
border-radius: 10px;
border: 0;
background: none;
color: var(--text-2);
font-size: 0.87rem;
font-weight: 600;
cursor: pointer;
text-align: left;
transition: background 0.15s, color 0.15s;
}
.nav-item svg { width: 17px; height: 17px; flex-shrink: 0; }
.nav-item:hover {
background: rgba(255, 255, 255, 0.05);
color: var(--text);
}
.nav-item.active {
background: rgba(255, 255, 255, 0.06);
color: var(--text);
box-shadow: inset 2.5px 0 0 var(--accent);
}
.nav-text {
min-width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.nav-count {
margin-left: auto;
font-size: 0.67rem;
font-weight: 750;
flex-shrink: 0;
color: var(--text-3);
background: rgba(255, 255, 255, 0.05);
padding: 2px 8px;
border-radius: 99px;
}
.nav-item.active .nav-count {
background: rgba(255, 255, 255, 0.10);
color: var(--text-2);
}
/* System items (tiles.js renders these as .sidebar-support-btn) */
.sidebar-support-btn {
display: flex;
align-items: center;
gap: 10px;
gap: 11px;
width: 100%;
background-color: var(--card-color);
border: 1px solid var(--border-color);
border-radius: 12px;
padding: 12px 14px;
color: var(--text-primary);
padding: 8px 10px;
border-radius: 10px;
border: 0;
background: none;
color: var(--text-2);
font-size: 0.87rem;
font-weight: 600;
cursor: pointer;
transition: border-style 0.15s, border-color 0.15s, background-color 0.15s;
text-align: left;
transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.sidebar-support-btn:hover {
border-color: var(--accent-color);
border-style: solid;
background-color: #162320;
background: rgba(255, 255, 255, 0.05);
color: var(--text);
}
.sidebar-support-btn + .sidebar-support-btn {
margin-top: 8px;
margin-top: 2px;
}
.sidebar-support-icon {
font-size: 1.5rem;
font-size: 1rem;
width: 17px;
height: 17px;
display: grid;
place-items: center;
flex-shrink: 0;
}
.sidebar-support-icon svg { width: 17px; height: 17px; }
.sidebar-support-text {
display: flex;
flex-direction: column;
gap: 2px;
gap: 1px;
min-width: 0;
}
.sidebar-support-title {
font-size: 0.88rem;
font-weight: 700;
color: var(--text-primary);
font-size: 0.87rem;
font-weight: 600;
line-height: 1.3;
color: var(--text);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.sidebar-support-hint {
font-size: 0.72rem;
color: var(--accent-color);
font-weight: 600;
font-size: 0.68rem;
font-weight: 650;
color: var(--text-3);
display: flex;
align-items: center;
gap: 6px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.sidebar-divider {
border: none;
border-top: 1px solid var(--border-color);
margin: 16px 0;
border-top: 1px solid var(--border);
margin: 14px 0 0;
}
/* ── Upgrade modal ──────────────────────────────────────────────── */
.sidebar-spacer { flex: 1; min-height: 18px; }
.upgrade-dialog {
max-width: 480px;
.sidebar-footer {
border-top: 1px solid var(--border);
padding-top: 14px;
}
.upgrade-info-box {
background-color: var(--card-color);
border: 1px solid var(--border-color);
border-radius: 10px;
padding: 14px 18px;
margin-bottom: 14px;
.host-note {
text-align: center;
font-size: 0.66rem;
color: var(--text-3);
font-family: var(--mono);
margin-top: 9px;
}
.upgrade-info-title {
font-size: 0.88rem;
/* ── Widgets row (dashboard.js) ─────────────────────────────────── */
.widgets {
display: grid;
grid-template-columns: 1.1fr 1.45fr;
gap: 16px;
margin-bottom: 32px;
}
@media (max-width: 900px) {
.widgets { grid-template-columns: 1fr; }
}
.widget {
background: var(--card);
border: 1px solid var(--border);
border-radius: 20px;
padding: 17px 19px;
display: flex;
gap: 14px;
align-items: center;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03), var(--shadow-card);
transition: border-color 0.18s;
position: relative;
overflow: hidden;
min-width: 0;
}
.widget:hover { border-color: var(--border-strong); }
.widget.clickable { cursor: pointer; }
.widget.clickable:focus-visible {
outline: 2px solid rgba(66, 243, 154, 0.45);
outline-offset: 2px;
}
.widget-chip {
width: 46px;
height: 46px;
border-radius: 14px;
flex-shrink: 0;
display: grid;
place-items: center;
color: #fff;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 6px 16px rgba(0, 0, 0, 0.3);
}
.widget-chip svg { width: 22px; height: 22px; }
.widget-chip img { width: 46px; height: 46px; display: block; object-fit: contain; }
.widget-chip.chip-green {
background: linear-gradient(160deg, #2f9f6b, #17683f);
}
.widget-chip.chip-btc {
background: linear-gradient(160deg, #f7931a, #b96a0a);
}
.widget-chip.chip-sovran {
background: linear-gradient(160deg, #42f39a, #1aa45d);
}
.w-body { min-width: 0; }
.widget h3 {
font-size: 0.9rem;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 8px;
letter-spacing: -0.005em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.upgrade-info-list {
padding-left: 20px;
font-size: 0.85rem;
color: var(--text-secondary);
line-height: 1.7;
margin: 0;
.widget .sub {
margin-top: 4px;
font-size: 0.78rem;
color: var(--text-2);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.upgrade-info-list a {
color: var(--accent-color);
.widget .sub b { color: var(--text); font-weight: 650; }
.widget .sub .good { color: var(--accent); font-weight: 650; }
.widget .sub .warn { color: var(--amber); font-weight: 650; }
.w-bar {
height: 7px;
border-radius: 99px;
background: rgba(255, 255, 255, 0.07);
overflow: hidden;
margin: 8px 0 7px;
}
.upgrade-rebuild-note {
font-style: italic;
color: var(--text-dim);
font-size: 0.82rem;
.w-bar-fill {
height: 100%;
border-radius: 99px;
background: linear-gradient(90deg, #42f39a, #1aa45d);
transition: width 0.6s cubic-bezier(0.3, 0.7, 0.3, 1);
}
.w-chev {
margin-left: auto;
width: 30px;
height: 30px;
border-radius: 50%;
display: grid;
place-items: center;
color: var(--text-3);
flex-shrink: 0;
}
.w-chev svg { width: 15px; height: 15px; }
.widget.clickable:hover .w-chev {
color: var(--text-2);
background: rgba(255, 255, 255, 0.07);
}
/* ── Tiles area ─────────────────────────────────────────────────── */
#tiles-area {
flex: 1;
height: 100%;
overflow-y: auto;
padding: 24px 20px 48px;
min-width: 0;
}
.dashboard-loading {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
padding: 72px 24px;
color: var(--text-3);
font-size: 0.9rem;
}
.dashboard-loading-spinner {
width: 20px;
height: 20px;
border-radius: 50%;
border: 2.5px solid rgba(255, 255, 255, 0.12);
border-top-color: var(--accent);
animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
/* ── Category sections ──────────────────────────────────────────── */
.category-section {
@@ -140,25 +369,30 @@
}
.section-header {
font-size: 0.82rem;
font-weight: 700;
letter-spacing: 0.08em;
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 15px;
font-size: 0.72rem;
font-weight: 750;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--text-secondary);
margin-bottom: 4px;
padding-left: 4px;
color: var(--text-2);
white-space: nowrap;
}
.section-divider {
border: none;
border-top: 1px solid var(--border-color);
margin-bottom: 16px;
flex: 1;
height: 1px;
background: linear-gradient(90deg, var(--border), transparent);
margin: 0;
}
.tiles-grid {
display: flex;
flex-wrap: wrap;
gap: 14px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
gap: 15px;
}
/* ── Empty state ────────────────────────────────────────────────── */
@@ -166,10 +400,64 @@
.empty-state {
text-align: center;
padding: 64px 24px;
color: var(--text-dim);
color: var(--text-3);
}
.empty-state p {
font-size: 1rem;
margin-bottom: 8px;
}
/* ── Upgrade modal (kept from previous layout) ──────────────────── */
.upgrade-dialog {
max-width: 480px;
}
.upgrade-info-box {
background: rgba(0, 0, 0, 0.16);
border: 1px solid var(--border-strong);
border-radius: 16px;
padding: 14px 16px;
margin: 14px 0;
}
.upgrade-info-title {
font-size: 0.88rem;
font-weight: 700;
color: var(--text);
margin-bottom: 8px;
}
.upgrade-info-list {
padding-left: 20px;
font-size: 0.85rem;
color: var(--text-2);
line-height: 1.7;
margin: 0;
}
.upgrade-info-list a {
color: var(--accent);
}
.upgrade-rebuild-note {
font-style: italic;
color: var(--text-3);
font-size: 0.82rem;
}
/* ── First-login security banner (inside .content) ──────────────── */
.security-first-login-banner {
display: flex;
align-items: center;
gap: 12px;
background: rgba(233, 182, 74, 0.08);
border: 1px solid rgba(233, 182, 74, 0.30);
border-radius: 16px;
padding: 12px 16px;
color: var(--text-2);
font-size: 0.85rem;
margin-bottom: 24px;
}
File diff suppressed because it is too large Load Diff
@@ -7,7 +7,7 @@
justify-content: flex-start;
min-height: 100vh;
background:
radial-gradient(ellipse at top, rgba(94, 173, 138, 0.04) 0%, transparent 50%),
radial-gradient(ellipse at top, rgba(62, 207, 142, 0.04) 0%, transparent 50%),
var(--bg-color);
padding: 24px 16px 48px;
overflow-y: auto;
@@ -70,13 +70,13 @@
.onboarding-step-dot.active {
background-color: var(--accent-color);
border-color: var(--accent-color);
color: #0A1A10;
color: #04220f;
}
.onboarding-step-dot.completed {
background-color: var(--green);
border-color: var(--green);
color: #0A1A10;
color: #04220f;
}
.onboarding-step-connector {
@@ -139,7 +139,7 @@
/* Cards */
.onboarding-card {
background-color: rgba(14, 16, 15, 0.65);
background-color: rgba(18, 24, 20, 0.65);
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
border: 1px solid rgba(255, 255, 255, 0.06);
@@ -184,10 +184,10 @@
font-size: 0.82rem;
font-weight: 700;
color: var(--accent-color);
background-color: rgba(94, 173, 138, 0.10);
background-color: rgba(62, 207, 142, 0.10);
padding: 3px 10px;
border-radius: 20px;
border: 1px solid rgba(94, 173, 138, 0.25);
border: 1px solid rgba(62, 207, 142, 0.25);
}
/* Step header */
@@ -371,8 +371,8 @@
.onboarding-port-warn {
padding: 10px 14px;
background-color: rgba(229, 165, 10, 0.1);
border: 1px solid rgba(229, 165, 10, 0.35);
background-color: rgba(233, 182, 74, 0.1);
border: 1px solid rgba(233, 182, 74, 0.35);
border-radius: 8px;
font-size: 0.85rem;
color: var(--yellow);
@@ -409,8 +409,8 @@
.onboarding-creds-notice {
padding: 12px 16px;
background-color: rgba(94, 173, 138, 0.08);
border: 1px solid rgba(94, 173, 138, 0.20);
background-color: rgba(62, 207, 142, 0.08);
border: 1px solid rgba(62, 207, 142, 0.20);
border-radius: 8px;
font-size: 0.85rem;
color: var(--text-secondary);
@@ -503,8 +503,8 @@
font-size: 0.72rem;
padding: 2px 8px;
border-radius: 4px;
background-color: rgba(94, 173, 138, 0.08);
border: 1px solid rgba(94, 173, 138, 0.20);
background-color: rgba(62, 207, 142, 0.08);
border: 1px solid rgba(62, 207, 142, 0.20);
color: var(--accent-color);
cursor: pointer;
white-space: nowrap;
@@ -512,7 +512,7 @@
}
.onboarding-cred-reveal-btn:hover {
background-color: rgba(94, 173, 138, 0.15);
background-color: rgba(62, 207, 142, 0.15);
}
/* Completion checklist (Step 5) */
@@ -671,7 +671,7 @@
}
.onboarding-password-toggle:hover {
background-color: rgba(94, 173, 138, 0.10);
background-color: rgba(62, 207, 142, 0.10);
border-color: var(--accent-color);
}
@@ -683,8 +683,8 @@
.onboarding-password-warning {
padding: 10px 14px;
background-color: rgba(229, 165, 10, 0.1);
border: 1px solid rgba(229, 165, 10, 0.35);
background-color: rgba(233, 182, 74, 0.1);
border: 1px solid rgba(233, 182, 74, 0.35);
border-radius: 8px;
font-size: 0.85rem;
color: var(--yellow);
@@ -694,8 +694,8 @@
.onboarding-password-success {
padding: 12px 16px;
background-color: rgba(94, 173, 138, 0.10);
border: 1px solid rgba(94, 173, 138, 0.30);
background-color: rgba(62, 207, 142, 0.10);
border: 1px solid rgba(62, 207, 142, 0.30);
border-radius: 8px;
font-size: 0.92rem;
color: var(--green);
@@ -748,7 +748,7 @@
}
.reboot-card {
background-color: rgba(14, 16, 15, 0.8);
background-color: rgba(18, 24, 20, 0.8);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.08);
@@ -28,7 +28,7 @@
.security-warning-box {
background-color: rgba(180, 40, 40, 0.10);
border-left: 3px solid #c94040;
border-left: 3px solid var(--red);
border-radius: 6px;
padding: 12px 14px;
margin-bottom: 14px;
@@ -78,7 +78,7 @@
}
.btn-danger {
background-color: #c94040;
background-color: var(--red);
color: #fff;
border: none;
border-radius: 6px;
@@ -90,7 +90,7 @@
}
.btn-danger:hover:not(:disabled) {
background-color: #a83030;
background-color: var(--red);
}
.btn-danger:disabled {
@@ -105,8 +105,8 @@
}
.security-status-info { color: var(--text-secondary); }
.security-status-ok { color: #6DBF8B; }
.security-status-error { color: #e05252; }
.security-status-ok { color: var(--accent); }
.security-status-error { color: var(--red); }
/* ── Verify System Integrity ─────────────────────────────────────── */
@@ -160,7 +160,7 @@
.security-verify-link {
font-size: 0.78rem;
color: var(--accent-color, #6DBF8B);
color: var(--accent-color, var(--accent));
text-decoration: none;
}
@@ -174,13 +174,13 @@
}
.security-verify-pass {
background-color: rgba(109, 191, 139, 0.15);
color: #6DBF8B;
background-color: rgba(66, 243, 154, 0.15);
color: var(--accent);
}
.security-verify-fail {
background-color: rgba(224, 82, 82, 0.15);
color: #e05252;
color: var(--red);
}
.security-verify-errors {
@@ -221,12 +221,11 @@
display: none;
position: fixed;
inset: 0;
background-color: rgba(6, 8, 7, 0.94);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
background: radial-gradient(1000px 640px at 50% 18%, #17211c, #0b100d 72%);
z-index: 1000;
align-items: center;
justify-content: center;
padding: 26px;
animation: security-reset-fade-in 0.35s ease-out;
}
@@ -253,13 +252,13 @@
}
.security-reset-password-box {
font-family: monospace;
font-family: var(--mono);
font-size: 1.35rem;
font-weight: 700;
color: var(--text-primary);
background: rgba(109, 191, 139, 0.10);
border: 1.5px solid rgba(109, 191, 139, 0.35);
border-radius: 8px;
background: var(--accent-dim);
border: 1.5px solid rgba(66, 243, 154, 0.35);
border-radius: 14px;
padding: 14px 24px;
letter-spacing: 0.04em;
text-align: center;
@@ -277,10 +276,11 @@
}
.security-reset-reboot-btn {
background-color: #6DBF8B;
color: #0a0c0b;
background: linear-gradient(180deg, #3fd68e, #1ea263);
color: #04220f;
border: none;
border-radius: 7px;
border-radius: 99px;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28), 0 6px 18px rgba(35, 199, 124, 0.22);
padding: 11px 22px;
font-size: 0.88rem;
font-weight: 700;
@@ -290,7 +290,7 @@
}
.security-reset-reboot-btn:hover:not(:disabled) {
background-color: #5aab78;
background-color: var(--accent);
}
.security-reset-reboot-btn:disabled {
@@ -303,11 +303,12 @@
.security-first-login-banner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 12px 18px;
background-color: rgba(94, 173, 138, 0.08);
border-bottom: 2px solid rgba(94, 173, 138, 0.25);
padding: 12px 16px;
margin-bottom: 24px;
background: rgba(233, 182, 74, 0.08);
border: 1px solid rgba(233, 182, 74, 0.30);
border-radius: 16px;
color: var(--text-primary);
}
@@ -333,19 +334,21 @@
.security-banner-dismiss {
background: none;
border: 1px solid var(--border-color);
border-radius: 4px;
border: 1px solid var(--border-strong);
border-radius: 99px;
cursor: pointer;
font-size: 0.9rem;
color: var(--text-secondary);
padding: 2px 7px;
padding: 4px 10px;
flex-shrink: 0;
line-height: 1.4;
transition: background-color 0.15s;
transition: 0.15s;
}
.security-banner-dismiss:hover {
background-color: rgba(0,0,0,0.08);
color: var(--text);
border-color: rgba(255, 255, 255, 0.26);
background: rgba(255, 255, 255, 0.04);
}
/* ── Legacy security inline warning banner ───────────────────────── */
@@ -357,14 +360,14 @@
padding: 12px 14px;
margin-bottom: 12px;
background-color: rgba(180, 100, 0, 0.12);
border-left: 3px solid #c97a00;
border-left: 3px solid #c98d08;
border-radius: 6px;
color: var(--text-primary);
}
.security-inline-icon {
font-size: 1rem;
color: #e69000;
color: #e0a010;
flex-shrink: 0;
}
@@ -378,9 +381,9 @@
display: inline-block;
font-size: 0.82rem;
font-weight: 600;
color: #e69000;
color: #e0a010;
text-decoration: none;
border: 1px solid #c97a00;
border: 1px solid #c98d08;
border-radius: 4px;
padding: 4px 10px;
align-self: flex-start;
@@ -447,9 +450,9 @@
.pw-credentials-note {
font-size: 0.78rem;
color: #c97a00;
color: #c98d08;
background-color: rgba(180, 100, 0, 0.10);
border-left: 2px solid #c97a00;
border-left: 2px solid #c98d08;
border-radius: 4px;
padding: 7px 10px;
margin-bottom: 12px;
+11 -11
View File
@@ -104,7 +104,7 @@
}
.support-steps code {
background-color: rgba(94, 173, 138, 0.10);
background-color: rgba(62, 207, 142, 0.10);
padding: 2px 6px;
border-radius: 4px;
font-size: 0.82rem;
@@ -116,7 +116,7 @@
padding: 12px;
border-radius: var(--radius-btn);
background-color: var(--accent-color);
color: #0A1A10;
color: #04220f;
font-size: 0.95rem;
font-weight: 700;
margin-bottom: 10px;
@@ -146,7 +146,7 @@
padding: 12px;
border-radius: var(--radius-btn);
background-color: var(--accent-color);
color: #0A1A10;
color: #04220f;
font-size: 0.95rem;
font-weight: 700;
margin-top: 16px;
@@ -168,7 +168,7 @@
}
.support-btn-auditlog:hover:not(:disabled) {
background-color: #1c2a24;
background-color: var(--card-hover);
}
.support-fine-print {
@@ -219,13 +219,13 @@
}
.support-wallet-protected {
background-color: rgba(109, 191, 139, 0.06);
border-color: rgba(109, 191, 139, 0.3);
background-color: rgba(66, 243, 154, 0.06);
border-color: rgba(66, 243, 154, 0.3);
}
.support-wallet-unlocked {
background-color: rgba(229, 165, 10, 0.06);
border-color: rgba(229, 165, 10, 0.3);
background-color: rgba(233, 182, 74, 0.06);
border-color: rgba(233, 182, 74, 0.3);
}
.support-wallet-warning {
@@ -290,7 +290,7 @@
padding: 8px 16px;
border-radius: var(--radius-btn);
background-color: var(--yellow);
color: #0A1A10;
color: #04220f;
font-size: 0.82rem;
font-weight: 700;
}
@@ -310,7 +310,7 @@
}
.support-btn-wallet-lock:hover:not(:disabled) {
background-color: #529E7E;
background-color: var(--accent);
}
/* ── Audit log ───────────────────────────────────────────────────── */
@@ -324,7 +324,7 @@
.support-audit-log {
max-height: 200px;
overflow-y: auto;
background-color: #0c0f0e;
background-color: var(--inset);
border-radius: 8px;
padding: 10px 14px;
}
+106 -401
View File
@@ -1,473 +1,178 @@
/* ── Service tile card (status-only) ─────────────────────────────── */
.dashboard-loading {
min-height: 180px;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
color: var(--text-secondary);
font-size: 0.9rem;
}
.dashboard-loading-spinner {
width: 16px;
height: 16px;
border: 2px solid var(--border-color);
border-top-color: var(--accent-color);
border-radius: 50%;
animation: dashboard-loading-spin 0.8s linear infinite;
}
@keyframes dashboard-loading-spin {
to { transform: rotate(360deg); }
}
/* ── Service tiles ──────────────────────────────────────────────── */
.service-tile {
width: 160px;
min-height: 130px;
background-color: var(--card-color);
border: 1px solid var(--border-color);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
border-radius: var(--radius-card);
box-shadow: var(--shadow-card);
background: var(--card);
border: 1px solid var(--border);
border-radius: 20px;
overflow: hidden;
padding: 21px 12px 17px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px 12px 18px;
gap: 0;
transition: box-shadow 0.2s, border-color 0.2s;
position: relative;
cursor: pointer;
position: relative;
transition: transform 0.18s, border-color 0.18s, background 0.18s, box-shadow 0.18s, opacity 0.18s;
animation: tileIn 0.45s cubic-bezier(0.2, 0.8, 0.3, 1) backwards;
}
@keyframes tileIn {
from { opacity: 0; transform: translateY(10px) scale(0.96); }
}
.service-tile:hover {
transform: translateY(-4px);
border-color: var(--border-strong);
background: var(--card-hover);
box-shadow: var(--shadow-hover);
border-color: var(--accent-color);
}
.service-tile.disabled {
opacity: 0.45;
.service-tile:active { transform: translateY(-1px) scale(0.985); }
.service-tile:focus-visible {
outline: 2px solid rgba(66, 243, 154, 0.45);
outline-offset: 2px;
}
.service-tile.disabled { opacity: 0.55; }
.tile-icon {
width: 48px;
height: 48px;
width: 62px;
height: 62px;
display: block;
object-fit: contain;
margin-bottom: 10px;
}
.tile-icon-fallback {
width: 48px;
height: 48px;
width: 62px;
height: 62px;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--border-color);
border-radius: 12px;
color: var(--text-dim);
font-size: 1.5rem;
margin-bottom: 10px;
color: var(--text-3);
font-size: 1.2rem;
font-weight: 700;
}
.tile-name {
font-size: 0.88rem;
font-weight: 600;
margin-top: 13px;
font-size: 0.86rem;
font-weight: 650;
text-align: center;
color: var(--text-primary);
line-height: 1.3;
max-width: 140px;
word-break: break-word;
hyphens: auto;
min-height: 1.3em;
line-height: 1.25;
min-height: 2.5em;
display: flex;
align-items: center;
justify-content: center;
color: var(--text);
max-width: 100%;
}
/* Status pill — dot + label inside a rounded pill */
.tile-status {
font-size: 0.75rem;
margin-top: 8px;
display: flex;
margin-top: 9px;
display: inline-flex;
align-items: center;
gap: 5px;
color: var(--text-secondary);
gap: 6px;
font-size: 0.69rem;
font-weight: 700;
padding: 3px 10px;
border-radius: 99px;
letter-spacing: 0.01em;
white-space: nowrap;
background: rgba(255, 255, 255, 0.05);
color: var(--text-2);
}
.tile-version {
font-size: 0.7rem;
color: var(--text-dim);
margin-top: 2px;
text-align: center;
}
.status-text { line-height: 1; }
.status-dot {
width: 8px;
height: 8px;
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--text-3);
flex-shrink: 0;
background-color: var(--grey);
}
.status-dot.active { background-color: var(--green); }
.status-dot.inactive { background-color: var(--red); }
.status-dot.loading { background-color: var(--yellow); animation: pulse-badge 1s infinite; }
.status-dot.failed { background-color: var(--red); }
.status-dot.disabled { background-color: var(--grey); }
.status-dot.needs-attention { background-color: var(--yellow); }
.status-dot.syncing { background-color: #f5a623; animation: pulse-badge 1.5s infinite; }
.status-dot.checking-reachability { background-color: var(--accent-color); animation: pulse-badge 1s infinite; }
.status-dot.active { background: var(--accent); }
.status-dot.needs-attention { background: var(--amber); }
.status-dot.failed { background: var(--red); }
.status-dot.inactive,
.status-dot.disabled { background: var(--text-3); }
.status-dot.syncing,
.status-dot.loading,
.status-dot.checking-reachability { background: var(--blue); animation: tile-dot-pulse 1.4s ease-in-out infinite; }
.status-dot.unknown { background: var(--text-3); }
/* ── Bitcoin IBD sync progress bar ──────────────────────────────── */
@keyframes tile-dot-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.35; }
}
/* Progressive enhancement: tint the whole pill on modern browsers */
.tile-status:has(.status-dot.active) { background: var(--accent-dim); color: var(--accent); }
.tile-status:has(.status-dot.needs-attention) { background: rgba(233, 182, 74, 0.10); color: var(--amber); }
.tile-status:has(.status-dot.failed) { background: rgba(246, 97, 81, 0.10); color: var(--red); }
.tile-status:has(.status-dot.syncing),
.tile-status:has(.status-dot.loading),
.tile-status:has(.status-dot.checking-reachability) { background: rgba(120, 174, 237, 0.10); color: var(--blue); }
.support-status-label {
font-size: 0.69rem;
font-weight: 700;
color: var(--text-2);
}
/* ── Bitcoin IBD sync tile ──────────────────────────────────────── */
.tile-sync-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
margin-top: 12px;
width: 100%;
margin-top: 6px;
padding: 0 6px;
}
.tile-sync-label {
font-size: 0.72rem;
color: #f5a623;
font-weight: 600;
font-size: 0.66rem;
font-weight: 750;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--amber);
text-align: center;
white-space: nowrap;
}
.tile-sync-bar-row {
display: flex;
align-items: center;
gap: 5px;
width: 100%;
gap: 8px;
margin-top: 7px;
}
.tile-sync-bar-track {
flex: 1;
height: 6px;
background-color: var(--border-color);
border-radius: 3px;
height: 7px;
border-radius: 99px;
background: rgba(255, 255, 255, 0.07);
overflow: hidden;
}
.tile-sync-bar-fill {
height: 100%;
background-color: #f5a623;
border-radius: 3px;
transition: width 0.6s ease;
min-width: 2px;
border-radius: 99px;
background: linear-gradient(90deg, #42f39a, #1aa45d);
transition: width 0.6s cubic-bezier(0.3, 0.7, 0.3, 1);
}
.tile-sync-percent {
font-size: 0.72rem;
font-family: var(--mono);
font-size: 0.7rem;
font-weight: 700;
color: #f5a623;
white-space: nowrap;
min-width: 2.5em;
text-align: right;
color: var(--amber);
flex-shrink: 0;
}
.tile-sync-eta {
font-size: 0.68rem;
color: var(--text-dim);
margin-top: 6px;
font-family: var(--mono);
font-size: 0.66rem;
color: var(--text-3);
text-align: center;
white-space: nowrap;
}
/* ── Service detail modal sections ───────────────────────────────── */
.svc-detail-section {
margin-bottom: 20px;
padding-bottom: 16px;
border-bottom: 1px solid var(--border-color);
}
.svc-detail-section:last-child {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
.svc-detail-section-title {
font-size: 0.78rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-dim);
margin-bottom: 10px;
}
.svc-detail-desc {
font-size: 0.9rem;
color: var(--text-secondary);
line-height: 1.6;
}
.svc-detail-status {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.9rem;
font-weight: 600;
color: var(--text-primary);
}
/* ── Service detail: Domain ──────────────────────────────────────── */
.svc-detail-domain-value {
font-size: 0.9rem;
color: var(--text-primary);
font-weight: 600;
}
.tile-domain-label--ok {
color: var(--green);
font-weight: 600;
}
.tile-domain-label--warn {
color: var(--yellow);
font-weight: 600;
}
.tile-domain-label--error {
color: var(--red);
font-weight: 600;
}
/* ── Service detail: Port table ──────────────────────────────────── */
.svc-detail-port-table {
width: 100%;
border-collapse: collapse;
font-size: 0.82rem;
margin-top: 8px;
}
.svc-detail-port-table th {
text-align: left;
color: var(--text-dim);
font-weight: 600;
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.04em;
padding: 6px 10px;
border-bottom: 1px solid var(--border-color);
}
.svc-detail-port-table td {
padding: 8px 10px;
border-bottom: 1px solid rgba(30, 45, 39, 0.6);
color: var(--text-primary);
}
.svc-detail-port-table tr:last-child td {
border-bottom: none;
}
.svc-detail-port-table-port {
font-family: 'JetBrains Mono', 'Fira Code', 'Source Code Pro', monospace;
font-weight: 600;
color: var(--accent-color);
}
.svc-detail-port-table-proto {
text-transform: uppercase;
color: var(--text-secondary);
}
.svc-detail-port-table-desc {
color: var(--text-secondary);
}
.svc-detail-port-table-status {
font-weight: 600;
}
.port-status-listening { color: var(--green); }
.port-status-open { color: var(--yellow); }
.port-status-closed { color: var(--red); }
.port-status-unknown { color: var(--text-dim); }
/* ── Service detail: Troubleshoot box ────────────────────────────── */
.svc-detail-troubleshoot {
margin-top: 12px;
padding: 14px 16px;
background-color: rgba(229, 165, 10, 0.08);
border: 1px solid rgba(229, 165, 10, 0.3);
border-radius: 10px;
font-size: 0.85rem;
color: var(--text-secondary);
line-height: 1.6;
}
.svc-detail-troubleshoot strong {
color: var(--yellow);
}
.svc-detail-troubleshoot ol {
margin-top: 8px;
padding-left: 20px;
}
.svc-detail-troubleshoot li {
margin-bottom: 4px;
}
.svc-detail-troubleshoot code {
background-color: rgba(94, 173, 138, 0.10);
padding: 2px 6px;
border-radius: 4px;
font-size: 0.82rem;
color: var(--accent-color);
}
.svc-detail-troubleshoot a {
color: var(--accent-color);
text-decoration: none;
}
.svc-detail-troubleshoot a:hover {
text-decoration: underline;
}
/* ── Service detail: Domain configure button ─────────────────────── */
.svc-detail-domain-btn {
margin-top: 12px;
}
/* ── Service detail: Addon feature toggle ────────────────────────── */
.svc-detail-addon-row {
display: flex;
align-items: center;
gap: 14px;
margin-top: 12px;
}
.svc-detail-addon-status {
font-size: 0.88rem;
font-weight: 700;
}
.addon-status--on {
color: var(--green);
}
.addon-status--off {
color: var(--text-dim);
}
.svc-detail-option-card {
padding: 16px;
background: rgba(94, 173, 138, 0.06);
border: 1px solid rgba(94, 173, 138, 0.24);
border-radius: 10px;
}
.svc-detail-option-list {
margin: 10px 0 0;
padding-left: 20px;
color: var(--text-secondary);
font-size: 0.84rem;
line-height: 1.55;
}
.svc-detail-option-list li {
margin-bottom: 5px;
}
.svc-detail-option-privacy {
margin-top: 12px;
padding: 10px 12px;
border-left: 3px solid var(--accent-color);
background: rgba(94, 173, 138, 0.08);
border-radius: 6px;
color: var(--text-secondary);
font-size: 0.82rem;
line-height: 1.5;
}
.svc-detail-option-privacy strong {
color: var(--accent-color);
}
.svc-detail-related-feature-btn:disabled {
cursor: not-allowed;
opacity: 0.55;
}
.feature-conflict-warning {
margin-top: 8px;
margin-bottom: 8px;
padding: 10px 14px;
background-color: rgba(229, 165, 10, 0.1);
border: 1px solid rgba(229, 165, 10, 0.3);
border-radius: 8px;
font-size: 0.82rem;
color: var(--yellow);
font-weight: 600;
}
.btn-warning {
background-color: #d97706;
color: #fff;
}
.btn-warning:hover:not(:disabled) {
background-color: #b45309;
}
.svc-detail-restart-section {
border-top: 1px solid var(--border-color);
padding-top: 16px;
}
.svc-detail-restart-btn {
margin-top: 8px;
}
.svc-detail-restart-result {
margin-top: 12px;
padding: 12px 16px;
border-radius: 8px;
font-size: 0.88rem;
line-height: 1.5;
display: none;
}
.svc-detail-restart-result.success {
background-color: rgba(109, 191, 139, 0.12);
border: 1px solid var(--green);
color: var(--green);
display: block;
}
.svc-detail-restart-result.error {
background-color: rgba(239, 68, 68, 0.12);
border: 1px solid #ef4444;
color: #f87171;
display: block;
}
/* ── Desktop launch buttons ──────────────────────────────────────── */
.svc-detail-launch-row {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.svc-detail-launch-btn {
font-size: 0.85rem;
padding: 8px 18px;
cursor: pointer;
}