Files
oikos/public/styles/glass.css
T
Ulas 5a2bc5cdb1 fix: Safari < 18 glass UI - webkit backdrop-filter @supports fallback
- All @supports checks extended to include or (-webkit-backdrop-filter: blur(1px))
  so Safari < 18 (which only recognizes the -webkit- prefix) no longer skips
  the entire @supports block and receives no glass styles at all
- Non-blur glass styles (background-color, border, box-shadow) moved outside
  @supports blocks - always active on all browsers regardless of blur support
- Capsule buttons, specular highlights, glass borders and shadows now visible
  on all devices, blur effects added on top where supported
2026-04-13 22:02:23 +02:00

491 lines
15 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Modul: Liquid Glass - Shell Components (Phase 13)
* Zweck: Glass-Effekte für Navigation, Modal, Buttons, FAB, Animationen
* Rein additiv: überschreibt nur optische Eigenschaften,
* keine Layout-, Größen- oder Funktionsänderungen.
* Abhängigkeiten: tokens.css (Section 16 Glass-Tokens), layout.css
*
* Architektur:
* Nicht-Blur-Stile (background, border, shadow) sind AUSSERHALB von
* @supports gesetzt → wirken auf allen Geräten und Browsern.
* Blur-Filter (backdrop-filter) sind INNERHALB von @supports mit
* webkit-Fallback → greifen wenn vom Browser unterstützt.
* @supports-Check: (backdrop-filter) OR (-webkit-backdrop-filter)
* deckt Safari < 18 (nur webkit-Prefix) und moderne Browser ab.
*/
/* ================================================================
* 1. Bottom Navigation — Glass Bar
* ================================================================ */
/* Immer aktiv: Glass-Hintergrund, Border, Shadow */
.nav-bottom {
background-color: var(--glass-bg);
border-top: 1px solid var(--glass-border);
box-shadow: var(--glass-shadow-sm);
}
/* Blur nur wenn unterstützt (webkit-Fallback für Safari < 18) */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.nav-bottom {
backdrop-filter: var(--blur-md) saturate(180%);
-webkit-backdrop-filter: var(--blur-md) saturate(180%);
}
}
/* Active-State: Glass-Kapsel hinter aktivem Nav-Item */
.nav-item[aria-current="page"] {
background: color-mix(in srgb, var(--active-module-accent, var(--color-accent)) 14%, transparent);
border-radius: var(--radius-glass-chip);
box-shadow: inset 0 1px 0 var(--glass-highlight-subtle);
}
/* Hover-State auf Desktop */
@media (hover: hover) {
.nav-item:hover:not([aria-current="page"]) {
background: color-mix(in srgb, var(--color-text-tertiary) 8%, transparent);
border-radius: var(--radius-glass-chip);
}
}
/* ================================================================
* 2. Sidebar (Desktop ≥ 1024px) — Glass Panel
* ================================================================ */
@media (min-width: 1024px) {
.nav-sidebar {
background: var(--glass-bg-elevated);
border-right: 1px solid var(--glass-border);
box-shadow: var(--glass-shadow-md);
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.nav-sidebar {
backdrop-filter: var(--blur-sm) saturate(160%);
-webkit-backdrop-filter: var(--blur-sm) saturate(160%);
}
}
/* Active-State in Sidebar */
.nav-sidebar .nav-item[aria-current="page"] {
background: color-mix(in srgb, var(--active-module-accent, var(--color-accent)) 12%, transparent);
border-radius: var(--radius-sm);
box-shadow: inset 0 1px 0 var(--glass-highlight-subtle);
}
}
/* ================================================================
* 3. Modal — Glass Overlay + Glass Panel
* ================================================================ */
/* Immer aktiv: stärkerer Schatten und Glass-Border */
.modal-panel {
border: 1px solid var(--glass-border);
box-shadow: var(--glass-shadow-lg);
}
.modal-panel__header {
border-bottom-color: var(--glass-border);
}
/* Blur nur wenn unterstützt */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.modal-overlay {
background-color: rgba(0, 0, 0, 0.30);
backdrop-filter: var(--blur-xs) saturate(120%);
-webkit-backdrop-filter: var(--blur-xs) saturate(120%);
}
.modal-panel {
background: var(--glass-bg-elevated);
backdrop-filter: var(--blur-sm);
-webkit-backdrop-filter: var(--blur-sm);
}
.modal-panel__header {
background: var(--glass-bg-elevated);
}
}
/* Bottom-Sheet Handle */
@media (max-width: 767px) {
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.modal-panel::before {
background: var(--glass-border);
}
}
}
/* ================================================================
* 4. Buttons — Capsule Shape + Specular Highlight
* ================================================================ */
.btn--primary {
border-radius: var(--radius-glass-button);
box-shadow:
var(--shadow-sm),
inset 0 1px 0 rgba(255, 255, 255, 0.22);
}
.btn--primary:hover {
box-shadow:
var(--shadow-md),
inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.btn--secondary {
border-radius: var(--radius-glass-button);
}
/* Ghost-Buttons */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.btn--ghost:hover {
background: color-mix(in srgb, var(--color-text-tertiary) 10%, transparent);
backdrop-filter: var(--blur-xs);
-webkit-backdrop-filter: var(--blur-xs);
}
}
/* ================================================================
* 5. FAB — Specular Highlight
* ================================================================ */
.fab {
box-shadow:
var(--shadow-lg),
inset 0 1px 0 rgba(255, 255, 255, 0.28),
inset 0 -1px 0 rgba(0, 0, 0, 0.12);
}
.fab:hover {
box-shadow:
var(--shadow-lg),
inset 0 1px 0 rgba(255, 255, 255, 0.32),
inset 0 -1px 0 rgba(0, 0, 0, 0.16);
}
/* ================================================================
* 6. Cards — Glass auf hover (nur interaktive Cards)
* ================================================================ */
@media (hover: hover) {
.card--interactive:hover {
border: 1px solid var(--glass-border-subtle);
box-shadow: var(--glass-shadow-md);
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.card--interactive:hover {
background: var(--glass-bg-hover);
backdrop-filter: var(--blur-xs);
-webkit-backdrop-filter: var(--blur-xs);
}
}
}
/* ================================================================
* 7. Accessibility Overrides — Phase 1
* ================================================================ */
@media (prefers-reduced-transparency: reduce) {
.nav-item[aria-current="page"],
.nav-item:hover:not([aria-current="page"]) {
box-shadow: none;
}
.btn--primary,
.btn--primary:hover,
.fab,
.fab:hover {
box-shadow: var(--shadow-sm);
}
}
@media (prefers-reduced-motion: reduce) {
.nav-item,
.nav-sidebar .nav-item,
.btn,
.fab,
.card--interactive {
transition-duration: 0.01ms !important;
}
}
/* ================================================================
* PHASE 2 — Modul-Komponenten
* ================================================================ */
/* ================================================================
* 8. Form-Inputs — Glass Border + verbesserter Focus-Ring
* ================================================================ */
.input,
.form-input,
select.form-input,
textarea.form-input {
border-color: var(--glass-border-subtle);
background-color: color-mix(in srgb, var(--color-surface) 95%, transparent);
}
.input:focus,
.form-input:focus {
border-color: var(--color-accent);
box-shadow:
0 0 0 3px color-mix(in srgb, var(--color-accent) 20%, transparent),
inset 0 1px 2px rgba(0, 0, 0, 0.04);
}
/* ================================================================
* 9. Toasts — Glass + Capsule
* ================================================================ */
.toast {
border-radius: var(--radius-glass-card);
box-shadow: var(--glass-shadow-md);
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.toast:not(.toast--success):not(.toast--danger):not(.toast--warning) {
background-color: color-mix(in srgb, var(--neutral-800) 90%, transparent);
backdrop-filter: var(--blur-sm);
-webkit-backdrop-filter: var(--blur-sm);
border: 1px solid rgba(255, 255, 255, 0.10);
}
}
.toast--success,
.toast--danger,
.toast--warning {
border-radius: var(--radius-glass-card);
box-shadow:
var(--glass-shadow-md),
inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
/* ================================================================
* 10. Filter-Chips — Glass Border (immer aktiv)
* Aktiver Glass-State: direkt in tasks.css (Load-Order-Konflikt)
* ================================================================ */
.filter-chip {
border-color: var(--glass-border-subtle);
}
.filter-chip:hover:not(.filter-chip--active) {
border-color: var(--glass-border);
background-color: color-mix(in srgb, var(--color-text-tertiary) 8%, transparent);
}
/* ================================================================
* 11. Priority Badges — Capsule + Glass Border
* Immer aktiv (kein backdrop-filter nötig)
* ================================================================ */
.nav-badge {
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.20);
}
/* ================================================================
* 12. Toggle-Switch — Specular Thumb
* ================================================================ */
.toggle__track::after {
box-shadow:
var(--shadow-sm),
inset 0 1px 0 rgba(255, 255, 255, 0.90),
inset 0 -1px 0 rgba(0, 0, 0, 0.08);
}
.toggle input:checked + .toggle__track::after {
transition: transform var(--transition-glass);
}
/* ================================================================
* 13. FAB-Backdrop (Dashboard) — Glass Blur
* ================================================================ */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.fab-backdrop--visible {
backdrop-filter: var(--blur-xs);
-webkit-backdrop-filter: var(--blur-xs);
background: rgba(0, 0, 0, 0.18);
}
}
/* ================================================================
* 14. Dashboard-Widgets — Glass Cards
* Glass-Styles direkt in dashboard.css (Load-Order-Konflikt)
* ================================================================ */
/* ================================================================
* 15. Modal-Inputs
* ================================================================ */
.modal-panel .form-input,
.modal-panel .input {
background-color: var(--color-surface-2);
}
/* ================================================================
* 16. Accessibility — Phase 2
* ================================================================ */
@media (prefers-reduced-transparency: reduce) {
.filter-chip--active,
.toast:not(.toast--success):not(.toast--danger):not(.toast--warning) {
background-color: var(--color-accent-light);
border-color: var(--color-accent);
backdrop-filter: none;
-webkit-backdrop-filter: none;
}
}
@media (prefers-reduced-motion: reduce) {
.toggle__track::after {
transition: none;
}
.toast {
animation-duration: 0.01ms !important;
}
}
/* ================================================================
* PHASE 3 — Micro-Interactions + Polish
* ================================================================ */
/* ================================================================
* 17. Bottom-Nav Auto-Hide on Scroll
* ================================================================ */
.nav-bottom {
transition:
transform var(--transition-base) var(--ease-out),
background-color var(--transition-fast),
box-shadow var(--transition-fast);
will-change: transform;
}
.nav-bottom--hidden {
transform: translateY(calc(100% + var(--safe-area-inset-bottom)));
pointer-events: none;
}
/* ================================================================
* 18. Modal-Entrance — Glass Spring
* ================================================================ */
@keyframes glass-modal-scale-in {
from {
opacity: 0;
transform: scale(0.90) translateY(8px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
@keyframes glass-sheet-in {
from {
opacity: 0.6;
transform: translateY(40%);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (min-width: 768px) {
.modal-panel {
animation: glass-modal-scale-in 0.32s var(--ease-glass) forwards;
}
}
@media (max-width: 767px) {
.modal-panel {
animation: glass-sheet-in 0.30s var(--ease-glass) forwards;
}
}
/* ================================================================
* 19. Seitentransitionen — Spring Easing
* ================================================================ */
.page-transition--in-right,
.page-transition--in-left {
animation-duration: 0.30s;
animation-timing-function: var(--ease-glass);
}
.page-transition--out-left,
.page-transition--out-right {
animation-duration: 0.14s;
animation-timing-function: var(--ease-out);
}
/* ================================================================
* 20. List-Stagger — Spring Timing
* ================================================================ */
.list-stagger > * {
animation-duration: 0.28s;
animation-timing-function: var(--ease-glass);
}
/* ================================================================
* 21. Focus-Ring — Scale-In Animation
* ================================================================ */
:focus-visible {
transition:
box-shadow var(--transition-fast),
outline-offset var(--transition-fast);
outline-offset: 3px;
}
/* ================================================================
* 22. Skeleton Shimmer — Glass Shimmer
* ================================================================ */
.skeleton {
background: linear-gradient(
105deg,
var(--color-border-subtle) 0%,
var(--color-border-subtle) 30%,
color-mix(in srgb, var(--color-surface) 90%, var(--glass-highlight)) 50%,
var(--color-border-subtle) 70%,
var(--color-border-subtle) 100%
);
background-size: 250% 100%;
}
/* ================================================================
* 23. FAB — Attention Pulse
* ================================================================ */
@keyframes fab-ring-pulse {
0% { box-shadow: var(--shadow-lg), inset 0 1px 0 rgba(255,255,255,0.28), 0 0 0 0 color-mix(in srgb, var(--module-accent, var(--color-btn-primary)) 50%, transparent); }
60% { box-shadow: var(--shadow-lg), inset 0 1px 0 rgba(255,255,255,0.28), 0 0 0 10px transparent; }
100% { box-shadow: var(--shadow-lg), inset 0 1px 0 rgba(255,255,255,0.28), 0 0 0 0 transparent; }
}
.fab {
animation:
fab-in 0.35s var(--ease-out) backwards,
fab-ring-pulse 0.6s var(--ease-out) 0.4s 1 backwards;
}
/* ================================================================
* 24. Accessibility — Phase 3
* ================================================================ */
@media (prefers-reduced-motion: reduce) {
.nav-bottom {
transition: none;
}
.nav-bottom--hidden {
transition: none;
}
.modal-panel {
animation: none;
}
.page-transition--in-right,
.page-transition--in-left,
.page-transition--out-left,
.page-transition--out-right {
animation-duration: 0.01ms !important;
}
.list-stagger > * {
animation-duration: 0.01ms !important;
}
.fab {
animation: none;
}
}