/* Admin area — Overview board + shared admin-page chrome. Visually aligned with the backup dashboard (tile/card style) and the config page header. */ /* Per-area identity hues (--page-*) now live in shared/css/tokens.css so they are part of the always-present base token layer. */ .admin-page { padding: 4px 2px 40px; } .admin-breadcrumb { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: rgba(var(--text-rgb), 0.45); margin-bottom: 2px; } /* Overview cards */ .admin-card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; margin-top: 8px; } .admin-card { display: flex; flex-direction: column; padding: 16px; border: 1px solid rgba(var(--text-rgb), 0.10); border-radius: 12px; background: var(--card-bg); } .admin-card-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; } .admin-card-title { font-size: 0.95rem; font-weight: 700; } .admin-status-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; } .admin-status-dot.ok { background: #36d399; } .admin-status-dot.warn { background: #fbbd23; } .admin-status-dot.none { background: rgba(var(--text-rgb), 0.25); } /* Inline integrity readout (dot + label) inside a card line. */ .admin-integrity { display: inline-flex; align-items: center; gap: 6px; } .admin-integrity .admin-status-dot { width: 8px; height: 8px; } /* Storage → Images list: reuses the Tasks list look (.task-item etc., loaded globally), with a small toolbar + image-specific status pills. */ .sys-images-toolbar { display: flex; align-items: center; justify-content: flex-end; gap: 14px; margin: 10px 0 6px; } .sys-images-list { margin-top: 4px; } .sys-image-item .task-header { cursor: default; } .sys-img-icon { color: rgba(var(--text-rgb), 0.6); flex-shrink: 0; } .sys-img-pill.is-inuse { background: rgba(var(--accent-rgb), 0.16); color: var(--accent); } .sys-img-pill.is-unused { background: rgba(var(--text-rgb), 0.10); color: rgba(var(--text-rgb), 0.6); } .sys-img-pill.is-dangling { background: rgba(251, 189, 35, 0.16); color: #fbbd23; } .admin-card-body { display: flex; flex-direction: column; gap: 6px; flex: 1; } .admin-card-line { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: 0.85rem; color: rgba(var(--text-rgb), 0.6); } .admin-card-line strong { color: var(--text-primary); font-weight: 600; text-align: right; word-break: break-word; } .admin-card-actions { margin-top: 14px; padding-top: 12px; border-top: 1px solid rgba(var(--text-rgb), 0.08); } .admin-card-ok { font-size: 0.82rem; color: rgba(var(--text-rgb), 0.55); } /* Per-page identity button. The card sets --page / --page-rgb inline; the button (and its icon, via currentColor) takes the area's hue. Reusable on any admin surface going forward — set the two vars and use .admin-action-btn. */ .admin-action-btn { display: inline-flex; align-items: center; gap: 8px; padding: 9px 16px; border-radius: 8px; font-size: 0.875rem; font-weight: 600; cursor: pointer; /* Translucent hue tint + WHITE text: keeps the soft coloured look (solid fills were too heavy) while staying legible on nebula's dark cards — white on the tinted-over-dark surface has plenty of contrast, unlike the coloured text it replaces. */ color: #fff; background: rgba(var(--page-rgb, var(--accent-rgb)), 0.16); border: 1px solid rgba(var(--page-rgb, var(--accent-rgb)), 0.42); transition: background 0.12s ease, transform 0.12s ease, box-shadow 0.12s ease; } .admin-action-btn:hover { background: rgba(var(--page-rgb, var(--accent-rgb)), 0.26); transform: translateY(-1px); } .admin-action-btn:disabled { opacity: 0.6; cursor: default; transform: none; box-shadow: none; } /* Primary action (Update now): a stronger tint so it stands out. */ .admin-action-btn.is-primary { background: rgba(var(--page-rgb, var(--accent-rgb)), 0.28); border-color: rgba(var(--page-rgb, var(--accent-rgb)), 0.60); } .admin-action-btn.is-primary:hover { background: rgba(var(--page-rgb, var(--accent-rgb)), 0.36); box-shadow: 0 6px 16px rgba(var(--page-rgb, var(--accent-rgb)), 0.30); } /* ============================================================ Admin → System (in-depth statistics page) ============================================================ */ .sys-section-head { display: flex; align-items: center; justify-content: space-between; margin: 26px 0 12px; } .sys-section-head h2 { font-size: 1.05rem; font-weight: 700; margin: 0; } .sys-chart-meta { font-size: 0.78rem; color: rgba(var(--text-rgb), 0.5); } /* Range selector (1h / 6h / 24h) */ .sys-range { display: inline-flex; gap: 4px; } .sys-range-btn { padding: 4px 12px; font-size: 0.78rem; font-weight: 600; color: rgba(var(--text-rgb), 0.7); background: rgba(var(--text-rgb), 0.06); border: 1px solid rgba(var(--text-rgb), 0.12); border-radius: 999px; cursor: pointer; transition: background .15s ease, border-color .15s ease, color .15s ease; } .sys-range-btn:hover { background: rgba(var(--accent-rgb), 0.15); } .sys-range-btn.active { color: var(--text-primary); background: rgba(var(--accent-rgb), 0.22); border-color: rgba(var(--accent-rgb), 0.55); } /* Gauges row */ .sys-gauges { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 16px; margin-top: 10px; } .lp-gauge { position: relative; display: flex; flex-direction: column; align-items: center; padding: 14px 12px 10px; background: var(--card-bg); border: 1px solid rgba(var(--text-rgb), 0.10); border-radius: 12px; } .lp-gauge-svg { width: 116px; height: 116px; display: block; } .lp-gauge-center { position: absolute; top: 72px; left: 0; right: 0; transform: translateY(-50%); text-align: center; pointer-events: none; } .lp-gauge-value { font-size: 1.5rem; font-weight: 700; color: var(--text-primary); line-height: 1; } .lp-gauge-value span { font-size: 0.8rem; font-weight: 600; opacity: 0.6; margin-left: 1px; } .lp-gauge-sub { font-size: 0.68rem; color: rgba(var(--text-rgb), 0.5); margin-top: 3px; } .lp-gauge-label { margin-top: 6px; font-size: 0.82rem; font-weight: 600; color: rgba(var(--text-rgb), 0.75); } /* Trend chart cards */ .sys-charts { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; } .sys-chart-card { background: var(--card-bg); border: 1px solid rgba(var(--text-rgb), 0.10); border-radius: 12px; padding: 14px 16px 10px; transition: border-color .2s ease, box-shadow .2s ease; } .sys-chart-card:hover { border-color: rgba(var(--accent-rgb), 0.28); box-shadow: 0 6px 22px rgba(var(--accent-rgb), 0.10); } .sys-chart-card:hover .sys-expand { color: var(--accent); background: rgba(var(--accent-rgb), 0.18); } .sys-chart-head { display: flex; align-items: baseline; justify-content: space-between; font-size: 0.88rem; font-weight: 700; margin-bottom: 8px; } .sys-chart-head .sys-chart-meta { font-weight: 500; } .sys-chart-body { position: relative; } .lp-chart { width: 100%; height: 92px; display: block; overflow: visible; } .lp-chart-last { position: absolute; top: 0; right: 0; font-size: 0.85rem; font-weight: 700; } .lp-chart-empty { height: 92px; display: flex; align-items: center; justify-content: center; font-size: 0.82rem; color: rgba(var(--text-rgb), 0.4); } .sys-net-legend { display: flex; gap: 16px; margin-top: 6px; font-size: 0.8rem; color: rgba(var(--text-rgb), 0.7); } .sys-net-legend .dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 5px; } .sys-net-legend .dot.ok { background: var(--status-success); } .sys-net-legend .dot.accent { background: var(--accent); } /* Info / docker stat strips */ .sys-strip { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; } .sys-stat { display: flex; flex-direction: column; gap: 3px; padding: 12px 14px; background: var(--card-bg); border: 1px solid rgba(var(--text-rgb), 0.10); border-radius: 10px; } .sys-stat-label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; color: rgba(var(--text-rgb), 0.45); } .sys-stat-value { font-size: 0.92rem; font-weight: 600; color: var(--text-primary); word-break: break-word; } /* OS + CPU value rows: a rounded icon tile (same look as the backup app tiles) followed by the label text. */ .sys-id-value { display: inline-flex; align-items: center; gap: 10px; } .sys-id-icon { width: 36px; height: 36px; flex-shrink: 0; box-sizing: border-box; padding: 5px; border-radius: 8px; background: rgba(var(--text-rgb), 0.05); display: inline-flex; align-items: center; justify-content: center; } .sys-id-icon img { max-width: 100%; max-height: 100%; object-fit: contain; display: block; } /* Per-app table */ .sys-apps-wrap { background: var(--card-bg); border: 1px solid rgba(var(--text-rgb), 0.10); border-radius: 12px; overflow: hidden; } table.sys-apps { width: 100%; border-collapse: collapse; font-size: 0.85rem; } table.sys-apps th { text-align: left; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; color: rgba(var(--text-rgb), 0.45); padding: 12px 14px; border-bottom: 1px solid rgba(var(--text-rgb), 0.10); } table.sys-apps td { padding: 11px 14px; border-bottom: 1px solid rgba(var(--text-rgb), 0.06); vertical-align: middle; color: var(--text-primary); } table.sys-apps tr:last-child td { border-bottom: none; } table.sys-apps tr:hover td { background: rgba(var(--text-rgb), 0.03); } .sys-app-name { font-weight: 600; display: flex; align-items: center; gap: 8px; } .sys-app-sub { font-size: 0.72rem; font-weight: 500; color: rgba(var(--text-rgb), 0.45); } .sys-cell-val { font-size: 0.78rem; color: rgba(var(--text-rgb), 0.65); margin-left: 2px; } .sys-net-cell { font-size: 0.78rem; color: rgba(var(--text-rgb), 0.7); white-space: nowrap; } .sys-spark-cell { width: 110px; } .sys-apps-empty { text-align: center; color: rgba(var(--text-rgb), 0.45); padding: 24px 14px !important; } /* Bars + sparklines (shared by LPCharts) */ .lp-bar { display: inline-block; width: 90px; max-width: 40%; height: 6px; border-radius: 3px; background: rgba(var(--text-rgb), 0.12); overflow: hidden; vertical-align: middle; } .lp-bar-fill { display: block; height: 100%; border-radius: 3px; transition: width .4s ease; } .lp-spark { width: 100px; height: 24px; display: block; } /* Gauge wrapper — each gauge tile is a button that opens the detail overlay. The visual is identical to before (.lp-gauge); the wrapper adds the press affordance + the corner expand icon. */ .sys-gauge-wrap { all: unset; position: relative; display: block; cursor: pointer; border-radius: 12px; transition: transform .15s ease, box-shadow .15s ease; } .sys-gauge-wrap:focus-visible { outline: 2px solid rgba(var(--accent-rgb), 0.6); outline-offset: 2px; } .sys-gauge-wrap:hover { transform: translateY(-1px); } .sys-gauge-wrap:hover .lp-gauge { box-shadow: 0 6px 24px rgba(var(--accent-rgb), 0.18); border-color: rgba(var(--accent-rgb), 0.35); } .sys-gauge-wrap .lp-gauge { transition: box-shadow .2s ease, border-color .2s ease; height: 100%; } .sys-gauge-expand { position: absolute; top: 8px; right: 10px; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; color: rgba(var(--text-rgb), 0.45); border-radius: 6px; background: rgba(var(--text-rgb), 0.04); opacity: 0; transition: opacity .15s ease, color .15s ease, background .15s ease; pointer-events: none; } .sys-gauge-wrap:hover .sys-gauge-expand, .sys-gauge-wrap:focus-visible .sys-gauge-expand { opacity: 1; } .sys-gauge-wrap:hover .sys-gauge-expand { color: var(--accent); background: rgba(var(--accent-rgb), 0.12); } /* Chart card head — right cluster keeps the meta + expand button aligned. */ .sys-chart-head { gap: 12px; } .sys-chart-head-right { display: inline-flex; align-items: center; gap: 10px; } .sys-expand { all: unset; display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; color: rgba(var(--text-rgb), 0.5); background: rgba(var(--text-rgb), 0.05); border-radius: 6px; cursor: pointer; transition: color .15s ease, background .15s ease, transform .15s ease; } .sys-expand:hover { color: var(--accent); background: rgba(var(--accent-rgb), 0.14); transform: scale(1.06); } .sys-expand:focus-visible { outline: 2px solid rgba(var(--accent-rgb), 0.6); outline-offset: 2px; } /* ========================================================================= Admin → System — sub-pages (metric / app / storage) ========================================================================= */ /* Shared breadcrumb-link style for sub-page back navigation. */ .admin-breadcrumb a { color: inherit; text-decoration: none; transition: color .15s ease; } .admin-breadcrumb a:hover { color: var(--accent); } /* ---- Metric deep-dive page (.sys-metric-page) ---- */ .sys-metric-page { --metric-rgb: var(--accent-rgb); } .sys-metric-page .page-header { align-items: flex-start; justify-content: space-between; gap: 16px; display: flex; } .sys-metric-name { background: linear-gradient(120deg, var(--text-primary) 0%, rgba(var(--metric-rgb), 1) 110%); -webkit-background-clip: text; background-clip: text; color: transparent; } .sys-metric-sub { color: rgba(var(--text-rgb), 0.6); } .sys-metric-actions { display: flex; flex-direction: column; align-items: flex-end; gap: 10px; margin-top: 6px; } .sys-detail-range { display: inline-flex; gap: 4px; padding: 4px; background: rgba(var(--text-rgb), 0.06); border-radius: 999px; } .sys-detail-range-btn { all: unset; padding: 5px 14px; font-size: 0.8rem; font-weight: 600; color: rgba(var(--text-rgb), 0.65); border-radius: 999px; cursor: pointer; transition: background .15s ease, color .15s ease; } .sys-detail-range-btn:hover { color: var(--text-primary); } .sys-detail-range-btn.active { color: var(--text-on-accent, #0a1426); background: rgba(var(--metric-rgb), 0.95); box-shadow: 0 2px 12px rgba(var(--metric-rgb), 0.35); } .sys-detail-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; } .sys-detail-stat { padding: 14px 18px 12px; background: rgba(var(--text-rgb), 0.04); border: 1px solid rgba(var(--text-rgb), 0.08); border-radius: 14px; display: flex; flex-direction: column; gap: 4px; transition: border-color .2s ease; } .sys-detail-stat[data-stat="now"] { background: linear-gradient(135deg, rgba(var(--metric-rgb), 0.16) 0%, rgba(var(--metric-rgb), 0.05) 100%); border-color: rgba(var(--metric-rgb), 0.35); } .sys-detail-stat-k { font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.14em; color: rgba(var(--text-rgb), 0.5); font-weight: 700; } .sys-detail-stat-v { font-size: 1.55rem; font-weight: 700; color: var(--text-primary); line-height: 1.05; font-variant-numeric: tabular-nums; } .sys-detail-stat[data-stat="now"] .sys-detail-stat-v { background: linear-gradient(120deg, var(--text-primary) 0%, rgba(var(--metric-rgb), 1) 100%); -webkit-background-clip: text; background-clip: text; color: transparent; } .sys-detail-stat-t { font-size: 0.72rem; color: rgba(var(--text-rgb), 0.45); font-variant-numeric: tabular-nums; } .sys-detail-canvas, .sys-metric-canvas { position: relative; min-height: 420px; background: radial-gradient(120% 80% at 50% 100%, rgba(var(--metric-rgb), 0.08) 0%, transparent 60%), rgba(0, 0, 0, 0.22); border: 1px solid rgba(var(--text-rgb), 0.06); border-radius: 14px; overflow: hidden; margin-top: 16px; } .sys-detail-svg { width: 100%; height: 100%; display: block; } .sys-detail-loading, .sys-detail-empty { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: rgba(var(--text-rgb), 0.45); font-size: 0.92rem; pointer-events: none; } .sys-detail-empty { color: rgba(var(--text-rgb), 0.55); } .sys-detail-grid { stroke: rgba(var(--text-rgb), 0.07); stroke-width: 1; stroke-dasharray: 2 4; vector-effect: non-scaling-stroke; } .sys-detail-axis-line { stroke: rgba(var(--text-rgb), 0.18); stroke-width: 1; vector-effect: non-scaling-stroke; } .sys-detail-axis { fill: rgba(var(--text-rgb), 0.55); font-size: 11px; font-variant-numeric: tabular-nums; } .sys-detail-axis-y { text-anchor: end; } .sys-detail-axis-x { text-anchor: middle; } .sys-detail-peak { fill: var(--status-warning); filter: drop-shadow(0 0 6px rgba(var(--status-warning-rgb, 255 193 7), 0.6)); } .sys-detail-min { fill: rgba(var(--text-rgb), 0.55); } /* LibrePortal share reference line on the Disk page. */ .sys-detail-lpline { stroke: var(--accent); stroke-width: 1.5; stroke-dasharray: 5 4; opacity: 0.85; } .sys-detail-lplabel { fill: var(--accent); font-size: 12px; font-weight: 600; } .sys-detail-now { fill: rgb(var(--metric-rgb)); filter: drop-shadow(0 0 8px rgba(var(--metric-rgb), 0.7)); animation: sys-detail-pulse 2.2s ease-in-out infinite; } @keyframes sys-detail-pulse { 0%, 100% { r: 5; } 50% { r: 7; } } .sys-detail-cross { stroke: rgba(var(--metric-rgb), 0.55); stroke-width: 1; stroke-dasharray: 3 3; vector-effect: non-scaling-stroke; pointer-events: none; } .sys-detail-cross-dot { fill: rgb(var(--metric-rgb)); stroke: var(--surface-bg-solid, #0f1729); stroke-width: 2; pointer-events: none; } .sys-detail-tooltip { position: absolute; pointer-events: none; padding: 8px 12px; background: rgba(15, 23, 41, 0.92); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); border: 1px solid rgba(var(--metric-rgb), 0.4); border-radius: 10px; color: var(--text-primary); font-size: 0.85rem; transition: transform 60ms linear; will-change: transform; box-shadow: 0 8px 28px rgba(0,0,0,0.4); min-width: 110px; } .sys-detail-tip-v { font-weight: 700; font-size: 0.95rem; font-variant-numeric: tabular-nums; color: rgb(var(--metric-rgb)); } .sys-detail-tip-t { font-size: 0.72rem; color: rgba(var(--text-rgb), 0.6); margin-top: 2px; font-variant-numeric: tabular-nums; } .sys-detail-foot { display: flex; justify-content: space-between; align-items: center; color: rgba(var(--text-rgb), 0.45); font-size: 0.75rem; font-variant-numeric: tabular-nums; margin-top: 10px; } .sys-detail-foot-hint kbd, .sys-detail-foot-hint { letter-spacing: 0.02em; } /* Index per-app table rows are now clickable to open the app deep-dive. */ .sys-app-row { cursor: pointer; } .sys-app-row:hover td { background: rgba(var(--accent-rgb), 0.06) !important; } .sys-app-row:focus { outline: none; } .sys-app-row:focus-visible td { background: rgba(var(--accent-rgb), 0.10) !important; } .sys-app-arrow { text-align: right; color: rgba(var(--text-rgb), 0.35); font-size: 1.1rem; width: 1em; } .sys-app-row:hover .sys-app-arrow { color: var(--accent); } /* Clickable stat tile in the Docker strip — same chrome as .sys-stat but feels like a button. */ .sys-stat-link { all: unset; display: flex; flex-direction: column; gap: 3px; padding: 12px 14px; background: var(--card-bg); border: 1px solid rgba(var(--accent-rgb), 0.25); border-radius: 10px; cursor: pointer; transition: border-color .15s ease, transform .15s ease, box-shadow .15s ease; } .sys-stat-link:hover { border-color: rgba(var(--accent-rgb), 0.55); transform: translateY(-1px); box-shadow: 0 4px 16px rgba(var(--accent-rgb), 0.16); } .sys-stat-link .sys-stat-value { color: var(--accent); } @media (max-width: 900px) { .sys-metric-page .page-header { flex-direction: column; } .sys-detail-stats { grid-template-columns: 1fr 1fr; } .sys-detail-stat-v { font-size: 1.25rem; } } /* ========================================================================= Admin → System → App — per-container deep-dive (.sys-app-page) ========================================================================= */ .sys-app-empty { padding: 36px 20px; text-align: center; color: rgba(var(--text-rgb), 0.55); background: var(--card-bg); border: 1px dashed rgba(var(--text-rgb), 0.18); border-radius: 14px; } .sys-app-grid { display: grid; grid-template-columns: 1fr; gap: 18px; margin-top: 18px; } .sys-app-card { background: var(--card-bg); border: 1px solid rgba(var(--text-rgb), 0.10); border-radius: 14px; padding: 18px 20px 14px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15); } .sys-app-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 10px; } .sys-app-card-status { display: flex; align-items: center; gap: 8px; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; color: rgba(var(--text-rgb), 0.55); font-weight: 700; } .sys-app-card-svc { padding: 1px 8px; background: rgba(var(--accent-rgb), 0.18); color: var(--accent); border-radius: 999px; font-size: 0.7rem; } .sys-app-card-name { font-size: 1.25rem; font-weight: 700; margin: 4px 0 2px; color: var(--text-primary); } .sys-app-card-meta { font-size: 0.8rem; color: rgba(var(--text-rgb), 0.55); } .sys-app-card-sep { margin: 0 6px; opacity: 0.5; } .sys-app-card-status-line { font-size: 0.78rem; color: rgba(var(--text-rgb), 0.45); text-align: right; flex-shrink: 0; font-variant-numeric: tabular-nums; } .sys-app-card-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 10px; padding: 12px; background: rgba(0, 0, 0, 0.22); border: 1px solid rgba(var(--text-rgb), 0.06); border-radius: 10px; margin-bottom: 12px; } .sys-app-stat { display: flex; flex-direction: column; gap: 2px; } .sys-app-stat-k { font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.10em; color: rgba(var(--text-rgb), 0.5); font-weight: 700; } .sys-app-stat-v { font-size: 1.05rem; font-weight: 700; color: var(--text-primary); font-variant-numeric: tabular-nums; transition: color .2s ease; } .sys-app-stat-v.warn { color: var(--status-warning); } .sys-app-stat-v.danger { color: var(--status-danger); } .sys-app-card-body { display: flex; flex-direction: column; gap: 14px; } .sys-app-card-loading, .sys-app-card-err { padding: 14px; color: rgba(var(--text-rgb), 0.5); text-align: center; font-size: 0.88rem; } .sys-app-card-err { color: var(--status-danger); } .sys-app-card-limits { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; } .sys-app-limit { padding: 10px 12px; background: rgba(var(--text-rgb), 0.03); border: 1px solid rgba(var(--text-rgb), 0.06); border-radius: 8px; } .sys-app-limit-k { display: block; font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.08em; color: rgba(var(--text-rgb), 0.45); font-weight: 700; margin-bottom: 2px; } .sys-app-limit-v { font-size: 0.9rem; font-weight: 600; color: var(--text-primary); word-break: break-word; } .sys-app-section h3 { font-size: 0.85rem; font-weight: 700; margin: 0 0 8px; color: rgba(var(--text-rgb), 0.7); text-transform: uppercase; letter-spacing: 0.06em; } .sys-app-table { width: 100%; border-collapse: collapse; font-size: 0.82rem; background: rgba(var(--text-rgb), 0.03); border-radius: 8px; overflow: hidden; } .sys-app-table th { text-align: left; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.06em; color: rgba(var(--text-rgb), 0.45); padding: 8px 10px; border-bottom: 1px solid rgba(var(--text-rgb), 0.08); } .sys-app-table td { padding: 8px 10px; border-bottom: 1px solid rgba(var(--text-rgb), 0.04); color: rgba(var(--text-rgb), 0.85); font-variant-numeric: tabular-nums; } .sys-app-table tr:last-child td { border-bottom: none; } .sys-app-mount-type { display: inline-block; padding: 1px 7px; border-radius: 4px; font-size: 0.66rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; } .sys-app-mount-volume { background: rgba(var(--status-success-rgb), 0.2); color: var(--status-success); } .sys-app-mount-bind { background: rgba(var(--accent-rgb), 0.18); color: var(--accent); } .sys-app-mount-tmpfs { background: rgba(var(--status-warning-rgb), 0.18); color: var(--status-warning); } .sys-app-mount-path { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.78rem; word-break: break-all; } .sys-app-ports { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; } .sys-app-ports li { padding: 4px 10px; background: rgba(var(--accent-rgb), 0.12); border: 1px solid rgba(var(--accent-rgb), 0.30); border-radius: 999px; font-size: 0.78rem; font-variant-numeric: tabular-nums; color: var(--text-primary); } .sys-app-health { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; } .sys-app-health-pill { padding: 2px 10px; border-radius: 999px; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; } .sys-app-health-healthy { background: rgba(var(--status-success-rgb), 0.18); color: var(--status-success); } .sys-app-health-starting { background: rgba(var(--status-warning-rgb), 0.18); color: var(--status-warning); } .sys-app-health-unhealthy { background: rgba(var(--status-danger-rgb), 0.18); color: var(--status-danger); } .sys-app-health-unknown { background: rgba(var(--text-rgb), 0.10); color: rgba(var(--text-rgb), 0.6); } .sys-app-health-fail { color: var(--status-danger); font-size: 0.78rem; font-weight: 600; } .sys-app-health-log { background: rgba(var(--text-rgb), 0.03); border-radius: 6px; margin-top: 4px; padding: 4px 8px; font-size: 0.78rem; } .sys-app-health-log summary { cursor: pointer; color: rgba(var(--text-rgb), 0.65); } .sys-app-health-log pre { margin: 6px 0 0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.78rem; white-space: pre-wrap; color: rgba(var(--text-rgb), 0.7); } .sys-app-card-logs { margin-top: 12px; padding-top: 12px; border-top: 1px solid rgba(var(--text-rgb), 0.08); } .sys-app-card-logs-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; } .sys-app-logs-toggle { all: unset; cursor: pointer; padding: 4px 12px; font-size: 0.78rem; font-weight: 600; color: rgba(var(--text-rgb), 0.7); background: rgba(var(--text-rgb), 0.06); border-radius: 999px; transition: background .15s ease; } .sys-app-logs-toggle:hover { background: rgba(var(--accent-rgb), 0.15); color: var(--accent); } .sys-app-logs-refresh { all: unset; cursor: pointer; width: 24px; height: 24px; display: inline-flex; align-items: center; justify-content: center; color: rgba(var(--text-rgb), 0.5); border-radius: 6px; } .sys-app-logs-refresh:hover { color: var(--accent); background: rgba(var(--accent-rgb), 0.12); } .sys-app-logs-pre { margin: 0; padding: 12px; background: rgba(0, 0, 0, 0.42); border-radius: 8px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.78rem; line-height: 1.45; color: rgba(var(--text-rgb), 0.85); max-height: 400px; overflow: auto; white-space: pre-wrap; word-break: break-word; } .sys-app-logs-loading, .sys-app-logs-err { padding: 12px; color: rgba(var(--text-rgb), 0.5); font-size: 0.85rem; } .sys-app-logs-err { color: var(--status-danger); } @media (min-width: 1100px) { .sys-app-grid { grid-template-columns: 1fr; } } /* ========================================================================= Admin → System → Storage (.sys-storage-page) ========================================================================= */ .sys-storage-loading, .sys-storage-err { padding: 36px; text-align: center; color: rgba(var(--text-rgb), 0.55); font-size: 0.92rem; } .sys-storage-err { color: var(--status-danger); } .sys-storage-headline { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 18px; margin-top: 14px; } @media (max-width: 800px) { .sys-storage-headline { grid-template-columns: 1fr; } } .sys-storage-head-card { background: var(--card-bg); border: 1px solid rgba(var(--text-rgb), 0.10); border-radius: 14px; padding: 18px; display: flex; align-items: center; gap: 18px; } .sys-storage-donut { width: 200px; height: 200px; flex-shrink: 0; } .sys-storage-donut-total { fill: var(--text-primary); font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; } .sys-storage-donut-sub { fill: rgba(var(--text-rgb), 0.5); font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; } .sys-storage-legend { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 0; } .sys-storage-legend li { display: grid; grid-template-columns: 14px auto 1fr auto; align-items: center; gap: 10px; font-size: 0.85rem; } .sys-storage-swatch { width: 12px; height: 12px; border-radius: 3px; } .sys-storage-leg-k { color: var(--text-primary); font-weight: 600; } .sys-storage-leg-v { color: rgba(var(--text-rgb), 0.65); font-variant-numeric: tabular-nums; text-align: right; } .sys-storage-leg-r { grid-column: 2 / -1; font-size: 0.72rem; color: rgba(var(--text-rgb), 0.45); margin-top: -4px; } .sys-storage-head-stats { display: grid; grid-template-rows: auto 1fr; gap: 12px; } .sys-storage-stat { padding: 18px 20px; background: var(--card-bg); border: 1px solid rgba(var(--text-rgb), 0.10); border-radius: 14px; display: flex; flex-direction: column; gap: 4px; } .sys-storage-stat-recl { border-color: rgba(var(--status-warning-rgb), 0.32); background: linear-gradient(135deg, rgba(var(--status-warning-rgb), 0.14) 0%, rgba(var(--status-warning-rgb), 0.04) 100%); } .sys-storage-stat-k { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.10em; color: rgba(var(--text-rgb), 0.5); font-weight: 700; } .sys-storage-stat-v { font-size: 1.8rem; font-weight: 700; color: var(--text-primary); font-variant-numeric: tabular-nums; line-height: 1.05; } .sys-storage-stat-recl .sys-storage-stat-v { color: var(--status-warning); } /* Storage header: title left, "Reclaim space" action top-right (matches the metric page's header layout). */ .sys-storage-page .page-header { align-items: flex-start; justify-content: space-between; } /* "Reclaim space" action — orange. Safe prune only (build cache + dangling images); never volumes or in-use images. */ .sys-storage-reclaim { display: inline-flex; align-items: center; gap: 8px; padding: 9px 16px; font-size: 0.85rem; font-weight: 600; white-space: nowrap; color: var(--status-warning); background: rgba(var(--status-warning-rgb), 0.12); border: 1px solid rgba(var(--status-warning-rgb), 0.4); border-radius: 10px; cursor: pointer; transition: background .15s ease, border-color .15s ease, transform .15s ease; } .sys-storage-reclaim:hover { background: rgba(var(--status-warning-rgb), 0.2); border-color: rgba(var(--status-warning-rgb), 0.65); transform: translateY(-1px); } .sys-storage-reclaim:disabled, .sys-storage-reclaim.is-running { opacity: 0.6; cursor: progress; transform: none; } .sys-storage-reclaim svg { flex: 0 0 auto; } /* Neutral pill CTA — same shape as Reclaim, accent colour (e.g. "View storage breakdown" on the Disk metric page). */ .sys-storage-cta { display: inline-flex; align-items: center; gap: 8px; padding: 9px 16px; font-size: 0.85rem; font-weight: 600; white-space: nowrap; color: var(--accent); background: rgba(var(--accent-rgb), 0.12); border: 1px solid rgba(var(--accent-rgb), 0.4); border-radius: 10px; cursor: pointer; transition: background .15s ease, border-color .15s ease, transform .15s ease; } .sys-storage-cta:hover { background: rgba(var(--accent-rgb), 0.2); border-color: rgba(var(--accent-rgb), 0.65); transform: translateY(-1px); } .sys-storage-cta svg { flex: 0 0 auto; } .sys-storage-reclaim.is-running svg { animation: sysReclaimSpin 0.8s linear infinite; } @keyframes sysReclaimSpin { to { transform: rotate(360deg); } } @media (prefers-reduced-motion: reduce) { .sys-storage-reclaim.is-running svg { animation: none; } } .sys-storage-stat-sub { font-size: 0.78rem; color: rgba(var(--text-rgb), 0.55); } .sys-storage-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; } .sys-storage-card { --cat: var(--accent); --cat-rgb: var(--accent-rgb); padding: 16px; background: var(--card-bg); border: 1px solid rgba(var(--text-rgb), 0.10); border-left: 3px solid var(--cat); border-radius: 12px; } .sys-storage-card-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 4px; } .sys-storage-card-head h3 { font-size: 0.85rem; margin: 0; color: var(--text-primary); } .sys-storage-card-count { font-size: 0.72rem; color: rgba(var(--text-rgb), 0.5); font-variant-numeric: tabular-nums; } .sys-storage-card-size { font-size: 1.45rem; font-weight: 700; color: var(--text-primary); font-variant-numeric: tabular-nums; margin-bottom: 8px; } .sys-storage-card-bar { height: 6px; border-radius: 3px; background: rgba(var(--text-rgb), 0.08); overflow: hidden; } .sys-storage-card-bar > span { display: block; height: 100%; background: var(--cat); transition: width .4s ease; } /* Inline bar for the "Storage by app" table. */ .sys-storage-app-barcol { width: 38%; } .sys-storage-app-bar { display: block; height: 6px; border-radius: 3px; background: rgba(var(--text-rgb), 0.08); overflow: hidden; } .sys-storage-app-bar > span { display: block; height: 100%; background: var(--accent); transition: width .4s ease; } .sys-storage-app-empty { padding: 16px 4px; color: rgba(var(--text-rgb), 0.5); font-size: 0.85rem; } /* Expandable per-app folder breakdown. */ .sys-app-name .sys-storage-swatch { display: inline-block; vertical-align: middle; margin-right: 8px; } .sys-storage-app-row.is-clickable { cursor: pointer; } .sys-storage-caret, .sys-storage-caret-spacer { display: inline-block; width: 1em; margin-right: 6px; color: rgba(var(--text-rgb), 0.45); transition: transform .15s ease; } .sys-storage-caret.is-open { transform: rotate(90deg); } .sys-storage-app-detail.is-collapsed { display: none; } .sys-storage-app-detail > td { padding: 2px 12px 10px 30px; background: rgba(var(--text-rgb), 0.02); } .sys-storage-folders { list-style: none; margin: 0; padding: 0; } .sys-storage-folders li { display: flex; align-items: center; gap: 10px; padding: 4px 0; font-size: 0.82rem; color: rgba(var(--text-rgb), 0.72); } .sys-storage-folder-path { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .sys-storage-folder-size { margin-left: auto; font-variant-numeric: tabular-nums; color: rgba(var(--text-rgb), 0.92); } .sys-storage-ext-badge { flex-shrink: 0; padding: 1px 6px; border-radius: 4px; font-size: 0.68rem; background: rgba(var(--status-warning-rgb), 0.18); color: var(--status-warning); } /* Tasks-style list container (Images + Storage by app): a recessed dark panel behind the rows. */ .sys-tasklist { margin-top: 10px; padding: 8px; background: rgba(0, 0, 0, 0.18); border: 1px solid rgba(var(--text-rgb), 0.08); border-radius: 12px; display: flex; flex-direction: column; gap: 8px; } /* App / image icon inside a task row. */ .sys-task-icon { width: 20px; height: 20px; flex-shrink: 0; object-fit: contain; border-radius: 4px; } /* Clear All / Select all now live in the section head — no extra top margin. */ .sys-images-head .sys-images-toolbar { margin: 0; } /* Donut-colour key dot in a Storage-by-app row. */ .task-info .sys-storage-swatch { display: inline-block; width: 10px; height: 10px; border-radius: 3px; flex-shrink: 0; } /* Storage-by-app rows reuse .task-item; the folder list drops in below. */ .sys-storage-app-item.is-clickable .task-header { cursor: pointer; } .sys-storage-app-item .sys-storage-folders { padding: 4px 12px 8px 30px; } .sys-storage-app-item .task-actions .sys-storage-caret { margin-right: 0; } .sys-storage-card-meta { margin-top: 8px; display: flex; justify-content: space-between; align-items: center; gap: 8px; font-size: 0.74rem; color: rgba(var(--text-rgb), 0.5); } .sys-storage-card-recl { color: var(--status-warning); font-weight: 600; } .sys-storage-orphan { display: inline-block; margin-left: 4px; padding: 1px 6px; background: rgba(var(--status-warning-rgb), 0.18); color: var(--status-warning); border-radius: 4px; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; } /* System index — inline Storage summary (donut + legend + reclaimable), links through to the full breakdown page. */ .sys-storage-summary { margin-top: 10px; display: flex; align-items: center; gap: 24px; background: var(--card-bg); border: 1px solid rgba(var(--text-rgb), 0.10); border-radius: 14px; padding: 18px 22px; } @media (max-width: 700px) { .sys-storage-summary { flex-direction: column; align-items: stretch; gap: 16px; } } .sys-storage-summary-donut { all: unset; display: block; flex-shrink: 0; cursor: pointer; border-radius: 50%; transition: transform .15s ease, filter .15s ease; } .sys-storage-summary-donut:hover { transform: scale(1.03); filter: drop-shadow(0 4px 14px rgba(var(--accent-rgb), 0.25)); } .sys-storage-summary-donut:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; } .sys-storage-summary-donut .sys-storage-donut { width: 148px; height: 148px; } .sys-storage-summary-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 14px; } .sys-storage-srows { display: flex; flex-direction: column; gap: 9px; } .sys-storage-srow { display: grid; grid-template-columns: 12px auto minmax(60px, 1fr) auto; align-items: center; gap: 10px; font-size: 0.85rem; } .sys-storage-srow-k { color: var(--text-primary); font-weight: 600; } .sys-storage-srow-bar { min-width: 0; } .sys-storage-srow-bar .lp-bar { width: 100%; max-width: none; } .sys-storage-srow-v { color: rgba(var(--text-rgb), 0.65); font-variant-numeric: tabular-nums; text-align: right; } .sys-storage-summary-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; border-top: 1px solid rgba(var(--text-rgb), 0.08); padding-top: 13px; } .sys-storage-recl-pill { font-size: 0.78rem; font-weight: 600; color: var(--status-warning); background: rgba(var(--status-warning-rgb), 0.12); border: 1px solid rgba(var(--status-warning-rgb), 0.28); padding: 4px 11px; border-radius: 999px; } .sys-storage-more { all: unset; cursor: pointer; font-size: 0.82rem; font-weight: 600; color: var(--accent); transition: opacity .15s ease; } .sys-storage-more:hover { opacity: 0.78; text-decoration: underline; } .sys-storage-more:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; } .sys-storage-summary-empty { justify-content: space-between; color: rgba(var(--text-rgb), 0.55); font-size: 0.9rem; }