'use client' import { motion, AnimatePresence } from 'motion/react' import { ArrowRight, Menu, X, Check, BrainCircuit, Network, GraduationCap, Bot, KeyRound, Globe, ChevronDown } from 'lucide-react' import Link from 'next/link' import Image from 'next/image' import { useLanguage } from '@/lib/i18n' import type { SupportedLanguage } from '@/lib/i18n/load-translations' import { SUBSCRIPTION_TRIAL_DAYS } from '@/lib/billing/trial-constants' import { useEffect, useRef, useState, type ReactNode } from 'react' import { useQuery } from '@tanstack/react-query' const ECHO_LINES = ['echo0', 'echo1', 'echo2'] as const const LANDING_LANGS: { code: SupportedLanguage; labelKey: string }[] = [ { code: 'fr', labelKey: 'languages.fr' }, { code: 'en', labelKey: 'languages.en' }, { code: 'es', labelKey: 'languages.es' }, { code: 'de', labelKey: 'languages.de' }, { code: 'it', labelKey: 'languages.it' }, { code: 'pt', labelKey: 'languages.pt' }, { code: 'nl', labelKey: 'languages.nl' }, { code: 'pl', labelKey: 'languages.pl' }, { code: 'ru', labelKey: 'languages.ru' }, { code: 'zh', labelKey: 'languages.zh' }, { code: 'ja', labelKey: 'languages.ja' }, { code: 'ko', labelKey: 'languages.ko' }, { code: 'ar', labelKey: 'languages.ar' }, { code: 'fa', labelKey: 'languages.fa' }, { code: 'hi', labelKey: 'languages.hi' }, ] export function LandingPage() { const { t, language, setLanguage } = useLanguage() const [billingInterval, setBillingInterval] = useState<'monthly' | 'annual'>('monthly') const [menuOpen, setMenuOpen] = useState(false) const [langOpen, setLangOpen] = useState(false) const [echoIndex, setEchoIndex] = useState(0) const langRef = useRef(null) const { data: byokCatalog } = useQuery({ queryKey: ['public', 'byok-catalog'], queryFn: async () => { const res = await fetch('/api/public/byok-catalog') if (!res.ok) throw new Error('catalog') return res.json() as Promise<{ providers: { id: string; name: string }[] }> }, staleTime: 60_000, }) const byokProviders = byokCatalog?.providers ?? [] useEffect(() => { if (!langOpen) return const onPointer = (e: MouseEvent) => { if (langRef.current && !langRef.current.contains(e.target as Node)) setLangOpen(false) } const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') setLangOpen(false) } document.addEventListener('mousedown', onPointer) document.addEventListener('keydown', onKey) return () => { document.removeEventListener('mousedown', onPointer) document.removeEventListener('keydown', onKey) } }, [langOpen]) useEffect(() => { const id = setInterval(() => setEchoIndex((i) => (i + 1) % ECHO_LINES.length), 3200) return () => clearInterval(id) }, []) useEffect(() => { const root = document.querySelector('[data-public-scroll-root]') if (!root) return const prev = root.style.overflow if (menuOpen) root.style.overflow = 'hidden' else root.style.overflow = prev || '' return () => { root.style.overflow = prev } }, [menuOpen]) const trialDays = SUBSCRIPTION_TRIAL_DAYS const PLANS = [ { key: 'basic', popular: false, hasTrial: false, price: t('landing.pricing.basicPrice'), period: '' }, { key: 'pro', popular: true, hasTrial: true, price: billingInterval === 'monthly' ? t('landing.pricing.proMonthly') : t('landing.pricing.proAnnualMonthly'), period: billingInterval === 'monthly' ? t('landing.pricing.perMonth') : t('landing.pricing.perMonthAnnual'), }, { key: 'business', popular: false, hasTrial: true, price: billingInterval === 'monthly' ? t('landing.pricing.businessMonthly') : t('landing.pricing.businessAnnualMonthly'), period: billingInterval === 'monthly' ? t('landing.pricing.perMonth') : t('landing.pricing.perMonthAnnual'), }, { key: 'enterprise', popular: false, hasTrial: false, price: t('landing.pricing.enterprisePrice'), period: '', }, ] const NAV = [ { href: '#product', label: t('landing.nav.secondBrain') }, { href: '#echo', label: t('landing.nav.echo') }, { href: '#agents', label: t('landing.nav.agents') }, { href: '#pricing', label: t('landing.nav.pricing') }, ] const scrollPublicHash = (hash: string) => { const id = hash.replace(/^#/, '') const target = document.getElementById(id) const root = document.querySelector('[data-public-scroll-root]') if (!target || !root) return const top = target.getBoundingClientRect().top - root.getBoundingClientRect().top + root.scrollTop - 88 root.scrollTo({ top, behavior: 'smooth' }) } useEffect(() => { const hash = window.location.hash if (!hash) return const id = window.requestAnimationFrame(() => scrollPublicHash(hash)) return () => window.cancelAnimationFrame(id) }, []) return (
{/* Nav */} {menuOpen && (
{NAV.map((l) => ( { event.preventDefault() setMenuOpen(false) scrollPublicHash(l.href) window.history.replaceState(null, '', l.href) }} className="py-4 text-3xl font-serif border-b border-white/10" > {l.label} ))} setMenuOpen(false)} className="mt-10 py-4 text-2xl font-serif text-white/80 text-center border-b border-white/10" > {t('landing.nav.login')} setMenuOpen(false)} className="mt-4 py-4 rounded-2xl bg-[#F4F1EA] text-[#0B0A09] text-center font-semibold"> {t('landing.nav.cta')}
)}
{/* ── HERO ── */}
{/* Atmosphere — warm, not purple neon */}
{t('landing.hero.badge')}

