Files
Momento/memento-note/components/landing-page.tsx
Antigravity 96e7902f01
Some checks failed
CI / Lint, Unit Tests & Build (push) Failing after 1m22s
CI / Deploy production (on server) (push) Has been skipped
feat: publication IA (magazine/brief/essay) + fixes critique
Publication IA:
- 4 templates (magazine, brief, essay, simple) avec CSS riche
- Rewrite IA (article/exercises/tutorial/reference/mixed)
- Modération avec timeout 12s + fallback safe
- Quotas publish_enhance par tier (basic=2, pro=15, business=100)
- Détection contenu stale (hash)
- Migration DB publishedContent/publishedTemplate/publishedSourceHash

Fixes:
- cheerio v1.2: Element -> AnyNode (domhandler), decodeEntities cast
- _isShared ajouté au type Note (champ virtuel serveur)
- callout colors PDF export: extraction fonction pure testable
- admin/published: guard note.userId null
- Cmd+S fonctionne en mode dialog (pas seulement fullPage)

i18n:
- 23 clés publish* traduites dans les 15 locales
- Extension Web Clipper: 13 locales mise à jour

Tests:
- callout-colors.test.ts (6 tests)
- note-visible-in-view.test.ts (5 tests)
- entitlements.test.ts + byok-entitlements.test.ts: mock usageLog + unstubAllEnvs
- 199/199 tests passent

Tracker: user-stories.md sync avec sprint-status.yaml
2026-06-28 07:32:57 +00:00

413 lines
26 KiB
TypeScript

