diff --git a/src/app/home/page.tsx b/src/app/home/page.tsx
new file mode 100644
index 0000000..8c24a9f
--- /dev/null
+++ b/src/app/home/page.tsx
@@ -0,0 +1,65 @@
+import { Metadata } from 'next';
+import { LandingPage } from '@/components/landing/LandingPage';
+
+export const metadata: Metadata = {
+ title: 'QuitTraq - Track Your Journey to Quit Smoking & Marijuana',
+ description: 'Free app to track nicotine and marijuana usage. Health recovery timeline, achievements, savings tracker. PWA works offline. Your companion to a healthier life.',
+ keywords: ['quit smoking', 'stop smoking app', 'nicotine tracker', 'marijuana tracker', 'health recovery', 'quit vaping', 'substance tracker'],
+ authors: [{ name: 'QuitTraq' }],
+ openGraph: {
+ type: 'website',
+ locale: 'en_US',
+ url: 'https://quittraq.com/home',
+ title: 'QuitTraq - Track Your Journey to Quit Smoking',
+ description: 'Free app to track nicotine and marijuana usage with health timeline and achievements.',
+ siteName: 'QuitTraq',
+ images: [
+ {
+ url: '/og-image.png',
+ width: 1200,
+ height: 630,
+ alt: 'QuitTraq - Quit Smoking App',
+ },
+ ],
+ },
+ twitter: {
+ card: 'summary_large_image',
+ title: 'QuitTraq - Track Your Journey to Quit Smoking',
+ description: 'Free app to track nicotine and marijuana usage with health timeline and achievements.',
+ images: ['/og-image.png'],
+ },
+ robots: {
+ index: true,
+ follow: true,
+ googleBot: {
+ index: true,
+ follow: true,
+ },
+ },
+};
+
+export default function HomePage() {
+ const jsonLd = {
+ '@context': 'https://schema.org',
+ '@type': 'WebApplication',
+ name: 'QuitTraq',
+ description: 'Track your journey to quit smoking and marijuana',
+ applicationCategory: 'HealthApplication',
+ operatingSystem: 'Any',
+ offers: {
+ '@type': 'Offer',
+ price: '0',
+ priceCurrency: 'USD',
+ },
+ };
+
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/src/components/landing/CTASection.tsx b/src/components/landing/CTASection.tsx
new file mode 100644
index 0000000..dc9d512
--- /dev/null
+++ b/src/components/landing/CTASection.tsx
@@ -0,0 +1,224 @@
+'use client';
+
+import { useState } from 'react';
+import Link from 'next/link';
+import { Button } from '@/components/ui/button';
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+} from '@/components/ui/dialog';
+import { ArrowRight, Smartphone, Shield, CreditCard, Wifi, Download, Share, Plus, MoreVertical } from 'lucide-react';
+import { type PWAInstallState } from '@/hooks/usePWAInstall';
+
+interface CTASectionProps {
+ pwaInstall: PWAInstallState;
+}
+
+export function CTASection({ pwaInstall }: CTASectionProps) {
+ const [showInstructions, setShowInstructions] = useState(false);
+
+ const handleInstallClick = async () => {
+ if (pwaInstall.isInstallable) {
+ await pwaInstall.promptInstall();
+ } else {
+ setShowInstructions(true);
+ }
+ };
+
+ return (
+
+ {/* Background gradient */}
+
+
+
+
+ {/* Headline */}
+
+ Ready to Start Your{' '}
+
+ Journey?
+
+
+
+ {/* Subheadline */}
+
+ Join thousands of people taking control of their health. Your first step starts here.
+
+
+ {/* Dual CTAs */}
+
+
+
+ {!pwaInstall.isStandalone && (
+
+ )}
+
+
+ {/* Trust signals */}
+
+
+
+ No Credit Card Required
+
+
+
+ Privacy Focused
+
+
+
+ Works Offline
+
+
+
+
+ {/* PWA Install Instructions Dialog */}
+
+
+ );
+}
diff --git a/src/components/landing/DemoSection.tsx b/src/components/landing/DemoSection.tsx
new file mode 100644
index 0000000..e55f7de
--- /dev/null
+++ b/src/components/landing/DemoSection.tsx
@@ -0,0 +1,267 @@
+'use client';
+
+import { useState, useEffect } from 'react';
+import { Cigarette, Leaf, Heart, Trophy, DollarSign, TrendingDown, CheckCircle } from 'lucide-react';
+
+const DEMO_SCREENS = [
+ {
+ id: 'logging',
+ title: 'Log Your Usage',
+ subtitle: 'Track daily consumption with ease',
+ content: (
+
+
+
+
+
+ Down 40% from last week
+
+
+ ),
+ },
+ {
+ id: 'health',
+ title: 'Health Recovery',
+ subtitle: 'Watch your body heal',
+ content: (
+
+
+
+ Blood Pressure Normalizes
+
+
+
+
+
+
+ Oxygen Levels Rise
+
+
+
+
+
+
+ Circulation Improves
+ 1 week to go
+
+
+
+
+
+ Heart Attack Risk Drops
+ 2 weeks to go
+
+
+
+
+ ),
+ },
+ {
+ id: 'achievements',
+ title: 'Achievements',
+ subtitle: 'Celebrate every milestone',
+ content: (
+
+ {[
+ { name: 'First Step', unlocked: true },
+ { name: 'Hat Trick', unlocked: true },
+ { name: 'Week Warrior', unlocked: true },
+ { name: 'Fighter', unlocked: false },
+ { name: 'Monthly Master', unlocked: false },
+ { name: 'Goal Crusher', unlocked: false },
+ ].map((badge) => (
+
+
+ {badge.name}
+
+ ))}
+
+ ),
+ },
+ {
+ id: 'savings',
+ title: 'Money Saved',
+ subtitle: 'Track your financial wins',
+ content: (
+
+
+
+
+
+
$127.50
+
saved this month
+
+
+
+ ),
+ },
+];
+
+export function DemoSection() {
+ const [activeScreen, setActiveScreen] = useState(0);
+ const [isPaused, setIsPaused] = useState(false);
+
+ useEffect(() => {
+ if (isPaused) return;
+
+ const interval = setInterval(() => {
+ setActiveScreen((prev) => (prev + 1) % DEMO_SCREENS.length);
+ }, 4000);
+
+ return () => clearInterval(interval);
+ }, [isPaused]);
+
+ return (
+
+ {/* Background accents */}
+
+
+
+
+ {/* Section Header */}
+
+
+ See It In{' '}
+
+ Action
+
+
+
+ A quick look at how QuitTraq helps you track progress and stay motivated.
+
+
+
+
+ {/* Phone Mockup */}
+
setIsPaused(true)}
+ onMouseLeave={() => setIsPaused(false)}
+ onTouchStart={() => setIsPaused(true)}
+ onTouchEnd={() => setIsPaused(false)}
+ >
+ {/* Phone frame glow */}
+
+
+ {/* Phone frame */}
+
+ {/* Notch */}
+
+
+ {/* Screen content */}
+
+ {/* Screen header */}
+
+
{DEMO_SCREENS[activeScreen].title}
+
+ {DEMO_SCREENS[activeScreen].subtitle}
+
+
+
+ {/* Screen content with transition */}
+
+ {DEMO_SCREENS[activeScreen].content}
+
+
+
+ {/* Bottom gradient overlay */}
+
+
+
+
+ {/* Description and indicators */}
+
+
+ {/* Screen descriptions */}
+ {DEMO_SCREENS.map((screen, index) => (
+
+ ))}
+
+
+ {/* Dot indicators (mobile) */}
+
+ {DEMO_SCREENS.map((_, index) => (
+
+
+
+
+
+ );
+}
diff --git a/src/components/landing/FeatureCard.tsx b/src/components/landing/FeatureCard.tsx
new file mode 100644
index 0000000..d5144b1
--- /dev/null
+++ b/src/components/landing/FeatureCard.tsx
@@ -0,0 +1,78 @@
+'use client';
+
+import { useRef, useEffect, useState } from 'react';
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
+import { LucideIcon } from 'lucide-react';
+
+interface FeatureIcon {
+ Icon: LucideIcon;
+ color: string;
+ bg: string;
+}
+
+interface FeatureCardProps {
+ title: string;
+ description: string;
+ icons: FeatureIcon[];
+ gradient: string;
+ delay?: number;
+}
+
+export function FeatureCard({ title, description, icons, gradient, delay = 0 }: FeatureCardProps) {
+ const ref = useRef(null);
+ const [isInView, setIsInView] = useState(false);
+
+ useEffect(() => {
+ const observer = new IntersectionObserver(
+ ([entry]) => {
+ if (entry.isIntersecting) {
+ setIsInView(true);
+ observer.disconnect();
+ }
+ },
+ { threshold: 0.1 }
+ );
+
+ if (ref.current) {
+ observer.observe(ref.current);
+ }
+
+ return () => observer.disconnect();
+ }, []);
+
+ return (
+
+
+ {/* Decorative gradient orb */}
+
+
+
+
+ {icons.map((icon, index) => (
+
+
+
+ ))}
+
+ {title}
+
+
+
+ {description}
+
+
+
+ );
+}
diff --git a/src/components/landing/FeaturesSection.tsx b/src/components/landing/FeaturesSection.tsx
new file mode 100644
index 0000000..2cf4cdd
--- /dev/null
+++ b/src/components/landing/FeaturesSection.tsx
@@ -0,0 +1,88 @@
+'use client';
+
+import { FeatureCard } from './FeatureCard';
+import { Cigarette, Leaf, Heart, Trophy, DollarSign } from 'lucide-react';
+
+const FEATURES = [
+ {
+ id: 'dual-tracking',
+ title: 'Dual Substance Tracking',
+ description:
+ 'Track both nicotine and marijuana independently. Each substance has its own stats, timeline, and achievements to support your unique journey.',
+ icons: [
+ { Icon: Cigarette, color: 'text-red-400', bg: 'bg-red-500/20' },
+ { Icon: Leaf, color: 'text-green-400', bg: 'bg-green-500/20' },
+ ],
+ gradient: 'rgba(239, 68, 68, 0.15) 0%, rgba(34, 197, 94, 0.15) 100%',
+ },
+ {
+ id: 'health-timeline',
+ title: 'Health Recovery Timeline',
+ description:
+ 'Watch your body heal in real-time. From 20 minutes to 1 year, track every health milestone as your body recovers and gets stronger.',
+ icons: [{ Icon: Heart, color: 'text-teal-400', bg: 'bg-teal-500/20' }],
+ gradient: 'rgba(20, 184, 166, 0.15) 0%, rgba(6, 182, 212, 0.1) 100%',
+ },
+ {
+ id: 'achievements',
+ title: 'Achievements & Badges',
+ description:
+ 'Unlock badges as you progress. First Step, Week Warrior, Goal Crusher - celebrate every win and stay motivated on your journey.',
+ icons: [{ Icon: Trophy, color: 'text-yellow-400', bg: 'bg-yellow-500/20' }],
+ gradient: 'rgba(234, 179, 8, 0.15) 0%, rgba(245, 158, 11, 0.1) 100%',
+ },
+ {
+ id: 'savings',
+ title: 'Money Savings Tracker',
+ description:
+ 'See how much you save by cutting back. Set your goals and watch your savings grow daily - extra motivation to keep going.',
+ icons: [{ Icon: DollarSign, color: 'text-emerald-400', bg: 'bg-emerald-500/20' }],
+ gradient: 'rgba(16, 185, 129, 0.15) 0%, rgba(34, 197, 94, 0.1) 100%',
+ },
+];
+
+export function FeaturesSection() {
+ return (
+
+ {/* Background accent */}
+
+
+
+ {/* Section Header */}
+
+
+ Everything You Need to{' '}
+
+ Succeed
+
+
+
+ Built with empathy and designed for your success. Every feature supports your journey
+ to a healthier, happier life.
+
+
+
+ {/* Features Grid */}
+
+ {FEATURES.map((feature, index) => (
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/landing/HeroSection.tsx b/src/components/landing/HeroSection.tsx
new file mode 100644
index 0000000..017a271
--- /dev/null
+++ b/src/components/landing/HeroSection.tsx
@@ -0,0 +1,233 @@
+'use client';
+
+import { useState } from 'react';
+import Link from 'next/link';
+import { Button } from '@/components/ui/button';
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+} from '@/components/ui/dialog';
+import { ArrowRight, Smartphone, CheckCircle, Shield, Wifi, Download, Share, Plus, MoreVertical } from 'lucide-react';
+import { type PWAInstallState } from '@/hooks/usePWAInstall';
+
+interface HeroSectionProps {
+ pwaInstall: PWAInstallState;
+}
+
+export function HeroSection({ pwaInstall }: HeroSectionProps) {
+ const [showInstructions, setShowInstructions] = useState(false);
+
+ const handleInstallClick = async () => {
+ if (pwaInstall.isInstallable) {
+ await pwaInstall.promptInstall();
+ } else {
+ setShowInstructions(true);
+ }
+ };
+
+ return (
+
+ {/* Background decorative elements */}
+
+
+
+
+
+ {/* Badge */}
+
+
+ Free & Works Offline
+
+
+ {/* Headline */}
+
+
+ Take Control
+
+
+ of Your Journey
+
+
+ {/* Subheadline */}
+
+ Track nicotine and marijuana usage, celebrate milestones, and watch your health recover.
+ Your companion to a healthier life.
+
+
+ {/* Dual CTAs */}
+
+
+
+ {!pwaInstall.isStandalone && (
+
+ )}
+
+
+ {/* Trust signals */}
+
+
+
+ Privacy First
+
+
+
+ Works Offline
+
+
+
+ Always Free
+
+
+
+
+ {/* PWA Install Instructions Dialog */}
+
+
+ );
+}
diff --git a/src/components/landing/LandingFooter.tsx b/src/components/landing/LandingFooter.tsx
new file mode 100644
index 0000000..8a5c6ee
--- /dev/null
+++ b/src/components/landing/LandingFooter.tsx
@@ -0,0 +1,107 @@
+'use client';
+
+import Link from 'next/link';
+
+const footerLinks = {
+ product: [
+ { label: 'Features', href: '#features' },
+ { label: 'Demo', href: '#demo' },
+ { label: 'Get Started', href: '#cta' },
+ ],
+ legal: [
+ { label: 'Privacy Policy', href: '/privacy' },
+ { label: 'Terms of Service', href: '/terms' },
+ ],
+};
+
+export function LandingFooter() {
+ const currentYear = new Date().getFullYear();
+
+ const handleAnchorClick = (href: string) => {
+ if (href.startsWith('#')) {
+ const element = document.querySelector(href);
+ if (element) {
+ element.scrollIntoView({ behavior: 'smooth' });
+ }
+ }
+ };
+
+ return (
+
+ );
+}
diff --git a/src/components/landing/LandingNav.tsx b/src/components/landing/LandingNav.tsx
new file mode 100644
index 0000000..813e573
--- /dev/null
+++ b/src/components/landing/LandingNav.tsx
@@ -0,0 +1,142 @@
+'use client';
+
+import { useState } from 'react';
+import Link from 'next/link';
+import { Button } from '@/components/ui/button';
+import { Menu, X, Sun, Moon } from 'lucide-react';
+
+interface LandingNavProps {
+ theme: 'dark' | 'light';
+ toggleTheme: () => void;
+}
+
+const navLinks = [
+ { href: '#features', label: 'Features' },
+ { href: '#demo', label: 'Demo' },
+ { href: '#cta', label: 'Get Started' },
+];
+
+export function LandingNav({ theme, toggleTheme }: LandingNavProps) {
+ const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
+
+ const handleNavClick = (href: string) => {
+ setMobileMenuOpen(false);
+ // Smooth scroll handled by CSS (scroll-behavior: smooth)
+ const element = document.querySelector(href);
+ if (element) {
+ element.scrollIntoView({ behavior: 'smooth' });
+ }
+ };
+
+ return (
+
+ );
+}
diff --git a/src/components/landing/LandingPage.tsx b/src/components/landing/LandingPage.tsx
new file mode 100644
index 0000000..a02759f
--- /dev/null
+++ b/src/components/landing/LandingPage.tsx
@@ -0,0 +1,38 @@
+'use client';
+
+import { useTheme } from '@/lib/theme-context';
+import { LandingNav } from './LandingNav';
+import { HeroSection } from './HeroSection';
+import { FeaturesSection } from './FeaturesSection';
+import { DemoSection } from './DemoSection';
+import { CTASection } from './CTASection';
+import { LandingFooter } from './LandingFooter';
+import { usePWAInstall } from '@/hooks/usePWAInstall';
+
+export function LandingPage() {
+ const { theme, toggleTheme } = useTheme();
+ const pwaInstall = usePWAInstall();
+
+ return (
+
+ );
+}
diff --git a/src/hooks/usePWAInstall.ts b/src/hooks/usePWAInstall.ts
new file mode 100644
index 0000000..9ac4f3c
--- /dev/null
+++ b/src/hooks/usePWAInstall.ts
@@ -0,0 +1,78 @@
+'use client';
+
+import { useState, useEffect, useCallback } from 'react';
+
+interface BeforeInstallPromptEvent extends Event {
+ prompt: () => Promise;
+ userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>;
+}
+
+export interface PWAInstallState {
+ isInstallable: boolean;
+ isStandalone: boolean;
+ isIOS: boolean;
+ isAndroid: boolean;
+ needsManualInstructions: boolean;
+ promptInstall: () => Promise<{ outcome: 'accepted' | 'dismissed' | 'unavailable' }>;
+}
+
+export function usePWAInstall(): PWAInstallState {
+ const [deferredPrompt, setDeferredPrompt] = useState(null);
+ const [isIOS, setIsIOS] = useState(false);
+ const [isAndroid, setIsAndroid] = useState(false);
+ const [isStandalone, setIsStandalone] = useState(false);
+ const [isInstallable, setIsInstallable] = useState(false);
+
+ useEffect(() => {
+ // Check if already installed as PWA
+ const isAppInstalled =
+ window.matchMedia('(display-mode: standalone)').matches ||
+ (window.navigator as Navigator & { standalone?: boolean }).standalone === true;
+ setIsStandalone(isAppInstalled);
+
+ // Detect platform
+ const userAgent = window.navigator.userAgent.toLowerCase();
+ const isIOSDevice = /iphone|ipad|ipod/.test(userAgent);
+ const isAndroidDevice = /android/.test(userAgent);
+ setIsIOS(isIOSDevice);
+ setIsAndroid(isAndroidDevice);
+
+ // Listen for beforeinstallprompt (Android/Chrome)
+ const handleBeforeInstallPrompt = (e: Event) => {
+ e.preventDefault();
+ setDeferredPrompt(e as BeforeInstallPromptEvent);
+ setIsInstallable(true);
+ };
+
+ window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
+
+ return () => {
+ window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
+ };
+ }, []);
+
+ const promptInstall = useCallback(async (): Promise<{ outcome: 'accepted' | 'dismissed' | 'unavailable' }> => {
+ if (!deferredPrompt) {
+ return { outcome: 'unavailable' };
+ }
+
+ await deferredPrompt.prompt();
+ const { outcome } = await deferredPrompt.userChoice;
+
+ if (outcome === 'accepted') {
+ setDeferredPrompt(null);
+ setIsInstallable(false);
+ }
+
+ return { outcome };
+ }, [deferredPrompt]);
+
+ return {
+ isInstallable,
+ isStandalone,
+ isIOS,
+ isAndroid,
+ needsManualInstructions: !deferredPrompt && (isIOS || isAndroid),
+ promptInstall,
+ };
+}
diff --git a/src/lib/theme-context.tsx b/src/lib/theme-context.tsx
index d8a450d..e9a9ad4 100644
--- a/src/lib/theme-context.tsx
+++ b/src/lib/theme-context.tsx
@@ -15,10 +15,31 @@ export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState('dark');
useEffect(() => {
+ // Check localStorage first
const saved = localStorage.getItem('theme') as Theme | null;
if (saved) {
setTheme(saved);
+ return;
}
+
+ // Fall back to system preference
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
+ setTheme(prefersDark ? 'dark' : 'light');
+ }, []);
+
+ // Listen for system preference changes (only if no manual preference set)
+ useEffect(() => {
+ const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
+
+ const handleChange = (e: MediaQueryListEvent) => {
+ // Only update if user hasn't manually set a preference
+ if (!localStorage.getItem('theme')) {
+ setTheme(e.matches ? 'dark' : 'light');
+ }
+ };
+
+ mediaQuery.addEventListener('change', handleChange);
+ return () => mediaQuery.removeEventListener('change', handleChange);
}, []);
useEffect(() => {