{t('landing.hero.eyebrow')}

{t('landing.hero.headline')}
{t('landing.hero.headlineAccent')}

{t('landing.hero.subtitle')}

{t('landing.hero.cta')}

{t('landing.hero.ctaHint')}

{/* Product stage */}
{t('landing.hero.imageAlt')} {/* Live Memory Echo chip */}
{t('landing.hero.echoLive')}
{t(`landing.hero.${ECHO_LINES[echoIndex]}`)}
{/* Trust strip */}
{['trust0', 'trust1', 'trust2', 'trust3'].map((k) => ( {t(`landing.trust.${k}`)} ))}
{/* Pain → Promise */}

{t('landing.pain.label')}

{t('landing.pain.title')}

{t('landing.pain.desc')}

{t('landing.pain.secondBrain')}

{/* Product moments — large narrative blocks, not wireframe cards */}
{[0, 1, 2].map((i) => (

{t(`landing.moments.echo.card${i}Label`)}

{t(`landing.moments.echo.card${i}`)}

))}
{['w0', 'w1', 'w2', 'w3'].map((w) => (

{t(`landing.moments.dashboard.${w}Label`)}

{t(`landing.moments.dashboard.${w}`)}

))}

{t('landing.moments.insights.chip')}

{t('landing.moments.revision.card')}

? {t('landing.moments.revision.badge')}
{/* How it works */}

{t('landing.how.title')}

{['s0', 's1', 's2'].map((s, i) => (
0{i + 1}

{t(`landing.how.${s}.title`)}

{t(`landing.how.${s}.desc`)}

))}
{/* Agents */}

{t('landing.agents.label')}

{t('landing.agents.title')}

{t('landing.agents.desc')}

{(['scraper', 'researcher', 'slideGen', 'monitor', 'diagramGen', 'custom'] as const).map((key) => (

{t(`landing.agents.${key}.title`)}

{t(`landing.agents.${key}.desc`)}

))}
{/* BYOK */}
{t('landing.byok.label')}

{t('landing.byok.title')}

{t('landing.byok.desc')}

{byokProviders.length > 0 ? (
    {byokProviders.map((p) => (
  • {p.name}
  • ))}
) : (

{t('landing.byok.pointProvider')}

)}

{t('landing.byok.pointYours')}

{/* Pricing */}

{t('landing.pricing.title')}

{t('landing.pricing.desc')}

{PLANS.map((plan) => (
{plan.popular && ( {t('landing.pricing.popular')} )}

{t(`landing.pricing.${plan.key}.name`)}

{plan.price} {plan.period && {plan.period}}
{plan.hasTrial && (

{t('landing.pricing.trialBadge', { days: trialDays })}

)}

{t(`landing.pricing.${plan.key}.desc`)}

    {plan.hasTrial && (
  • {t('landing.pricing.trialFeature', { days: trialDays })}
  • )} {[0, 1, 2, 3, 4, 5].map((j) => { const feat = t(`landing.pricing.${plan.key}.feature${j}`, { count: byokProviders.length || '…', }) if (!feat || feat.startsWith('landing.')) return null return (
  • {feat}
  • ) })}
{plan.hasTrial ? t('landing.pricing.trialCta', { days: trialDays }) : t(`landing.pricing.${plan.key}.cta`)}
))}
{/* Final CTA */}

{t('landing.cta.title')}

{t('landing.cta.desc')}

{t('landing.cta.button')}

{t('landing.hero.ctaHint')}

M
Memento

{t('landing.footer.desc')}

{(['product', 'community', 'legal'] as const).map((section) => (

{t(`landing.footer.${section}.title`)}

    {[0, 1, 2].map((j) => { const label = t(`landing.footer.${section}.link${j}`) const href = t(`landing.footer.${section}.link${j}Href`) if (!label || label.startsWith('landing.')) return null return (
  • {href.startsWith('/') ? ( {label} ) : ( {label} )}
  • ) })}
))}

© 2026 Memento. {t('landing.footer.rights')}

) } function ProductMoment({ id, eyebrow, title, desc, children, dark, compact, }: { id?: string eyebrow: string title: string desc: string children: ReactNode dark?: boolean compact?: boolean }) { return (

{eyebrow}

{title}

{desc}

{children}
) }