'use client'
import { motion } from 'motion/react'
import {
BrainCircuit, Search, MessageSquare, Zap, Cpu, Workflow,
Globe, Shield, ArrowRight, Sparkles, Layers, Activity,
Box
} from 'lucide-react'
import { useRouter } from 'next/navigation'
import { useLanguage } from '@/lib/i18n'
import { useState } from 'react'
export function LandingPage() {
const { t } = useLanguage()
const router = useRouter()
const [billingInterval, setBillingInterval] = useState<'monthly' | 'annual'>('monthly')
const AGENTS = [
{ key: 'scraper', icon: <Globe size={24} /> },
{ key: 'researcher', icon: <Search size={24} /> },
{ key: 'slideGen', icon: <Layers size={24} /> },
{ key: 'monitor', icon: <Activity size={24} /> },
{ key: 'diagramGen', icon: <Box size={24} /> },
{ key: 'custom', icon: <Workflow size={24} /> },
]
const BRAINSTORM_ITEMS = ['waveGeneration', 'collaboration', 'export']
const PLANS = [
{ key: 'basic', popular: false, price: t('landing.pricing.basicPrice'), period: '' },
{ key: 'pro', popular: true, price: billingInterval === 'monthly' ? '9,90€' : '7,90€', period: billingInterval === 'monthly' ? t('landing.pricing.perMonth') : t('landing.pricing.perMonthAnnual') },
{ key: 'business', popular: false, price: billingInterval === 'monthly' ? '29,90€' : '23,90€', period: billingInterval === 'monthly' ? t('landing.pricing.perMonth') : t('landing.pricing.perMonthAnnual') },
{ key: 'enterprise', popular: false, price: billingInterval === 'monthly' ? '49,90€' : '39,90€', period: billingInterval === 'monthly' ? t('landing.pricing.perUser') : t('landing.pricing.perUserAnnual') },
]
const TECH_TIERS = [
{ key: 'tags', color: 'bg-brand-accent' },
{ key: 'embeddings', color: 'bg-ochre' },
{ key: 'chatRag', color: 'bg-ink' },
]
const FOOTER_SECTIONS = ['product', 'community', 'legal'] as const
return (
<div className="min-h-screen bg-paper text-ink font-sans selection:bg-ochre/30 selection:text-ink">
{/* Navigation */}
<nav className="fixed top-0 left-0 right-0 z-[100] bg-paper/80 backdrop-blur-md border-b border-border px-8 py-4 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-ink flex items-center justify-center rounded-xl shadow-lg rotate-3 group hover:rotate-0 transition-transform cursor-pointer">
<span className="text-paper font-serif text-2xl font-bold">M</span>
</div>
<span className="font-serif text-2xl font-medium tracking-tight">Memento</span>
</div>
<div className="hidden md:flex items-center gap-10">
<a href="#features" className="text-[11px] font-bold uppercase tracking-widest text-concrete hover:text-ink transition-colors">{t('landing.nav.features')}</a>
<a href="#agents" className="text-[11px] font-bold uppercase tracking-widest text-concrete hover:text-ink transition-colors">{t('landing.nav.agents')}</a>
<a href="#brainstorm" className="text-[11px] font-bold uppercase tracking-widest text-concrete hover:text-ink transition-colors">{t('landing.nav.brainstorm')}</a>
<a href="#pricing" className="text-[11px] font-bold uppercase tracking-widest text-concrete hover:text-ink transition-colors">{t('landing.nav.pricing')}</a>
<a href="#tech" className="text-[11px] font-bold uppercase tracking-widest text-concrete hover:text-ink transition-colors">{t('landing.nav.tech')}</a>
</div>
<div className="flex items-center gap-4">
<button onClick={() => router.push('/login')} className="hidden md:block px-6 py-2.5 text-concrete hover:text-ink text-[11px] font-bold uppercase tracking-widest transition-colors">
{t('landing.nav.login')}
</button>
<button onClick={() => router.push('/register')} className="px-6 py-2.5 bg-ink text-paper rounded-full text-[11px] font-bold uppercase tracking-widest hover:opacity-90 transition-all flex items-center gap-2 group shadow-xl shadow-ink/10">
{t('landing.nav.cta')}
<ArrowRight size={14} className="group-hover:translate-x-1 transition-transform" />
</button>
</div>
</nav>
{/* Hero */}
<section className="relative pt-40 pb-32 px-8 overflow-hidden">
<div className="absolute top-0 right-0 w-[800px] h-[800px] bg-ochre/5 rounded-full blur-[120px] -translate-y-1/2 translate-x-1/4 -z-10" />
<div className="absolute bottom-0 left-0 w-[600px] h-[600px] bg-brand-accent/5 rounded-full blur-[100px] translate-y-1/2 -translate-x-1/4 -z-10" />
<div className="max-w-6xl mx-auto text-center">
<motion.div initial={{ opacity: 0, y: 30 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.8, ease: [0.23, 1, 0.32, 1] }}>
<div className="inline-flex items-center gap-2 px-4 py-1.5 rounded-full bg-ochre/10 border border-ochre/20 text-ochre text-[10px] font-bold uppercase tracking-[0.2em] mb-8">
<Sparkles size={12} />
{t('landing.hero.badge')}
</div>
<h1 className="text-6xl md:text-8xl font-serif font-medium tracking-tight text-ink mb-8 leading-[1.1]">
{t('landing.hero.title1')} <br />
<span className="italic">{t('landing.hero.title2')}</span>
</h1>
<p className="max-w-2xl mx-auto text-lg md:text-xl text-concrete font-light leading-relaxed mb-12">
{t('landing.hero.subtitle')}
</p>
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
<button onClick={() => router.push('/register')} className="px-10 py-5 bg-ink text-paper rounded-2xl text-sm font-bold uppercase tracking-[0.2em] hover:opacity-95 transition-all shadow-2xl shadow-ink/20 flex items-center gap-4 group">
{t('landing.hero.cta')}
<ArrowRight size={18} className="group-hover:translate-x-1 transition-transform" />
</button>
<a href="#features" className="px-10 py-5 border border-border rounded-2xl text-sm font-bold uppercase tracking-[0.2em] hover:bg-slate-50 transition-all">
{t('landing.hero.secondary')}
</a>
</div>
</motion.div>
{/* App Preview Mockup */}
<motion.div initial={{ opacity: 0, y: 100 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 1, delay: 0.2, ease: [0.23, 1, 0.32, 1] }} className="mt-24 relative">
<div className="relative mx-auto max-w-5xl aspect-[16/10] bg-white rounded-[32px] shadow-[0_40px_100px_-20px_rgba(0,0,0,0.15)] border border-border p-4 overflow-hidden group">
<img src="/images/workspace-hero.jpg" alt="Memento Workspace" className="w-full h-full object-cover rounded-2xl filter saturate-[0.8]" />
<div className="absolute inset-0 bg-ink/10 group-hover:bg-ink/0 transition-colors duration-500" />
<div className="absolute top-10 right-10 w-64 bg-paper/90 backdrop-blur-xl border border-border p-6 rounded-2xl shadow-2xl">
<div className="flex items-center gap-3 mb-4">
<div className="w-8 h-8 rounded-full bg-brand-accent/20 flex items-center justify-center text-brand-accent">
<BrainCircuit size={16} />
</div>
<span className="text-[10px] font-bold uppercase tracking-widest">{t('landing.hero.memoryEcho')}</span>
</div>
<p className="text-xs font-serif italic text-ink/70">{t('landing.hero.memoryEchoText')}</p>
</div>
<div className="absolute bottom-10 left-10 w-72 bg-ink text-paper p-6 rounded-2xl shadow-2xl">
<div className="flex items-center gap-3 mb-4">
<Activity size={16} className="text-ochre" />
<span className="text-[10px] font-bold uppercase tracking-widest text-ochre">{t('landing.hero.brainstormLive')}</span>
</div>
<div className="flex items-center -space-x-2">
{[1, 2, 3].map(i => (
<div key={i} className="w-6 h-6 rounded-full border-2 border-ink bg-concrete text-[8px] flex items-center justify-center font-bold">JD</div>
))}
<span className="text-[10px] ml-4 text-paper/60">{t('landing.hero.ideasGenerated')}</span>
</div>
</div>
</div>
</motion.div>
</div>
</section>
{/* Features */}
<section id="features" className="py-32 px-8 bg-paper">
<div className="max-w-6xl mx-auto">
<div className="mb-24 flex flex-col md:flex-row md:items-end justify-between gap-8">
<div className="max-w-2xl">
<span className="text-[11px] font-bold uppercase tracking-[0.3em] text-ochre mb-4 block">{t('landing.features.label')}</span>
<h2 className="text-4xl md:text-5xl font-serif tracking-tight text-ink">{t('landing.features.title')} <br />{t('landing.features.title2')}</h2>
</div>
<div className="text-concrete font-light">{t('landing.features.desc')}</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-12">
{['f1', 'f2', 'f3'].map((f, i) => {
const icons = [
<Search key="s" className="text-brand-accent" />,
<MessageSquare key="m" className="text-ochre" />,
<Zap key="z" className="text-ink" />
]
return (
<div key={f} className="group">
<div className="w-14 h-14 bg-slate-50 border border-border rounded-2xl flex items-center justify-center mb-8 group-hover:bg-ink group-hover:text-paper transition-all duration-300">
{icons[i]}
</div>
<h3 className="text-xl font-serif font-medium mb-4">{t(`landing.features.${f}Title`)}</h3>
<p className="text-sm text-concrete leading-relaxed font-light">{t(`landing.features.${f}Desc`)}</p>
</div>
)
})}
</div>
</div>
</section>
{/* Agents */}
<section id="agents" className="py-32 px-8 bg-ink text-paper overflow-hidden relative">
<div className="absolute top-0 right-0 w-[1000px] h-[1000px] bg-brand-accent/10 rounded-full blur-[150px] -translate-y-1/2 translate-x-1/2" />
<div className="max-w-6xl mx-auto relative z-10">
<div className="text-center mb-24">
<span className="text-[11px] font-bold uppercase tracking-[0.3em] text-ochre mb-4 block">{t('landing.agents.label')}</span>
<h2 className="text-4xl md:text-6xl font-serif tracking-tight mb-8">{t('landing.agents.title')}</h2>
<p className="text-paper/60 max-w-xl mx-auto font-light">{t('landing.agents.desc')}</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{AGENTS.map((agent, i) => (
<div key={i} className="p-8 rounded-3xl bg-white/5 border border-white/10 hover:bg-white/10 transition-all cursor-default group">
<div className="text-ochre mb-6 transition-transform group-hover:scale-110 duration-300">{agent.icon}</div>
<h4 className="text-xl font-serif font-medium mb-4">{t(`landing.agents.${agent.key}.title`)}</h4>
<p className="text-sm text-paper/50 leading-relaxed font-light">{t(`landing.agents.${agent.key}.desc`)}</p>
</div>
))}
</div>
</div>
</section>
{/* Brainstorm */}
<section id="brainstorm" className="py-32 px-8 bg-paper">
<div className="max-w-6xl mx-auto flex flex-col md:flex-row items-center gap-24">
<div className="flex-1">
<span className="text-[11px] font-bold uppercase tracking-[0.3em] text-ochre mb-4 block">{t('landing.brainstorm.label')}</span>
<h2 className="text-4xl md:text-5xl font-serif tracking-tight text-ink mb-8 leading-tight">{t('landing.brainstorm.title')}</h2>
<div className="space-y-8">
{BRAINSTORM_ITEMS.map((item, i) => (
<div key={item} className="flex gap-6">
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-ochre/10 text-ochre flex items-center justify-center font-bold text-xs">{i + 1}</div>
<div>
<h5 className="font-bold text-sm mb-1">{t(`landing.brainstorm.${item}.title`)}</h5>
<p className="text-sm text-concrete font-light leading-relaxed">{t(`landing.brainstorm.${item}.desc`)}</p>
</div>
</div>
))}
</div>
</div>
<div className="flex-1 relative">
<div className="w-[450px] h-[450px] border-2 border-dashed border-border rounded-full flex items-center justify-center relative">
<div className="absolute top-0 right-1/2 translate-x-1/2 -translate-y-1/2 w-4 h-4 bg-ink rounded-full" />
<div className="absolute bottom-0 right-1/2 translate-x-1/2 translate-y-1/2 w-4 h-4 bg-ochre rounded-full" />
<div className="w-[300px] h-[300px] border-2 border-dashed border-border rounded-full flex items-center justify-center">
<div className="w-[150px] h-[150px] border-2 border-dashed border-border rounded-full flex items-center justify-center">
<div className="w-12 h-12 bg-ink rounded-xl shadow-2xl flex items-center justify-center text-paper font-serif text-xl">M</div>
</div>
</div>
</div>
<div className="absolute top-10 right-0 p-4 bg-white border border-border rounded-xl shadow-xl">
<p className="text-[10px] font-bold text-ochre">{t('landing.brainstorm.disruptionLabel')}</p>
<p className="text-xs font-serif italic text-ink">{t('landing.brainstorm.disruptionText')}</p>
</div>
<div className="absolute bottom-20 -left-10 p-4 bg-white border border-border rounded-xl shadow-xl">
<p className="text-[10px] font-bold text-brand-accent">{t('landing.brainstorm.analogyLabel')}</p>
<p className="text-xs font-serif italic text-ink">{t('landing.brainstorm.analogyText')}</p>
</div>
</div>
</div>
</section>
{/* Tech */}
<section id="tech" className="py-32 px-8 bg-slate-50 border-y border-border">
<div className="max-w-6xl mx-auto text-center">
<span className="text-[11px] font-bold uppercase tracking-[0.3em] text-ochre mb-4 block">{t('landing.tech.label')}</span>
<h2 className="text-4xl font-serif tracking-tight mb-16">{t('landing.tech.title')}</h2>
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-8 grayscale opacity-50 hover:grayscale-0 hover:opacity-100 transition-all duration-700">
{['OpenAI', 'Google', 'Anthropic', 'DeepSeek', 'Mistral', 'Meta', 'Ollama', 'Groq', 'X.AI', 'Custom'].map((brand, i) => (
<div key={i} className="flex flex-col items-center gap-3">
<div className="w-12 h-12 bg-white rounded-xl border border-border flex items-center justify-center text-xs font-black tracking-tighter">
{brand.slice(0, 2).toUpperCase()}
</div>
<span className="text-[10px] font-bold uppercase tracking-widest">{brand}</span>
</div>
))}
</div>
<div className="mt-24 max-w-2xl mx-auto p-1 bg-white rounded-3xl border border-border shadow-sm flex flex-col md:flex-row gap-0.5">
{TECH_TIERS.map((tier, i) => (
<div key={i} className="flex-1 p-6 text-left">
<div className={`w-1.5 h-1.5 rounded-full ${tier.color} mb-4`} />
<h6 className="text-[10px] font-bold uppercase tracking-widest text-concrete mb-2">{t(`landing.tech.${tier.key}.title`)}</h6>
<p className="text-xs font-light text-concrete">{t(`landing.tech.${tier.key}.desc`)}</p>
</div>
))}
</div>
</div>
</section>
{/* Pricing */}
<section id="pricing" className="py-32 px-8 bg-paper">
<div className="max-w-7xl mx-auto">
<div className="text-center mb-12">
<span className="text-[11px] font-bold uppercase tracking-[0.3em] text-ochre mb-4 block">{t('landing.pricing.label')}</span>
<h2 className="text-4xl md:text-5xl font-serif tracking-tight text-ink mb-6">{t('landing.pricing.title')}</h2>
<p className="text-concrete font-light max-w-xl mx-auto mb-12">{t('landing.pricing.desc')}</p>
<div className="flex items-center justify-center gap-10 mb-8">
<button onClick={() => setBillingInterval('monthly')} className={`group relative py-2 px-1 transition-all ${billingInterval === 'monthly' ? 'text-ink' : 'text-concrete/40 hover:text-concrete'}`}>
<span className="text-xs font-black uppercase tracking-[0.2em]">{t('landing.pricing.monthly')}</span>
{billingInterval === 'monthly' && (
<motion.div layoutId="interval-active" className="absolute -inset-x-1 -inset-y-0.5 border border-ochre/60" transition={{ type: 'spring', bounce: 0.2, duration: 0.6 }} />
)}
</button>
<div className="relative">
<button onClick={() => setBillingInterval('annual')} className={`group relative py-2 px-1 transition-all ${billingInterval === 'annual' ? 'text-ink' : 'text-concrete/40 hover:text-concrete'}`}>
<span className="text-xs font-black uppercase tracking-[0.2em]">{t('landing.pricing.annual')}</span>
{billingInterval === 'annual' && (
<motion.div layoutId="interval-active" className="absolute -inset-x-1 -inset-y-0.5 border border-ochre/60" transition={{ type: 'spring', bounce: 0.2, duration: 0.6 }} />
)}
</button>
<div className="absolute -top-6 left-1/2 -translate-x-1/2 whitespace-nowrap">
<span className="text-[9px] font-bold text-ochre uppercase tracking-widest italic animate-pulse">(-20%)</span>
</div>
</div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 items-stretch">
{PLANS.map((plan, i) => (
<div key={plan.key} className={`relative p-8 rounded-[32px] border flex flex-col transition-all duration-300 hover:shadow-2xl hover:shadow-ink/5 ${plan.popular ? 'bg-ink text-paper border-ink ring-4 ring-ochre/20' : 'bg-white border-border text-ink'}`}>
{plan.popular && (
<div className="absolute -top-4 left-1/2 -translate-x-1/2 px-4 py-1 bg-ochre text-ink text-[10px] font-bold uppercase tracking-widest rounded-full">
{t('landing.pricing.popular')}
</div>
)}
<div className="mb-8">
<h4 className="text-[11px] font-bold uppercase tracking-widest mb-2 opacity-60">{t(`landing.pricing.${plan.key}.name`)}</h4>
<div className="flex items-baseline gap-1 mb-4">
<span className="text-4xl font-serif font-medium">{plan.price}</span>
{plan.period && <span className="text-xs opacity-60">{plan.period}</span>}
</div>
<p className="text-sm font-light leading-relaxed opacity-80">{t(`landing.pricing.${plan.key}.desc`)}</p>
</div>
<div className="flex-1 space-y-4 mb-10">
{[0, 1, 2, 3, 4, 5].map(j => {
const feat = t(`landing.pricing.${plan.key}.feature${j}`)
if (!feat || feat === `landing.pricing.${plan.key}.feature${j}`) return null
return (
<div key={j} className="flex items-start gap-3">
<div className={`mt-1 rounded-full p-0.5 ${plan.popular ? 'bg-ochre text-ink' : 'bg-brand-accent/10 text-brand-accent'}`}>
<Shield size={10} fill="currentColor" />
</div>
<span className="text-xs font-light">{feat}</span>
</div>
)
})}
</div>
<button onClick={() => router.push('/register')} className={`w-full py-4 rounded-2xl text-xs font-bold uppercase tracking-widest transition-all ${plan.popular ? 'bg-ochre text-ink hover:opacity-90' : 'bg-ink text-paper hover:bg-ink/90'}`}>
{t(`landing.pricing.${plan.key}.cta`)}
</button>
</div>
))}
</div>
{/* BYOK */}
<div className="mt-20 p-12 bg-slate-50 border border-border rounded-[40px] flex flex-col md:flex-row items-center gap-12">
<div className="flex-1">
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-brand-accent/10 text-brand-accent text-[9px] font-bold uppercase tracking-widest mb-6">
<Cpu size={12} />
{t('landing.byok.label')}
</div>
<h3 className="text-3xl font-serif font-medium mb-4">{t('landing.byok.title')}</h3>
<p className="text-concrete font-light leading-relaxed mb-6">{t('landing.byok.desc')}</p>
<div className="grid grid-cols-2 gap-4">
<div className="p-4 bg-white rounded-2xl border border-border">
<h5 className="text-[10px] font-bold uppercase tracking-widest mb-2">{t('landing.byok.noLockin')}</h5>
<p className="text-[10px] text-concrete font-light">{t('landing.byok.noLockinDesc')}</p>
</div>
<div className="p-4 bg-white rounded-2xl border border-border">
<h5 className="text-[10px] font-bold uppercase tracking-widest mb-2">{t('landing.byok.cost')}</h5>
<p className="text-[10px] text-concrete font-light">{t('landing.byok.costDesc')}</p>
</div>
</div>
</div>
<div className="w-full md:w-[400px] bg-ink rounded-3xl p-8 relative overflow-hidden group">
<div className="absolute inset-0 bg-brand-accent/10 blur-[50px] group-hover:bg-ochre/10 transition-colors" />
<div className="relative z-10 font-mono text-[10px] text-paper/40 space-y-2">
<p className="text-ochre">{"{"}</p>
<p className="pl-4">"provider": "anthropic",</p>
<p className="pl-4">"model": "claude-3-opus",</p>
<p className="pl-4 border-l border-brand-accent/30 bg-brand-accent/5">"apiKey": "sk-ant-at03-..."</p>
<p className="pl-4">"useSystemKey": false</p>
<p className="text-ochre">{"}"}</p>
</div>
<div className="mt-8 flex items-center justify-between relative z-10">
<span className="text-[10px] font-bold text-paper uppercase tracking-widest">{t('landing.byok.configLabel')}</span>
<div className="flex gap-1">{[1, 2, 3].map(i => <div key={i} className="w-1 h-1 rounded-full bg-paper/20" />)}</div>
</div>
</div>
</div>
</div>
</section>
{/* Final CTA */}
<section className="py-40 px-8 text-center bg-paper relative overflow-hidden">
<div className="max-w-3xl mx-auto relative z-10">
<h2 className="text-5xl md:text-7xl font-serif tracking-tight mb-8 leading-tight">{t('landing.cta.title1')} <br /><span className="italic">{t('landing.cta.title2')}</span></h2>
<p className="text-lg text-concrete font-light mb-12">{t('landing.cta.desc')}</p>
<button onClick={() => router.push('/register')} className="px-16 py-6 bg-ink text-paper rounded-[32px] text-lg font-bold uppercase tracking-[0.2em] hover:scale-105 transition-all shadow-[0_30px_60px_-15px_rgba(0,0,0,0.3)]">
{t('landing.cta.button')}
</button>
</div>
</section>
{/* Footer */}
<footer className="py-20 px-8 border-t border-border bg-paper">
<div className="max-w-6xl mx-auto flex flex-col md:flex-row justify-between gap-12">
<div className="space-y-6">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-ink flex items-center justify-center rounded-lg">
<span className="text-paper font-serif text-lg font-bold">M</span>
</div>
<span className="font-serif text-xl font-medium tracking-tight">Memento</span>
</div>
<p className="text-sm text-concrete font-light max-w-xs">{t('landing.footer.desc')}</p>
</div>
<div className="grid grid-cols-2 md:grid-cols-3 gap-16">
{FOOTER_SECTIONS.map(section => (
<div key={section} className="space-y-4">
<h6 className="text-[10px] font-bold uppercase tracking-widest text-ink">{t(`landing.footer.${section}.title`)}</h6>
<ul className="space-y-2 text-sm text-concrete font-light">
{[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 <li key={j}><a href={href} className="hover:text-ink">{label}</a></li>
})}
</ul>
</div>
))}
</div>
</div>
<div className="max-w-6xl mx-auto mt-20 pt-10 border-t border-border flex flex-col md:flex-row justify-between items-center gap-4 text-[10px] uppercase font-bold tracking-widest text-concrete">
<div>© 2026 MOMENTO LABS. ALL RIGHTS RESERVED.</div>
<div className="flex gap-8"><span>DESIGNED BY ANTIGRAVITY</span></div>
</div>
</footer>
</div>
)
}