Files
felhom-controller/controller/internal/web/templates/style.css
T
admin f908eee2a3
gates / gates (push) Failing after 47s
v0.316.1: the settings tab's reused form markup loses the install page's boxes
The fields on Beallitasok are the install wizard's markup, which carries that page's card around
the whole form and one around every generated value. On a TAB those are sections, so the boxes come
off; the input itself is still a field, which is what tells the household it holds a value. Scoped
to .app-section so the install page — same column, its own form — is untouched.

Found in a browser by asking the page which elements still paint a background, rather than reading
the markup and guessing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117kRTSgs3rJWUFGxyoWN6Y
2026-10-15 20:45:57 +02:00

3914 lines
101 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: 0 auto 0.25rem;
}
.login-logo {
width: 200px;
height: auto;
display: block;
margin: 0 auto 0.5rem;
}
.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); }
/* i18n (v0.254.0): the language switch is a GLOBE. Two text links wrapped in the sidebar footer and
asked the reader to recognise „Magyar"/„English" as links; a globe is the one symbol every web user
already reads as "language", so nobody has to read Hungarian to find their way out of Hungarian.
<details>/<summary> — a menu with no script: it opens on click and on Enter, and a screen reader
announces it. Language names inside are shown in their OWN language, never translated. */
.lang-globe { position: relative; margin: 0; }
.lang-globe-btn { list-style: none; display: inline-flex; align-items: center; color: var(--text-3); cursor: pointer; padding: .15rem; border-radius: var(--radius); }
.lang-globe-btn::-webkit-details-marker { display: none; }
.lang-globe-btn:hover, .lang-globe[open] .lang-globe-btn { color: var(--blue-bright); }
.lang-globe-menu { position: absolute; bottom: calc(100% + .35rem); left: 50%; transform: translateX(-50%); margin: 0; padding: .25rem; list-style: none; min-width: 7.5rem; background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius); z-index: 20; }
.lang-globe-menu li { margin: 0; }
.lang-globe-menu form { margin: 0; }
.lang-globe-item { display: block; width: 100%; text-align: left; background: none; border: none; color: var(--text-2); font: inherit; font-size: .8rem; padding: .3rem .5rem; border-radius: var(--radius); cursor: pointer; white-space: nowrap; }
.lang-globe-item:hover { color: var(--blue-bright); }
.lang-globe-item.current { color: var(--text-1); font-weight: 600; }
.lang-globe-item.current::after { content: " \2713"; }
.logout-link { color: var(--text-3); text-decoration: none; transition: color 0.2s ease; }
.logout-link:hover { color: var(--blue-bright); }
/* Mobile chrome (v0.166.0) — hidden by default so desktop (>768px) stays pixel-identical; the
≤768px block below turns the top bar on and converts the sidebar into an off-canvas drawer. */
.mobile-topbar { display: none; }
.nav-backdrop { display: none; }
.nav-burger {
display: flex;
align-items: center;
padding: .375rem;
background: none;
border: none;
color: var(--text-2);
cursor: pointer;
transition: color 0.2s ease;
}
.nav-burger:hover { color: var(--blue-bright); }
.nav-burger:focus-visible {
outline: 2px solid var(--blue-bright);
outline-offset: -2px;
}
.nav-burger .ico { width: 24px; height: 24px; }
/* 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-field-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); }
/* Card header, the same on every card (2026-10-08): row 1 = logo + name (+ the address under it), row 2 =
the tags, left-aligned and wrapping. The tags used to share one space-between row with the name and
covered it once an installed app had two of them; the logo was centred on the name block, so a card
with an address carried it lower. Pinned by TestStackCardHeaderLayout. */
.stack-detail-header {
display: flex;
flex-direction: column;
gap: .6rem;
margin-bottom: .75rem;
}
.stack-title-row {
display: flex;
align-items: flex-start;
gap: .75rem;
min-width: 0;
}
.stack-title-text {
flex: 1;
min-width: 0;
}
.stack-title-text h3 { margin-bottom: .25rem; overflow-wrap: anywhere; }
.stack-title-text .route-unpublished { white-space: normal; }
.stack-tags {
display: flex;
flex-wrap: wrap;
gap: .4rem;
}
.subdomain-link {
display: flex;
align-items: baseline;
gap: .3rem;
max-width: 100%;
font-size: .8rem;
color: var(--blue-bright);
text-decoration: none;
transition: color 0.2s ease;
white-space: nowrap;
}
.subdomain-text {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
}
.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; }
/* The link takes the banner's own colour (it had none and rendered browser-default blue, 2026-10-08). */
.alert-link { margin-left: auto; white-space: nowrap; color: inherit; text-decoration: none; }
.alert-link:hover { text-decoration: underline; }
/* 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); }
.empty-state-link { color: var(--blue-bright); }
/* Indítópult (launcher) — a grid of large tappable app tiles. Each tile has a deterministic
per-app background (tileColor / brand_color override), the white monogram fallback UNDER the
logo (revealed when the logo fails to load), and the app name below. */
.launch-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
gap: 1.25rem;
margin-top: .5rem;
}
.launch-cell {
display: flex;
flex-direction: column;
align-items: center;
gap: .5rem;
text-decoration: none;
color: var(--text-1);
}
.launch-tile {
position: relative;
width: 100%;
aspect-ratio: 1 / 1;
border-radius: var(--radius);
border: 1px solid var(--line);
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
transition: transform .12s ease, border-color .12s ease;
}
.launch-cell:hover .launch-tile {
transform: translateY(-2px);
border-color: var(--blue);
}
/* The monogram is the logo-less fallback ONLY: hidden by default, revealed when the tile's <img>
chain fails (onerror adds .launch-tile--noimg). Otherwise a transparent white glyph would show
the letter bleeding through its gaps on every tile (v0.163.1 live finding). */
.launch-mono {
display: none;
position: absolute;
inset: 0;
align-items: center;
justify-content: center;
color: #fff;
font-family: var(--font-ui);
font-size: 2.4rem;
font-weight: 600;
line-height: 1;
user-select: none;
}
.launch-tile--noimg .launch-mono { display: flex; }
.launch-logo {
position: relative;
width: 58%;
height: 58%;
object-fit: contain;
}
.launch-name {
max-width: 100%;
font-size: .85rem;
color: var(--text-1);
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.launch-cell--off { cursor: default; }
.launch-tile--off { opacity: .4; }
.launch-cell--off .launch-name { color: var(--text-3); }
.launch-off-label { font-size: .8rem; color: var(--text-3); text-align: center; }
/* Launcher share modal (v0.165.0) */
.share-open-btn { margin-left: auto; }
.share-lede { color: var(--text-2); font-size: .9rem; margin-bottom: 1rem; }
.share-field { margin-bottom: 1rem; }
.share-label { display: block; font-size: .85rem; color: var(--text-2); margin-bottom: .35rem; }
.share-note { color: var(--text-2); font-size: .9rem; }
.share-link-row { display: flex; gap: .5rem; align-items: center; }
.share-link-row input { flex: 1; min-width: 0; }
.share-qr { display: flex; flex-direction: column; align-items: center; gap: .35rem; margin-bottom: 1rem; }
.share-qr img { border: 1px solid var(--line); border-radius: var(--radius); background: #fff; padding: .35rem; }
.share-qr-hint { color: var(--text-3); font-size: .8rem; }
.share-actions { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: .5rem; }
/* Standalone guest launcher + password gate (v0.165.0) — no sidebar/nav */
.guest-content { max-width: 960px; margin: 0 auto; padding: 2rem 1.25rem; }
.guest-gate-body { display: flex; align-items: center; justify-content: center; min-height: 100vh; }
.guest-gate { width: 100%; display: flex; justify-content: center; padding: 1.25rem; }
.guest-gate-card { width: 100%; max-width: 360px; background: var(--bg-1); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.75rem; text-align: center; }
.guest-gate-card form { display: flex; flex-direction: column; gap: .75rem; margin-top: 1rem; }
.gate-error { color: var(--crit); font-size: .9rem; margin-top: .5rem; }
/* 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 --- */
/* ── THE APP PAGE (v0.316.0) — one column, hairlines, boxes only where they mean something ───────
Operator-approved mockup, 2026-10-15. The rules, and why each one:
ONE COLUMN of ONE WIDTH. Boxes of different widths read as a page assembled by accident.
SECTIONS ARE SEPARATED BY HAIRLINES, not drawn as cards. A card says "this is a thing you act
on"; most of an app page is a thing you READ, so a card there is a promise it cannot keep.
A BOX MEANS SOMETHING. Exactly two exist: blue when the app is waiting for the household, amber
when something is risky. The exception-colour principle, applied to shape as well as colour.
Tokens only — no raw hexes, 2px radius, no shadows. */
.app-page {
max-width: 820px;
padding: 32px 48px 64px;
}
/* The log is the one tab whose content is genuinely wide: log lines are long, and wrapping them at
820px makes them unreadable. */
.app-page-wide { max-width: none; }
.app-back {
display: inline-block;
font-size: 13px;
color: var(--text-2);
text-decoration: none;
margin-bottom: 14px;
}
.app-back:hover { color: var(--text-1); }
/* HERO — no box, no border. The app's identity is a heading, not a card. */
.app-hero {
display: flex;
align-items: flex-start;
gap: 20px;
flex-wrap: wrap;
}
.app-hero-logo {
width: 64px; height: 64px;
min-width: 64px;
border: 1px solid var(--line);
background: var(--bg-1);
border-radius: var(--radius);
object-fit: contain;
padding: 8px;
}
.app-hero-text { flex: 1 1 320px; min-width: 0; }
.app-hero-name { font-size: 26px; font-weight: 700; color: var(--text-1); margin: 0; line-height: 1.2; }
.app-hero-tagline { font-size: 15px; color: var(--text-2); margin: 4px 0 10px; }
.app-hero-actions { margin-left: auto; }
.app-chips { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.app-chip {
font-size: 12px; font-weight: 600;
border: 1px solid var(--line);
border-radius: var(--radius);
padding: 3px 8px;
color: var(--text-1);
white-space: nowrap;
}
/* The meta line carries what used to be a full-width green banner saying the automatic update
worked. A success that needed no decision is not news; it is a date. */
.app-meta { font-size: 12px; color: var(--text-3); }
/* TABS — links with a line under the open one. No pills, no fills. */
.app-tabs {
display: flex;
gap: 28px;
flex-wrap: wrap;
margin: 28px 0 8px;
border-bottom: 1px solid var(--line);
}
.app-tab {
font-size: 15px; font-weight: 600;
padding: 12px 0;
color: var(--text-2);
text-decoration: none;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
white-space: nowrap;
}
.app-tab:hover { color: var(--text-1); }
.app-tab-active { color: var(--text-1); border-bottom-color: var(--blue-bright); }
/* SECTIONS — a hairline between, nothing around. */
.app-section {
padding: 28px 0;
border-bottom: 1px solid var(--line-soft);
background: none;
border-left: 0; border-right: 0; border-top: 0;
border-radius: 0;
margin: 0;
}
.app-section:last-child { border-bottom: 0; }
.app-section > h3, .app-section > h4 {
font-size: 17px; font-weight: 700; color: var(--text-1); margin: 0 0 6px;
}
.app-section > p { font-size: 14px; color: var(--text-2); line-height: 1.55; margin: 0 0 16px; }
/* ROWS — label and value, one grid so every value on the page starts at the same x. */
.app-field-row {
display: grid;
grid-template-columns: 200px minmax(0, 1fr);
gap: 16px;
padding: 10px 0;
align-items: baseline;
}
.app-field-label { font-size: 14px; color: var(--text-2); }
.app-field-value { font-size: 14px; color: var(--text-1); min-width: 0; }
.app-field-hint { font-size: 12px; color: var(--text-3); margin: 6px 0 0; }
/* CALLOUTS — the only boxes on the page. */
.app-callout {
padding: 14px 16px;
border-radius: var(--radius);
font-size: 14px;
border: 1px solid var(--line);
}
.app-callout > h3, .app-callout > h4 { font-size: 15px; font-weight: 700; margin: 0 0 6px; color: var(--text-1); }
/* „The app is waiting for you" — a request, never a fault, so blue and never amber. */
.app-callout-ask { border-color: var(--blue); background: var(--blue-dim); }
/* „Something here is risky" — the exception colour, and only on a deviation. */
.app-callout-warn { border-color: var(--warn); background: var(--warn-dim); }
/* The settings tab reuses the install wizard's field markup, which carries that page's boxes: a
card around the whole form and one around every generated value. On a TAB those are sections, so
the boxes come off — the input itself is still a field, which is what tells the household it is a
value. Scoped to .app-section, so the install page (same column, its own form) is untouched. */
.app-section .deploy-form,
.app-section .form-group-auto,
.app-section .app-optional-config,
.app-section .deploy-storage-info,
.app-section .deploy-cross-drive,
.app-section .monitor-card,
.app-section .card {
background: none;
border: 0;
border-radius: 0;
padding-left: 0;
padding-right: 0;
}
.app-faq { margin: .5rem 0 0; }
.app-faq dt { color: var(--text-1); font-weight: 600; margin-top: .85rem; }
.app-faq dd { color: var(--text-2); margin: .25rem 0 0; padding: 0; }
@media (max-width: 720px) {
.app-page { padding: 20px 16px 48px; }
.app-field-row { grid-template-columns: 1fr; gap: 4px; }
.app-hero-actions { margin-left: 0; flex-basis: 100%; }
.app-tabs { gap: 18px; }
.app-tab { font-size: 14px; }
}
.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);
}
/* „Hova tegyem a fájlokat?" — R-75 folder rows on the app page. */
.datapath-list {
display: flex;
flex-direction: column;
gap: .75rem;
}
.datapath-row {
border-left: 3px solid var(--blue);
background: var(--blue-dim);
padding: .6rem .75rem;
border-radius: var(--radius);
}
.datapath-head {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: .75rem;
flex-wrap: wrap;
}
.datapath-link {
color: var(--blue-bright);
font-weight: 600;
text-decoration: none;
}
.datapath-link:hover {
text-decoration: underline;
}
.datapath-space {
color: var(--text-2);
font-size: .8rem;
white-space: nowrap;
}
.datapath-note {
margin: .35rem 0 0 0;
color: var(--text-2);
font-size: .85rem;
line-height: 1.45;
}
.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;
}
/* Disk-health card (v0.169.0) — same card grammar as the backup card. */
.disk-health-card {
background: var(--bg-1);
border-radius: var(--radius);
padding: 1rem 1.25rem;
border: 1px solid var(--line);
margin-bottom: 2rem;
}
.disk-health-card h3 { margin-bottom: .75rem; }
.disk-health-list { list-style: none; padding: 0; margin: 0; }
.disk-health-row {
display: flex;
align-items: center;
gap: .75rem;
padding: .35rem 0;
font-size: .85rem;
border-top: 1px solid var(--line);
}
.disk-health-row:first-child { border-top: none; }
.disk-health-label { flex: 1; color: var(--text-1); }
.disk-health-status { font-weight: 600; }
.disk-health-temp { color: var(--text-3); font-variant-numeric: tabular-nums; }
.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;
}
/* R-388 slice 1 — the notification page's three group switches and the „Részletek" fold */
.notif-group {
display: flex;
flex-direction: column;
gap: .25rem;
margin-bottom: .75rem;
}
.notif-details {
margin-bottom: 1rem;
}
.notif-details summary {
cursor: pointer;
font-size: .9rem;
}
.notif-details[open] summary {
margin-bottom: .75rem;
}
.storage-add-details[open] summary {
margin-bottom: 1rem;
}
.storage-add-form {
margin-top: .75rem;
}
/* Responsive */
@media(max-width: 768px) {
/* v0.166.0: the old horizontal .nav-links strip was deleted — it predated the v0.146.0
accordion and, because the nested sub-lists share the .nav-links class, laid them out
horizontally inside an overflow:hidden row and clipped every sub-item past the first.
Replaced by a sticky top bar + off-canvas drawer (JS) with a static-sidebar fallback (no-JS). */
.mobile-topbar {
display: flex;
align-items: center;
justify-content: space-between;
position: sticky;
top: 0;
z-index: 800;
background: var(--bg-2);
border-bottom: 1px solid var(--line);
padding: .5rem 1rem;
}
.mobile-topbar-logo img { height: 36px; width: auto; display: block; }
/* JS path: the vertical sidebar becomes an off-canvas left drawer (accordion untouched). */
.js .sidebar {
position: fixed;
top: 0;
left: 0;
height: 100vh;
height: 100dvh;
width: min(280px, 85vw);
transform: translateX(-100%);
transition: transform .2s ease;
z-index: 950;
border-right: 1px solid var(--line);
border-bottom: none;
}
.js .sidebar.is-open { transform: none; }
.js .nav-backdrop:not([hidden]) {
display: block;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, .5);
z-index: 900;
}
body.nav-open { overflow: hidden; }
/* No-JS fallback: sidebar renders static inline above the content so no destination dead-ends. */
.no-js .sidebar {
position: static;
height: auto;
width: 100%;
border-right: none;
border-bottom: 1px solid var(--line);
}
.no-js .nav-burger { display: none; }
.content { margin-left: 0; padding: 1rem; }
body { flex-direction: column; }
.app-field-row { flex-wrap: wrap; }
.app-row-actions { width: 100%; justify-content: flex-end; }
.stack-grid { grid-template-columns: 1fr; }
/* R-907: a page header (title, domain chip, buttons) wraps instead of running off the screen; on the
launcher the share button drops to its own line. Pinned by TestR907_PageHeaderWrapsOnAPhone. */
.page-header { flex-wrap: wrap; row-gap: .6rem; }
.share-open-btn { margin-left: 0; white-space: nowrap; }
/* A banner wraps too: a long path breaks, and the link drops to its own line inside the banner (2026-10-08 —
on 9202 the „Rendszermonitor" link ran 90 px past a 390 px screen). Pinned by TestR907_PageHeaderWrapsOnAPhone. */
.alert-banner { flex-wrap: wrap; }
.alert-message { min-width: 0; overflow-wrap: anywhere; }
.alert-link { flex-basis: 100%; text-align: right; }
.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%; }
}
/* v0.166.0: honor reduced-motion for the drawer slide, matching the accordion/chevron convention. */
@media (prefers-reduced-motion: reduce) {
.js .sidebar { transition: none; }
}
/* ===================================================================
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); }
/* R-48 offsite restore wizard — scoped to the wizard page only.
The destructive intent card is marked by a critical-tone left rule, not a shouty background:
the exception-color principle applies to cards too, and the copy carries the warning. */
.restore-wizard-phases {
display: flex;
flex-wrap: wrap;
gap: .35rem .75rem;
margin-bottom: 1.5rem;
font-size: .8rem;
color: var(--text-3);
}
.restore-wizard-phase + .restore-wizard-phase::before {
content: "·";
margin-right: .75rem;
color: var(--line);
}
.restore-wizard-phase.is-current {
color: var(--blue-bright);
font-weight: 600;
}
.restore-danger-card {
border-left: 2px solid var(--crit);
}
/* i18n (v0.254.0, placed properly in v0.255.0): the globe on the pages outside the dashboard chrome —
sign-in, claim, recovery. Those pages have their own shell and no sidebar.
v0.255.0: it lives INSIDE the card, centred under the footer, and the menu opens UPWARD — which is
the shared .lang-globe-menu rule, so this block adds no positioning of its own. It floated in the
top-left of the viewport before, outside the card, which read as a stray browser control. */
.shell-lang { display: flex; justify-content: center; margin-top: 1.5rem; }
/* ── Kept data (`09` §3 decision 36): the install-time choice and the „Megőrzött adatok" list ── */
.kept-choice { margin-bottom: 1rem; }
.kept-choice-title { margin: 0 0 .5rem; }
.kept-choice-body { color: var(--text-1); margin: 0 0 1rem; }
.kept-choice-option { border-top: 1px solid var(--line-soft); padding: .75rem 0; }
.kept-choice-desc, .kept-choice-note { color: var(--text-2); margin: .4rem 0 0; font-size: .9rem; }
.kept-choice-note { color: var(--text-3); }
.kept-header { display: flex; align-items: center; gap: .5rem; }
.kept-list { display: flex; flex-direction: column; gap: .75rem; margin-top: .75rem; }
.kept-item { border: 1px solid var(--line); border-radius: var(--radius); padding: .75rem; background: var(--bg-1); }
.kept-item-head { display: flex; justify-content: space-between; gap: .75rem; flex-wrap: wrap; }
.kept-item-name { font-weight: 600; color: var(--text-1); }
.kept-item-meta { color: var(--text-2); }
.kept-item-backup { color: var(--text-2); margin: .35rem 0 .5rem; font-size: .9rem; }
.kept-item-actions { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }
.kept-inline-form { display: inline; margin: 0; }
.kept-delete { margin-top: .5rem; }
.kept-delete summary { list-style: none; display: inline-block; cursor: pointer; }
.kept-delete-form { display: flex; flex-direction: column; gap: .4rem; margin-top: .5rem; max-width: 32rem; }
.kept-delete-text { color: var(--warn); margin: 0; }
.storage-kept-link { margin-top: .75rem; }
/* media drive notice (v0.313.0) */
.media-notice-list { margin: .4rem 0 .6rem 1.1rem; padding: 0; }
.media-notice-list li { margin: .15rem 0; }
.media-notice-actions { display: flex; gap: .5rem; flex-wrap: wrap; margin: .6rem 0; }