CodeIssuesPull RequestsActionsSecurityInsights
✨ AI
More
Settings

Homepage redesign — modern clean SaaS, not retro #4019

Merged⚡ AI-generatedXSccantynz wants to mergeclaude/seo-pricing-pagesmainopened Mar 25, 2026
2 changed files+294−458
Modifiedapp/globals.css+51−106View fileUnifiedSplit
33@tailwind utilities;
44
55:root {
6 --hud-bg: rgba(10, 10, 14, 0.88);
7 --hud-border: rgba(255, 255, 255, 0.08);
8 --glow-cyan: #00f0ff;
9 --glow-red: #ff3b5c;
10 --glow-green: #00ff88;
11 --glow-amber: #ffb800;
6 --bg: #09090b;
7 --bg-subtle: #111113;
8 --border: rgba(255, 255, 255, 0.06);
9 --text-primary: rgba(255, 255, 255, 0.92);
10 --text-secondary: rgba(255, 255, 255, 0.55);
11 --text-muted: rgba(255, 255, 255, 0.3);
12 --text-faint: rgba(255, 255, 255, 0.12);
13 --accent: #6366f1; /* indigo — modern, not neon */
14 --accent-light: #818cf8;
15 --accent-glow: rgba(99, 102, 241, 0.15);
16 --success: #22c55e;
17 --danger: #ef4444;
18 --warning: #eab308;
1219}
1320
1421* {
1825}
1926
2027body {
21 background: #0a0a0e;
22 font-family: 'JetBrains Mono', monospace;
28 background: var(--bg);
29 font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', Roboto, sans-serif;
30 -webkit-font-smoothing: antialiased;
2331}
2432
25/* Glass panel */
26.glass {
27 background: var(--hud-bg);
28 backdrop-filter: blur(24px);
29 -webkit-backdrop-filter: blur(24px);
30 border: 1px solid var(--hud-border);
31}
32
33/* Status glow rings */
33/* ── Extension ring states ────────────────────────────────── */
3434.ring-idle { box-shadow: 0 0 0 2px rgba(255,255,255,0.15); }
35.ring-record { box-shadow: 0 0 0 2px var(--glow-red), 0 0 16px var(--glow-red); }
36.ring-process { box-shadow: 0 0 0 2px var(--glow-amber), 0 0 12px var(--glow-amber); }
37.ring-done { box-shadow: 0 0 0 2px var(--glow-green), 0 0 12px var(--glow-green); }
35.ring-record { box-shadow: 0 0 0 2px var(--danger), 0 0 16px var(--danger); animation: pulse_ring 1.2s ease-in-out infinite; }
36.ring-process { box-shadow: 0 0 0 2px var(--warning), 0 0 12px var(--warning); }
37.ring-done { box-shadow: 0 0 0 2px var(--success), 0 0 12px var(--success); }
3838
39/* Pulse animation for recording state */
4039@keyframes pulse_ring {
41 0%, 100% { box-shadow: 0 0 0 2px var(--glow-red), 0 0 16px var(--glow-red); }
42 50% { box-shadow: 0 0 0 4px var(--glow-red), 0 0 28px var(--glow-red); }
40 0%, 100% { box-shadow: 0 0 0 2px var(--danger), 0 0 16px var(--danger); }
41 50% { box-shadow: 0 0 0 4px var(--danger), 0 0 28px var(--danger); }
4342}
44.ring-record { animation: pulse_ring 1.2s ease-in-out infinite; }
4543
46/* Waveform bar animations — staggered durations for organic feel */
44/* ── Waveform bars ────────────────────────────────────────── */
4745@keyframes bar1 { 0%,100%{height:6px} 50%{height:22px} }
4846@keyframes bar2 { 0%,100%{height:10px} 50%{height:30px} }
4947@keyframes bar3 { 0%,100%{height:4px} 50%{height:26px} }
5048@keyframes bar4 { 0%,100%{height:14px} 50%{height:36px} }
5149@keyframes bar5 { 0%,100%{height:8px} 50%{height:20px} }
52
5350.bar1 { animation: bar1 0.7s ease-in-out infinite; }
5451.bar2 { animation: bar2 0.9s ease-in-out infinite 0.1s; }
5552.bar3 { animation: bar3 0.6s ease-in-out infinite 0.2s; }
5653.bar4 { animation: bar4 1.0s ease-in-out infinite 0.05s; }
5754.bar5 { animation: bar5 0.75s ease-in-out infinite 0.15s; }
5855
59/* ── Hero Animations ─────────────────────────────────────────── */
60
61@keyframes float {
62 0%, 100% { transform: translateY(0); }
63 50% { transform: translateY(-12px); }
64}
65
66@keyframes glow-pulse {
67 0%, 100% { opacity: 0.4; transform: scale(1); }
68 50% { opacity: 0.8; transform: scale(1.05); }
69}
70
71@keyframes typing-cursor {
72 0%, 50% { border-right-color: var(--glow-cyan); }
73 51%, 100% { border-right-color: transparent; }
74}
75
56/* ── Animations ───────────────────────────────────────────── */
7657@keyframes fade-up {
77 from { opacity: 0; transform: translateY(24px); }
58 from { opacity: 0; transform: translateY(20px); }
7859 to { opacity: 1; transform: translateY(0); }
7960}
8061
81@keyframes slide-in-left {
82 from { opacity: 0; transform: translateX(-32px); }
83 to { opacity: 1; transform: translateX(0); }
84}
85
86@keyframes slide-in-right {
87 from { opacity: 0; transform: translateX(32px); }
88 to { opacity: 1; transform: translateX(0); }
89}
90
91@keyframes gradient-shift {
92 0% { background-position: 0% 50%; }
93 50% { background-position: 100% 50%; }
94 100% { background-position: 0% 50%; }
95}
96
97@keyframes orbit {
98 from { transform: rotate(0deg) translateX(280px) rotate(0deg); }
99 to { transform: rotate(360deg) translateX(280px) rotate(-360deg); }
100}
101
102@keyframes scan-line {
103 0% { top: -2px; opacity: 0; }
104 10% { opacity: 0.6; }
105 90% { opacity: 0.6; }
106 100% { top: 100%; opacity: 0; }
62@keyframes typing-cursor {
63 0%, 50% { border-right-color: var(--accent); }
64 51%, 100% { border-right-color: transparent; }
10765}
10866
109.animate-float { animation: float 4s ease-in-out infinite; }
110.animate-glow-pulse { animation: glow-pulse 3s ease-in-out infinite; }
111.animate-typing-cursor { border-right: 2px solid var(--glow-cyan); animation: typing-cursor 1s step-end infinite; }
112.animate-fade-up { animation: fade-up 0.8s ease-out both; }
113.animate-gradient {
114 background-size: 200% 200%;
115 animation: gradient-shift 6s ease infinite;
116}
67.animate-fade-up { animation: fade-up 0.6s ease-out both; }
68.animate-typing-cursor { border-right: 2px solid var(--accent); animation: typing-cursor 1s step-end infinite; }
11769
118/* Scroll-triggered visibility */
70/* Scroll reveal */
11971.reveal {
12072 opacity: 0;
121 transform: translateY(32px);
122 transition: opacity 0.8s ease, transform 0.8s ease;
73 transform: translateY(24px);
74 transition: opacity 0.7s ease, transform 0.7s ease;
12375}
12476.reveal.visible {
12577 opacity: 1;
12678 transform: translateY(0);
12779}
12880
129/* Gradient border card */
130.gradient-border {
131 position: relative;
132 background: rgba(10, 10, 14, 0.94);
133 border: 1px solid transparent;
134 background-clip: padding-box;
81/* Card */
82.card {
83 background: var(--bg-subtle);
84 border: 1px solid var(--border);
85 border-radius: 16px;
13586}
136.gradient-border::before {
137 content: '';
138 position: absolute;
139 inset: -1px;
140 border-radius: inherit;
141 padding: 1px;
142 background: linear-gradient(135deg, rgba(0,240,255,0.2), rgba(0,255,136,0.1), rgba(255,59,92,0.1), rgba(0,240,255,0.2));
143 -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
144 -webkit-mask-composite: xor;
145 mask-composite: exclude;
146 pointer-events: none;
87.card:hover {
88 border-color: rgba(255, 255, 255, 0.1);
14789}
14890
149/* Subtle grid bg */
150.grid-bg {
151 background-image:
152 linear-gradient(rgba(0,240,255,0.03) 1px, transparent 1px),
153 linear-gradient(90deg, rgba(0,240,255,0.03) 1px, transparent 1px);
154 background-size: 60px 60px;
91/* Subtle gradient mesh (hero only) */
92.hero-gradient {
93 background:
94 radial-gradient(ellipse 80% 50% at 50% -20%, rgba(99, 102, 241, 0.12), transparent),
95 radial-gradient(ellipse 60% 40% at 80% 60%, rgba(34, 197, 94, 0.06), transparent),
96 var(--bg);
15597}
15698
157/* Scrollbar hidden */
158::-webkit-scrollbar { display: none; }
99/* Clean scrollbar */
100::-webkit-scrollbar { width: 6px; }
101::-webkit-scrollbar-track { background: transparent; }
102::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 3px; }
103::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.15); }
Modifiedapp/page.jsx+243−352View fileUnifiedSplit
11'use client'
22
3import { useState, useRef, useEffect, useCallback } from 'react'
3import { useState, useRef, useEffect } from 'react'
44import Waveform from '../components/Waveform'
55
6// ── Typing simulator for hero ────────────────────────────────
6// ── Typing demo ──────────────────────────────────────────
77function useTypingDemo() {
88 const phrases = [
9 { spoken: 'Hey Claude comma can you refactor this function to use async await question mark', typed: 'Hey Claude, can you refactor this function to use async/await?' },
10 { spoken: 'Send an email to the team new line we ship tomorrow exclamation point', typed: 'Send an email to the team\nWe ship tomorrow!' },
11 { spoken: 'Create a React component called dashboard with a dark theme', typed: 'Create a React component called Dashboard with a dark theme' },
12 { spoken: 'The meeting is at 3 PM period Please send the agenda beforehand period', typed: 'The meeting is at 3 PM. Please send the agenda beforehand.' },
9 {
10 before: 'uh so like I think we should maybe redo the the dashboard because users are confused',
11 after: 'I recommend redesigning the dashboard to improve user clarity and navigation.',
12 label: 'AI Rewrite',
13 },
14 {
15 before: 'Hey Claude comma can you refactor this function to use async await question mark',
16 after: 'Hey Claude, can you refactor this function to use async/await?',
17 label: 'Voice Punctuation',
18 },
19 {
20 before: 'send an email to the team new line we ship tomorrow exclamation point',
21 after: 'Send an email to the team\nWe ship tomorrow!',
22 label: 'Natural Commands',
23 },
1324 ]
1425
15 const [phraseIdx, setPhraseIdx] = useState(0)
26 const [idx, setIdx] = useState(0)
1627 const [charIdx, setCharIdx] = useState(0)
17 const [isTyping, setIsTyping] = useState(true)
18 const [paused, setPaused] = useState(false)
28 const [phase, setPhase] = useState('typing') // typing | pause | next
1929
20 const phrase = phrases[phraseIdx]
30 const phrase = phrases[idx]
2131
2232 useEffect(() => {
23 if (paused) return
24
25 if (isTyping && charIdx < phrase.typed.length) {
26 const timeout = setTimeout(() => setCharIdx(c => c + 1), 35 + Math.random() * 25)
27 return () => clearTimeout(timeout)
33 if (phase === 'typing' && charIdx < phrase.after.length) {
34 const t = setTimeout(() => setCharIdx(c => c + 1), 30 + Math.random() * 20)
35 return () => clearTimeout(t)
2836 }
29
30 if (isTyping && charIdx >= phrase.typed.length) {
31 setIsTyping(false)
32 const timeout = setTimeout(() => {
33 setPaused(true)
37 if (phase === 'typing' && charIdx >= phrase.after.length) {
38 setPhase('pause')
39 const t = setTimeout(() => {
40 setPhase('next')
3441 setTimeout(() => {
35 setPhraseIdx(i => (i + 1) % phrases.length)
42 setIdx(i => (i + 1) % phrases.length)
3643 setCharIdx(0)
37 setIsTyping(true)
38 setPaused(false)
39 }, 1200)
40 }, 2000)
41 return () => clearTimeout(timeout)
44 setPhase('typing')
45 }, 400)
46 }, 2500)
47 return () => clearTimeout(t)
4248 }
43 }, [charIdx, isTyping, paused, phrase.typed.length, phraseIdx, phrases.length])
49 }, [charIdx, phase, phrase.after.length, idx, phrases.length])
4450
4551 return {
46 spoken: phrase.spoken,
47 typed: phrase.typed.slice(0, charIdx),
48 isTyping: isTyping && charIdx < phrase.typed.length,
49 progress: charIdx / phrase.typed.length,
52 before: phrase.before,
53 after: phrase.after.slice(0, charIdx),
54 label: phrase.label,
55 isTyping: phase === 'typing' && charIdx < phrase.after.length,
5056 }
5157}
5258
53// ── Scroll reveal hook ───────────────────────────────────────
59// ── Scroll reveal ────────────────────────────────────────
5460function useReveal() {
5561 const ref = useRef(null)
5662 useEffect(() => {
5864 if (!el) return
5965 const observer = new IntersectionObserver(
6066 ([entry]) => { if (entry.isIntersecting) el.classList.add('visible') },
61 { threshold: 0.15 }
67 { threshold: 0.1 }
6268 )
6369 observer.observe(el)
6470 return () => observer.disconnect()
6672 return ref
6773}
6874
69// ── Stats counter ────────────────────────────────────────────
70function AnimatedNumber({ target, suffix = '', duration = 2000 }) {
71 const [value, setValue] = useState(0)
72 const ref = useRef(null)
73
74 useEffect(() => {
75 const el = ref.current
76 if (!el) return
77 const observer = new IntersectionObserver(([entry]) => {
78 if (entry.isIntersecting) {
79 const start = performance.now()
80 const animate = (now) => {
81 const elapsed = now - start
82 const progress = Math.min(elapsed / duration, 1)
83 const eased = 1 - Math.pow(1 - progress, 3)
84 setValue(Math.round(target * eased))
85 if (progress < 1) requestAnimationFrame(animate)
86 }
87 requestAnimationFrame(animate)
88 observer.disconnect()
89 }
90 }, { threshold: 0.5 })
91 observer.observe(el)
92 return () => observer.disconnect()
93 }, [target, duration])
94
95 return <span ref={ref}>{value}{suffix}</span>
96}
97
98const FEATURES = [
99 { icon: '\u{26A1}', title: 'Types Automatically', desc: 'Text appears directly in the focused field. No copy-paste. No clipboard. Just speak and it types.', color: '#00ff88' },
100 { icon: '\u{1F3AF}', title: 'Whisper Accuracy', desc: 'Desktop app uses OpenAI Whisper for near-perfect transcription. Web tools use free browser speech API.', color: '#00f0ff' },
101 { icon: '\u{2328}\u{FE0F}', title: 'Global Hotkey', desc: 'Ctrl+Shift+Space from anywhere. Works system-wide in the desktop app, per-page in browser.', color: '#00f0ff' },
102 { icon: '\u{1F399}\u{FE0F}', title: 'Voice Commands', desc: 'Say punctuation naturally. Developer prompts like \u201Crefactor this\u201D. Emoji by voice.', color: '#ff3b5c' },
103 { icon: '\u{27E8}/\u{27E9}', title: 'Auto Code Fences', desc: 'Detects coding keywords and wraps in markdown fences with language detection.', color: '#ffb800' },
104 { icon: '\u{1F6E1}\u{FE0F}', title: 'Privacy First', desc: 'Audio goes direct to the speech API. Nothing stored on our servers. Your key, your data.', color: '#00f0ff' },
105]
106
107const COMPETITORS = [
108 { name: 'WhisperTyping', type: 'Desktop', price: '$5/mo', anyApp: true, codeFence: false, voiceCmd: false, free: false },
109 { name: 'Wispr Flow', type: 'Desktop', price: '$15/mo', anyApp: true, codeFence: false, voiceCmd: false, free: false },
110 { name: 'Voicy', type: 'Extension', price: '$8.49/mo', anyApp: false, codeFence: false, voiceCmd: false, free: false },
111 { name: 'Superwhisper', type: 'Mac Only', price: '$8.49/mo', anyApp: true, codeFence: false, voiceCmd: false, free: false },
112 { name: '48co', type: 'All 3', price: 'Free*', anyApp: true, codeFence: true, voiceCmd: true, free: true },
113]
114
11575export default function LandingPage() {
76 const typing = useTypingDemo()
11677 const [demoStatus, setDemoStatus] = useState('idle')
11778 const [demoTranscript, setDemoTranscript] = useState('')
11879 const recognitionRef = useRef(null)
119 const typing = useTypingDemo()
12080
12181 const r1 = useReveal()
12282 const r2 = useReveal()
12383 const r3 = useReveal()
12484 const r4 = useReveal()
125 const r5 = useReveal()
126 const r6 = useReveal()
12785
12886 useEffect(() => {
12987 return () => { if (recognitionRef.current) { recognitionRef.current.abort(); recognitionRef.current = null } }
13593 return
13694 }
13795 const SR = typeof window !== 'undefined' && (window.SpeechRecognition || window.webkitSpeechRecognition)
138 if (!SR) {
139 setDemoTranscript('Speech Recognition requires Chrome or Edge.')
140 setDemoStatus('done')
141 setTimeout(() => setDemoStatus('idle'), 3000)
142 return
143 }
96 if (!SR) { setDemoTranscript('Requires Chrome or Edge.'); setDemoStatus('done'); setTimeout(() => setDemoStatus('idle'), 3000); return }
14497 const rec = new SR()
145 rec.continuous = true
146 rec.interimResults = true
147 rec.lang = 'en'
98 rec.continuous = true; rec.interimResults = true; rec.lang = 'en'
14899 rec.onstart = () => { setDemoStatus('recording'); setDemoTranscript('') }
149100 rec.onresult = (e) => { let f = ''; for (let i = 0; i < e.results.length; i++) f += e.results[i][0].transcript; setDemoTranscript(f) }
150101 rec.onend = () => { setDemoStatus('done'); setTimeout(() => setDemoStatus('idle'), 2500) }
151102 rec.onerror = (e) => {
152103 if (e.error === 'not-allowed') setDemoTranscript('Microphone access denied.')
153 else if (e.error === 'no-speech') setDemoTranscript('No speech detected. Try again.')
154 setDemoStatus('done')
155 setTimeout(() => setDemoStatus('idle'), 3000)
104 else if (e.error === 'no-speech') setDemoTranscript('No speech detected.')
105 setDemoStatus('done'); setTimeout(() => setDemoStatus('idle'), 3000)
156106 }
157 recognitionRef.current = rec
158 rec.start()
107 recognitionRef.current = rec; rec.start()
159108 }
160109
161110 return (
162 <main className="min-h-screen bg-[#0a0a0e] text-white font-mono overflow-x-hidden">
163
164 {/* ── HERO ─────────────────────────────────────────────────── */}
165 <section className="relative min-h-screen flex flex-col items-center justify-center px-4 text-center grid-bg">
166 {/* Animated glow orbs */}
167 <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[800px] h-[800px] pointer-events-none">
168 <div className="absolute inset-0 bg-[#00f0ff]/[0.04] rounded-full blur-[150px] animate-glow-pulse" />
169 <div className="absolute top-20 -left-20 w-[300px] h-[300px] bg-[#ff3b5c]/[0.03] rounded-full blur-[100px] animate-glow-pulse" style={{ animationDelay: '1s' }} />
170 <div className="absolute -bottom-10 -right-10 w-[250px] h-[250px] bg-[#00ff88]/[0.03] rounded-full blur-[100px] animate-glow-pulse" style={{ animationDelay: '2s' }} />
171 </div>
111 <main className="min-h-screen bg-[#09090b] text-white overflow-x-hidden">
172112
173 {/* Floating orbit dots */}
174 <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-0 h-0 pointer-events-none">
175 <div className="absolute w-1.5 h-1.5 rounded-full bg-[#00f0ff]/30" style={{ animation: 'orbit 20s linear infinite' }} />
176 <div className="absolute w-1 h-1 rounded-full bg-[#ff3b5c]/20" style={{ animation: 'orbit 28s linear infinite reverse' }} />
177 <div className="absolute w-1 h-1 rounded-full bg-[#00ff88]/20" style={{ animation: 'orbit 35s linear infinite', animationDelay: '-10s' }} />
113 {/* ── NAV ───────────────────────────────────────────── */}
114 <nav className="fixed top-0 w-full z-50 bg-[#09090b]/80 backdrop-blur-xl border-b border-white/[0.04]">
115 <div className="max-w-6xl mx-auto flex items-center justify-between px-6 py-3">
116 <a href="/" className="text-base font-semibold tracking-tight">
117 <span className="text-white/90">48</span><span className="text-indigo-400">co</span>
118 </a>
119 <div className="flex items-center gap-6">
120 <a href="/compare" className="text-[13px] text-white/40 hover:text-white/70 transition-colors">Compare</a>
121 <a href="/pricing" className="text-[13px] text-white/40 hover:text-white/70 transition-colors">Pricing</a>
122 <a href="/live" className="text-[13px] text-white/40 hover:text-white/70 transition-colors">Try Live</a>
123 <a href="/download" className="text-[13px] px-4 py-1.5 rounded-lg bg-indigo-500/10 border border-indigo-500/20 text-indigo-400 hover:bg-indigo-500/20 transition-all">
124 Download
125 </a>
126 </div>
178127 </div>
128 </nav>
129
130 {/* ── HERO ──────────────────────────────────────────── */}
131 <section className="hero-gradient pt-32 pb-24 px-4">
132 <div className="max-w-3xl mx-auto text-center">
133 <div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-indigo-500/10 border border-indigo-500/15 mb-8 animate-fade-up">
134 <span className="w-1.5 h-1.5 rounded-full bg-green-400"></span>
135 <span className="text-[12px] text-indigo-300/70">Now with AI Rewrite Mode</span>
136 </div>
179137
180 <div className="relative z-10 max-w-4xl mx-auto">
181 <p className="text-[11px] tracking-[0.4em] text-[#00f0ff]/50 mb-6 uppercase animate-fade-up">
182 Voice-to-text for everything
183 </p>
184
185 <h1 className="text-6xl md:text-8xl lg:text-9xl font-bold tracking-tighter mb-6 animate-fade-up" style={{ animationDelay: '0.1s' }}>
186 <span className="text-white">48</span>
187 <span className="bg-gradient-to-r from-[#00f0ff] to-[#00ff88] bg-clip-text text-transparent">co</span>
138 <h1 className="text-5xl md:text-7xl font-bold tracking-tight mb-6 animate-fade-up" style={{ animationDelay: '0.1s' }}>
139 Speak naturally.
140 <br />
141 <span className="bg-gradient-to-r from-indigo-400 to-emerald-400 bg-clip-text text-transparent">Get perfect text.</span>
188142 </h1>
189143
190 <p className="text-white/30 text-base md:text-lg max-w-xl mx-auto leading-relaxed mb-12 animate-fade-up" style={{ animationDelay: '0.2s' }}>
191 Speak and it types. Into any app, any website, any text field. Free and open source.
144 <p className="text-lg text-white/45 max-w-xl mx-auto leading-relaxed mb-10 animate-fade-up" style={{ animationDelay: '0.2s' }}>
145 Voice-to-text that types into any app. AI polishes your words automatically. Works on Mac and Windows.
192146 </p>
193147
194 {/* ── Typing Demo ─────────────────────────────────────── */}
195 <div className="animate-fade-up" style={{ animationDelay: '0.3s' }}>
196 <div className="glass gradient-border rounded-2xl w-full max-w-[540px] mx-auto overflow-hidden mb-10 animate-float" style={{ animationDuration: '6s' }}>
197 {/* Header bar */}
148 <div className="flex flex-col sm:flex-row gap-3 justify-center mb-16 animate-fade-up" style={{ animationDelay: '0.3s' }}>
149 <a href="/download" className="px-8 py-3 rounded-xl bg-indigo-500 hover:bg-indigo-400 text-white text-sm font-medium transition-all">
150 Download Free
151 </a>
152 <a href="/live" className="px-8 py-3 rounded-xl border border-white/10 text-white/50 text-sm font-medium hover:border-white/20 hover:text-white/70 transition-all">
153 Try in Browser
154 </a>
155 </div>
156
157 {/* ── Demo Card ──────────────────────────────── */}
158 <div className="max-w-lg mx-auto animate-fade-up" style={{ animationDelay: '0.4s' }}>
159 <div className="card overflow-hidden">
198160 <div className="flex items-center justify-between px-5 py-3 border-b border-white/[0.04]">
199161 <div className="flex items-center gap-2">
200162 <div className="flex gap-1.5">
201 <div className="w-2.5 h-2.5 rounded-full bg-[#ff3b5c]/60" />
202 <div className="w-2.5 h-2.5 rounded-full bg-[#ffb800]/60" />
203 <div className="w-2.5 h-2.5 rounded-full bg-[#00ff88]/60" />
163 <div className="w-2 h-2 rounded-full bg-white/10" />
164 <div className="w-2 h-2 rounded-full bg-white/10" />
165 <div className="w-2 h-2 rounded-full bg-white/10" />
204166 </div>
205 <span className="text-[10px] text-white/20 ml-2">Any App</span>
206 </div>
207 <div className="flex items-center gap-2">
208 <span className={`inline-block w-1.5 h-1.5 rounded-full ${typing.isTyping ? 'bg-[#ff3b5c] shadow-[0_0_6px_rgba(255,59,92,0.6)]' : 'bg-[#00ff88] shadow-[0_0_6px_rgba(0,255,136,0.4)]'}`} />
209 <span className="text-[9px] text-white/25">{typing.isTyping ? 'LISTENING' : 'DONE'}</span>
167 <span className="text-[11px] text-white/20 ml-2 font-mono">{typing.label}</span>
210168 </div>
169 <span className={`w-2 h-2 rounded-full ${typing.isTyping ? 'bg-red-400 shadow-[0_0_6px_rgba(239,68,68,0.5)]' : 'bg-green-400'}`} />
211170 </div>
212171
213 {/* Waveform */}
214 <div className="py-3 border-b border-white/[0.04]">
215 <Waveform isRecording={typing.isTyping} />
216 </div>
217
218 {/* Spoken text (faded) */}
219172 <div className="px-5 py-3 border-b border-white/[0.04]">
220 <p className="text-[9px] text-white/15 tracking-wider mb-1">YOU SAID</p>
221 <p className="text-[11px] text-white/25 leading-relaxed">{typing.spoken}</p>
173 <p className="text-[10px] text-white/20 uppercase tracking-wider mb-1">You said</p>
174 <p className="text-[13px] text-white/25 leading-relaxed">{typing.before}</p>
222175 </div>
223176
224 {/* Typed result */}
225 <div className="px-5 py-4 bg-[#00f0ff]/[0.02]">
226 <p className="text-[9px] text-[#00f0ff]/30 tracking-wider mb-1">48CO TYPES</p>
227 <p className={`text-[13px] text-white/70 leading-relaxed whitespace-pre-wrap min-h-[40px] ${typing.isTyping ? 'animate-typing-cursor pr-0.5' : ''}`}>
228 {typing.typed || <span className="text-white/10">|</span>}
177 <div className="px-5 py-4 bg-indigo-500/[0.03]">
178 <p className="text-[10px] text-indigo-400/40 uppercase tracking-wider mb-1">48co types</p>
179 <p className={`text-[14px] text-white/75 leading-relaxed whitespace-pre-wrap min-h-[44px] ${typing.isTyping ? 'animate-typing-cursor pr-0.5' : ''}`}>
180 {typing.after || <span className="text-white/10">|</span>}
229181 </p>
230182 </div>
231
232 {/* Progress bar */}
233 <div className="h-[2px] bg-white/[0.03]">
234 <div
235 className="h-full bg-gradient-to-r from-[#00f0ff] to-[#00ff88] transition-all duration-100"
236 style={{ width: `${typing.progress * 100}%` }}
237 />
238 </div>
239183 </div>
240184 </div>
241185
242 {/* CTAs */}
243 <div className="flex flex-col sm:flex-row gap-3 justify-center mb-6 animate-fade-up" style={{ animationDelay: '0.4s' }}>
244 <a href="/download" className="group relative px-8 py-3.5 rounded-xl text-sm tracking-wider transition-all overflow-hidden">
245 <div className="absolute inset-0 bg-gradient-to-r from-[#00f0ff]/20 to-[#00ff88]/10 group-hover:from-[#00f0ff]/30 group-hover:to-[#00ff88]/20 transition-all" />
246 <div className="absolute inset-0 border border-[#00f0ff]/30 group-hover:border-[#00f0ff]/50 rounded-xl transition-all" />
247 <span className="relative text-[#00f0ff]">DOWNLOAD FOR FREE</span>
248 </a>
249 <a href="/live" className="px-8 py-3.5 rounded-xl border border-white/10 text-white/40 text-sm tracking-wider hover:border-white/20 hover:text-white/60 transition-all">
250 TRY IN BROWSER
251 </a>
252 </div>
253
254 <p className="text-[10px] text-white/10 animate-fade-up" style={{ animationDelay: '0.5s' }}>
255 Windows + Mac + Web &middot; No account needed &middot; Open source
186 <p className="text-[11px] text-white/15 mt-6 animate-fade-up" style={{ animationDelay: '0.5s' }}>
187 Mac + Windows &middot; Free tier available &middot; No account required
256188 </p>
257189 </div>
258
259 {/* Scroll indicator */}
260 <div className="absolute bottom-8 left-1/2 -translate-x-1/2 flex flex-col items-center gap-2 animate-fade-up" style={{ animationDelay: '1s' }}>
261 <span className="text-[9px] text-white/15 tracking-wider">SCROLL</span>
262 <div className="w-[1px] h-8 bg-gradient-to-b from-white/15 to-transparent" />
263 </div>
264190 </section>
265191
266 {/* ── STATS BAR ────────────────────────────────────────────── */}
267 <section ref={r1} className="reveal border-y border-white/[0.04] py-12 bg-[#0a0a0e]">
268 <div className="max-w-5xl mx-auto px-4 grid grid-cols-2 md:grid-cols-4 gap-8 text-center">
269 {[
270 { n: 50, s: '+', label: 'Languages' },
271 { n: 3, s: '', label: 'Delivery Modes' },
272 { n: 40, s: '+', label: 'Voice Commands' },
273 { n: 0, s: '', label: 'Monthly Cost', prefix: '$' },
274 ].map((stat, i) => (
275 <div key={stat.label}>
276 <p className="text-3xl md:text-4xl font-bold text-white/90 mb-1">
277 {stat.prefix || ''}<AnimatedNumber target={stat.n} suffix={stat.s} />
278 </p>
279 <p className="text-[10px] text-white/25 tracking-wider uppercase">{stat.label}</p>
280 </div>
281 ))}
192 {/* ── HOW IT WORKS ─────────────────────────────────── */}
193 <section ref={r1} className="reveal py-24 px-4">
194 <div className="max-w-5xl mx-auto">
195 <div className="text-center mb-16">
196 <h2 className="text-3xl font-bold text-white/90 mb-3">How it works</h2>
197 <p className="text-sm text-white/35">Three steps. No configuration.</p>
198 </div>
199
200 <div className="grid md:grid-cols-3 gap-6">
201 {[
202 { step: '1', title: 'Press the hotkey', desc: 'Ctrl+Shift+Space (Cmd on Mac). Works from any app — browser, Slack, email, code editor, anything.' },
203 { step: '2', title: 'Speak naturally', desc: 'Talk like you normally would. Say punctuation out loud or let AI figure it out. Supports 50+ languages.' },
204 { step: '3', title: 'Text appears instantly', desc: 'AI rewrites your words into clean, professional text and types it directly into the focused field.' },
205 ].map((s) => (
206 <div key={s.step} className="card p-6">
207 <div className="w-8 h-8 rounded-lg bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center text-indigo-400 text-sm font-semibold mb-4">
208 {s.step}
209 </div>
210 <h3 className="text-[15px] font-semibold text-white/85 mb-2">{s.title}</h3>
211 <p className="text-[13px] text-white/35 leading-relaxed">{s.desc}</p>
212 </div>
213 ))}
214 </div>
282215 </div>
283216 </section>
284217
285 {/* ── HOW IT WORKS ─────────────────────────────────────────── */}
286 <section ref={r2} className="reveal max-w-5xl mx-auto px-4 py-28">
287 <div className="text-center mb-16">
288 <p className="text-[10px] tracking-[0.4em] text-[#00ff88]/40 mb-3 uppercase">How it works</p>
289 <h2 className="text-3xl md:text-4xl font-bold text-white/90">Three ways to use 48co</h2>
290 </div>
218 {/* ── KEY FEATURES ──────────────────────────────────── */}
219 <section ref={r2} className="reveal py-24 px-4 bg-[#0c0c0f]">
220 <div className="max-w-5xl mx-auto">
221 <div className="text-center mb-16">
222 <h2 className="text-3xl font-bold text-white/90 mb-3">What makes 48co different</h2>
223 <p className="text-sm text-white/35">Features no other dictation tool has.</p>
224 </div>
291225
292 <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
293 {[
294 {
295 num: '01',
296 title: 'Desktop App',
297 desc: 'Download for Windows or Mac. Lives in your system tray. Press the hotkey, speak, and text appears in whatever app you\u2019re using \u2014 browsers, Slack, VS Code, email, anything.',
298 badge: 'Best experience',
299 badgeColor: 'text-[#00ff88] border-[#00ff88]/30 bg-[#00ff88]/5',
300 accent: '#00f0ff',
301 href: '/download',
302 },
303 {
304 num: '02',
305 title: 'Web Bookmarklet',
306 desc: 'Zero download. Visit the live page, drag a bookmark, and click it on any website. Injects a voice widget that types directly into text fields.',
307 badge: 'Zero friction',
308 badgeColor: 'text-white/40 border-white/10 bg-white/[0.03]',
309 accent: '#ffb800',
310 href: '/live',
311 },
312 {
313 num: '03',
314 title: 'Chrome Extension',
315 desc: 'Always-on voice widget with developer commands. Optimized for AI chat sites: Claude, ChatGPT, Gemini, DeepSeek. Works on other sites too.',
316 badge: 'Power users',
317 badgeColor: 'text-white/40 border-white/10 bg-white/[0.03]',
318 accent: '#ff3b5c',
319 href: '/install',
320 },
321 ].map((mode) => (
322 <a key={mode.num} href={mode.href} className="group glass rounded-2xl p-6 hover:border-white/15 transition-all relative overflow-hidden">
323 <div className="absolute top-0 left-0 w-full h-[2px] bg-gradient-to-r opacity-0 group-hover:opacity-100 transition-opacity" style={{ backgroundImage: `linear-gradient(to right, ${mode.accent}, transparent)` }} />
324 <div className="flex items-center justify-between mb-4">
325 <span className="text-[32px] font-bold text-white/[0.04]">{mode.num}</span>
326 <span className={`text-[9px] px-2 py-0.5 rounded border ${mode.badgeColor}`}>{mode.badge}</span>
327 </div>
328 <h3 className="text-lg font-bold text-white/80 mb-3" style={{ color: mode.accent + 'cc' }}>{mode.title}</h3>
329 <p className="text-[11px] text-white/35 leading-relaxed">{mode.desc}</p>
330 <div className="mt-4 flex items-center gap-1 text-[10px] text-white/20 group-hover:text-white/40 transition-colors">
331 <span>Learn more</span>
332 <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
226 <div className="grid md:grid-cols-2 gap-5">
227 {[
228 {
229 title: 'AI Rewrite Mode',
230 desc: 'You ramble, it writes professionally. Claude AI removes filler words, fixes grammar, and adjusts tone automatically. No other dictation tool does this.',
231 tag: 'Exclusive',
232 tagColor: 'text-indigo-400 bg-indigo-500/10 border-indigo-500/20',
233 },
234 {
235 title: 'Context-Aware',
236 desc: 'Automatically detects which app you\'re in. Professional tone for email, casual for Slack, technical for code editors. Zero configuration.',
237 tag: 'Exclusive',
238 tagColor: 'text-indigo-400 bg-indigo-500/10 border-indigo-500/20',
239 },
240 {
241 title: 'Works Everywhere',
242 desc: 'Types into any focused text field on your computer. Browsers, Slack, Discord, VS Code, Word, email — anything. Not limited to the browser.',
243 tag: 'Desktop',
244 tagColor: 'text-emerald-400 bg-emerald-500/10 border-emerald-500/20',
245 },
246 {
247 title: 'Privacy First',
248 desc: 'Offline mode coming soon with local Whisper. Your voice never has to leave your computer. No data stored on our servers.',
249 tag: 'Local-first',
250 tagColor: 'text-emerald-400 bg-emerald-500/10 border-emerald-500/20',
251 },
252 {
253 title: 'Auto Code Detection',
254 desc: 'Detects coding keywords and wraps in markdown fences with language detection. Perfect for ChatGPT, Claude, and GitHub.',
255 tag: 'Developers',
256 tagColor: 'text-amber-400 bg-amber-500/10 border-amber-500/20',
257 },
258 {
259 title: '50+ Languages',
260 desc: 'Powered by OpenAI Whisper for near-perfect accuracy in over 50 languages. English, Spanish, French, German, Japanese, and many more.',
261 tag: 'Global',
262 tagColor: 'text-white/40 bg-white/5 border-white/10',
263 },
264 ].map((f) => (
265 <div key={f.title} className="card p-6 transition-all">
266 <div className="flex items-center justify-between mb-3">
267 <h3 className="text-[15px] font-semibold text-white/85">{f.title}</h3>
268 <span className={`text-[10px] px-2 py-0.5 rounded-full border ${f.tagColor}`}>{f.tag}</span>
269 </div>
270 <p className="text-[13px] text-white/35 leading-relaxed">{f.desc}</p>
333271 </div>
334 </a>
335 ))}
272 ))}
273 </div>
336274 </div>
337275 </section>
338276
339 {/* ── LIVE DEMO ────────────────────────────────────────────── */}
340 <section ref={r3} className="reveal py-28 bg-gradient-to-b from-transparent via-[#00f0ff]/[0.02] to-transparent">
341 <div className="max-w-2xl mx-auto px-4 text-center">
342 <p className="text-[10px] tracking-[0.4em] text-[#00f0ff]/40 mb-3 uppercase">Try it now</p>
343 <h2 className="text-3xl md:text-4xl font-bold text-white/90 mb-4">Live Demo</h2>
344 <p className="text-[12px] text-white/30 mb-10 max-w-md mx-auto">Click the microphone, speak, and see your words appear. This runs entirely in your browser &mdash; no download needed.</p>
277 {/* ── LIVE DEMO ─────────────────────────────────────── */}
278 <section ref={r3} className="reveal py-24 px-4">
279 <div className="max-w-lg mx-auto text-center">
280 <h2 className="text-3xl font-bold text-white/90 mb-3">Try it now</h2>
281 <p className="text-sm text-white/35 mb-10">Click the mic, speak, see your words. Runs in your browser — no download needed.</p>
345282
346 <div className="glass gradient-border rounded-2xl max-w-md mx-auto overflow-hidden">
283 <div className="card overflow-hidden">
347284 <div className="flex items-center justify-between px-5 py-3 border-b border-white/[0.04]">
348 <span className="text-[11px] font-bold tracking-[0.2em] text-white/50">&equiv; 48CO</span>
349 <span className={`text-[9px] px-2 py-0.5 rounded border transition-all ${
350 demoStatus === 'recording' ? 'border-[#ff3b5c]/40 text-[#ff3b5c] bg-[#ff3b5c]/10' :
351 demoStatus === 'done' ? 'border-[#00ff88]/40 text-[#00ff88] bg-[#00ff88]/10' :
285 <span className="text-[12px] font-medium text-white/40">Live Demo</span>
286 <span className={`text-[10px] px-2 py-0.5 rounded-full border transition-all ${
287 demoStatus === 'recording' ? 'border-red-500/30 text-red-400 bg-red-500/10' :
288 demoStatus === 'done' ? 'border-green-500/30 text-green-400 bg-green-500/10' :
352289 'border-white/10 text-white/25'
353290 }`}>
354 {demoStatus === 'recording' ? 'LISTENING' : demoStatus === 'done' ? 'DONE' : 'LIVE DEMO'}
291 {demoStatus === 'recording' ? 'Listening' : demoStatus === 'done' ? 'Done' : 'Ready'}
355292 </span>
356293 </div>
357294
360297 </div>
361298
362299 {demoTranscript && (
363 <div className="px-5 py-3 border-b border-white/[0.04] bg-white/[0.01]">
364 <p className="text-[11px] text-white/50 leading-relaxed">{demoTranscript}</p>
300 <div className="px-5 py-3 border-b border-white/[0.04]">
301 <p className="text-[13px] text-white/50 leading-relaxed">{demoTranscript}</p>
365302 </div>
366303 )}
367304
368305 <div className="py-8 flex flex-col items-center gap-3">
369306 <button
370307 onClick={handleDemoClick}
371 className={`w-16 h-16 rounded-full glass flex items-center justify-center transition-all duration-300 cursor-pointer ${
372 demoStatus === 'recording' ? 'ring-2 ring-[#ff3b5c] shadow-[0_0_24px_rgba(255,59,92,0.4)]' :
373 demoStatus === 'done' ? 'ring-2 ring-[#00ff88] shadow-[0_0_20px_rgba(0,255,136,0.3)]' :
374 'ring-2 ring-white/15 hover:ring-white/25 hover:shadow-[0_0_20px_rgba(0,240,255,0.15)]'
308 className={`w-14 h-14 rounded-full flex items-center justify-center transition-all cursor-pointer border-2 ${
309 demoStatus === 'recording' ? 'border-red-500 bg-red-500/10 shadow-[0_0_20px_rgba(239,68,68,0.3)]' :
310 demoStatus === 'done' ? 'border-green-500 bg-green-500/10' :
311 'border-white/15 bg-white/[0.03] hover:border-white/25'
375312 }`}
376313 >
377314 {demoStatus === 'recording' ? (
378 <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#ff3b5c" strokeWidth="1.5"><path d="M2 12h2M6 8v8M10 5v14M14 9v6M18 7v10M22 12h-2"/></svg>
315 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ef4444" strokeWidth="1.5"><path d="M2 12h2M6 8v8M10 5v14M14 9v6M18 7v10M22 12h-2"/></svg>
379316 ) : demoStatus === 'done' ? (
380 <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#00ff88" strokeWidth="2"><path d="M5 13l4 4L19 7" strokeLinecap="round" strokeLinejoin="round"/></svg>
317 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#22c55e" strokeWidth="2"><path d="M5 13l4 4L19 7" strokeLinecap="round" strokeLinejoin="round"/></svg>
381318 ) : (
382 <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,0.5)" strokeWidth="1.5"><rect x="9" y="2" width="6" height="11" rx="3"/><path d="M5 10a7 7 0 0014 0"/><line x1="12" y1="21" x2="12" y2="17"/><line x1="9" y1="21" x2="15" y2="21"/></svg>
319 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,0.4)" strokeWidth="1.5"><rect x="9" y="2" width="6" height="11" rx="3"/><path d="M5 10a7 7 0 0014 0"/><line x1="12" y1="21" x2="12" y2="17"/><line x1="9" y1="21" x2="15" y2="21"/></svg>
383320 )}
384321 </button>
385 <span className={`text-[11px] tracking-wider ${
386 demoStatus === 'recording' ? 'text-[#ff3b5c]' : demoStatus === 'done' ? 'text-[#00ff88]' : 'text-white/25'
322 <span className={`text-[12px] ${
323 demoStatus === 'recording' ? 'text-red-400' : demoStatus === 'done' ? 'text-green-400' : 'text-white/25'
387324 }`}>
388325 {demoStatus === 'recording' ? 'Click to stop' : demoStatus === 'done' ? 'Done' : 'Click to try'}
389326 </span>
392329 </div>
393330 </section>
394331
395 {/* ── FEATURES ─────────────────────────────────────────────── */}
396 <section ref={r4} className="reveal max-w-5xl mx-auto px-4 py-28">
397 <div className="text-center mb-16">
398 <p className="text-[10px] tracking-[0.4em] text-[#00f0ff]/40 mb-3 uppercase">Features</p>
399 <h2 className="text-3xl md:text-4xl font-bold text-white/90">Everything you need</h2>
400 </div>
332 {/* ── PRICING TEASER ─────────────────────────────────── */}
333 <section ref={r4} className="reveal py-24 px-4 bg-[#0c0c0f]">
334 <div className="max-w-3xl mx-auto text-center">
335 <h2 className="text-3xl font-bold text-white/90 mb-3">Simple pricing</h2>
336 <p className="text-sm text-white/35 mb-10">Free tier to get started. Pro when you need AI rewrite.</p>
401337
402 <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
403 {FEATURES.map((f, i) => (
404 <div key={f.title} className="glass rounded-2xl p-6 hover:border-white/10 transition-all group">
405 <div className="flex items-center gap-3 mb-3">
406 <span className="text-2xl">{f.icon}</span>
407 <div className="h-[1px] flex-1 bg-gradient-to-r from-white/[0.06] to-transparent" />
338 <div className="grid md:grid-cols-3 gap-4 mb-10">
339 {[
340 { name: 'Free', price: '$0', desc: 'Basic dictation, 60 min/mo', highlight: false },
341 { name: 'Pro', price: '$12/mo', desc: 'Unlimited + AI Rewrite + Offline', highlight: true },
342 { name: 'Lifetime', price: '$89', desc: 'Pro features forever. Limited.', highlight: false },
343 ].map((p) => (
344 <div key={p.name} className={`card p-6 ${p.highlight ? 'border-indigo-500/30 bg-indigo-500/[0.03]' : ''}`}>
345 <p className="text-sm font-semibold text-white/70 mb-1">{p.name}</p>
346 <p className="text-2xl font-bold text-white/90 mb-2">{p.price}</p>
347 <p className="text-[12px] text-white/30">{p.desc}</p>
408348 </div>
409 <h3 className="text-sm font-bold mb-2" style={{ color: f.color + 'cc' }}>{f.title}</h3>
410 <p className="text-[11px] text-white/30 leading-relaxed">{f.desc}</p>
411 </div>
412 ))}
413 </div>
414 </section>
415
416 {/* ── VS COMPETITORS ───────────────────────────────────────── */}
417 <section ref={r5} className="reveal max-w-4xl mx-auto px-4 py-28">
418 <div className="text-center mb-16">
419 <p className="text-[10px] tracking-[0.4em] text-[#00ff88]/40 mb-3 uppercase">Comparison</p>
420 <h2 className="text-3xl md:text-4xl font-bold text-white/90">vs the competition</h2>
421 </div>
349 ))}
350 </div>
422351
423 <div className="glass gradient-border rounded-2xl overflow-hidden overflow-x-auto">
424 <table className="w-full text-[11px]">
425 <thead>
426 <tr className="border-b border-white/[0.06]">
427 {['Tool', 'Type', 'Price', 'Any App', 'Code Fences', 'Voice Cmds', 'Free'].map(h => (
428 <th key={h} className="text-left px-4 py-3.5 text-white/25 font-normal text-[10px] tracking-wider uppercase">{h}</th>
429 ))}
430 </tr>
431 </thead>
432 <tbody>
433 {COMPETITORS.map((c) => {
434 const is48 = c.name === '48co'
435 const Check = () => <span className="text-[#00ff88]">{'\u2713'}</span>
436 const Cross = () => <span className="text-white/10">{'\u2014'}</span>
437 return (
438 <tr key={c.name} className={`border-b border-white/[0.03] ${is48 ? 'bg-[#00f0ff]/[0.04]' : 'hover:bg-white/[0.01]'} transition-colors`}>
439 <td className={`px-4 py-3.5 font-bold ${is48 ? 'text-[#00f0ff]' : 'text-white/50'}`}>{c.name}</td>
440 <td className="px-4 py-3.5 text-white/25">{c.type}</td>
441 <td className={`px-4 py-3.5 ${c.price.includes('Free') ? 'text-[#00ff88]' : 'text-white/25'}`}>{c.price}</td>
442 <td className="px-4 py-3.5">{c.anyApp ? <Check /> : <Cross />}</td>
443 <td className="px-4 py-3.5">{c.codeFence ? <Check /> : <Cross />}</td>
444 <td className="px-4 py-3.5">{c.voiceCmd ? <Check /> : <Cross />}</td>
445 <td className="px-4 py-3.5">{c.free ? <Check /> : <Cross />}</td>
446 </tr>
447 )
448 })}
449 </tbody>
450 </table>
352 <a href="/pricing" className="text-[13px] text-indigo-400 hover:text-indigo-300 transition-colors">
353 See full pricing details &rarr;
354 </a>
451355 </div>
452 <p className="text-[9px] text-white/10 text-center mt-4">*Web tools use free browser speech. Desktop uses Whisper API (~$0.006/min, your own key).</p>
453356 </section>
454357
455 {/* ── CTA ──────────────────────────────────────────────────── */}
456 <section ref={r6} className="reveal py-28 relative">
457 <div className="absolute inset-0 bg-gradient-to-b from-transparent via-[#00f0ff]/[0.02] to-transparent pointer-events-none" />
458
459 <div className="max-w-3xl mx-auto px-4 text-center relative z-10">
460 <h2 className="text-4xl md:text-5xl font-bold mb-4">
461 <span className="text-white/90">Get </span>
462 <span className="bg-gradient-to-r from-[#00f0ff] to-[#00ff88] bg-clip-text text-transparent">48co</span>
358 {/* ── CTA ───────────────────────────────────────────── */}
359 <section className="py-24 px-4">
360 <div className="max-w-2xl mx-auto text-center">
361 <h2 className="text-4xl font-bold text-white/90 mb-4">
362 Stop typing. Start talking.
463363 </h2>
464 <p className="text-white/30 text-sm mb-12 max-w-md mx-auto">
465 Pick what works for you. All options are free. No account required.
364 <p className="text-white/35 text-base mb-10">
365 Join thousands of writers, developers, and professionals who type 3x faster with their voice.
466366 </p>
467
468 <div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-12">
469 {[
470 { title: 'Desktop App', desc: 'Windows + Mac. Types into any app.', badge: 'Recommended', color: '#00f0ff', href: '/download' },
471 { title: 'Web Bookmarklet', desc: 'Zero download. Any website.', badge: 'Instant', color: '#ffb800', href: '/live' },
472 { title: 'Chrome Extension', desc: 'AI chat sites + more.', badge: 'Always on', color: '#ff3b5c', href: '/install' },
473 ].map((opt) => (
474 <a key={opt.title} href={opt.href} className="group glass rounded-2xl p-6 text-left hover:border-white/15 transition-all">
475 <div className="flex items-center justify-between mb-3">
476 <span className="text-sm font-bold" style={{ color: opt.color }}>{opt.title}</span>
477 <span className="text-[8px] px-1.5 py-0.5 rounded border border-white/[0.06] text-white/20">{opt.badge}</span>
478 </div>
479 <p className="text-[10px] text-white/25">{opt.desc}</p>
480 <div className="mt-4 h-[1px] w-0 group-hover:w-full transition-all duration-500" style={{ background: `linear-gradient(to right, ${opt.color}40, transparent)` }} />
481 </a>
482 ))}
483 </div>
484
485 <a href="https://github.com/ccantynz-alt/-48co-ai-pa" target="_blank" className="text-[11px] text-white/15 hover:text-white/30 transition-colors">
486 View source on GitHub
367 <a href="/download" className="inline-block px-10 py-3.5 rounded-xl bg-indigo-500 hover:bg-indigo-400 text-white text-sm font-medium transition-all">
368 Download 48co Free
487369 </a>
370 <p className="text-[11px] text-white/15 mt-4">Mac + Windows. Free tier. No credit card.</p>
488371 </div>
489372 </section>
490373
491 {/* ── FOOTER ───────────────────────────────────────────────── */}
492 <footer className="border-t border-white/[0.04] py-10 text-center">
493 <div className="flex items-center justify-center gap-2 mb-3">
494 <span className="text-sm font-bold text-white/40">48</span>
495 <span className="text-sm font-bold text-[#00f0ff]/40">co</span>
374 {/* ── FOOTER ────────────────────────────────────────── */}
375 <footer className="border-t border-white/[0.04] py-10">
376 <div className="max-w-5xl mx-auto px-6 flex flex-col md:flex-row items-center justify-between gap-4">
377 <div className="flex items-center gap-2">
378 <span className="text-sm font-semibold text-white/40">48</span>
379 <span className="text-sm font-semibold text-indigo-400/60">co</span>
380 </div>
381 <div className="flex gap-6 text-[12px] text-white/20">
382 <a href="/download" className="hover:text-white/50 transition-colors">Download</a>
383 <a href="/compare" className="hover:text-white/50 transition-colors">Compare</a>
384 <a href="/pricing" className="hover:text-white/50 transition-colors">Pricing</a>
385 <a href="/live" className="hover:text-white/50 transition-colors">Try Live</a>
386 </div>
387 <p className="text-[11px] text-white/10">Built in New Zealand</p>
496388 </div>
497 <p className="text-[10px] text-white/10 tracking-wider">Built in New Zealand &middot; Open Source &middot; Free Forever</p>
498389 </footer>
499390 </main>
500391 )
501392
c comment · e edit title · m merge · a approve · r request changes · ? shortcuts