// Practivo — bottom sections: Demo, Social Proof, Final CTA, Footer /* ---------- Demo / Preview ---------- */ const DemoSection = () => (
Practivo practice session — AI avatar in a simulated office {/* live badge */}
Scenario · Difficult conversation

Your participants practice on their own. You get the report.

); /* ---------- Social Proof ---------- */ const SocialProofSection = () => (
{[ { name: '4skills', sub: 'Business development & competency training', country: 'Poland', logo: 'assets/logo-4skills.png' }, { name: 'mad2learn', sub: 'Digital learning & VR experiences', country: 'Germany', logo: 'assets/logo-mad2learn.png' }, ].map((c, i) => (
{c.logo ? (
{`${c.name}
) : (
{c.mono}
)}

{c.name}

{c.sub}

{c.country}
))}

Both companies use Practivo to extend their training programs with AI practice and evaluation.

); /* ---------- Final CTA form ---------- */ const FinalCTA = () => { const [state, setState] = React.useState({ name: '', email: '', company: '', role: 'Freelance trainer' }); const [submitted, setSubmitted] = React.useState(false); const [submitting, setSubmitting] = React.useState(false); const [errors, setErrors] = React.useState({}); const submit = async (e) => { e.preventDefault(); const err = {}; if (!state.name.trim()) err.name = 'Required'; if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(state.email)) err.email = 'Enter a valid work email'; if (!state.company.trim()) err.company = 'Required'; setErrors(err); if (Object.keys(err).length > 0) return; setSubmitting(true); try { const token = await new Promise((resolve, reject) => { grecaptcha.ready(async () => { try { resolve(await grecaptcha.execute('6Ld9-dssAAAAAIpgwT0d2xx3BtWnxaT9HERPEVy0', { action: 'REQUEST_DEMO' })); } catch (e) { reject(e); } }); }); const res = await fetch('https://formspree.io/f/xykojnre', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: state.name, email: state.email, company: state.company, role: state.role, 'g-recaptcha-response': token }), }); const data = await res.json(); if (res.ok) { setSubmitted(true); } else { const fsErrors = {}; (data.errors || []).forEach(e => { if (e.field) fsErrors[e.field] = e.message; else fsErrors._form = e.message; }); setErrors(Object.keys(fsErrors).length ? fsErrors : { _form: 'Something went wrong. Please try again.' }); } } catch { setErrors({ _form: 'Network error. Please try again.' }); } finally { setSubmitting(false); } }; const field = (name, label, type = 'text') => ( ); return (
Start the conversation

Ready to add AI practice to your training programs?

Request a demo and we will show you how Practivo fits into your existing offer — and what the reports look like for your clients.

We typically respond within 24 hours.
{submitted ? (

Request received

Thanks {state.name.split(' ')[0]}. We'll be in touch at {state.email} within 24 hours.

) : (
{field('name', 'Name')} {field('email', 'Work email', 'email')} {field('company', 'Company or practice name')}
{errors._form && (

{errors._form}

)}

By submitting, you agree to our privacy policy.

)}
); }; /* ---------- Obfuscated email link ---------- Renders a placeholder in the static HTML; assembles the real address from split fragments + ROT13 only after mount, so non-JS crawlers and simple regex scrapers never see the full string. */ const ObfuscatedEmail = ({ style, className, children }) => { const [addr, setAddr] = React.useState(''); React.useEffect(() => { // Fragments — never written contiguously in source. const u = ['hel', 'lo'].join(''); const d = ['practivo', '.', 'app'].join(''); setAddr(u + String.fromCharCode(64) + d); }, []); const onClick = (e) => { if (!addr) { e.preventDefault(); return; } }; return ( {children || (addr || 'contact →')} ); }; /* ---------- Footer ---------- */ const Footer = () => ( ); Object.assign(window, { DemoSection, SocialProofSection, FinalCTA, Footer });