feat(web): reusable accessible Modal (portal, focus trap, scroll lock)

Pressing Plant styled modal — ESC + backdrop close, Tab focus trap, body
scroll lock, focus restore, reduced-motion. Foundation for album/artist modals.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jonathan
2026-07-12 15:12:36 +02:00
parent 3f29ac1930
commit 3284059aba
2 changed files with 107 additions and 0 deletions
+32
View File
@@ -242,3 +242,35 @@ nav.contents .sep { flex: 1; }
}
.save-row { display: flex; align-items: center; gap: 14px; margin-top: 8px; }
.settings-section { margin-bottom: 30px; }
/* ── Modal ────────────────────────────────────────────── */
.modal-backdrop {
position: fixed; inset: 0; z-index: 100;
background: rgba(0, 0, 0, 0.55);
display: flex; align-items: flex-start; justify-content: center;
padding: 6vh 20px; overflow-y: auto;
animation: modal-fade 0.14s ease-out;
}
.modal-panel {
background: var(--paper-2); border: 1.5px solid var(--rule-2); width: 100%; max-width: 560px;
box-shadow: 0 24px 70px -24px rgba(0, 0, 0, 0.6); margin: auto 0;
animation: modal-rise 0.16s ease-out;
}
.modal-panel.wide { max-width: 780px; }
.modal-head {
display: flex; align-items: center; justify-content: space-between; gap: 16px;
padding: 15px 20px; border-bottom: 1px solid var(--rule);
}
.modal-title {
font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase;
color: var(--graphite); min-width: 0;
}
.modal-close {
background: transparent; border: 0; color: var(--graphite); cursor: pointer;
font-size: 0.95rem; line-height: 1; padding: 4px 6px;
}
.modal-close:hover { color: var(--ink); }
.modal-body { padding: 20px; }
@keyframes modal-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .modal-backdrop, .modal-panel { animation: none; } }