All checks were successful
Deploy / deploy (push) Successful in 3m8s
Big design pass across Home + tokens + components. — globals.css: new data-* palette (cool/warm/hot/good/info/rose/violet/mood) with theme-aware variants, .grain overlay utility, .num-display typography helper, .hit-zone 44px wrapper, .eyebrow label, .focus-card base, focus-visible outline-offset 3px, space/touch scale vars. — FocusCard.tsx: context engine — пять состояний (morning-outfit, tram-imminent, event-upcoming, countdown, bill-due, night, quiet). Auto-rotates by hour + live data. 96px display numbers, accent-mixed surfaces, grain overlay. — CountdownCard.tsx + /api/countdowns: rotating 8s list, persistent /data/tablet-countdowns.json, full CRUD. Default seeded with Токио. — HomeTab: replaced plain Weather hero with FocusCard, added Row 4 with CountdownCard. Pulls trams + countdowns for the Focus context. — Swipe between tabs: pointer-level detection on <main>, data-swipe-ignore bails out inside modals + note swipe-to-delete + voice overlay. — Touch-target sweep: TopBar HA dot → 44px hit-zone, sensor chip 44px min-height, forecast day buttons 92px min, DeviceCard toggle 60x36, CalendarTab prev/next/close/list all 44x44, NotesTab buttons 44x44, TimerHomeWidget + 44x44, WeatherDayModal chevrons 48x48, close 48. — Hardcoded hex → data-* tokens: TopBar sensors, TransportWidget routes (via color-mix), DeviceCard full rewrite (per-kind accent, glass removed in favor of color-mix surfaces + proper mock-state treatment), NotesTab palette refreshed to match dark theme. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
411 lines
14 KiB
CSS
411 lines
14 KiB
CSS
* {
|
||
box-sizing: border-box;
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
|
||
/* ——————————————————————————————
|
||
Tokens — dark (default)
|
||
—————————————————————————————— */
|
||
:root {
|
||
/* 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.6);
|
||
--text-tertiary: rgba(255, 255, 255, 0.38);
|
||
|
||
/* Accents — UI */
|
||
--accent: #818cf8;
|
||
--accent-strong: #6366f1;
|
||
--accent-secondary: #22d3ee;
|
||
--accent-glow: rgba(129, 140, 248, 0.22);
|
||
|
||
/* Data palette — semantic, theme-aware */
|
||
--data-cool: #38bdf8; /* небо, влажность, охлаждение */
|
||
--data-info: #60a5fa; /* ссылки, second-accent */
|
||
--data-good: #34d399; /* успех, здоровье, streak */
|
||
--data-warm: #fbbf24; /* свет, тепло, утро */
|
||
--data-hot: #fb923c; /* обострение, urgent-minor */
|
||
--data-danger: #f87171; /* критичное, истёк, ошибка */
|
||
--data-rose: #f472b6; /* Света, романтика */
|
||
--data-violet: #a78bfa; /* Cosmo, индиго-вариант */
|
||
--data-mood: #8b5cf6; /* секреты, события 2-го уровня */
|
||
|
||
/* Soft backgrounds for data (color-mix with surface-2) */
|
||
--data-cool-bg: color-mix(in srgb, var(--data-cool) 12%, var(--surface-2));
|
||
--data-good-bg: color-mix(in srgb, var(--data-good) 12%, var(--surface-2));
|
||
--data-warm-bg: color-mix(in srgb, var(--data-warm) 12%, var(--surface-2));
|
||
--data-hot-bg: color-mix(in srgb, var(--data-hot) 14%, var(--surface-2));
|
||
--data-danger-bg: color-mix(in srgb, var(--data-danger) 12%, var(--surface-2));
|
||
--data-rose-bg: color-mix(in srgb, var(--data-rose) 12%, var(--surface-2));
|
||
--data-violet-bg: color-mix(in srgb, var(--data-violet) 12%, var(--surface-2));
|
||
|
||
/* 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;
|
||
|
||
/* Layout rhythm */
|
||
--space-1: 4px;
|
||
--space-2: 8px;
|
||
--space-3: 12px;
|
||
--space-4: 16px;
|
||
--space-5: 22px;
|
||
--space-6: 28px;
|
||
|
||
/* Touch */
|
||
--touch-min: 44px;
|
||
--touch-comfy: 56px;
|
||
|
||
/* 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-strong: #4f46e5;
|
||
--accent-secondary: #0891b2;
|
||
--accent-glow: rgba(91, 99, 224, 0.14);
|
||
|
||
/* Data palette — slightly darker in light theme for contrast */
|
||
--data-cool: #0284c7;
|
||
--data-info: #2563eb;
|
||
--data-good: #059669;
|
||
--data-warm: #d97706;
|
||
--data-hot: #ea580c;
|
||
--data-danger: #dc2626;
|
||
--data-rose: #db2777;
|
||
--data-violet: #7c3aed;
|
||
--data-mood: #6d28d9;
|
||
|
||
/* Soft backgrounds — lighter mix for light theme */
|
||
--data-cool-bg: color-mix(in srgb, var(--data-cool) 9%, var(--surface-1));
|
||
--data-good-bg: color-mix(in srgb, var(--data-good) 9%, var(--surface-1));
|
||
--data-warm-bg: color-mix(in srgb, var(--data-warm) 9%, var(--surface-1));
|
||
--data-hot-bg: color-mix(in srgb, var(--data-hot) 10%, var(--surface-1));
|
||
--data-danger-bg: color-mix(in srgb, var(--data-danger) 9%, var(--surface-1));
|
||
--data-rose-bg: color-mix(in srgb, var(--data-rose) 9%, var(--surface-1));
|
||
--data-violet-bg: color-mix(in srgb, var(--data-violet) 9%, var(--surface-1));
|
||
|
||
--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);
|
||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', system-ui, sans-serif;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
transition: background 0.3s ease, color 0.3s ease;
|
||
}
|
||
|
||
#__next, main { height: 100%; }
|
||
|
||
/* Better tabular numbers across the app */
|
||
.num, .num-display {
|
||
font-variant-numeric: tabular-nums slashed-zero;
|
||
font-feature-settings: "tnum", "zero";
|
||
}
|
||
.num-display {
|
||
letter-spacing: -0.02em;
|
||
font-weight: 800;
|
||
line-height: 0.95;
|
||
}
|
||
|
||
/* ——————————————————————————————
|
||
Grain overlay
|
||
——— subtle SVG-noise; cheap, no image asset needed
|
||
—————————————————————————————— */
|
||
.grain {
|
||
position: relative;
|
||
}
|
||
.grain::after {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
pointer-events: none;
|
||
border-radius: inherit;
|
||
opacity: 0.035;
|
||
mix-blend-mode: overlay;
|
||
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
|
||
background-size: 120px 120px;
|
||
}
|
||
.light .grain::after {
|
||
opacity: 0.05;
|
||
mix-blend-mode: multiply;
|
||
filter: invert(1);
|
||
}
|
||
|
||
/* ——————————————————————————————
|
||
Aurora
|
||
—————————————————————————————— */
|
||
.bg-ambient {
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: 0;
|
||
overflow: hidden;
|
||
pointer-events: none;
|
||
}
|
||
.bg-ambient::before,
|
||
.bg-ambient::after {
|
||
content: '';
|
||
position: absolute;
|
||
border-radius: 50%;
|
||
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 {
|
||
0%, 100% { transform: translate(0, 0) scale(1); }
|
||
33% { transform: translate(30px, 40px) scale(1.05); }
|
||
66% { transform: translate(-20px, 20px) scale(0.95); }
|
||
}
|
||
@keyframes float2 {
|
||
0%, 100% { transform: translate(0, 0) scale(1); }
|
||
33% { transform: translate(-40px, -30px) scale(1.1); }
|
||
66% { transform: translate(20px, -10px) scale(0.9); }
|
||
}
|
||
|
||
/* ——————————————————————————————
|
||
Cards
|
||
—————————————————————————————— */
|
||
.card {
|
||
background: var(--surface-1);
|
||
border: 1px solid var(--border-subtle);
|
||
border-radius: var(--radius-lg);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
.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);
|
||
}
|
||
|
||
/* Focus-card styling — for the context-aware hero */
|
||
.focus-card {
|
||
position: relative;
|
||
background: var(--surface-1);
|
||
border: 1px solid var(--border-subtle);
|
||
border-radius: var(--radius-xl);
|
||
box-shadow: var(--shadow-lg);
|
||
overflow: hidden;
|
||
}
|
||
.focus-card-accent::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
background: radial-gradient(circle at top right, var(--accent-glow), transparent 60%);
|
||
pointer-events: none;
|
||
}
|
||
|
||
.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); }
|
||
|
||
/* Hairline divider helper */
|
||
.divider {
|
||
height: 1px;
|
||
width: 100%;
|
||
background: var(--hairline);
|
||
}
|
||
|
||
/* Chip / hit-zone — wraps small icons into 44px tap surface */
|
||
.hit-zone {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-width: var(--touch-min);
|
||
min-height: var(--touch-min);
|
||
border-radius: 12px;
|
||
}
|
||
|
||
/* Small uppercase label */
|
||
.eyebrow {
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.1em;
|
||
text-transform: uppercase;
|
||
color: var(--text-tertiary);
|
||
}
|
||
|
||
.gradient-text {
|
||
background: var(--gradient-primary);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
}
|
||
|
||
button {
|
||
cursor: pointer;
|
||
border: none;
|
||
outline: none;
|
||
background: none;
|
||
-webkit-tap-highlight-color: transparent;
|
||
touch-action: manipulation;
|
||
font-family: inherit;
|
||
color: inherit;
|
||
}
|
||
button:focus-visible {
|
||
outline: 2px solid var(--accent);
|
||
outline-offset: 3px;
|
||
border-radius: 14px;
|
||
}
|
||
|
||
::-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); }
|
||
|
||
/* ——————————————————————————————
|
||
Motion
|
||
—————————————————————————————— */
|
||
@keyframes pulse-glow {
|
||
0%, 100% { box-shadow: 0 0 20px var(--accent-glow); }
|
||
50% { box-shadow: 0 0 30px var(--accent-glow); }
|
||
}
|
||
@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; }
|
||
|
||
@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 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; }
|
||
50% { transform: translateY(10px) translateX(-1px); opacity: 0.7; }
|
||
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; }
|
||
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; }
|
||
}
|
||
|
||
/* 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); }
|