/** * Zentrales Glassmorphism-Benachrichtigungssystem für MYP Platform * Vereinheitlicht alle Notification-Typen mit modernem Design */ class GlassmorphismNotificationSystem { constructor() { this.notifications = new Map(); this.toastCounter = 0; this.soundEnabled = localStorage.getItem('myp-notification-sound') !== 'false'; this.animationsEnabled = !window.matchMedia('(prefers-reduced-motion: reduce)').matches; this.init(); this.setupGlobalFunctions(); this.injectStyles(); } init() { // Container für Toasts erstellen this.createToastContainer(); // Event-Listener für Einstellungen this.setupEventListeners(); console.log('🎨 Glassmorphism Notification System initialisiert'); } createToastContainer() { if (!document.getElementById('glassmorphism-toast-container')) { const container = document.createElement('div'); container.id = 'glassmorphism-toast-container'; container.className = 'notifications-container'; document.body.appendChild(container); } } setupGlobalFunctions() { // Globale Funktionen überschreiben für einheitliches Design window.showFlashMessage = this.showToast.bind(this); window.showToast = this.showToast.bind(this); window.showNotification = this.showToast.bind(this); window.showSuccessMessage = (msg, duration) => this.showToast(msg, 'success', duration); window.showErrorMessage = (msg, duration) => this.showToast(msg, 'error', duration); window.showWarningMessage = (msg, duration) => this.showToast(msg, 'warning', duration); window.showInfoMessage = (msg, duration) => this.showToast(msg, 'info', duration); window.showSuccessNotification = (msg) => this.showToast(msg, 'success'); // Spezielle Funktionen window.showPersistentAlert = this.showPersistentAlert.bind(this); window.showConfirmationToast = this.showConfirmationToast.bind(this); window.showProgressToast = this.showProgressToast.bind(this); } setupEventListeners() { // Keyboard Shortcuts document.addEventListener('keydown', (e) => { // ESC schließt alle Toasts if (e.key === 'Escape') { this.closeAllToasts(); } // Ctrl/Cmd + Shift + N öffnet Benachrichtigungseinstellungen if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'N') { this.showNotificationSettings(); } }); // Geräte-Rotation window.addEventListener('orientationchange', () => { setTimeout(() => this.repositionAllToasts(), 200); }); } /** * Zeigt eine Glassmorphism-Toast-Benachrichtigung */ showToast(message, type = 'info', duration = 5000, options = {}) { // DND-Check if (window.dndManager?.isEnabled) { window.dndManager.suppressNotification(message, type); return null; } const toastId = `glass-toast-${++this.toastCounter}`; const toast = this.createToastElement(toastId, message, type, duration, options); this.addToContainer(toast); this.animateIn(toast); this.scheduleRemoval(toastId, duration, options.persistent); // Sound abspielen if (this.soundEnabled && options.playSound !== false) { this.playNotificationSound(type); } // Browser-Notification (optional) if (options.browserNotification && 'Notification' in window) { this.showBrowserNotification(message, type, options); } return toastId; } createToastElement(toastId, message, type, duration, options) { const toast = document.createElement('div'); toast.id = toastId; toast.className = `glassmorphism-toast notification notification-${type}`; // Accessibility toast.setAttribute('role', 'alert'); toast.setAttribute('aria-live', 'polite'); toast.setAttribute('aria-atomic', 'true'); const iconSvg = this.getIconSvg(type); const progressBar = duration > 0 && !options.persistent ? this.createProgressBar(duration) : ''; toast.innerHTML = `
${iconSvg}
${options.title ? `
${options.title}
` : ''}
${message}
${options.actions ? this.createActionButtons(options.actions, toastId) : ''}
${progressBar}
`; // Hover-Events für Auto-Close-Pausierung if (duration > 0 && !options.persistent) { this.setupHoverEvents(toast, toastId); } this.notifications.set(toastId, { element: toast, type, message, timestamp: Date.now(), options }); return toast; } createProgressBar(duration) { return `
`; } createActionButtons(actions, toastId) { return actions.map(action => ` `).join(''); } getIconSvg(type) { const icons = { success: ` `, error: ` `, warning: ` `, info: ` `, loading: ` ` }; return icons[type] || icons.info; } addToContainer(toast) { const container = document.getElementById('glassmorphism-toast-container'); if (container) { container.appendChild(toast); this.repositionAllToasts(); } } animateIn(toast) { if (!this.animationsEnabled) { toast.classList.add('show'); return; } // Erweiterte Eingangsanimation mit Glassmorphism-Effekten toast.style.transform = 'translateX(120%) scale(0.8) rotateY(15deg)'; toast.style.opacity = '0'; toast.style.filter = 'blur(8px)'; // Trigger animation requestAnimationFrame(() => { toast.style.transition = 'all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1)'; toast.style.transform = 'translateX(0) scale(1) rotateY(0deg)'; toast.style.opacity = '1'; toast.style.filter = 'blur(0px)'; toast.classList.add('show'); }); } setupHoverEvents(toast, toastId) { let timeoutId; let isPaused = false; const notification = this.notifications.get(toastId); if (!notification) return; const pauseTimer = () => { isPaused = true; clearTimeout(timeoutId); const progressBar = toast.querySelector('.toast-progress-bar'); if (progressBar) { progressBar.style.animationPlayState = 'paused'; } // Hover-Effekt verstärken toast.style.transform = 'translateY(-4px) scale(1.03)'; toast.style.filter = 'brightness(1.1) saturate(1.1)'; }; const resumeTimer = () => { isPaused = false; const progressBar = toast.querySelector('.toast-progress-bar'); if (progressBar) { progressBar.style.animationPlayState = 'running'; } // Hover-Effekt zurücksetzen toast.style.transform = 'translateY(0) scale(1)'; toast.style.filter = 'brightness(1) saturate(1)'; }; toast.addEventListener('mouseenter', pauseTimer); toast.addEventListener('mouseleave', resumeTimer); toast.addEventListener('focus', pauseTimer); toast.addEventListener('blur', resumeTimer); } scheduleRemoval(toastId, duration, persistent = false) { if (persistent || duration <= 0) return; setTimeout(() => { this.closeToast(toastId); }, duration); } closeToast(toastId) { const notification = this.notifications.get(toastId); if (!notification) return; const toast = notification.element; if (this.animationsEnabled) { // Verbesserte Ausgangsanimation toast.style.transition = 'all 0.6s cubic-bezier(0.4, 0, 1, 1)'; toast.style.transform = 'translateX(120%) scale(0.8) rotateY(-15deg)'; toast.style.opacity = '0'; toast.style.filter = 'blur(4px)'; setTimeout(() => { this.removeToast(toastId); }, 600); } else { this.removeToast(toastId); } } removeToast(toastId) { const notification = this.notifications.get(toastId); if (!notification) return; if (notification.element.parentNode) { notification.element.parentNode.removeChild(notification.element); } this.notifications.delete(toastId); this.repositionAllToasts(); } repositionAllToasts() { const container = document.getElementById('glassmorphism-toast-container'); if (!container) return; const toasts = Array.from(container.children); toasts.forEach((toast, index) => { // Gestaffelte Positionierung mit smooth transition toast.style.top = `${1 + index * 4.5}rem`; toast.style.zIndex = 1000 - index; // Leichter Versatz für Tiefeneffekt if (index > 0) { toast.style.transform = `scale(${1 - index * 0.02})`; toast.style.opacity = `${1 - index * 0.1}`; } }); } closeAllToasts() { const toastIds = Array.from(this.notifications.keys()); toastIds.forEach((id, index) => { setTimeout(() => this.closeToast(id), index * 100); }); } /** * Spezielle Toast-Typen */ showConfirmationToast(message, onConfirm, onCancel = null, options = {}) { return this.showToast(message, 'warning', 0, { persistent: true, title: options.title || 'Bestätigung erforderlich', actions: [ { text: options.confirmText || 'Bestätigen', type: 'primary', onClick: `(${onConfirm.toString()})()` }, { text: options.cancelText || 'Abbrechen', type: 'secondary', onClick: onCancel ? `(${onCancel.toString()})()` : '' } ], ...options }); } showProgressToast(message, type = 'info', options = {}) { const toastId = this.showToast(message, 'loading', 0, { persistent: true, title: options.title || 'Verarbeitung...', ...options }); return { id: toastId, updateProgress: (percent) => this.updateProgressToast(toastId, percent), updateMessage: (newMessage) => this.updateToastMessage(toastId, newMessage), complete: (finalMessage, finalType = 'success') => { this.closeToast(toastId); if (finalMessage) { this.showToast(finalMessage, finalType, 3000); } } }; } updateProgressToast(toastId, percent) { const notification = this.notifications.get(toastId); if (!notification) return; let progressBar = notification.element.querySelector('.toast-progress-bar'); if (!progressBar) { const progressContainer = document.createElement('div'); progressContainer.className = 'toast-progress'; progressContainer.innerHTML = `
`; notification.element.querySelector('.toast-content').appendChild(progressContainer); progressBar = progressContainer.querySelector('.toast-progress-bar'); } progressBar.style.width = `${Math.min(100, Math.max(0, percent))}%`; } updateToastMessage(toastId, newMessage) { const notification = this.notifications.get(toastId); if (!notification) return; const messageEl = notification.element.querySelector('.toast-message'); if (messageEl) { messageEl.textContent = newMessage; } } showPersistentAlert(message, type = 'warning', options = {}) { return this.showToast(message, type, 0, { persistent: true, title: options.title || 'Wichtiger Hinweis', actions: [{ text: 'Verstanden', type: 'primary', onClick: '' }], ...options }); } /** * Browser-Benachrichtigungen */ async showBrowserNotification(message, type, options = {}) { if (!('Notification' in window)) return null; if (Notification.permission === 'granted') { return new Notification(options.title || 'MYP Platform', { body: message, icon: '/static/icons/notification-icon.png', badge: '/static/icons/badge-icon.png', tag: `myp-${type}`, ...options.browserOptions }); } else if (Notification.permission === 'default') { const permission = await Notification.requestPermission(); if (permission === 'granted') { return this.showBrowserNotification(message, type, options); } } return null; } /** * Sound-System */ playNotificationSound(type) { if (!this.soundEnabled) return; try { const audioContext = new (window.AudioContext || window.webkitAudioContext)(); const frequencies = { success: [523.25, 659.25, 783.99], // C-E-G Akkord error: [440, 415.3, 370], // A-Ab-F# (dissonant) warning: [493.88, 523.25], // B-C info: [523.25], // C loading: [392, 440, 493.88] // G-A-B (aufsteigend) }; const freq = frequencies[type] || frequencies.info; freq.forEach((f, i) => { setTimeout(() => { const oscillator = audioContext.createOscillator(); const gainNode = audioContext.createGain(); oscillator.connect(gainNode); gainNode.connect(audioContext.destination); oscillator.frequency.setValueAtTime(f, audioContext.currentTime); oscillator.type = type === 'error' ? 'sawtooth' : 'sine'; gainNode.gain.setValueAtTime(0.1, audioContext.currentTime); gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.2); oscillator.start(audioContext.currentTime); oscillator.stop(audioContext.currentTime + 0.2); }, i * 150); }); } catch (error) { // Silent fail } } toggleSound() { this.soundEnabled = !this.soundEnabled; localStorage.setItem('myp-notification-sound', this.soundEnabled.toString()); this.showToast( `Benachrichtigungstöne ${this.soundEnabled ? 'aktiviert' : 'deaktiviert'}`, 'info', 2000 ); } /** * Einstellungen */ showNotificationSettings() { const settingsHTML = `

Benachrichtigungseinstellungen

`; this.showToast(settingsHTML, 'info', 0, { persistent: true, title: 'Einstellungen', actions: [{ text: 'Schließen', type: 'secondary', onClick: '' }] }); } toggleAnimations() { this.animationsEnabled = !this.animationsEnabled; this.showToast( `Animationen ${this.animationsEnabled ? 'aktiviert' : 'deaktiviert'}`, 'info', 2000 ); } /** * CSS-Styles einbetten */ injectStyles() { if (document.getElementById('glassmorphism-notification-styles')) return; const styles = document.createElement('style'); styles.id = 'glassmorphism-notification-styles'; styles.textContent = ` .glassmorphism-toast { margin-bottom: 0.75rem; transform: translateX(100%); opacity: 0; transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1); will-change: transform, opacity, filter; /* Erweiterte Glassmorphism-Eigenschaften */ backdrop-filter: blur(50px) saturate(200%) brightness(120%) contrast(110%); -webkit-backdrop-filter: blur(50px) saturate(200%) brightness(120%) contrast(110%); box-shadow: 0 32px 64px rgba(0, 0, 0, 0.25), 0 16px 32px rgba(0, 0, 0, 0.15), 0 8px 16px rgba(0, 0, 0, 0.1), inset 0 2px 0 rgba(255, 255, 255, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.15); border-radius: 1.5rem; overflow: hidden; position: relative; } .glassmorphism-toast::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: radial-gradient(circle at 20% 20%, rgba(255, 255, 255, 0.15) 0%, transparent 30%), radial-gradient(circle at 80% 80%, rgba(255, 255, 255, 0.1) 0%, transparent 30%), linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, transparent 50%); pointer-events: none; opacity: 0; transition: opacity 0.3s ease; } .glassmorphism-toast:hover::before { opacity: 1; } .glassmorphism-toast.show { transform: translateX(0); opacity: 1; } /* Typ-spezifische erweiterte Glassmorphism-Effekte */ .glassmorphism-toast.notification-success { background: linear-gradient(135deg, rgba(34, 197, 94, 0.25) 0%, rgba(134, 239, 172, 0.15) 30%, rgba(34, 197, 94, 0.1) 70%, rgba(16, 185, 129, 0.08) 100%); border: 1px solid rgba(34, 197, 94, 0.4); box-shadow: 0 32px 64px rgba(34, 197, 94, 0.2), 0 16px 32px rgba(34, 197, 94, 0.1), inset 0 2px 0 rgba(255, 255, 255, 0.4), 0 0 0 1px rgba(34, 197, 94, 0.3); } .glassmorphism-toast.notification-error { background: linear-gradient(135deg, rgba(239, 68, 68, 0.25) 0%, rgba(252, 165, 165, 0.15) 30%, rgba(239, 68, 68, 0.1) 70%, rgba(220, 38, 38, 0.08) 100%); border: 1px solid rgba(239, 68, 68, 0.4); box-shadow: 0 32px 64px rgba(239, 68, 68, 0.2), 0 16px 32px rgba(239, 68, 68, 0.1), inset 0 2px 0 rgba(255, 255, 255, 0.4), 0 0 0 1px rgba(239, 68, 68, 0.3); } .glassmorphism-toast.notification-warning { background: linear-gradient(135deg, rgba(245, 158, 11, 0.25) 0%, rgba(252, 211, 77, 0.15) 30%, rgba(245, 158, 11, 0.1) 70%, rgba(217, 119, 6, 0.08) 100%); border: 1px solid rgba(245, 158, 11, 0.4); box-shadow: 0 32px 64px rgba(245, 158, 11, 0.2), 0 16px 32px rgba(245, 158, 11, 0.1), inset 0 2px 0 rgba(255, 255, 255, 0.4), 0 0 0 1px rgba(245, 158, 11, 0.3); } .glassmorphism-toast.notification-info { background: linear-gradient(135deg, rgba(59, 130, 246, 0.25) 0%, rgba(147, 197, 253, 0.15) 30%, rgba(59, 130, 246, 0.1) 70%, rgba(37, 99, 235, 0.08) 100%); border: 1px solid rgba(59, 130, 246, 0.4); box-shadow: 0 32px 64px rgba(59, 130, 246, 0.2), 0 16px 32px rgba(59, 130, 246, 0.1), inset 0 2px 0 rgba(255, 255, 255, 0.4), 0 0 0 1px rgba(59, 130, 246, 0.3); } .glassmorphism-toast.notification-loading { background: linear-gradient(135deg, rgba(99, 102, 241, 0.25) 0%, rgba(165, 180, 252, 0.15) 30%, rgba(99, 102, 241, 0.1) 70%, rgba(79, 70, 229, 0.08) 100%); border: 1px solid rgba(99, 102, 241, 0.4); box-shadow: 0 32px 64px rgba(99, 102, 241, 0.2), 0 16px 32px rgba(99, 102, 241, 0.1), inset 0 2px 0 rgba(255, 255, 255, 0.4), 0 0 0 1px rgba(99, 102, 241, 0.3); } /* Dark Mode Anpassungen */ .dark .glassmorphism-toast { backdrop-filter: blur(60px) saturate(180%) brightness(110%) contrast(120%); -webkit-backdrop-filter: blur(60px) saturate(180%) brightness(110%) contrast(120%); box-shadow: 0 32px 64px rgba(0, 0, 0, 0.6), 0 16px 32px rgba(0, 0, 0, 0.4), 0 8px 16px rgba(0, 0, 0, 0.3), inset 0 2px 0 rgba(255, 255, 255, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.3), 0 0 0 1px rgba(255, 255, 255, 0.1); } .toast-content { position: relative; overflow: hidden; padding: 1.25rem; } .toast-header { display: flex; align-items: flex-start; gap: 1rem; } .toast-icon { flex-shrink: 0; width: 2.5rem; height: 2.5rem; display: flex; align-items: center; justify-content: center; border-radius: 50%; background: rgba(255, 255, 255, 0.25); backdrop-filter: blur(15px); -webkit-backdrop-filter: blur(15px); border: 1px solid rgba(255, 255, 255, 0.4); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.5); transition: all 0.3s ease; } .toast-icon:hover { transform: scale(1.1) rotate(5deg); box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.6); } .dark .toast-icon { background: rgba(0, 0, 0, 0.3); border: 1px solid rgba(255, 255, 255, 0.2); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.2); } .toast-body { flex: 1; min-width: 0; } .toast-title { font-weight: 700; font-size: 0.9rem; margin-bottom: 0.375rem; line-height: 1.3; letter-spacing: 0.01em; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); } .toast-message { font-size: 0.875rem; line-height: 1.5; opacity: 0.95; font-weight: 500; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); } .toast-actions { display: flex; gap: 0.625rem; align-items: flex-start; flex-shrink: 0; } .toast-action-btn { padding: 0.5rem 1rem; border-radius: 0.75rem; font-size: 0.8125rem; font-weight: 600; border: none; cursor: pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); display: flex; align-items: center; gap: 0.375rem; background: rgba(255, 255, 255, 0.2); color: inherit; backdrop-filter: blur(15px); -webkit-backdrop-filter: blur(15px); border: 1px solid rgba(255, 255, 255, 0.3); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); } .toast-action-btn:hover { background: rgba(255, 255, 255, 0.35); transform: translateY(-2px) scale(1.05); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15); } .toast-action-btn:active { transform: translateY(-1px) scale(1.02); transition: transform 0.1s ease; } .toast-action-primary { background: linear-gradient(135deg, rgba(59, 130, 246, 0.9) 0%, rgba(37, 99, 235, 0.9) 100%); color: white; border-color: rgba(59, 130, 246, 0.6); box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3); } .toast-action-primary:hover { background: linear-gradient(135deg, rgba(59, 130, 246, 1) 0%, rgba(37, 99, 235, 1) 100%); box-shadow: 0 8px 20px rgba(59, 130, 246, 0.4); } .dark .toast-action-btn { background: rgba(0, 0, 0, 0.3); border: 1px solid rgba(255, 255, 255, 0.2); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); } .dark .toast-action-btn:hover { background: rgba(0, 0, 0, 0.4); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3); } .toast-close { padding: 0.375rem; border-radius: 0.5rem; border: none; background: rgba(255, 255, 255, 0.15); color: inherit; cursor: pointer; opacity: 0.8; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); display: flex; align-items: center; justify-content: center; backdrop-filter: blur(15px); -webkit-backdrop-filter: blur(15px); border: 1px solid rgba(255, 255, 255, 0.2); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .toast-close:hover { opacity: 1; background: rgba(255, 255, 255, 0.25); transform: scale(1.15) rotate(90deg); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); } .toast-close:active { transform: scale(1.1) rotate(90deg); transition: transform 0.1s ease; } .dark .toast-close { background: rgba(0, 0, 0, 0.2); border: 1px solid rgba(255, 255, 255, 0.15); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } .dark .toast-close:hover { background: rgba(0, 0, 0, 0.3); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); } .toast-progress { position: absolute; bottom: 0; left: 0; right: 0; height: 4px; background: rgba(255, 255, 255, 0.15); overflow: hidden; border-radius: 0 0 1.5rem 1.5rem; } .toast-progress-bar { height: 100%; background: linear-gradient(90deg, rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0.9) 50%, rgba(255, 255, 255, 0.7) 100%); width: 0%; transition: width 0.3s ease; position: relative; border-radius: inherit; box-shadow: 0 0 8px rgba(255, 255, 255, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.8); } .toast-progress-bar::after { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.4) 50%, transparent 100%); animation: progress-shimmer 2s ease-in-out infinite; } @keyframes progress-shimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } } @keyframes toast-progress { from { width: 100%; } to { width: 0%; } } .notification-settings { max-width: 350px; padding: 0.5rem 0; } .notification-settings h3 { margin-bottom: 1rem; font-size: 1.1rem; font-weight: 700; color: inherit; } .setting-item { display: flex; align-items: center; gap: 0.75rem; margin: 1rem 0; cursor: pointer; font-size: 0.9rem; font-weight: 500; padding: 0.5rem; border-radius: 0.5rem; transition: all 0.2s ease; } .setting-item:hover { background: rgba(255, 255, 255, 0.1); transform: translateX(4px); } .setting-item input[type="checkbox"] { margin: 0; width: 1.2rem; height: 1.2rem; accent-color: currentColor; } /* Responsive Design */ @media (max-width: 640px) { .notifications-container { left: 0.75rem; right: 0.75rem; top: 0.75rem; } .glassmorphism-toast { margin-bottom: 0.5rem; border-radius: 1rem; } .toast-content { padding: 1rem; } .toast-header { gap: 0.75rem; } .toast-icon { width: 2rem; height: 2rem; } .toast-title { font-size: 0.85rem; } .toast-message { font-size: 0.8125rem; } .toast-action-btn { padding: 0.4rem 0.8rem; font-size: 0.75rem; } } /* High Contrast Mode */ @media (prefers-contrast: high) { .glassmorphism-toast { border: 2px solid currentColor; backdrop-filter: none; -webkit-backdrop-filter: none; background: rgba(255, 255, 255, 0.95); } .dark .glassmorphism-toast { background: rgba(0, 0, 0, 0.95); } } /* Reduced Motion */ @media (prefers-reduced-motion: reduce) { .glassmorphism-toast, .toast-icon, .toast-action-btn, .toast-close { transition: none !important; animation: none !important; } .glassmorphism-toast:hover { transform: none !important; } } `; document.head.appendChild(styles); } } // Globale Instanz erstellen const glassNotificationSystem = new GlassmorphismNotificationSystem(); // Für Rückwärtskompatibilität if (typeof window !== 'undefined') { window.glassNotificationSystem = glassNotificationSystem; window.GlassmorphismNotificationSystem = GlassmorphismNotificationSystem; } // Event für DOM-ready ohne Test-Benachrichtigung document.addEventListener('DOMContentLoaded', () => { console.log('🎨 Glassmorphism Notification System bereit'); });