pdf-quiz-generator/frontend/src/pages/LandingPage.jsx
Daniel 695392f022 Remove HIBP breached password warnings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 02:24:24 +02:00

534 lines
28 KiB
JavaScript

import { useState, useEffect, useRef } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import api from '../api/client'
import { useAuth } from '../context/AuthContext'
import Navbar from '../components/Navbar'
// ── Turnstile widget ──────────────────────────────────────────────────────────
const TURNSTILE_SITE_KEY = window.__APP_CONFIG__?.TURNSTILE_SITE_KEY || ''
function TurnstileWidget({ onVerify }) {
const ref = useRef(null)
const widgetId = useRef(null)
useEffect(() => {
if (!TURNSTILE_SITE_KEY) return
let timer
const tryRender = () => {
if (!window.turnstile || !ref.current) { timer = setTimeout(tryRender, 200); return }
widgetId.current = window.turnstile.render(ref.current, {
sitekey: TURNSTILE_SITE_KEY,
callback: onVerify,
})
}
tryRender()
return () => { clearTimeout(timer); if (widgetId.current != null) try { window.turnstile.remove(widgetId.current) } catch {} }
}, [])
if (!TURNSTILE_SITE_KEY) return null
return <div ref={ref} style={{ margin: '8px 0' }} />
}
// ── Feature cards data ────────────────────────────────────────────────────────
const FEATURES = [
{
icon: '📄',
title: 'Quiz from Any PDF',
desc: 'Upload PREP materials, textbook chapters, or lecture slides. AI extracts questions with answers and explanations — no formatting required.',
},
{
icon: '🎓',
title: 'AI Tutor Built In',
desc: 'Ask anything mid-study. The AI tutor knows the current question, the correct answer, and pulls in related questions from your bank for context.',
},
{
icon: '🔊',
title: 'Audio Mode',
desc: 'Every question read aloud with natural-sounding voices. Study during rounds, commuting, or on a run — no screen needed.',
},
{
icon: '🏦',
title: 'Question Bank',
desc: 'All questions in one searchable place. Filter by category, topic, or search semantically — "hyponatremia in neonates" just works.',
},
{
icon: '📊',
title: 'Track Your Progress',
desc: 'Every attempt saved. Review past scores, see where you struggled, and focus your study time where it counts.',
},
{
icon: '⚡',
title: 'Fast by Design',
desc: 'Study mode loads instantly. The AI works in the background — it never holds up the quiz. No spinners on the critical path.',
},
]
// ── Contact form ──────────────────────────────────────────────────────────────
function ContactForm() {
const [form, setForm] = useState({ name: '', email: '', type: 'question', message: '' })
const [turnstileToken, setTurnstileToken] = useState('')
const [loading, setLoading] = useState(false)
const [sent, setSent] = useState(false)
const [error, setError] = useState('')
const hasTurnstile = !!TURNSTILE_SITE_KEY
const canSubmit = form.name && form.email && form.message && (!hasTurnstile || turnstileToken)
const submit = async (e) => {
e.preventDefault()
setError('')
setLoading(true)
try {
await api.post('/contact', { ...form, turnstile_token: turnstileToken || null })
setSent(true)
} catch (err) {
setError(err.response?.data?.detail || 'Something went wrong. Please try again.')
} finally {
setLoading(false)
}
}
if (sent) return (
<div style={{ textAlign: 'center', padding: '32px 0' }}>
<div style={{ fontSize: '2.5rem', marginBottom: 12 }}></div>
<h3 style={{ fontSize: '1.2rem', marginBottom: 8 }}>Message received</h3>
<p style={{ color: 'var(--text-muted)', fontSize: '0.9rem' }}>
{form.type === 'moderator'
? "We'll review your application and get back to you."
: "We'll get back to you shortly."}
</p>
</div>
)
return (
<form onSubmit={submit} style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 200px), 1fr))', gap: 12 }}>
<div>
<label style={{ display: 'block', fontSize: '0.82rem', fontWeight: 600, marginBottom: 5, color: 'var(--text-muted)' }}>Name</label>
<input
value={form.name} onChange={e => setForm(f => ({ ...f, name: e.target.value }))}
placeholder="Your name" required maxLength={120}
style={{ width: '100%', padding: '9px 12px', borderRadius: 8, border: '1px solid var(--border)', background: 'var(--input-bg)', color: 'var(--text)', fontSize: '0.9rem', boxSizing: 'border-box' }}
/>
</div>
<div>
<label style={{ display: 'block', fontSize: '0.82rem', fontWeight: 600, marginBottom: 5, color: 'var(--text-muted)' }}>Email</label>
<input
type="email" value={form.email} onChange={e => setForm(f => ({ ...f, email: e.target.value }))}
placeholder="you@example.com" required
style={{ width: '100%', padding: '9px 12px', borderRadius: 8, border: '1px solid var(--border)', background: 'var(--input-bg)', color: 'var(--text)', fontSize: '0.9rem', boxSizing: 'border-box' }}
/>
</div>
</div>
<div>
<label style={{ display: 'block', fontSize: '0.82rem', fontWeight: 600, marginBottom: 5, color: 'var(--text-muted)' }}>Type</label>
<div style={{ display: 'flex', gap: 10 }}>
{[['question', '💬 Question'], ['moderator', '🛡 Apply as Moderator']].map(([val, label]) => (
<button
key={val} type="button"
onClick={() => setForm(f => ({ ...f, type: val }))}
style={{
flex: 1, padding: '8px 12px', borderRadius: 8, fontSize: '0.85rem', cursor: 'pointer',
fontWeight: form.type === val ? 700 : 400,
background: form.type === val ? 'var(--primary)' : 'var(--bg)',
color: form.type === val ? 'var(--primary-fg)' : 'var(--text)',
border: `1px solid ${form.type === val ? 'var(--primary)' : 'var(--border)'}`,
transition: 'all 0.15s',
}}
>{label}</button>
))}
</div>
{form.type === 'moderator' && (
<p style={{ fontSize: '0.78rem', color: 'var(--text-muted)', marginTop: 6 }}>
Moderators can upload PDFs and manage quiz content. Tell us about your background and how you'd like to contribute.
</p>
)}
</div>
<div>
<label style={{ display: 'block', fontSize: '0.82rem', fontWeight: 600, marginBottom: 5, color: 'var(--text-muted)' }}>Message</label>
<textarea
value={form.message} onChange={e => setForm(f => ({ ...f, message: e.target.value }))}
placeholder={form.type === 'moderator' ? "Tell us about your background, specialty, and how you'd like to help..." : 'Your question or message...'}
required rows={4} maxLength={2000}
style={{ width: '100%', padding: '9px 12px', borderRadius: 8, border: '1px solid var(--border)', background: 'var(--input-bg)', color: 'var(--text)', fontSize: '0.9rem', resize: 'vertical', fontFamily: 'inherit', boxSizing: 'border-box' }}
/>
</div>
<TurnstileWidget onVerify={setTurnstileToken} />
{error && <div style={{ color: 'var(--wrong-fg)', fontSize: '0.85rem', background: 'var(--wrong-bg)', padding: '8px 12px', borderRadius: 6 }}>{error}</div>}
<button
type="submit" disabled={loading || !canSubmit}
className="btn btn-primary"
style={{ alignSelf: 'flex-start', minWidth: 140 }}
>
{loading ? 'Sending…' : 'Send Message'}
</button>
</form>
)
}
// ── Auth modal (Sign In / Register as overlay) ──────────────────────────────
function AuthModal({ mode, onClose, onSwitch }) {
const { login, loginWithToken } = useAuth()
const navigate = useNavigate()
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState('')
const [loading, setLoading] = useState(false)
const [unverified, setUnverified] = useState(false)
const [turnstileToken, setTurnstileToken] = useState('')
const [resendSent, setResendSent] = useState(false)
const [resending, setResending] = useState(false)
const [registered, setRegistered] = useState(false)
const reset = () => { setError(''); setUnverified(false); setResendSent(false); setRegistered(false) }
const switchMode = (m) => { reset(); setName(''); setEmail(''); setPassword(''); onSwitch(m) }
const handleLogin = async (e) => {
e.preventDefault()
setError(''); setUnverified(false)
setLoading(true)
try {
await login(email, password, turnstileToken)
onClose()
navigate('/')
} catch (err) {
if (err.response?.status === 403) setUnverified(true)
else setError(err.response?.data?.detail || 'Login failed')
} finally { setLoading(false) }
}
const handleRegister = async (e) => {
e.preventDefault()
setError('')
setLoading(true)
try {
const res = await api.post('/auth/register', { email, password, name, turnstile_token: turnstileToken || null })
if (res.data.requires_verification) {
setRegistered(true)
} else {
await loginWithToken(res.data.access_token)
onClose()
navigate('/')
}
} catch (err) {
const detail = err.response?.data?.detail
if (typeof detail === 'string') setError(detail)
else if (Array.isArray(detail)) setError(detail.some(e => e.loc?.includes('email')) ? 'Invalid email address.' : 'Please check your input and try again.')
else setError('Registration failed')
} finally { setLoading(false) }
}
const resendVerification = async () => {
setResending(true)
try { await api.post('/auth/resend-verification', { email }) } catch {}
setResendSent(true)
setResending(false)
}
const isLogin = mode === 'login'
return (
<div onClick={onClose} style={{
position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.55)', zIndex: 1000,
display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 16,
}}>
<div onClick={e => e.stopPropagation()} style={{
background: 'var(--card-bg)', borderRadius: 'var(--card-radius, 14px)',
padding: '28px 24px', maxWidth: 400, width: '100%',
boxShadow: '0 20px 60px rgba(0,0,0,0.3)', position: 'relative',
}}>
<button onClick={onClose} style={{
position: 'absolute', top: 12, right: 14, background: 'none',
border: 'none', cursor: 'pointer', color: 'var(--text-muted)', fontSize: '1.2rem',
}}>✕</button>
{/* Tabs */}
<div style={{ display: 'flex', gap: 0, marginBottom: 20, borderBottom: '2px solid var(--border)' }}>
{[['login', 'Sign In'], ['register', 'Register']].map(([m, label]) => (
<button key={m} onClick={() => switchMode(m)} style={{
flex: 1, padding: '10px 0', background: 'none', border: 'none', cursor: 'pointer',
fontWeight: mode === m ? 700 : 400, fontSize: '0.95rem',
color: mode === m ? 'var(--primary)' : 'var(--text-muted)',
borderBottom: mode === m ? '2px solid var(--primary)' : '2px solid transparent',
marginBottom: -2,
}}>{label}</button>
))}
</div>
{/* Registration success */}
{registered && (
<div style={{ textAlign: 'center', padding: '12px 0' }}>
<div style={{ fontSize: '2.5rem', marginBottom: 12 }}>📧</div>
<h3 style={{ marginBottom: 8 }}>Check your email</h3>
<p style={{ color: 'var(--text-muted)', fontSize: '0.875rem', marginBottom: 16 }}>
We sent a verification link to <strong>{email}</strong>. Click it to activate your account.
</p>
<button className="btn btn-primary" onClick={() => { setRegistered(false); switchMode('login') }}>
Go to Sign In
</button>
</div>
)}
{/* Login form */}
{isLogin && !registered && (
<>
{unverified && !resendSent && (
<div style={{ background: '#fffbeb', border: '1px solid #fcd34d', borderRadius: 8, padding: '12px 14px', marginBottom: 14 }}>
<p style={{ margin: '0 0 8px', fontSize: '0.85rem', color: '#92400e', fontWeight: 500 }}>
Email not verified. Check your inbox.
</p>
<button className="btn btn-sm btn-primary" onClick={resendVerification} disabled={resending}>
{resending ? 'Sending…' : 'Resend verification email'}
</button>
</div>
)}
{resendSent && <div className="alert alert-success" style={{ marginBottom: 14 }}>Verification email sent.</div>}
{error && <div className="alert alert-error" style={{ marginBottom: 14 }}>{error}</div>}
<form onSubmit={handleLogin}>
<div className="form-group">
<label>Email</label>
<input type="email" value={email} onChange={e => setEmail(e.target.value)} required autoFocus />
</div>
<div className="form-group">
<label>Password</label>
<input type="password" value={password} onChange={e => setPassword(e.target.value)} required />
</div>
<TurnstileWidget onVerify={setTurnstileToken} />
<button className="btn btn-primary" style={{ width: '100%' }} disabled={loading || (TURNSTILE_SITE_KEY && !turnstileToken)}>
{loading ? 'Signing in…' : 'Sign In'}
</button>
</form>
<div style={{ textAlign: 'center', marginTop: 12, fontSize: '0.82rem' }}>
<Link to="/forgot-password" onClick={onClose} style={{ color: 'var(--text-muted)' }}>Forgot password?</Link>
</div>
</>
)}
{/* Register form */}
{!isLogin && !registered && (
<>
{error && <div className="alert alert-error" style={{ marginBottom: 14 }}>{error}</div>}
<form onSubmit={handleRegister}>
<div className="form-group">
<label>Name</label>
<input type="text" value={name} onChange={e => setName(e.target.value)} required autoFocus />
</div>
<div className="form-group">
<label>Email</label>
<input type="email" value={email} onChange={e => setEmail(e.target.value)} required />
</div>
<div className="form-group">
<label>Password</label>
<input type="password" value={password} onChange={e => setPassword(e.target.value)} required minLength={8} />
</div>
<TurnstileWidget onVerify={setTurnstileToken} />
<button className="btn btn-primary" style={{ width: '100%' }} disabled={loading || (TURNSTILE_SITE_KEY && !turnstileToken)}>
{loading ? 'Creating account…' : 'Sign Up'}
</button>
</form>
</>
)}
</div>
</div>
)
}
// ── Main landing page ─────────────────────────────────────────────────────────
export default function LandingPage() {
const { user } = useAuth()
const [authModal, setAuthModal] = useState(null) // null | 'login' | 'register'
// Load Turnstile script once
useEffect(() => {
if (!TURNSTILE_SITE_KEY || document.getElementById('cf-turnstile-script')) return
const s = document.createElement('script')
s.id = 'cf-turnstile-script'
s.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js'
s.async = true
document.head.appendChild(s)
}, [])
return (
<div style={{ minHeight: '100vh', background: 'var(--bg)' }}>
{/* Auth modal overlay */}
{authModal && (
<AuthModal
mode={authModal}
onClose={() => setAuthModal(null)}
onSwitch={setAuthModal}
/>
)}
{/* ── Shared Navbar (handles auth state) ─────────────────────────────── */}
<style>{`.navbar { margin-bottom: 0 !important; }`}</style>
<Navbar onSignIn={() => setAuthModal('login')} onRegister={() => setAuthModal('register')} />
{/* ── Hero ───────────────────────────────────────────────────────────── */}
<section style={{
background: 'var(--navbar-bg)',
color: 'var(--navbar-fg)',
padding: '96px 24px 88px',
textAlign: 'center',
position: 'relative',
overflow: 'hidden',
}}>
{/* subtle grid */}
<div style={{
position: 'absolute', inset: 0, opacity: 0.04,
backgroundImage: 'linear-gradient(#fff 1px, transparent 1px), linear-gradient(90deg, #fff 1px, transparent 1px)',
backgroundSize: '48px 48px',
}} />
<div style={{ position: 'relative', maxWidth: 720, margin: '0 auto' }}>
<div style={{ display: 'inline-block', background: 'rgba(96,165,250,0.15)', border: '1px solid rgba(96,165,250,0.3)', borderRadius: 20, padding: '4px 14px', fontSize: '0.78rem', fontWeight: 600, color: '#93c5fd', marginBottom: 28, letterSpacing: '0.04em', textTransform: 'uppercase' }}>
Pediatric Learning Platform
</div>
<h1 style={{ fontSize: 'clamp(2.2rem, 5vw, 3.4rem)', fontWeight: 800, lineHeight: 1.15, margin: '0 0 22px', letterSpacing: '-0.03em' }}>
Turn your textbooks<br />
<span style={{ background: 'linear-gradient(90deg, #60a5fa, #a78bfa)', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent' }}>
into tests
</span>
</h1>
<p style={{ fontSize: '1.15rem', color: 'rgba(226,232,240,0.75)', lineHeight: 1.7, marginBottom: 40, maxWidth: 560, margin: '0 auto 40px' }}>
Upload any PDF — PREP materials, lecture notes, textbook chapters.
AI extracts questions, reads them aloud, and explains every answer.
</p>
<div style={{ display: 'flex', gap: 14, justifyContent: 'center', flexWrap: 'wrap' }}>
{user ? <>
<Link to="/" className="btn btn-primary" style={{ padding: '12px 28px', fontSize: '1rem', borderRadius: 10 }}>Dashboard</Link>
<Link to="/quizzes" className="btn" style={{ padding: '12px 28px', fontSize: '1rem', borderRadius: 10, background: 'rgba(255,255,255,0.08)', color: 'var(--navbar-fg)', border: '1px solid rgba(255,255,255,0.18)', textDecoration: 'none' }}>My Quizzes</Link>
<Link to="/question-bank" className="btn" style={{ padding: '12px 28px', fontSize: '1rem', borderRadius: 10, background: 'rgba(255,255,255,0.08)', color: 'var(--navbar-fg)', border: '1px solid rgba(255,255,255,0.18)', textDecoration: 'none' }}>Question Bank</Link>
</> : <>
<button onClick={() => setAuthModal('login')} className="btn btn-primary" style={{ padding: '12px 28px', fontSize: '1rem', borderRadius: 10 }}>Sign In</button>
<button onClick={() => setAuthModal('register')} className="btn" style={{ padding: '12px 28px', fontSize: '1rem', borderRadius: 10, background: 'rgba(255,255,255,0.08)', color: 'var(--navbar-fg)', border: '1px solid rgba(255,255,255,0.18)' }}>Register</button>
</>}
</div>
</div>
</section>
{/* ── Features ───────────────────────────────────────────────────────── */}
<section style={{ maxWidth: 1100, margin: '0 auto', padding: '80px 24px' }}>
<div style={{ textAlign: 'center', marginBottom: 56 }}>
<h2 style={{ fontSize: 'clamp(1.6rem, 3vw, 2.2rem)', fontWeight: 800, letterSpacing: '-0.02em', margin: '0 0 12px' }}>
Everything you need to study smarter
</h2>
<p style={{ color: 'var(--text-muted)', fontSize: '1.05rem', maxWidth: 480, margin: '0 auto' }}>
Built specifically for pediatric board prep and clinical learning.
</p>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 280px), 1fr))', gap: 20 }}>
{FEATURES.map((f, i) => (
<div key={i} className="card" style={{ padding: '24px', transition: 'transform 0.2s, box-shadow 0.2s' }}
onMouseEnter={e => { e.currentTarget.style.transform = 'translateY(-3px)'; e.currentTarget.style.boxShadow = '0 8px 32px rgba(0,0,0,0.12)' }}
onMouseLeave={e => { e.currentTarget.style.transform = 'none'; e.currentTarget.style.boxShadow = '' }}
>
<div style={{ fontSize: '2rem', marginBottom: 12 }}>{f.icon}</div>
<h3 style={{ fontWeight: 700, fontSize: '1rem', margin: '0 0 8px' }}>{f.title}</h3>
<p style={{ color: 'var(--text-muted)', fontSize: '0.9rem', lineHeight: 1.65, margin: 0 }}>{f.desc}</p>
</div>
))}
</div>
</section>
{/* ── AI Scribe section ──────────────────────────────────────────────── */}
<section style={{ background: 'var(--navbar-bg)', color: 'var(--navbar-fg)', padding: '80px 24px' }}>
<div style={{ maxWidth: 1000, margin: '0 auto', display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 320px), 1fr))', gap: 40, alignItems: 'center' }}>
<div>
<div style={{ display: 'inline-block', background: 'rgba(96,165,250,0.15)', border: '1px solid rgba(96,165,250,0.3)', borderRadius: 20, padding: '4px 14px', fontSize: '0.78rem', fontWeight: 600, color: '#93c5fd', marginBottom: 20, letterSpacing: '0.04em', textTransform: 'uppercase' }}>
Also from PedsHub
</div>
<h2 style={{ fontSize: 'clamp(1.6rem, 3vw, 2rem)', fontWeight: 800, letterSpacing: '-0.02em', margin: '0 0 16px', color: '#f1f5f9' }}>
Pediatric AI Scribe
</h2>
<p style={{ color: '#94a3b8', lineHeight: 1.7, marginBottom: 28, fontSize: '0.95rem' }}>
A clinical assistant built for pediatric providers. Voice-to-note documentation,
age-specific well visit workflows, developmental milestones, vaccine schedules,
catch-up planners, and automatic ICD-10 billing codes — all in one tool.
</p>
<div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginBottom: 32, overflow: 'hidden' }}>
{[
'🩺 Well visit planner from newborn through adolescence',
'📋 Developmental milestone tracking across 4 domains',
'💉 Full AAP/ACIP vaccine schedule with catch-up planner',
'🎙 AI scribe — speak, get a structured note',
'💊 Automatic ICD-10 and CPT billing codes',
].map((item, i) => (
<div key={i} style={{ fontSize: '0.88rem', color: '#cbd5e1', display: 'flex', gap: 8, alignItems: 'flex-start', overflowWrap: 'break-word', wordBreak: 'break-word', minWidth: 0 }}>
<span>{item}</span>
</div>
))}
</div>
<a
href="https://app.pedshub.com"
target="_blank"
rel="noopener noreferrer"
className="btn btn-primary"
style={{ display: 'inline-block', textDecoration: 'none', padding: '11px 24px', borderRadius: 10 }}
>
Open AI Scribe
</a>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 130px), 1fr))', gap: 10 }}>
{[
{ icon: '📅', label: 'Well Visits', sub: '2wk → 18yr' },
{ icon: '🧠', label: 'Milestones', sub: '2mo → 5yr' },
{ icon: '💉', label: 'Vaccines', sub: 'Full schedule' },
{ icon: '🎙', label: 'AI Scribe', sub: 'Voice-to-note' },
{ icon: '💊', label: 'ICD-10', sub: 'Auto-suggested' },
{ icon: '📋', label: 'SOAP Notes', sub: 'Structured' },
].map((item, i) => (
<div key={i} style={{
background: 'rgba(255,255,255,0.05)',
border: '1px solid rgba(255,255,255,0.08)',
borderRadius: 10, padding: '14px',
transition: 'background 0.2s',
}}
onMouseEnter={e => e.currentTarget.style.background = 'rgba(255,255,255,0.09)'}
onMouseLeave={e => e.currentTarget.style.background = 'rgba(255,255,255,0.05)'}
>
<div style={{ fontSize: '1.5rem', marginBottom: 6 }}>{item.icon}</div>
<div style={{ fontWeight: 700, fontSize: '0.85rem', color: '#e2e8f0' }}>{item.label}</div>
<div style={{ fontSize: '0.75rem', color: '#64748b' }}>{item.sub}</div>
</div>
))}
</div>
</div>
</section>
{/* ── Contact form ───────────────────────────────────────────────────── */}
<section id="contact" style={{ maxWidth: 680, margin: '0 auto', padding: '80px 24px' }}>
<div style={{ textAlign: 'center', marginBottom: 40 }}>
<h2 style={{ fontSize: 'clamp(1.5rem, 3vw, 2rem)', fontWeight: 800, letterSpacing: '-0.02em', margin: '0 0 12px' }}>
Get in touch
</h2>
<p style={{ color: 'var(--text-muted)', fontSize: '0.95rem' }}>
Have a question? Want to contribute as a moderator? We'd love to hear from you.
</p>
</div>
<div className="card" style={{ padding: '32px' }}>
<ContactForm />
</div>
</section>
{/* ── Footer ─────────────────────────────────────────────────────────── */}
<footer style={{
background: 'var(--navbar-bg)',
padding: '32px 24px',
borderTop: '1px solid rgba(255,255,255,0.05)',
}}>
<div style={{ maxWidth: 1100, margin: '0 auto', display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 16 }}>
<span style={{ fontWeight: 700, color: 'rgba(226,232,240,0.6)', fontSize: '0.9rem' }}>
🏥 PedsHub
<span style={{ fontWeight: 400, marginLeft: 16 }}>© {new Date().getFullYear()}</span>
</span>
<div style={{ display: 'flex', gap: 24, fontSize: '0.85rem' }}>
<button onClick={() => setAuthModal('login')} style={{ color: 'rgba(226,232,240,0.45)', background: 'none', border: 'none', cursor: 'pointer', fontSize: 'inherit' }}>Sign In</button>
<a href="#contact" style={{ color: 'rgba(226,232,240,0.45)', textDecoration: 'none' }}>Contact</a>
<a href="https://app.pedshub.com" target="_blank" rel="noopener noreferrer" style={{ color: 'rgba(226,232,240,0.45)', textDecoration: 'none' }}>AI Scribe</a>
</div>
</div>
</footer>
</div>
)
}