add linting, redesign pages, move css to files

This commit is contained in:
Cipher Vance
2026-01-21 07:32:34 -06:00
parent d3c1dabf64
commit b50d28be20
16 changed files with 6530 additions and 4466 deletions

View File

@@ -0,0 +1,7 @@
{
"permissions": {
"allow": [
"Bash(npm run lint:*)"
]
}
}

View File

@@ -9,6 +9,13 @@ export default {
</script>
<style>
/* Import shared styles */
@import './styles/tokens.css';
@import './styles/components.css';
@import './styles/modern-components.css';
@import './styles/animations.css';
/* Global reset and base styles */
* {
margin: 0;
padding: 0;
@@ -16,12 +23,11 @@ export default {
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
font-family: var(--font-family);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: #f5f5f5;
background-color: var(--color-background);
color: var(--color-text-primary);
}
#app {

View File

@@ -1,48 +1,92 @@
<template>
<nav class="modern-navbar">
<div class="navbar-container">
<!-- Enhanced Logo with Better Typography -->
<RouterLink to="/dashboard" class="navbar-brand">
<h1>RideAware</h1>
<span class="tagline">Train Smart. Ride Aware.</span>
<div class="brand-logo">
<svg viewBox="0 0 32 32" class="logo-icon">
<circle cx="16" cy="16" r="14" fill="url(#logoGradient)" />
<path d="M12 10L16 6L20 10L16 14L12 10Z" fill="white" opacity="0.9" />
<circle cx="16" cy="22" r="3" fill="white" opacity="0.9" />
<defs>
<linearGradient id="logoGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#0066cc;stop-opacity:1" />
<stop offset="100%" style="stop-color:#0052a3;stop-opacity:1" />
</linearGradient>
</defs>
</svg>
<div class="brand-text">
<h1>RideAware</h1>
<span class="tagline">Train Smart. Ride Aware.</span>
</div>
</div>
</RouterLink>
<button class="mobile-menu-toggle" @click="toggleMobileMenu" :class="{ active: mobileMenuOpen }">
<!-- Mobile Menu Toggle -->
<button
class="mobile-menu-toggle"
@click="toggleMobileMenu"
:class="{ active: mobileMenuOpen }"
aria-label="Toggle navigation menu"
>
<span></span>
<span></span>
<span></span>
</button>
<!-- Navigation Menu -->
<div class="navbar-menu" :class="{ active: mobileMenuOpen }">
<!-- Navigation Links with btn-modern-secondary -->
<div class="nav-links">
<RouterLink to="/dashboard" class="nav-link" @click="closeMobileMenu">
<RouterLink
to="/dashboard"
class="nav-link btn-modern btn-modern-secondary"
@click="closeMobileMenu"
>
<svg viewBox="0 0 24 24" fill="none">
<path d="M3 9L12 2L21 9V20C21 20.5304 20.7893 21.0391 20.4142 21.4142C20.0391 21.7893 19.5304 22 19 22H5C4.46957 22 3.96086 21.7893 3.58579 21.4142C3.21071 21.0391 3 20.5304 3 20V9Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span>Dashboard</span>
</RouterLink>
<RouterLink to="/profile" class="nav-link" @click="closeMobileMenu">
<RouterLink
to="/profile"
class="nav-link btn-modern btn-modern-secondary"
@click="closeMobileMenu"
>
<svg viewBox="0 0 24 24" fill="none">
<path d="M20 21V19C20 17.9391 19.5786 16.9217 18.8284 16.1716C18.0783 15.4214 17.0609 15 16 15H8C6.93913 15 5.92172 15.4214 5.17157 16.1716C4.42143 16.9217 4 17.9391 4 19V21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="12" cy="7" r="4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span>Profile</span>
</RouterLink>
<RouterLink to="/equipment" class="nav-link" @click="closeMobileMenu">
<RouterLink
to="/equipment"
class="nav-link btn-modern btn-modern-secondary"
@click="closeMobileMenu"
>
<svg viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="2"/>
<path d="M12 1V3M12 21V23M4.22 4.22L5.64 5.64M18.36 18.36L19.78 19.78M1 12H3M21 12H23M4.22 19.78L5.64 18.36M18.36 5.64L19.78 4.22" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
<span>Equipment</span>
</RouterLink>
<RouterLink to="/zones" class="nav-link" @click="closeMobileMenu">
<RouterLink
to="/zones"
class="nav-link btn-modern btn-modern-secondary"
@click="closeMobileMenu"
>
<svg viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="1" fill="currentColor"/>
<circle cx="19" cy="12" r="1" fill="currentColor"/>
<circle cx="5" cy="12" r="1" fill="currentColor"/>
<path d="M12 2L2 7L12 12L22 7L12 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 17L12 22L22 17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 12L12 17L22 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span>Zones</span>
</RouterLink>
<RouterLink to="/calendar" class="nav-link" @click="closeMobileMenu">
<RouterLink
to="/calendar"
class="nav-link btn-modern btn-modern-secondary"
@click="closeMobileMenu"
>
<svg viewBox="0 0 24 24" fill="none">
<rect x="3" y="4" width="18" height="18" rx="2" ry="2" stroke="currentColor" stroke-width="2"/>
<line x1="16" y1="2" x2="16" y2="6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
@@ -52,10 +96,17 @@
<span>Calendar</span>
</RouterLink>
</div>
<!-- Navigation Actions -->
<div class="nav-actions">
<button class="theme-toggle" @click="toggleTheme" :title="isDarkMode ? 'Light mode' : 'Dark mode'">
<svg v-if="isDarkMode" viewBox="0 0 24 24" fill="none">
<!-- Enhanced Dark Mode Toggle -->
<button
class="theme-toggle btn-modern btn-modern-secondary"
@click="toggleTheme"
:title="isDarkMode ? 'Switch to light mode' : 'Switch to dark mode'"
aria-label="Toggle theme"
>
<svg v-if="isDarkMode" viewBox="0 0 24 24" fill="none" class="theme-icon">
<circle cx="12" cy="12" r="5" stroke="currentColor" stroke-width="2"/>
<line x1="12" y1="1" x2="12" y2="3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<line x1="12" y1="21" x2="12" y2="23" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
@@ -66,46 +117,66 @@
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
<svg v-else viewBox="0 0 24 24" fill="none">
<svg v-else viewBox="0 0 24 24" fill="none" class="theme-icon">
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span class="theme-text">{{ isDarkMode ? 'Light' : 'Dark' }}</span>
</button>
<!-- Enhanced User Menu -->
<div class="user-menu">
<button class="user-avatar" @click="toggleUserMenu">
<button
class="user-avatar"
@click="toggleUserMenu"
aria-label="User menu"
>
<svg viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
<path d="M12 14C14.21 14 16 12.21 16 10C16 7.79 14.21 6 12 6C9.79 6 8 7.79 8 10C8 12.21 9.79 14 12 14Z" stroke="currentColor" stroke-width="2"/>
<path d="M12 14C10.5 15.5 8 16.5 8 18.5V20C8 20.5304 8.21071 21.0391 8.58579 21.4142C8.96086 21.7893 9.46957 22 10 22H14C14.5304 22 15.0391 21.7893 15.4142 21.4142C15.7893 21.0391 16 20.5304 16 20V18.5C16 16.5 13.5 15.5 12 14Z" stroke="currentColor" stroke-width="2"/>
<circle cx="12" cy="8" r="4" stroke="currentColor" stroke-width="2"/>
<path d="M6 21V19C6 17.3431 7.34315 16 9 16H15C16.6569 16 18 17.3431 18 19V21" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
</button>
<div class="user-dropdown" :class="{ active: userMenuOpen }">
<div class="user-info">
<div class="user-avatar-large">
<svg viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="8" r="4" stroke="currentColor" stroke-width="2"/>
<path d="M6 21V19C6 17.3431 7.34315 16 9 16H15C16.6569 16 18 17.3431 18 19V21" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
</div>
<p class="username">{{ auth.user?.username || 'User' }}</p>
<small>{{ auth.user?.email || 'user@example.com' }}</small>
</div>
<hr>
<div class="dropdown-divider"></div>
<RouterLink to="/profile" class="dropdown-item" @click="closeMenus">
<svg viewBox="0 0 24 24" fill="none">
<path d="M20 21V19C20 17.9391 19.5786 16.9217 18.8284 16.1716C18.0783 15.4214 17.0609 15 16 15H8C6.93913 15 5.92172 15.4214 5.17157 16.1716C4.42143 16.9217 4 17.9391 4 19V21" stroke="currentColor" stroke-width="2"/>
<circle cx="12" cy="7" r="4" stroke="currentColor" stroke-width="2"/>
</svg>
Edit Profile
<span>Edit Profile</span>
</RouterLink>
<RouterLink to="/equipment" class="dropdown-item" @click="closeMenus">
<svg viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="2"/>
<path d="M12 1V3M12 21V23M4.22 4.22L5.64 5.64M18.36 18.36L19.78 19.78M1 12H3M21 12H23M4.22 19.78L5.64 18.36M18.36 5.64L19.78 4.22" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
<span>Equipment</span>
</RouterLink>
<RouterLink to="/zones" class="dropdown-item" @click="closeMenus">
<svg viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="1" fill="currentColor"/>
<circle cx="19" cy="12" r="1" fill="currentColor"/>
<circle cx="5" cy="12" r="1" fill="currentColor"/>
<path d="M12 2L2 7L12 12L22 7L12 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 17L12 22L22 17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 12L12 17L22 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Training Zones
<span>Training Zones</span>
</RouterLink>
<button @click="handleLogout" class="logout-btn">
<div class="dropdown-divider"></div>
<button @click="handleLogout" class="dropdown-item logout-btn">
<svg viewBox="0 0 24 24" fill="none">
<path d="M9 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V5C3 4.46957 3.21071 3.96086 3.58579 3.58579C3.96086 3.21071 4.46957 3 5 3H9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<polyline points="16,17 21,12 16,7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="21" y1="12" x2="9" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
Logout
<span>Logout</span>
</button>
</div>
</div>
@@ -160,50 +231,77 @@ function handleLogout() {
</script>
<style scoped>
/* Modern Navbar with Enhanced Design */
.modern-navbar {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
background: var(--glass-background);
backdrop-filter: var(--glass-blur);
border-bottom: 1px solid var(--color-border);
position: sticky;
top: 0;
z-index: 100;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
z-index: var(--z-sticky);
transition: all var(--transition-slow);
box-shadow: var(--shadow-sm);
}
.navbar-container {
max-width: 1400px;
margin: 0 auto;
padding: 0.75rem 2rem;
padding: var(--spacing-md) var(--spacing-xl);
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--spacing-xl);
}
/* Enhanced Brand Logo */
.navbar-brand {
display: flex;
flex-direction: column;
gap: 0;
text-decoration: none;
cursor: pointer;
transition: opacity var(--transition-base);
}
.navbar-brand h1 {
.navbar-brand:hover {
opacity: 0.9;
}
.brand-logo {
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.logo-icon {
width: 42px;
height: 42px;
flex-shrink: 0;
}
.brand-text {
display: flex;
flex-direction: column;
gap: 2px;
}
.brand-text h1 {
margin: 0;
font-size: 1.5rem;
font-weight: 700;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
font-size: var(--font-size-xl);
font-weight: var(--font-weight-bold);
background: var(--gradient-primary);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
letter-spacing: -0.5px;
line-height: 1.2;
}
.tagline {
font-size: 0.75rem;
color: #6b7280;
font-weight: 500;
margin-top: -2px;
font-size: var(--font-size-xs);
color: var(--color-text-secondary);
font-weight: var(--font-weight-medium);
letter-spacing: 0.3px;
}
/* Mobile Menu Toggle */
.mobile-menu-toggle {
display: none;
flex-direction: column;
@@ -211,100 +309,119 @@ function handleLogout() {
background: none;
border: none;
cursor: pointer;
padding: 0.5rem;
padding: var(--spacing-xs);
z-index: calc(var(--z-sticky) + 1);
}
.mobile-menu-toggle span {
width: 24px;
height: 2px;
background: #1f2937;
border-radius: 1px;
transition: all 0.3s ease;
height: 3px;
background: var(--color-text-primary);
border-radius: var(--radius-sm);
transition: all var(--transition-base);
}
.mobile-menu-toggle.active span:nth-child(1) {
transform: rotate(45deg) translate(8px, 8px);
transform: rotate(45deg) translate(7px, 7px);
}
.mobile-menu-toggle.active span:nth-child(2) {
opacity: 0;
transform: translateX(-10px);
}
.mobile-menu-toggle.active span:nth-child(3) {
transform: rotate(-45deg) translate(7px, -7px);
}
/* Navigation Menu */
.navbar-menu {
display: flex;
align-items: center;
gap: 2rem;
gap: var(--spacing-xl);
flex: 1;
justify-content: flex-end;
}
/* Navigation Links with btn-modern-secondary */
.nav-links {
display: flex;
gap: 1.5rem;
align-items: center;
gap: var(--spacing-sm);
}
.nav-link {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
border-radius: 0.75rem;
padding: var(--spacing-xs) var(--spacing-md);
font-size: var(--font-size-sm);
text-decoration: none;
color: #374151;
font-weight: 500;
transition: all 0.2s ease;
font-size: 0.95rem;
white-space: nowrap;
position: relative;
}
.nav-link svg {
width: 16px;
height: 16px;
}
.nav-link:hover {
background: rgba(102, 126, 234, 0.1);
color: #667eea;
transform: translateY(-1px);
width: 18px;
height: 18px;
flex-shrink: 0;
}
/* Active State Indicator */
.nav-link.router-link-active {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
background: var(--color-primary);
color: var(--color-text-inverse);
border-color: var(--color-primary);
box-shadow: 0 2px 8px rgba(0, 102, 204, 0.25);
position: relative;
}
.nav-link.router-link-active::after {
content: '';
position: absolute;
bottom: -2px;
left: 50%;
transform: translateX(-50%);
width: 60%;
height: 3px;
background: var(--color-primary);
border-radius: var(--radius-full);
}
.nav-link.router-link-active:hover {
background: var(--color-primary-dark);
border-color: var(--color-primary-dark);
}
/* Navigation Actions */
.nav-actions {
display: flex;
align-items: center;
gap: 1rem;
gap: var(--spacing-sm);
padding-left: var(--spacing-lg);
border-left: 1px solid var(--color-border);
}
/* Enhanced Theme Toggle */
.theme-toggle {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 0.75rem;
background: #f3f4f6;
border: none;
color: #374151;
cursor: pointer;
transition: all 0.2s ease;
padding: var(--spacing-xs) var(--spacing-md);
min-width: auto;
position: relative;
}
.theme-toggle svg {
.theme-toggle .theme-icon {
width: 18px;
height: 18px;
transition: transform var(--transition-base);
}
.theme-toggle:hover {
background: #e5e7eb;
.theme-toggle .theme-text {
font-size: var(--font-size-sm);
font-weight: var(--font-weight-medium);
}
.theme-toggle:hover .theme-icon {
transform: rotate(20deg);
}
/* User Menu */
.user-menu {
position: relative;
}
@@ -313,41 +430,44 @@ function handleLogout() {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 0.75rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
width: 42px;
height: 42px;
border-radius: var(--radius-md);
background: var(--gradient-primary);
border: none;
color: white;
color: var(--color-text-inverse);
cursor: pointer;
transition: all 0.2s ease;
transition: all var(--transition-base);
box-shadow: 0 2px 8px rgba(0, 102, 204, 0.2);
}
.user-avatar svg {
width: 20px;
height: 20px;
width: 22px;
height: 22px;
}
.user-avatar:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
box-shadow: 0 4px 12px rgba(0, 102, 204, 0.3);
}
/* Enhanced User Dropdown */
.user-dropdown {
position: absolute;
top: 100%;
top: calc(100% + var(--spacing-xs));
right: 0;
margin-top: 0.5rem;
background: white;
border-radius: 1rem;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
background: var(--color-surface);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-xl);
border: 1px solid var(--color-border);
padding: 0;
min-width: 250px;
min-width: 280px;
opacity: 0;
visibility: hidden;
transform: translateY(-10px);
transition: all 0.3s ease;
z-index: 1000;
transition: all var(--transition-slow);
z-index: var(--z-dropdown);
overflow: hidden;
}
.user-dropdown.active {
@@ -356,72 +476,121 @@ function handleLogout() {
transform: translateY(0);
}
/* Enhanced User Info Section */
.user-info {
padding: 1rem;
border-bottom: 1px solid #e5e7eb;
padding: var(--spacing-lg);
background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-dark) 100%);
color: var(--color-text-inverse);
display: flex;
flex-direction: column;
align-items: center;
gap: var(--spacing-sm);
}
.user-avatar-large {
width: 56px;
height: 56px;
border-radius: var(--radius-full);
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
display: flex;
align-items: center;
justify-content: center;
border: 2px solid rgba(255, 255, 255, 0.3);
}
.user-avatar-large svg {
width: 28px;
height: 28px;
stroke: white;
}
.user-info .username {
margin: 0;
font-weight: 600;
color: #1f2937;
font-weight: var(--font-weight-bold);
color: white;
font-size: var(--font-size-lg);
text-align: center;
}
.user-info small {
display: block;
color: #6b7280;
margin-top: 0.25rem;
color: rgba(255, 255, 255, 0.9);
font-size: var(--font-size-xs);
text-align: center;
}
.dropdown-divider {
height: 1px;
background: var(--color-border);
margin: 0;
}
/* Enhanced Dropdown Items */
.dropdown-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem 1rem;
color: #374151;
gap: var(--spacing-sm);
padding: var(--spacing-md) var(--spacing-lg);
color: var(--color-text-primary);
text-decoration: none;
transition: all 0.2s ease;
border-bottom: 1px solid #f3f4f6;
transition: all var(--transition-base);
cursor: pointer;
background: none;
border: none;
width: 100%;
text-align: left;
font-size: var(--font-size-sm);
font-weight: var(--font-weight-medium);
}
.dropdown-item svg {
width: 16px;
height: 16px;
color: #667eea;
width: 20px;
height: 20px;
color: var(--color-primary);
transition: transform var(--transition-base);
flex-shrink: 0;
}
.dropdown-item span {
flex: 1;
}
.dropdown-item:hover {
background: #f8fafc;
color: #667eea;
background: var(--color-surface-hover);
color: var(--color-primary);
padding-left: calc(var(--spacing-lg) + 4px);
}
.dropdown-item:hover svg {
transform: translateX(2px);
}
.logout-btn {
width: 100%;
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem 1rem;
background: none;
border: none;
color: #ef4444;
text-align: left;
cursor: pointer;
transition: all 0.2s ease;
color: var(--color-danger);
}
.logout-btn svg {
width: 16px;
height: 16px;
color: var(--color-danger);
}
.logout-btn:hover {
background: #fef2f2;
background: rgba(230, 57, 70, 0.08);
color: var(--color-danger);
}
/* Mobile Responsive */
@media (max-width: 768px) {
/* Mobile Responsive Design */
@media (max-width: 992px) {
.navbar-container {
padding: 0.75rem 1rem;
padding: var(--spacing-sm) var(--spacing-lg);
}
.brand-text h1 {
font-size: var(--font-size-lg);
}
.logo-icon {
width: 36px;
height: 36px;
}
.mobile-menu-toggle {
@@ -430,21 +599,23 @@ function handleLogout() {
.navbar-menu {
position: fixed;
top: 100%;
top: 65px;
left: 0;
right: 0;
background: rgba(255, 255, 255, 0.98);
backdrop-filter: blur(20px);
background: var(--color-surface);
backdrop-filter: var(--glass-blur);
flex-direction: column;
gap: 1rem;
padding: 1.5rem;
border-top: 1px solid rgba(0, 0, 0, 0.08);
transform: translateY(-100%);
gap: var(--spacing-md);
padding: var(--spacing-lg);
border-top: 1px solid var(--color-border);
border-bottom: 1px solid var(--color-border);
transform: translateY(-150%);
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
max-height: calc(100vh - 60px);
transition: all var(--transition-slow);
max-height: calc(100vh - 65px);
overflow-y: auto;
box-shadow: var(--shadow-lg);
}
.navbar-menu.active {
@@ -455,26 +626,39 @@ function handleLogout() {
.nav-links {
flex-direction: column;
gap: 0.5rem;
gap: var(--spacing-xs);
width: 100%;
}
.nav-link {
width: 100%;
justify-content: flex-start;
padding: 1rem;
padding: var(--spacing-md);
font-size: var(--font-size-base);
}
.nav-link.router-link-active::after {
display: none;
}
.nav-actions {
flex-direction: column;
width: 100%;
gap: 1rem;
gap: var(--spacing-xs);
padding-left: 0;
border-left: none;
padding-top: var(--spacing-md);
border-top: 1px solid var(--color-border);
}
.theme-toggle {
width: 100%;
justify-content: flex-start;
background: #f3f4f6;
padding: var(--spacing-md);
}
.theme-toggle .theme-text {
display: inline;
}
.user-menu {
@@ -484,7 +668,13 @@ function handleLogout() {
.user-avatar {
width: 100%;
justify-content: flex-start;
padding: 0 1rem;
padding: var(--spacing-md);
border-radius: var(--radius-md);
height: auto;
}
.user-avatar svg {
margin-right: var(--spacing-sm);
}
.user-dropdown {
@@ -493,10 +683,39 @@ function handleLogout() {
visibility: visible;
transform: none;
margin: 0;
margin-top: var(--spacing-xs);
box-shadow: none;
background: #f9fafb;
border-top: 1px solid #e5e7eb;
border-bottom: 1px solid #e5e7eb;
border: 1px solid var(--color-border);
max-height: 0;
overflow: hidden;
transition: max-height var(--transition-slow);
}
.user-dropdown.active {
max-height: 500px;
}
.dropdown-item {
font-size: var(--font-size-base);
}
}
@media (max-width: 480px) {
.navbar-container {
padding: var(--spacing-sm) var(--spacing-md);
}
.tagline {
display: none;
}
.brand-text h1 {
font-size: var(--font-size-base);
}
.logo-icon {
width: 32px;
height: 32px;
}
}
</style>

View File

@@ -178,8 +178,8 @@ function resetForm() {
flex-direction: column;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 1rem;
background: var(--gradient-primary);
padding: var(--spacing-md);
position: relative;
overflow: hidden;
}
@@ -188,14 +188,14 @@ function resetForm() {
RESET CARD
============================================ */
.reset-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border-radius: 2rem;
background: var(--glass-background);
backdrop-filter: var(--glass-blur);
border-radius: var(--radius-2xl);
max-width: 480px;
width: 100%;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
border: 1px solid rgba(255, 255, 255, 0.2);
animation: slideUp 0.6s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: var(--shadow-2xl);
border: 1px solid var(--glass-border);
animation: slideUp var(--transition-slower) cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
z-index: 10;
}
@@ -204,22 +204,22 @@ function resetForm() {
CARD HEADER
============================================ */
.card-header {
padding: 2.5rem 2rem 1rem;
padding: var(--spacing-2xl) var(--spacing-xl) var(--spacing-md);
text-align: center;
}
.logo-wrapper {
width: 80px;
height: 80px;
margin: 0 auto 1.5rem;
padding: 1.5rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 2rem;
color: white;
margin: 0 auto var(--spacing-lg);
padding: var(--spacing-lg);
background: var(--gradient-primary);
border-radius: var(--radius-2xl);
color: var(--color-text-inverse);
display: flex;
align-items: center;
justify-content: center;
animation: iconBounce 0.6s ease-out 0.2s both;
animation: iconBounce var(--transition-slower) ease-out 0.2s both;
}
.logo-wrapper svg {
@@ -228,42 +228,42 @@ function resetForm() {
}
h1 {
margin: 0 0 0.75rem 0;
color: #1f2937;
font-size: 2rem;
font-weight: 800;
animation: titleSlide 0.6s ease-out 0.3s both;
margin: 0 0 var(--spacing-sm) 0;
color: var(--color-text-primary);
font-size: var(--font-size-3xl);
font-weight: var(--font-weight-bold);
animation: titleSlide var(--transition-slower) ease-out 0.3s both;
}
.subtitle {
color: #6b7280;
font-size: 1rem;
line-height: 1.6;
color: var(--color-text-secondary);
font-size: var(--font-size-base);
line-height: var(--line-height-relaxed);
margin: 0;
animation: subtitleFade 0.6s ease-out 0.4s both;
animation: subtitleFade var(--transition-slower) ease-out 0.4s both;
}
/* ============================================
RESET FORM
============================================ */
.reset-form {
padding: 1rem 2rem;
padding: var(--spacing-md) var(--spacing-xl);
display: flex;
flex-direction: column;
gap: 1.5rem;
animation: formSlide 0.6s ease-out 0.5s both;
gap: var(--spacing-lg);
animation: formSlide var(--transition-slower) ease-out 0.5s both;
}
.form-group {
display: flex;
flex-direction: column;
gap: 0.75rem;
gap: var(--spacing-sm);
}
label {
font-weight: 600;
color: #374151;
font-size: 0.95rem;
font-weight: var(--font-weight-semibold);
color: var(--color-text-secondary);
font-size: var(--font-size-sm);
}
.input-wrapper {
@@ -274,45 +274,46 @@ label {
input {
width: 100%;
padding: 1rem 1rem 1rem 3rem;
border: 2px solid #e5e7eb;
border-radius: 1rem;
font-size: 1rem;
padding: var(--spacing-md) var(--spacing-md) var(--spacing-md) 3rem;
border: 2px solid var(--color-border);
border-radius: var(--radius-lg);
font-size: var(--font-size-base);
font-family: inherit;
transition: all 0.3s ease;
background: white;
transition: all var(--transition-slow);
background: var(--color-surface);
color: var(--color-text-primary);
box-sizing: border-box;
}
input:focus {
outline: none;
border-color: #667eea;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
transform: translateY(-2px);
}
input:disabled {
background: #f9fafb;
background: var(--color-surface-hover);
cursor: not-allowed;
opacity: 0.6;
}
input::placeholder {
color: #9ca3af;
color: var(--color-text-tertiary);
}
.input-icon {
position: absolute;
left: 1rem;
left: var(--spacing-md);
width: 20px;
height: 20px;
color: #9ca3af;
color: var(--color-text-tertiary);
pointer-events: none;
}
.helper-text {
font-size: 0.8rem;
color: #6b7280;
font-size: var(--font-size-xs);
color: var(--color-text-secondary);
margin: 0;
}
@@ -321,16 +322,16 @@ input::placeholder {
============================================ */
.btn-primary {
width: 100%;
padding: 1.125rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: var(--spacing-md);
background: var(--gradient-primary);
color: var(--color-text-inverse);
border: none;
border-radius: 1rem;
font-size: 1rem;
font-weight: 700;
border-radius: var(--radius-lg);
font-size: var(--font-size-base);
font-weight: var(--font-weight-bold);
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
transition: all var(--transition-slow);
box-shadow: var(--shadow-md);
display: flex;
align-items: center;
justify-content: center;
@@ -339,7 +340,7 @@ input::placeholder {
.btn-primary:hover:not(:disabled) {
transform: translateY(-3px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
box-shadow: var(--shadow-lg);
}
.btn-primary:active:not(:disabled) {
@@ -355,7 +356,7 @@ input::placeholder {
.loading-content {
display: flex;
align-items: center;
gap: 0.75rem;
gap: var(--spacing-sm);
}
.spinner {
@@ -368,23 +369,23 @@ input::placeholder {
SUCCESS SECTION
============================================ */
.success-section {
padding: 1rem 2rem 2rem;
padding: var(--spacing-md) var(--spacing-xl) var(--spacing-xl);
text-align: center;
animation: formSlide 0.6s ease-out;
animation: formSlide var(--transition-slower) ease-out;
}
.check-animation {
width: 80px;
height: 80px;
margin: 0 auto 1.5rem;
padding: 1.5rem;
background: linear-gradient(135deg, #10b981, #059669);
border-radius: 50%;
color: white;
margin: 0 auto var(--spacing-lg);
padding: var(--spacing-lg);
background: var(--gradient-secondary);
border-radius: var(--radius-full);
color: var(--color-text-inverse);
display: flex;
align-items: center;
justify-content: center;
animation: checkBounce 0.6s ease-out;
animation: checkBounce var(--transition-slower) ease-out;
}
.check-animation svg {
@@ -393,27 +394,27 @@ input::placeholder {
}
.success-section h3 {
margin: 0 0 1rem 0;
color: #065f46;
font-size: 1.5rem;
font-weight: 700;
margin: 0 0 var(--spacing-md) 0;
color: var(--color-secondary);
font-size: var(--font-size-2xl);
font-weight: var(--font-weight-bold);
}
.success-message {
margin: 0.5rem 0;
color: #6b7280;
line-height: 1.6;
font-size: 0.95rem;
margin: var(--spacing-sm) 0;
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
font-size: var(--font-size-sm);
}
.email-display {
color: #667eea !important;
font-weight: 600;
font-size: 1.1rem;
color: var(--color-primary) !important;
font-weight: var(--font-weight-semibold);
font-size: var(--font-size-lg);
background: rgba(102, 126, 234, 0.1);
padding: 0.75rem;
border-radius: 0.75rem;
margin: 1rem 0 !important;
padding: var(--spacing-sm);
border-radius: var(--radius-md);
margin: var(--spacing-md) 0 !important;
word-break: break-all;
}
@@ -423,18 +424,18 @@ input::placeholder {
.instructions {
display: flex;
flex-direction: column;
gap: 1rem;
margin: 1.5rem 0;
gap: var(--spacing-md);
margin: var(--spacing-lg) 0;
text-align: left;
}
.instruction-step {
display: flex;
gap: 1rem;
padding: 1rem;
background: #f8fafc;
border-radius: 0.75rem;
border-left: 4px solid #667eea;
gap: var(--spacing-md);
padding: var(--spacing-md);
background: var(--color-surface-hover);
border-radius: var(--radius-md);
border-left: 4px solid var(--color-primary);
}
.step-number {
@@ -444,23 +445,23 @@ input::placeholder {
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 50%;
font-weight: 700;
font-size: 1rem;
background: var(--gradient-primary);
color: var(--color-text-inverse);
border-radius: var(--radius-full);
font-weight: var(--font-weight-bold);
font-size: var(--font-size-base);
}
.step-content p {
margin: 0;
color: #374151;
font-size: 0.9rem;
line-height: 1.4;
color: var(--color-text-secondary);
font-size: var(--font-size-sm);
line-height: var(--line-height-normal);
}
.step-content p:first-child {
font-weight: 600;
color: #1f2937;
font-weight: var(--font-weight-semibold);
color: var(--color-text-primary);
margin-bottom: 0.25rem;
}
@@ -469,46 +470,46 @@ input::placeholder {
============================================ */
.spam-notice {
display: flex;
gap: 1rem;
padding: 1rem;
background: #fef3c7;
border: 1px solid #fcd34d;
border-radius: 0.75rem;
margin: 1rem 0;
gap: var(--spacing-md);
padding: var(--spacing-md);
background: rgba(245, 158, 11, 0.1);
border: 1px solid var(--color-warning);
border-radius: var(--radius-md);
margin: var(--spacing-md) 0;
}
.spam-notice svg {
width: 20px;
height: 20px;
color: #92400e;
color: var(--color-warning);
flex-shrink: 0;
margin-top: 2px;
}
.spam-notice p {
margin: 0;
color: #92400e;
font-size: 0.9rem;
line-height: 1.5;
color: var(--color-warning);
font-size: var(--font-size-sm);
line-height: var(--line-height-normal);
}
.spam-notice strong {
color: #78350f;
color: var(--color-warning);
}
/* ============================================
SECONDARY BUTTON
============================================ */
.btn-secondary {
padding: 0.875rem 1.5rem;
padding: var(--spacing-sm) var(--spacing-lg);
background: rgba(102, 126, 234, 0.1);
color: #667eea;
color: var(--color-primary);
border: 2px solid rgba(102, 126, 234, 0.2);
border-radius: 0.75rem;
font-weight: 600;
border-radius: var(--radius-md);
font-weight: var(--font-weight-semibold);
cursor: pointer;
transition: all 0.3s ease;
margin-top: 1rem;
transition: all var(--transition-slow);
margin-top: var(--spacing-md);
}
.btn-secondary:hover {
@@ -522,14 +523,14 @@ input::placeholder {
.error-message {
display: flex;
align-items: center;
gap: 0.75rem;
margin-top: 1rem;
padding: 1rem;
gap: var(--spacing-sm);
margin-top: var(--spacing-md);
padding: var(--spacing-md);
background: #fef2f2;
border: 1px solid #fecaca;
color: #dc2626;
border-radius: 0.75rem;
font-size: 0.9rem;
color: var(--color-danger);
border-radius: var(--radius-md);
font-size: var(--font-size-sm);
animation: shakeError 0.5s ease-out;
}
@@ -541,13 +542,13 @@ input::placeholder {
.error-title {
margin: 0 0 0.25rem 0;
font-weight: 600;
font-size: 0.95rem;
font-weight: var(--font-weight-semibold);
font-size: var(--font-size-sm);
}
.error-text {
margin: 0;
font-size: 0.85rem;
font-size: var(--font-size-sm);
opacity: 0.9;
}
@@ -557,7 +558,7 @@ input::placeholder {
.divider {
position: relative;
text-align: center;
margin: 2rem 0 1.5rem;
margin: var(--spacing-xl) 0 var(--spacing-lg);
z-index: 10;
}
@@ -573,11 +574,11 @@ input::placeholder {
.divider span {
position: relative;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 0 1rem;
color: white;
font-size: 0.9rem;
font-weight: 500;
background: var(--gradient-primary);
padding: 0 var(--spacing-md);
color: var(--color-text-inverse);
font-size: var(--font-size-sm);
font-weight: var(--font-weight-medium);
}
/* ============================================
@@ -585,7 +586,7 @@ input::placeholder {
============================================ */
.links-section {
text-align: center;
padding: 0 2rem 2rem;
padding: 0 var(--spacing-xl) var(--spacing-xl);
z-index: 10;
position: relative;
}
@@ -598,15 +599,15 @@ input::placeholder {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
gap: var(--spacing-sm);
color: rgba(255, 255, 255, 0.9);
text-decoration: none;
font-weight: 600;
padding: 0.75rem 1.5rem;
border-radius: 0.75rem;
font-weight: var(--font-weight-semibold);
padding: var(--spacing-sm) var(--spacing-lg);
border-radius: var(--radius-md);
background: rgba(255, 255, 255, 0.1);
transition: all 0.2s ease;
margin-bottom: 1rem;
transition: all var(--transition-base);
margin-bottom: var(--spacing-md);
}
.back-link svg {
@@ -620,33 +621,33 @@ input::placeholder {
}
.signup-prompt {
margin-top: 1rem;
margin-top: var(--spacing-md);
}
.signup-prompt p {
margin: 0 0 0.5rem 0;
margin: 0 0 var(--spacing-sm) 0;
color: rgba(255, 255, 255, 0.8);
font-size: 0.95rem;
font-size: var(--font-size-sm);
}
.signup-link {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: white;
gap: var(--spacing-sm);
color: var(--color-text-inverse);
text-decoration: none;
font-weight: 700;
transition: all 0.2s ease;
font-weight: var(--font-weight-bold);
transition: all var(--transition-base);
}
.signup-link svg {
width: 16px;
height: 16px;
transition: all 0.2s ease;
transition: all var(--transition-base);
}
.signup-link:hover {
gap: 0.75rem;
gap: var(--spacing-sm);
text-decoration: underline;
}
@@ -662,7 +663,7 @@ input::placeholder {
.decoration-blob {
position: absolute;
border-radius: 50%;
border-radius: var(--radius-full);
background: rgba(255, 255, 255, 0.1);
animation: float 8s ease-in-out infinite;
}
@@ -789,66 +790,66 @@ input::placeholder {
============================================ */
@media (max-width: 640px) {
.password-reset-container {
padding: 1rem;
padding: var(--spacing-md);
}
.reset-card {
border-radius: 1.5rem;
border-radius: var(--radius-xl);
}
.card-header {
padding: 2rem 1.5rem 1rem;
padding: var(--spacing-xl) var(--spacing-lg) var(--spacing-md);
}
.reset-form {
padding: 1rem 1.5rem;
padding: var(--spacing-md) var(--spacing-lg);
}
.success-section {
padding: 1rem 1.5rem 1.5rem;
padding: var(--spacing-md) var(--spacing-lg) var(--spacing-lg);
}
.links-section {
padding: 0 1.5rem 1.5rem;
padding: 0 var(--spacing-lg) var(--spacing-lg);
}
h1 {
font-size: 1.75rem;
font-size: var(--font-size-3xl);
}
.subtitle {
font-size: 0.95rem;
font-size: var(--font-size-sm);
}
.logo-wrapper {
width: 64px;
height: 64px;
margin-bottom: 1rem;
padding: 1rem;
margin-bottom: var(--spacing-md);
padding: var(--spacing-md);
}
.instructions {
gap: 0.75rem;
gap: var(--spacing-sm);
}
.instruction-step {
gap: 0.75rem;
padding: 0.75rem;
gap: var(--spacing-sm);
padding: var(--spacing-sm);
}
.step-number {
width: 32px;
height: 32px;
font-size: 0.9rem;
font-size: var(--font-size-sm);
}
.step-content p {
font-size: 0.85rem;
font-size: var(--font-size-sm);
}
.spam-notice {
gap: 0.75rem;
padding: 0.75rem;
gap: var(--spacing-sm);
padding: var(--spacing-sm);
}
.spam-notice svg {
@@ -857,25 +858,25 @@ input::placeholder {
}
.spam-notice p {
font-size: 0.85rem;
font-size: var(--font-size-sm);
}
.email-display {
font-size: 1rem;
font-size: var(--font-size-base);
word-break: break-word;
}
input {
padding: 0.875rem 0.875rem 0.875rem 2.75rem;
padding: var(--spacing-sm) var(--spacing-sm) var(--spacing-sm) 2.75rem;
font-size: 16px;
}
.input-icon {
left: 0.75rem;
left: var(--spacing-sm);
}
.divider {
margin: 1.5rem 0 1rem;
margin: var(--spacing-lg) 0 var(--spacing-md);
}
.divider::before {
@@ -885,11 +886,11 @@ input::placeholder {
.back-link {
width: 100%;
margin-bottom: 1rem;
margin-bottom: var(--spacing-md);
}
.signup-prompt p {
font-size: 0.9rem;
font-size: var(--font-size-sm);
}
.blob-1 {
@@ -910,28 +911,28 @@ input::placeholder {
@media (max-width: 480px) {
.reset-card {
border-radius: 1.25rem;
border-radius: var(--radius-lg);
}
.card-header {
padding: 1.5rem 1rem 0.75rem;
padding: var(--spacing-lg) var(--spacing-md) var(--spacing-sm);
}
.reset-form {
padding: 0.75rem 1rem;
gap: 1rem;
padding: var(--spacing-sm) var(--spacing-md);
gap: var(--spacing-md);
}
.success-section {
padding: 0.75rem 1rem 1rem;
padding: var(--spacing-sm) var(--spacing-md) var(--spacing-md);
}
.links-section {
padding: 0 1rem 1rem;
padding: 0 var(--spacing-md) var(--spacing-md);
}
h1 {
font-size: 1.5rem;
font-size: var(--font-size-2xl);
}
.logo-wrapper {
@@ -942,28 +943,28 @@ input::placeholder {
.check-animation {
width: 64px;
height: 64px;
margin-bottom: 1rem;
padding: 1rem;
margin-bottom: var(--spacing-md);
padding: var(--spacing-md);
}
label {
font-size: 0.9rem;
font-size: var(--font-size-sm);
}
.btn-primary {
padding: 1rem;
font-size: 0.95rem;
padding: var(--spacing-md);
font-size: var(--font-size-sm);
}
.btn-secondary {
padding: 0.75rem 1rem;
font-size: 0.9rem;
padding: var(--spacing-sm) var(--spacing-md);
font-size: var(--font-size-sm);
}
.error-message {
gap: 0.5rem;
padding: 0.75rem;
font-size: 0.85rem;
gap: var(--spacing-xs);
padding: var(--spacing-sm);
font-size: var(--font-size-sm);
}
.error-message svg {
@@ -972,21 +973,21 @@ input::placeholder {
}
.divider span {
font-size: 0.85rem;
font-size: var(--font-size-sm);
}
.signup-prompt {
margin-top: 0.75rem;
margin-top: var(--spacing-sm);
}
.signup-prompt p {
font-size: 0.85rem;
margin-bottom: 0.375rem;
font-size: var(--font-size-sm);
margin-bottom: var(--spacing-xs);
}
.back-link {
padding: 0.625rem 1rem;
font-size: 0.9rem;
padding: var(--spacing-xs) var(--spacing-md);
font-size: var(--font-size-sm);
}
}
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,46 +1,55 @@
<template>
<div class="login-container">
<div class="login-card">
<div class="card-header">
<div class="card-modern auth-card">
<div class="auth-header">
<div class="logo-wrapper">
<svg viewBox="0 0 24 24" fill="none">
<path d="M3 9L12 2L21 9V20C21 20.5304 20.7893 21.0391 20.4142 21.4142C20.0391 21.7893 19.5304 22 19 22H5C4.46957 22 3.96086 21.7893 3.58579 21.4142C3.21071 21.0391 3 20.5304 3 20V9Z" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<circle cx="12" cy="13" r="2" fill="currentColor"/>
</svg>
</div>
<h1>Welcome Back</h1>
<p class="subtitle">Train with Focus. Ride with Awareness.</p>
<h1>Welcome Back!</h1>
<p class="subtitle">Ready to track your training? Log in to continue your journey.</p>
</div>
<form @submit.prevent="handleLogin" class="login-form">
<form @submit.prevent="handleLogin" class="form-modern">
<!-- Username Field -->
<div class="form-group">
<label for="username">Username</label>
<div class="input-wrapper">
<input
id="username"
v-model="form.username"
type="text"
placeholder="Enter your username"
required
:disabled="auth.loading"
autocomplete="username"
/>
<svg class="input-icon" viewBox="0 0 24 24" fill="none">
<div class="form-group-modern">
<label for="username" class="form-label-modern">
<svg class="label-icon" viewBox="0 0 24 24" fill="none">
<path d="M20 21V19C20 17.9391 19.5786 16.9217 18.8284 16.1716C18.0783 15.4214 17.0609 15 16 15H8C6.93913 15 5.92172 15.4214 5.17157 16.1716C4.42143 16.9217 4 17.9391 4 19V21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="12" cy="7" r="4" stroke="currentColor" stroke-width="2"/>
</svg>
</div>
Username
</label>
<input
id="username"
v-model="form.username"
type="text"
class="form-input-modern"
placeholder="Enter your username"
required
:disabled="auth.loading"
autocomplete="username"
/>
<span class="form-helper-text">Your unique account identifier</span>
</div>
<!-- Password Field -->
<div class="form-group">
<label for="password">Password</label>
<div class="form-group-modern">
<label for="password" class="form-label-modern">
<svg class="label-icon" viewBox="0 0 24 24" fill="none">
<rect x="5" y="11" width="14" height="10" rx="2" stroke="currentColor" stroke-width="2"/>
<path d="M8 11V7C8 5.93913 8.42143 4.92172 9.17157 4.17157C9.92172 3.42143 10.9391 3 12 3C13.0609 3 14.0783 3.42143 14.8284 4.17157C15.5786 4.92172 16 5.93913 16 7V11" stroke="currentColor" stroke-width="2"/>
</svg>
Password
</label>
<div class="input-wrapper">
<input
id="password"
v-model="form.password"
:type="showPassword ? 'text' : 'password'"
class="form-input-modern"
placeholder="Enter your password"
required
:disabled="auth.loading"
@@ -49,8 +58,9 @@
<button
type="button"
@click="showPassword = !showPassword"
class="password-toggle"
class="password-toggle-btn"
:title="showPassword ? 'Hide password' : 'Show password'"
:aria-label="showPassword ? 'Hide password' : 'Show password'"
>
<svg v-if="showPassword" viewBox="0 0 24 24" fill="none">
<path d="M1 12S6 4 12 4C18 4 23 12 23 12S18 20 12 20C6 20 1 12 1 12Z" stroke="currentColor" stroke-width="2"/>
@@ -62,21 +72,59 @@
</svg>
</button>
</div>
<span class="form-helper-text">Keep your account secure</span>
</div>
<!-- Remember Me & Forgot Password -->
<div class="form-options">
<label class="remember-me">
<label class="remember-checkbox">
<input v-model="rememberMe" type="checkbox" />
<span>Remember me</span>
<span>Keep me logged in on this device</span>
</label>
<RouterLink to="/password-reset" class="forgot-password">
Forgot password?
<RouterLink to="/password-reset" class="forgot-link">
Forgot your password?
</RouterLink>
</div>
<!-- Info Box -->
<div class="info-box info-box-info">
<svg viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
<line x1="12" y1="8" x2="12" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<line x1="12" y1="16" x2="12.01" y2="16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
<div>
<strong>Tip:</strong> For security, never share your login credentials. Use a strong, unique password.
</div>
</div>
<!-- Error Message -->
<div v-if="auth.error" class="info-box info-box-danger">
<svg viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
<line x1="15" y1="9" x2="9" y2="15" stroke="currentColor" stroke-width="2"/>
<line x1="9" y1="9" x2="15" y2="15" stroke="currentColor" stroke-width="2"/>
</svg>
<div>
<div class="form-error-text">
<strong>Login Failed:</strong> {{ auth.error }}
</div>
</div>
</div>
<!-- Success State -->
<div v-if="loginSuccess" class="info-box info-box-success">
<svg viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
<path d="m9 12 2 2 4-4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<div>
<strong>Success!</strong> Redirecting to your dashboard...
</div>
</div>
<!-- Login Button -->
<button type="submit" :disabled="auth.loading" class="btn-primary">
<button type="submit" :disabled="auth.loading" class="btn-modern btn-modern-primary btn-modern-large">
<span v-if="auth.loading" class="loading-content">
<svg class="spinner" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none" opacity="0.25"/>
@@ -84,34 +132,28 @@
</svg>
Logging in...
</span>
<span v-else>Login</span>
<span v-else>
<svg viewBox="0 0 24 24" fill="none" style="width: 20px; height: 20px;">
<path d="M15 3H19C19.5304 3 20.0391 3.21071 20.4142 3.58579C20.7893 3.96086 21 4.46957 21 5V19C21 19.5304 20.7893 20.0391 20.4142 20.4142C20.0391 20.7893 19.5304 21 19 21H15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 17L15 12L10 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15 12H3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Log In
</span>
</button>
</form>
<!-- Error Message -->
<div v-if="auth.error" class="error-message">
<svg viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
<line x1="12" y1="8" x2="12" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<line x1="12" y1="16" x2="12.01" y2="16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
<div>
<p class="error-title">Login Failed</p>
<p class="error-text">{{ auth.error }}</p>
</div>
</div>
<!-- Divider -->
<div class="divider">
<span>Or</span>
<div class="auth-divider">
<span>New to RideAware?</span>
</div>
<!-- Sign Up Link -->
<div class="signup-section">
<p>Don't have an account?</p>
<RouterLink to="/signup" class="signup-link">
Sign up now
<svg viewBox="0 0 24 24" fill="none">
<div class="auth-footer">
<p>Don't have an account yet? Join the community!</p>
<RouterLink to="/signup" class="btn-modern btn-modern-secondary">
Create Free Account
<svg viewBox="0 0 24 24" fill="none" style="width: 20px; height: 20px;">
<line x1="5" y1="12" x2="19" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<polyline points="12 5 19 12 12 19" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
@@ -128,7 +170,12 @@
<!-- Bottom Link -->
<div class="bottom-link">
<RouterLink to="/">Back to Home</RouterLink>
<RouterLink to="/" class="btn-modern btn-modern-secondary">
<svg viewBox="0 0 24 24" fill="none" style="width: 16px; height: 16px;">
<path d="M19 12H5M12 19L5 12L12 5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Back to Home
</RouterLink>
</div>
</div>
</template>
@@ -143,6 +190,7 @@ const auth = useAuth()
const showPassword = ref(false)
const rememberMe = ref(false)
const loginSuccess = ref(false)
const form = reactive({
username: '',
@@ -159,9 +207,13 @@ async function handleLogin() {
localStorage.removeItem('rememberMe')
localStorage.removeItem('username')
}
router.push('/dashboard')
loginSuccess.value = true
setTimeout(() => {
router.push('/dashboard')
}, 1000)
} catch (error) {
console.error('Login error:', error)
loginSuccess.value = false
}
}
</script>
@@ -172,45 +224,39 @@ async function handleLogin() {
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 1rem;
background: var(--gradient-primary);
padding: var(--spacing-md);
position: relative;
overflow: hidden;
}
/* ============================================
LOGIN CARD
AUTH CARD
============================================ */
.login-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border-radius: 2rem;
padding: 3rem;
max-width: 480px;
.auth-card {
max-width: 520px;
width: 100%;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
border: 1px solid rgba(255, 255, 255, 0.2);
animation: slideUp 0.6s cubic-bezier(0.4, 0, 0.2, 1);
animation: slideUp var(--transition-slower) cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
z-index: 10;
}
/* ============================================
CARD HEADER
AUTH HEADER
============================================ */
.card-header {
.auth-header {
text-align: center;
margin-bottom: 2rem;
margin-bottom: var(--spacing-2xl);
}
.logo-wrapper {
width: 80px;
height: 80px;
margin: 0 auto 1.5rem;
padding: 1.5rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 2rem;
color: white;
margin: 0 auto var(--spacing-lg);
padding: var(--spacing-lg);
background: var(--gradient-primary);
border-radius: var(--radius-2xl);
color: var(--color-text-inverse);
display: flex;
align-items: center;
justify-content: center;
@@ -223,43 +269,30 @@ async function handleLogin() {
}
h1 {
margin: 0 0 0.75rem 0;
font-size: 2rem;
font-weight: 800;
color: #1f2937;
animation: titleSlide 0.6s ease-out 0.3s both;
margin: 0 0 var(--spacing-sm) 0;
font-size: var(--font-size-3xl);
font-weight: var(--font-weight-bold);
color: var(--color-text-primary);
animation: titleSlide var(--transition-slower) ease-out 0.3s both;
}
.subtitle {
margin: 0;
font-size: 1rem;
color: #6b7280;
font-weight: 500;
font-style: italic;
animation: subtitleFade 0.6s ease-out 0.4s both;
margin: var(--spacing-sm) 0 0 0;
font-size: var(--font-size-base);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
animation: subtitleFade var(--transition-slower) ease-out 0.4s both;
}
/* ============================================
LOGIN FORM
FORM ENHANCEMENTS
============================================ */
.login-form {
display: flex;
flex-direction: column;
gap: 1.5rem;
animation: formSlide 0.6s ease-out 0.5s both;
}
.form-group {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
label {
font-weight: 600;
color: #374151;
font-size: 0.95rem;
display: block;
.label-icon {
width: 18px;
height: 18px;
margin-right: var(--spacing-xs);
vertical-align: middle;
color: var(--color-primary);
}
.input-wrapper {
@@ -268,67 +301,31 @@ label {
align-items: center;
}
input {
width: 100%;
padding: 1rem 1rem 1rem 3rem;
border: 2px solid #e5e7eb;
border-radius: 1rem;
font-size: 1rem;
font-family: inherit;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
background: white;
box-sizing: border-box;
}
input:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
transform: translateY(-2px);
}
input:disabled {
background: #f9fafb;
cursor: not-allowed;
opacity: 0.6;
}
input::placeholder {
color: #9ca3af;
}
.input-icon {
.password-toggle-btn {
position: absolute;
left: 1rem;
width: 20px;
height: 20px;
color: #9ca3af;
pointer-events: none;
}
.password-toggle {
position: absolute;
right: 1rem;
right: 12px;
width: 24px;
height: 24px;
background: none;
border: none;
color: #9ca3af;
color: var(--color-text-secondary);
cursor: pointer;
transition: all 0.2s ease;
transition: all var(--transition-base);
display: flex;
align-items: center;
justify-content: center;
padding: 0;
padding: 4px;
border-radius: 4px;
}
.password-toggle svg {
.password-toggle-btn svg {
width: 100%;
height: 100%;
}
.password-toggle:hover {
color: #667eea;
.password-toggle-btn:hover {
color: var(--color-primary);
background: rgba(0, 102, 204, 0.1);
}
/* ============================================
@@ -338,186 +335,124 @@ input::placeholder {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.9rem;
font-size: var(--font-size-sm);
flex-wrap: wrap;
gap: var(--spacing-sm);
}
.remember-me {
.remember-checkbox {
display: flex;
align-items: center;
gap: 0.5rem;
gap: var(--spacing-sm);
cursor: pointer;
color: #374151;
font-weight: 500;
color: var(--color-text-secondary);
font-weight: var(--font-weight-medium);
user-select: none;
}
.remember-me input {
width: auto;
padding: 0;
border: 2px solid #e5e7eb;
border-radius: 0.375rem;
.remember-checkbox input {
width: 18px;
height: 18px;
cursor: pointer;
accent-color: #667eea;
margin: 0;
accent-color: var(--color-primary);
border: 2px solid var(--color-border);
border-radius: 4px;
}
.remember-me input:checked {
background: #667eea;
}
.forgot-password {
color: #667eea;
.forgot-link {
color: var(--color-primary);
text-decoration: none;
font-weight: 600;
transition: all 0.2s ease;
font-weight: var(--font-weight-semibold);
transition: all var(--transition-base);
}
.forgot-password:hover {
color: #764ba2;
.forgot-link:hover {
color: var(--color-primary-dark);
text-decoration: underline;
}
/* ============================================
SUBMIT BUTTON
BUTTON ENHANCEMENTS
============================================ */
.btn-primary {
.btn-modern-large {
width: 100%;
padding: 1.125rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 1rem;
font-size: 1rem;
font-weight: 700;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
display: flex;
align-items: center;
justify-content: center;
min-height: 52px;
}
.btn-primary:hover:not(:disabled) {
transform: translateY(-3px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}
.btn-primary:active:not(:disabled) {
transform: translateY(-1px);
}
.btn-primary:disabled {
opacity: 0.7;
cursor: not-allowed;
transform: none;
padding: 16px 32px;
font-size: var(--font-size-lg);
min-height: 56px;
}
.loading-content {
display: flex;
align-items: center;
gap: 0.75rem;
gap: var(--spacing-sm);
}
.spinner {
width: 20px;
height: 20px;
width: 22px;
height: 22px;
animation: spin 1s linear infinite;
}
/* ============================================
ERROR MESSAGE
INFO BOXES
============================================ */
.error-message {
.info-box {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
background: #fef2f2;
border: 2px solid #fecaca;
border-radius: 1rem;
color: #dc2626;
animation: slideInError 0.4s cubic-bezier(0.4, 0, 0.2, 1);
align-items: flex-start;
gap: var(--spacing-md);
}
.error-message svg {
width: 24px;
height: 24px;
.info-box svg {
width: 20px;
height: 20px;
flex-shrink: 0;
}
.error-title {
margin: 0 0 0.25rem 0;
font-weight: 600;
font-size: 0.95rem;
}
.error-text {
margin: 0;
font-size: 0.85rem;
opacity: 0.9;
margin-top: 2px;
}
/* ============================================
DIVIDER
============================================ */
.divider {
.auth-divider {
position: relative;
text-align: center;
margin: 1.5rem 0;
margin: var(--spacing-2xl) 0 var(--spacing-xl) 0;
}
.divider::before {
.auth-divider::before {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1px;
background: #e5e7eb;
height: 2px;
background: var(--color-divider);
}
.divider span {
.auth-divider span {
position: relative;
background: white;
padding: 0 1rem;
color: #9ca3af;
font-size: 0.9rem;
font-weight: 500;
background: var(--color-surface);
padding: 0 var(--spacing-lg);
color: var(--color-text-secondary);
font-size: var(--font-size-base);
font-weight: var(--font-weight-semibold);
}
/* ============================================
SIGNUP SECTION
AUTH FOOTER
============================================ */
.signup-section {
.auth-footer {
text-align: center;
}
.signup-section p {
margin: 0 0 0.75rem 0;
color: #6b7280;
font-size: 0.95rem;
.auth-footer p {
margin: 0 0 var(--spacing-md) 0;
color: var(--color-text-secondary);
font-size: var(--font-size-base);
line-height: var(--line-height-relaxed);
}
.signup-link {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: #667eea;
text-decoration: none;
font-weight: 700;
transition: all 0.2s ease;
}
.signup-link svg {
width: 16px;
height: 16px;
transition: all 0.2s ease;
}
.signup-link:hover {
color: #764ba2;
gap: 0.75rem;
.auth-footer .btn-modern {
width: 100%;
}
/* ============================================
@@ -532,7 +467,7 @@ input::placeholder {
.decoration-blob {
position: absolute;
border-radius: 50%;
border-radius: var(--radius-full);
background: rgba(255, 255, 255, 0.1);
animation: float 8s ease-in-out infinite;
}
@@ -566,23 +501,22 @@ input::placeholder {
============================================ */
.bottom-link {
position: absolute;
bottom: 2rem;
bottom: var(--spacing-2xl);
left: 50%;
transform: translateX(-50%);
z-index: 10;
}
.bottom-link a {
.bottom-link .btn-modern {
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(10px);
color: white;
text-decoration: none;
font-weight: 500;
transition: all 0.2s ease;
opacity: 0.8;
border: 1px solid rgba(255, 255, 255, 0.3);
}
.bottom-link a:hover {
opacity: 1;
text-decoration: underline;
.bottom-link .btn-modern:hover {
background: rgba(255, 255, 255, 0.25);
border-color: rgba(255, 255, 255, 0.5);
}
/* ============================================
@@ -642,17 +576,6 @@ input::placeholder {
}
}
@keyframes slideInError {
from {
transform: translateX(-20px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes spin {
from {
transform: rotate(0deg);
@@ -676,81 +599,39 @@ input::placeholder {
============================================ */
@media (max-width: 640px) {
.login-container {
padding: 1rem;
padding: var(--spacing-md);
}
.login-card {
padding: 2rem;
border-radius: 1.5rem;
.auth-card {
padding: var(--spacing-xl);
}
.card-header {
margin-bottom: 1.5rem;
.auth-header {
margin-bottom: var(--spacing-lg);
}
.logo-wrapper {
width: 64px;
height: 64px;
margin-bottom: 1rem;
padding: 1rem;
margin-bottom: var(--spacing-md);
padding: var(--spacing-md);
}
h1 {
font-size: 1.75rem;
font-size: var(--font-size-3xl);
}
.subtitle {
font-size: 0.9rem;
}
.login-form {
gap: 1.25rem;
font-size: var(--font-size-sm);
}
.form-options {
flex-direction: column;
gap: 1rem;
align-items: flex-start;
}
.remember-me {
width: 100%;
}
.forgot-password {
width: 100%;
text-align: center;
}
input {
padding: 0.875rem 0.875rem 0.875rem 2.75rem;
font-size: 16px;
}
.input-icon {
left: 0.75rem;
}
.password-toggle {
right: 0.75rem;
}
.error-message {
flex-direction: column;
text-align: center;
}
.divider {
margin: 1.25rem 0;
}
.divider::before {
left: -50px;
right: -50px;
}
.signup-section p {
font-size: 0.9rem;
.auth-divider {
margin: var(--spacing-xl) 0 var(--spacing-md) 0;
}
.blob-1 {
@@ -769,18 +650,17 @@ input::placeholder {
}
.bottom-link a {
font-size: 0.9rem;
font-size: var(--font-size-sm);
}
}
@media (max-width: 480px) {
.login-card {
padding: 1.5rem;
border-radius: 1.25rem;
.auth-card {
padding: var(--spacing-lg);
}
.card-header {
margin-bottom: 1.25rem;
.auth-header {
margin-bottom: var(--spacing-md);
}
.logo-wrapper {
@@ -789,87 +669,26 @@ input::placeholder {
}
h1 {
font-size: 1.5rem;
font-size: var(--font-size-2xl);
}
.subtitle {
font-size: 0.85rem;
}
label {
font-size: 0.9rem;
}
.btn-primary {
padding: 1rem;
font-size: 0.95rem;
}
.form-options {
font-size: 0.85rem;
}
.remember-me,
.forgot-password {
font-size: 0.85rem;
}
.divider span {
font-size: 0.85rem;
padding: 0 0.75rem;
}
.signup-section p {
margin-bottom: 0.5rem;
}
.signup-link {
font-size: 0.9rem;
}
.error-message {
gap: 0.75rem;
padding: 0.75rem;
}
.error-message svg {
width: 20px;
height: 20px;
}
.error-title {
font-size: 0.9rem;
}
.error-text {
font-size: 0.8rem;
font-size: var(--font-size-sm);
}
.bottom-link {
bottom: 1rem;
}
.bottom-link a {
font-size: 0.85rem;
bottom: var(--spacing-md);
}
}
/* Accessibility */
@media (prefers-reduced-motion: reduce) {
.login-card,
.auth-card,
.logo-wrapper,
h1,
.subtitle,
.login-form,
.error-message,
.decoration-blob {
animation: none;
}
input:focus,
.btn-primary:hover,
.password-toggle:hover {
transform: none;
}
}
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

218
src/styles/animations.css Normal file
View File

@@ -0,0 +1,218 @@
/* Common Animations */
/* Keyframe Animations */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideInLeft {
from {
opacity: 0;
transform: translateX(-20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideInRight {
from {
opacity: 0;
transform: translateX(20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
@keyframes float {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-10px);
}
}
@keyframes shimmer {
0% {
background-position: -1000px 0;
}
100% {
background-position: 1000px 0;
}
}
/* Animation Classes */
.animate-fadeIn {
animation: fadeIn var(--transition-slow) ease-out;
}
.animate-slideUp {
animation: slideUp var(--transition-slow) ease-out;
}
.animate-slideDown {
animation: slideDown var(--transition-slow) ease-out;
}
.animate-slideInLeft {
animation: slideInLeft var(--transition-slow) ease-out;
}
.animate-slideInRight {
animation: slideInRight var(--transition-slow) ease-out;
}
.animate-scaleIn {
animation: scaleIn var(--transition-slow) ease-out;
}
.animate-spin {
animation: spin 1s linear infinite;
}
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
.animate-float {
animation: float 3s ease-in-out infinite;
}
/* Animation Delays */
.delay-100 {
animation-delay: 0.1s;
}
.delay-200 {
animation-delay: 0.2s;
}
.delay-300 {
animation-delay: 0.3s;
}
.delay-400 {
animation-delay: 0.4s;
}
.delay-500 {
animation-delay: 0.5s;
}
/* Transition Classes */
.transition-all {
transition: all var(--transition-base);
}
.transition-transform {
transition: transform var(--transition-base);
}
.transition-opacity {
transition: opacity var(--transition-base);
}
.transition-colors {
transition: background-color var(--transition-base), border-color var(--transition-base), color var(--transition-base);
}
/* Hover Effects */
.hover-lift {
transition: transform var(--transition-base), box-shadow var(--transition-base);
}
.hover-lift:hover {
transform: translateY(-4px);
}
.hover-scale {
transition: transform var(--transition-base);
}
.hover-scale:hover {
transform: scale(1.05);
}
.hover-brightness:hover {
filter: brightness(1.1);
}
/* Loading States */
.loading-skeleton {
background: linear-gradient(
90deg,
var(--color-border) 0%,
var(--color-surface-hover) 50%,
var(--color-border) 100%
);
background-size: 200% 100%;
animation: shimmer 1.5s ease-in-out infinite;
border-radius: var(--radius-md);
}
.loading-spinner {
border: 3px solid var(--color-border);
border-top-color: var(--color-primary);
border-radius: 50%;
animation: spin 0.8s linear infinite;
}

375
src/styles/components.css Normal file
View File

@@ -0,0 +1,375 @@
/* Shared Component Styles */
/* Card Components */
.glass-card {
background: var(--glass-background);
backdrop-filter: var(--glass-blur);
border: 1px solid var(--glass-border);
border-radius: var(--radius-xl);
box-shadow: var(--shadow-glass);
transition: all var(--transition-base);
}
.glass-card:hover {
background: var(--glass-background-hover);
box-shadow: var(--shadow-glass-hover);
transform: translateY(-2px);
}
.card {
background: var(--color-surface);
border-radius: var(--radius-lg);
padding: var(--spacing-lg);
box-shadow: var(--shadow-md);
transition: all var(--transition-base);
}
.card:hover {
box-shadow: var(--shadow-lg);
transform: translateY(-2px);
}
/* Button Components */
.btn {
padding: var(--spacing-sm) var(--spacing-lg);
border-radius: var(--radius-md);
font-weight: var(--font-weight-medium);
font-size: var(--font-size-base);
transition: all var(--transition-base);
cursor: pointer;
border: none;
outline: none;
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--spacing-sm);
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.btn-primary {
background: var(--gradient-primary);
color: var(--color-text-inverse);
box-shadow: var(--shadow-md);
}
.btn-primary:hover:not(:disabled) {
box-shadow: var(--shadow-lg);
transform: translateY(-2px);
}
.btn-secondary {
background: var(--color-surface);
color: var(--color-text-primary);
border: 1px solid var(--color-border);
}
.btn-secondary:hover:not(:disabled) {
background: var(--color-surface-hover);
border-color: var(--color-border-hover);
}
.btn-danger {
background: var(--gradient-danger);
color: var(--color-text-inverse);
}
.btn-icon {
width: 40px;
height: 40px;
padding: 0;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
background: var(--color-surface);
border: 1px solid var(--color-border);
cursor: pointer;
transition: all var(--transition-base);
}
.btn-icon:hover {
background: var(--color-surface-hover);
border-color: var(--color-border-hover);
}
/* Input Components */
.input-group {
display: flex;
flex-direction: column;
gap: var(--spacing-sm);
}
.input-label {
font-size: var(--font-size-sm);
font-weight: var(--font-weight-medium);
color: var(--color-text-secondary);
}
.input-field {
width: 100%;
padding: var(--spacing-sm) var(--spacing-md);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
font-size: var(--font-size-base);
color: var(--color-text-primary);
background: var(--color-surface);
transition: all var(--transition-base);
}
.input-field:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.input-field::placeholder {
color: var(--color-text-tertiary);
}
.input-wrapper {
position: relative;
display: flex;
align-items: center;
}
.input-icon {
position: absolute;
left: var(--spacing-md);
color: var(--color-text-tertiary);
pointer-events: none;
}
.input-wrapper .input-field {
padding-left: 2.5rem;
}
/* Badge Components */
.badge {
display: inline-flex;
align-items: center;
padding: 0.25rem var(--spacing-sm);
border-radius: var(--radius-full);
font-size: var(--font-size-xs);
font-weight: var(--font-weight-medium);
}
.badge-success {
background: rgba(16, 185, 129, 0.1);
color: #10b981;
}
.badge-warning {
background: rgba(245, 158, 11, 0.1);
color: #f59e0b;
}
.badge-danger {
background: rgba(239, 68, 68, 0.1);
color: #ef4444;
}
.badge-info {
background: rgba(59, 130, 246, 0.1);
color: #3b82f6;
}
/* Gradient Text */
.gradient-text {
background: var(--gradient-primary);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Page Header */
.page-header {
margin-bottom: var(--spacing-xl);
}
.page-title {
font-size: var(--font-size-3xl);
font-weight: var(--font-weight-bold);
color: var(--color-text-primary);
margin-bottom: var(--spacing-sm);
}
.page-subtitle {
font-size: var(--font-size-lg);
color: var(--color-text-secondary);
}
/* Modal/Overlay */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: var(--z-modal-backdrop);
backdrop-filter: blur(4px);
}
.modal-content {
background: var(--color-surface);
border-radius: var(--radius-xl);
padding: var(--spacing-xl);
max-width: 90vw;
max-height: 90vh;
overflow-y: auto;
box-shadow: var(--shadow-2xl);
position: relative;
z-index: var(--z-modal);
}
/* Tab Navigation */
.tab-navigation {
display: flex;
gap: var(--spacing-md);
border-bottom: 2px solid var(--color-border);
margin-bottom: var(--spacing-xl);
}
.tab-button {
padding: var(--spacing-md) var(--spacing-lg);
background: none;
border: none;
border-bottom: 2px solid transparent;
color: var(--color-text-secondary);
font-weight: var(--font-weight-medium);
cursor: pointer;
transition: all var(--transition-base);
margin-bottom: -2px;
}
.tab-button:hover {
color: var(--color-text-primary);
}
.tab-button.active {
color: var(--color-primary);
border-bottom-color: var(--color-primary);
}
/* Progress Indicators */
.progress-ring {
transition: stroke-dashoffset var(--transition-slow);
}
.progress-bar {
height: 8px;
background: var(--color-border);
border-radius: var(--radius-full);
overflow: hidden;
}
.progress-bar-fill {
height: 100%;
background: var(--gradient-primary);
border-radius: var(--radius-full);
transition: width var(--transition-slow);
}
/* Stat Cards */
.stat-card {
display: flex;
flex-direction: column;
gap: var(--spacing-sm);
}
.stat-label {
font-size: var(--font-size-sm);
color: var(--color-text-secondary);
font-weight: var(--font-weight-medium);
}
.stat-value {
font-size: var(--font-size-2xl);
font-weight: var(--font-weight-bold);
color: var(--color-text-primary);
}
.stat-change {
font-size: var(--font-size-sm);
font-weight: var(--font-weight-medium);
}
.stat-change.positive {
color: var(--color-secondary);
}
.stat-change.negative {
color: var(--color-danger);
}
/* Utility Classes */
.flex {
display: flex;
}
.flex-col {
flex-direction: column;
}
.items-center {
align-items: center;
}
.justify-between {
justify-content: space-between;
}
.gap-sm {
gap: var(--spacing-sm);
}
.gap-md {
gap: var(--spacing-md);
}
.gap-lg {
gap: var(--spacing-lg);
}
.text-sm {
font-size: var(--font-size-sm);
}
.text-base {
font-size: var(--font-size-base);
}
.text-lg {
font-size: var(--font-size-lg);
}
.font-medium {
font-weight: var(--font-weight-medium);
}
.font-semibold {
font-weight: var(--font-weight-semibold);
}
.font-bold {
font-weight: var(--font-weight-bold);
}
.text-primary {
color: var(--color-text-primary);
}
.text-secondary {
color: var(--color-text-secondary);
}
.text-tertiary {
color: var(--color-text-tertiary);
}

View File

@@ -0,0 +1,541 @@
/* Modern Component Styles - TrainingPeaks/TrainerRoad Inspired */
/* Enhanced Cards */
.card-modern {
background: var(--color-surface);
border-radius: 12px;
padding: var(--spacing-xl);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
border: 1px solid var(--color-border);
transition: all var(--transition-base);
}
.card-modern:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
transform: translateY(-1px);
}
.card-modern-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-lg);
padding-bottom: var(--spacing-md);
border-bottom: 2px solid var(--color-divider);
}
.card-modern-title {
font-size: var(--font-size-xl);
font-weight: var(--font-weight-bold);
color: var(--color-text-primary);
margin: 0;
}
.card-modern-subtitle {
font-size: var(--font-size-sm);
color: var(--color-text-secondary);
margin: var(--spacing-xs) 0 0 0;
}
/* Metric Cards */
.metric-card {
background: var(--color-surface);
border-radius: 12px;
padding: var(--spacing-lg);
border: 1px solid var(--color-border);
transition: all var(--transition-base);
position: relative;
overflow: hidden;
}
.metric-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: var(--gradient-primary);
}
.metric-card:hover {
box-shadow: 0 4px 12px rgba(0, 102, 204, 0.15);
transform: translateY(-2px);
}
.metric-label {
font-size: var(--font-size-xs);
font-weight: var(--font-weight-semibold);
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: var(--spacing-xs);
}
.metric-value {
font-size: 2.5rem;
font-weight: var(--font-weight-bold);
color: var(--color-text-primary);
line-height: 1;
margin-bottom: var(--spacing-sm);
}
.metric-change {
font-size: var(--font-size-sm);
font-weight: var(--font-weight-medium);
display: flex;
align-items: center;
gap: var(--spacing-xs);
}
.metric-change.positive {
color: var(--color-secondary);
}
.metric-change.negative {
color: var(--color-danger);
}
/* Enhanced Buttons */
.btn-modern {
padding: 12px 24px;
border-radius: 8px;
font-weight: var(--font-weight-semibold);
font-size: var(--font-size-base);
transition: all var(--transition-base);
cursor: pointer;
border: none;
outline: none;
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--spacing-sm);
text-decoration: none;
white-space: nowrap;
}
.btn-modern:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.btn-modern-primary {
background: var(--color-primary);
color: white;
box-shadow: 0 2px 4px rgba(0, 102, 204, 0.2);
}
.btn-modern-primary:hover:not(:disabled) {
background: var(--color-primary-dark);
box-shadow: 0 4px 8px rgba(0, 102, 204, 0.3);
transform: translateY(-1px);
}
.btn-modern-secondary {
background: var(--color-surface);
color: var(--color-text-primary);
border: 2px solid var(--color-border);
}
.btn-modern-secondary:hover:not(:disabled) {
border-color: var(--color-primary);
color: var(--color-primary);
background: rgba(0, 102, 204, 0.05);
}
.btn-modern-success {
background: var(--color-secondary);
color: white;
box-shadow: 0 2px 4px rgba(0, 200, 83, 0.2);
}
.btn-modern-success:hover:not(:disabled) {
background: #00a844;
box-shadow: 0 4px 8px rgba(0, 200, 83, 0.3);
}
.btn-modern-large {
padding: 16px 32px;
font-size: var(--font-size-lg);
}
.btn-modern-small {
padding: 8px 16px;
font-size: var(--font-size-sm);
}
/* Status Pills */
.status-pill {
display: inline-flex;
align-items: center;
padding: 6px 12px;
border-radius: 16px;
font-size: var(--font-size-xs);
font-weight: var(--font-weight-semibold);
text-transform: uppercase;
letter-spacing: 0.3px;
}
.status-pill-completed {
background: rgba(0, 200, 83, 0.1);
color: #00a844;
}
.status-pill-planned {
background: rgba(255, 152, 0, 0.1);
color: #f57c00;
}
.status-pill-skipped {
background: rgba(230, 57, 70, 0.1);
color: #d62828;
}
.status-pill-active {
background: rgba(0, 102, 204, 0.1);
color: var(--color-primary);
}
/* Info Boxes */
.info-box {
padding: var(--spacing-md);
border-radius: 8px;
border-left: 4px solid;
font-size: var(--font-size-sm);
margin: var(--spacing-md) 0;
}
.info-box-info {
background: rgba(0, 188, 212, 0.1);
border-color: var(--color-info);
color: #00838f;
}
.info-box-warning {
background: rgba(255, 152, 0, 0.1);
border-color: var(--color-warning);
color: #ef6c00;
}
.info-box-success {
background: rgba(0, 200, 83, 0.1);
border-color: var(--color-secondary);
color: #00a844;
}
.info-box-danger {
background: rgba(230, 57, 70, 0.1);
border-color: var(--color-danger);
color: #d62828;
}
/* Enhanced Forms */
.form-modern {
display: flex;
flex-direction: column;
gap: var(--spacing-lg);
}
.form-group-modern {
display: flex;
flex-direction: column;
gap: var(--spacing-xs);
}
.form-label-modern {
font-size: var(--font-size-sm);
font-weight: var(--font-weight-semibold);
color: var(--color-text-primary);
margin-bottom: var(--spacing-xs);
}
.form-input-modern {
padding: 12px 16px;
border: 2px solid var(--color-border);
border-radius: 8px;
font-size: var(--font-size-base);
color: var(--color-text-primary);
background: var(--color-surface);
transition: all var(--transition-base);
font-family: var(--font-family);
}
.form-input-modern:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);
}
.form-input-modern::placeholder {
color: var(--color-text-muted);
}
.form-input-modern:disabled {
background: var(--color-surface-secondary);
cursor: not-allowed;
opacity: 0.6;
}
.form-helper-text {
font-size: var(--font-size-xs);
color: var(--color-text-secondary);
margin-top: var(--spacing-xs);
}
.form-error-text {
font-size: var(--font-size-xs);
color: var(--color-danger);
margin-top: var(--spacing-xs);
display: flex;
align-items: center;
gap: var(--spacing-xs);
}
/* Data Tables */
.table-modern {
width: 100%;
border-collapse: collapse;
background: var(--color-surface);
border-radius: 12px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.table-modern thead {
background: var(--color-surface-secondary);
}
.table-modern th {
padding: 16px;
text-align: left;
font-size: var(--font-size-xs);
font-weight: var(--font-weight-bold);
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
border-bottom: 2px solid var(--color-divider);
}
.table-modern td {
padding: 16px;
font-size: var(--font-size-sm);
color: var(--color-text-primary);
border-bottom: 1px solid var(--color-border);
}
.table-modern tbody tr {
transition: background var(--transition-fast);
}
.table-modern tbody tr:hover {
background: var(--color-surface-hover);
}
.table-modern tbody tr:last-child td {
border-bottom: none;
}
/* Progress Bars */
.progress-bar-modern {
width: 100%;
height: 8px;
background: var(--color-border);
border-radius: 4px;
overflow: hidden;
position: relative;
}
.progress-bar-modern-fill {
height: 100%;
background: var(--gradient-primary);
border-radius: 4px;
transition: width var(--transition-slow);
position: relative;
overflow: hidden;
}
.progress-bar-modern-fill::after {
content: '';
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.3),
transparent
);
animation: shimmer 2s infinite;
}
/* Tooltips */
.tooltip {
position: relative;
display: inline-block;
}
.tooltip-text {
visibility: hidden;
background: var(--color-text-primary);
color: white;
text-align: center;
padding: 8px 12px;
border-radius: 6px;
font-size: var(--font-size-xs);
position: absolute;
z-index: var(--z-tooltip);
bottom: 125%;
left: 50%;
transform: translateX(-50%);
white-space: nowrap;
opacity: 0;
transition: opacity var(--transition-base);
}
.tooltip:hover .tooltip-text {
visibility: visible;
opacity: 1;
}
/* Empty States */
.empty-state-modern {
text-align: center;
padding: var(--spacing-4xl) var(--spacing-xl);
}
.empty-state-icon {
font-size: 64px;
margin-bottom: var(--spacing-lg);
opacity: 0.3;
}
.empty-state-title {
font-size: var(--font-size-2xl);
font-weight: var(--font-weight-bold);
color: var(--color-text-primary);
margin-bottom: var(--spacing-sm);
}
.empty-state-description {
font-size: var(--font-size-base);
color: var(--color-text-secondary);
margin-bottom: var(--spacing-xl);
max-width: 400px;
margin-left: auto;
margin-right: auto;
}
/* Loading States */
.loading-spinner-modern {
width: 40px;
height: 40px;
border: 4px solid var(--color-border);
border-top-color: var(--color-primary);
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
.loading-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.9);
display: flex;
align-items: center;
justify-content: center;
z-index: var(--z-modal);
border-radius: inherit;
}
/* Section Headers */
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-xl);
}
.section-title {
font-size: var(--font-size-3xl);
font-weight: var(--font-weight-bold);
color: var(--color-text-primary);
margin: 0;
}
.section-description {
font-size: var(--font-size-base);
color: var(--color-text-secondary);
margin-top: var(--spacing-xs);
}
/* Zone Color Bars */
.zone-bar {
height: 6px;
border-radius: 3px;
background: var(--color-border);
position: relative;
overflow: hidden;
margin-top: var(--spacing-sm);
}
.zone-bar-fill {
height: 100%;
border-radius: 3px;
transition: width var(--transition-slow);
}
/* Icon Badges */
.icon-badge {
width: 48px;
height: 48px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
background: var(--gradient-primary);
color: white;
box-shadow: 0 2px 8px rgba(0, 102, 204, 0.2);
}
/* Responsive Grid */
.responsive-grid {
display: grid;
gap: var(--spacing-lg);
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
/* Utility Classes */
.text-large {
font-size: var(--font-size-lg);
}
.text-small {
font-size: var(--font-size-sm);
}
.text-bold {
font-weight: var(--font-weight-bold);
}
.text-semibold {
font-weight: var(--font-weight-semibold);
}
.text-center {
text-align: center;
}
.mb-sm { margin-bottom: var(--spacing-sm); }
.mb-md { margin-bottom: var(--spacing-md); }
.mb-lg { margin-bottom: var(--spacing-lg); }
.mb-xl { margin-bottom: var(--spacing-xl); }
.mt-sm { margin-top: var(--spacing-sm); }
.mt-md { margin-top: var(--spacing-md); }
.mt-lg { margin-top: var(--spacing-lg); }
.mt-xl { margin-top: var(--spacing-xl); }

164
src/styles/tokens.css Normal file
View File

@@ -0,0 +1,164 @@
/* Design Tokens - Centralized CSS Variables */
:root {
/* Color Palette - TrainingPeaks/TrainerRoad Inspired */
--color-primary: #0066cc;
--color-primary-dark: #0052a3;
--color-primary-light: #3385d6;
--color-secondary: #00c853;
--color-danger: #e63946;
--color-warning: #ff9800;
--color-info: #00bcd4;
/* Gradients */
--gradient-primary: linear-gradient(135deg, #0066cc 0%, #0052a3 100%);
--gradient-secondary: linear-gradient(135deg, #00c853 0%, #00a844 100%);
--gradient-danger: linear-gradient(135deg, #e63946 0%, #d62828 100%);
--gradient-accent: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
/* Neutral Colors - Light Mode */
--color-background: #f5f7fa;
--color-surface: #ffffff;
--color-surface-hover: #f8f9fb;
--color-surface-secondary: #f9fafb;
--color-border: #dfe3e8;
--color-border-hover: #c4cdd5;
--color-divider: #ebeef2;
/* Text Colors - Light Mode */
--color-text-primary: #1a1f36;
--color-text-secondary: #697386;
--color-text-tertiary: #8898aa;
--color-text-muted: #a8b4c0;
--color-text-inverse: #ffffff;
--color-text-link: #0066cc;
/* Glassmorphism */
--glass-background: rgba(255, 255, 255, 0.7);
--glass-background-hover: rgba(255, 255, 255, 0.85);
--glass-border: rgba(255, 255, 255, 0.3);
--glass-blur: blur(20px);
/* Spacing Scale */
--spacing-xs: 0.5rem;
--spacing-sm: 0.75rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
--spacing-2xl: 2.5rem;
--spacing-3xl: 3rem;
--spacing-4xl: 4rem;
/* Border Radius */
--radius-sm: 0.5rem;
--radius-md: 0.75rem;
--radius-lg: 1rem;
--radius-xl: 1.5rem;
--radius-2xl: 2rem;
--radius-full: 9999px;
/* Shadows */
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
--shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
/* Custom Shadows for Glassmorphism */
--shadow-glass: 0 8px 25px -5px rgba(0, 0, 0, 0.1),
0 10px 10px -5px rgba(0, 0, 0, 0.04);
--shadow-glass-hover: 0 12px 40px -8px rgba(0, 0, 0, 0.15),
0 15px 15px -8px rgba(0, 0, 0, 0.06);
/* Typography */
--font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', Arial, sans-serif;
--font-size-xs: 0.75rem;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--font-size-2xl: 1.5rem;
--font-size-3xl: 1.875rem;
--font-size-4xl: 2.25rem;
--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-semibold: 600;
--font-weight-bold: 700;
--line-height-tight: 1.25;
--line-height-normal: 1.5;
--line-height-relaxed: 1.75;
/* Transitions */
--transition-fast: 0.15s cubic-bezier(0.4, 0, 0.2, 1);
--transition-base: 0.2s cubic-bezier(0.4, 0, 0.2, 1);
--transition-slow: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
--transition-slower: 0.6s cubic-bezier(0.4, 0, 0.2, 1);
/* Z-Index Scale */
--z-dropdown: 1000;
--z-sticky: 1020;
--z-fixed: 1030;
--z-modal-backdrop: 1040;
--z-modal: 1050;
--z-popover: 1060;
--z-tooltip: 1070;
/* Workout Type Colors */
--workout-ride: #3b82f6;
--workout-run: #10b981;
--workout-swim: #06b6d4;
--workout-strength: #8b5cf6;
--workout-yoga: #ec4899;
--workout-other: #6b7280;
/* Training Zone Colors */
--zone-1: #3b82f6;
--zone-2: #10b981;
--zone-3: #f59e0b;
--zone-4: #f97316;
--zone-5: #ef4444;
}
/* Dark Mode Overrides */
.dark {
/* Neutral Colors - Dark Mode */
--color-background: #111827;
--color-surface: #1f2937;
--color-surface-hover: #374151;
--color-border: #374151;
--color-border-hover: #4b5563;
/* Text Colors - Dark Mode */
--color-text-primary: #f9fafb;
--color-text-secondary: #d1d5db;
--color-text-tertiary: #9ca3af;
/* Glassmorphism - Dark Mode */
--glass-background: rgba(31, 41, 55, 0.7);
--glass-background-hover: rgba(31, 41, 55, 0.85);
--glass-border: rgba(255, 255, 255, 0.1);
/* Shadows - Dark Mode (lighter for visibility) */
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.5);
--shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.6);
--shadow-glass: 0 8px 25px -5px rgba(0, 0, 0, 0.4),
0 10px 10px -5px rgba(0, 0, 0, 0.2);
--shadow-glass-hover: 0 12px 40px -8px rgba(0, 0, 0, 0.5),
0 15px 15px -8px rgba(0, 0, 0, 0.3);
}
/* Reduced Motion Support */
@media (prefers-reduced-motion: reduce) {
:root {
--transition-fast: 0.01ms;
--transition-base: 0.01ms;
--transition-slow: 0.01ms;
--transition-slower: 0.01ms;
}
}