Files
oikos/public/styles/glass.css
T
Konrad M. e729bc9c4e fix(layout): refactor page transition animations; expand sidebar at 1440px
Page-in animations drop 'forwards' fill mode — a .page-transition base class
(opacity:0) serves as the initial state, and .page-transition--in-{left,right}
force opacity:1 after the animation ends, preventing a flash-back-to-invisible
on some WebKit versions. Sidebar expands at 1440px instead of 1280px.
Glass desktop toolbar loses the rounded card border in favour of a flat
accent-top-border + bottom border consistent with other module headers.
2026-04-21 22:18:14 +02:00

788 lines
25 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),
var(--glass-inset-medium);
}
.btn--primary:hover {
box-shadow:
var(--shadow-md),
var(--glass-inset-soft);
}
.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),
var(--glass-inset-elevated),
inset 0 -1px 0 rgba(0, 0, 0, 0.12);
}
.fab:hover {
box-shadow:
var(--shadow-lg),
var(--glass-inset-strong),
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),
var(--glass-inset-soft);
}
/* ================================================================
* 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: var(--glass-inset-base);
}
/* ================================================================
* 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 {
margin-bottom: 0;
transition:
transform var(--transition-base) var(--ease-out),
margin-bottom var(--transition-base) var(--ease-out),
background-color var(--transition-fast),
box-shadow var(--transition-fast);
/* will-change: transform absichtlich weggelassen - auf iOS (WebKit) korrumpiert die
* dauerhafte GPU-Layer-Promotion eines position:relative Flex-Kinds dessen Position. */
}
.nav-bottom--hidden {
transform: translateY(100%);
margin-bottom: calc(-1 * (var(--nav-height-mobile)));
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.20s;
animation-timing-function: var(--ease-glass);
}
.page-transition--out-left,
.page-transition--out-right {
animation-duration: 0.12s;
animation-timing-function: var(--ease-out);
}
/* Performance: backdrop-filter deaktivieren während Seitenübergängen.
* Auf Android verursachen viele gleichzeitige backdrop-filter-Layer
* (Widgets, Cards, Inputs) hohen GPU-Aufwand → Transition wirkt träge.
* html.navigating wird von router.js für die Dauer des Übergangs gesetzt. */
html.navigating .app-content *,
html.navigating .app-content *::before,
html.navigating .app-content *::after {
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
}
/* ================================================================
* 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), var(--glass-inset-elevated), 0 0 0 0 color-mix(in srgb, var(--module-accent, var(--color-btn-primary)) 50%, transparent); }
60% { box-shadow: var(--shadow-lg), var(--glass-inset-elevated), 0 0 0 10px transparent; }
100% { box-shadow: var(--shadow-lg), var(--glass-inset-elevated), 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;
}
}
/* ================================================================
* PHASE 4 — Liquid Glass Vibrancy + Tint
* ================================================================ */
/* ================================================================
* 25. Widget Cards — Glass Vibrancy
*
* Widgets bekommen transparente Hintergruende mit Blur,
* sodass darunterliegender Content durchscheint.
* Tint: subtile Tonung durch Modul-Akzentfarbe.
* ================================================================ */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
/* .dashboard Eltern-Selektor fuer Spezifitaet (Load-Order: glass.css < dashboard.css) */
.dashboard .widget {
background-color: var(--glass-bg-card);
backdrop-filter: var(--blur-sm) saturate(180%);
-webkit-backdrop-filter: var(--blur-sm) saturate(180%);
}
.dashboard .widget:hover {
background-color: var(--glass-bg-card-hover);
}
/* Modul-Tint: subtiler Farbverlauf durch Akzentfarbe */
.dashboard .widget::after {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
background: linear-gradient(
135deg,
color-mix(in srgb, var(--module-accent, var(--color-accent)) var(--glass-tint-strength), transparent),
transparent 70%
);
pointer-events: none;
z-index: 0;
}
}
/* ================================================================
* 26. Greeting-Widget — Glass + Vibrancy auf Gradient
* ================================================================ */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.widget-greeting {
backdrop-filter: var(--blur-xs) saturate(200%);
-webkit-backdrop-filter: var(--blur-xs) saturate(200%);
}
/* Greeting braucht keinen separaten Tint - hat eigenen Gradient */
.widget-greeting::after {
display: none;
}
}
/* ================================================================
* 27. Wetter-Widget — Vibrancy auf Gradient
* ================================================================ */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.weather-widget {
backdrop-filter: var(--blur-xs) saturate(200%);
-webkit-backdrop-filter: var(--blur-xs) saturate(200%);
}
.weather-widget::after {
display: none;
}
}
/* ================================================================
* 28. Page-Toolbars — Glass Bar mit Tint
*
* Modul-Header/Toolbars als Glass-Elemente mit
* Modul-Akzentfarbe als dezenter Tint.
* ================================================================ */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
/* Eltern-Selektoren fuer Spezifitaet */
.tasks-page .tasks-toolbar,
.notes-page .notes-toolbar,
.contacts-page .contacts-toolbar,
.calendar-page .cal-toolbar {
background-color: var(--glass-bg-toolbar);
backdrop-filter: var(--blur-sm) saturate(160%);
-webkit-backdrop-filter: var(--blur-sm) saturate(160%);
border-top: 3px solid var(--module-accent);
border-bottom: 1px solid var(--glass-border-subtle);
padding-left: var(--space-4);
padding-right: var(--space-4);
}
}
/* ================================================================
* 29. Note-Items — Glass Cards
* ================================================================ */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.notes-page .note-item,
.dashboard .note-item {
background-color: var(--glass-bg-card);
backdrop-filter: var(--blur-xs) saturate(150%);
-webkit-backdrop-filter: var(--blur-xs) saturate(150%);
border: 1px solid var(--glass-border-subtle);
box-shadow: var(--glass-shadow-sm);
}
.notes-page .note-item:hover,
.dashboard .note-item:hover {
background-color: var(--glass-bg-card-hover);
box-shadow: var(--glass-shadow-md);
}
}
/* ================================================================
* 30. Meal-Slots — Glass Grid-Zellen
* ================================================================ */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.dashboard .meal-slot,
.meals-page .meal-slot {
background-color: var(--glass-bg-card);
backdrop-filter: var(--blur-xs) saturate(140%);
-webkit-backdrop-filter: var(--blur-xs) saturate(140%);
}
.dashboard .meal-slot:hover,
.meals-page .meal-slot:hover {
background-color: var(--glass-bg-card-hover);
}
.dashboard .meal-slot--filled,
.meals-page .meal-slot--filled {
background-color: color-mix(in srgb, var(--module-accent, var(--module-meals)) 4%, var(--glass-bg-card));
}
}
/* ================================================================
* 31. Form-Inputs — Glass Vibrancy
* ================================================================ */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.input,
.form-input,
select.form-input,
textarea.form-input {
background-color: var(--glass-bg-input);
backdrop-filter: var(--blur-xs) saturate(120%);
-webkit-backdrop-filter: var(--blur-xs) saturate(120%);
}
}
/* ================================================================
* 32. List-Items — Subtile Glass-Trennung
* ================================================================ */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
/* Eltern-Selektoren fuer Spezifitaet (glass.css < page CSS) */
.tasks-page .task-card {
background-color: var(--glass-bg-card);
backdrop-filter: var(--blur-xs) saturate(150%);
-webkit-backdrop-filter: var(--blur-xs) saturate(150%);
}
.tasks-page .task-card:hover {
background-color: color-mix(in srgb, var(--module-accent, var(--color-accent)) 4%, var(--glass-bg-card-hover));
}
.shopping-page .shopping-item:hover,
.contacts-page .contact-item:hover {
background-color: color-mix(in srgb, var(--module-accent, var(--color-accent)) 4%, var(--glass-bg-card-hover));
border-radius: var(--radius-sm);
}
}
/* ================================================================
* 33. Group-Toggle / Filter-Chips — Glass Segmented Control
* ================================================================ */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.group-toggle {
background-color: var(--glass-bg-input);
backdrop-filter: var(--blur-xs) saturate(140%);
-webkit-backdrop-filter: var(--blur-xs) saturate(140%);
border: 1px solid var(--glass-border-subtle);
}
.group-toggle__btn--active {
background-color: var(--glass-bg-elevated);
box-shadow: var(--glass-shadow-sm);
}
}
/* ================================================================
* 34. FAB Speed-Dial Actions — Glass Labels + Buttons
* ================================================================ */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.fab-action__label {
background-color: var(--glass-bg-elevated);
backdrop-filter: var(--blur-sm) saturate(160%);
-webkit-backdrop-filter: var(--blur-sm) saturate(160%);
border: 1px solid var(--glass-border-subtle);
box-shadow: var(--glass-shadow-md);
}
.fab-action__btn {
background-color: var(--glass-bg-elevated);
backdrop-filter: var(--blur-sm) saturate(160%);
-webkit-backdrop-filter: var(--blur-sm) saturate(160%);
border: 1px solid var(--glass-border-subtle);
}
}
/* ================================================================
* 35. App-Content-Hintergrund — Vibrancy-Basis
*
* Subtiler Gradient im Seitenhintergrund damit Glass-
* Elemente darauf lebendiger wirken.
* ================================================================ */
.app-content {
background:
radial-gradient(
ellipse at 20% 0%,
color-mix(in srgb, var(--module-accent, var(--color-accent)) 3%, transparent),
transparent 60%
),
var(--color-bg);
}
/* ================================================================
* 36. Skeleton — Glass Shimmer Update
* ================================================================ */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.widget-skeleton {
background-color: var(--glass-bg-card);
backdrop-filter: var(--blur-xs) saturate(140%);
-webkit-backdrop-filter: var(--blur-xs) saturate(140%);
border: 1px solid var(--glass-border-subtle);
}
}
/* ================================================================
* 37. Accessibility — Phase 4
* ================================================================ */
@media (prefers-reduced-transparency: reduce) {
.dashboard .widget,
.tasks-page .task-card,
.notes-page .note-item,
.dashboard .note-item,
.dashboard .meal-slot,
.meals-page .meal-slot,
.widget-skeleton {
background-color: var(--color-surface);
backdrop-filter: none;
-webkit-backdrop-filter: none;
}
.dashboard .widget::after {
display: none;
}
.app-content {
background: var(--color-bg);
}
.group-toggle,
.fab-action__label,
.fab-action__btn {
backdrop-filter: none;
-webkit-backdrop-filter: none;
}
.input,
.form-input,
select.form-input,
textarea.form-input {
backdrop-filter: none;
-webkit-backdrop-filter: none;
}
.tasks-page .tasks-toolbar,
.notes-page .notes-toolbar,
.contacts-page .contacts-toolbar,
.calendar-page .cal-toolbar {
background-color: var(--color-surface);
backdrop-filter: none;
-webkit-backdrop-filter: none;
}
}