diff --git a/public/css/app.css b/public/css/app.css
index 7137326..78901de 100644
--- a/public/css/app.css
+++ b/public/css/app.css
@@ -309,4 +309,177 @@ label { font-size: 13px; color: var(--text-dim); margin-bottom: 4px; display: bl
.leaflet-container {
position: relative !important;
z-index: 1;
+}
+
+/* ===== Onboarding (welcome flow) — dark Telegram-style ===== */
+.onboarding-overlay {
+ position: absolute;
+ inset: 0;
+ background: #1C1C1E;
+ color: #fff;
+ z-index: 300;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ animation: ob-fade-in 260ms ease-out both;
+ border-radius: inherit;
+ background: radial-gradient(1200px 600px at 20% 0%, #2A2A2E 0%, #1C1C1E 60%, #141416 100%);
+}
+.onboarding-overlay.leaving { animation: ob-fade-out 240ms ease-in both; }
+
+@keyframes ob-fade-in { from { opacity: 0; } to { opacity: 1; } }
+@keyframes ob-fade-out { from { opacity: 1; } to { opacity: 0; } }
+
+.onboarding-stage {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ padding: 8px 28px 24px;
+ position: relative;
+}
+
+.onboarding-top {
+ height: 44px; /* место под status-bar / notch */
+ flex-shrink: 0;
+}
+
+.onboarding-slides {
+ flex: 1;
+ position: relative;
+ min-height: 0;
+}
+
+.onboarding-slide {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ padding: 8px 0 0;
+ opacity: 0;
+ transform: translateX(40px);
+ transition: opacity 320ms ease, transform 360ms cubic-bezier(.2,.7,.2,1);
+ pointer-events: none;
+ will-change: opacity, transform;
+}
+.onboarding-slide.from-left { transform: translateX(-40px); }
+.onboarding-slide.from-right { transform: translateX(40px); }
+.onboarding-slide.is-active {
+ opacity: 1;
+ transform: translateX(0);
+ pointer-events: auto;
+}
+.onboarding-slide.to-left { opacity: 0; transform: translateX(-40px); }
+.onboarding-slide.to-right { opacity: 0; transform: translateX(40px); }
+
+.onboarding-icon {
+ width: 220px;
+ height: 220px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-bottom: 28px;
+ filter: drop-shadow(0 16px 36px rgba(0,0,0,0.35));
+ animation: ob-float 6s ease-in-out infinite;
+}
+.onboarding-icon svg { width: 100%; height: 100%; display: block; }
+@keyframes ob-float {
+ 0%, 100% { transform: translateY(0); }
+ 50% { transform: translateY(-8px); }
+}
+
+.onboarding-title {
+ font-size: 26px;
+ font-weight: 700;
+ letter-spacing: -0.4px;
+ margin-bottom: 12px;
+ max-width: 320px;
+ color: #fff;
+ line-height: 1.2;
+}
+.onboarding-body {
+ font-size: 15px;
+ line-height: 1.45;
+ color: rgba(255,255,255,0.75);
+ max-width: 300px;
+}
+
+.onboarding-bottom {
+ display: flex;
+ flex-direction: column;
+ gap: 0;
+ flex-shrink: 0;
+ padding-bottom: env(safe-area-inset-bottom);
+}
+
+.onboarding-dots {
+ display: flex;
+ justify-content: center;
+ gap: 8px;
+ margin-top: 18px;
+ margin-bottom: 18px;
+}
+.onboarding-dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: rgba(255,255,255,0.25);
+ border: 0;
+ padding: 0;
+ cursor: pointer;
+ transition: width 240ms ease, background 240ms ease;
+}
+.onboarding-dot.is-active {
+ width: 22px;
+ border-radius: 4px;
+ background: var(--primary);
+}
+
+.onboarding-actions {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.onboarding-btn {
+ appearance: none;
+ border: 0;
+ cursor: pointer;
+ font-family: inherit;
+ font-size: 16px;
+ font-weight: 600;
+ border-radius: 14px;
+ padding: 16px 20px;
+ transition: transform 120ms ease, background 200ms ease, opacity 200ms ease;
+}
+.onboarding-btn:active { transform: scale(0.98); }
+
+.onboarding-btn-primary {
+ background: var(--primary);
+ color: #fff;
+ box-shadow: 0 6px 16px rgba(255,107,53,0.35);
+}
+.onboarding-btn-primary:hover { background: var(--primary-dark); }
+
+.onboarding-btn-skip {
+ background: transparent;
+ color: rgba(255,255,255,0.65);
+}
+.onboarding-btn-skip:hover { color: #fff; }
+
+.onboarding-caption {
+ margin-top: 14px;
+ color: rgba(255,255,255,0.5);
+ font-size: 12px;
+ text-align: center;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .onboarding-overlay,
+ .onboarding-slide,
+ .onboarding-icon,
+ .onboarding-dot { animation: none !important; transition: none !important; }
+ .onboarding-slide { transform: none; opacity: 1; pointer-events: auto; }
}
\ No newline at end of file
diff --git a/public/index.html b/public/index.html
index 41115a6..b580725 100644
--- a/public/index.html
+++ b/public/index.html
@@ -42,6 +42,7 @@
+