@@ -7,22 +7,172 @@ import { useNavigate } from 'react-router-dom';
77export default function Landing ( ) {
88 const navigate = useNavigate ( ) ;
99
10+ // Landing page is always dark — temporarily disable light theme if active
11+ useEffect ( ( ) => {
12+ const html = document . documentElement ;
13+ const wasLight = html . classList . contains ( 'light' ) ;
14+ if ( wasLight ) html . classList . remove ( 'light' ) ;
15+ return ( ) => { if ( wasLight ) html . classList . add ( 'light' ) ; } ;
16+ } , [ ] ) ;
17+
1018 return (
1119 < div className = "bg-slate-950 text-white overflow-x-hidden" >
1220 < Nav onLogin = { ( ) => navigate ( '/login' ) } />
1321 < Hero onGetStarted = { ( ) => navigate ( '/login' ) } />
22+ < WaveDivider flip />
1423 < Problem />
24+ < WaveDivider />
1525 < Solution />
26+ < WaveDivider flip />
1627 < HowItWorks />
28+ < WaveDivider />
1729 < Features />
30+ < WaveDivider flip />
1831 < TechSpecs />
32+ < WaveDivider />
1933 < Pricing onGetStarted = { ( ) => navigate ( '/login' ) } />
34+ < WaveDivider flip />
2035 < Hardware />
2136 < Footer />
2237 </ div >
2338 ) ;
2439}
2540
41+ // ─── SVG ICONS ─────────────────────────────────────────────────────────────
42+ const icons = {
43+ droplet : (
44+ < svg width = "32" height = "32" viewBox = "0 0 24 24" fill = "none" stroke = "#38BDF8" strokeWidth = "1.5" strokeLinecap = "round" strokeLinejoin = "round" >
45+ < path d = "M12 2.69l5.66 5.66a8 8 0 1 1-11.31 0z" />
46+ </ svg >
47+ ) ,
48+ zap : (
49+ < svg width = "32" height = "32" viewBox = "0 0 24 24" fill = "none" stroke = "#38BDF8" strokeWidth = "1.5" strokeLinecap = "round" strokeLinejoin = "round" >
50+ < polygon points = "13 2 3 14 12 14 11 22 21 10 12 10 13 2" />
51+ </ svg >
52+ ) ,
53+ home : (
54+ < svg width = "32" height = "32" viewBox = "0 0 24 24" fill = "none" stroke = "#38BDF8" strokeWidth = "1.5" strokeLinecap = "round" strokeLinejoin = "round" >
55+ < path d = "M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
56+ < polyline points = "9 22 9 12 15 12 15 22" />
57+ </ svg >
58+ ) ,
59+ radio : (
60+ < svg width = "28" height = "28" viewBox = "0 0 24 24" fill = "none" stroke = "#38BDF8" strokeWidth = "1.5" strokeLinecap = "round" strokeLinejoin = "round" >
61+ < path d = "M16.72 11.06A10.94 10.94 0 0 1 19 17.94" />
62+ < path d = "M7.28 11.06A10.94 10.94 0 0 0 5 17.94" />
63+ < path d = "M14.34 13.5A6.97 6.97 0 0 1 16 17.94" />
64+ < path d = "M9.66 13.5A6.97 6.97 0 0 0 8 17.94" />
65+ < circle cx = "12" cy = "18" r = "1" />
66+ < path d = "M12 2v10" />
67+ </ svg >
68+ ) ,
69+ battery : (
70+ < svg width = "28" height = "28" viewBox = "0 0 24 24" fill = "none" stroke = "#38BDF8" strokeWidth = "1.5" strokeLinecap = "round" strokeLinejoin = "round" >
71+ < rect x = "1" y = "6" width = "18" height = "12" rx = "2" ry = "2" />
72+ < line x1 = "23" y1 = "10" x2 = "23" y2 = "14" />
73+ < rect x = "4" y = "9" width = "6" height = "6" rx = "1" fill = "#38BDF8" opacity = "0.3" />
74+ </ svg >
75+ ) ,
76+ phone : (
77+ < svg width = "28" height = "28" viewBox = "0 0 24 24" fill = "none" stroke = "#38BDF8" strokeWidth = "1.5" strokeLinecap = "round" strokeLinejoin = "round" >
78+ < rect x = "5" y = "2" width = "14" height = "20" rx = "2" ry = "2" />
79+ < line x1 = "12" y1 = "18" x2 = "12.01" y2 = "18" />
80+ </ svg >
81+ ) ,
82+ bell : (
83+ < svg width = "28" height = "28" viewBox = "0 0 24 24" fill = "none" stroke = "#38BDF8" strokeWidth = "1.5" strokeLinecap = "round" strokeLinejoin = "round" >
84+ < path d = "M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" />
85+ < path d = "M13.73 21a2 2 0 0 1-3.46 0" />
86+ </ svg >
87+ ) ,
88+ chart : (
89+ < svg width = "28" height = "28" viewBox = "0 0 24 24" fill = "none" stroke = "#38BDF8" strokeWidth = "1.5" strokeLinecap = "round" strokeLinejoin = "round" >
90+ < line x1 = "18" y1 = "20" x2 = "18" y2 = "10" />
91+ < line x1 = "12" y1 = "20" x2 = "12" y2 = "4" />
92+ < line x1 = "6" y1 = "20" x2 = "6" y2 = "14" />
93+ </ svg >
94+ ) ,
95+ homeAssistant : (
96+ < svg width = "28" height = "28" viewBox = "0 0 24 24" fill = "none" stroke = "#38BDF8" strokeWidth = "1.5" strokeLinecap = "round" strokeLinejoin = "round" >
97+ < path d = "M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
98+ < circle cx = "12" cy = "14" r = "3" />
99+ < path d = "M12 11v-1" />
100+ < path d = "M14.6 12.5l.8-.5" />
101+ < path d = "M14.6 15.5l.8.5" />
102+ < path d = "M12 17v1" />
103+ < path d = "M9.4 15.5l-.8.5" />
104+ < path d = "M9.4 12.5l-.8-.5" />
105+ </ svg >
106+ ) ,
107+ shield : (
108+ < svg width = "28" height = "28" viewBox = "0 0 24 24" fill = "none" stroke = "#38BDF8" strokeWidth = "1.5" strokeLinecap = "round" strokeLinejoin = "round" >
109+ < path d = "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
110+ < path d = "M9 12l2 2 4-4" />
111+ </ svg >
112+ ) ,
113+ layers : (
114+ < svg width = "28" height = "28" viewBox = "0 0 24 24" fill = "none" stroke = "#38BDF8" strokeWidth = "1.5" strokeLinecap = "round" strokeLinejoin = "round" >
115+ < polygon points = "12 2 2 7 12 12 22 7 12 2" />
116+ < polyline points = "2 17 12 22 22 17" />
117+ < polyline points = "2 12 12 17 22 12" />
118+ </ svg >
119+ ) ,
120+ refresh : (
121+ < svg width = "28" height = "28" viewBox = "0 0 24 24" fill = "none" stroke = "#38BDF8" strokeWidth = "1.5" strokeLinecap = "round" strokeLinejoin = "round" >
122+ < path d = "M21 2v6h-6" />
123+ < path d = "M3 12a9 9 0 0 1 15-6.7L21 8" />
124+ < path d = "M3 22v-6h6" />
125+ < path d = "M21 12a9 9 0 0 1-15 6.7L3 16" />
126+ </ svg >
127+ ) ,
128+ } ;
129+
130+ // ─── WAVE DIVIDER ──────────────────────────────────────────────────────────
131+ function WaveDivider ( { flip = false } ) {
132+ return (
133+ < div className = { `relative w-full h-16 sm:h-24 overflow-hidden ${ flip ? 'rotate-180' : '' } ` } >
134+ < svg className = "absolute bottom-0 w-full h-full" viewBox = "0 0 1440 100" preserveAspectRatio = "none" fill = "none" >
135+ < path d = "M0,40 C360,100 1080,0 1440,60 L1440,100 L0,100Z" fill = "#0EA5E9" opacity = "0.05" />
136+ < path d = "M0,60 C480,10 960,90 1440,40 L1440,100 L0,100Z" fill = "#0EA5E9" opacity = "0.03" />
137+ </ svg >
138+ </ div >
139+ ) ;
140+ }
141+
142+ // ─── FLOATING BUBBLES ──────────────────────────────────────────────────────
143+ function Bubbles ( ) {
144+ return (
145+ < div className = "absolute inset-0 overflow-hidden pointer-events-none" aria-hidden = "true" >
146+ { [ ...Array ( 12 ) ] . map ( ( _ , i ) => (
147+ < div
148+ key = { i }
149+ className = "landing-bubble absolute rounded-full"
150+ style = { {
151+ width : `${ 6 + ( i % 5 ) * 4 } px` ,
152+ height : `${ 6 + ( i % 5 ) * 4 } px` ,
153+ left : `${ 5 + ( i * 8 ) % 90 } %` ,
154+ bottom : `-${ 10 + ( i * 7 ) % 20 } %` ,
155+ animationDelay : `${ i * 1.2 } s` ,
156+ animationDuration : `${ 8 + ( i % 4 ) * 3 } s` ,
157+ } }
158+ />
159+ ) ) }
160+ </ div >
161+ ) ;
162+ }
163+
164+ // ─── WATER SURFACE ─────────────────────────────────────────────────────────
165+ function WaterSurface ( { className = '' } ) {
166+ return (
167+ < div className = { `absolute left-0 right-0 overflow-hidden pointer-events-none ${ className } ` } aria-hidden = "true" >
168+ < svg className = "w-full landing-water-surface" viewBox = "0 0 1440 60" preserveAspectRatio = "none" >
169+ < path className = "landing-wave-1" d = "M0,30 C240,10 480,50 720,30 C960,10 1200,50 1440,30 L1440,60 L0,60Z" fill = "#0EA5E9" opacity = "0.06" />
170+ < path className = "landing-wave-2" d = "M0,35 C300,55 600,15 900,35 C1200,55 1350,20 1440,35 L1440,60 L0,60Z" fill = "#38BDF8" opacity = "0.04" />
171+ </ svg >
172+ </ div >
173+ ) ;
174+ }
175+
26176// ─── ANIMATIONS ─────────────────────────────────────────────────────────────
27177function FadeIn ( { children, className = '' , delay = 0 } ) {
28178 const ref = useRef ( null ) ;
@@ -80,6 +230,12 @@ function Hero({ onGetStarted }) {
80230 < div className = "absolute inset-0 bg-gradient-to-b from-sky-500/10 via-transparent to-transparent" />
81231 < div className = "absolute top-1/3 left-1/2 -translate-x-1/2 w-[600px] h-[600px] bg-sky-500/5 rounded-full blur-3xl" />
82232
233+ { /* Floating bubbles */ }
234+ < Bubbles />
235+
236+ { /* Water surface at bottom */ }
237+ < WaterSurface className = "bottom-0 h-20" />
238+
83239 < FadeIn >
84240 < div className = "inline-flex items-center gap-2 bg-sky-500/10 border border-sky-500/20 rounded-full px-4 py-1.5 mb-8" >
85241 < div className = "w-2 h-2 rounded-full bg-emerald-400 animate-pulse" />
@@ -116,7 +272,6 @@ function Hero({ onGetStarted }) {
116272 </ FadeIn >
117273
118274 < FadeIn delay = { 500 } className = "mt-16 w-full max-w-4xl" >
119- { /* PLACEHOLDER: Dashboard screenshot mockup on phone/laptop */ }
120275 < div className = "relative mx-auto" >
121276 < div className = "bg-slate-900 rounded-2xl border border-slate-800 p-4 shadow-2xl shadow-sky-500/10" >
122277 < div className = "bg-slate-800 rounded-xl aspect-[16/9] flex items-center justify-center" >
@@ -138,13 +293,25 @@ function Hero({ onGetStarted }) {
138293// ─── PROBLEM ────────────────────────────────────────────────────────────────
139294function Problem ( ) {
140295 const stats = [
141- { value : '135L' , label : 'water wasted daily per household due to overflow' , icon : '💧' } ,
142- { value : '23%' , label : 'of water pumps fail from running dry' , icon : '⚡' } ,
143- { value : '2x' , label : 'daily roof climbs to check water level' , icon : '🏠' } ,
296+ {
297+ value : '135L' ,
298+ label : 'water wasted daily per household due to overflow' ,
299+ icon : icons . droplet ,
300+ } ,
301+ {
302+ value : '23%' ,
303+ label : 'of water pumps fail from running dry' ,
304+ icon : icons . zap ,
305+ } ,
306+ {
307+ value : '2x' ,
308+ label : 'daily roof climbs to check water level' ,
309+ icon : icons . home ,
310+ } ,
144311 ] ;
145312
146313 return (
147- < section className = "py-24 px-6" >
314+ < section className = "py-24 px-6 relative " >
148315 < div className = "max-w-6xl mx-auto" >
149316 < FadeIn >
150317 < p className = "text-sky-400 font-medium text-sm tracking-wider uppercase mb-4 text-center" > The Problem</ p >
@@ -161,7 +328,9 @@ function Problem() {
161328 { stats . map ( ( stat , i ) => (
162329 < FadeIn key = { i } delay = { i * 150 } >
163330 < div className = "bg-slate-900/50 border border-slate-800 rounded-2xl p-8 text-center hover:border-sky-500/30 transition-all" >
164- < div className = "text-4xl mb-4" > { stat . icon } </ div >
331+ < div className = "w-14 h-14 rounded-xl bg-sky-500/10 flex items-center justify-center mx-auto mb-4" >
332+ { stat . icon }
333+ </ div >
165334 < div className = "text-4xl font-bold text-white mb-2" > { stat . value } </ div >
166335 < p className = "text-slate-400 text-sm" > { stat . label } </ p >
167336 </ div >
@@ -176,7 +345,8 @@ function Problem() {
176345// ─── SOLUTION ───────────────────────────────────────────────────────────────
177346function Solution ( ) {
178347 return (
179- < section className = "py-24 px-6 bg-gradient-to-b from-slate-950 via-slate-900 to-slate-950" >
348+ < section className = "py-24 px-6 bg-gradient-to-b from-slate-950 via-slate-900 to-slate-950 relative" >
349+ < WaterSurface className = "top-0 h-16 opacity-50" />
180350 < div className = "max-w-6xl mx-auto grid md:grid-cols-2 gap-16 items-center" >
181351 < FadeIn >
182352 < p className = "text-sky-400 font-medium text-sm tracking-wider uppercase mb-4" > The Solution</ p >
@@ -208,7 +378,6 @@ function Solution() {
208378 </ FadeIn >
209379
210380 < FadeIn delay = { 200 } >
211- { /* PLACEHOLDER: Product photo — receiver + transmitter */ }
212381 < div className = "bg-slate-800 rounded-2xl aspect-square flex items-center justify-center border border-slate-700" >
213382 < div className = "text-center p-8" >
214383 < p className = "text-slate-500 text-sm" > Product photo placeholder</ p >
@@ -254,7 +423,7 @@ function HowItWorks() {
254423
255424 < div className = "space-y-24" >
256425 { steps . map ( ( step , i ) => (
257- < div key = { i } className = { `grid md:grid-cols-2 gap-12 items-center ${ i % 2 === 1 ? 'md:flex-row-reverse' : '' } ` } >
426+ < div key = { i } className = { `grid md:grid-cols-2 gap-12 items-center` } >
258427 < FadeIn className = { i % 2 === 1 ? 'md:order-2' : '' } >
259428 < div className = "text-sky-500 font-mono text-6xl font-bold opacity-20 mb-4" > { step . num } </ div >
260429 < h3 className = "text-2xl font-bold mb-4" > { step . title } </ h3 >
@@ -276,19 +445,20 @@ function HowItWorks() {
276445// ─── FEATURES ───────────────────────────────────────────────────────────────
277446function Features ( ) {
278447 const features = [
279- { icon : '📡' , title : 'Long Range LoRa' , desc : 'Up to 5km line-of-sight. Works through walls and across buildings.' } ,
280- { icon : '🔋' , title : 'Low Power' , desc : '6+ months battery life with deep sleep. Solar charging optional.' } ,
281- { icon : '📱' , title : 'Real-Time Dashboard' , desc : 'See water levels, battery, signal strength — all from your phone.' } ,
282- { icon : '🔔' , title : 'Smart Alerts' , desc : 'Low water, overflow risk, battery low, device offline — push to your phone.' } ,
283- { icon : '📊' , title : 'Usage History' , desc : 'Track water consumption patterns. Know when to schedule delivery.' } ,
284- { icon : '🏠' , title : 'Home Assistant' , desc : 'Native MQTT integration. Auto-discovery for seamless smart home setup.' } ,
285- { icon : '🔒' , title : 'Secure by Design' , desc : 'MQTT over TLS, per-user credentials, encrypted cloud connection.' } ,
286- { icon : '📦' , title : 'Multi-Tank' , desc : 'Monitor up to 10 tanks from one receiver. Perfect for farms and buildings.' } ,
287- { icon : '🔄' , title : 'OTA Updates' , desc : 'Update firmware wirelessly. New features delivered over the air.' } ,
448+ { icon : icons . radio , title : 'Long Range LoRa' , desc : 'Up to 5km line-of-sight. Works through walls and across buildings.' } ,
449+ { icon : icons . battery , title : 'Low Power' , desc : '6+ months battery life with deep sleep. Solar charging optional.' } ,
450+ { icon : icons . phone , title : 'Real-Time Dashboard' , desc : 'See water levels, battery, signal strength — all from your phone.' } ,
451+ { icon : icons . bell , title : 'Smart Alerts' , desc : 'Low water, overflow risk, battery low, device offline — push to your phone.' } ,
452+ { icon : icons . chart , title : 'Usage History' , desc : 'Track water consumption patterns. Know when to schedule delivery.' } ,
453+ { icon : icons . homeAssistant , title : 'Home Assistant' , desc : 'Native MQTT integration. Auto-discovery for seamless smart home setup.' } ,
454+ { icon : icons . shield , title : 'Secure by Design' , desc : 'MQTT over TLS, per-user credentials, encrypted cloud connection.' } ,
455+ { icon : icons . layers , title : 'Multi-Tank' , desc : 'Monitor up to 10 tanks from one receiver. Perfect for farms and buildings.' } ,
456+ { icon : icons . refresh , title : 'OTA Updates' , desc : 'Update firmware wirelessly. New features delivered over the air.' } ,
288457 ] ;
289458
290459 return (
291- < section id = "features" className = "py-24 px-6 bg-gradient-to-b from-slate-950 via-slate-900 to-slate-950" >
460+ < section id = "features" className = "py-24 px-6 bg-gradient-to-b from-slate-950 via-slate-900 to-slate-950 relative" >
461+ < WaterSurface className = "bottom-0 h-16 opacity-40" />
292462 < div className = "max-w-6xl mx-auto" >
293463 < FadeIn >
294464 < p className = "text-sky-400 font-medium text-sm tracking-wider uppercase mb-4 text-center" > Features</ p >
@@ -299,7 +469,9 @@ function Features() {
299469 { features . map ( ( f , i ) => (
300470 < FadeIn key = { i } delay = { i * 80 } >
301471 < div className = "bg-slate-900/50 border border-slate-800 rounded-2xl p-6 hover:border-sky-500/30 hover:bg-slate-900 transition-all group" >
302- < div className = "text-3xl mb-4 group-hover:scale-110 transition-transform" > { f . icon } </ div >
472+ < div className = "w-12 h-12 rounded-xl bg-sky-500/10 flex items-center justify-center mb-4 group-hover:bg-sky-500/20 transition-colors" >
473+ { f . icon }
474+ </ div >
303475 < h3 className = "font-semibold text-lg mb-2" > { f . title } </ h3 >
304476 < p className = "text-slate-400 text-sm leading-relaxed" > { f . desc } </ p >
305477 </ div >
@@ -375,7 +547,6 @@ function TechSpecs() {
375547
376548// ─── PRICING ────────────────────────────────────────────────────────────────
377549function Pricing ( { onGetStarted } ) {
378- // Detect India by timezone (simple, no API call)
379550 const isIndia = Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone ?. startsWith ( 'Asia/Calcutta' ) ||
380551 Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone ?. startsWith ( 'Asia/Kolkata' ) ;
381552
@@ -415,13 +586,13 @@ function Pricing({ onGetStarted }) {
415586 } ,
416587 {
417588 name : 'Pro' ,
418- price : isIndia ? '299 ' : '4 .99' ,
589+ price : isIndia ? '599 ' : '9 .99' ,
419590 currency : isIndia ? '₹' : '$' ,
420591 period : '/month' ,
421- annual : isIndia ? '₹2,499 /year (save 30%)' : '$49 /year (save 18 %)' ,
592+ annual : isIndia ? '₹4,999 /year (save 30%)' : '$99 /year (save 17 %)' ,
422593 desc : 'For installers and property managers' ,
423594 features : [
424- 'Unlimited sites and tanks' ,
595+ 'Up to 10 sites, 50 tanks' ,
425596 '1-year history' ,
426597 'Fleet dashboard' ,
427598 'Client sharing (read-only links)' ,
@@ -513,7 +684,6 @@ function Hardware() {
513684 < div className = "grid md:grid-cols-2 gap-8 max-w-4xl mx-auto" >
514685 < FadeIn >
515686 < div className = "bg-slate-900/50 border border-slate-800 rounded-2xl overflow-hidden hover:border-sky-500/30 transition-all" >
516- { /* PLACEHOLDER: Single tank kit photo */ }
517687 < div className = "bg-slate-800 aspect-[4/3] flex items-center justify-center" >
518688 < p className = "text-slate-600 text-xs" > Single Tank Kit photo — 800x600</ p >
519689 </ div >
@@ -534,7 +704,6 @@ function Hardware() {
534704
535705 < FadeIn delay = { 150 } >
536706 < div className = "bg-slate-900/50 border border-slate-800 rounded-2xl overflow-hidden hover:border-sky-500/30 transition-all" >
537- { /* PLACEHOLDER: Dual tank kit photo */ }
538707 < div className = "bg-slate-800 aspect-[4/3] flex items-center justify-center" >
539708 < p className = "text-slate-600 text-xs" > Dual Tank Kit photo — 800x600</ p >
540709 </ div >
0 commit comments