Polish modals and add settings save button feedback
Release rolling / release (push) Has been cancelled

Replace stock Bootstrap modal chrome with a dark teal panel system, and
give Settings Save all a Saving… / Saved state with motion-aware styles.
This commit is contained in:
Raven Scott
2026-07-16 15:38:29 -04:00
parent 2b1b40e967
commit fbe1751468
5 changed files with 710 additions and 58 deletions
+2 -2
View File
@@ -2995,8 +2995,8 @@ services:
</div><!-- /.settings-page-scroll --> </div><!-- /.settings-page-scroll -->
<div class="settings-footer" role="toolbar" aria-label="Settings actions"> <div class="settings-footer" role="toolbar" aria-label="Settings actions">
<button type="button" class="btn btn-primary settings-save-btn" id="settings-save-btn"> <button type="button" class="btn btn-primary settings-save-btn" id="settings-save-btn" aria-live="polite">
<i class="fas fa-floppy-disk me-1" aria-hidden="true"></i>Save all <i class="fas fa-floppy-disk me-1" aria-hidden="true"></i><span class="settings-save-label">Save all</span>
</button> </button>
</div> </div>
</div> </div>
+543 -30
View File
@@ -2909,27 +2909,535 @@ table.pd-col-table td.pd-col-hidden {
} }
} }
.card, .card {
.modal-content {
background: var(--bg-elevated) !important; background: var(--bg-elevated) !important;
border: 1px solid var(--border-color) !important; border: 1px solid var(--border-color) !important;
border-radius: var(--border-radius) !important; border-radius: var(--border-radius) !important;
color: var(--text-primary); color: var(--text-primary);
} }
.modal-header { /* ═══════════════════════════════════════════════════════════
border-bottom-color: var(--border-color) !important; Modal design system — polished panels matching app chrome
padding: 16px 20px; ═══════════════════════════════════════════════════════════ */
.modal-backdrop {
background: rgba(2, 6, 23, 0.78) !important;
backdrop-filter: blur(12px) saturate(1.15);
-webkit-backdrop-filter: blur(12px) saturate(1.15);
} }
.modal-footer { .modal-backdrop.show {
border-top-color: var(--border-color) !important; opacity: 1 !important;
padding: 14px 20px; }
/* Entrance: soft rise + scale (pairs with Bootstrap fade) */
.modal.fade .modal-dialog {
transform: translateY(14px) scale(0.97);
transition:
transform 0.22s cubic-bezier(0.22, 1, 0.36, 1),
opacity 0.2s ease;
}
.modal.show .modal-dialog {
transform: none;
}
.modal-dialog {
margin-top: max(1.25rem, calc(var(--titlebar-h, 42px) + 0.65rem));
margin-bottom: 1.25rem;
}
.modal-dialog-centered {
margin-top: auto;
margin-bottom: auto;
}
.modal-content {
--pd-modal-pad-x: 1.35rem;
background:
radial-gradient(900px 280px at 12% -20%, rgba(52, 211, 153, 0.1), transparent 55%),
radial-gradient(700px 240px at 100% 0%, rgba(45, 212, 191, 0.06), transparent 50%),
linear-gradient(168deg, #1a2433 0%, #121a24 48%, #0d131c 100%) !important;
border: 1px solid rgba(255, 255, 255, 0.09) !important;
border-radius: 16px !important;
color: var(--text-primary) !important;
box-shadow:
0 28px 64px rgba(0, 0, 0, 0.58),
0 0 0 1px rgba(52, 211, 153, 0.07),
inset 0 1px 0 rgba(255, 255, 255, 0.045);
overflow: hidden;
}
.modal-content.bg-dark {
background:
radial-gradient(900px 280px at 12% -20%, rgba(52, 211, 153, 0.1), transparent 55%),
radial-gradient(700px 240px at 100% 0%, rgba(45, 212, 191, 0.06), transparent 50%),
linear-gradient(168deg, #1a2433 0%, #121a24 48%, #0d131c 100%) !important;
}
/* ── Header ── */
.modal-header {
position: relative;
display: flex;
align-items: center;
gap: 0.75rem;
background: transparent !important;
border-bottom: 1px solid rgba(255, 255, 255, 0.06) !important;
padding: 1.15rem var(--pd-modal-pad-x, 1.35rem) 1rem !important;
min-height: 3.65rem;
}
.modal-header.border-secondary,
.modal-footer.border-secondary {
border-color: rgba(255, 255, 255, 0.06) !important;
}
.modal-header::after {
content: '';
position: absolute;
left: var(--pd-modal-pad-x, 1.35rem);
right: var(--pd-modal-pad-x, 1.35rem);
bottom: -1px;
height: 1px;
background: linear-gradient(
90deg,
rgba(52, 211, 153, 0.5) 0%,
rgba(52, 211, 153, 0.12) 42%,
transparent 88%
);
pointer-events: none;
} }
.modal-title { .modal-title {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.55rem;
margin: 0;
font-size: 1.05rem;
font-weight: 700;
letter-spacing: -0.025em;
line-height: 1.3;
color: var(--text-primary) !important;
}
/* Icon chip in titles — matches page-header accent treatment */
.modal-title > i,
.modal-title > .fas,
.modal-title > .far,
.modal-title > .fab,
.modal-title > .fa {
flex: 0 0 auto;
width: 1.85rem;
height: 1.85rem;
margin: 0 !important;
display: inline-grid;
place-items: center;
font-size: 0.82rem;
border-radius: 9px;
color: var(--accent-primary) !important;
background: rgba(52, 211, 153, 0.12);
border: 1px solid rgba(52, 211, 153, 0.2);
box-shadow: 0 0 0 1px rgba(52, 211, 153, 0.04);
}
/* ── Close control ── */
.modal-header .btn-close,
.modal-header .btn-close-white {
width: 2rem;
height: 2rem;
padding: 0;
margin: 0 0 0 auto;
border-radius: 10px;
box-sizing: border-box;
opacity: 0.72;
background-color: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
background-size: 0.62em;
transition:
opacity 0.15s ease,
background-color 0.15s ease,
border-color 0.15s ease,
transform 0.12s ease;
}
.modal-header .btn-close-white {
filter: invert(1) grayscale(100%) brightness(200%);
}
.modal-header .btn-close:hover,
.modal-header .btn-close-white:hover,
.modal-header .btn-close:focus {
opacity: 1;
background-color: rgba(248, 113, 113, 0.12) !important;
border-color: rgba(248, 113, 113, 0.28);
box-shadow: none;
transform: scale(1.04);
}
.modal-header .btn-close:focus-visible {
outline: 2px solid rgba(52, 211, 153, 0.45);
outline-offset: 2px;
}
/* ── Body ── */
.modal-body {
background: transparent !important;
color: var(--text-secondary) !important;
padding: 1.2rem var(--pd-modal-pad-x, 1.35rem) 1.05rem !important;
line-height: 1.55;
}
.modal-body > p:last-child,
.modal-body > .mb-0:last-child {
margin-bottom: 0 !important;
}
.modal-body .text-muted,
.modal-body small,
.modal-body .form-text,
.modal-content .form-text {
color: var(--text-muted) !important;
font-size: 0.8rem;
line-height: 1.45;
}
.modal-body code {
font-family: var(--font-mono);
font-size: 0.82em;
padding: 0.1em 0.35em;
border-radius: 5px;
color: var(--accent-secondary);
background: rgba(45, 212, 191, 0.08);
border: 1px solid rgba(45, 212, 191, 0.14);
}
/* Form labels — refined, not Bootstrap default */
.modal-body .form-label {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.4rem;
margin-bottom: 0.4rem;
font-size: 0.8rem;
font-weight: 600;
letter-spacing: -0.01em;
color: var(--text-secondary) !important;
}
.modal-body .form-label .text-danger {
font-weight: 700;
}
.modal-body .form-label .text-muted {
font-weight: 500;
font-size: 0.78em;
}
/* Inputs sit slightly recessed in the panel */
.modal-body .form-control,
.modal-body .form-select,
.modal-content .form-control,
.modal-content .form-select {
background: rgba(0, 0, 0, 0.28) !important;
border: 1px solid rgba(255, 255, 255, 0.09) !important;
border-radius: 10px !important;
color: var(--text-primary) !important;
min-height: 2.45rem;
padding: 0.55rem 0.8rem;
font-size: 0.9rem;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.02);
transition:
border-color 0.15s ease,
box-shadow 0.15s ease,
background 0.15s ease;
}
.modal-body textarea.form-control {
min-height: 5rem;
line-height: 1.45;
padding-top: 0.65rem;
padding-bottom: 0.65rem;
}
.modal-body .form-control:hover,
.modal-body .form-select:hover,
.modal-content .form-control:hover,
.modal-content .form-select:hover {
border-color: rgba(52, 211, 153, 0.28) !important;
background: rgba(0, 0, 0, 0.34) !important;
}
.modal-body .form-control:focus,
.modal-body .form-select:focus,
.modal-content .form-control:focus,
.modal-content .form-select:focus {
border-color: rgba(52, 211, 153, 0.55) !important;
background: rgba(0, 0, 0, 0.36) !important;
box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.14) !important;
color: var(--text-primary) !important;
}
.modal-body .form-control::placeholder {
color: var(--text-faint);
opacity: 0.9;
}
.modal-body .form-control.font-monospace,
.modal-body .form-select.font-monospace {
font-family: var(--font-mono);
font-size: 0.84rem;
letter-spacing: -0.01em;
}
.modal-body .input-group .form-control {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
.modal-body .input-group .btn {
font-weight: 600;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
}
.modal-body .form-check-input {
background-color: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.14);
cursor: pointer;
}
.modal-body .form-switch .form-check-input {
width: 2.4rem;
height: 1.25rem;
margin-top: 0.12rem;
}
.modal-body .form-check-input:checked {
background-color: var(--accent-primary);
border-color: var(--accent-primary);
}
.modal-body .form-check-input:focus {
box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.18);
border-color: rgba(52, 211, 153, 0.45);
}
.modal-body .form-check-label {
color: var(--text-secondary);
font-size: 0.9rem;
cursor: pointer;
}
/* Section titles inside large forms (duplicate / deploy) */
.modal-body h6 {
display: flex;
align-items: center;
gap: 0.5rem;
margin: 0.35rem 0 0.95rem;
padding-bottom: 0.65rem;
font-size: 0.88rem;
font-weight: 650; font-weight: 650;
letter-spacing: -0.02em; letter-spacing: -0.015em;
color: var(--text-primary) !important;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.modal-body h6 i {
color: var(--accent-primary);
font-size: 0.85em;
opacity: 0.95;
}
.modal-body h6.text-primary {
color: var(--text-primary) !important;
}
/* Grouped form sections (h6 + fields) read as soft cards */
.modal-body .mb-3 {
margin-bottom: 1rem !important;
}
.modal-body > form > .mb-4,
.modal-body > .mb-4 {
margin-bottom: 1.15rem !important;
padding: 0.9rem 1rem;
border-radius: 12px;
background: rgba(255, 255, 255, 0.018);
border: 1px solid rgba(255, 255, 255, 0.05);
}
.modal-body > form > .mb-4 > h6,
.modal-body > .mb-4 > h6 {
margin-top: 0;
}
/* ── Footer ── */
.modal-footer {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
gap: 0.55rem;
background: linear-gradient(180deg, rgba(0, 0, 0, 0.12) 0%, rgba(0, 0, 0, 0.28) 100%) !important;
border-top: 1px solid rgba(255, 255, 255, 0.06) !important;
padding: 0.9rem var(--pd-modal-pad-x, 1.35rem) !important;
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
.modal-footer > * {
margin: 0 !important; /* kill Bootstrap .btn + .btn spacing */
}
.modal-footer .btn {
border-radius: 10px;
min-height: 2.4rem;
padding: 0.45rem 1.05rem;
font-weight: 600;
font-size: 0.875rem;
letter-spacing: -0.01em;
}
/* Cancel / secondary CTAs read as quiet companions to primary */
.modal-footer .btn-secondary {
background: transparent !important;
border: 1px solid rgba(255, 255, 255, 0.12) !important;
color: var(--text-secondary) !important;
box-shadow: none;
}
.modal-footer .btn-secondary:hover,
.modal-footer .btn-secondary:focus {
background: rgba(255, 255, 255, 0.06) !important;
border-color: rgba(255, 255, 255, 0.2) !important;
color: var(--text-primary) !important;
}
.modal-footer .btn-primary {
box-shadow: 0 4px 16px rgba(52, 211, 153, 0.22);
}
.modal-footer .btn-primary:hover {
box-shadow: 0 6px 20px rgba(52, 211, 153, 0.3);
}
.modal-footer .btn-danger {
box-shadow: 0 4px 14px rgba(248, 113, 113, 0.18);
}
/* Compact / large variants */
.modal-sm .modal-content {
border-radius: 14px !important;
}
.modal-sm .modal-header,
.modal-sm .modal-body,
.modal-sm .modal-footer {
--pd-modal-pad-x: 1.15rem;
}
.modal-lg .modal-content,
.modal-xl .modal-content {
--pd-modal-pad-x: 1.5rem;
}
/* Scrollable bodies keep header/footer chrome intact */
.modal-dialog-scrollable .modal-content {
max-height: calc(100vh - var(--titlebar-h, 42px) - 2.5rem);
}
.modal-dialog-scrollable .modal-body {
overscroll-behavior: contain;
}
/* Accordion inside modals (duplicate form etc.) */
.modal-body .accordion-item {
background: rgba(0, 0, 0, 0.18) !important;
border: 1px solid rgba(255, 255, 255, 0.06) !important;
border-radius: 10px !important;
overflow: hidden;
margin-bottom: 0.5rem;
}
.modal-body .accordion-button {
background: rgba(255, 255, 255, 0.02) !important;
font-size: 0.875rem;
font-weight: 600;
padding: 0.75rem 1rem;
}
.modal-body .accordion-body {
background: transparent;
padding: 0.85rem 1rem 1rem;
border-top: 1px solid rgba(255, 255, 255, 0.05);
}
/* Suggested badges in smart forms */
.modal-body .pd-suggested {
font-size: 0.68rem;
font-weight: 650;
letter-spacing: 0.04em;
text-transform: uppercase;
padding: 0.15rem 0.45rem;
border-radius: 999px;
color: var(--accent-primary);
background: rgba(52, 211, 153, 0.12);
border: 1px solid rgba(52, 211, 153, 0.22);
}
/* List groups in modals (Hub search) */
.modal-body .list-group-item {
background: rgba(0, 0, 0, 0.2) !important;
border-color: rgba(255, 255, 255, 0.06) !important;
color: var(--text-secondary);
}
.modal-body .list-group-item-action:hover {
background: rgba(52, 211, 153, 0.08) !important;
color: var(--text-primary) !important;
}
/* Terminal toolbar strip under header */
.modal-content > .terminal-toolbar {
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
background: rgba(0, 0, 0, 0.18);
}
/* Quiet scrollbars in modal bodies */
.modal-body::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.modal-body::-webkit-scrollbar-track {
background: transparent;
}
.modal-body::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.12);
border-radius: 999px;
border: 2px solid transparent;
background-clip: padding-box;
}
.modal-body::-webkit-scrollbar-thumb:hover {
background: rgba(52, 211, 153, 0.35);
background-clip: padding-box;
border: 2px solid transparent;
}
/* Inspect modals: pre blocks feel like code panels */
.modal-body pre {
background: rgba(0, 0, 0, 0.35) !important;
border: 1px solid rgba(255, 255, 255, 0.07);
border-radius: 10px;
padding: 0.85rem 1rem;
color: var(--text-secondary);
font-size: 0.8rem;
line-height: 1.5;
} }
.accordion-item { .accordion-item {
@@ -3377,16 +3885,22 @@ table.pd-col-table td.pd-col-hidden {
/* ── Container more-actions modal ── */ /* ── Container more-actions modal ── */
.cam-modal { .cam-modal {
border: 1px solid var(--border-strong); /* inherits modal design system surface; only layout overrides here */
border-radius: 16px; border-radius: 16px !important;
background: var(--bg-elevated) !important;
box-shadow: var(--shadow-lg);
} }
.cam-header { .cam-header {
align-items: flex-start; align-items: flex-start;
} }
.cam-header::after {
display: none; /* subtitle sits under title; no accent line needed */
}
.cam-modal .modal-body.cam-body {
padding-top: 0.85rem !important;
}
.cam-header-text { .cam-header-text {
min-width: 0; min-width: 0;
padding-right: 0.5rem; padding-right: 0.5rem;
@@ -4161,18 +4675,13 @@ kbd {
background-color: var(--bg-hover) !important; background-color: var(--bg-hover) !important;
} }
/* Accordion / forms in modals */ /* Accordion body text (modal body colors owned by modal design system) */
.accordion-body, .accordion-body,
.accordion-body .text-muted, .accordion-body .text-muted {
.modal-body,
.modal-body .text-muted,
.modal-content .form-text,
.modal-content small {
color: var(--text-muted); color: var(--text-muted);
} }
.accordion-body, .accordion-body {
.modal-body {
color: var(--text-primary); color: var(--text-primary);
} }
@@ -4603,15 +5112,7 @@ td.image-update-cell {
box-shadow: 0 4px 14px rgba(52, 211, 153, 0.28); box-shadow: 0 4px 14px rgba(52, 211, 153, 0.28);
} }
/* Modal footer buttons stay readable on dark modals */ /* Close buttons: detailed styles live in the modal design system above */
.modal-content.bg-dark .btn-close-white {
filter: invert(1) grayscale(100%) brightness(200%);
opacity: 0.75;
}
.modal-content.bg-dark .btn-close-white:hover {
opacity: 1;
}
/* List-group dark actions used in Hub search / volume browser */ /* List-group dark actions used in Hub search / volume browser */
.list-group-item-dark, .list-group-item-dark,
@@ -5092,6 +5593,18 @@ option {
margin-right: auto; margin-right: auto;
} }
.modal-dialog.modal-sm {
--bs-modal-width: 380px;
}
.modal-dialog.modal-lg {
--bs-modal-width: 800px;
}
.modal-dialog.modal-xl {
--bs-modal-width: 1140px;
}
.modal-content { .modal-content {
max-width: 100%; max-width: 100%;
} }
+60 -8
View File
@@ -2195,14 +2195,66 @@ export function initOpsApp({ navigateToView, sendCommand }) {
showSettingsTab(btn.getAttribute('data-settings-tab')) showSettingsTab(btn.getAttribute('data-settings-tab'))
}) })
document.getElementById('settings-save-btn')?.addEventListener('click', () => { document.getElementById('settings-save-btn')?.addEventListener('click', (e) => {
setTemplateListUrls(templateUrlsDraft) const btn = e.currentTarget
const partial = readSettingsForm() if (btn?.classList.contains('is-saving') || btn?.classList.contains('is-saved')) return
partial.templateListUrls = getTemplateListUrls()
const next = saveSettings(partial) const idleHtml =
startListAutoRefresh(next.refreshSeconds) btn.dataset.idleHtml ||
if (typeof window !== 'undefined') window.__peardockClearDeployTemplateCache?.() '<i class="fas fa-floppy-disk me-1" aria-hidden="true"></i><span class="settings-save-label">Save all</span>'
showAlert('success', 'Preferences saved', { badge: false }) if (btn) btn.dataset.idleHtml = idleHtml
clearTimeout(btn?._saveFeedbackTimer)
if (btn) {
btn.classList.remove('is-saved', 'is-error')
btn.classList.add('is-saving')
btn.disabled = true
btn.setAttribute('aria-busy', 'true')
btn.innerHTML =
'<i class="fas fa-circle-notch fa-spin me-1" aria-hidden="true"></i><span class="settings-save-label">Saving…</span>'
}
// Brief saving state so the control always gives tactile feedback (save is local/sync).
const finish = (ok, errMsg) => {
if (!btn) return
btn.classList.remove('is-saving')
btn.removeAttribute('aria-busy')
if (ok) {
btn.classList.add('is-saved')
btn.innerHTML =
'<i class="fas fa-check me-1 settings-save-check" aria-hidden="true"></i><span class="settings-save-label">Saved</span>'
btn._saveFeedbackTimer = setTimeout(() => {
btn.classList.remove('is-saved')
btn.disabled = false
btn.innerHTML = btn.dataset.idleHtml || idleHtml
}, 2000)
} else {
btn.classList.add('is-error')
btn.disabled = false
btn.innerHTML =
'<i class="fas fa-triangle-exclamation me-1" aria-hidden="true"></i><span class="settings-save-label">Failed</span>'
btn._saveFeedbackTimer = setTimeout(() => {
btn.classList.remove('is-error')
btn.innerHTML = btn.dataset.idleHtml || idleHtml
}, 2400)
if (errMsg) showAlert('danger', errMsg, { badge: false })
}
}
window.setTimeout(() => {
try {
setTemplateListUrls(templateUrlsDraft)
const partial = readSettingsForm()
partial.templateListUrls = getTemplateListUrls()
const next = saveSettings(partial)
startListAutoRefresh(next.refreshSeconds)
if (typeof window !== 'undefined') window.__peardockClearDeployTemplateCache?.()
finish(true)
showAlert('success', 'Preferences saved', { badge: false })
} catch (err) {
finish(false, err?.message || 'Could not save preferences')
}
}, 220)
}) })
document.getElementById('settings-template-url-add')?.addEventListener('click', () => { document.getElementById('settings-template-url-add')?.addEventListener('click', () => {
+82
View File
@@ -986,6 +986,16 @@
font-weight: 600; font-weight: 600;
border-radius: 0.55rem; border-radius: 0.55rem;
box-shadow: 0 6px 18px rgba(45, 212, 191, 0.22); box-shadow: 0 6px 18px rgba(45, 212, 191, 0.22);
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.15rem;
transition:
background-color 0.18s ease,
border-color 0.18s ease,
box-shadow 0.18s ease,
color 0.18s ease,
transform 0.15s ease;
} }
#settings-view .settings-footer .settings-save-btn:hover, #settings-view .settings-footer .settings-save-btn:hover,
@@ -993,6 +1003,78 @@
box-shadow: 0 8px 22px rgba(45, 212, 191, 0.32); box-shadow: 0 8px 22px rgba(45, 212, 191, 0.32);
} }
#settings-view .settings-footer .settings-save-btn:disabled {
opacity: 1;
cursor: default;
}
/* Saving… spinner state */
#settings-view .settings-footer .settings-save-btn.is-saving {
pointer-events: none;
background: linear-gradient(135deg, #2dd4bf 0%, #14b8a6 100%) !important;
border-color: transparent !important;
color: #042f1a !important;
box-shadow: 0 4px 14px rgba(45, 212, 191, 0.28);
}
/* Saved — success flash */
#settings-view .settings-footer .settings-save-btn.is-saved {
pointer-events: none;
background: linear-gradient(135deg, #4ade80 0%, #22c55e 100%) !important;
border-color: transparent !important;
color: #052e16 !important;
box-shadow:
0 0 0 1px rgba(74, 222, 128, 0.35),
0 8px 24px rgba(34, 197, 94, 0.35);
animation: settings-save-pop 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
#settings-view .settings-footer .settings-save-btn.is-saved .settings-save-check {
animation: settings-save-check-in 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
/* Failed */
#settings-view .settings-footer .settings-save-btn.is-error {
background: linear-gradient(135deg, #f87171 0%, #ef4444 100%) !important;
border-color: transparent !important;
color: #450a0a !important;
box-shadow: 0 6px 18px rgba(248, 113, 113, 0.3);
}
@keyframes settings-save-pop {
0% {
transform: scale(0.96);
}
55% {
transform: scale(1.04);
}
100% {
transform: scale(1);
}
}
@keyframes settings-save-check-in {
0% {
transform: scale(0.4);
opacity: 0;
}
60% {
transform: scale(1.15);
opacity: 1;
}
100% {
transform: scale(1);
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
#settings-view .settings-footer .settings-save-btn.is-saved,
#settings-view .settings-footer .settings-save-btn.is-saved .settings-save-check {
animation: none;
}
}
/* Network card disconnect control alignment */ /* Network card disconnect control alignment */
.network-card-header { .network-card-header {
display: flex; display: flex;
+23 -18
View File
@@ -2838,39 +2838,44 @@
color: var(--text-primary); color: var(--text-primary);
} }
/* Modal Styling */ /* Modal Styling — base layer (modern.css extends the full system) */
.modal-content { .modal-content {
background: var(--bg-secondary); background: linear-gradient(165deg, #1a2332 0%, #121820 50%, #0e141c 100%);
border: 1px solid var(--border-color); border: 1px solid rgba(255, 255, 255, 0.09);
border-radius: var(--border-radius); border-radius: 16px;
box-shadow: var(--shadow-xl); box-shadow:
backdrop-filter: blur(10px); 0 28px 64px rgba(0, 0, 0, 0.55),
0 0 0 1px rgba(45, 212, 191, 0.06),
inset 0 1px 0 rgba(255, 255, 255, 0.04);
overflow: hidden;
} }
.modal-header { .modal-header {
background: var(--bg-elevated); background: transparent;
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid rgba(255, 255, 255, 0.06);
border-radius: var(--border-radius) var(--border-radius) 0 0; border-radius: 0;
padding: var(--spacing-lg); padding: 1.15rem 1.35rem 1rem;
} }
.modal-title { .modal-title {
color: var(--text-primary); color: var(--text-primary);
font-weight: 600; font-weight: 700;
font-size: 1.25rem; font-size: 1.05rem;
letter-spacing: -0.025em;
} }
.modal-body { .modal-body {
background: var(--bg-secondary); background: transparent;
color: var(--text-secondary); color: var(--text-secondary);
padding: var(--spacing-lg); padding: 1.25rem 1.35rem 1.1rem;
} }
.modal-footer { .modal-footer {
background: var(--bg-elevated); background: rgba(0, 0, 0, 0.22);
border-top: 1px solid var(--border-color); border-top: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 0 0 var(--border-radius) var(--border-radius); border-radius: 0;
padding: var(--spacing-lg); padding: 0.9rem 1.35rem;
gap: 0.55rem;
} }
.btn-close-white { .btn-close-white {