diff --git a/app/globals.css b/app/globals.css index f3ab2d9..5c4266c 100644 --- a/app/globals.css +++ b/app/globals.css @@ -4,34 +4,101 @@ padding: 0; } +/* —————————————————————————————— + Tokens — dark (default) + —————————————————————————————— */ :root { - --bg: #0c0c18; - --bg-secondary: #12121f; - --sidebar-bg: rgba(12, 12, 24, 0.8); - --card-bg: rgba(255, 255, 255, 0.04); - --card-bg-hover: rgba(255, 255, 255, 0.07); - --card-border: rgba(255, 255, 255, 0.07); - --card-border-hover: rgba(255, 255, 255, 0.12); + /* Surfaces */ + --bg: #0b0b14; + --bg-secondary: #101020; + --surface-1: #15152a; + --surface-2: #1c1c36; + --surface-3: #242444; + --surface-hover: #1e1e3c; + + /* Borders */ + --border-subtle: rgba(255, 255, 255, 0.06); + --border-strong: rgba(255, 255, 255, 0.12); + --hairline: rgba(255, 255, 255, 0.08); + + /* Text */ --text-primary: rgba(255, 255, 255, 0.95); - --text-secondary: rgba(255, 255, 255, 0.45); - --text-tertiary: rgba(255, 255, 255, 0.25); + --text-secondary: rgba(255, 255, 255, 0.6); + --text-tertiary: rgba(255, 255, 255, 0.38); + + /* Accents */ --accent: #818cf8; --accent-secondary: #22d3ee; - --accent-glow: rgba(129, 140, 248, 0.15); - --glass: rgba(255, 255, 255, 0.03); - --glass-border: rgba(255, 255, 255, 0.06); + --accent-glow: rgba(129, 140, 248, 0.22); + + /* Brand gradients */ --gradient-primary: linear-gradient(135deg, #6366f1, #8b5cf6); --gradient-warm: linear-gradient(135deg, #f59e0b, #ef4444); --gradient-cool: linear-gradient(135deg, #06b6d4, #3b82f6); --gradient-green: linear-gradient(135deg, #10b981, #34d399); + + /* Shadows */ + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35); + --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.45); + --shadow-xl: 0 24px 60px rgba(0, 0, 0, 0.5); + + /* State */ --on-color: #818cf8; --off-color: rgba(255, 255, 255, 0.15); + + /* Radius */ + --radius-xs: 8px; --radius-sm: 12px; --radius-md: 16px; --radius-lg: 22px; --radius-xl: 28px; + + /* Legacy aliases */ + --sidebar-bg: var(--bg); + --card-bg: var(--surface-1); + --card-bg-hover: var(--surface-2); + --card-border: var(--border-subtle); + --card-border-hover: var(--border-strong); + --glass: var(--surface-1); + --glass-border: var(--border-subtle); } +/* —————————————————————————————— + Tokens — light + —————————————————————————————— */ +.light { + --bg: #f6f7fb; + --bg-secondary: #eef0f5; + --surface-1: #ffffff; + --surface-2: #f3f4f8; + --surface-3: #eaebf0; + --surface-hover: #f8f9fc; + + --border-subtle: rgba(15, 20, 40, 0.06); + --border-strong: rgba(15, 20, 40, 0.12); + --hairline: rgba(15, 20, 40, 0.08); + + --text-primary: rgba(15, 20, 40, 0.94); + --text-secondary: rgba(15, 20, 40, 0.62); + --text-tertiary: rgba(15, 20, 40, 0.38); + + --accent: #5b63e0; + --accent-secondary: #0891b2; + --accent-glow: rgba(91, 99, 224, 0.14); + + --shadow-sm: 0 1px 2px rgba(15, 20, 40, 0.05); + --shadow-md: 0 2px 6px rgba(15, 20, 40, 0.06), 0 12px 28px -8px rgba(15, 20, 40, 0.1); + --shadow-lg: 0 4px 10px rgba(15, 20, 40, 0.06), 0 24px 60px -12px rgba(15, 20, 40, 0.14); + --shadow-xl: 0 8px 16px rgba(15, 20, 40, 0.06), 0 40px 100px -24px rgba(15, 20, 40, 0.2); + + --on-color: #5b63e0; + --off-color: rgba(15, 20, 40, 0.12); +} + +/* —————————————————————————————— + Base + —————————————————————————————— */ html, body { background: var(--bg); color: var(--text-primary); @@ -40,13 +107,14 @@ html, body { overflow: hidden; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + transition: background 0.3s ease, color 0.3s ease; } -#__next, main { - height: 100%; -} +#__next, main { height: 100%; } -/* Ambient background orbs */ +/* —————————————————————————————— + Aurora + —————————————————————————————— */ .bg-ambient { position: fixed; inset: 0; @@ -54,27 +122,27 @@ html, body { overflow: hidden; pointer-events: none; } -.bg-ambient::before { - content: ''; - position: absolute; - width: 600px; - height: 600px; - border-radius: 50%; - background: radial-gradient(circle, rgba(99, 102, 241, 0.08) 0%, transparent 70%); - top: -200px; - right: -100px; - animation: float1 20s ease-in-out infinite; -} +.bg-ambient::before, .bg-ambient::after { content: ''; position: absolute; - width: 500px; - height: 500px; border-radius: 50%; - background: radial-gradient(circle, rgba(139, 92, 246, 0.06) 0%, transparent 70%); - bottom: -150px; - left: -50px; - animation: float2 25s ease-in-out infinite; + filter: blur(80px); +} +.bg-ambient::before { + width: 560px; height: 560px; + background: radial-gradient(circle, var(--accent-glow) 0%, transparent 70%); + top: -180px; right: -80px; + animation: float1 22s ease-in-out infinite; +} +.bg-ambient::after { + width: 480px; height: 480px; + background: radial-gradient(circle, rgba(139, 92, 246, 0.14) 0%, transparent 70%); + bottom: -140px; left: -60px; + animation: float2 27s ease-in-out infinite; +} +.light .bg-ambient::after { + background: radial-gradient(circle, rgba(99, 102, 241, 0.1) 0%, transparent 70%); } @keyframes float1 { @@ -88,21 +156,36 @@ html, body { 66% { transform: translate(20px, -10px) scale(0.9); } } -/* Glass card base */ -.glass-card { - background: var(--card-bg); - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - border: 1px solid var(--card-border); +/* —————————————————————————————— + Cards + —————————————————————————————— */ +.card { + background: var(--surface-1); + border: 1px solid var(--border-subtle); border-radius: var(--radius-lg); - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: var(--shadow-sm); } -.glass-card:hover { - background: var(--card-bg-hover); - border-color: var(--card-border-hover); +.card-raised { + background: var(--surface-1); + border: 1px solid var(--border-subtle); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-md); +} +.card-hero { + background: var(--surface-1); + border: 1px solid var(--border-subtle); + border-radius: var(--radius-xl); + box-shadow: var(--shadow-lg); } -/* Gradient text */ +.glass-card { + background: var(--surface-1); + border: 1px solid var(--border-subtle); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-sm); +} +.glass-card:hover { background: var(--surface-hover); } + .gradient-text { background: var(--gradient-primary); -webkit-background-clip: text; @@ -118,125 +201,48 @@ button { -webkit-tap-highlight-color: transparent; touch-action: manipulation; font-family: inherit; + color: inherit; } - button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } -/* Smooth scrollbar */ -::-webkit-scrollbar { - width: 4px; - height: 4px; -} -::-webkit-scrollbar-track { - background: transparent; -} -::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.08); - border-radius: 2px; -} -::-webkit-scrollbar-thumb:hover { - background: rgba(255, 255, 255, 0.15); -} +::-webkit-scrollbar { width: 6px; height: 6px; } +::-webkit-scrollbar-track { background: transparent; } +::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 3px; } +::-webkit-scrollbar-thumb:hover { background: var(--text-tertiary); } -/* Pulse animation for active devices */ +/* —————————————————————————————— + Motion + —————————————————————————————— */ @keyframes pulse-glow { - 0%, 100% { box-shadow: 0 0 20px rgba(129, 140, 248, 0.15); } - 50% { box-shadow: 0 0 30px rgba(129, 140, 248, 0.25); } + 0%, 100% { box-shadow: 0 0 20px var(--accent-glow); } + 50% { box-shadow: 0 0 30px var(--accent-glow); } } - -/* Slide in animation */ @keyframes slideUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } +.animate-slide-up { animation: slideUp 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; } -.animate-slide-up { - animation: slideUp 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; -} - -/* ————— Light theme ————— */ -.light { - --bg: #f5f5fa; - --bg-secondary: #eeeef4; - --sidebar-bg: rgba(255, 255, 255, 0.8); - --card-bg: rgba(255, 255, 255, 0.7); - --card-bg-hover: rgba(255, 255, 255, 0.85); - --card-border: rgba(0, 0, 0, 0.06); - --card-border-hover: rgba(0, 0, 0, 0.1); - --text-primary: rgba(0, 0, 0, 0.88); - --text-secondary: rgba(0, 0, 0, 0.45); - --text-tertiary: rgba(0, 0, 0, 0.2); - --accent: #6366f1; - --accent-secondary: #0891b2; - --accent-glow: rgba(99, 102, 241, 0.12); - --glass: rgba(255, 255, 255, 0.5); - --glass-border: rgba(0, 0, 0, 0.06); - --on-color: #6366f1; - --off-color: rgba(0, 0, 0, 0.12); -} - -.light .bg-ambient::before { - background: radial-gradient(circle, rgba(99, 102, 241, 0.06) 0%, transparent 70%); -} -.light .bg-ambient::after { - background: radial-gradient(circle, rgba(139, 92, 246, 0.04) 0%, transparent 70%); -} - -.light ::-webkit-scrollbar-thumb { - background: rgba(0, 0, 0, 0.1); -} -.light ::-webkit-scrollbar-thumb:hover { - background: rgba(0, 0, 0, 0.2); -} - -/* ————— Device animations ————— */ -@keyframes fan-spin { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } -} - +@keyframes fan-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } @keyframes light-pulse { 0%, 100% { filter: drop-shadow(0 0 4px rgba(251, 191, 36, 0.3)); } 50% { filter: drop-shadow(0 0 12px rgba(251, 191, 36, 0.6)); } } +@keyframes device-breathe { 0%, 100% { opacity: 0.7; } 50% { opacity: 1; } } +.fan-spinning { animation: fan-spin 2s linear infinite; } +.light-on-pulse { animation: light-pulse 3s ease-in-out infinite; } +.device-active-breathe { animation: device-breathe 3s ease-in-out infinite; } -@keyframes device-breathe { - 0%, 100% { opacity: 0.7; } - 50% { opacity: 1; } -} - -.fan-spinning { - animation: fan-spin 2s linear infinite; -} - -.light-on-pulse { - animation: light-pulse 3s ease-in-out infinite; -} - -.device-active-breathe { - animation: device-breathe 3s ease-in-out infinite; -} - -/* ————— Weather animations ————— */ -@keyframes spin-slow { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } -} - -@keyframes cloud-float { - 0%, 100% { transform: translateX(0); } - 50% { transform: translateX(4px); } -} - +@keyframes spin-slow { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } +@keyframes cloud-float { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(4px); } } @keyframes rain-fall { 0% { transform: translateY(0); opacity: 0.7; } 80% { opacity: 0.7; } 100% { transform: translateY(16px); opacity: 0; } } - @keyframes snow-fall { 0% { transform: translateY(0) translateX(0); opacity: 0.9; } 25% { transform: translateY(5px) translateX(2px); opacity: 0.8; } @@ -244,7 +250,6 @@ button:focus-visible { 75% { transform: translateY(15px) translateX(3px); opacity: 0.4; } 100% { transform: translateY(22px) translateX(0); opacity: 0; } } - @keyframes thunder-flash { 0%, 100% { opacity: 0; } 5%, 7% { opacity: 1; } @@ -252,52 +257,21 @@ button:focus-visible { 50%, 52% { opacity: 0.8; } 51% { opacity: 0.2; } } - @keyframes fog-drift { 0%, 100% { transform: translateX(0); opacity: 0.4; } 50% { transform: translateX(8px); opacity: 0.6; } } -/* ————— Dynamic weather backgrounds ————— */ -.weather-bg-clear { - --orb1-color: rgba(251, 191, 36, 0.08); - --orb2-color: rgba(245, 158, 11, 0.05); -} -.weather-bg-cloudy { - --orb1-color: rgba(148, 163, 184, 0.08); - --orb2-color: rgba(100, 116, 139, 0.06); -} -.weather-bg-rain { - --orb1-color: rgba(59, 130, 246, 0.08); - --orb2-color: rgba(30, 64, 175, 0.06); -} -.weather-bg-snow { - --orb1-color: rgba(186, 230, 253, 0.1); - --orb2-color: rgba(147, 197, 253, 0.07); -} -.weather-bg-thunder { - --orb1-color: rgba(139, 92, 246, 0.1); - --orb2-color: rgba(88, 28, 135, 0.06); -} -.weather-bg-night { - --orb1-color: rgba(67, 56, 202, 0.06); - --orb2-color: rgba(49, 46, 129, 0.05); -} - -.weather-bg-clear .bg-ambient::before, -.weather-bg-cloudy .bg-ambient::before, -.weather-bg-rain .bg-ambient::before, -.weather-bg-snow .bg-ambient::before, -.weather-bg-thunder .bg-ambient::before, -.weather-bg-night .bg-ambient::before { - background: radial-gradient(circle, var(--orb1-color) 0%, transparent 70%); -} - -.weather-bg-clear .bg-ambient::after, -.weather-bg-cloudy .bg-ambient::after, -.weather-bg-rain .bg-ambient::after, -.weather-bg-snow .bg-ambient::after, -.weather-bg-thunder .bg-ambient::after, -.weather-bg-night .bg-ambient::after { - background: radial-gradient(circle, var(--orb2-color) 0%, transparent 70%); -} +/* Weather ambient tints via accent-glow */ +.weather-bg-clear { --accent-glow: rgba(251, 191, 36, 0.18); } +.weather-bg-cloudy { --accent-glow: rgba(148, 163, 184, 0.18); } +.weather-bg-rain { --accent-glow: rgba(59, 130, 246, 0.18); } +.weather-bg-snow { --accent-glow: rgba(186, 230, 253, 0.22); } +.weather-bg-thunder { --accent-glow: rgba(139, 92, 246, 0.22); } +.weather-bg-night { --accent-glow: rgba(67, 56, 202, 0.16); } +.light.weather-bg-clear { --accent-glow: rgba(234, 169, 27, 0.16); } +.light.weather-bg-cloudy { --accent-glow: rgba(100, 116, 139, 0.14); } +.light.weather-bg-rain { --accent-glow: rgba(37, 99, 235, 0.14); } +.light.weather-bg-snow { --accent-glow: rgba(125, 211, 252, 0.22); } +.light.weather-bg-thunder { --accent-glow: rgba(109, 40, 217, 0.14); } +.light.weather-bg-night { --accent-glow: rgba(55, 48, 163, 0.14); } diff --git a/app/page.tsx b/app/page.tsx index b5bf8b7..d8b4f4e 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -419,94 +419,199 @@ function HomeTab({ weather, sensors }: { weather: WeatherData | null; sensors: S return ( -