diff --git a/app/globals.css b/app/globals.css
index 8d3c21a..a3df93a 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -219,3 +219,83 @@ button:focus-visible {
.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 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) rotate(0deg); opacity: 0.8; }
+ 50% { transform: translateY(10px) translateX(3px) rotate(180deg); opacity: 0.6; }
+ 100% { transform: translateY(20px) rotate(360deg); opacity: 0; }
+}
+
+@keyframes thunder-flash {
+ 0%, 100% { opacity: 0; }
+ 5%, 7% { opacity: 1; }
+ 6% { opacity: 0.3; }
+ 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%);
+}
diff --git a/app/page.tsx b/app/page.tsx
index 7c32234..5ab0ecb 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -8,6 +8,7 @@ import TopBar from '@/components/TopBar'
import RoomTabs from '@/components/RoomTabs'
import DeviceCard from '@/components/DeviceCard'
import CalendarTab from '@/components/CalendarTab'
+import WeatherAnimation from '@/components/WeatherAnimation'
type Tab = 'home' | 'devices' | 'calendar' | 'settings'
@@ -91,6 +92,18 @@ function formatEventTime(iso: string): string {
return new Date(iso).toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' })
}
+function getWeatherBgClass(desc: string | null): string {
+ if (!desc) return ''
+ const d = desc.toLowerCase()
+ const hour = new Date().getHours()
+ if (hour >= 22 || hour < 5) return 'weather-bg-night'
+ if (d.includes('гроз')) return 'weather-bg-thunder'
+ if (d.includes('снег')) return 'weather-bg-snow'
+ if (d.includes('дождь') || d.includes('ливен') || d.includes('морос')) return 'weather-bg-rain'
+ if (d.includes('пасмурн') || d.includes('облач') || d.includes('туман')) return 'weather-bg-cloudy'
+ return 'weather-bg-clear'
+}
+
function getGreeting(): string {
const h = new Date().getHours()
if (h >= 5 && h < 12) return 'Доброе утро'
@@ -161,7 +174,7 @@ function Screensaver({ weather, onDismiss }: { weather: WeatherData | null; onDi
display: 'flex', alignItems: 'center', gap: 12,
marginTop: 16, color: 'rgba(255,255,255,0.3)',
}}>
- {getWeatherIcon(weather.desc)}
+