diff --git a/UI_UPDATE.MD b/UI_UPDATE.MD index 7a06d9f..c1fb21d 100644 --- a/UI_UPDATE.MD +++ b/UI_UPDATE.MD @@ -424,39 +424,20 @@ All components now consistently scale and behave appropriately across devices wh ### Sub-task 4.1: Animations and Transitions System -#### 4.1.1: Transition Library - COMPLETED 9/29/2025 -- [x] Implement CSS transition utilities -- [x] Create consistent timing functions -- [x] Define transition duration constants +#### 4.1.1: Transition Library +- [ ] Implement CSS transition utilities +- [ ] Create consistent timing functions +- [ ] Define transition duration constants -**Notes:** Comprehensive transition and animation utilities library implemented in utilities.css with: -- **CSS Custom Properties**: --duration-fast (150ms), --duration-normal (250ms), --duration-slow (350ms), --animation-duration-fast (200ms), --animation-duration-normal (300ms), --animation-duration-slow (500ms), and timing functions (--timing-linear, --timing-ease, etc.) defined in :root -- **Transition Property Utilities**: .transition-all, .transition-colors, .transition-opacity, .transition-shadow, .transition-transform, and .transition-text classes targeting specific CSS properties -- **Transition Duration Utilities**: .duration-fast, .duration-normal, .duration-slow, and precise durations from .duration-75 to .duration-1000 -- **Timing Function Utilities**: .ease-linear, .ease-in, .ease-out, .ease-in-out, .ease-spring, and .ease-bounce for different animation feels -- **Keyframe Animations**: Comprehensive set of @keyframes for fade, slide, scale, pulse, bounce, spin, ping, and shake animations -- **Animation Utility Classes**: .animate-fade-in, .animate-slide-in-left, .animate-scale-out, .animate-pulse, .animate-spin, etc. using the CSS custom properties for consistent timing -- **Animation Modifiers**: Duration modifiers, timing function modifiers, direction and fill mode controls, and play state controls -- **Hover Transition Utilities**: .hover-transition, .hover-scale, .hover-opacity, and .hover-lift for interactive elements -All utilities follow the established pattern of using CSS custom properties from variables.css for maintainability and consistency. +#### 4.1.2: Component Animations +- [ ] Add smooth state transitions +- [ ] Implement enter/exit animations +- [ ] Create micro-interaction feedback -#### 4.1.2: Component Animations - COMPLETED 9/29/2025 -- [x] Add smooth state transitions -- [x] Implement enter/exit animations -- [x] Create micro-interaction feedback - -**Notes:** Comprehensive component animation system implemented including smooth state transitions (hover, focus, active states), enter/exit animations for dynamic content (message slide-ins, system message fades), and micro-interaction feedback (button scales, form lifts, mobile navigation feedback). Added scroll-triggered animations with Intersection Observer support for performance-optimized viewport animations. Enhanced loading state animations with skeleton pulsing and shimmer effects. All animations use CSS custom properties from utilities.css for consistent timing and performance. - -#### 4.1.3: Loading Animations - COMPLETED 9/29/2025 -- [x] Implement spinner and progress indicators -- [x] Add skeleton loading states -- [x] Create engaging loading experiences - -**Notes:** Comprehensive loading animation system implemented in utilities.css with: -- **Spinners & Progress Indicators**: Border spinners (.spinner-border), grow spinners (.spinner-grow), loading dots (.loading-dots), loading bars (.loading-bars), spinning dots (.spinning-dots), progress bars (.progress-bar with .progress-bar-striped variants and indeterminate animations), and circular progress indicators (.progress-circular) -- **Skeleton Loading States**: Base skeleton (.skeleton), skeleton lines (.skeleton-line), circles (.skeleton-circle), rectangles (.skeleton-rectangle), shimmer effect (.skeleton-shimmer), skeleton cards (.skeleton-card), and skeleton lists (.skeleton-list). Includes light/dark variants (.skeleton-light, .skeleton-dark) -- **Engaging Loading Experiences**: Orbital spinners (.loading-orbit), animated hourglass (.hourglass), digital counter (.loading-counter), matrix-style rain (.loading-matrix), and cosmic orbiting particles (.loading-cosmic) -- **Technical Features**: All animations use Dodgers-themed color scheme (--dodgers-blue, --dodgers-red, --dodgers-yellow), 60fps performance with transform/opacity animations, responsive design, and accessibility considerations. Uses keyframe animations for smooth performance and CSS custom properties for consistency. +#### 4.1.3: Loading Animations +- [ ] Implement spinner and progress indicators +- [ ] Add skeleton loading states +- [ ] Create engaging loading experiences ### Sub-task 4.2: Interactive States and Feedback diff --git a/static/css/components.css b/static/css/components.css index 9056ff8..900e42d 100644 --- a/static/css/components.css +++ b/static/css/components.css @@ -344,206 +344,9 @@ } /* ================================================================= - COMPONENT ANIMATIONS AND STATE TRANSITIONS + LOADING STATES - SKELETONS AND TRANSITIONS ================================================================= */ -/* ===== INTERSECTION OBSERVER ANIMATIONS ===== */ - -/* Base classes for scroll-triggered animations */ -.animate-on-scroll { - opacity: 0; - transform: translateY(20px); - transition: all var(--animation-duration-normal) var(--timing-ease-out); - will-change: opacity, transform; -} - -.animate-on-scroll.animate-in { - opacity: 1; - transform: translateY(0); -} - -/* Staggered animations for lists */ -.animate-stagger { - opacity: 0; - transform: translateY(15px) scale(0.95); - transition: all var(--animation-duration-normal) var(--timing-ease-out); -} - -.animate-stagger.animate-in { - opacity: 1; - transform: translateY(0) scale(1); -} - -/* Left slide animations */ -.animate-on-scroll-left { - opacity: 0; - transform: translateX(-30px); - transition: all var(--animation-duration-normal) var(--timing-ease-out); - will-change: opacity, transform; -} - -.animate-on-scroll-left.animate-in { - opacity: 1; - transform: translateX(0); -} - -/* Right slide animations */ -.animate-on-scroll-right { - opacity: 0; - transform: translateX(30px); - transition: all var(--animation-duration-normal) var(--timing-ease-out); - will-change: opacity, transform; -} - -.animate-on-scroll-right.animate-in { - opacity: 1; - transform: translateX(0); -} - -/* Scale animations for cards/widgets */ -.animate-on-scroll-scale { - opacity: 0; - transform: scale(0.9); - transition: all var(--animation-duration-normal) var(--timing-ease-out); - will-change: opacity, transform; -} - -.animate-on-scroll-scale.animate-in { - opacity: 1; - transform: scale(1); -} - -/* Performance optimization - remove transforms when animations complete */ -.animate-on-scroll.animate-in, -.animate-on-scroll-left.animate-in, -.animate-on-scroll-right.animate-in, -.animate-on-scroll-scale.animate-in, -.animate-stagger.animate-in { - will-change: auto; -} - -/* ===== STATE TRANSITIONS ===== */ - -/* Enhanced button state transitions */ -.btn:hover { - transform: translateY(-1px); - box-shadow: var(--elevation-4); - transition: all var(--transition-fast); -} - -.btn:active { - transform: translateY(0); - transition: all 75ms; -} - -/* Card state transitions */ -.card:hover { - transform: translateY(-2px); - box-shadow: var(--elevation-3); - transition: transform var(--transition-normal), box-shadow var(--transition-normal); -} - -.card-interactive:active { - transform: translateY(0); - box-shadow: var(--elevation-1); -} - -/* Stats card micro-interactions */ -.stats-card { - transition: transform var(--transition-normal), box-shadow var(--transition-normal); -} - -.stats-card:hover { - transform: translateY(-3px); - box-shadow: var(--elevation-4); -} - -/* ===== ENTER/EXIT ANIMATIONS ===== */ - -/* Message enter animations */ -.message { - animation: messageSlideIn var(--animation-duration-normal) ease-out; - transform: translateX(0); - opacity: 1; -} - -@keyframes messageSlideIn { - from { - opacity: 0; - transform: translateX(-20px); - } - to { - opacity: 1; - transform: translateX(0); - } -} - -.message.own-message { - animation: ownMessageSlideIn var(--animation-duration-normal) ease-out; -} - -@keyframes ownMessageSlideIn { - from { - opacity: 0; - transform: translateX(20px); - } - to { - opacity: 1; - transform: translateX(0); - } -} - -/* System message animations */ -.system-message { - animation: systemMessageFadeIn var(--animation-duration-fast) ease-out; - transform: translateY(0); - opacity: 1; -} - -@keyframes systemMessageFadeIn { - from { - opacity: 0; - transform: translateY(-10px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -/* ===== MICRO-INTERACTIONS ===== */ - -/* Button micro-feedback */ -.btn-primary:active { - transform: scale(0.98); - transition: transform 75ms ease-out; -} - -.btn-accent:active { - transform: scale(0.98); -} - -/* Input focus micro-interactions */ -.form-control:focus { - transform: translateY(-1px); - box-shadow: 0 0 0 3px var(--focus-ring); - transition: all var(--transition-fast); -} - -/* Mobile navigation button feedback */ -.mobile-nav-btn:active { - transform: scale(0.92); - transition: transform 75ms ease-out; -} - -/* Chat input button feedback */ -.chat__input button:active { - transform: scale(0.95); - box-shadow: var(--elevation-1); -} - -/* ===== LOADING STATES ANIMATIONS ===== */ - /* Skeleton loading animations */ @keyframes skeleton-pulse { 0% { opacity: 1; } @@ -551,11 +354,6 @@ 100% { opacity: 1; } } -@keyframes skeleton-shimmer { - 0% { background-position: -200% 0; } - 100% { background-position: 200% 0; } -} - /* Base skeleton styles */ .skeleton { background: linear-gradient(90deg, var(--color-surface-variant) 25%, var(--color-surface) 50%, var(--color-surface-variant) 75%); diff --git a/static/css/utilities.css b/static/css/utilities.css index 04e4d2f..d224e6a 100644 --- a/static/css/utilities.css +++ b/static/css/utilities.css @@ -956,955 +956,3 @@ .content-between { align-content: space-between; } .content-around { align-content: space-around; } .content-stretch { align-content: stretch; } - -/* ================================================================= - TRANSITION AND ANIMATION UTILITIES - ================================================================= */ - -:root { - /* Transition Duration Constants - Using CSS Custom Properties */ - --duration-fast: 150ms; - --duration-normal: 250ms; - --duration-slow: 350ms; - - /* Animation Duration Constants */ - --animation-duration-fast: 200ms; - --animation-duration-normal: 300ms; - --animation-duration-slow: 500ms; - - /* Timing Functions */ - --timing-linear: linear; - --timing-ease: ease; - --timing-ease-in: ease-in; - --timing-ease-out: ease-out; - --timing-ease-in-out: ease-in-out; -} - -/* ===== TRANSITION UTILITIES ===== */ - -/* Transition Property Utilities */ -.transition-all { - transition-property: all; - transition-duration: var(--duration-normal); - transition-timing-function: var(--timing-ease); -} - -.transition-none { - transition-property: none; -} - -.transition-colors { - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; - transition-duration: var(--duration-normal); - transition-timing-function: var(--timing-ease); -} - -.transition-opacity { - transition-property: opacity; - transition-duration: var(--duration-normal); - transition-timing-function: var(--timing-ease); -} - -.transition-shadow { - transition-property: box-shadow; - transition-duration: var(--duration-normal); - transition-timing-function: var(--timing-ease); -} - -.transition-transform { - transition-property: transform; - transition-duration: var(--duration-normal); - transition-timing-function: var(--timing-ease); -} - -.transition-text { - transition-property: color, font-size, font-weight, letter-spacing, line-height, text-decoration, text-underline-offset; - transition-duration: var(--duration-normal); - transition-timing-function: var(--timing-ease); -} - -/* Transition Duration Utilities */ -.duration-fast { - transition-duration: var(--duration-fast); -} - -.duration-normal { - transition-duration: var(--duration-normal); -} - -.duration-slow { - transition-duration: var(--duration-slow); -} - -.duration-75 { transition-duration: 75ms; } -.duration-100 { transition-duration: 100ms; } -.duration-150 { transition-duration: 150ms; } -.duration-200 { transition-duration: 200ms; } -.duration-300 { transition-duration: 300ms; } -.duration-500 { transition-duration: 500ms; } -.duration-700 { transition-duration: 700ms; } -.duration-1000 { transition-duration: 1000ms; } - -/* Timing Function Utilities */ -.ease-linear { transition-timing-function: var(--timing-linear); } -.ease-in { transition-timing-function: var(--timing-ease-in); } -.ease-out { transition-timing-function: var(--timing-ease-out); } -.ease-in-out { transition-timing-function: var(--timing-ease-in-out); } -.ease-spring { transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55); } -.ease-bounce { transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55); } - -/* ===== ANIMATION UTILITIES ===== */ - -/* Keyframe Animations */ - -/* Fade animations */ -@keyframes fadeIn { - from { opacity: 0; } - to { opacity: 1; } -} - -@keyframes fadeOut { - from { opacity: 1; } - to { opacity: 0; } -} - -@keyframes fadeInUp { - from { - opacity: 0; - transform: translateY(10px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -@keyframes fadeInDown { - from { - opacity: 0; - transform: translateY(-10px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -/* Slide animations */ -@keyframes slideInFromLeft { - from { transform: translateX(-100%); } - to { transform: translateX(0); } -} - -@keyframes slideInFromRight { - from { transform: translateX(100%); } - to { transform: translateX(0); } -} - -@keyframes slideOutToLeft { - from { transform: translateX(0); } - to { transform: translateX(-100%); } -} - -@keyframes slideOutToRight { - from { transform: translateX(0); } - to { transform: translateX(100%); } -} - -/* Scale animations */ -@keyframes scaleIn { - from { transform: scale(0.9); opacity: 0; } - to { transform: scale(1); opacity: 1; } -} - -@keyframes scaleOut { - from { transform: scale(1); opacity: 1; } - to { transform: scale(0.9); opacity: 0; } -} - -/* Pulse animation */ -@keyframes pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: .5; } -} - -/* Bounce animation */ -@keyframes bounce { - 0%, 20%, 53%, 80%, 100% { animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); transform: translate3d(0, 0, 0); } - 40%, 43% { animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); transform: translate3d(0, -30px, 0); } - 70% { animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); transform: translate3d(0, -15px, 0); } - 90% { transform: translate3d(0, -4px, 0); } -} - -/* Spin animation */ -@keyframes spin { - to { transform: rotate(360deg); } -} - -/* Ping animation */ -@keyframes ping { - 75%, 100% { transform: scale(2); opacity: 0; } -} - -/* Shake animation */ -@keyframes shake { - 0%, 100% { transform: translateX(0); } - 10%, 30%, 50%, 70%, 90% { transform: translateX(-10px); } - 20%, 40%, 60%, 80% { transform: translateX(10px); } -} - -/* Animation Utility Classes */ - -/* Fade animations */ -.animate-fade-in { - animation: fadeIn var(--animation-duration-normal) var(--timing-ease-out); -} - -.animate-fade-out { - animation: fadeOut var(--animation-duration-normal) var(--timing-ease-out); -} - -.animate-fade-in-up { - animation: fadeInUp var(--animation-duration-normal) var(--timing-ease-out); -} - -.animate-fade-in-down { - animation: fadeInDown var(--animation-duration-normal) var(--timing-ease-out); -} - -/* Slide animations */ -.animate-slide-in-left { - animation: slideInFromLeft var(--animation-duration-normal) var(--timing-ease-out); -} - -.animate-slide-in-right { - animation: slideInFromRight var(--animation-duration-normal) var(--timing-ease-out); -} - -.animate-slide-out-left { - animation: slideOutToLeft var(--animation-duration-normal) var(--timing-ease-out); -} - -.animate-slide-out-right { - animation: slideOutToRight var(--animation-duration-normal) var(--timing-ease-out); -} - -/* Scale animations */ -.animate-scale-in { - animation: scaleIn var(--animation-duration-normal) var(--timing-ease-out); -} - -.animate-scale-out { - animation: scaleOut var(--animation-duration-normal) var(--timing-ease-out); -} - -/* Special animations */ -.animate-pulse { - animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; -} - -.animate-bounce { - animation: bounce 1s infinite; -} - -.animate-spin { - animation: spin 1s linear infinite; -} - -.animate-ping { - animation: ping 1s cubic-bezier(0.215, 0.61, 0.355, 1) infinite; -} - -.animate-shake { - animation: shake 0.5s ease-in-out; -} - -/* Animation Duration Modifiers */ -.animate-duration-fast { animation-duration: var(--animation-duration-fast); } -.animate-duration-normal { animation-duration: var(--animation-duration-normal); } -.animate-duration-slow { animation-duration: var(--animation-duration-slow); } -.animate-duration-75 { animation-duration: 75ms; } -.animate-duration-100 { animation-duration: 100ms; } -.animate-duration-200 { animation-duration: 200ms; } -.animate-duration-300 { animation-duration: 300ms; } -.animate-duration-500 { animation-duration: 500ms; } -.animate-duration-700 { animation-duration: 700ms; } -.animate-duration-1000 { animation-duration: 1000ms; } - -/* Animation Timing Modifiers */ -.animate-ease-linear { animation-timing-function: linear; } -.animate-ease-in { animation-timing-function: ease-in; } -.animate-ease-out { animation-timing-function: ease-out; } -.animate-ease-in-out { animation-timing-function: ease-in-out; } - -/* Animation Direction and Fill Mode */ -.animate-forwards { animation-fill-mode: forwards; } -.animate-backwards { animation-fill-mode: backwards; } -.animate-both { animation-fill-mode: both; } -.animate-alternate { animation-direction: alternate; } -.animate-reverse { animation-direction: reverse; } - -/* Animation States */ -.animate-paused { animation-play-state: paused; } -.animate-running { animation-play-state: running; } - -/* ===== HOVER TRANSITIONS ===== */ - -/* Hover transition triggers for interactive elements */ -.hover-transition { - transition: all var(--duration-normal) var(--timing-ease); -} - -.hover-scale { - transition: transform var(--duration-normal) var(--timing-ease); -} - -.hover-scale:hover { - transform: scale(1.02); -} - -.hover-opacity { - transition: opacity var(--duration-normal) var(--timing-ease); -} - -.hover-opacity:hover { - opacity: 0.8; -} - -.hover-lift { - transition: transform var(--duration-normal) var(--timing-ease), box-shadow var(--duration-normal) var(--timing-ease); -} - -.hover-lift:hover { - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); -} - -/* ================================================================= - LOADING ANIMATIONS - Phase 4.1.3 Implementation - ================================================================= */ - -/* ===== LOADING SPINNERS ===== */ - -@keyframes spinner-border { - to { transform: rotate(360deg); } -} - -@keyframes spinner-grow { - 0% { - transform: scale(0); - opacity: 1; - } - 50% { - opacity: 0.7; - } - 100% { - transform: scale(1); - opacity: 0; - } -} - -@keyframes loading-dots { - 0%, 20% { opacity: 0; } - 50% { opacity: 1; } - 100% { opacity: 0; } -} - -@keyframes loading-bars { - 0% { transform: scaleY(0.4); } - 20% { transform: scaleY(1); } - 40% { transform: scaleY(0.4); } - 100% { transform: scaleY(0.4); } -} - -@keyframes spinning-dots { - 0% { transform: rotate(0deg) scale(1); } - 25% { transform: rotate(90deg) scale(0.8); } - 50% { transform: rotate(180deg) scale(1.2); } - 75% { transform: rotate(270deg) scale(0.8); } - 100% { transform: rotate(360deg) scale(1); } -} - -/* Spinner variants */ -.spinner-border { - display: inline-block; - width: 2rem; - height: 2rem; - border: 0.25rem solid var(--dodgers-gray-200); - border-right-color: var(--dodgers-blue); - border-radius: 50%; - animation: spinner-border 0.75s linear infinite; -} - -.spinner-border-sm { - width: 1rem; - height: 1rem; - border-width: 0.2rem; -} - -.spinner-grow { - display: inline-block; - width: 2rem; - height: 2rem; - background-color: var(--dodgers-blue); - border-radius: 50%; - animation: spinner-grow 0.75s linear infinite; - opacity: 0; -} - -.loading-dots { - display: inline-flex; - gap: 0.25rem; - align-items: center; -} - -.loading-dots > span { - width: 0.5rem; - height: 0.5rem; - border-radius: 50%; - background-color: var(--dodgers-blue); - animation: loading-dots 1.4s ease-in-out infinite both; -} - -.loading-dots > span:nth-child(1) { animation-delay: -0.32s; } -.loading-dots > span:nth-child(2) { animation-delay: -0.16s; } -.loading-dots > span:nth-child(3) { animation-delay: 0s; } - -.loading-bars { - display: inline-flex; - gap: 0.125rem; - align-items: flex-end; -} - -.loading-bars > span { - width: 0.25rem; - height: 1rem; - background-color: var(--dodgers-blue); - animation: loading-bars 1.2s ease-in-out infinite both; - transform-origin: bottom; -} - -.loading-bars > span:nth-child(1) { animation-delay: -1.1s; } -.loading-bars > span:nth-child(2) { animation-delay: -1.0s; } -.loading-bars > span:nth-child(3) { animation-delay: -0.9s; } -.loading-bars > span:nth-child(4) { animation-delay: -0.8s; } -.loading-bars > span:nth-child(5) { animation-delay: -0.7s; } - -.spinning-dots { - display: inline-flex; - position: relative; -} - -.spinning-dots > span { - position: absolute; - width: 0.75rem; - height: 0.75rem; - border-radius: 50%; - background-color: var(--dodgers-blue); -} - -.spinning-dots > span:nth-child(1) { - top: 0.5rem; - left: 1.25rem; -} - -.spinning-dots > span:nth-child(2) { - top: 0.75rem; - left: 1rem; -} - -.spinning-dots > span:nth-child(3) { - top: 1.25rem; - left: 0.75rem; -} - -.spinning-dots > span:nth-child(4) { - top: 1.5rem; - left: 0.5rem; -} - -@keyframes spinning-dots { - 0% { - transform: rotate(0deg); - } - 10% { - background-color: var(--dodgers-blue); - } - 20% { - background-color: var(--dodgers-red); - } - 30% { - background-color: var(--dodgers-yellow); - } - 40% { - background-color: var(--dodgers-blue); - } - 100% { - transform: rotate(360deg); - } -} - -.spinning-dots > span:nth-child(1) { animation: spinning-dots 2s infinite linear; } -.spinning-dots > span:nth-child(2) { animation: spinning-dots 2s infinite linear 0.1s; } -.spinning-dots > span:nth-child(3) { animation: spinning-dots 2s infinite linear 0.2s; } -.spinning-dots > span:nth-child(4) { animation: spinning-dots 2s infinite linear 0.3s; } - -/* ===== PROGRESS INDICATORS ===== */ - -@keyframes progress-bar { - from { width: 0%; } - to { width: 100%; } -} - -@keyframes progress-bar-stripes { - from { transform: translateX(0); } - to { transform: translateX(1rem); } -} - -@keyframes indeterminate { - 0% { transform: translateX(-100%) scaleX(1); } - 49.999% { transform: translateX(0%) scaleX(1); } - 50% { transform: translateX(0%) scaleX(1); } - 100% { transform: translateX(100%) scaleX(1); } -} - -.progress-bar { - position: relative; - height: 0.5rem; - background-color: var(--dodgers-gray-200); - border-radius: 0.25rem; - overflow: hidden; -} - -.progress-bar > .progress-fill { - height: 100%; - background: linear-gradient(90deg, var(--dodgers-blue) 0%, var(--dodgers-red) 100%); - border-radius: inherit; - transition: width 0.3s ease; - display: flex; - align-items: center; - justify-content: flex-end; - color: white; - font-size: 0.75rem; - padding-right: 0.25rem; -} - -.progress-bar-striped > .progress-fill { - background-image: linear-gradient( - 45deg, - rgba(255, 255, 255, 0.15) 25%, - transparent 25%, - transparent 50%, - rgba(255, 255, 255, 0.15) 50%, - rgba(255, 255, 255, 0.15) 75%, - transparent 75%, - transparent - ); - background-size: 1rem 1rem; - animation: progress-bar-stripes 1s linear infinite; -} - -.progress-bar-indeterminate > .progress-fill { - width: 30% !important; - animation: indeterminate 1.5s ease-in-out infinite; -} - -.progress-circular { - position: relative; - width: 3rem; - height: 3rem; -} - -.progress-circular > svg { - transform: rotate(-90deg); -} - -.progress-circular > svg circle { - cx: 1.5rem; - cy: 1.5rem; - r: 1.25rem; - fill: none; - stroke: var(--dodgers-gray-200); - stroke-width: 0.25rem; -} - -.progress-circular > svg circle.progress-fill { - stroke: var(--dodgers-blue); - stroke-linecap: round; - transition: stroke-dasharray 0.3s ease; -} - -/* ===== SKELETON LOADING STATES ===== */ - -@keyframes skeleton-pulse { - 0% { opacity: 1; } - 50% { opacity: 0.4; } - 100% { opacity: 1; } -} - -@keyframes skeleton-shimmer { - 0% { transform: translateX(-100%); } - 100% { transform: translateX(100%); } -} - -.skeleton { - background-color: var(--dodgers-gray-100); - border-radius: 0.25rem; - animation: skeleton-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; -} - -.skeleton-line { - height: 1rem; - margin-bottom: 0.5rem; -} - -.skeleton-line:last-child { - margin-bottom: 0; -} - -.skeleton-circle { - width: 2.5rem; - height: 2.5rem; - border-radius: 50%; -} - -.skeleton-rectangle { - width: 100%; - height: 8rem; - border-radius: 0.5rem; -} - -.skeleton-shimmer { - position: relative; - overflow: hidden; - background-color: var(--dodgers-gray-100); - border-radius: 0.25rem; -} - -.skeleton-shimmer::before { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: linear-gradient( - 90deg, - transparent, - rgba(255, 255, 255, 0.4), - transparent - ); - animation: skeleton-shimmer 1.5s infinite; -} - -.skeleton-light { - background-color: var(--dodgers-gray-50); -} - -.skeleton-dark { - background-color: var(--dodgers-gray-200); -} - -/* Skeleton card layout */ -.skeleton-card { - padding: 1rem; - border: 1px solid var(--dodgers-gray-200); - border-radius: 0.5rem; -} - -.skeleton-card-header { - display: flex; - align-items: center; - margin-bottom: 1rem; -} - -.skeleton-card-header .skeleton-circle { - margin-right: 0.75rem; - flex-shrink: 0; -} - -.skeleton-card-header .skeleton-line { - flex: 1; - height: 1.25rem; -} - -.skeleton-card-content .skeleton-line { - margin-bottom: 0.5rem; -} - -.skeleton-card-content .skeleton-line:nth-child(2) { width: 90%; } -.skeleton-card-content .skeleton-line:nth-child(3) { width: 75%; } - -/* Skeleton list layout */ -.skeleton-list { - display: flex; - flex-direction: column; - gap: 0.75rem; -} - -.skeleton-list-item { - display: flex; - align-items: center; - padding: 0.5rem 0; -} - -.skeleton-list-item .skeleton-circle { - width: 2rem; - height: 2rem; - margin-right: 0.75rem; - flex-shrink: 0; -} - -.skeleton-list-item .skeleton-content { - flex: 1; -} - -.skeleton-list-item .skeleton-content .skeleton-line { - height: 1rem; - margin-bottom: 0.25rem; -} - -.skeleton-list-item .skeleton-content .skeleton-line:nth-child(2) { width: 70%; } - -/* ===== ENGAGING LOADING EXPERIENCES ===== */ - -@keyframes loading-bounce { - 0%, 20%, 50%, 80%, 100% { transform: translateY(0); } - 40% { transform: translateY(-0.5rem); } - 60% { transform: translateY(-0.25rem); } -} - -@keyframes loading-elastic { - 0% { transform: scale(0.3); } - 40% { transform: scale(1); } - 80% { transform: scale(0.9); } - 100% { transform: scale(0.9); } -} - -@keyframes loading-wave { - 0% { transform: rotate(0deg); } - 10% { transform: rotate(14deg); } - 20% { transform: rotate(-8deg); } - 30% { transform: rotate(14deg); } - 40% { transform: rotate(-4deg); } - 50% { transform: rotate(10deg); } - 60% { transform: rotate(0deg); } - 100% { transform: rotate(0deg); } -} - -@keyframes loading-heartbeat { - 0% { transform: scale(1); } - 50% { transform: scale(1.1); } - 100% { transform: scale(1); } -} - -@keyframes loading-orbit { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -.loading-bounce { - animation: loading-bounce 2s infinite; -} - -.loading-elastic { - animation: loading-elastic 2s infinite; -} - -.loading-wave { - animation: loading-wave 2.5s infinite; -} - -.loading-heartbeat { - animation: loading-heartbeat 1s infinite; -} - -/* Orbit spinning loader */ -.loading-orbit { - position: relative; - width: 4rem; - height: 4rem; -} - -.loading-orbit > span { - position: absolute; - width: 0.5rem; - height: 0.5rem; - border-radius: 50%; - background-color: var(--dodgers-blue); -} - -.loading-orbit > span:nth-child(1) { top: 0; left: 50%; margin-left: -0.25rem; } -.loading-orbit > span:nth-child(2) { top: 12.5%; right: 12.5%; } -.loading-orbit > span:nth-child(3) { bottom: 12.5%; right: 12.5%; } -.loading-orbit > span:nth-child(4) { bottom: 0; left: 50%; margin-left: -0.25rem; } -.loading-orbit > span:nth-child(5) { bottom: 12.5%; left: 12.5%; } -.loading-orbit > span:nth-child(6) { top: 12.5%; left: 12.5%; } - -.loading-orbit > span:nth-child(1) { animation: loading-orbit 2s linear infinite; animation-delay: -1.9s; } -.loading-orbit > span:nth-child(2) { animation: loading-orbit 2s linear infinite; animation-delay: -1.6s; } -.loading-orbit > span:nth-child(3) { animation: loading-orbit 2s linear infinite; animation-delay: -1.3s; } -.loading-orbit > span:nth-child(4) { animation: loading-orbit 2s linear infinite; animation-delay: -1.0s; } -.loading-orbit > span:nth-child(5) { animation: loading-orbit 2s linear infinite; animation-delay: -0.7s; } -.loading-orbit > span:nth-child(6) { animation: loading-orbit 2s linear infinite; animation-delay: -0.4s; } - -/* Hourglass loader */ -@keyframes hourglass { - 0%, 100% { - transform: rotate(0deg); - border-radius: 0; - } - 25% { - transform: rotate(15deg); - } - 50% { - transform: rotate(0deg); - border-radius: 50% 0 50% 50%; - } - 75% { - transform: rotate(-15deg); - } -} - -.hourglass { - width: 2rem; - height: 2rem; - position: relative; - background: linear-gradient( - to bottom, - transparent 25%, - var(--dodgers-blue) 25%, - var(--dodgers-blue) 75%, - transparent 75% - ); - border-radius: 0 0 50% 50%; - animation: hourglass 2s infinite; - transform-origin: center bottom; -} - -.hourglass::after { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: 0.25rem; - height: 0.5rem; - background: var(--dodgers-blue); - transform: translate(-50%, -50%); -} - -/* Digital loading counter */ -.loading-counter { - font-family: 'Courier New', monospace; - font-size: 2rem; - font-weight: bold; - color: var(--dodgers-blue); - animation: loading-counter 2s linear infinite; - text-shadow: 0 0 10px rgba(30, 144, 255, 0.5); -} - -@keyframes loading-counter { - 0% { content: "0"; } - 10% { content: "1"; } - 20% { content: "2"; } - 30% { content: "3"; } - 40% { content: "4"; } - 50% { content: "5"; } - 60% { content: "6"; } - 70% { content: "7"; } - 80% { content: "8"; } - 90% { content: "9"; } - 100% { content: "0"; } -} - -/* Matrix-style loading */ -@keyframes matrix-rain { - 0% { opacity: 0; transform: translateY(-2rem); } - 10% { opacity: 1; } - 90% { opacity: 1; } - 100% { opacity: 0; transform: translateY(2rem); } -} - -.loading-matrix { - position: relative; - width: 3rem; - height: 3rem; - font-family: 'Courier New', monospace; - font-size: 1.5rem; - color: var(--dodgers-blue); - display: flex; - align-items: center; - justify-content: center; - overflow: hidden; -} - -.loading-matrix::before { - content: '01'; - position: absolute; - animation: matrix-rain 2s infinite; - animation-delay: -1s; -} - -.loading-matrix::after { - content: '10'; - position: absolute; - animation: matrix-rain 2s infinite; -} - -/* Cosmic loading effect */ -@keyframes cosmic-orbit { - 0% { - transform: rotate(0deg) scale(0.8); - opacity: 0.5; - } - 50% { - transform: rotate(180deg) scale(1.2); - opacity: 1; - } - 100% { - transform: rotate(360deg) scale(0.8); - opacity: 0.5; - } -} - -.loading-cosmic { - position: relative; - width: 4rem; - height: 4rem; -} - -.loading-cosmic > span { - position: absolute; - width: 0.75rem; - height: 0.75rem; - border-radius: 50%; - background: linear-gradient(45deg, var(--dodgers-blue), var(--dodgers-red)); - box-shadow: 0 0 10px rgba(30, 144, 255, 0.6); -} - -.loading-cosmic > span:nth-child(1) { - top: 0; - left: 50%; - margin-left: -0.375rem; - animation: cosmic-orbit 3s infinite linear; -} - -.loading-cosmic > span:nth-child(2) { - top: 25%; - right: 0; - margin-top: -0.375rem; - animation: cosmic-orbit 3s infinite linear; - animation-delay: -1s; - background: linear-gradient(45deg, var(--dodgers-red), var(--dodgers-yellow)); - box-shadow: 0 0 10px rgba(220, 20, 60, 0.6); -} - -.loading-cosmic > span:nth-child(3) { - bottom: 25%; - right: 0; - margin-bottom: -0.375rem; - animation: cosmic-orbit 3s infinite linear; - animation-delay: -2s; - background: linear-gradient(45deg, var(--dodgers-yellow), var(--dodgers-blue)); - box-shadow: 0 0 10px rgba(255, 215, 0, 0.6); -}