/* ── LIGHT MEMBERSHIP GATE ── Free preview → simple signup (name + email + offers opt-in). No password — this is a lead-capture gate, not the full auth layer. window.MemberGate — wrap a mode; locks after the free allowance Storage: tfe_member_v1 (current member), tfe_leads_v1 (all signups on this device) */ const MEMBER_KEY = 'tfe_member_v1'; const LEADS_KEY = 'tfe_leads_v1'; const FREE_PRACTICE_ANSWERS = 12; // free scored answers (practice + lessons) /* Speaking is ALWAYS free — never gated. */ function loadMember() { try { const m = JSON.parse(localStorage.getItem(MEMBER_KEY)); if (m && m.email) return m; } catch {} return null; } function saveMember(m) { localStorage.setItem(MEMBER_KEY, JSON.stringify(m)); try { const leads = JSON.parse(localStorage.getItem(LEADS_KEY)) || []; if (!leads.some(l => l.email === m.email)) { leads.push(m); localStorage.setItem(LEADS_KEY, JSON.stringify(leads)); } } catch {} } function SignupCard({ t, onDone, context }) { const [name, setName] = React.useState(''); const [email, setEmail] = React.useState(''); const [offers, setOffers] = React.useState(true); const [err, setErr] = React.useState(null); const [joined, setJoined] = React.useState(null); const submit = () => { if (!name.trim()) { setErr(t('Please enter your name.','يرجى إدخال اسمك.','Lütfen adınızı girin.')); return; } const em = email.trim().toLowerCase(); if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(em)) { setErr(t('Please enter a valid email.','يرجى إدخال بريد إلكتروني صحيح.','Lütfen geçerli bir e-posta girin.')); return; } const m = { name: name.trim(), email: em, offers, at: Date.now() }; saveMember(m); setJoined(m); }; if (joined) return (