const{useState,useEffect,useCallback,useRef}=React;
const M="'JetBrains Mono',monospace",F="'DM Sans',system-ui,sans-serif";
const TH={
dark:{bg:"#06060A",bgG:"linear-gradient(160deg,#06060A 0%,#0f0d1f 40%,#0a0e1a 100%)",s:"#0D0D15",sa:"#14142A",bd:"#1C1C36",bf:"#7C5CFC",tx:"#EEEEF5",tm:"#6E6E8A",td:"#3E3E58",ac:"#7C5CFC",ok:"#34D399",er:"#F87171",wa:"#FBBF24",bl:"#60A5FA",sh:"0 8px 32px rgba(0,0,0,.5)",shL:"0 2px 8px rgba(0,0,0,.3)",shC:"0 4px 20px rgba(124,92,252,.12)"},
light:{bg:"#F7F7FB",bgG:"linear-gradient(160deg,#f0ecff 0%,#e8f0ff 40%,#fef6ff 100%)",s:"#FFFFFF",sa:"#EDEDF4",bd:"#DDDDE8",bf:"#7C5CFC",tx:"#111128",tm:"#6B6B88",td:"#A0A0B8",ac:"#7C5CFC",ok:"#059669",er:"#DC2626",wa:"#D97706",bl:"#2563EB",sh:"0 8px 32px rgba(0,0,0,.08)",shL:"0 2px 8px rgba(0,0,0,.04)",shC:"0 4px 20px rgba(124,92,252,.08)"}};
const ap={tk:localStorage.getItem("at"),h(){const h={"Content-Type":"application/json"};if(this.tk)h.Authorization="Bearer "+this.tk;return h},async g(p){const r=await fetch("/api"+p,{headers:this.h()});if(r.status===401){this.out();throw Error("X")}if(!r.ok){const e=await r.json().catch(()=>({}));throw Error(e.detail||"Erreur")}return r.json()},async p(p,b){const r=await fetch("/api"+p,{method:"POST",headers:this.h(),body:JSON.stringify(b)});if(r.status===401){this.out();throw Error("X")}if(!r.ok){const e=await r.json().catch(()=>({}));throw Error(e.detail||"Erreur")}return r.json()},async put(p,b){const r=await fetch("/api"+p,{method:"PUT",headers:this.h(),body:JSON.stringify(b)});if(!r.ok){const e=await r.json().catch(()=>({}));throw Error(e.detail||"Erreur")}return r.json()},async uf(p,f){const fd=new FormData();fd.append("file",f);const h={};if(this.tk)h.Authorization="Bearer "+this.tk;const r=await fetch("/api"+p,{method:"POST",headers:h,body:fd});if(!r.ok){const e=await r.json().catch(()=>({}));throw Error(e.detail||"Erreur")}return r.json()},st(t){this.tk=t;t?localStorage.setItem("at",t):localStorage.removeItem("at")},out(){this.tk=null;localStorage.removeItem("at");localStorage.removeItem("au");location.reload()}};
function getRouteRole(){const p=location.pathname.replace(/\/$/,"");if(p==="/admin")return"admin";if(p==="/validator")return"validator";if(p==="/staff")return"staff";return"worker"}
const ic={check:c=><path d="M20 6L9 17l-5-5" stroke={c} strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round"/>,x:c=><><path d="M18 6L6 18" stroke={c} strokeWidth="2.5" strokeLinecap="round"/><path d="M6 6l12 12" stroke={c} strokeWidth="2.5" strokeLinecap="round"/></>,edit:c=><><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7" stroke={c} strokeWidth="2" fill="none" strokeLinecap="round"/><path d="M18.5 2.5a2.12 2.12 0 013 3L12 15l-4 1 1-4 9.5-9.5z" stroke={c} strokeWidth="2" fill="none" strokeLinecap="round"/></>,flag:c=><><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z" stroke={c} strokeWidth="2" fill="none"/><line x1="4" y1="22" x2="4" y2="15" stroke={c} strokeWidth="2"/></>,dl:c=><><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4" stroke={c} strokeWidth="2" fill="none" strokeLinecap="round"/><polyline points="7 10 12 15 17 10" stroke={c} strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/><line x1="12" y1="15" x2="12" y2="3" stroke={c} strokeWidth="2" strokeLinecap="round"/></>,ul:c=><><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4" stroke={c} strokeWidth="2" fill="none" strokeLinecap="round"/><polyline points="17 8 12 3 7 8" stroke={c} strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/><line x1="12" y1="3" x2="12" y2="15" stroke={c} strokeWidth="2" strokeLinecap="round"/></>,chart:c=><><line x1="18" y1="20" x2="18" y2="10" stroke={c} strokeWidth="2.5" strokeLinecap="round"/><line x1="12" y1="20" x2="12" y2="4" stroke={c} strokeWidth="2.5" strokeLinecap="round"/><line x1="6" y1="20" x2="6" y2="14" stroke={c} strokeWidth="2.5" strokeLinecap="round"/></>,back:c=><polyline points="15 18 9 12 15 6" stroke={c} strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round"/>,out:c=><><path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4" stroke={c} strokeWidth="2" fill="none" strokeLinecap="round"/><polyline points="16 17 21 12 16 7" stroke={c} strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/><line x1="21" y1="12" x2="9" y2="12" stroke={c} strokeWidth="2" strokeLinecap="round"/></>,plus:c=><><line x1="12" y1="5" x2="12" y2="19" stroke={c} strokeWidth="2.5" strokeLinecap="round"/><line x1="5" y1="12" x2="19" y2="12" stroke={c} strokeWidth="2.5" strokeLinecap="round"/></>,sun:c=><><circle cx="12" cy="12" r="5" stroke={c} strokeWidth="2" fill="none"/>{[[12,1,12,3],[12,21,12,23],[4.22,4.22,5.64,5.64],[18.36,18.36,19.78,19.78],[1,12,3,12],[21,12,23,12]].map(([a,b,d,e],i)=><line key={i} x1={a} y1={b} x2={d} y2={e} stroke={c} strokeWidth="2" strokeLinecap="round"/>)}</>,moon:c=><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z" stroke={c} strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/>,file:c=><><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" stroke={c} strokeWidth="2" fill="none" strokeLinecap="round"/><polyline points="14 2 14 8 20 8" stroke={c} strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/></>,wallet:c=><><rect x="2" y="6" width="20" height="14" rx="2" stroke={c} strokeWidth="2" fill="none"/><path d="M2 10h20" stroke={c} strokeWidth="2"/><circle cx="16" cy="14" r="1.5" fill={c}/></>,globe:c=><><circle cx="12" cy="12" r="10" stroke={c} strokeWidth="2" fill="none"/><path d="M2 12h20" stroke={c} strokeWidth="2"/><path d="M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z" stroke={c} strokeWidth="2" fill="none"/></>,zap:c=><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" stroke={c} strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/>,shield:c=><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" stroke={c} strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/>,phone:c=><><rect x="5" y="2" width="14" height="20" rx="2" stroke={c} strokeWidth="2" fill="none"/><line x1="12" y1="18" x2="12.01" y2="18" stroke={c} strokeWidth="2" strokeLinecap="round"/></>,user:c=><><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2" stroke={c} strokeWidth="2" fill="none"/><circle cx="12" cy="7" r="4" stroke={c} strokeWidth="2" fill="none"/></>,box:c=><><path d="M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 003 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0021 16z" stroke={c} strokeWidth="2" fill="none"/><polyline points="3.27 6.96 12 12.01 20.73 6.96" stroke={c} strokeWidth="2" fill="none"/><line x1="12" y1="22.08" x2="12" y2="12" stroke={c} strokeWidth="2"/></>};
const I=({n,s=20,c="#999"})=><svg width={s} height={s} viewBox="0 0 24 24" style={{flexShrink:0}}>{ic[n]?.(c)}</svg>;
const Orbs=({t})=><><div style={{position:"fixed",width:350,height:350,borderRadius:"50%",background:t.ac,filter:"blur(140px)",opacity:.06,top:"-5%",right:"-5%",pointerEvents:"none",zIndex:0}}/><div style={{position:"fixed",width:250,height:250,borderRadius:"50%",background:t.bl,filter:"blur(120px)",opacity:.04,bottom:"15%",left:"-5%",pointerEvents:"none",zIndex:0}}/></>;
const Bg=({children,c})=><span style={{display:"inline-flex",padding:"3px 10px",borderRadius:99,fontSize:10,fontWeight:700,letterSpacing:.6,color:c,background:c+"15",textTransform:"uppercase"}}>{children}</span>;
const Bt=({children,onClick,v="primary",dis,full,style:st={},t})=>{const vs={primary:{bg:`linear-gradient(135deg,${t.ac},${t.ac}cc)`,c:"#fff",bx:t.shC},success:{bg:`linear-gradient(135deg,${t.ok},${t.ok}cc)`,c:"#fff",bx:`0 4px 16px ${t.ok}25`},danger:{bg:t.er,c:"#fff"},ghost:{bg:t.s+"88",c:t.tm,bd:`1.5px solid ${t.bd}`,bk:"blur(8px)"},dim:{bg:t.sa,c:t.tm},warn:{bg:`linear-gradient(135deg,${t.wa},${t.wa}cc)`,c:"#fff",bx:`0 4px 16px ${t.wa}25`}};const vv=vs[v]||vs.primary;return<button onClick={onClick} disabled={dis} style={{background:vv.bg,color:vv.c,border:vv.bd||"none",display:"inline-flex",alignItems:"center",justifyContent:"center",gap:8,padding:"14px 22px",borderRadius:16,fontSize:15,fontWeight:700,fontFamily:F,opacity:dis?.35:1,width:full?"100%":"auto",transition:"all .2s",boxShadow:vv.bx||"none",backdropFilter:vv.bk||"none",letterSpacing:-.2,...st}}>{children}</button>};
const Cd=({children,style:st={},onClick,t,anim="fi",delay:d=0})=><div onClick={onClick} className={anim} style={{background:t.s+"ee",backdropFilter:"blur(8px)",border:`1px solid ${t.bd}`,borderRadius:20,padding:20,boxShadow:t.shL,animationDelay:`${d}ms`,...st}}>{children}</div>;
const SC=({l,v,sub,c,icon:ii,t,d=0})=><Cd t={t} anim="pi" delay={d} style={{flex:1,minWidth:90,padding:14}}><div style={{display:"flex",alignItems:"center",gap:5,marginBottom:8}}>{ii&&<I n={ii} s={13} c={c}/>}<span style={{fontSize:9,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:1}}>{l}</span></div><div style={{fontSize:24,fontWeight:800,color:c,fontFamily:M,lineHeight:1}}>{v}</div>{sub&&<div style={{fontSize:11,color:t.tm,marginTop:5,fontWeight:500}}>{sub}</div>}</Cd>;
const Pr=({v,mx,c,t,h=4})=><div style={{height:h,background:t.sa,borderRadius:99,overflow:"hidden"}}><div style={{height:"100%",width:`${mx>0?Math.min(100,(v/mx)*100):0}%`,background:`linear-gradient(90deg,${c},${c}99)`,borderRadius:99,transition:"width .6s ease"}}/></div>;
const TA=({value:v,onChange:oc,rows:r=4,t,ph})=><textarea value={v} onChange={e=>oc(e.target.value)} rows={r} placeholder={ph} style={{width:"100%",background:t.sa+"cc",border:`1.5px solid ${t.bd}`,borderRadius:14,padding:"14px 16px",color:t.tx,fontSize:15,fontFamily:F,resize:"vertical",outline:"none",lineHeight:1.65,boxSizing:"border-box",transition:"border-color .2s,box-shadow .2s"}} onFocus={e=>{e.target.style.borderColor=t.bf;e.target.style.boxShadow=`0 0 0 3px ${t.bf}22`}} onBlur={e=>{e.target.style.borderColor=t.bd;e.target.style.boxShadow="none"}}/>;
const In=({value:v,onChange:oc,placeholder:ph,type:tp="text",t,style:st={},onKey})=><input type={tp} value={v} onChange={e=>oc(e.target.value)} placeholder={ph} onKeyDown={onKey} style={{width:"100%",background:t.sa+"cc",border:`1.5px solid ${t.bd}`,borderRadius:14,padding:"14px 18px",color:t.tx,fontSize:16,fontFamily:F,outline:"none",boxSizing:"border-box",transition:"border-color .2s,box-shadow .2s",...st}} onFocus={e=>{e.target.style.borderColor=t.bf;e.target.style.boxShadow=`0 0 0 3px ${t.bf}22`}} onBlur={e=>{e.target.style.borderColor=t.bd;e.target.style.boxShadow="none"}}/>;
const TB=({tabs,active:a,onChange:oc,t})=><div style={{display:"flex",background:t.s+"cc",backdropFilter:"blur(8px)",borderRadius:16,padding:4,gap:3,border:`1px solid ${t.bd}`,boxShadow:t.shL}}>{tabs.map(tb=><button key={tb.id} onClick={()=>oc(tb.id)} style={{flex:1,padding:"11px 6px",borderRadius:13,border:"none",background:a===tb.id?`linear-gradient(135deg,${t.ac},${t.ac}cc)`:t.s+"00",color:a===tb.id?"#fff":t.tm,fontSize:12,fontWeight:700,fontFamily:F,transition:"all .25s",boxShadow:a===tb.id?t.shC:"none"}}>{tb.l}</button>)}</div>;
const Hd=({title:ti,subtitle:su,onBack:ob,right:ri,t})=><div style={{padding:"20px 24px 12px",display:"flex",alignItems:"center",gap:12,position:"relative",zIndex:1}}>{ob&&<button onClick={ob} style={{background:t.sa+"88",backdropFilter:"blur(8px)",border:`1px solid ${t.bd}`,borderRadius:12,padding:8,display:"flex"}}><I n="back" s={20} c={t.tx}/></button>}<div style={{flex:1}}><div style={{fontSize:22,fontWeight:800,letterSpacing:-.5,color:t.tx}}>{ti}</div>{su&&<div style={{fontSize:12,color:t.tm,marginTop:3,fontWeight:500}}>{su}</div>}</div>{ri}</div>;
const ThB=({theme:th,toggle:tg,t})=><button onClick={tg} style={{background:t.sa+"88",backdropFilter:"blur(8px)",border:`1px solid ${t.bd}`,borderRadius:12,padding:9,display:"flex"}}><I n={th==="dark"?"sun":"moon"} s={16} c={t.tm}/></button>;
const RB=({theme:th,toggle:tg,t})=><div style={{display:"flex",gap:8}}><ThB theme={th} toggle={tg} t={t}/><button onClick={()=>ap.out()} style={{background:t.sa+"88",backdropFilter:"blur(8px)",border:`1px solid ${t.bd}`,borderRadius:12,padding:9,display:"flex"}}><I n="out" s={16} c={t.tm}/></button></div>;
const Em=({icon:ii,title:ti,sub:su,t})=><div style={{textAlign:"center",padding:"70px 24px",position:"relative",zIndex:1}} className="fi"><div style={{width:64,height:64,borderRadius:20,background:t.sa+"cc",backdropFilter:"blur(8px)",display:"flex",alignItems:"center",justifyContent:"center",margin:"0 auto 20px"}}><I n={ii} s={28} c={t.td}/></div><div style={{fontSize:17,fontWeight:700,color:t.tm,marginBottom:8}}>{ti}</div><div style={{fontSize:14,color:t.td,lineHeight:1.5}}>{su}</div></div>;
const ScBadge=({score:sc,t})=>{if(!sc)return null;const cs={excellent:t.ok,good:t.bl,average:t.wa,low:t.er};const c=cs[sc.level]||t.td;return<span style={{display:"inline-flex",alignItems:"center",gap:4,padding:"3px 10px",borderRadius:99,fontSize:10,fontWeight:700,background:c+"15",color:c}}><span style={{width:5,height:5,borderRadius:3,background:c,display:"inline-block"}}/>{sc.score}%</span>};
const FiabBadge=({v,t})=>{const c=v>=80?t.ok:v>=60?t.wa:t.er;return<span style={{display:"inline-flex",alignItems:"center",gap:4,padding:"3px 10px",borderRadius:99,fontSize:10,fontWeight:700,background:c+"15",color:c}}><I n="shield" s={10} c={c}/>{v}%</span>};
const StBg=({status:s,t})=>{const m={raw:t.bl,corrected:t.wa,pre_validated:t.ac,validated:t.ok,rejected:t.er,flagged:t.td};const l={raw:"Brut",corrected:"Corrigé",pre_validated:"Pré-validé",validated:"Validé",rejected:"Rejeté",flagged:"Flaggé"};return<Bg c={m[s]||t.td}>{l[s]||s}</Bg>};
const Toast=({msg,t})=>msg?<div style={{position:"fixed",top:16,left:"50%",transform:"translateX(-50%)",padding:"12px 24px",borderRadius:14,background:t.s+"ee",backdropFilter:"blur(12px)",color:t.ok,fontSize:14,fontWeight:600,zIndex:1000,boxShadow:t.sh,animation:"toastIn .3s ease",maxWidth:"90vw",textAlign:"center"}}>{msg}</div>:null;
const Overlay=({children,onClose,t})=><div style={{position:"fixed",inset:0,background:"rgba(0,0,0,.5)",backdropFilter:"blur(8px)",display:"flex",alignItems:"flex-end",justifyContent:"center",zIndex:999,animation:"modalBgIn .2s ease"}} onClick={onClose}><div onClick={e=>e.stopPropagation()} style={{background:t.bgG,borderRadius:"24px 24px 0 0",padding:"28px 24px",width:"100%",maxWidth:640,maxHeight:"90vh",overflowY:"auto",animation:"modalSlideUp .35s cubic-bezier(.25,.46,.45,.94)",border:`1px solid ${t.bd}`,borderBottom:"none"}}>{children}</div></div>;
const Skel=({t})=><div style={{padding:20,position:"relative",zIndex:1}}>{[80,140,200].map((h,i)=><div key={i} style={{height:h,background:t.sa+"88",borderRadius:16,marginBottom:12,animation:"pulse 1.5s ease infinite",animationDelay:`${i*150}ms`}}/>)}</div>;
const Page=({children,t})=><div style={{fontFamily:F,background:t.bgG,color:t.tx,minHeight:"100vh",maxWidth:640,margin:"0 auto",padding:"0 4px",position:"relative"}} className="safe-bottom">{children}</div>;
const LogoByLessan=({t,size=22})=><div style={{display:"flex",alignItems:"center",gap:14}}><div style={{fontSize:size,fontWeight:900,letterSpacing:-1.5,color:t.tx,lineHeight:1}}>annotate<span style={{color:t.ac}}>.</span></div><div style={{width:1,height:size*.75,background:t.bd}}/><a href="https://lessan.co" target="_blank" rel="noopener" style={{fontSize:size*.48,color:t.tm,fontWeight:500,lineHeight:1}}>by <span style={{fontWeight:700,color:t.tx}}>lessan</span><span style={{color:t.ac}}>.</span></a></div>;
const Footer=({t,wide})=><div style={{borderTop:`1px solid ${t.bd}`,marginTop:wide?64:32,position:"relative",zIndex:1}}><div style={{padding:"40px 24px",display:"flex",flexWrap:"wrap",justifyContent:"space-between",alignItems:"center",gap:20,maxWidth:1100,margin:"0 auto"}}><LogoByLessan t={t} size={20}/><div style={{fontSize:12,color:t.td}}>© 2026 lessan. Tous droits réservés.</div></div></div>;
/* LANDING */
const Landing=({onGoLogin,t,theme,toggle})=>{const ctaBtn={background:`linear-gradient(135deg,${t.ac},${t.ac}bb)`,color:"#fff",border:"none",borderRadius:16,padding:"16px 40px",fontSize:17,fontWeight:800,fontFamily:F,boxShadow:t.shC,cursor:"pointer"};return<div style={{fontFamily:F,background:t.bgG,color:t.tx,minHeight:"100vh"}}><div style={{position:"sticky",top:0,zIndex:10,backdropFilter:"blur(16px)",WebkitBackdropFilter:"blur(16px)",background:t.bg+"cc",borderBottom:`1px solid ${t.bd}44`}}><div style={{maxWidth:1100,margin:"0 auto",padding:"16px 24px",display:"flex",justifyContent:"space-between",alignItems:"center"}}><div style={{fontSize:24,fontWeight:900,letterSpacing:-1.5,color:t.tx,lineHeight:1}}>annotate<span style={{color:t.ac}}>.</span></div><div style={{display:"flex",gap:12,alignItems:"center"}}><ThB theme={theme} toggle={toggle} t={t}/><button onClick={onGoLogin} style={{background:`linear-gradient(135deg,${t.ac},${t.ac}cc)`,color:"#fff",border:"none",borderRadius:12,padding:"10px 24px",fontSize:14,fontWeight:700,fontFamily:F,boxShadow:t.shC}}>Se connecter</button></div></div></div><div style={{position:"relative",padding:"72px 0 48px",overflow:"hidden"}}><div style={{position:"absolute",width:400,height:400,borderRadius:"50%",background:t.ac,filter:"blur(140px)",opacity:.07,top:-100,right:-100,pointerEvents:"none"}}/><div style={{position:"absolute",width:250,height:250,borderRadius:"50%",background:t.bl,filter:"blur(120px)",opacity:.05,bottom:-50,left:"20%",pointerEvents:"none"}}/><div style={{maxWidth:1100,margin:"0 auto",padding:"0 24px",textAlign:"center",position:"relative",zIndex:1}}><div className="fi" style={{display:"inline-flex",padding:"8px 20px",borderRadius:99,background:t.ac+"10",marginBottom:24}}><span style={{fontSize:13,fontWeight:700,color:t.ac,letterSpacing:.5}}>CONTRIBUEZ À L'IA DE DEMAIN</span></div><h1 className="land-hero-title fi" style={{fontWeight:900,marginBottom:20,color:t.tx}}>Votre langue<span style={{color:t.ac}}>.</span><br/><span style={{color:t.ac}}>Votre IA.</span></h1><p className="land-hero-sub fi" style={{color:t.tm,lineHeight:1.65,margin:"0 auto 36px",animationDelay:"100ms"}}>Les plus grandes IA du monde ne comprennent pas la Darija. On construit celle qui la comprendra. Participez à l'entraînement de la première IA souveraine en dialecte marocain — et soyez rémunéré pour chaque contribution.</p><div className="fi" style={{animationDelay:"200ms"}}><button onClick={onGoLogin} style={ctaBtn}>Commencer maintenant</button></div></div></div><div style={{padding:"32px 0 56px"}}><div style={{maxWidth:1100,margin:"0 auto",padding:"0 24px"}}><div className="land-stats-row fi" style={{animationDelay:"300ms"}}>{[{v:"1 MAD",l:"par annotation validée"},{v:"60s",l:"par session en moyenne"},{v:"24/7",l:"travaillez quand vous voulez"}].map((s,i)=><div key={i} style={{display:"flex",alignItems:"center",gap:12,padding:"12px 20px",background:t.s+"ee",backdropFilter:"blur(8px)",border:`1px solid ${t.bd}`,borderRadius:14,boxShadow:t.shL}}><span style={{fontSize:22,fontWeight:900,fontFamily:M,color:t.ac}}>{s.v}</span><span style={{fontSize:13,color:t.tm,fontWeight:500}}>{s.l}</span></div>)}</div></div></div><div style={{padding:"0 0 64px"}}><div style={{maxWidth:1100,margin:"0 auto",padding:"0 24px"}}><div className="land-grid-3">{[{icon:"globe",c:t.ac,ti:"Une mission qui a du sens",de:"Les 40 millions de locuteurs de Darija méritent une IA qui les comprend. En annotant, vous entraînez un modèle qui parle votre langue."},{icon:"wallet",c:t.ok,ti:"Chaque contribution mérite sa récompense",de:"Chaque annotation validée vous rapporte 1 MAD. Plus vous êtes rigoureux, plus vous gagnez."},{icon:"phone",c:t.wa,ti:"Depuis votre téléphone, à votre rythme",de:"Pas besoin d'ordinateur. Ouvrez le site, lisez, corrigez, soumettez. 60 secondes par annotation."}].map((s,i)=><div key={i} className="su" style={{padding:"28px 24px",background:t.s+"ee",backdropFilter:"blur(8px)",border:`1px solid ${t.bd}`,borderRadius:24,boxShadow:t.shL,animationDelay:`${100+i*100}ms`}}><div style={{width:52,height:52,borderRadius:16,background:s.c+"12",display:"flex",alignItems:"center",justifyContent:"center",marginBottom:16}}><I n={s.icon} s={24} c={s.c}/></div><div style={{fontSize:18,fontWeight:800,color:t.tx,marginBottom:8}}>{s.ti}</div><div style={{fontSize:15,color:t.tm,lineHeight:1.65}}>{s.de}</div></div>)}</div></div></div><div style={{padding:"0 0 64px"}}><div style={{maxWidth:1100,margin:"0 auto",padding:"0 24px"}}><div style={{textAlign:"center",marginBottom:36}}><span style={{fontSize:12,fontWeight:700,color:t.ac,textTransform:"uppercase",letterSpacing:2}}>Comment ça marche</span><div style={{fontSize:28,fontWeight:900,letterSpacing:-1,marginTop:8,color:t.tx}}>Trois étapes, c'est tout</div></div><div className="land-steps">{[{n:"1",ti:"Lisez le texte",de:"Un texte en Darija s'affiche avec une question et une réponse.",c:t.bl},{n:"2",ti:"Corrigez si besoin",de:"Si vous voyez une erreur, corrigez-la directement.",c:t.ac},{n:"3",ti:"Recevez votre paiement",de:"Si c'est validé, 1 MAD est crédité sur votre compte.",c:t.ok}].map((s,i)=><div key={i} className="su" style={{textAlign:"center",padding:"32px 20px",background:t.s+"ee",backdropFilter:"blur(8px)",border:`1px solid ${t.bd}`,borderRadius:22,boxShadow:t.shL,animationDelay:`${400+i*100}ms`}}><div style={{width:48,height:48,borderRadius:14,background:s.c+"15",display:"flex",alignItems:"center",justifyContent:"center",margin:"0 auto 14px",fontSize:20,fontWeight:900,color:s.c,fontFamily:M}}>{s.n}</div><div style={{fontSize:17,fontWeight:800,color:t.tx,marginBottom:6}}>{s.ti}</div><div style={{fontSize:14,color:t.tm,lineHeight:1.55}}>{s.de}</div></div>)}</div></div></div><div style={{padding:"0 0 0"}}><div style={{maxWidth:1100,margin:"0 auto",padding:"0 24px"}}><div className="land-cta-section"><div className="su"><span style={{fontSize:12,fontWeight:700,color:t.ok,textTransform:"uppercase",letterSpacing:2}}>Qui peut participer</span><div style={{fontSize:28,fontWeight:900,letterSpacing:-1,marginTop:8,marginBottom:16,color:t.tx}}>On cherche des gens comme vous</div><div style={{fontSize:16,color:t.tm,lineHeight:1.7}}>Vous parlez Darija au quotidien. Vous savez faire la différence entre une phrase naturelle et une phrase bizarre. C'est tout ce qu'il faut.</div><div style={{marginTop:20,display:"flex",flexDirection:"column",gap:12}}>{["Vous parlez Darija couramment","Vous avez un smartphone et une connexion internet","Vous êtes rigoureux et attentif"].map((tx,i)=><div key={i} style={{display:"flex",alignItems:"center",gap:10}}><div style={{width:24,height:24,borderRadius:8,background:t.ok+"15",display:"flex",alignItems:"center",justifyContent:"center"}}><I n="check" s={14} c={t.ok}/></div><span style={{fontSize:15,color:t.tx,fontWeight:500}}>{tx}</span></div>)}</div></div><div className="su" style={{padding:"36px 28px",background:t.s+"ee",backdropFilter:"blur(8px)",border:`1px solid ${t.bd}`,borderRadius:24,boxShadow:t.sh,animationDelay:"200ms"}}><div style={{fontSize:22,fontWeight:900,letterSpacing:-.5,marginBottom:6,color:t.tx}}>Prêt à commencer ?</div><div style={{fontSize:14,color:t.tm,marginBottom:24,lineHeight:1.6}}>Inscrivez-vous ou connectez-vous avec les identifiants communiqués par votre administrateur.</div><button onClick={onGoLogin} style={{...ctaBtn,width:"100%",padding:"16px 24px"}}>S'inscrire / Se connecter</button></div></div></div></div><Footer t={t} wide/></div>};
/* AUTH */
const AuthScreen=({onLogin,onBack,t,theme,toggle,role})=>{const[mode,setMode]=useState("login");const[n,setN]=useState(""),[pin,setP]=useState(""),[err,setE]=useState(""),[ld,setL]=useState(false);const[fn,setFn]=useState(""),[ln,setLn]=useState(""),[em,setEm]=useState(""),[ph,setPh]=useState(""),[edu,setEdu]=useState(""),[regOk,setRegOk]=useState(false);const submitLogin=async()=>{if(!n.trim()){setE("Entrez votre identifiant");return}if(pin.length<4){setE("Code 4 chiffres minimum");return}setL(true);setE("");try{const r=await ap.p("/auth/login",{name:n.trim(),pin,role});ap.st(r.token);localStorage.setItem("au",JSON.stringify(r.user));onLogin(r.user)}catch(e){setE(e.message);setP("")}setL(false)};const submitRegister=async()=>{if(!fn.trim()||!ln.trim()){setE("Nom et prénom requis");return}if(!em.trim()||!em.includes("@")){setE("Email invalide");return}if(!ph.trim()){setE("Téléphone requis");return}setL(true);setE("");try{await ap.p("/auth/register",{first_name:fn.trim(),last_name:ln.trim(),email:em.trim(),phone:ph.trim(),education:edu.trim()});setRegOk(true)}catch(e){setE(e.message)}setL(false)};const hk=e=>{if(e.key==="Enter"){if(mode==="login")submitLogin();else submitRegister()}};const showReg=role==="worker";
if(regOk)return<div style={{fontFamily:F,background:t.bgG,color:t.tx,display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center",padding:24,textAlign:"center",minHeight:"100vh"}}><Orbs t={t}/><div className="pi" style={{width:72,height:72,borderRadius:20,background:t.ok+"15",display:"flex",alignItems:"center",justifyContent:"center",marginBottom:24,position:"relative",zIndex:1}}><I n="check" s={32} c={t.ok}/></div><div style={{fontSize:22,fontWeight:800,marginBottom:8,position:"relative",zIndex:1}}>Demande envoyée !</div><div style={{fontSize:15,color:t.tm,lineHeight:1.6,maxWidth:340,marginBottom:28,position:"relative",zIndex:1}}>Votre candidature a été transmise. Vous recevrez vos identifiants par email.</div><Bt v="ghost" t={t} onClick={onBack} style={{position:"relative",zIndex:1}}>Retour</Bt></div>;
return<div style={{fontFamily:F,background:t.bgG,color:t.tx,display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center",padding:24,position:"relative",minHeight:"100vh"}}><Orbs t={t}/><div style={{position:"absolute",top:20,left:20,zIndex:2}}>{onBack&&<button onClick={onBack} style={{background:t.sa+"88",backdropFilter:"blur(8px)",border:`1px solid ${t.bd}`,borderRadius:12,padding:9,display:"flex"}}><I n="back" s={18} c={t.tm}/></button>}</div><div style={{position:"absolute",top:20,right:20,zIndex:2}}><ThB theme={theme} toggle={toggle} t={t}/></div><div style={{textAlign:"center",marginBottom:28,marginTop:48,width:"100%",maxWidth:420,position:"relative",zIndex:1}} className="fi"><div style={{fontSize:32,fontWeight:900,letterSpacing:-1.5,color:t.tx,lineHeight:1}}>annotate<span style={{color:t.ac}}>.</span></div></div>{showReg&&<div style={{padding:"0 0 14px",width:"100%",maxWidth:420,position:"relative",zIndex:1}}><TB tabs={[{id:"login",l:"Connexion"},{id:"register",l:"Inscription"}]} active={mode} onChange={setMode} t={t}/></div>}<div className="su" style={{width:"100%",maxWidth:420,position:"relative",zIndex:1}}><Cd t={t} style={{padding:"32px 28px",boxShadow:t.sh}}>{mode==="login"?<><div style={{display:"flex",flexDirection:"column",gap:16}}><div><label style={{fontSize:11,fontWeight:700,color:t.tm,display:"block",marginBottom:6,textTransform:"uppercase",letterSpacing:1}}>Identifiant</label><In value={n} onChange={v=>{setN(v);setE("")}} placeholder="Votre identifiant" t={t} onKey={hk}/></div><div><label style={{fontSize:11,fontWeight:700,color:t.tm,display:"block",marginBottom:6,textTransform:"uppercase",letterSpacing:1}}>Code PIN</label><In type="password" value={pin} onChange={v=>{setP(v);setE("")}} placeholder="• • • •" t={t} onKey={hk} style={{fontSize:22,letterSpacing:10,fontFamily:M,textAlign:"center"}}/></div></div>{err&&<div className="si" style={{color:t.er,fontSize:13,marginTop:14,textAlign:"center",padding:"10px 14px",background:t.er+"10",borderRadius:12,fontWeight:600}}>{err}</div>}<Bt full onClick={submitLogin} dis={ld} t={t} style={{marginTop:20,padding:"16px",fontSize:16}}>{ld?"Connexion...":"Se connecter"}</Bt></>:<><div style={{display:"flex",flexDirection:"column",gap:14}}><div style={{display:"flex",gap:10}}><div style={{flex:1}}><label style={{fontSize:11,fontWeight:700,color:t.tm,display:"block",marginBottom:6,textTransform:"uppercase",letterSpacing:1}}>Prénom</label><In value={fn} onChange={v=>{setFn(v);setE("")}} placeholder="Prénom" t={t} onKey={hk}/></div><div style={{flex:1}}><label style={{fontSize:11,fontWeight:700,color:t.tm,display:"block",marginBottom:6,textTransform:"uppercase",letterSpacing:1}}>Nom</label><In value={ln} onChange={v=>{setLn(v);setE("")}} placeholder="Nom" t={t} onKey={hk}/></div></div><div><label style={{fontSize:11,fontWeight:700,color:t.tm,display:"block",marginBottom:6,textTransform:"uppercase",letterSpacing:1}}>Email</label><In type="email" value={em} onChange={v=>{setEm(v);setE("")}} placeholder="votre@email.com" t={t} onKey={hk}/></div><div><label style={{fontSize:11,fontWeight:700,color:t.tm,display:"block",marginBottom:6,textTransform:"uppercase",letterSpacing:1}}>Téléphone</label><In value={ph} onChange={v=>{setPh(v);setE("")}} placeholder="06 XX XX XX XX" t={t} onKey={hk}/></div><div><label style={{fontSize:11,fontWeight:700,color:t.tm,display:"block",marginBottom:6,textTransform:"uppercase",letterSpacing:1}}>Niveau d'étude</label><In value={edu} onChange={v=>setEdu(v)} placeholder="Bac+2, Licence, etc." t={t} onKey={hk}/></div></div>{err&&<div className="si" style={{color:t.er,fontSize:13,marginTop:14,textAlign:"center",padding:"10px 14px",background:t.er+"10",borderRadius:12,fontWeight:600}}>{err}</div>}<Bt full onClick={submitRegister} dis={ld} t={t} style={{marginTop:20,padding:"16px",fontSize:16}}>{ld?"Envoi...":"Envoyer ma candidature"}</Bt><div style={{textAlign:"center",marginTop:12,fontSize:12,color:t.td}}>Identifiants envoyés par email après validation.</div></>}</Cd></div><Footer t={t}/></div>};
/* WORKER */
const AnimNum=({value:v,t,size=48,color})=>{const[display,setD]=useState(v);const ref=useRef(null);useEffect(()=>{const start=display;const diff=v-start;if(diff===0)return;const dur=400;const st=performance.now();const tick=(now)=>{const p=Math.min(1,(now-st)/dur);const eased=1-Math.pow(1-p,3);setD(start+diff*eased);if(p<1)requestAnimationFrame(tick)};requestAnimationFrame(tick)},[v]);return<span style={{fontSize:size,fontWeight:900,fontFamily:M,color:color||t.wa,lineHeight:1,transition:"color .3s"}}>{display.toFixed(1)}</span>};
const WV=({user:u,t,theme:th,toggle:tg})=>{const[tab,setTab]=useState("annotate"),[task,setT]=useState(null),[st,setSt]=useState({submitted:0,confirmed:0,owed:0,remaining:0,paid:0}),[earn,setEarn]=useState(null),[eI,setEI]=useState(""),[eO,setEO]=useState(""),[ld,setLd]=useState(true),[toast,setToast]=useState(""),[key,setKey]=useState(0),[sessionCount,setSC]=useState(0);const flash=m=>{setToast(m);setTimeout(()=>setToast(""),2500)};const lo=useCallback(async()=>{try{const[tk,s,e]=await Promise.all([ap.g("/tasks/next"),ap.g("/tasks/my-stats"),ap.g("/tasks/my-earnings")]);setT(tk);setSt(s);setEarn(e);if(tk){setEI(tk.instruction);setEO(tk.output);setKey(k=>k+1)}}catch{}setLd(false)},[]);useEffect(()=>{lo()},[lo]);const sub=async(a,i,o)=>{if(!task)return;try{await ap.p(`/tasks/${task.id}/annotate`,{action:a,edited_instruction:i,edited_output:o});if(a==="corrected"){setSC(c=>c+1);flash("+1 MAD ✓")}else flash("Flaggé ✓");setLd(true);await lo()}catch(e){flash("Erreur: "+e.message)}};
if(ld)return<Page t={t}><Orbs t={t}/><Skel t={t}/></Page>;
if(!task&&tab==="annotate")return<Page t={t}><Orbs t={t}/><Toast msg={toast} t={t}/><Hd title={`Salam ${u.name}`} t={t} right={<RB theme={th} toggle={tg} t={t}/>}/><div style={{padding:"0 20px",marginBottom:20,position:"relative",zIndex:1}}><TB tabs={[{id:"annotate",l:"Annoter"},{id:"dashboard",l:"Mes gains"}]} active={tab} onChange={setTab} t={t}/></div><div style={{padding:"0 20px",position:"relative",zIndex:1}} className="fi"><Cd t={t} style={{textAlign:"center",padding:"48px 24px",marginBottom:20}}><div style={{width:80,height:80,borderRadius:24,background:`linear-gradient(135deg,${t.ok}20,${t.ac}20)`,display:"flex",alignItems:"center",justifyContent:"center",margin:"0 auto 20px"}}><I n="trophy" s={36} c={t.ok}/></div><div style={{fontSize:22,fontWeight:800,color:t.tx,marginBottom:6}}>Tout est fait !</div><div style={{fontSize:14,color:t.tm,lineHeight:1.6,marginBottom:24}}>Aucun item disponible pour le moment.<br/>Revenez bientôt pour gagner plus.</div>{earn&&<div style={{background:`linear-gradient(135deg,${t.ac}08,${t.wa}08)`,borderRadius:16,padding:"20px 24px",border:`1px solid ${t.ac}15`}}><div style={{fontSize:10,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:1,marginBottom:8}}>Votre solde</div><AnimNum value={earn.owed} t={t} size={44} color={earn.owed>0?t.wa:t.ok}/><span style={{fontSize:16,color:t.tm,fontWeight:600,marginLeft:6}}>MAD</span><div style={{display:"flex",justifyContent:"center",gap:20,marginTop:14}}><div style={{textAlign:"center"}}><div style={{fontSize:16,fontWeight:800,fontFamily:M,color:t.ok}}>{earn.confirmed}</div><div style={{fontSize:9,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:.5}}>validés</div></div><div style={{textAlign:"center"}}><div style={{fontSize:16,fontWeight:800,fontFamily:M,color:t.bl}}>{earn.submitted}</div><div style={{fontSize:9,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:.5}}>soumis</div></div>{earn.paid>0&&<div style={{textAlign:"center"}}><div style={{fontSize:16,fontWeight:800,fontFamily:M,color:t.ok}}>{earn.paid.toFixed(1)}</div><div style={{fontSize:9,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:.5}}>payé</div></div>}</div></div>}</Cd></div><Footer t={t}/></Page>;
return<Page t={t}><Orbs t={t}/><Toast msg={toast} t={t}/><Hd title={`Salam ${u.name}`} subtitle={`${st.remaining} disponible${st.remaining>1?"s":""}`} t={t} right={<RB theme={th} toggle={tg} t={t}/>}/><div style={{padding:"0 20px",marginBottom:16,position:"relative",zIndex:1}}><TB tabs={[{id:"annotate",l:"Annoter"},{id:"dashboard",l:"Mes gains"}]} active={tab} onChange={setTab} t={t}/></div>
{tab==="annotate"&&<div style={{padding:"0 20px",position:"relative",zIndex:1}} key={key} className="su">
<Cd t={t} style={{marginBottom:16,padding:0,overflow:"hidden",border:`1px solid ${t.ac}22`}} anim="fi">
<div style={{background:`linear-gradient(135deg,${t.ac}10,${t.wa}08)`,padding:"20px 24px"}}>
<div style={{display:"flex",alignItems:"center",justifyContent:"space-between",flexWrap:"wrap",gap:12}}>
<div>
<div style={{fontSize:9,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:1.5,marginBottom:6}}>Gains potentiels</div>
<div style={{display:"flex",alignItems:"baseline",gap:4}}><AnimNum value={st.submitted*1.0} t={t} size={40} color={t.wa}/><span style={{fontSize:14,color:t.tm,fontWeight:600}}>MAD</span></div>
<div style={{fontSize:11,color:t.td,marginTop:4}}>{st.confirmed} validés sur {st.submitted} soumis</div>
</div>
<div style={{display:"flex",gap:10}}>
{sessionCount>0&&<div className="pi" style={{textAlign:"center",padding:"8px 14px",background:t.ok+"12",borderRadius:12}}><div style={{fontSize:20,fontWeight:900,fontFamily:M,color:t.ok}}>{sessionCount}</div><div style={{fontSize:8,fontWeight:700,color:t.ok,textTransform:"uppercase",letterSpacing:.5}}>session</div></div>}
<div style={{textAlign:"center",padding:"8px 14px",background:t.ac+"12",borderRadius:12}}><div style={{fontSize:20,fontWeight:900,fontFamily:M,color:t.ac}}>{st.remaining}</div><div style={{fontSize:8,fontWeight:700,color:t.ac,textTransform:"uppercase",letterSpacing:.5}}>restants</div></div>
</div></div></div>
<div style={{padding:"0 24px 14px",marginTop:"-1px",background:t.s+"ee"}}><div style={{height:6,background:t.sa,borderRadius:99,overflow:"hidden",marginTop:12}}><div style={{height:"100%",width:`${st.submitted+st.remaining>0?Math.min(100,(st.submitted/(st.submitted+st.remaining))*100):0}%`,background:`linear-gradient(90deg,${t.ac},${t.ok})`,borderRadius:99,transition:"width .8s cubic-bezier(.25,.46,.45,.94)"}}/></div><div style={{display:"flex",justifyContent:"space-between",marginTop:6}}><span style={{fontSize:10,color:t.td}}>{st.submitted} soumis</span><span style={{fontSize:10,fontWeight:700,color:t.ok}}>{st.remaining>0?`+${st.remaining} à faire`:""}</span></div></div>
</Cd>
<Cd t={t} style={{marginBottom:14,padding:20}} anim="fi" delay={100}>
<div style={{display:"flex",justifyContent:"space-between",marginBottom:14}}><Bg c={t.bl}>Question</Bg><Bg c={t.td}>{task.domain}</Bg></div>
<TA value={eI} onChange={setEI} rows={3} t={t}/>
</Cd>
<Cd t={t} style={{marginBottom:20,padding:20}} anim="fi" delay={150}>
<div style={{marginBottom:14}}><Bg c={t.ok}>Réponse</Bg></div>
<TA value={eO} onChange={setEO} rows={8} t={t}/>
</Cd>
<div style={{display:"flex",gap:10,paddingBottom:32}}>
<Bt full v="success" t={t} onClick={()=>sub("corrected",eI,eO)} style={{padding:"16px 22px",fontSize:16}}><I n="check" s={20} c="#fff"/> Soumettre (+1 MAD)</Bt>
<Bt v="ghost" t={t} onClick={()=>{if(confirm("Signaler comme inutilisable ?"))sub("flagged")}} style={{padding:"16px"}}><I n="flag" s={20} c={t.er}/></Bt>
</div></div>}
{tab==="dashboard"&&<div style={{padding:"0 20px 32px",position:"relative",zIndex:1}} className="su">{earn?<>
<Cd t={t} style={{marginBottom:20,padding:"28px 24px",background:`linear-gradient(135deg,${t.ac}08,${t.wa}08)`,border:`1px solid ${t.ac}22`}} anim="pi">
<div style={{textAlign:"center"}}>
<div style={{fontSize:10,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:1.5,marginBottom:8}}>Solde à recevoir</div>
<div style={{display:"flex",alignItems:"baseline",justifyContent:"center",gap:6}}><AnimNum value={earn.owed} t={t} size={56} color={earn.owed>0?t.wa:t.ok}/><span style={{fontSize:20,color:t.tm,fontWeight:600}}>MAD</span></div>
<div style={{display:"flex",justifyContent:"center",gap:24,marginTop:16}}>
<div style={{textAlign:"center"}}><div style={{fontSize:20,fontWeight:800,fontFamily:M,color:t.bl}}>{earn.submitted}</div><div style={{fontSize:9,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:.5}}>soumis</div></div>
<div style={{textAlign:"center"}}><div style={{fontSize:20,fontWeight:800,fontFamily:M,color:t.ok}}>{earn.confirmed}</div><div style={{fontSize:9,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:.5}}>validés</div></div>
{earn.paid>0&&<div style={{textAlign:"center"}}><div style={{fontSize:20,fontWeight:800,fontFamily:M,color:t.ok}}>{earn.paid.toFixed(1)}</div><div style={{fontSize:9,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:.5}}>payé</div></div>}
</div></div></Cd>
<div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:10}}>
<SC l="Aujourd'hui" v={earn.today.items} sub={`${earn.today.amount} MAD`} icon="check" c={t.ok} t={t} d={0}/>
<SC l="Cette semaine" v={earn.week.items} sub={`${earn.week.amount} MAD`} icon="check" c={t.bl} t={t} d={50}/>
<SC l="Ce mois" v={earn.month.items} sub={`${earn.month.amount} MAD`} icon="check" c={t.ac} t={t} d={100}/>
<SC l="Total" v={earn.total.items} sub={`${earn.total.amount} MAD`} icon="chart" c={t.wa} t={t} d={150}/>
</div></>:<Skel t={t}/>}</div>}
<Footer t={t}/></Page>};
const ReviewView=({user:u,t,theme:th,toggle:tg,isStaff,isAdmin,onBack:ob})=>{const[task,setT]=useState(null),[cnt,setCnt]=useState(0),[ld,setLd]=useState(true),[ed,setEd]=useState(false),[eI,setEI]=useState(""),[eO,setEO]=useState(""),[toast,setToast]=useState(""),[key,setKey]=useState(0);const flash=m=>{setToast(m);setTimeout(()=>setToast(""),2500)};const ep=isStaff?"/staff":"/validation";const lo=useCallback(async()=>{try{const[tk,c]=await Promise.all([ap.g(`${ep}/next`),ap.g(`${ep}/count`)]);setT(tk);setCnt(c.count);if(tk){setEI(tk.final_instruction||tk.edited_instruction||tk.instruction);setEO(tk.final_output||tk.edited_output||tk.output);setEd(false);setKey(k=>k+1)}}catch{}setLd(false)},[]);useEffect(()=>{lo()},[lo]);const act=async(action,we)=>{if(!task)return;try{if(isStaff){await ap.p(`/staff/${task.id}`,{action,edited_instruction:we?eI:undefined,edited_output:we?eO:undefined})}else{await ap.p(`/validation/${task.id}`,{accepted:action==="accept",edited_instruction:we?eI:undefined,edited_output:we?eO:undefined})}flash(action==="accept"?(we?"Corrigé & validé ✓":"Accepté ✓"):"Rejeté ✓");setLd(true);await lo()}catch(e){flash("Erreur: "+e.message)}};const rt=isStaff?"Pré-validation":"Validation";if(ld)return<Page t={t}><Orbs t={t}/><Skel t={t}/></Page>;if(!task)return<Page t={t}><Orbs t={t}/><Toast msg={toast} t={t}/><Hd title={isAdmin?rt:`Salam ${u.name}`} subtitle={isStaff?"Staff":"Validateur"} onBack={ob} t={t} right={!isAdmin?<RB theme={th} toggle={tg} t={t}/>:undefined}/><Em icon="check" title="Rien à traiter" sub={isStaff?"En attente de corrections.":"En attente de pré-validations."} t={t}/></Page>;const wk=task.corrected_by_name||"—";const ws=task.worker_score;const sf=task.staff_fiability;const sn=task.staff_name;return<Page t={t}><Orbs t={t}/><Toast msg={toast} t={t}/><Hd title={isAdmin?rt:`Salam ${u.name}`} subtitle={`${cnt} en attente`} onBack={ob} t={t} right={!isAdmin?<RB theme={th} toggle={tg} t={t}/>:undefined}/><div style={{padding:"0 20px",position:"relative",zIndex:1}} key={key} className="su"><div style={{display:"flex",alignItems:"center",gap:10,marginBottom:10,padding:"10px 14px",background:t.sa+"88",backdropFilter:"blur(8px)",borderRadius:14}}><div style={{width:32,height:32,borderRadius:10,background:t.bl+"18",display:"flex",alignItems:"center",justifyContent:"center",fontSize:14,fontWeight:800,color:t.bl}}>{wk[0]}</div><div style={{flex:1}}><span style={{fontSize:13,color:t.tm}}>Annotateur: </span><span style={{fontSize:14,fontWeight:700,color:t.tx}}>{wk}</span></div>{ws&&<ScBadge score={ws} t={t}/>}</div>{!isStaff&&sn&&<div style={{display:"flex",alignItems:"center",gap:10,marginBottom:14,padding:"10px 14px",background:t.sa+"88",backdropFilter:"blur(8px)",borderRadius:14}}><div style={{width:32,height:32,borderRadius:10,background:t.ac+"18",display:"flex",alignItems:"center",justifyContent:"center",fontSize:14,fontWeight:800,color:t.ac}}>{sn[0]}</div><div style={{flex:1}}><span style={{fontSize:13,color:t.tm}}>Staff: </span><span style={{fontSize:14,fontWeight:700,color:t.tx}}>{sn}</span></div>{sf!==undefined&&<FiabBadge v={sf} t={t}/>}{task.staff_corrected===1&&<Bg c={t.wa}>a corrigé</Bg>}</div>}<Cd t={t} style={{marginBottom:14,padding:18}} anim="fi" delay={100}><div style={{display:"flex",justifyContent:"space-between",marginBottom:12}}><Bg c={t.bl}>Question</Bg>{!ed&&<button onClick={()=>setEd(true)} style={{background:t.ac+"12",border:"none",borderRadius:10,padding:"6px 12px",display:"flex",alignItems:"center",gap:5,color:t.ac,fontSize:12,fontWeight:700}}><I n="edit" s={13} c={t.ac}/> Corriger</button>}</div>{ed?<TA value={eI} onChange={setEI} rows={3} t={t}/>:<div style={{fontSize:15,lineHeight:1.7,color:t.tx}}>{task.final_instruction||task.edited_instruction||task.instruction}</div>}</Cd><Cd t={t} style={{marginBottom:20,padding:18}} anim="fi" delay={150}><div style={{marginBottom:12}}><Bg c={t.ok}>Réponse</Bg></div>{ed?<TA value={eO} onChange={setEO} rows={7} t={t}/>:<div style={{fontSize:15,lineHeight:1.7,color:t.tx}}>{task.final_output||task.edited_output||task.output}</div>}</Cd>{ed&&<div className="si" style={{fontSize:13,color:t.wa,textAlign:"center",marginBottom:16,padding:"10px 14px",background:t.wa+"10",borderRadius:12,fontWeight:600}}>⚠ Si vous corrigez, l'annotateur n'est pas rémunéré.</div>}<div style={{display:"flex",gap:10,paddingBottom:32}}>{ed?<><Bt full v="warn" t={t} onClick={()=>act("accept",true)}><I n="check" s={18} c="#fff"/> Valider ma correction</Bt><Bt v="ghost" t={t} onClick={()=>{setEI(task.final_instruction||task.edited_instruction||task.instruction);setEO(task.final_output||task.edited_output||task.output);setEd(false)}} style={{padding:"14px 16px"}}><I n="x" s={18} c={t.tm}/></Bt></>:<><Bt full v="success" t={t} onClick={()=>act("accept",false)}><I n="check" s={18} c="#fff"/> Accepter</Bt><Bt v="danger" t={t} onClick={()=>act("reject",false)} style={{padding:"14px 18px",borderRadius:16}}><I n="x" s={18} c="#fff"/></Bt></>}</div></div></Page>};
/* MODALS */
const EditModal=({task:tk,onSave:os,onClose:oc,t})=>{const[inst,setI]=useState(tk.final_instruction||tk.edited_instruction||tk.instruction);const[out,setO]=useState(tk.final_output||tk.edited_output||tk.output);const[sav,setSav]=useState(false);const save=async()=>{setSav(true);try{await ap.put(`/admin/tasks/${tk.id}`,{instruction:inst,output:out});os()}catch{}setSav(false)};return<Overlay onClose={oc} t={t}><div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:20}}><div style={{fontSize:18,fontWeight:800,color:t.tx}}>Éditer</div><button onClick={oc} style={{background:t.sa,border:"none",borderRadius:10,padding:8}}><I n="x" s={18} c={t.tm}/></button></div><div style={{marginBottom:14}}><div style={{fontSize:11,fontWeight:700,color:t.tm,textTransform:"uppercase",marginBottom:8}}>Question</div><TA value={inst} onChange={setI} rows={3} t={t}/></div><div style={{marginBottom:20}}><div style={{fontSize:11,fontWeight:700,color:t.tm,textTransform:"uppercase",marginBottom:8}}>Réponse</div><TA value={out} onChange={setO} rows={6} t={t}/></div><div style={{display:"flex",gap:10}}><Bt full v="success" t={t} onClick={save} dis={sav}>{sav?"...":"Sauvegarder"}</Bt><Bt v="ghost" t={t} onClick={oc}>Annuler</Bt></div></Overlay>};
const NewUserModal=({onSave:os,onClose:oc,t})=>{const[n,setN]=useState(""),[pin,setP]=useState(""),[role,setR]=useState("worker"),[err,setE]=useState(""),[sav,setSav]=useState(false);const save=async()=>{if(!n.trim()||pin.length<4){setE("Identifiant + code 4 chiffres");return}setSav(true);try{await ap.p("/admin/users",{name:n.trim(),pin,role});os()}catch(e){setE(e.message)}setSav(false)};return<Overlay onClose={oc} t={t}><div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:20}}><div style={{fontSize:18,fontWeight:800,color:t.tx}}>Nouveau compte</div><button onClick={oc} style={{background:t.sa,border:"none",borderRadius:10,padding:8}}><I n="x" s={18} c={t.tm}/></button></div><div style={{display:"flex",gap:6,marginBottom:20}}>{["worker","staff","validator"].map(r=><button key={r} onClick={()=>setR(r)} style={{flex:1,padding:"12px 8px",borderRadius:14,border:"none",background:role===r?`linear-gradient(135deg,${t.ac},${t.ac}cc)`:t.sa,color:role===r?"#fff":t.tm,fontSize:13,fontWeight:700,fontFamily:F,minWidth:80}}>{r==="worker"?"Annotateur":r==="staff"?"Staff":"Validateur"}</button>)}</div><div style={{display:"flex",flexDirection:"column",gap:14,marginBottom:20}}><In value={n} onChange={setN} placeholder="Identifiant" t={t}/><In type="password" value={pin} onChange={setP} placeholder="Code 4 chiffres" t={t}/></div>{err&&<div style={{color:t.er,fontSize:13,marginBottom:12,textAlign:"center",fontWeight:600}}>{err}</div>}<Bt full onClick={save} dis={sav} t={t}>{sav?"...":"Créer"}</Bt></Overlay>};
const GoldenModal=({onSave:os,onClose:oc,t})=>{const[inst,setI]=useState(""),[out,setO]=useState(""),[gi,setGI]=useState(""),[go,setGO]=useState(""),[sav,setSav]=useState(false);const save=async()=>{if(!inst.trim()||!out.trim()||!gi.trim()||!go.trim())return;setSav(true);try{await ap.p("/admin/golden",{instruction:inst,output:out,golden_instruction:gi,golden_output:go});os()}catch{}setSav(false)};return<Overlay onClose={oc} t={t}><div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:20}}><div style={{fontSize:18,fontWeight:800,color:t.tx}}>Golden Item</div><button onClick={oc} style={{background:t.sa,border:"none",borderRadius:10,padding:8}}><I n="x" s={18} c={t.tm}/></button></div><div style={{fontSize:13,color:t.tm,marginBottom:16,lineHeight:1.5}}>L'annotateur verra la version avec erreurs.</div><div style={{marginBottom:10}}><div style={{fontSize:11,fontWeight:700,color:t.er,textTransform:"uppercase",marginBottom:6}}>Question (avec erreurs)</div><TA value={inst} onChange={setI} rows={2} t={t} ph="Ce que l'annotateur verra"/></div><div style={{marginBottom:10}}><div style={{fontSize:11,fontWeight:700,color:t.er,textTransform:"uppercase",marginBottom:6}}>Réponse (avec erreurs)</div><TA value={out} onChange={setO} rows={3} t={t}/></div><div style={{marginBottom:10}}><div style={{fontSize:11,fontWeight:700,color:t.ok,textTransform:"uppercase",marginBottom:6}}>Question parfaite</div><TA value={gi} onChange={setGI} rows={2} t={t}/></div><div style={{marginBottom:16}}><div style={{fontSize:11,fontWeight:700,color:t.ok,textTransform:"uppercase",marginBottom:6}}>Réponse parfaite</div><TA value={go} onChange={setGO} rows={3} t={t}/></div><Bt full v="success" t={t} onClick={save} dis={sav}>{sav?"...":"Insérer"}</Bt></Overlay>};
/* ADMIN */
const AV=({user:u,t,theme:th,toggle:tg})=>{const[tab,setTab]=useState("overview"),[st,setSt]=useState({total:0,raw:0,corrected:0,pre_validated:0,validated:0,rejected:0,flagged:0,archived:0,golden_count:0,auto_validated:0,pending_registrations:0,archive_threshold:100}),[tm,setTm]=useState({workers:[],staff:[],validators:[],total_owed:0,total_paid:0}),[rv,setRv]=useState(null),[msg,setMsg]=useState(""),[items,setItems]=useState([]),[itTotal,setItT]=useState(0),[itPage,setItP]=useState(1),[itFilter,setItF]=useState(""),[editTk,setEditTk]=useState(null),[showNU,setShowNU]=useState(false),[showGold,setShowGold]=useState(false),[regs,setRegs]=useState([]),[archives,setArchives]=useState([]),[archiving,setArchiving]=useState(false);const fr=useRef(null);
const lo=useCallback(async()=>{try{const[s,t]=await Promise.all([ap.g("/admin/stats"),ap.g("/admin/team")]);setSt(s);setTm(t)}catch{}},[]);
const loadItems=useCallback(async(pg=1,fl="")=>{try{let q=`/admin/tasks?page=${pg}&per_page=15`;if(fl)q+=`&status=${fl}`;const r=await ap.g(q);setItems(r.tasks);setItT(r.total);setItP(r.page)}catch{}},[]);
const loadRegs=useCallback(async()=>{try{setRegs(await ap.g("/admin/registrations?status=pending"))}catch{}},[]);
const loadArchives=useCallback(async()=>{try{setArchives(await ap.g("/admin/archives"))}catch{}},[]);
useEffect(()=>{lo()},[lo]);useEffect(()=>{if(tab==="items")loadItems(1,itFilter);if(tab==="team")loadRegs();if(tab==="data"){loadArchives()}},[tab]);
const hf=async e=>{const f=e.target.files?.[0];if(!f)return;try{const r=await ap.uf("/admin/import-file",f);setMsg(`${r.imported} items importés ✓`);setTimeout(()=>setMsg(""),3000);lo()}catch(er){setMsg("Erreur: "+er.message)}e.target.value=""};
const doArchive=async()=>{if(!confirm(`Archiver ${st.validated} items validés ? Ils seront téléchargés et retirés du dashboard.`))return;setArchiving(true);try{const r=await ap.p("/admin/archive",{});const b=new Blob([JSON.stringify(r.dataset,null,2)],{type:"application/json"});const u=URL.createObjectURL(b);const a=document.createElement("a");a.href=u;a.download=`${r.batch}.json`;a.click();URL.revokeObjectURL(u);setMsg(`${r.count} items archivés → ${r.batch}.json ✓`);setTimeout(()=>setMsg(""),4000);lo();loadArchives()}catch(e){setMsg("Erreur: "+e.message)}setArchiving(false)};
const dlArchive=async(bid)=>{try{const r=await fetch(`/api/admin/archives/${bid}/download`,{headers:ap.h()});const b=await r.blob();const u=URL.createObjectURL(b);const a=document.createElement("a");a.href=u;a.download=`${bid}.json`;a.click();URL.revokeObjectURL(u)}catch{}};
const payW=async(wid)=>{try{await ap.p(`/admin/users/${wid}/pay`,{});setMsg("Paiement enregistré ✓");setTimeout(()=>setMsg(""),3000);lo()}catch(e){setMsg("Erreur: "+e.message)}};
const regAction=async(id,action)=>{try{await ap.p(`/admin/registrations/${id}/${action}`,{});setMsg(action==="approve"?"Approuvée ✓":"Refusée");setTimeout(()=>setMsg(""),3000);loadRegs();lo()}catch(e){setMsg("Erreur: "+e.message)}};
if(rv==="staff")return<ReviewView user={u} t={t} theme={th} toggle={tg} isStaff isAdmin onBack={()=>{setRv(null);lo()}}/>;if(rv==="validator")return<ReviewView user={u} t={t} theme={th} toggle={tg} isAdmin onBack={()=>{setRv(null);lo()}}/>;
return<Page t={t}><Orbs t={t}/><input ref={fr} type="file" accept=".json" onChange={hf} style={{display:"none"}}/>{editTk&&<EditModal task={editTk} t={t} onClose={()=>setEditTk(null)} onSave={()=>{setEditTk(null);loadItems(itPage,itFilter);lo()}}/>}{showNU&&<NewUserModal t={t} onClose={()=>setShowNU(false)} onSave={()=>{setShowNU(false);lo();setMsg("Compte créé ✓");setTimeout(()=>setMsg(""),2000)}}/>}{showGold&&<GoldenModal t={t} onClose={()=>setShowGold(false)} onSave={()=>{setShowGold(false);lo();setMsg("Golden créé ✓");setTimeout(()=>setMsg(""),2000)}}/>}<Hd title={<span>annotate<span style={{color:t.ac}}>.</span></span>} subtitle={`${u.name} — Admin`} t={t} right={<RB theme={th} toggle={tg} t={t}/>}/><div style={{padding:"0 20px",marginBottom:20,position:"relative",zIndex:1}}><TB tabs={[{id:"overview",l:"Dashboard"},{id:"items",l:"Items"},{id:"team",l:"Équipe"},{id:"data",l:"Data"}]} active={tab} onChange={setTab} t={t}/></div>{msg&&<Toast msg={msg} t={t}/>}

{tab==="overview"&&<div style={{padding:"0 20px 32px",position:"relative",zIndex:1}} className="su">
{st.pending_registrations>0&&<Cd t={t} onClick={()=>setTab("team")} style={{marginBottom:14,cursor:"pointer",border:`1.5px solid ${t.ok}44`,padding:16}} anim="pi"><div style={{display:"flex",alignItems:"center",justifyContent:"space-between"}}><div><div style={{fontSize:14,fontWeight:700,color:t.ok}}>{st.pending_registrations} candidature{st.pending_registrations>1?"s":""}</div><div style={{fontSize:11,color:t.tm,marginTop:2}}>En attente</div></div><I n="user" s={18} c={t.ok}/></div></Cd>}
{st.validated>=st.archive_threshold&&<Cd t={t} onClick={()=>setTab("data")} style={{marginBottom:14,cursor:"pointer",border:`1.5px solid ${t.ac}44`,padding:16}} anim="pi"><div style={{display:"flex",alignItems:"center",justifyContent:"space-between"}}><div><div style={{fontSize:14,fontWeight:700,color:t.ac}}>{st.validated} items prêts à archiver</div><div style={{fontSize:11,color:t.tm,marginTop:2}}>Seuil: {st.archive_threshold}</div></div><I n="box" s={18} c={t.ac}/></div></Cd>}
<div style={{display:"flex",gap:10,marginBottom:18}}>{st.corrected>0&&<Cd t={t} onClick={()=>setRv("staff")} style={{flex:1,cursor:"pointer",border:`1.5px solid ${t.wa}44`,padding:16}} anim="pi"><div style={{fontSize:14,fontWeight:700,color:t.wa}}>{st.corrected} à pré-valider</div><div style={{fontSize:11,color:t.tm,marginTop:2}}>Staff</div></Cd>}{st.pre_validated>0&&<Cd t={t} onClick={()=>setRv("validator")} style={{flex:1,cursor:"pointer",border:`1.5px solid ${t.ac}44`,padding:16}} anim="pi"><div style={{fontSize:14,fontWeight:700,color:t.ac}}>{st.pre_validated} à valider</div><div style={{fontSize:11,color:t.tm,marginTop:2}}>Validator</div></Cd>}</div>
<div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:10,marginBottom:18}}><SC l="Total" v={st.total} icon="chart" c={t.ac} t={t} d={0}/><SC l="Validés" v={st.validated} icon="check" c={t.ok} t={t} sub={st.total>0?`${((st.validated/st.total)*100).toFixed(0)}%`:""} d={50}/><SC l="Auto-validés" v={st.auto_validated} icon="zap" c={t.wa} t={t} d={100}/><SC l="Archivés" v={st.archived} icon="box" c={t.bl} t={t} d={150}/></div>
<Cd t={t} style={{marginBottom:18}} anim="fi" delay={200}><div style={{fontSize:10,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:1,marginBottom:16}}>Pipeline</div>{[{l:"Bruts",c:st.raw,co:t.bl},{l:"Corrigés",c:st.corrected,co:t.wa},{l:"Pré-validés",c:st.pre_validated,co:t.ac},{l:"Validés",c:st.validated,co:t.ok},{l:"Rejetés",c:st.rejected,co:t.er}].map(s=><div key={s.l} style={{marginBottom:12}}><div style={{display:"flex",justifyContent:"space-between",fontSize:12,marginBottom:5}}><span style={{color:t.tm}}>{s.l}</span><span style={{fontWeight:700,fontFamily:M,color:s.co,fontSize:13}}>{s.c}</span></div><Pr v={s.c} mx={st.total||1} c={s.co} t={t}/></div>)}</Cd>
<Cd t={t} anim="fi" delay={250}><div style={{display:"flex",justifyContent:"space-between",alignItems:"center"}}><div><div style={{fontSize:10,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:1}}>À payer</div><div style={{fontSize:32,fontWeight:900,fontFamily:M,color:t.wa,marginTop:6}}>{tm.total_owed.toFixed(1)} <span style={{fontSize:14,color:t.tm}}>MAD</span></div></div><div style={{textAlign:"right"}}><div style={{fontSize:12,color:t.ok,fontWeight:600}}>Payé: {tm.total_paid.toFixed(1)} MAD</div><div style={{fontSize:11,color:t.tm,marginTop:2}}>Budget: {(tm.total_owed+tm.total_paid).toFixed(1)} MAD</div></div></div></Cd></div>}

