24d23b80bd
UI-only; no behavioural or backup/restore surface touched. Green: build, vet, tests all pass; template_id_gate, emoji_gate, native_confirm_gate, offbox_rename_gate, mojibake_gate, app_row_dedup_gate all PASS. Scrollbars (style.css): the platform default reads as a bright chunky stripe against the navy and competes with the content it scrolls. Now thin and hairline-coloured — scrollbar-width/scrollbar-color for Firefox AND ::-webkit-scrollbar (8px, thumb --line, hover --text-3, --radius) for WebKit/Blink, because neither alone covers the browsers customers use. The two surfaces that actually scroll take their own panel background as the track (.sidebar -> --bg-2, html -> --bg-0) so the gutter never shows as a lighter channel. Tokens only, no raw hexes. Collapsible nav groups (layout.html + style.css, vanilla JS, no framework): Tárhely, Biztonsági mentés and Megosztás become accordions with a chevron; exactly one open at a time, clicking the open one closes it. Groups without sub-items are untouched plain links. Hungarian labels unchanged. - The header is a real <button>, so keyboard and AT reachability come for free instead of being simulated with tabindex/role on a div. aria-expanded + aria-controls + a :focus-visible outline. - Nothing became unreachable when the header stopped being a link: every group's landing page is ALSO its first sub-item (/storage -> Meghajtók, /backups -> Áttekintés, /sharing -> Hálózati megosztás). Checked before the conversion, not assumed. - Progressive enhancement: the group containing the active page is rendered open SERVER-SIDE (.is-open), so the right group is open before any JS runs and stays open if JS never does. The listener only handles clicks. - No layout jump: collapse animates grid-template-rows 0fr -> 1fr (with min-height:0 + overflow:hidden on the sub-list) rather than max-height, so it animates to the content's REAL height and there is no magic number to drift when a group gains or loses an item — the specific way a max-height accordion rots. The toggle reserves its 3px active border as transparent so becoming active adds no width shift. .18s transitions, and both the collapse and the chevron rotation are disabled under prefers-reduced-motion. Pre-existing and deliberately NOT bundled: docker_run_volume_path_gate.py still fails on internal/appexport/estimate.go:179. That is ROADMAP R-29, unrelated to this change, verified to fail identically on the untouched tree, and R-29 itself says not to bundle it into an unrelated feature commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nn3VgQk9iwEGgyx6QJ2NvE
3424 lines
81 KiB
CSS
3424 lines
81 KiB
CSS
/* Vendored fonts — variable woff2 embedded in the binary, served from /static/fonts/.
|
|
No CDN dependency (offline customer nodes). latin-ext is mandatory for Hungarian ő/ű. */
|
|
@font-face {
|
|
font-family: 'Plus Jakarta Sans';
|
|
font-style: normal;
|
|
font-weight: 400 800;
|
|
font-display: swap;
|
|
src: url('/static/fonts/pjs-latin.woff2') format('woff2');
|
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
}
|
|
@font-face {
|
|
font-family: 'Plus Jakarta Sans';
|
|
font-style: normal;
|
|
font-weight: 400 800;
|
|
font-display: swap;
|
|
src: url('/static/fonts/pjs-latin-ext.woff2') format('woff2');
|
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
}
|
|
@font-face {
|
|
font-family: 'JetBrains Mono';
|
|
font-style: normal;
|
|
font-weight: 400 500;
|
|
font-display: swap;
|
|
src: url('/static/fonts/jbm-latin.woff2') format('woff2');
|
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
}
|
|
@font-face {
|
|
font-family: 'JetBrains Mono';
|
|
font-style: normal;
|
|
font-weight: 400 500;
|
|
font-display: swap;
|
|
src: url('/static/fonts/jbm-latin-ext.woff2') format('woff2');
|
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
}
|
|
|
|
:root {
|
|
--bg-0: #0A1220; --bg-1: #0F1B2E; --bg-2: #16263F;
|
|
--line: #22344F; --line-soft: #1A2A42;
|
|
--text-1: #EDF2F9; --text-2: #94A6BF; --text-3: #5E7392;
|
|
--blue: #0083D8; --blue-bright: #2EA8F5; --blue-dim: rgba(0,131,216,.13);
|
|
--warn: #E0A93E; --warn-dim: rgba(224,169,62,.12);
|
|
--crit: #E5534B; --crit-dim: rgba(229,83,75,.12);
|
|
--radius: 2px;
|
|
--font-ui: 'Plus Jakarta Sans', -apple-system, sans-serif;
|
|
--font-data: 'JetBrains Mono', monospace;
|
|
}
|
|
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
html { scroll-behavior: smooth; }
|
|
|
|
body {
|
|
font-family: var(--font-ui);
|
|
background: var(--bg-0);
|
|
color: var(--text-1);
|
|
display: flex;
|
|
min-height: 100vh;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
/* Focus visibility on all interactive elements (design system v2). */
|
|
:focus-visible {
|
|
outline: 2px solid var(--blue-bright);
|
|
outline-offset: 1px;
|
|
}
|
|
|
|
/* Inline icon (vendored Lucide sprite, stroke = currentColor) */
|
|
.ico {
|
|
width: 16px;
|
|
height: 16px;
|
|
flex-shrink: 0;
|
|
vertical-align: -0.18em;
|
|
}
|
|
.ico-sm { width: 14px; height: 14px; }
|
|
|
|
/* Sidebar */
|
|
.sidebar {
|
|
width: 240px;
|
|
background: var(--bg-2);
|
|
color: var(--text-1);
|
|
display: flex;
|
|
flex-direction: column;
|
|
position: fixed;
|
|
height: 100vh;
|
|
overflow-y: auto;
|
|
border-right: 1px solid var(--line);
|
|
}
|
|
.sidebar-header {
|
|
padding: 1.5rem;
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
.sidebar-logo {
|
|
width: 140px;
|
|
height: auto;
|
|
display: block;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
.login-logo {
|
|
width: 200px;
|
|
height: auto;
|
|
display: block;
|
|
margin: 0 auto 0.5rem;
|
|
}
|
|
.customer-name {
|
|
display: block;
|
|
font-size: .85rem;
|
|
color: var(--text-2);
|
|
margin-top: .25rem;
|
|
}
|
|
.nav-links {
|
|
list-style: none;
|
|
padding: 1rem 0;
|
|
flex: 1;
|
|
}
|
|
.nav-links a {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .6rem;
|
|
padding: .75rem 1.5rem;
|
|
color: var(--text-2);
|
|
text-decoration: none;
|
|
font-size: .95rem;
|
|
font-weight: 500;
|
|
transition: color 0.2s ease, background 0.2s ease;
|
|
}
|
|
.nav-links a:hover {
|
|
color: var(--blue-bright);
|
|
background: var(--blue-dim);
|
|
}
|
|
.nav-links a.active {
|
|
color: var(--blue-bright);
|
|
background: var(--blue-dim);
|
|
border-left: 3px solid var(--blue);
|
|
}
|
|
.sidebar-footer {
|
|
padding: 1rem 1.5rem;
|
|
border-top: 1px solid var(--line);
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
font-size: .8rem;
|
|
}
|
|
.version { color: var(--text-3); }
|
|
.logout-link { color: var(--text-3); text-decoration: none; transition: color 0.2s ease; }
|
|
.logout-link:hover { color: var(--blue-bright); }
|
|
|
|
/* Main content */
|
|
.content {
|
|
margin-left: 240px;
|
|
padding: 2rem;
|
|
flex: 1;
|
|
max-width: 1200px;
|
|
}
|
|
.page-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
.page-header h2 {
|
|
font-size: 1.5rem;
|
|
font-weight: 600;
|
|
color: var(--text-1);
|
|
}
|
|
.domain-badge {
|
|
border: 1px solid var(--line);
|
|
color: var(--text-2);
|
|
padding: .2rem .6rem;
|
|
border-radius: var(--radius);
|
|
font-size: .8rem;
|
|
font-weight: 500;
|
|
font-family: var(--font-data);
|
|
}
|
|
|
|
h3 {
|
|
font-size: 1.1rem;
|
|
font-weight: 600;
|
|
color: var(--text-1);
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
/* Stats — boxless figures, 1px right hairline dividers (v2). */
|
|
.stats-grid {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
margin-bottom: 2rem;
|
|
}
|
|
.stat-card {
|
|
flex: 1;
|
|
min-width: 140px;
|
|
padding: .35rem 1.5rem;
|
|
border-right: 1px solid var(--line);
|
|
}
|
|
.stat-card:first-child { padding-left: 0; }
|
|
.stat-card:last-child { border-right: none; }
|
|
.stat-value {
|
|
font-family: var(--font-data);
|
|
font-size: 1.9rem;
|
|
font-weight: 500;
|
|
color: var(--text-1);
|
|
}
|
|
.stat-zero .stat-value { color: var(--text-3); }
|
|
.stat-warn .stat-value { color: var(--warn); }
|
|
.stat-label {
|
|
color: var(--text-2);
|
|
font-size: .85rem;
|
|
margin-top: .25rem;
|
|
}
|
|
|
|
/* System info bar */
|
|
.system-info-card {
|
|
background: var(--bg-1);
|
|
border-radius: var(--radius);
|
|
padding: 1rem 1.25rem;
|
|
border: 1px solid var(--line);
|
|
margin-bottom: 2rem;
|
|
}
|
|
.system-info-items {
|
|
display: flex;
|
|
gap: 2rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
.system-info-item {
|
|
flex: 1;
|
|
min-width: 200px;
|
|
}
|
|
.system-info-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: .5rem;
|
|
}
|
|
.system-info-label {
|
|
font-size: .8rem;
|
|
font-weight: 600;
|
|
color: var(--text-2);
|
|
text-transform: uppercase;
|
|
letter-spacing: .5px;
|
|
}
|
|
.system-info-value {
|
|
font-size: .8rem;
|
|
color: var(--text-3);
|
|
font-family: var(--font-data);
|
|
}
|
|
/* Meter — hairline capacity readout. Nominal fill is blue; amber/red appear
|
|
only past the 70%/85% thresholds (exception-color principle). The threshold
|
|
ticks are neutral hairlines baked into the track. */
|
|
.meter-track {
|
|
position: relative;
|
|
width: 100%;
|
|
height: 3px;
|
|
background: var(--line-soft);
|
|
}
|
|
.meter-track::before,
|
|
.meter-track::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: -2px;
|
|
bottom: -2px;
|
|
width: 1px;
|
|
background: var(--line);
|
|
z-index: 2;
|
|
}
|
|
.meter-track::before { left: 70%; }
|
|
.meter-track::after { left: 85%; }
|
|
.meter-track.no-ticks::before,
|
|
.meter-track.no-ticks::after { display: none; }
|
|
.meter-fill {
|
|
position: absolute;
|
|
left: 0; top: 0; bottom: 0;
|
|
background: var(--blue);
|
|
z-index: 1;
|
|
transition: width 0.3s ease;
|
|
}
|
|
.meter.warn .meter-fill { background: var(--warn); }
|
|
.meter.crit .meter-fill { background: var(--crit); }
|
|
.meter-flag {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .4rem;
|
|
margin-top: .5rem;
|
|
padding: .2rem .55rem;
|
|
font-size: .75rem;
|
|
font-weight: 500;
|
|
border-radius: var(--radius);
|
|
}
|
|
.meter.warn .meter-flag { color: var(--warn); background: var(--warn-dim); }
|
|
.meter.crit .meter-flag { color: var(--crit); background: var(--crit-dim); }
|
|
.meter-flag .ico { width: 13px; height: 13px; }
|
|
|
|
/* ─── Shared app-list row (v0.126.0) ──────────────────────────────────
|
|
THE canonical list grammar (app_row.html partial): icon + name left, caller action
|
|
block right. Compact single-row height unless a secondary line is present — matches
|
|
the Alkalmazások backup-status collapsed-header density. */
|
|
.app-row-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .5rem;
|
|
}
|
|
.app-row {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .75rem;
|
|
padding: .5rem 1rem;
|
|
min-height: 44px;
|
|
background: var(--bg-2);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
}
|
|
.app-row-icon {
|
|
width: 24px;
|
|
height: 24px;
|
|
border-radius: var(--radius);
|
|
object-fit: contain;
|
|
background: var(--bg-2);
|
|
flex-shrink: 0;
|
|
}
|
|
.app-row-text {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .1rem;
|
|
min-width: 0;
|
|
flex: 1;
|
|
}
|
|
.app-row-name {
|
|
font-weight: 500;
|
|
font-size: .9rem;
|
|
}
|
|
.app-row-secondary {
|
|
font-size: .8rem;
|
|
color: var(--text-2);
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
.app-row-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
gap: .5rem;
|
|
flex-shrink: 0;
|
|
flex-wrap: wrap;
|
|
}
|
|
/* 2px state edge (dashboard rows carry stack-state-<color> as RowClass). */
|
|
.app-row::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: 0; top: 0; bottom: 0;
|
|
width: 2px;
|
|
background: transparent;
|
|
}
|
|
.app-row.stack-state-run::before,
|
|
.app-row.stack-state-progress::before { background: var(--blue); }
|
|
.app-row.stack-state-warn::before { background: var(--warn); }
|
|
|
|
/* Stack list (dashboard) — one panel, hairline-separated shared rows. */
|
|
.stack-list {
|
|
background: var(--bg-1);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
}
|
|
.stack-list .app-row {
|
|
background: transparent;
|
|
border: none;
|
|
border-top: 1px solid var(--line-soft);
|
|
border-radius: 0;
|
|
padding: .6rem 1.25rem;
|
|
transition: background 0.15s ease;
|
|
}
|
|
.stack-list .app-row:first-child { border-top: none; }
|
|
.stack-list .app-row:hover {
|
|
background: rgba(0,131,216,.04);
|
|
}
|
|
.stack-logo-lg {
|
|
width: 48px;
|
|
height: 48px;
|
|
border-radius: var(--radius);
|
|
object-fit: contain;
|
|
background: var(--bg-2);
|
|
padding: 6px;
|
|
}
|
|
.stack-state-label {
|
|
font-size: .8rem;
|
|
color: var(--text-2);
|
|
margin-right: .5rem;
|
|
}
|
|
|
|
/* Stack detail grid (applications page) */
|
|
.stack-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
|
gap: 1rem;
|
|
}
|
|
.stack-detail-card {
|
|
background: var(--bg-1);
|
|
border-radius: var(--radius);
|
|
padding: 1.25rem;
|
|
border: 1px solid var(--line);
|
|
transition: border-color 0.3s ease, transform 0.3s ease;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
.stack-detail-card:hover {
|
|
border-color: var(--blue);
|
|
transform: translateY(-2px);
|
|
}
|
|
.stack-detail-card {
|
|
position: relative;
|
|
}
|
|
.stack-detail-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: 0; top: 0; bottom: 0;
|
|
width: 2px;
|
|
background: transparent;
|
|
}
|
|
.stack-detail-card.stack-state-run::before,
|
|
.stack-detail-card.stack-state-progress::before { background: var(--blue); }
|
|
.stack-detail-card.stack-state-warn::before { background: var(--warn); }
|
|
.stack-detail-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
margin-bottom: .75rem;
|
|
}
|
|
.stack-title-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .75rem;
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
.subdomain-link {
|
|
font-size: .8rem;
|
|
color: var(--blue-bright);
|
|
text-decoration: none;
|
|
transition: color 0.2s ease;
|
|
}
|
|
.subdomain-link:hover { text-decoration: underline; }
|
|
/* Tag — square 2px state chip with a 6px dot. Color only on deviation:
|
|
run/progress are blue (nominal), warn/crit amber/red, neutral/off gray. */
|
|
.tag {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .45rem;
|
|
padding: .15rem .55rem;
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
font-size: .75rem;
|
|
font-weight: 600;
|
|
color: var(--text-2);
|
|
white-space: nowrap;
|
|
flex-shrink: 0;
|
|
}
|
|
.tag .dot {
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
background: var(--text-3);
|
|
flex-shrink: 0;
|
|
}
|
|
.tag-run { border-color: rgba(0,131,216,.45); color: var(--blue-bright); }
|
|
.tag-run .dot { background: var(--blue); }
|
|
.tag-progress { border-color: rgba(0,131,216,.45); color: var(--blue-bright); }
|
|
.tag-progress .dot { background: var(--blue); animation: tag-pulse 1.2s ease-in-out infinite; }
|
|
.tag-warn { border-color: var(--warn); color: var(--warn); background: var(--warn-dim); }
|
|
.tag-warn .dot { background: var(--warn); }
|
|
.tag-crit { border-color: var(--crit); color: var(--crit); background: var(--crit-dim); }
|
|
.tag-crit .dot { background: var(--crit); }
|
|
.tag-neutral .dot, .tag-off .dot { background: transparent; border: 1px solid var(--text-3); }
|
|
@keyframes tag-pulse {
|
|
0%, 100% { opacity: 1; }
|
|
50% { opacity: 0.25; }
|
|
}
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.tag-progress .dot { animation: none; }
|
|
}
|
|
/* State text colors — funcmap emits run/progress/warn/neutral/off (stateColor)
|
|
and nominal/warn/crit (usageColor/tempColor). */
|
|
.state-text-run { color: var(--blue-bright); }
|
|
.state-text-progress { color: var(--blue-bright); }
|
|
.state-text-nominal { color: var(--text-1); }
|
|
.state-text-warn { color: var(--warn); }
|
|
.state-text-crit { color: var(--crit); }
|
|
.state-text-neutral, .state-text-off { color: var(--text-3); }
|
|
.stack-detail-desc {
|
|
color: var(--text-2);
|
|
font-size: .85rem;
|
|
margin-bottom: .75rem;
|
|
}
|
|
/* Metadata rows — icon + text, NO container (replaces informational pills). */
|
|
.metarows {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: .3rem 1rem;
|
|
margin: .5rem 0;
|
|
}
|
|
.metarow {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .4rem;
|
|
font-size: .78rem;
|
|
color: var(--text-2);
|
|
}
|
|
.metarow .ico {
|
|
width: 14px;
|
|
height: 14px;
|
|
color: var(--text-3);
|
|
}
|
|
.metarow .mono { font-family: var(--font-data); font-size: .75rem; }
|
|
/* Legacy informational pill — restyled flat until the Phase-4 sweep replaces the markup. */
|
|
.meta-badge {
|
|
color: var(--text-2);
|
|
padding: .1rem 0;
|
|
font-size: .78rem;
|
|
}
|
|
.meta-badge-ok {
|
|
color: var(--text-2);
|
|
}
|
|
.container-list { margin: .75rem 0; }
|
|
.container-list h4 { font-size: .8rem; color: var(--text-3); margin-bottom: .4rem; }
|
|
.container-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
font-size: .8rem;
|
|
padding: .3rem 0;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
.container-row:last-child { border-bottom: none; }
|
|
.container-name { font-family: var(--font-data); color: var(--text-2); }
|
|
.container-status { font-size: .75rem; }
|
|
.stack-detail-actions {
|
|
display: flex;
|
|
gap: .5rem;
|
|
margin-top: auto;
|
|
padding-top: 1rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
/* Buttons */
|
|
.btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .3rem;
|
|
padding: .5rem 1rem;
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
font-size: .85rem;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
|
|
text-decoration: none;
|
|
color: var(--text-1);
|
|
font-family: inherit;
|
|
background: var(--bg-2);
|
|
}
|
|
.btn:hover { border-color: var(--blue); }
|
|
.btn:active { opacity: .85; }
|
|
.btn:disabled { opacity: .5; cursor: not-allowed; transform: none; }
|
|
.btn.loading { opacity: .6; }
|
|
.btn-sm { padding: .3rem .6rem; font-size: .8rem; }
|
|
.btn-lg { padding: .65rem 1.5rem; font-size: 1rem; }
|
|
.btn-full { width: 100%; justify-content: center; }
|
|
.btn-primary {
|
|
background: var(--blue);
|
|
border-color: var(--blue);
|
|
color: #fff;
|
|
}
|
|
.btn-primary:hover { background: var(--blue-bright); border-color: var(--blue-bright); }
|
|
.btn-success {
|
|
background: var(--blue);
|
|
border-color: var(--blue);
|
|
color: #fff;
|
|
}
|
|
.btn-success:hover { background: var(--blue-bright); border-color: var(--blue-bright); }
|
|
.btn-warning {
|
|
background: transparent;
|
|
border: 1px solid var(--line);
|
|
color: var(--text-2);
|
|
}
|
|
.btn-warning:hover {
|
|
border-color: var(--blue);
|
|
color: var(--blue-bright);
|
|
background: var(--blue-dim);
|
|
}
|
|
.btn-danger {
|
|
background: transparent;
|
|
border: 1px solid var(--crit);
|
|
color: var(--crit);
|
|
}
|
|
.btn-danger:hover {
|
|
background: var(--crit-dim);
|
|
}
|
|
.btn-outline {
|
|
background: transparent;
|
|
border: 1px solid var(--line);
|
|
color: var(--text-2);
|
|
}
|
|
.btn-outline:hover {
|
|
border-color: var(--blue);
|
|
color: var(--blue-bright);
|
|
background: var(--blue-dim);
|
|
}
|
|
.badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .25rem;
|
|
padding: .2rem .6rem;
|
|
border-radius: var(--radius);
|
|
font-size: .75rem;
|
|
font-weight: 500;
|
|
}
|
|
.badge-protected {
|
|
background: var(--bg-2);
|
|
color: var(--text-3);
|
|
}
|
|
|
|
/* Deploy page */
|
|
.deploy-container { max-width: 700px; }
|
|
.deploy-info {
|
|
display: flex;
|
|
gap: 1rem;
|
|
align-items: flex-start;
|
|
background: var(--bg-1);
|
|
padding: 1.25rem;
|
|
border-radius: var(--radius);
|
|
border: 1px solid var(--line);
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
.deploy-logo {
|
|
width: 64px;
|
|
height: 64px;
|
|
border-radius: var(--radius);
|
|
object-fit: contain;
|
|
background: var(--bg-2);
|
|
padding: 8px;
|
|
flex-shrink: 0;
|
|
}
|
|
.deploy-info h3 { font-size: 1.2rem; margin-bottom: .25rem; }
|
|
.deploy-info p { color: var(--text-2); font-size: .9rem; }
|
|
.deploy-form {
|
|
background: var(--bg-1);
|
|
padding: 1.5rem;
|
|
border-radius: var(--radius);
|
|
border: 1px solid var(--line);
|
|
}
|
|
.form-section { margin-bottom: 1.5rem; }
|
|
.form-section h4 { font-size: 1rem; margin-bottom: .5rem; color: var(--text-1); }
|
|
.form-section-desc { color: var(--text-2); font-size: .85rem; margin-bottom: .75rem; }
|
|
.form-group { margin-bottom: 1rem; }
|
|
.form-group label { display: block; font-size: .85rem; font-weight: 500; margin-bottom: .4rem; color: var(--text-1); }
|
|
.form-group-auto {
|
|
padding: .5rem .75rem;
|
|
background: var(--bg-2);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
}
|
|
.form-group-auto label { display: flex; align-items: center; gap: .5rem; margin-bottom: .4rem; }
|
|
.form-group-auto .form-control[readonly] { background: var(--bg-0); }
|
|
.auto-generated-badge { color: var(--blue); font-size: .75rem; font-weight: normal; }
|
|
.checkbox-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .5rem;
|
|
margin-top: .25rem;
|
|
}
|
|
.form-inline {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .75rem;
|
|
}
|
|
.form-control-narrow {
|
|
width: 80px;
|
|
}
|
|
.form-hint {
|
|
font-size: .85rem;
|
|
color: var(--text-3);
|
|
}
|
|
.form-actions {
|
|
display: flex;
|
|
gap: .75rem;
|
|
margin-top: 1rem;
|
|
}
|
|
.form-control {
|
|
width: 100%;
|
|
padding: .55rem .75rem;
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
font-size: .9rem;
|
|
background: var(--bg-2);
|
|
color: var(--text-1);
|
|
font-family: inherit;
|
|
transition: border-color 0.2s ease;
|
|
}
|
|
.form-control:focus {
|
|
outline: none;
|
|
border-color: var(--blue);
|
|
}
|
|
.form-control:disabled {
|
|
background: var(--bg-0);
|
|
color: var(--text-3);
|
|
cursor: not-allowed;
|
|
}
|
|
select.form-control { appearance: auto; }
|
|
select.form-control option { background: var(--bg-2); color: var(--text-1); }
|
|
/* .form-input / .form-row — the backups-page twin of .form-control (v0.126.1): the class
|
|
was used across the backups/import/offbox templates with NO backing rule, so those
|
|
inputs rendered as browser defaults (the operator's "unstyled clipped placeholder"
|
|
screenshot). Same visual spec as .form-control. */
|
|
.form-input {
|
|
width: 100%;
|
|
padding: .55rem .75rem;
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
font-size: .9rem;
|
|
background: var(--bg-2);
|
|
color: var(--text-1);
|
|
font-family: inherit;
|
|
transition: border-color 0.2s ease;
|
|
}
|
|
.form-input:focus { outline: none; border-color: var(--blue); }
|
|
.form-input::placeholder { color: var(--text-3); }
|
|
.form-row { margin-bottom: .75rem; }
|
|
.form-row > label { display: block; font-size: .85rem; color: var(--text-2); margin-bottom: .3rem; }
|
|
.input-with-button { display: flex; gap: .5rem; }
|
|
.input-with-button .form-control { flex: 1; }
|
|
.subdomain-input-group { display: flex; align-items: center; gap: .5rem; }
|
|
.subdomain-input-group .subdomain-input { width: 8rem; }
|
|
.subdomain-input-group .subdomain-suffix {
|
|
color: var(--text-2); font-size: .95rem; white-space: nowrap;
|
|
}
|
|
.form-hint { display: block; font-size: .8rem; color: var(--text-3); margin-top: .25rem; }
|
|
.required { color: var(--crit); }
|
|
.locked-hint { font-size: .75rem; color: var(--text-3); font-weight: 400; margin-left: .5rem; }
|
|
.deploy-actions {
|
|
display: flex;
|
|
gap: .75rem;
|
|
margin-top: 1.5rem;
|
|
padding-top: 1rem;
|
|
border-top: 1px solid var(--line);
|
|
}
|
|
|
|
/* Deploy progress */
|
|
.deploy-progress {
|
|
background: var(--bg-1);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
padding: 1.5rem;
|
|
}
|
|
.deploy-progress h3 {
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
.deploy-steps {
|
|
margin: 1rem 0;
|
|
}
|
|
.deploy-step {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
padding: 0.5rem 0;
|
|
font-size: .95rem;
|
|
color: var(--text-3);
|
|
}
|
|
.deploy-step.active {
|
|
color: var(--text-1);
|
|
}
|
|
.deploy-step.done {
|
|
color: var(--text-1);
|
|
}
|
|
.deploy-step.done .step-icon {
|
|
color: var(--blue);
|
|
}
|
|
.deploy-step.error .step-icon {
|
|
color: var(--crit);
|
|
}
|
|
.deploy-step.warn .step-icon {
|
|
color: var(--warn);
|
|
}
|
|
.step-icon {
|
|
font-size: 1.1rem;
|
|
width: 1.5rem;
|
|
text-align: center;
|
|
flex-shrink: 0;
|
|
}
|
|
.deploy-elapsed {
|
|
color: var(--text-3);
|
|
font-size: .85rem;
|
|
margin-top: 0.5rem;
|
|
}
|
|
|
|
/* Toggle switch */
|
|
.toggle { cursor: pointer; display: flex; align-items: center; gap: .5rem; }
|
|
.toggle input[type="checkbox"] { accent-color: var(--blue); }
|
|
.toggle-label { font-size: .9rem; color: var(--text-2); }
|
|
|
|
/* Alerts */
|
|
.alert {
|
|
padding: .75rem 1rem;
|
|
border-radius: var(--radius);
|
|
margin-bottom: 1rem;
|
|
font-size: .85rem;
|
|
border: 1px solid;
|
|
}
|
|
.alert-error {
|
|
background: var(--crit-dim);
|
|
color: var(--crit);
|
|
border-color: var(--crit-dim);
|
|
}
|
|
.alert-info {
|
|
background: var(--blue-dim);
|
|
color: var(--blue-bright);
|
|
border-color: rgba(0,131,216,.35);
|
|
}
|
|
.alert-warning {
|
|
background: var(--warn-dim);
|
|
color: var(--warn);
|
|
border-color: var(--warn-dim);
|
|
}
|
|
|
|
/* Dashboard alert banners */
|
|
.alerts-container { margin-bottom: 1rem; }
|
|
.alert-banner {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
padding: 0.75rem 1rem;
|
|
border-radius: var(--radius);
|
|
margin-bottom: 0.5rem;
|
|
font-size: 0.9rem;
|
|
border: 1px solid;
|
|
}
|
|
.alert-banner-error {
|
|
background: var(--crit-dim);
|
|
border-color: var(--crit-dim);
|
|
color: var(--crit);
|
|
}
|
|
.alert-banner-warning {
|
|
background: var(--warn-dim);
|
|
border-color: var(--warn-dim);
|
|
color: var(--warn);
|
|
}
|
|
.alert-banner-info {
|
|
background: var(--blue-dim);
|
|
border-color: var(--blue-dim);
|
|
color: var(--blue-bright);
|
|
}
|
|
.alert-icon { flex-shrink: 0; }
|
|
.alert-message { flex: 1; }
|
|
.alert-link { margin-left: auto; white-space: nowrap; }
|
|
|
|
/* Inline storage warnings (under storage bars on dashboard and monitoring) */
|
|
.inline-warnings { margin-top: 0.75rem; }
|
|
.inline-warning {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.4rem 0.75rem;
|
|
margin-top: 0.25rem;
|
|
font-size: 0.8rem;
|
|
border-radius: var(--radius);
|
|
}
|
|
.inline-warning-warning {
|
|
color: var(--warn);
|
|
background: var(--warn-dim);
|
|
border: 1px solid var(--warn-dim);
|
|
}
|
|
.inline-warning-error {
|
|
color: var(--crit);
|
|
background: var(--crit-dim);
|
|
border: 1px solid var(--crit-dim);
|
|
}
|
|
.inline-warning-dot { font-size: 0.6rem; flex-shrink: 0; }
|
|
.inline-warning-text { flex: 1; }
|
|
.inline-warning-link {
|
|
color: inherit;
|
|
opacity: 0.8;
|
|
white-space: nowrap;
|
|
text-decoration: none;
|
|
}
|
|
.inline-warning-link:hover { opacity: 1; text-decoration: underline; }
|
|
|
|
/* Memory summary on deploy page */
|
|
.memory-summary {
|
|
background: var(--bg-1);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
padding: 1rem 1.25rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
.memory-blocked {
|
|
border-color: var(--crit-dim);
|
|
}
|
|
.memory-summary-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
.memory-summary-label {
|
|
font-size: .8rem;
|
|
font-weight: 600;
|
|
color: var(--text-2);
|
|
text-transform: uppercase;
|
|
letter-spacing: .5px;
|
|
}
|
|
.memory-summary-value {
|
|
font-size: .8rem;
|
|
color: var(--text-3);
|
|
font-family: var(--font-data);
|
|
}
|
|
/* Deploy-page memory meter — two segments on the meter track:
|
|
committed = solid blue, new app = blue at 35% opacity (v2). */
|
|
.meter-track-stacked {
|
|
height: 3px;
|
|
display: flex;
|
|
overflow: visible;
|
|
position: relative;
|
|
background: var(--line-soft);
|
|
}
|
|
.meter-track-stacked::before,
|
|
.meter-track-stacked::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: -2px;
|
|
bottom: -2px;
|
|
width: 1px;
|
|
background: var(--line);
|
|
z-index: 2;
|
|
}
|
|
.meter-track-stacked::before { left: 70%; }
|
|
.meter-track-stacked::after { left: 85%; }
|
|
.memory-bar-segment {
|
|
height: 100%;
|
|
position: relative;
|
|
z-index: 1;
|
|
transition: width 0.3s ease;
|
|
}
|
|
.memory-bar-committed {
|
|
background: var(--blue);
|
|
}
|
|
.memory-bar-new {
|
|
background: rgba(0,131,216,.35);
|
|
}
|
|
.memory-bar-legend {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.5rem 1.25rem;
|
|
margin-top: 0.5rem;
|
|
}
|
|
.memory-legend-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.35rem;
|
|
font-size: .75rem;
|
|
color: var(--text-3);
|
|
white-space: nowrap;
|
|
}
|
|
.memory-legend-dot {
|
|
display: inline-block;
|
|
width: 10px;
|
|
height: 10px;
|
|
border-radius: var(--radius);
|
|
flex-shrink: 0;
|
|
}
|
|
.memory-legend-committed {
|
|
background: var(--blue);
|
|
}
|
|
.memory-legend-new {
|
|
background: rgba(0,131,216,.35);
|
|
}
|
|
.memory-dist-bar {
|
|
width: 100%;
|
|
height: 14px;
|
|
border-radius: var(--radius);
|
|
display: flex;
|
|
overflow: hidden;
|
|
background: var(--bg-2);
|
|
border: 1px solid var(--line);
|
|
}
|
|
.memory-dist-bar .memory-bar-segment:first-child {
|
|
border-radius: 0;
|
|
}
|
|
.memory-dist-bar .memory-bar-segment:last-child {
|
|
border-radius: 0;
|
|
}
|
|
.memory-dist-header {
|
|
font-size: .85rem;
|
|
color: var(--text-2);
|
|
margin-bottom: .5rem;
|
|
font-family: var(--font-data);
|
|
}
|
|
|
|
/* Logs */
|
|
.logs-container {
|
|
background: var(--bg-2);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
padding: 1rem;
|
|
overflow-x: auto;
|
|
overflow-y: auto;
|
|
max-height: 70vh;
|
|
margin-bottom: 1rem;
|
|
}
|
|
.logs-output {
|
|
color: var(--text-1);
|
|
font-family: var(--font-data);
|
|
font-size: .8rem;
|
|
line-height: 1.5;
|
|
white-space: pre-wrap;
|
|
word-break: break-all;
|
|
margin: 0;
|
|
}
|
|
.logs-actions {
|
|
display: flex;
|
|
gap: .5rem;
|
|
align-items: center;
|
|
}
|
|
.logs-live-indicator {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .35rem;
|
|
font-size: .8rem;
|
|
font-weight: 600;
|
|
color: var(--blue);
|
|
margin-right: .5rem;
|
|
}
|
|
.logs-live-indicator.logs-live-paused {
|
|
color: var(--text-3);
|
|
}
|
|
.logs-live-dot {
|
|
display: inline-block;
|
|
width: 8px;
|
|
height: 8px;
|
|
border-radius: 50%;
|
|
background: var(--blue);
|
|
animation: logs-pulse 1.5s ease-in-out infinite;
|
|
}
|
|
@keyframes logs-pulse {
|
|
0%, 100% { opacity: 1; }
|
|
50% { opacity: 0.3; }
|
|
}
|
|
|
|
/* Sync toast */
|
|
.sync-toast {
|
|
padding: .6rem 1rem;
|
|
border-radius: var(--radius);
|
|
font-size: .85rem;
|
|
margin-bottom: 1rem;
|
|
border: 1px solid;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
.sync-toast-ok {
|
|
background: var(--blue-dim);
|
|
color: var(--blue);
|
|
border-color: var(--blue-dim);
|
|
}
|
|
.sync-toast-err {
|
|
background: var(--crit-dim);
|
|
color: var(--crit);
|
|
border-color: var(--crit-dim);
|
|
}
|
|
|
|
/* --- Filter bar --- */
|
|
.filter-bar {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
margin-bottom: 1.5rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.filter-btn {
|
|
padding: 0.4rem 1rem;
|
|
border-radius: var(--radius);
|
|
border: 1px solid var(--line);
|
|
background: var(--bg-2);
|
|
color: var(--text-2);
|
|
cursor: pointer;
|
|
font-size: 0.85rem;
|
|
font-family: inherit;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.filter-btn:hover {
|
|
border-color: var(--blue);
|
|
color: var(--text-1);
|
|
}
|
|
|
|
.filter-btn.active {
|
|
background: var(--blue);
|
|
border-color: var(--blue);
|
|
color: #fff;
|
|
}
|
|
|
|
.filter-count {
|
|
opacity: 0.7;
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
/* Clickable stat cards */
|
|
a.stat-card {
|
|
text-decoration: none;
|
|
color: inherit;
|
|
transition: transform 0.15s;
|
|
}
|
|
|
|
a.stat-card:hover {
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
/* Clickable cards */
|
|
[data-href] { cursor: pointer; }
|
|
|
|
.empty-state { text-align: center; padding: 3rem; color: var(--text-3); }
|
|
|
|
/* Login page */
|
|
.login-body {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
min-height: 100vh;
|
|
background: var(--bg-0);
|
|
}
|
|
.login-card {
|
|
background: var(--bg-1);
|
|
padding: 2.5rem;
|
|
border-radius: var(--radius);
|
|
border: 1px solid var(--line);
|
|
width: 100%;
|
|
max-width: 380px;
|
|
text-align: center;
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
.login-card .login-logo {
|
|
width: 220px;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
.login-subtitle {
|
|
color: var(--text-2);
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
.login-footer {
|
|
margin-top: 1.5rem;
|
|
font-size: .75rem;
|
|
color: var(--text-3);
|
|
}
|
|
.login-footer a {
|
|
color: var(--blue-bright);
|
|
text-decoration: none;
|
|
transition: color 0.2s ease;
|
|
}
|
|
.login-footer a:hover { color: var(--blue); }
|
|
|
|
/* --- App Info Page --- */
|
|
.app-info-hero {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1.5rem;
|
|
padding: 1.5rem;
|
|
background: var(--bg-1);
|
|
border-radius: var(--radius);
|
|
border: 1px solid var(--line);
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
.app-info-logo {
|
|
width: 80px;
|
|
height: 80px;
|
|
min-width: 80px;
|
|
min-height: 80px;
|
|
max-width: 80px;
|
|
max-height: 80px;
|
|
border-radius: var(--radius);
|
|
object-fit: contain;
|
|
background: var(--bg-2);
|
|
padding: 10px;
|
|
flex-shrink: 0;
|
|
overflow: hidden;
|
|
}
|
|
.app-info-tagline {
|
|
font-size: 1.1rem;
|
|
color: var(--text-1);
|
|
margin: 0 0 .75rem 0;
|
|
}
|
|
.app-screenshots {
|
|
display: flex;
|
|
gap: 1rem;
|
|
margin-bottom: 1.5rem;
|
|
overflow-x: auto;
|
|
padding-bottom: .5rem;
|
|
}
|
|
.app-screenshot {
|
|
max-height: 220px;
|
|
border-radius: var(--radius);
|
|
border: 1px solid var(--line);
|
|
object-fit: cover;
|
|
}
|
|
.app-info-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
gap: 1rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
.app-info-card {
|
|
background: var(--bg-1);
|
|
border-radius: var(--radius);
|
|
padding: 1.25rem;
|
|
border: 1px solid var(--line);
|
|
}
|
|
.app-info-card h3 {
|
|
margin: 0 0 .75rem 0;
|
|
font-size: .95rem;
|
|
color: var(--text-1);
|
|
}
|
|
.app-info-list {
|
|
margin: 0;
|
|
padding-left: 1.25rem;
|
|
color: var(--text-2);
|
|
font-size: .9rem;
|
|
line-height: 1.6;
|
|
}
|
|
.app-info-creds {
|
|
font-family: monospace;
|
|
font-size: 1rem;
|
|
color: var(--blue-bright);
|
|
background: var(--bg-2);
|
|
padding: .5rem .75rem;
|
|
border-radius: var(--radius);
|
|
display: inline-block;
|
|
margin: 0 0 .5rem 0;
|
|
}
|
|
.app-info-creds-warn {
|
|
color: var(--warn);
|
|
font-size: .85rem;
|
|
margin: 0;
|
|
}
|
|
.app-info-link {
|
|
color: var(--blue-bright);
|
|
text-decoration: none;
|
|
}
|
|
.app-info-link:hover { text-decoration: underline; }
|
|
|
|
/* Optional config section */
|
|
.app-optional-config {
|
|
background: var(--bg-1);
|
|
border-radius: var(--radius);
|
|
padding: 1.5rem;
|
|
border: 1px solid var(--line);
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
.app-optional-config h3 {
|
|
margin: 0 0 1rem 0;
|
|
font-size: 1.05rem;
|
|
}
|
|
.config-group {
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
.config-group h4 {
|
|
margin: 0 0 .5rem 0;
|
|
font-size: .95rem;
|
|
color: var(--text-1);
|
|
}
|
|
.config-group-desc {
|
|
color: var(--text-2);
|
|
font-size: .85rem;
|
|
margin: 0 0 1rem 0;
|
|
}
|
|
.config-fields {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
|
gap: 1rem;
|
|
}
|
|
.config-field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .25rem;
|
|
}
|
|
.config-field label {
|
|
font-size: .85rem;
|
|
font-weight: 500;
|
|
color: var(--text-1);
|
|
}
|
|
.config-field-help {
|
|
font-size: .8rem;
|
|
color: var(--text-2);
|
|
margin: 0;
|
|
line-height: 1.4;
|
|
}
|
|
.config-field-help a {
|
|
color: var(--blue-bright);
|
|
text-decoration: none;
|
|
}
|
|
.config-field-help a:hover { text-decoration: underline; }
|
|
.config-input {
|
|
background: var(--bg-2);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
padding: .5rem .75rem;
|
|
color: var(--text-1);
|
|
font-size: .9rem;
|
|
font-family: monospace;
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
}
|
|
.config-input:focus {
|
|
outline: none;
|
|
border-color: var(--blue);
|
|
}
|
|
.config-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
margin-top: 1rem;
|
|
}
|
|
.config-save-status {
|
|
font-size: .9rem;
|
|
transition: opacity .3s;
|
|
}
|
|
.config-save-ok { color: var(--blue); }
|
|
.config-save-err { color: var(--crit); }
|
|
.meta-badge-storage {
|
|
background: var(--blue-dim);
|
|
color: var(--blue-bright);
|
|
}
|
|
.meta-badge-warn {
|
|
background: var(--warn-dim) !important;
|
|
color: var(--warn) !important;
|
|
}
|
|
.meta-badge-ok {
|
|
background: var(--blue-dim) !important;
|
|
color: var(--blue) !important;
|
|
}
|
|
|
|
/* Orphan badge */
|
|
.badge-orphaned {
|
|
background: var(--warn-dim);
|
|
color: var(--warn);
|
|
}
|
|
|
|
/* B2b: a deployed app whose data drive was decommissioned/disconnected — distinct warning, not error-spam. */
|
|
.badge-missing-storage {
|
|
background: var(--warn-dim);
|
|
color: var(--warn);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* F5: an unhealthy/restarting deployed app has its public route withheld by Traefik (404 at the URL). */
|
|
.badge-route-unpublished {
|
|
background: var(--warn-dim);
|
|
color: var(--warn);
|
|
white-space: nowrap;
|
|
}
|
|
.route-unpublished {
|
|
display: inline-block;
|
|
margin-top: 2px;
|
|
font-size: 0.8em;
|
|
color: var(--warn);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Delete modal */
|
|
.modal-overlay {
|
|
position: fixed;
|
|
top: 0; left: 0;
|
|
width: 100%; height: 100%;
|
|
background: rgba(0, 0, 0, 0.7);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 1000;
|
|
}
|
|
.modal-card {
|
|
background: var(--bg-1);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
padding: 1.5rem;
|
|
max-width: 500px;
|
|
width: 90%;
|
|
max-height: 80vh;
|
|
overflow-y: auto;
|
|
}
|
|
.modal-card h3 {
|
|
margin-bottom: .75rem;
|
|
}
|
|
.modal-hdd-info {
|
|
background: var(--bg-2);
|
|
border-radius: var(--radius);
|
|
padding: .75rem 1rem;
|
|
margin: .75rem 0;
|
|
font-size: .85rem;
|
|
color: var(--text-2);
|
|
}
|
|
.modal-hdd-path {
|
|
font-family: var(--font-data);
|
|
font-size: .8rem;
|
|
color: var(--text-3);
|
|
padding: .2rem 0;
|
|
}
|
|
.modal-checkbox {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .5rem;
|
|
margin: .75rem 0;
|
|
padding: .75rem 1rem;
|
|
background: var(--crit-dim);
|
|
border: 1px solid var(--crit-dim);
|
|
border-radius: var(--radius);
|
|
font-size: .85rem;
|
|
color: var(--crit);
|
|
cursor: pointer;
|
|
}
|
|
.modal-checkbox input[type="checkbox"] {
|
|
accent-color: var(--crit);
|
|
}
|
|
.modal-actions {
|
|
display: flex;
|
|
gap: .75rem;
|
|
margin-top: 1rem;
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
/* Load average text */
|
|
.system-load-avg {
|
|
font-size: .7rem;
|
|
color: var(--text-3);
|
|
font-family: var(--font-data);
|
|
margin-top: .25rem;
|
|
}
|
|
|
|
/* Temperature — plain mono value; color only on warn/crit (v2). */
|
|
.temp-value {
|
|
font-family: var(--font-data);
|
|
font-size: .85rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.system-info-item-compact {
|
|
flex: 0 1 auto;
|
|
min-width: 120px;
|
|
}
|
|
|
|
/* Backup status card */
|
|
.backup-status-card {
|
|
background: var(--bg-1);
|
|
border-radius: var(--radius);
|
|
padding: 1rem 1.25rem;
|
|
border: 1px solid var(--line);
|
|
margin-bottom: 2rem;
|
|
}
|
|
.backup-status-card h3 {
|
|
margin-bottom: .75rem;
|
|
}
|
|
.backup-info-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: .25rem 0;
|
|
font-size: .85rem;
|
|
}
|
|
.backup-label {
|
|
color: var(--text-2);
|
|
}
|
|
.backup-value {
|
|
color: var(--text-1);
|
|
font-family: var(--font-data);
|
|
font-size: .8rem;
|
|
}
|
|
.backup-status-ok { color: var(--blue); }
|
|
.backup-status-fail { color: var(--crit); }
|
|
.backup-status-none { color: var(--text-3); }
|
|
|
|
/* Dashboard backup card link */
|
|
.backup-card-link {
|
|
color: var(--text-1);
|
|
text-decoration: none;
|
|
transition: color 0.2s;
|
|
}
|
|
.backup-card-link:hover {
|
|
color: var(--blue-bright);
|
|
}
|
|
|
|
/* --- Backup page --- */
|
|
.backup-page-cards {
|
|
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
|
}
|
|
|
|
.backup-empty-state {
|
|
text-align: center;
|
|
padding: 4rem 2rem;
|
|
background: var(--bg-1);
|
|
border-radius: var(--radius);
|
|
border: 1px solid var(--line);
|
|
}
|
|
.backup-empty-icon {
|
|
font-size: 3rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
.backup-empty-state h3 {
|
|
margin-bottom: .5rem;
|
|
}
|
|
.backup-empty-state p {
|
|
color: var(--text-2);
|
|
font-size: .9rem;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.schedule-card {
|
|
background: var(--bg-1);
|
|
border-radius: var(--radius);
|
|
padding: 1.25rem;
|
|
border: 1px solid var(--line);
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
.schedule-card h3 {
|
|
margin-bottom: .75rem;
|
|
}
|
|
.schedule-rows {
|
|
margin-bottom: 1rem;
|
|
}
|
|
.schedule-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
padding: .4rem 0;
|
|
font-size: .85rem;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
.schedule-row:last-child { border-bottom: none; }
|
|
.schedule-task {
|
|
color: var(--text-1);
|
|
font-weight: 500;
|
|
min-width: 160px;
|
|
}
|
|
.schedule-time {
|
|
color: var(--blue-bright);
|
|
font-family: var(--font-data);
|
|
font-size: .8rem;
|
|
min-width: 80px;
|
|
}
|
|
.schedule-next {
|
|
color: var(--text-2);
|
|
font-size: .8rem;
|
|
}
|
|
.schedule-summary {
|
|
border-top: 1px solid var(--line);
|
|
padding-top: .75rem;
|
|
margin-bottom: .75rem;
|
|
}
|
|
.schedule-summary-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: .25rem 0;
|
|
font-size: .85rem;
|
|
color: var(--text-2);
|
|
}
|
|
.schedule-summary-value {
|
|
color: var(--text-1);
|
|
font-family: var(--font-data);
|
|
font-size: .8rem;
|
|
}
|
|
.schedule-actions {
|
|
padding-top: .5rem;
|
|
}
|
|
|
|
.backup-section-card {
|
|
background: var(--bg-1);
|
|
border-radius: var(--radius);
|
|
padding: 1.25rem;
|
|
border: 1px solid var(--line);
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
.backup-section-card h3 {
|
|
margin-bottom: .75rem;
|
|
}
|
|
|
|
.backup-table-wrap {
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.db-table, .snapshot-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: .85rem;
|
|
}
|
|
.db-table th, .snapshot-table th {
|
|
text-align: left;
|
|
padding: .5rem .75rem;
|
|
color: var(--text-3);
|
|
font-size: .75rem;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: .5px;
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
.db-table td, .snapshot-table td {
|
|
padding: .5rem .75rem;
|
|
color: var(--text-1);
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
.db-table tr:nth-child(even), .snapshot-table tr:nth-child(even) {
|
|
background: var(--bg-2);
|
|
}
|
|
.db-table tr:nth-child(odd), .snapshot-table tr:nth-child(odd) {
|
|
background: var(--bg-1);
|
|
}
|
|
.db-table td.mono, .snapshot-table td.mono {
|
|
font-family: var(--font-data);
|
|
font-size: .8rem;
|
|
}
|
|
|
|
.db-type-badge {
|
|
display: inline-block;
|
|
padding: .1rem .5rem;
|
|
border-radius: var(--radius);
|
|
font-size: .75rem;
|
|
font-weight: 500;
|
|
}
|
|
.db-type-postgres {
|
|
background: var(--blue-dim);
|
|
color: var(--blue-bright);
|
|
}
|
|
.db-type-mariadb {
|
|
background: var(--warn-dim);
|
|
color: var(--warn);
|
|
}
|
|
|
|
.validation-badge {
|
|
display: inline-block;
|
|
padding: .1rem .5rem;
|
|
border-radius: var(--radius);
|
|
font-size: .75rem;
|
|
font-weight: 500;
|
|
}
|
|
.validation-ok {
|
|
background: var(--blue-dim);
|
|
color: var(--blue);
|
|
}
|
|
.validation-fail {
|
|
background: var(--crit-dim);
|
|
color: var(--crit);
|
|
cursor: help;
|
|
}
|
|
.validation-na {
|
|
color: var(--text-3);
|
|
}
|
|
|
|
.col-subtitle {
|
|
font-size: .7rem;
|
|
font-weight: 400;
|
|
color: var(--text-3);
|
|
text-transform: none;
|
|
letter-spacing: 0;
|
|
margin-left: .25rem;
|
|
}
|
|
|
|
|
|
.snapshot-footer {
|
|
padding: .75rem .75rem 0;
|
|
font-size: .8rem;
|
|
color: var(--text-2);
|
|
}
|
|
|
|
.backup-table-empty {
|
|
padding: 1.5rem;
|
|
text-align: center;
|
|
color: var(--text-3);
|
|
font-size: .85rem;
|
|
}
|
|
|
|
.repo-card {
|
|
background: var(--bg-1);
|
|
border-radius: var(--radius);
|
|
padding: 1.25rem;
|
|
border: 1px solid var(--line);
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
.repo-card h3 {
|
|
margin-bottom: .75rem;
|
|
}
|
|
.repo-info-rows {
|
|
margin-bottom: 1rem;
|
|
}
|
|
.repo-info-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: .3rem 0;
|
|
font-size: .85rem;
|
|
}
|
|
.repo-label {
|
|
color: var(--text-2);
|
|
}
|
|
.repo-value {
|
|
color: var(--text-1);
|
|
}
|
|
.repo-value.mono {
|
|
font-family: var(--font-data);
|
|
font-size: .8rem;
|
|
}
|
|
.repo-paths {
|
|
border-top: 1px solid var(--line);
|
|
padding-top: .75rem;
|
|
margin-bottom: .75rem;
|
|
}
|
|
.repo-path-list {
|
|
list-style: disc;
|
|
padding-left: 1.5rem;
|
|
margin-top: .5rem;
|
|
}
|
|
.repo-path-list li {
|
|
font-family: var(--font-data);
|
|
font-size: .8rem;
|
|
color: var(--text-2);
|
|
padding: .15rem 0;
|
|
}
|
|
.repo-remote {
|
|
border-top: 1px solid var(--line);
|
|
padding-top: .75rem;
|
|
}
|
|
.repo-tier {
|
|
border-top: 1px solid var(--line);
|
|
padding-top: .75rem;
|
|
margin-top: .75rem;
|
|
}
|
|
.repo-tier:first-child {
|
|
border-top: none;
|
|
padding-top: 0;
|
|
margin-top: 0;
|
|
}
|
|
.repo-tier-title {
|
|
font-size: .85rem;
|
|
font-weight: 600;
|
|
color: var(--text-2);
|
|
margin-bottom: .5rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: .3px;
|
|
}
|
|
.repo-remote-status {
|
|
margin-top: .25rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .15rem;
|
|
}
|
|
|
|
/* Details tier (collapsible sections in Részletek) */
|
|
.details-tier {
|
|
border-top: 1px solid var(--line);
|
|
margin-top: .5rem;
|
|
}
|
|
.details-tier:first-child {
|
|
border-top: none;
|
|
margin-top: 0;
|
|
}
|
|
.details-tier-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .5rem;
|
|
cursor: pointer;
|
|
padding: .5rem 0;
|
|
user-select: none;
|
|
}
|
|
.details-tier-header:hover {
|
|
opacity: .8;
|
|
}
|
|
.details-tier-header .expand-icon {
|
|
font-size: .7rem;
|
|
color: var(--text-3);
|
|
min-width: 1rem;
|
|
text-align: center;
|
|
}
|
|
.details-tier-header .repo-tier-title {
|
|
margin-bottom: 0;
|
|
}
|
|
.details-tier-body {
|
|
padding-bottom: .75rem;
|
|
}
|
|
.drive-detail-card {
|
|
background: var(--bg-2);
|
|
border-radius: var(--radius);
|
|
padding: .75rem;
|
|
margin-bottom: .5rem;
|
|
}
|
|
.drive-detail-header {
|
|
font-size: .85rem;
|
|
font-weight: 600;
|
|
color: var(--text-1);
|
|
margin-bottom: .5rem;
|
|
}
|
|
.method-group {
|
|
margin-top: .5rem;
|
|
}
|
|
.method-group-label {
|
|
font-size: .8rem;
|
|
font-weight: 600;
|
|
color: var(--text-2);
|
|
margin-bottom: .25rem;
|
|
}
|
|
.tier-empty-state {
|
|
font-size: .85rem;
|
|
color: var(--text-3);
|
|
padding: .5rem 0;
|
|
}
|
|
|
|
.relative-time {
|
|
color: var(--text-3);
|
|
font-size: .8rem;
|
|
}
|
|
|
|
/* --- Monitoring page --- */
|
|
.monitor-card {
|
|
background: var(--bg-1);
|
|
border-radius: var(--radius);
|
|
padding: 1.25rem;
|
|
border: 1px solid var(--line);
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
.monitor-card h3 {
|
|
margin-bottom: .75rem;
|
|
}
|
|
.monitoring-banner {
|
|
padding: .75rem 1rem;
|
|
border-radius: var(--radius);
|
|
font-size: .9rem;
|
|
border: 1px solid;
|
|
}
|
|
.monitoring-banner-green {
|
|
background: var(--blue-dim);
|
|
color: var(--blue);
|
|
border-color: var(--blue-dim);
|
|
}
|
|
.monitoring-banner-yellow {
|
|
background: var(--warn-dim);
|
|
color: var(--warn);
|
|
border-color: var(--warn-dim);
|
|
}
|
|
.monitoring-banner-red {
|
|
background: var(--warn-dim);
|
|
color: var(--warn);
|
|
border-color: var(--warn-dim);
|
|
}
|
|
.monitoring-banner-warn {
|
|
background: var(--warn-dim);
|
|
border-left: 4px solid var(--warn);
|
|
color: var(--warn);
|
|
}
|
|
.ping-status-ok { color: var(--blue); }
|
|
.ping-status-warn { color: var(--warn); }
|
|
.ping-schedule {
|
|
color: var(--text-3);
|
|
font-size: .85rem;
|
|
margin-left: .75rem;
|
|
}
|
|
.monitor-card-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
margin-bottom: 1rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
.monitor-card-header h3 {
|
|
margin-bottom: 0;
|
|
flex: 1;
|
|
min-width: 150px;
|
|
}
|
|
.time-range-bar {
|
|
display: flex;
|
|
gap: .35rem;
|
|
}
|
|
.sysinfo-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 0;
|
|
}
|
|
.sysinfo-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: baseline;
|
|
padding: .5rem .75rem;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
font-size: .9rem;
|
|
gap: 1rem;
|
|
}
|
|
.sysinfo-row:last-child { border-bottom: none; }
|
|
.sysinfo-label {
|
|
color: var(--text-2);
|
|
font-weight: 500;
|
|
white-space: nowrap;
|
|
flex-shrink: 0;
|
|
}
|
|
.sysinfo-value {
|
|
color: var(--text-1);
|
|
font-family: var(--font-data);
|
|
font-size: .85rem;
|
|
font-weight: 600;
|
|
text-align: right;
|
|
word-break: break-word;
|
|
}
|
|
.charts-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 1rem;
|
|
}
|
|
.charts-grid-2 {
|
|
grid-template-columns: 1fr 1fr;
|
|
}
|
|
.chart-box {
|
|
background: var(--bg-2);
|
|
border-radius: var(--radius);
|
|
padding: .75rem;
|
|
border: 1px solid var(--line-soft);
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
}
|
|
.chart-box-half {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
.chart-title {
|
|
font-size: .8rem;
|
|
font-weight: 600;
|
|
color: var(--text-2);
|
|
margin-bottom: .5rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: .3px;
|
|
}
|
|
.chart-wrap {
|
|
position: relative;
|
|
height: 180px;
|
|
overflow: hidden;
|
|
max-width: 100%;
|
|
}
|
|
.chart-wrap canvas {
|
|
max-width: 100%;
|
|
}
|
|
.chart-wrap-bar {
|
|
position: relative;
|
|
height: 250px;
|
|
overflow: hidden;
|
|
max-width: 100%;
|
|
}
|
|
.container-charts-row {
|
|
display: flex;
|
|
gap: 1rem;
|
|
}
|
|
.chart-empty {
|
|
text-align: center;
|
|
padding: 2rem;
|
|
color: var(--text-3);
|
|
font-size: .9rem;
|
|
}
|
|
.storage-bars {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
}
|
|
.storage-item {
|
|
padding: .25rem 0;
|
|
}
|
|
.storage-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: .4rem;
|
|
}
|
|
.storage-label {
|
|
font-size: .85rem;
|
|
font-weight: 600;
|
|
color: var(--text-2);
|
|
}
|
|
.storage-value {
|
|
font-size: .8rem;
|
|
color: var(--text-3);
|
|
font-family: var(--font-data);
|
|
}
|
|
|
|
/* --- Settings page --- */
|
|
.settings-card {
|
|
background: var(--bg-1);
|
|
border-radius: var(--radius);
|
|
padding: 1.5rem;
|
|
border: 1px solid var(--line);
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
.settings-card h3 {
|
|
margin-bottom: .5rem;
|
|
}
|
|
.settings-card-desc {
|
|
color: var(--text-2);
|
|
font-size: .85rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
.settings-grid {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
.settings-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: .5rem .75rem;
|
|
border-bottom: 1px solid var(--line-soft);
|
|
font-size: .9rem;
|
|
gap: 1rem;
|
|
}
|
|
.settings-row:last-child { border-bottom: none; }
|
|
.settings-label {
|
|
color: var(--text-2);
|
|
font-weight: 500;
|
|
white-space: nowrap;
|
|
flex-shrink: 0;
|
|
}
|
|
.settings-value {
|
|
color: var(--text-1);
|
|
text-align: right;
|
|
word-break: break-word;
|
|
}
|
|
.settings-value.mono {
|
|
font-family: var(--font-data);
|
|
font-size: .85rem;
|
|
}
|
|
.settings-value-truncate {
|
|
max-width: 400px;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Sidebar bottom section */
|
|
.sidebar-bottom {
|
|
margin-top: auto;
|
|
border-top: 1px solid var(--line);
|
|
}
|
|
|
|
/* --- Backup page: Storage overview grid --- */
|
|
.storage-overview-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 1.5rem;
|
|
align-items: start;
|
|
}
|
|
.storage-stats {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .5rem;
|
|
}
|
|
.storage-stat-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: .3rem 0;
|
|
font-size: .85rem;
|
|
}
|
|
.storage-stat-label {
|
|
color: var(--text-2);
|
|
}
|
|
.storage-stat-value {
|
|
color: var(--text-1);
|
|
}
|
|
|
|
/* --- Backup page: App backup status (read-only) --- */
|
|
.backup-section-desc {
|
|
color: var(--text-2);
|
|
font-size: .85rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
.app-backup-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .5rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
.app-backup-item {
|
|
background: var(--bg-2);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
padding: .75rem 1rem;
|
|
}
|
|
.app-backup-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
.app-backup-name-link {
|
|
font-weight: 500;
|
|
font-size: .9rem;
|
|
color: var(--text-1);
|
|
text-decoration: none;
|
|
}
|
|
.app-backup-name-link:hover {
|
|
color: var(--blue);
|
|
text-decoration: underline;
|
|
}
|
|
.app-backup-status-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .5rem;
|
|
}
|
|
.app-backup-size {
|
|
font-size: .8rem;
|
|
color: var(--text-3);
|
|
}
|
|
.app-backup-status {
|
|
font-size: .8rem;
|
|
font-weight: 500;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .35rem;
|
|
}
|
|
.app-backup-status::before {
|
|
content: '';
|
|
display: inline-block;
|
|
width: 8px;
|
|
height: 8px;
|
|
border-radius: 50%;
|
|
flex-shrink: 0;
|
|
}
|
|
.app-backup-active {
|
|
color: var(--blue);
|
|
}
|
|
.app-backup-active::before {
|
|
background: var(--blue);
|
|
}
|
|
.app-backup-inactive {
|
|
color: var(--text-3);
|
|
}
|
|
.app-backup-inactive::before {
|
|
border: 1px solid var(--text-3);
|
|
background: transparent;
|
|
width: 6px;
|
|
height: 6px;
|
|
}
|
|
.app-backup-na {
|
|
color: var(--text-3);
|
|
}
|
|
.app-backup-na::before {
|
|
content: '—';
|
|
width: auto;
|
|
height: auto;
|
|
border-radius: 0;
|
|
background: none;
|
|
border: none;
|
|
font-size: .8rem;
|
|
}
|
|
|
|
/* --- Backup page: Encryption key --- */
|
|
.repo-encryption {
|
|
border-top: 1px solid var(--line);
|
|
padding-top: .75rem;
|
|
margin-bottom: .75rem;
|
|
}
|
|
.repo-encryption-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .5rem;
|
|
margin-top: .5rem;
|
|
margin-bottom: .5rem;
|
|
}
|
|
.restic-pw-field {
|
|
background: var(--bg-2);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
padding: .4rem .6rem;
|
|
color: var(--text-1);
|
|
font-size: .85rem;
|
|
width: 340px;
|
|
max-width: 100%;
|
|
}
|
|
.repo-encryption-warn {
|
|
font-size: .8rem;
|
|
color: var(--warn);
|
|
line-height: 1.4;
|
|
}
|
|
|
|
/* --- Backup page: Restore type info banners --- */
|
|
.restore-info {
|
|
padding: 0.5rem 0.75rem;
|
|
border-radius: var(--radius);
|
|
font-size: 0.85rem;
|
|
background: var(--blue-dim);
|
|
border: 1px solid var(--blue-dim);
|
|
color: var(--blue-bright);
|
|
}
|
|
.restore-info-partial {
|
|
background: var(--warn-dim);
|
|
border-color: var(--warn-dim);
|
|
color: var(--warn);
|
|
}
|
|
|
|
/* --- Backup page: Restore section --- */
|
|
.restore-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .75rem;
|
|
}
|
|
.restore-form-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .75rem;
|
|
}
|
|
.restore-label {
|
|
font-size: .85rem;
|
|
color: var(--text-2);
|
|
min-width: 110px;
|
|
}
|
|
.restore-select {
|
|
flex: 1;
|
|
max-width: 400px;
|
|
padding: .4rem .6rem;
|
|
background: var(--bg-2);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
color: var(--text-1);
|
|
font-size: .85rem;
|
|
font-family: inherit;
|
|
}
|
|
.restore-select option {
|
|
background: var(--bg-2);
|
|
color: var(--text-1);
|
|
}
|
|
.restore-paths {
|
|
padding: .5rem 0;
|
|
}
|
|
.restore-warning {
|
|
background: var(--crit-dim);
|
|
border: 1px solid var(--crit-dim);
|
|
border-radius: var(--radius);
|
|
padding: .75rem 1rem;
|
|
font-size: .85rem;
|
|
color: var(--crit);
|
|
line-height: 1.5;
|
|
}
|
|
.restore-confirm {
|
|
font-size: .85rem;
|
|
color: var(--text-2);
|
|
}
|
|
.restore-confirm label {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .5rem;
|
|
cursor: pointer;
|
|
}
|
|
.restore-confirm input[type="checkbox"] {
|
|
accent-color: var(--crit);
|
|
}
|
|
.restore-actions {
|
|
padding-top: .25rem;
|
|
}
|
|
|
|
/* --- Flash messages --- */
|
|
.flash {
|
|
padding: .75rem 1rem;
|
|
border-radius: var(--radius);
|
|
margin-bottom: 1rem;
|
|
font-size: .85rem;
|
|
border: 1px solid;
|
|
}
|
|
.flash-success {
|
|
background: var(--blue-dim);
|
|
color: var(--blue);
|
|
border-color: var(--blue-dim);
|
|
}
|
|
.flash-error {
|
|
background: var(--crit-dim);
|
|
color: var(--crit);
|
|
border-color: var(--crit-dim);
|
|
}
|
|
|
|
/* --- Settings page: Storage paths --- */
|
|
.storage-paths-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .75rem;
|
|
}
|
|
.storage-path-item {
|
|
background: var(--bg-2);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
padding: 1rem;
|
|
}
|
|
.storage-path-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
gap: 1rem;
|
|
margin-bottom: .5rem;
|
|
}
|
|
.storage-path-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .15rem;
|
|
}
|
|
.storage-path-label {
|
|
font-weight: 600;
|
|
font-size: .95rem;
|
|
}
|
|
.storage-path-path {
|
|
font-family: var(--font-data);
|
|
font-size: .8rem;
|
|
color: var(--text-3);
|
|
}
|
|
.storage-path-badges {
|
|
display: flex;
|
|
gap: .35rem;
|
|
flex-shrink: 0;
|
|
flex-wrap: wrap;
|
|
}
|
|
.storage-path-details {
|
|
margin: .5rem 0;
|
|
}
|
|
.storage-path-disk {
|
|
margin-bottom: .5rem;
|
|
}
|
|
.storage-path-fsinfo {
|
|
font-size: .75rem;
|
|
margin-bottom: .35rem;
|
|
}
|
|
.storage-path-meta {
|
|
font-size: .8rem;
|
|
color: var(--text-3);
|
|
}
|
|
.storage-path-actions {
|
|
display: flex;
|
|
gap: .5rem;
|
|
margin-top: .75rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
.btn-xs {
|
|
padding: .2rem .5rem;
|
|
font-size: .75rem;
|
|
border-radius: var(--radius);
|
|
}
|
|
.btn-ghost {
|
|
background: transparent;
|
|
border: none;
|
|
color: var(--text-3);
|
|
padding: .1rem .3rem;
|
|
}
|
|
.btn-ghost:hover {
|
|
color: var(--blue-bright);
|
|
}
|
|
.btn-danger-outline {
|
|
background: transparent;
|
|
border: 1px solid var(--crit-dim);
|
|
color: var(--crit);
|
|
}
|
|
.btn-danger-outline:hover {
|
|
background: var(--crit-dim);
|
|
border-color: var(--crit);
|
|
}
|
|
.storage-app-details summary {
|
|
font-size: .85rem;
|
|
}
|
|
.storage-app-list {
|
|
margin-top: .5rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .25rem;
|
|
}
|
|
.storage-app-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: .2rem .5rem;
|
|
font-size: .85rem;
|
|
}
|
|
.storage-app-link {
|
|
color: var(--blue-bright);
|
|
text-decoration: none;
|
|
}
|
|
.storage-app-link:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
/* Badge variants */
|
|
.badge-warn {
|
|
background: var(--warn-dim);
|
|
color: var(--warn);
|
|
}
|
|
.badge-error {
|
|
background: var(--crit-dim);
|
|
color: var(--crit);
|
|
}
|
|
|
|
/* Disconnected storage path card */
|
|
.storage-disconnected {
|
|
opacity: 0.75;
|
|
border-style: dashed;
|
|
}
|
|
.storage-decommissioned {
|
|
opacity: 0.6;
|
|
border-color: var(--line);
|
|
}
|
|
.storage-disconnected .storage-disconnected-info,
|
|
.storage-decommissioned .storage-disconnected-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .25rem;
|
|
}
|
|
.storage-stopped-apps-info {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: .25rem;
|
|
margin-bottom: .5rem;
|
|
}
|
|
|
|
/* Disconnected/unknown metric — empty track, no fill, no color (v2). */
|
|
.meter-empty .meter-fill { display: none; }
|
|
|
|
/* Task progress bar (storage init — not disk usage zone gradient) */
|
|
.progress-bar-task {
|
|
height: 8px;
|
|
background: var(--line);
|
|
border-radius: var(--radius);
|
|
overflow: hidden;
|
|
width: 100%;
|
|
}
|
|
|
|
.progress-bar-task .progress-fill {
|
|
height: 100%;
|
|
background: var(--blue);
|
|
border-radius: var(--radius);
|
|
transition: width 0.3s ease;
|
|
}
|
|
|
|
.storage-path-label-wrap {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .25rem;
|
|
}
|
|
.storage-add-details {
|
|
margin-top: .5rem;
|
|
}
|
|
.storage-add-details[open] summary {
|
|
margin-bottom: 1rem;
|
|
}
|
|
.storage-add-form {
|
|
margin-top: .75rem;
|
|
}
|
|
|
|
/* Responsive */
|
|
@media(max-width: 768px) {
|
|
.sidebar { width: 100%; height: auto; position: relative; border-right: none; border-bottom: 1px solid var(--line); }
|
|
.nav-links { display: flex; padding: 0; overflow-x: auto; }
|
|
.nav-links a { padding: .5rem 1rem; white-space: nowrap; }
|
|
.nav-links a.active { border-left: none; border-bottom: 2px solid var(--blue); }
|
|
.content { margin-left: 0; padding: 1rem; }
|
|
body { flex-direction: column; }
|
|
.app-row { flex-wrap: wrap; }
|
|
.app-row-actions { width: 100%; justify-content: flex-end; }
|
|
.stack-grid { grid-template-columns: 1fr; }
|
|
.stats-grid { grid-template-columns: repeat(3, 1fr); }
|
|
.deploy-info { flex-direction: column; }
|
|
.system-info-items { flex-direction: column; gap: 1rem; }
|
|
.charts-grid { grid-template-columns: 1fr; }
|
|
.container-charts-row { flex-direction: column; }
|
|
.sysinfo-grid { grid-template-columns: 1fr; }
|
|
.storage-overview-grid { grid-template-columns: 1fr; }
|
|
.restore-form-row { flex-direction: column; align-items: stretch; }
|
|
.restore-label { min-width: auto; }
|
|
.restore-select { max-width: 100%; }
|
|
}
|
|
|
|
/* ===================================================================
|
|
Storage Init Wizard & Migration UI
|
|
=================================================================== */
|
|
|
|
.disk-progress-steps {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .5rem;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.disk-step {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .75rem;
|
|
padding: .5rem .75rem;
|
|
border-radius: var(--radius);
|
|
color: var(--text-2);
|
|
font-size: .9rem;
|
|
background: var(--bg-0);
|
|
}
|
|
|
|
.disk-step-icon {
|
|
font-size: 1.1rem;
|
|
min-width: 1.4rem;
|
|
}
|
|
|
|
.disk-step.disk-step-done {
|
|
color: var(--text-1);
|
|
}
|
|
|
|
.disk-step.disk-step-active {
|
|
background: var(--blue-dim);
|
|
color: var(--blue-bright);
|
|
border: 1px solid var(--blue-dim);
|
|
}
|
|
|
|
.disk-progress-bar-wrap {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.disk-progress-bar-wrap .meter { flex: 1; }
|
|
|
|
.deploy-storage-info {
|
|
background: var(--bg-0);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
padding: 1.25rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.deploy-storage-info h4 {
|
|
font-size: .95rem;
|
|
font-weight: 600;
|
|
color: var(--text-2);
|
|
text-transform: uppercase;
|
|
letter-spacing: .05em;
|
|
margin-bottom: .75rem;
|
|
}
|
|
|
|
.storage-app-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .75rem;
|
|
padding: .35rem 0;
|
|
}
|
|
|
|
.storage-app-link {
|
|
color: var(--blue-bright);
|
|
text-decoration: none;
|
|
font-size: .9rem;
|
|
}
|
|
|
|
.storage-app-link:hover {
|
|
text-decoration: underline;
|
|
}
|
|
/* Stale data cleanup */
|
|
.deploy-stale-data {
|
|
background: var(--bg-1);
|
|
border: 1px solid var(--warn);
|
|
border-radius: var(--radius);
|
|
padding: 1.5rem;
|
|
margin-top: 1rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.deploy-stale-data h4 {
|
|
margin: 0 0 0.5rem 0;
|
|
color: var(--warn);
|
|
}
|
|
|
|
.stale-data-item {
|
|
padding: 1rem;
|
|
background: var(--warn-dim);
|
|
border-radius: var(--radius);
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
|
|
.stale-data-item:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
/* Red-filled danger buttons inside modal confirmation dialogs */
|
|
.modal-actions .btn-danger {
|
|
background: var(--crit);
|
|
color: white;
|
|
border-color: var(--crit);
|
|
}
|
|
.modal-actions .btn-danger:hover {
|
|
opacity: 0.85;
|
|
background: var(--crit);
|
|
color: white;
|
|
}
|
|
|
|
/* Cross-drive backup card on deploy page */
|
|
.deploy-cross-drive {
|
|
background: var(--bg-2);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
padding: 1.5rem;
|
|
margin-top: 1rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.deploy-cross-drive h4 {
|
|
margin: 0 0 1rem 0;
|
|
color: var(--text-1);
|
|
}
|
|
|
|
.cross-drive-nightly {
|
|
margin-bottom: .5rem;
|
|
}
|
|
|
|
/* Cross-drive list on backup page */
|
|
.cross-drive-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .5rem;
|
|
}
|
|
|
|
.cross-drive-item {
|
|
background: var(--bg-2);
|
|
border-radius: var(--radius);
|
|
padding: .75rem 1rem;
|
|
}
|
|
|
|
.cross-drive-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
flex-wrap: wrap;
|
|
gap: .5rem;
|
|
}
|
|
|
|
.cross-drive-name {
|
|
font-weight: 500;
|
|
color: var(--text-1);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.cross-drive-name:hover {
|
|
text-decoration: underline;
|
|
color: var(--blue);
|
|
}
|
|
|
|
.cross-drive-meta {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .4rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.cross-drive-actions {
|
|
display: flex;
|
|
gap: .5rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
/* Info tooltip (i icon with hover popup) */
|
|
.info-tooltip {
|
|
position: relative;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
margin-left: .35rem;
|
|
cursor: help;
|
|
}
|
|
|
|
.info-icon {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 16px;
|
|
height: 16px;
|
|
border-radius: 50%;
|
|
border: 1px solid var(--text-3);
|
|
color: var(--text-3);
|
|
font-size: .65rem;
|
|
font-weight: 700;
|
|
font-style: italic;
|
|
font-family: Georgia, serif;
|
|
line-height: 1;
|
|
}
|
|
|
|
.info-tooltip-text {
|
|
display: none;
|
|
position: absolute;
|
|
bottom: calc(100% + 8px);
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
width: 320px;
|
|
padding: .75rem 1rem;
|
|
background: var(--bg-0);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
font-size: .8rem;
|
|
font-weight: 400;
|
|
line-height: 1.5;
|
|
color: var(--text-2);
|
|
z-index: 100;
|
|
white-space: normal;
|
|
}
|
|
|
|
.info-tooltip:hover .info-tooltip-text,
|
|
.info-tooltip:focus .info-tooltip-text,
|
|
.info-tooltip:focus-within .info-tooltip-text {
|
|
display: block;
|
|
}
|
|
|
|
.info-tooltip-text::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 100%;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
border: 6px solid transparent;
|
|
border-top-color: var(--line);
|
|
}
|
|
|
|
/* Nightly backup status indicator (non-interactive) */
|
|
.cross-drive-nightly-status {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .5rem;
|
|
}
|
|
|
|
.nightly-status-indicator {
|
|
display: inline-block;
|
|
width: 10px;
|
|
height: 10px;
|
|
border-radius: 50%;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.nightly-enabled {
|
|
background: var(--blue);
|
|
}
|
|
|
|
.nightly-disabled {
|
|
background: var(--text-3);
|
|
opacity: 0.5;
|
|
}
|
|
|
|
/* meta-badge-fail */
|
|
.meta-badge-fail {
|
|
background: var(--crit-dim);
|
|
color: var(--crit);
|
|
}
|
|
|
|
/* ─── Unified App Backup Rows ──────────────────────────────────────── */
|
|
.app-backup-row {
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
margin-bottom: .5rem;
|
|
background: var(--bg-2);
|
|
overflow: hidden;
|
|
}
|
|
.app-backup-row[data-status="red"] { border-left: 3px solid var(--crit); }
|
|
.app-backup-row[data-status="yellow"] { border-left: 3px solid var(--warn); }
|
|
.app-backup-row[data-status="green"] { border-left: 3px solid var(--blue); }
|
|
.app-backup-row[data-status="auto"] { border-left: 3px solid var(--text-3); }
|
|
|
|
.app-backup-row-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .75rem;
|
|
padding: .5rem 1rem;
|
|
min-height: 44px; /* same compact height as the shared .app-row */
|
|
cursor: pointer;
|
|
user-select: none;
|
|
}
|
|
.app-backup-row-header:hover {
|
|
background: var(--bg-hover, rgba(255,255,255,0.03));
|
|
}
|
|
.app-backup-row-name {
|
|
font-weight: 500;
|
|
font-size: .9rem;
|
|
flex: 1;
|
|
}
|
|
.app-backup-row-meta {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .5rem;
|
|
}
|
|
.expand-icon {
|
|
color: var(--text-3);
|
|
font-size: .75rem;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* Status dot */
|
|
.status-dot {
|
|
width: 10px;
|
|
height: 10px;
|
|
border-radius: 50%;
|
|
flex-shrink: 0;
|
|
display: inline-block;
|
|
}
|
|
.status-dot.status-green { background: var(--blue); }
|
|
.status-dot.status-yellow { background: var(--warn); }
|
|
.status-dot.status-red { background: var(--crit); }
|
|
.status-dot.status-auto { background: var(--text-3); opacity: .6; }
|
|
|
|
/* Expanded detail */
|
|
.app-backup-row-detail {
|
|
border-top: 1px solid var(--line);
|
|
padding: .75rem 1rem;
|
|
}
|
|
.backup-layers {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .4rem;
|
|
}
|
|
.backup-layer-row {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: .4rem;
|
|
font-size: .85rem;
|
|
padding: .2rem 0;
|
|
}
|
|
.backup-layer-row.layer-row-na {
|
|
opacity: .55;
|
|
}
|
|
.layer-label {
|
|
font-weight: 500;
|
|
min-width: 14rem;
|
|
color: var(--text-2);
|
|
}
|
|
.layer-badge {
|
|
background: var(--blue-dim);
|
|
color: var(--blue-bright);
|
|
padding: .1rem .45rem;
|
|
border-radius: var(--radius);
|
|
font-size: .75rem;
|
|
}
|
|
.layer-na {
|
|
color: var(--text-3);
|
|
font-style: italic;
|
|
font-size: .82rem;
|
|
}
|
|
.layer-method {
|
|
color: var(--text-2);
|
|
font-size: .82rem;
|
|
}
|
|
.layer-dest {
|
|
color: var(--text-2);
|
|
font-size: .82rem;
|
|
}
|
|
.layer-schedule {
|
|
color: var(--text-3);
|
|
font-size: .8rem;
|
|
}
|
|
.layer-last {
|
|
color: var(--text-3);
|
|
font-size: .8rem;
|
|
margin-left: .25rem;
|
|
}
|
|
.layer-auto-ok {
|
|
color: var(--blue);
|
|
font-size: .85rem;
|
|
margin-right: .5rem;
|
|
}
|
|
.layer-unconfigured {
|
|
color: var(--warn);
|
|
font-weight: 500;
|
|
font-size: .85rem;
|
|
}
|
|
.layer-actions {
|
|
display: flex;
|
|
gap: .35rem;
|
|
margin-left: auto;
|
|
}
|
|
.btn-xs {
|
|
padding: .15rem .5rem;
|
|
font-size: .75rem;
|
|
border-radius: var(--radius);
|
|
}
|
|
.layer-warnings {
|
|
margin-top: .5rem;
|
|
padding-top: .5rem;
|
|
border-top: 1px solid var(--line);
|
|
}
|
|
.backup-layer-warning {
|
|
font-size: .82rem;
|
|
color: var(--warn);
|
|
padding: .2rem 0;
|
|
}
|
|
.text-ok { color: var(--blue); }
|
|
.text-error { color: var(--crit); }
|
|
.text-muted { color: var(--text-3); }
|
|
.tier-label {
|
|
font-weight: 600;
|
|
min-width: 5rem;
|
|
color: var(--text-1);
|
|
}
|
|
.tier-location {
|
|
color: var(--text-3);
|
|
font-size: .85rem;
|
|
}
|
|
.tier-contents {
|
|
color: var(--text-3);
|
|
font-size: .8rem;
|
|
font-style: italic;
|
|
margin-left: .25rem;
|
|
}
|
|
.tier-size {
|
|
color: var(--text-3);
|
|
font-size: .8rem;
|
|
margin-left: .25rem;
|
|
}
|
|
.tier-browsable {
|
|
font-size: .75rem;
|
|
margin-left: .15rem;
|
|
cursor: help;
|
|
}
|
|
|
|
/* ── Debug page ────────────────────────────────────────── */
|
|
.debug-banner {
|
|
background: var(--warn-dim);
|
|
border: 1px solid var(--warn-dim);
|
|
border-radius: var(--radius);
|
|
padding: 0.75rem 1rem;
|
|
margin-bottom: 1.5rem;
|
|
color: var(--warn);
|
|
font-size: 0.85rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
.debug-banner strong { color: var(--warn); }
|
|
|
|
.debug-section {
|
|
background: var(--bg-1);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
margin-bottom: 0.75rem;
|
|
overflow: hidden;
|
|
}
|
|
.debug-section-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 0.75rem 1rem;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
transition: background .15s;
|
|
}
|
|
.debug-section-header:hover { background: rgba(255,255,255,0.03); }
|
|
.debug-section-header h3 {
|
|
font-size: 0.95rem;
|
|
font-weight: 600;
|
|
color: var(--text-1);
|
|
margin: 0;
|
|
}
|
|
.debug-section-toggle {
|
|
color: var(--text-3);
|
|
font-size: 0.8rem;
|
|
transition: transform .2s;
|
|
}
|
|
.debug-section.open .debug-section-toggle { transform: rotate(180deg); }
|
|
.debug-section-body {
|
|
display: none;
|
|
padding: 0 1rem 1rem;
|
|
border-top: 1px solid var(--line);
|
|
}
|
|
.debug-section.open .debug-section-body { display: block; }
|
|
|
|
.debug-actions {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.5rem;
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
.debug-actions .btn { font-size: 0.8rem; padding: 0.35rem 0.75rem; }
|
|
|
|
.debug-result {
|
|
font-size: 0.8rem;
|
|
padding: 0.5rem 0.75rem;
|
|
border-radius: var(--radius);
|
|
margin-top: 0.5rem;
|
|
font-family: var(--font-data);
|
|
}
|
|
.debug-result-ok {
|
|
color: var(--blue);
|
|
background: var(--blue-dim);
|
|
border: 1px solid var(--blue-dim);
|
|
}
|
|
.debug-result-error {
|
|
color: var(--crit);
|
|
background: var(--crit-dim);
|
|
border: 1px solid var(--crit-dim);
|
|
}
|
|
.debug-result-pending {
|
|
color: var(--warn);
|
|
background: var(--warn-dim);
|
|
border: 1px solid var(--warn-dim);
|
|
}
|
|
|
|
.debug-kv-grid {
|
|
display: grid;
|
|
grid-template-columns: auto 1fr;
|
|
gap: 0.25rem 1rem;
|
|
font-size: 0.85rem;
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
.debug-kv-grid dt { color: var(--text-3); font-weight: 500; white-space: nowrap; }
|
|
.debug-kv-grid dd { color: var(--text-1); margin: 0; }
|
|
|
|
.debug-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 0.8rem;
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
.debug-table th {
|
|
text-align: left;
|
|
color: var(--text-3);
|
|
font-weight: 600;
|
|
font-size: 0.75rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
padding: 0.35rem 0.5rem;
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
.debug-table td {
|
|
padding: 0.35rem 0.5rem;
|
|
color: var(--text-1);
|
|
border-bottom: 1px solid var(--line-soft);
|
|
}
|
|
.debug-table tr:last-child td { border-bottom: none; }
|
|
|
|
.debug-log-viewer {
|
|
background: var(--bg-0);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
padding: 0.5rem;
|
|
max-height: 400px;
|
|
overflow-y: auto;
|
|
font-family: var(--font-data);
|
|
font-size: 0.75rem;
|
|
line-height: 1.5;
|
|
}
|
|
.debug-log-entry { white-space: pre-wrap; word-break: break-all; }
|
|
.debug-log-debug { color: var(--text-3); }
|
|
.debug-log-info { color: var(--text-1); }
|
|
.debug-log-warn { color: var(--warn); }
|
|
.debug-log-error { color: var(--crit); }
|
|
|
|
.debug-log-controls {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
margin-bottom: 0.5rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
.debug-log-controls .btn {
|
|
font-size: 0.75rem;
|
|
padding: 0.25rem 0.5rem;
|
|
}
|
|
.debug-log-controls .btn.active {
|
|
background: var(--blue);
|
|
color: #fff;
|
|
}
|
|
.debug-log-count {
|
|
font-size: 0.75rem;
|
|
color: var(--text-3);
|
|
margin-left: auto;
|
|
}
|
|
|
|
.debug-confirm-input {
|
|
background: var(--bg-0);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
padding: 0.4rem 0.75rem;
|
|
color: var(--text-1);
|
|
font-family: var(--font-data);
|
|
font-size: 0.85rem;
|
|
width: 120px;
|
|
}
|
|
.debug-confirm-input:focus {
|
|
outline: none;
|
|
border-color: var(--crit);
|
|
}
|
|
|
|
/* Debug page: red-filled danger buttons for destructive debug actions */
|
|
.debug-section .btn-danger {
|
|
background: var(--crit);
|
|
color: #fff;
|
|
border: none;
|
|
border-radius: var(--radius);
|
|
padding: 0.4rem 0.85rem;
|
|
cursor: pointer;
|
|
font-size: 0.85rem;
|
|
font-weight: 600;
|
|
transition: background .15s, opacity .15s;
|
|
}
|
|
.debug-section .btn-danger:hover { background: var(--crit); }
|
|
.debug-section .btn-danger:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
|
|
.debug-spinner {
|
|
display: inline-block;
|
|
width: 14px;
|
|
height: 14px;
|
|
border: 2px solid var(--text-3);
|
|
border-top-color: var(--blue);
|
|
border-radius: 50%;
|
|
animation: debug-spin 0.6s linear infinite;
|
|
vertical-align: middle;
|
|
margin-right: 0.3rem;
|
|
}
|
|
@keyframes debug-spin { to { transform: rotate(360deg); } }
|
|
|
|
/* --- Geo-restriction UI --- */
|
|
.geo-country-selector { position: relative; }
|
|
.geo-selected-tags { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.5rem; }
|
|
.geo-tag {
|
|
display: inline-flex; align-items: center; gap: 0.3rem;
|
|
background: var(--blue-dim); color: var(--blue-bright);
|
|
padding: 0.25rem 0.55rem; border-radius: var(--radius); font-size: 0.85rem;
|
|
white-space: nowrap;
|
|
}
|
|
.geo-tag-hu { background: var(--blue-dim); color: var(--blue); }
|
|
.geo-tag-sm { font-size: 0.75rem; padding: 0.15rem 0.4rem; }
|
|
.geo-tag-remove { cursor: pointer; opacity: 0.7; font-size: 1.1em; line-height: 1; }
|
|
.geo-tag-remove:hover { opacity: 1; }
|
|
.geo-country-list {
|
|
position: absolute; z-index: 10; background: var(--bg-1);
|
|
border: 1px solid var(--line); border-radius: var(--radius);
|
|
max-height: 220px; overflow-y: auto; width: 100%; margin-top: 2px;
|
|
display: none;
|
|
}
|
|
.geo-country-option {
|
|
padding: 0.4rem 0.75rem; cursor: pointer; font-size: 0.9rem;
|
|
color: var(--text-1);
|
|
}
|
|
.geo-country-option:hover { background: var(--blue-dim); }
|
|
.geo-country-option small { color: var(--text-3); }
|
|
.geo-app-override-row {
|
|
display: flex; align-items: center; gap: 0.5rem;
|
|
padding: 0.5rem 0; border-bottom: 1px solid var(--line);
|
|
flex-wrap: wrap;
|
|
}
|
|
.geo-app-override-row strong { min-width: 120px; color: var(--text-1); }
|
|
.geo-edit-overlay {
|
|
background: var(--bg-2); border: 1px solid var(--line);
|
|
border-radius: var(--radius); padding: 1rem; margin-top: 0.5rem;
|
|
}
|
|
.geo-edit-grid {
|
|
display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
gap: 0.2rem; max-height: 250px; overflow-y: auto; margin-top: 0.5rem;
|
|
}
|
|
.geo-edit-item { font-size: 0.85rem; cursor: pointer; padding: 0.15rem 0; color: var(--text-1); }
|
|
.geo-edit-item input { margin-right: 0.3rem; }
|
|
.btn-danger-outline {
|
|
background: transparent; color: var(--crit); border: 1px solid var(--crit);
|
|
border-radius: var(--radius); padding: 0.2rem 0.5rem; cursor: pointer; font-size: 0.8rem;
|
|
}
|
|
.btn-danger-outline:hover { background: var(--crit-dim); }
|
|
|
|
/* ============================================================================
|
|
Agent drive lists (overview + init/attach selector) — storage authz redesign.
|
|
Reuses the existing card/badge/bar tokens; no new design system.
|
|
============================================================================ */
|
|
.drive-list { display: flex; flex-direction: column; gap: .6rem; margin-top: .25rem; }
|
|
.drive-card {
|
|
background: var(--bg-1);
|
|
border: 1px solid var(--line);
|
|
border-left: 4px solid var(--text-3);
|
|
border-radius: var(--radius);
|
|
padding: .85rem 1rem;
|
|
display: flex; flex-direction: column; gap: .55rem;
|
|
}
|
|
.drive-card.role-user-data { border-left-color: var(--blue); }
|
|
.drive-card.role-system,
|
|
.drive-card.role-backup { border-left-color: var(--warn); }
|
|
.drive-card.is-selectable { cursor: pointer; transition: border-color .15s, background .15s; }
|
|
.drive-card.is-selectable:hover { border-color: var(--blue-bright); }
|
|
.drive-card.is-picked { border-color: var(--blue-bright); background: var(--blue-dim); }
|
|
.drive-card-top { display: flex; align-items: flex-start; justify-content: space-between; gap: .75rem; }
|
|
.drive-id { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
|
|
.drive-name { font-size: .95rem; font-weight: 600; color: var(--text-1); }
|
|
.drive-sub {
|
|
font-size: .78rem; color: var(--text-3);
|
|
font-family: var(--font-data); word-break: break-all;
|
|
}
|
|
.drive-badges { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; justify-content: flex-end; }
|
|
.drive-cap { display: flex; flex-direction: column; gap: .3rem; }
|
|
.drive-cap .meter-track { height: 3px; }
|
|
.drive-cap-label { font-size: .75rem; color: var(--text-3); font-family: var(--font-data); }
|
|
.drive-actions { display: flex; flex-wrap: wrap; gap: .4rem; }
|
|
.drive-select { display: flex; align-items: center; gap: .5rem; }
|
|
|
|
/* badges missing from the global sheet */
|
|
.badge-ok { background: var(--blue-dim); color: var(--blue); }
|
|
.badge-neutral { background: var(--bg-2); color: var(--text-2); }
|
|
.badge-muted { background: var(--bg-2); color: var(--text-3); }
|
|
.badge-info { background: var(--blue-dim); color: var(--blue-bright); }
|
|
/* Backup-page tier divider between the whole-guest section and the per-app section. */
|
|
.backup-tier-divider {
|
|
margin: 2rem 0 0.25rem; padding-top: 1.25rem;
|
|
border-top: 1px solid var(--line); font-size: 1.05rem;
|
|
}
|
|
/* Per-card storage purpose description + the tiering one-liner above the drive list. */
|
|
.drive-purpose { font-size: .8rem; color: var(--text-2); line-height: 1.4; }
|
|
.drive-tiering-note {
|
|
font-size: .8rem; color: var(--text-2); line-height: 1.4;
|
|
margin: 0 0 .75rem; padding: .5rem .75rem;
|
|
background: var(--blue-dim); border-left: 3px solid var(--blue); border-radius: var(--radius);
|
|
}
|
|
span.mono, .mono { font-family: var(--font-data); }
|
|
|
|
/* Type-to-confirm modal (destructive user-data eject/wipe) */
|
|
.confirm-overlay {
|
|
position: fixed; inset: 0; background: rgba(0,0,0,.6);
|
|
display: flex; align-items: center; justify-content: center; z-index: 1000; padding: 1rem;
|
|
}
|
|
.confirm-box {
|
|
background: var(--bg-1); border: 1px solid var(--line); border-radius: var(--radius);
|
|
max-width: 480px; width: 100%; padding: 1.4rem;
|
|
}
|
|
.confirm-box h3 { margin: 0 0 .75rem; font-size: 1.05rem; }
|
|
.confirm-box .confirm-apps { margin: .5rem 0; padding-left: 1.1rem; }
|
|
.confirm-box .confirm-apps li { margin: .15rem 0; }
|
|
.confirm-box .confirm-input { margin: .9rem 0 .4rem; }
|
|
.confirm-box .form-actions { display: flex; gap: .6rem; margin-top: 1rem; }
|
|
|
|
/* ===================================================================
|
|
Design system v2 primitives (TASK-D0)
|
|
=================================================================== */
|
|
|
|
/* Panel — flat surface: bg-1, hairline border, 2px radius, no shadow. */
|
|
.panel {
|
|
background: var(--bg-1);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
}
|
|
|
|
/* Boxless section header: h3 + right-aligned muted hint over a hairline. */
|
|
.section-h {
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
gap: 1rem;
|
|
border-bottom: 1px solid var(--line);
|
|
padding-bottom: .5rem;
|
|
margin: 1.75rem 0 1rem;
|
|
}
|
|
.section-h h3 { margin-bottom: 0; }
|
|
.section-h .hint {
|
|
font-size: .78rem;
|
|
color: var(--text-3);
|
|
}
|
|
|
|
/* List — one panel, rows separated by soft hairlines, 2px left state edge. */
|
|
.list {
|
|
background: var(--bg-1);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
}
|
|
.list .row {
|
|
position: relative;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
padding: .85rem 1.25rem;
|
|
border-top: 1px solid var(--line-soft);
|
|
}
|
|
.list .row:first-child { border-top: none; }
|
|
.list .row::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: 0; top: 0; bottom: 0;
|
|
width: 2px;
|
|
background: transparent;
|
|
}
|
|
.list .row.state-run::before,
|
|
.list .row.state-progress::before { background: var(--blue); }
|
|
.list .row.state-warn::before { background: var(--warn); }
|
|
|
|
/* Spinning progress icon (deploy steps, async tasks) */
|
|
.ico-spin { animation: ico-spin 1s linear infinite; }
|
|
@keyframes ico-spin { to { transform: rotate(360deg); } }
|
|
@media (prefers-reduced-motion: reduce) { .ico-spin { animation: none; } }
|
|
|
|
/* Login page — two-tone heading (H1 last word in blue-bright) */
|
|
.login-title {
|
|
font-size: 1.35rem;
|
|
font-weight: 700;
|
|
margin-bottom: .25rem;
|
|
}
|
|
.login-title .title-accent {
|
|
color: var(--blue-bright);
|
|
}
|
|
|
|
/* Sidebar settings group (D1) — group label + indented sub-links. */
|
|
.nav-group-label {
|
|
padding: .75rem 1.5rem .25rem;
|
|
font-size: .68rem;
|
|
font-weight: 700;
|
|
letter-spacing: .1em;
|
|
text-transform: uppercase;
|
|
color: var(--text-3);
|
|
}
|
|
.nav-links-sub {
|
|
padding: 0 0 .5rem;
|
|
flex: none;
|
|
}
|
|
.nav-links-sub a {
|
|
padding: .5rem 1.5rem .5rem 1.75rem;
|
|
font-size: .88rem;
|
|
}
|
|
|
|
/* Nested sub-links under a main-nav item (Tárhely → Meghajtók / Hálózati tárhely). */
|
|
.nav-links-nested {
|
|
padding: 0;
|
|
list-style: none;
|
|
}
|
|
.nav-links-nested a {
|
|
padding: .4rem 1.5rem .4rem 3.1rem;
|
|
font-size: .85rem;
|
|
}
|
|
.nav-links-nested a.active {
|
|
border-left: 3px solid var(--blue);
|
|
}
|
|
|
|
/* ============================================================================
|
|
Nav polish (v0.146.0) — scrollbars + collapsible sidebar groups.
|
|
============================================================================ */
|
|
|
|
/* Scrollbars. The platform default is a light, chunky bar that reads as a bright
|
|
stripe against the navy and competes with the content it is scrolling. Thin +
|
|
hairline-coloured puts it back in the background where it belongs. Firefox gets
|
|
the standard two-value form; WebKit/Blink the pseudo-elements. Both are declared
|
|
because neither alone covers the browsers customers actually use. */
|
|
* {
|
|
scrollbar-width: thin;
|
|
scrollbar-color: var(--line) transparent;
|
|
}
|
|
*::-webkit-scrollbar { width: 8px; height: 8px; }
|
|
*::-webkit-scrollbar-track { background: transparent; }
|
|
*::-webkit-scrollbar-thumb {
|
|
background: var(--line);
|
|
border-radius: var(--radius);
|
|
}
|
|
*::-webkit-scrollbar-thumb:hover { background: var(--text-3); }
|
|
/* Track takes the surrounding panel's own background, so the gutter never shows
|
|
through as a lighter channel on the two surfaces that actually scroll. */
|
|
.sidebar { scrollbar-color: var(--line) var(--bg-2); }
|
|
.sidebar::-webkit-scrollbar-track { background: var(--bg-2); }
|
|
html { scrollbar-color: var(--line) var(--bg-0); }
|
|
html::-webkit-scrollbar-track { background: var(--bg-0); }
|
|
|
|
/* Collapsible nav groups. The row is a real <button> (keyboard + AT reachable for
|
|
free); every group's own landing page is also its first sub-item, so nothing
|
|
became unreachable when the header stopped being a link.
|
|
|
|
The open/close uses grid-template-rows 0fr -> 1fr rather than max-height: it
|
|
animates to the content's REAL height, so there is no magic number to drift and
|
|
no jump when a group's item count changes. */
|
|
.nav-group {
|
|
display: grid;
|
|
grid-template-rows: auto 0fr;
|
|
transition: grid-template-rows .18s ease;
|
|
}
|
|
.nav-group.is-open { grid-template-rows: auto 1fr; }
|
|
.nav-group > .nav-links-nested {
|
|
overflow: hidden;
|
|
min-height: 0; /* required, or the grid row refuses to collapse below content height */
|
|
}
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.nav-group { transition: none; }
|
|
}
|
|
|
|
/* The toggle inherits the nav link's look exactly — it must not read as a form
|
|
control sitting in a list of links. */
|
|
.nav-group-toggle {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .6rem;
|
|
width: 100%;
|
|
padding: .75rem 1.5rem;
|
|
background: none;
|
|
border: none;
|
|
border-left: 3px solid transparent; /* reserved so .active adds no width shift */
|
|
color: var(--text-2);
|
|
font-family: inherit;
|
|
font-size: .95rem;
|
|
font-weight: 500;
|
|
text-align: left;
|
|
cursor: pointer;
|
|
transition: color 0.2s ease, background 0.2s ease;
|
|
}
|
|
.nav-group-toggle:hover {
|
|
color: var(--blue-bright);
|
|
background: var(--blue-dim);
|
|
}
|
|
.nav-group-toggle.active {
|
|
color: var(--blue-bright);
|
|
background: var(--blue-dim);
|
|
border-left-color: var(--blue);
|
|
}
|
|
.nav-group-toggle:focus-visible {
|
|
outline: 2px solid var(--blue-bright);
|
|
outline-offset: -2px;
|
|
}
|
|
.nav-chevron {
|
|
margin-left: auto;
|
|
width: 14px;
|
|
height: 14px;
|
|
color: var(--text-3);
|
|
transition: transform .18s ease;
|
|
}
|
|
.nav-group.is-open .nav-chevron { transform: rotate(180deg); }
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.nav-chevron { transition: none; }
|
|
}
|
|
|
|
/* Unified drive view enrichment slot — breathing room between the agent tag row,
|
|
the agent action row, and the registry action row below. */
|
|
.drive-agent-extra {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .6rem;
|
|
margin-top: .6rem;
|
|
}
|
|
.drive-agent-extra:empty { display: none; }
|
|
.drive-agent-extra .metarows {
|
|
margin: 0;
|
|
gap: .3rem .75rem;
|
|
}
|
|
.drive-agent-extra .drive-actions {
|
|
margin: 0;
|
|
}
|
|
|
|
/* Inline two-step confirm (drill F-11) — the in-place replacement for native confirm() */
|
|
.inline-confirm { display: inline-flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
|
|
.inline-confirm-q { font-size: .8rem; color: var(--warn); }
|