/** * Modul: Liquid Glass - Shell Components (Phase 1) * Zweck: Glass-Effekte für Navigation, Modal, Buttons, FAB * Rein additiv: überschreibt nur optische Eigenschaften, * keine Layout-, Größen- oder Funktionsänderungen. * Abhängigkeiten: tokens.css (Section 16 Glass-Tokens), layout.css * * Aufbau: * 1. Bottom Navigation * 2. Sidebar (Desktop) * 3. Modal (Overlay + Panel) * 4. Buttons (Capsule + Specular) * 5. FAB * 6. Karten (hover-only) * 7. Reduced-motion / Reduced-transparency Overrides */ /* ================================================================ * 1. Bottom Navigation — Glass Bar * * Upgrade von color-mix-Fallback auf --glass-* Tokens. * Bereits vorhandenes backdrop-filter wird auf Tokens umgestellt. * ================================================================ */ @supports (backdrop-filter: blur(1px)) { .nav-bottom { background-color: var(--glass-bg); backdrop-filter: var(--blur-md) saturate(180%); -webkit-backdrop-filter: var(--blur-md) saturate(180%); border-top: 1px solid var(--glass-border); box-shadow: var(--glass-shadow-sm); } } /* Active-State: Konzentrische 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 (falls Maus vorhanden) */ @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 * * backdrop-filter saturate() gibt dem Sidebar-Hintergrund einen * leichten Farbboost vom Content. blur() wirkt auf überlappenden * Content beim Scrollen in engen Layouts. * ================================================================ */ @media (min-width: 1024px) { @supports (backdrop-filter: blur(1px)) { .nav-sidebar { background: var(--glass-bg-elevated); backdrop-filter: var(--blur-sm) saturate(160%); -webkit-backdrop-filter: var(--blur-sm) saturate(160%); border-right: 1px solid var(--glass-border); box-shadow: var(--glass-shadow-md); } } /* Active-State in Sidebar: Glass Pill mit Akzentlinie */ .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 * * Overlay: leichter Page-Blur ("Tiefenschärfe"-Effekt) + * reduziertes Dimming (Glass braucht weniger Overlay-Dunkel). * Panel: Glass-Hintergrund mit --glass-bg-elevated + leichtem blur. * Header: Sticky-Header im Panel bekommt identisches Glass-BG. * ================================================================ */ @supports (backdrop-filter: blur(1px)) { .modal-overlay { /* Weniger Dimming, dafür Page-Blur für Tiefeneffekt */ 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); border: 1px solid var(--glass-border); box-shadow: var(--glass-shadow-lg); } /* Sticky-Header: identisches Glass-BG damit beim Scrollen der Blur-Layer nicht durch den Inhalt bricht */ .modal-panel__header { background: var(--glass-bg-elevated); border-bottom-color: var(--glass-border); } } /* Bottom-Sheet Handle: etwas prominenter auf Glass */ @media (max-width: 767px) { @supports (backdrop-filter: blur(1px)) { .modal-panel::before { background: var(--glass-border); } } } /* ================================================================ * 4. Buttons — Capsule Shape + Specular Highlight * * Primär-Button: Kapsel-Radius (--radius-glass-button = full) * + subtiles Specular-Highlight (inset box-shadow oben) * Sekundär-Button: leichte Glass-Border-Verfeinerung * ================================================================ */ .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 bekommen beim Hover ein leichtes Glass-Pill */ @supports (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 (Floating Action Button) — Specular Highlight * * Inset box-shadow erzeugt Specular-Highlight-Illusion (Lichtquelle * von oben) ohne Canvas-Manipulation oder SVG-Filter. * ================================================================ */ .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) * * .card--interactive bekommt beim Hover einen Glass-Lift: * leichter Blur + Glass-Border + erhöhter Schatten. * Nicht auf Touch-Geräten (hover: hover). * ================================================================ */ @media (hover: hover) { @supports (backdrop-filter: blur(1px)) { .card--interactive:hover { background: var(--glass-bg-hover); backdrop-filter: var(--blur-xs); -webkit-backdrop-filter: var(--blur-xs); border: 1px solid var(--glass-border-subtle); box-shadow: var(--glass-shadow-md); } } } /* ================================================================ * 7. Accessibility Overrides * * prefers-reduced-transparency: Tokens aus tokens.css schalten * backdrop-filter bereits ab. Hier zusätzliche Sicherheit für * Elemente, die ohne @supports-Guard arbeiten (Specular-Highlights). * * prefers-reduced-motion: Alle Glass-Transitionen deaktivieren. * (Animationen in layout.css mit animation: none bereits gedeckt, * hier nur Glass-spezifische Transitions.) * ================================================================ */ @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 * * Kein backdrop-filter auf Inputs (würde Inhalte hinter dem Input * in Modals unattraktiv unscharf rendern). Stattdessen: subtile * Glass-Border + abgestufter Focus-Glow via CSS-Shadow. * ================================================================ */ .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); } /* ================================================================ * 10. Toasts — Glass + Capsule * * Standard-Toast: Dark-Glass (neutrales --neutral-800 bleibt als * Fallback). Farbige Toasts (success/danger/warning) bekommen nur * den Capsule-Radius. * ================================================================ */ .toast { border-radius: var(--radius-glass-card); box-shadow: var(--glass-shadow-md); } @supports (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); } } /* Farbige Toasts: nur Capsule + specular, kein Blur */ .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); } /* ================================================================ * 11. Filter-Chips — Glass Active State * * Inaktiver Chip: glass border (subtil). * Aktiver Chip: voller Glass-Pip mit backdrop-filter + Accent-Tint. * ================================================================ */ .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); } @supports (backdrop-filter: blur(1px)) { .filter-chip--active { background: color-mix(in srgb, var(--color-accent) 18%, transparent); backdrop-filter: var(--blur-xs); -webkit-backdrop-filter: var(--blur-xs); border-color: color-mix(in srgb, var(--color-accent) 50%, transparent); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.20); } } /* ================================================================ * 12. Priority Badges — Capsule Radius + Glass Border * * Upgradet --radius-xs auf --radius-glass-chip (capsule) für einen * moderneren Look. Behält semantic colors bei. * ================================================================ */ .priority-badge { border-radius: var(--radius-glass-chip); border: 1px solid color-mix(in srgb, currentColor 25%, transparent); } /* Nav-Badge (Overdue-Indikator) */ .nav-badge { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.20); } /* ================================================================ * 13. Toggle-Switch — Specular Thumb * * Der weiße Thumb bekommt einen subtilen inset-Schatten der eine * Specular-Highlight-Illusion erzeugt (Lichtquelle von oben-rechts). * Die Animation verwendet bereits --ease-glass cubic-bezier. * ================================================================ */ .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); } /* ================================================================ * 14. Dashboard-Widgets — Glass Cards * * Glass-Styles (border, shadow, ::before highlight) direkt in * dashboard.css, da dieses Modul-CSS nach glass.css geladen wird * und sonst den box-shadow überschreiben würde. * ================================================================ */ /* ================================================================ * 15. FAB-Backdrop (Dashboard) — Glass Blur * * Der Overlay-Hintergrund beim Dashboard-FAB-Menü bekommt einen * dezenten Blur-Effekt für mehr Tiefe. * ================================================================ */ @supports (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); } } /* ================================================================ * 16. Search-Inputs (Modul-Toolbars) * * Modul-CSS wird on-demand nach glass.css geladen. Glass-Styles für * modul-spezifische Search-Inputs stehen daher in den jeweiligen * Modul-CSS-Dateien (contacts.css, notes.css, shopping.css). * Hier werden nur token-basierte Fallback-Regeln für generische Inputs * innerhalb von Modals definiert (via .modal-panel .form-input). * ================================================================ */ .modal-panel .form-input, .modal-panel .input { background-color: var(--color-surface-2); } /* ================================================================ * 17. Accessibility — Phase 2 Overrides * ================================================================ */ @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; } .sticky-header { background-color: var(--color-bg); 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 * ================================================================ */ /* ================================================================ * 18. Bottom-Nav Auto-Hide on Scroll * * .nav-bottom--hidden: Nav gleitet nach unten aus dem Viewport. * Per JS über scroll-Listener auf .app-content gesetzt. * FAB bleibt sichtbar (Daumen-Erreichbarkeit wichtiger als Konsistenz). * ================================================================ */ .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; } /* ================================================================ * 19. Modal-Entrance — Glass Spring * * Overlay: Blur-Ramp statt harten Fade (backdrop-filter via opacity). * Panel Desktop: Spring-Overshooting statt linearem scale-in. * Panel Mobile: Spring-Slide-up mit leichtem Bounce. * ================================================================ */ @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; } } /* ================================================================ * 20. Seitentransitionen — Spring Easing * * Ersetzt die festen 0.2s ease durch --transition-base + --ease-glass * für eine weichere, physikalisch plausible Bewegung. * ================================================================ */ .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); } /* ================================================================ * 21. List-Stagger — Spring Timing + erhöhter Offset * * Leicht längere Laufzeit + spring-Easing für einen * physikalischeren Erscheinungseffekt. * ================================================================ */ .list-stagger > * { animation-duration: 0.28s; animation-timing-function: var(--ease-glass); } /* ================================================================ * 22. Focus-Ring — Scale-In Animation * * Fokus-Indikator erscheint mit sanftem Scale-Pop statt hart. * Kein outline-transition (outline ist nicht transition-fähig), * daher box-shadow als Alternative für focus-visible. * ================================================================ */ :focus-visible { transition: box-shadow var(--transition-fast), outline-offset var(--transition-fast); outline-offset: 3px; } /* ================================================================ * 23. Skeleton Shimmer — Glass Shimmer * * Helleres, richtungstreues Shimmer mit glass-artiger Lichtquelle. * Behält bestehende Animation, verbessert nur den Farbverlauf. * ================================================================ */ .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%; } /* ================================================================ * 24. FAB — Attention Pulse (subtil, einmalig beim Erscheinen) * * Leichter Ring-Expand nach dem fab-in, signalisiert Interaktivität. * Nur einmal, kein dauerhaftes Blinken (kein infinite loop). * ================================================================ */ @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; } /* ================================================================ * 25. Accessibility — Phase 3 Overrides * ================================================================ */ @media (prefers-reduced-motion: reduce) { .nav-bottom { transition: none; } .nav-bottom--hidden { /* Sofort verstecken ohne Animation */ 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; } }