{tab==="items"&&<div style={{padding:"0 20px 32px",position:"relative",zIndex:1}} className="fi"><div style={{display:"flex",gap:6,marginBottom:16,flexWrap:"wrap"}}>{[{l:"Tous",v:""},{l:"Bruts",v:"raw"},{l:"Corrigés",v:"corrected"},{l:"Pré-val.",v:"pre_validated"},{l:"Validés",v:"validated"},{l:"Rejetés",v:"rejected"}].map(f=><button key={f.v} onClick={()=>{setItF(f.v);loadItems(1,f.v)}} style={{padding:"8px 14px",borderRadius:12,border:"none",background:itFilter===f.v?`linear-gradient(135deg,${t.ac},${t.ac}cc)`:t.sa+"cc",color:itFilter===f.v?"#fff":t.tm,fontSize:12,fontWeight:700,fontFamily:F}}>{f.l}</button>)}</div><div style={{fontSize:12,color:t.td,marginBottom:12,fontWeight:600}}>{itTotal} items</div>{items.length===0?<Em icon="file" title="Aucun item" sub="Changez le filtre ou importez." t={t}/>:<div style={{display:"flex",flexDirection:"column",gap:10}}>{items.map((tk,i)=><Cd key={tk.id} t={t} style={{padding:16,cursor:"pointer"}} onClick={()=>setEditTk(tk)} anim="fi" delay={i*30}><div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:10}}><StBg status={tk.status} t={t}/><div style={{display:"flex",alignItems:"center",gap:6}}>{tk.corrected_by_name&&<span style={{fontSize:10,color:t.td}}>{tk.corrected_by_name}</span>}{tk.staff_name&&<span style={{fontSize:10,color:t.ac}}>→{tk.staff_name}</span>}{tk.auto_validated===1&&<Bg c={t.wa}>auto</Bg>}</div></div><div style={{fontSize:14,lineHeight:1.5,color:t.tx,display:"-webkit-box",WebkitLineClamp:2,WebkitBoxOrient:"vertical",overflow:"hidden"}}>{tk.final_instruction||tk.edited_instruction||tk.instruction}</div></Cd>)}</div>}{itTotal>15&&<div style={{display:"flex",justifyContent:"center",gap:12,marginTop:20}}><Bt v="ghost" t={t} dis={itPage<=1} onClick={()=>loadItems(itPage-1,itFilter)} style={{padding:"10px 18px"}}>←</Bt><span style={{fontSize:14,color:t.tm,fontWeight:700,fontFamily:M,alignSelf:"center"}}>{itPage}</span><Bt v="ghost" t={t} dis={itPage*15>=itTotal} onClick={()=>loadItems(itPage+1,itFilter)} style={{padding:"10px 18px"}}>→</Bt></div>}</div>}

{tab==="team"&&<div style={{padding:"0 20px 32px",position:"relative",zIndex:1}} className="su">{regs.length>0&&<><div style={{fontSize:11,fontWeight:700,color:t.ok,textTransform:"uppercase",letterSpacing:1,marginBottom:14}}>Candidatures ({regs.length})</div><div style={{display:"flex",flexDirection:"column",gap:10,marginBottom:24}}>{regs.map((r,i)=><Cd key={r.id} t={t} style={{padding:16}} anim="fi" delay={i*50}><div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:8}}><div><div style={{fontWeight:700,fontSize:14,color:t.tx}}>{r.first_name} {r.last_name}</div><div style={{fontSize:12,color:t.tm,marginTop:2}}>{r.email} · {r.phone}</div>{r.education&&<div style={{fontSize:11,color:t.td,marginTop:2}}>{r.education}</div>}</div><div style={{fontSize:10,color:t.td}}>{r.created_at?.split("T")[0]}</div></div><div style={{display:"flex",gap:8}}><Bt v="success" t={t} onClick={()=>regAction(r.id,"approve")} style={{padding:"8px 16px",fontSize:12,flex:1}}><I n="check" s={14} c="#fff"/> Approuver</Bt><Bt v="ghost" t={t} onClick={()=>regAction(r.id,"reject")} style={{padding:"8px 16px",fontSize:12}}><I n="x" s={14} c={t.er}/></Bt></div></Cd>)}</div></>}<div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:14}}><div style={{fontSize:11,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:1}}>Annotateurs</div><Bt v="dim" t={t} onClick={()=>setShowNU(true)} style={{padding:"10px 16px",borderRadius:12,fontSize:13}}><I n="plus" s={14} c={t.tm}/> Ajouter</Bt></div>{tm.workers.length===0?<Cd t={t} style={{marginBottom:20,padding:32,textAlign:"center"}}><span style={{color:t.tm}}>Aucun</span></Cd>:<div style={{display:"flex",flexDirection:"column",gap:10,marginBottom:24}}>{tm.workers.map((ww,i)=>{const ow=ww.earnings?.owed||0;const pd=ww.total_paid||0;const sc=ww.score;return<Cd key={ww.id} t={t} style={{padding:16}} anim="fi" delay={i*50}><div style={{display:"flex",alignItems:"center",gap:12,marginBottom:8}}><div style={{width:36,height:36,borderRadius:10,background:t.bl+"18",display:"flex",alignItems:"center",justifyContent:"center",fontSize:14,fontWeight:800,color:t.bl}}>{ww.name[0].toUpperCase()}</div><div style={{flex:1}}><div style={{display:"flex",alignItems:"center",gap:8}}><span style={{fontWeight:700,fontSize:14,color:t.tx}}>{ww.name}</span>{sc&&<ScBadge score={sc} t={t}/>}</div><div style={{fontSize:11,color:t.tm}}>{sc?.done||0} faits · {sc?.rate||0}%</div></div><div style={{textAlign:"right"}}><div style={{fontSize:16,fontWeight:800,fontFamily:M,color:ow>0?t.wa:t.ok}}>{ow.toFixed(1)}</div><div style={{fontSize:10,color:t.tm}}>dû</div>{pd>0&&<div style={{fontSize:10,color:t.ok}}>Payé: {pd.toFixed(1)}</div>}</div></div>{ow>0&&<Bt full v="warn" t={t} onClick={()=>payW(ww.id)} style={{padding:"8px 14px",fontSize:12,marginTop:8}}><I n="wallet" s={14} c="#fff"/> Payer ({ow.toFixed(1)} MAD)</Bt>}</Cd>})}</div>}<div style={{fontSize:11,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:1,marginBottom:14}}>Staff</div>{tm.staff.length===0?<Cd t={t} style={{marginBottom:20,padding:32,textAlign:"center"}}><span style={{color:t.tm}}>Aucun</span></Cd>:<div style={{display:"flex",flexDirection:"column",gap:10,marginBottom:24}}>{tm.staff.map((ss,i)=><Cd key={ss.id} t={t} style={{padding:16}} anim="fi" delay={i*50}><div style={{display:"flex",alignItems:"center",gap:12}}><div style={{width:36,height:36,borderRadius:10,background:t.ac+"18",display:"flex",alignItems:"center",justifyContent:"center",fontSize:14,fontWeight:800,color:t.ac}}>{ss.name[0].toUpperCase()}</div><div style={{flex:1}}><div style={{display:"flex",alignItems:"center",gap:8}}><span style={{fontWeight:700,fontSize:14,color:t.tx}}>{ss.name}</span><FiabBadge v={ss.fiability} t={t}/></div><div style={{fontSize:11,color:t.tm}}>{ss.reviewed} reviews · Sondage: {ss.sample_rate}%</div></div><div style={{fontSize:11,color:t.tm,textAlign:"right"}}>{ss.golden_correct||0}/{ss.golden_total||0}<br/><span style={{fontSize:10}}>golden</span></div></div></Cd>)}</div>}<div style={{fontSize:11,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:1,marginBottom:14}}>Validateurs</div>{tm.validators.length===0?<Cd t={t}><span style={{color:t.tm,display:"block",textAlign:"center"}}>Aucun</span></Cd>:<div style={{display:"flex",flexDirection:"column",gap:10}}>{tm.validators.map((vv,i)=><Cd key={vv.id} t={t} style={{padding:16,display:"flex",alignItems:"center",gap:12}} anim="fi" delay={i*50}><div style={{width:36,height:36,borderRadius:10,background:t.ok+"18",display:"flex",alignItems:"center",justifyContent:"center",fontSize:14,fontWeight:800,color:t.ok}}>{vv.name[0].toUpperCase()}</div><div><span style={{fontWeight:700,fontSize:14,color:t.tx}}>{vv.name}</span><div style={{fontSize:11,color:t.tm}}>{vv.validations} validations</div></div></Cd>)}</div>}</div>}

{tab==="data"&&<div style={{padding:"0 20px 32px",position:"relative",zIndex:1}} className="su">
{/* ARCHIVE SECTION */}
<Cd t={t} style={{marginBottom:14,padding:24,border:st.validated>=st.archive_threshold?`1.5px solid ${t.ac}44`:`1px solid ${t.bd}`}} anim="fi">
<div style={{display:"flex",alignItems:"center",gap:10,marginBottom:14}}><I n="box" s={18} c={t.ac}/><div style={{fontSize:11,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:1}}>Archiver</div></div>
<div style={{fontSize:14,color:t.tm,lineHeight:1.6,marginBottom:16}}>
<span style={{color:t.ok,fontWeight:700,fontSize:20,fontFamily:M}}>{st.validated}</span> items validés prêts.
{st.validated>=st.archive_threshold?<span style={{color:t.ac,fontWeight:600}}> Seuil atteint !</span>:<span> Seuil: {st.archive_threshold}.</span>}
</div>
<Bt full t={t} onClick={doArchive} dis={st.validated===0||archiving} style={{marginBottom:archives.length>0?16:0}}>
<I n="box" s={17} c="#fff"/> {archiving?"Archivage...":st.validated>0?`Archiver ${st.validated} items`:"Rien à archiver"}
</Bt>
{archives.length>0&&<><div style={{fontSize:10,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:1,marginTop:16,marginBottom:10}}>Historique ({archives.length})</div>
{archives.map((ar,i)=><div key={ar.id} style={{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"10px 0",borderTop:i>0?`1px solid ${t.bd}`:undefined}}>
<div><div style={{fontSize:13,fontWeight:700,color:t.tx,fontFamily:M}}>{ar.name}</div><div style={{fontSize:11,color:t.tm}}>{ar.items_count} items · {ar.created_at?.split("T")[0]} · {(ar.file_size/1024).toFixed(0)} KB</div></div>
<button onClick={()=>dlArchive(ar.id)} style={{background:t.sa,border:`1px solid ${t.bd}`,borderRadius:10,padding:"6px 10px",display:"flex",alignItems:"center",gap:4,color:t.ac,fontSize:11,fontWeight:700}}><I n="dl" s={14} c={t.ac}/></button>
</div>)}</>}
</Cd>
{/* IMPORT */}
<Cd t={t} style={{marginBottom:14,padding:24}} anim="fi" delay={50}>
<div style={{display:"flex",alignItems:"center",gap:10,marginBottom:14}}><I n="ul" s={18} c={t.bl}/><div style={{fontSize:11,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:1}}>Importer</div></div>
<div style={{fontSize:14,color:t.tm,lineHeight:1.6,marginBottom:16}}>JSON: <span style={{fontFamily:M,fontSize:12,color:t.ac,fontWeight:700}}>instruction</span> + <span style={{fontFamily:M,fontSize:12,color:t.ac,fontWeight:700}}>output</span></div>
<Bt full v="ghost" t={t} onClick={()=>fr.current?.click()}><I n="ul" s={17} c={t.tm}/> Charger un fichier JSON</Bt>
</Cd>
{/* GOLDEN */}
<Cd t={t} style={{marginBottom:14,padding:24}} anim="fi" delay={100}>
<div style={{display:"flex",alignItems:"center",gap:10,marginBottom:14}}><I n="shield" s={18} c={t.wa}/><div style={{fontSize:11,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:1}}>Golden Items</div></div>
<div style={{fontSize:14,color:t.tm,lineHeight:1.6,marginBottom:16}}>{st.golden_count} golden items actifs.</div>
<Bt full v="warn" t={t} onClick={()=>setShowGold(true)}><I n="shield" s={17} c="#fff"/> Créer un golden item</Bt>
</Cd>
{/* EXPORT RAW */}
<Cd t={t} style={{padding:24}} anim="fi" delay={150}>
<div style={{display:"flex",alignItems:"center",gap:10,marginBottom:14}}><I n="dl" s={18} c={t.ok}/><div style={{fontSize:11,fontWeight:700,color:t.tm,textTransform:"uppercase",letterSpacing:1}}>Export brut</div></div>
<div style={{fontSize:14,color:t.tm,lineHeight:1.6,marginBottom:16}}>Télécharger les {st.validated} validés sans archiver (pas de changement de statut).</div>
<Bt full v="success" t={t} onClick={async()=>{try{const d=await ap.g("/admin/export");const b=new Blob([JSON.stringify(d,null,2)],{type:"application/json"});const u=URL.createObjectURL(b);const a=document.createElement("a");a.href=u;a.download=`annotate-export-${new Date().toISOString().split("T")[0]}.json`;a.click();URL.revokeObjectURL(u)}catch{}}} dis={st.validated===0}><I n="dl" s={17} c="#fff"/> Export ({st.validated})</Bt>
</Cd>
</div>}
<Footer t={t}/></Page>};

/* MAIN */
const App=()=>{const[user,setU]=useState(null),[theme,setTh]=useState(localStorage.getItem("anth")||"dark"),[ld,setLd]=useState(false),[showLogin,setSL]=useState(false);const t=TH[theme];const role=getRouteRole();useEffect(()=>{const st=localStorage.getItem("at");if(st){ap.tk=st;ap.g("/auth/me").then(u=>{setU(u);setLd(true)}).catch(()=>{ap.out();setLd(true)})}else setLd(true)},[]);useEffect(()=>{document.body.style.background=t.bg;document.querySelector('meta[name="theme-color"]')?.setAttribute("content",t.bg)},[theme]);const tg=()=>{const n=theme==="dark"?"light":"dark";setTh(n);localStorage.setItem("anth",n)};if(!ld)return<div style={{background:t.bgG,minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center"}}><div className="pu" style={{fontSize:36,fontWeight:900,color:t.tx,fontFamily:F,letterSpacing:-2}}>annotate<span style={{color:t.ac}}>.</span></div></div>;
if(!user){if(role==="worker"){if(showLogin)return<AuthScreen onLogin={setU} onBack={()=>setSL(false)} t={t} theme={theme} toggle={tg} role="worker"/>;return<Landing onGoLogin={()=>setSL(true)} t={t} theme={theme} toggle={tg}/>}return<AuthScreen onLogin={setU} t={t} theme={theme} toggle={tg} role={role}/>}
if(user.role==="worker")return<WV user={user} t={t} theme={theme} toggle={tg}/>;if(user.role==="staff")return<ReviewView user={user} t={t} theme={theme} toggle={tg} isStaff/>;if(user.role==="validator")return<ReviewView user={user} t={t} theme={theme} toggle={tg}/>;return<AV user={user} t={t} theme={theme} toggle={tg}/>};
ReactDOM.createRoot(document.getElementById("root")).render(<App/>);
