// Login / signup / invite-redeem screen. // Non-technical UX: one big email field, one password field, smart mode swap. const loginStyles = { page: { minHeight:'100vh', display:'flex', alignItems:'center', justifyContent:'center', background:'var(--paper-2)', fontFamily:'var(--sans)', padding:'40px 16px', }, card: { width:420, background:'var(--paper)', borderRadius:16, boxShadow:'0 24px 60px rgba(0,0,0,.08)', padding:'40px 36px 32px 36px', }, brand: { display:'flex', alignItems:'center', gap:10, marginBottom:24 }, brandImg: { width:36, height:36 }, title: { fontFamily:'var(--serif)', fontSize:28, color:'var(--ink)', letterSpacing:'-.01em', lineHeight:1.1, marginBottom:4 }, sub: { fontSize:13, color:'var(--ink-3)', marginBottom:22, fontFamily:'var(--serif)', fontStyle:'italic' }, tabs: { display:'flex', gap:6, marginBottom:16 }, tab: (a) => ({ padding:'6px 12px', borderRadius:999, border:'1px solid ' + (a ? 'var(--ink)' : 'var(--line-2)'), background: a ? 'var(--ink)' : 'var(--paper)', color: a ? 'var(--paper)' : 'var(--ink-2)', fontSize:11.5, fontFamily:'var(--mono)', letterSpacing:'.06em', textTransform:'uppercase', cursor:'pointer', }), label: { fontFamily:'var(--mono)', fontSize:10, letterSpacing:'.14em', color:'var(--ink-3)', textTransform:'uppercase', marginBottom:6 }, input: { width:'100%', border:'1px solid var(--line-2)', borderRadius:8, padding:'10px 12px', fontSize:14, background:'var(--paper-2)', outline:'none', marginBottom:14, fontFamily:'var(--sans)', color:'var(--ink)', }, primary: { width:'100%', height:44, border:'1px solid var(--ink)', background:'var(--ink)', color:'var(--paper)', borderRadius:999, fontSize:13.5, cursor:'pointer', fontFamily:'var(--sans)', marginTop:8, }, soft: { width:'100%', height:38, border:'1px solid var(--line-2)', background:'var(--paper)', color:'var(--ink-2)', borderRadius:999, fontSize:12.5, cursor:'pointer', fontFamily:'var(--sans)', marginTop:10, }, err: { fontSize:12, color:'var(--accent)', marginBottom:6 }, ok: { fontSize:12, color:'var(--accent-2)', marginBottom:6 }, small: { fontSize:11, color:'var(--ink-4)', textAlign:'center', marginTop:18, fontFamily:'var(--sans)' }, inviteTag: { fontFamily:'var(--mono)', fontSize:10, letterSpacing:'.1em', padding:'3px 8px', borderRadius:999, background:'var(--hl)', color:'var(--accent)', textTransform:'uppercase', marginLeft:8, }, }; function LoginScreen({ inviteToken, onReady }) { const [mode, setMode] = React.useState(inviteToken ? 'signup' : 'magic'); // 'magic' | 'password' | 'signup' const [email, setEmail] = React.useState(''); const [password, setPassword] = React.useState(''); const [busy, setBusy] = React.useState(false); const [err, setErr] = React.useState(null); const [note, setNote] = React.useState(null); const [invite, setInvite] = React.useState(null); React.useEffect(() => { if (!inviteToken) return; API.checkInvite(inviteToken) .then(setInvite) .catch(e => setErr('초대장 오류 — ' + e.message)); }, [inviteToken]); React.useEffect(() => { if (invite && invite.email) setEmail(invite.email); }, [invite]); const onMagic = async () => { if (!email.trim()) { setErr('이메일을 입력해주세요'); return; } setBusy(true); setErr(null); setNote(null); try { const { error } = await window.palette_auth.signInMagic(email.trim()); if (error) { setErr(error.message || '전송 실패'); return; } setNote('이메일로 로그인 링크를 보냈어요. 받은편지함을 확인해주세요.'); } finally { setBusy(false); } }; const onPassword = async () => { if (!email.trim() || !password) { setErr('이메일과 비밀번호를 모두 입력해주세요'); return; } setBusy(true); setErr(null); try { const { error } = await window.palette_auth.signInPassword(email.trim(), password); if (error) { setErr(error.message || '로그인 실패'); return; } onReady && onReady(); } finally { setBusy(false); } }; const onSignup = async () => { if (!email.trim() || !password || password.length < 8) { setErr('이메일과 8자 이상 비밀번호가 필요해요'); return; } setBusy(true); setErr(null); setNote(null); try { const res = await window.palette_auth.signUpWithInvite({ email: email.trim(), password, invite_token: inviteToken, }); if (res.error) { setErr(res.error.message || '가입 실패'); return; } setNote('가입 완료 — 확인 메일을 보냈어요. 메일의 링크를 눌러 로그인하세요.'); } finally { setBusy(false); } }; return (