/** * BetterDesk Console — Page Transition Animations * Loaded globally. Provides smooth page enter/exit transitions, * staggered list animations, modal animations, and toast slide-in. * * Respects `prefers-reduced-motion` for accessibility. */ /* ---- Reduced Motion Guard ---- */ @media (prefers-reduced-motion: reduce) { .page-enter, .page-enter-active, .page-exit, .page-exit-active, .stagger-item, .card-appear, .toast-enter, .modal-enter { animation: none !important; transition: none !important; opacity: 1 !important; transform: none !important; } } /* ---- Page Transitions ---- */ .page-enter { opacity: 0; transform: translateY(8px); } .page-enter-active { animation: pageEnter 150ms ease-out forwards; } .page-exit { opacity: 1; } .page-exit-active { animation: pageExit 100ms ease-in forwards; } @keyframes pageEnter { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } @keyframes pageExit { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-4px); } } /* Auto-apply page enter on main content area */ .main-content > .content-wrapper, .main-content > .page-content, .content-area { animation: pageEnter 200ms ease-out; } /* ---- Staggered List Items ---- */ .stagger-item { opacity: 0; animation: staggerFadeIn 200ms ease-out forwards; } /* Generate stagger delays for first 10 items */ .stagger-item:nth-child(1) { animation-delay: 0ms; } .stagger-item:nth-child(2) { animation-delay: 30ms; } .stagger-item:nth-child(3) { animation-delay: 60ms; } .stagger-item:nth-child(4) { animation-delay: 90ms; } .stagger-item:nth-child(5) { animation-delay: 120ms; } .stagger-item:nth-child(6) { animation-delay: 150ms; } .stagger-item:nth-child(7) { animation-delay: 180ms; } .stagger-item:nth-child(8) { animation-delay: 210ms; } .stagger-item:nth-child(9) { animation-delay: 240ms; } .stagger-item:nth-child(10) { animation-delay: 270ms; } @keyframes staggerFadeIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } } /* ---- Card Animations ---- */ .card-appear { animation: cardScale 200ms ease-out; } @keyframes cardScale { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } } .card-hover { transition: transform 150ms ease, box-shadow 150ms ease; transform: translateY(0); } .card-hover:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); } /* ---- Modal Animations ---- */ .modal-backdrop-enter { animation: backdropFade 200ms ease-out forwards; } .modal-enter { animation: modalSlideUp 200ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards; } .modal-exit { animation: modalSlideDown 150ms ease-in forwards; } @keyframes backdropFade { from { opacity: 0; } to { opacity: 1; } } @keyframes modalSlideUp { from { opacity: 0; transform: translateY(20px) scale(0.98); } to { opacity: 1; transform: translateY(0) scale(1); } } @keyframes modalSlideDown { from { opacity: 1; transform: translateY(0) scale(1); } to { opacity: 0; transform: translateY(10px) scale(0.98); } } /* ---- Toast Notifications ---- */ .toast-enter { animation: toastSlideIn 250ms ease-out forwards; } .toast-exit { animation: toastSlideOut 200ms ease-in forwards; } @keyframes toastSlideIn { from { opacity: 0; transform: translateX(100%); } to { opacity: 1; transform: translateX(0); } } @keyframes toastSlideOut { from { opacity: 1; transform: translateX(0); } to { opacity: 0; transform: translateX(100%); } } /* Toast progress bar (auto-dismiss indicator) */ .toast-progress { position: absolute; bottom: 0; left: 0; height: 3px; background: var(--accent-blue, #58a6ff); border-radius: 0 0 4px 4px; animation: toastShrink var(--toast-duration, 5s) linear forwards; } @keyframes toastShrink { from { width: 100%; } to { width: 0; } } /* ---- Skeleton Loading ---- */ .skeleton { background: linear-gradient( 90deg, var(--bg-tertiary, #21262d) 25%, var(--bg-elevated, #30363d) 50%, var(--bg-tertiary, #21262d) 75% ); background-size: 200% 100%; animation: skeletonPulse 1.5s ease-in-out infinite; border-radius: 4px; } .skeleton-text { height: 14px; margin-bottom: 8px; } .skeleton-text.short { width: 40%; } .skeleton-text.medium { width: 70%; } .skeleton-text.long { width: 100%; } .skeleton-circle { width: 40px; height: 40px; border-radius: 50%; } @keyframes skeletonPulse { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }