// Ecrãs base do PeopleX: Início (widgets), Inbox, Pendentes, visão de grupo e administração.
const {S,Head,I,P,PEOPLE,AV,useCtx,GROUP,useWidth}=window.WFA;
const {UIButton,UIInput,UIToggle,UICard,UIPill,UINavItem,UIStat,UITabs,UITable,UIAvatar,UIAvatarGroup,UISelect,UIBanner,UIModal,UIDrawer,UIDataTable,UIEmptyState,UIProgress,UIChart,UIKanban,UIToggleGroup,UICheckbox,UIMenu}=window.XCOPEDesignSystem_bf80f1;
const {TODAY,NOW,SHIFT_IN,SHIFT_TARGET,SHIFT_BREAK,WD_SHORT,WD_LONG,MONTHS_LONG,wdIndex,addDays,weekStart,fmtLong,hm,dur}=window.WFA_TODAY;

// ---------- screens ----------
function PontoW(){const[inN,setIn]=React.useState(true);const R=34,C=2*Math.PI*R;
  const trabalhado=Math.max(0,NOW-SHIFT_IN-SHIFT_BREAK);
  const falta=Math.max(0,SHIFT_TARGET-trabalhado);
  const frac=Math.min(1,trabalhado/SHIFT_TARGET);
  return <div style={{display:"flex",alignItems:"center",gap:16,paddingTop:2}}>
  <svg width="88" height="88" viewBox="0 0 88 88" style={{flexShrink:0}}>
    <circle cx="44" cy="44" r={R} fill="none" stroke="var(--ui-surface-3)" strokeWidth="7"/>
    <circle cx="44" cy="44" r={R} fill="none" stroke={inN?"var(--ui-success)":"var(--ui-border-2)"} strokeWidth="7" strokeLinecap="round" strokeDasharray={C} strokeDashoffset={C*(1-(inN?frac:0))} transform="rotate(-90 44 44)"/>
    <text x="44" y="49" textAnchor="middle" style={{fontWeight:600,fontSize:"var(--ui-fs-h3)",fill:"var(--ui-text)",letterSpacing:"-0.02em"}}>{hm(NOW)}</text>
  </svg>
  <div style={{flex:1,minWidth:0}}>
    <div className="row" style={{gap:6}}><span style={{width:8,height:8,borderRadius:999,background:inN?"var(--ui-success)":"var(--ui-text-3)"}}/><span style={{fontWeight:600,fontSize:"var(--ui-fs-sm)"}}>{inN?"Em serviço":"Fora de serviço"}</span></div>
    <div className="muted" style={{fontSize:"var(--ui-fs-xs)",margin:"3px 0 10px"}}>{inN?"desde "+hm(SHIFT_IN)+" · "+(falta?"faltam "+dur(falta):"jornada cumprida"):"último registo às 17:30"}</div>
    <UIButton size="sm" block variant={inN?"danger":"primary"} onClick={()=>setIn(!inN)}>{inN?"Registar saída":"Registar entrada"}</UIButton>
  </div>
</div>;}
function AgendaW({go}){
  const evs=[[9,"Entrevista — QA Tester","09:00-10:00",["Mira Mango","Zain Franci"]],[11,"Revisão de portefólio","11:30-13:00",["Carla Dias"]],[14,"Reunião semanal da equipa","14:00-16:00",["Ana Reis","Rui Pinto","Sofia Melo"]]];
  const hours=Array.from({length:13},(_,i)=>7+i);
  return <div style={{flex:1,display:"flex",flexDirection:"column"}}>
  <div style={{display:"grid",gridTemplateColumns:"repeat(7,1fr)",gap:4,marginBottom:12,textAlign:"center"}}>{Array.from({length:7},(_,i)=>addDays(weekStart(TODAY),i)).map((dt,i)=>{const hoje=dt.getDate()===TODAY.getDate()&&dt.getMonth()===TODAY.getMonth();const fds=i>=5;
    return <div key={i} style={{display:"flex",flexDirection:"column",alignItems:"center",gap:4}}><span style={{fontSize:"var(--ui-fs-xs)",fontWeight:600,color:fds?"var(--ui-text-3)":"var(--ui-text-2)"}}>{WD_SHORT[i]}</span><span style={{width:28,height:28,display:"flex",alignItems:"center",justifyContent:"center",borderRadius:999,fontSize:"var(--ui-fs-sm)",fontWeight:hoje?700:500,background:hoje?"var(--ui-accent)":"transparent",color:hoje?"var(--ui-on-accent)":fds?"var(--ui-text-3)":"var(--ui-text)",fontVariantNumeric:"tabular-nums",opacity:hoje?1:fds?0.75:1}}>{dt.getDate()}</span></div>;})}</div>
  <div style={{flex:1,display:"flex",flexDirection:"column",overflow:"auto",minHeight:0}}>
    {hours.map(h=>{const ev=evs.find(e=>e[0]===h);return <div key={h} style={{flexShrink:0,minHeight:34,display:"flex",flexDirection:"column",justifyContent:"flex-start"}}>
      <div className="row" style={{gap:10,flexShrink:0,height:16}}><span className="muted" style={{fontSize:"var(--ui-fs-xs)",fontVariantNumeric:"tabular-nums",width:38,flexShrink:0}}>{String(h).padStart(2,"0")}:00</span><div style={{flex:1,borderTop:"1px dashed var(--ui-divider)"}}/></div>
      {ev&&<div style={{margin:"6px 2px 10px 48px",minWidth:0,background:"var(--ui-surface-2)",borderLeft:"3px solid var(--ui-accent)",borderRadius:"var(--ui-r-sm)",padding:"9px 12px"}}>
        <div style={{fontWeight:600,fontSize:"var(--ui-fs-sm)"}}>{ev[1]}</div>
        <div className="row" style={{marginTop:5,gap:8,flexWrap:"wrap"}}><span className="muted" style={{fontSize:"var(--ui-fs-xs)",whiteSpace:"nowrap"}}>{ev[2]}</span><div className="spring" style={{minWidth:8}}/><UIAvatarGroup size="xs" max={3} avatars={ev[3].map(name=>({name}))}/></div>
      </div>}
    </div>;})}
  </div>
  <div onClick={()=>go&&go("calendar")} className="row" style={{cursor:"pointer",fontWeight:600,fontSize:"var(--ui-fs-sm)",paddingTop:10,borderTop:"1px solid var(--ui-divider)",marginTop:8}}>Ver calendário completo<div className="spring"/><I d={["m9 18 6-6-6-6"]} size={15} c="var(--ui-text-3)"/></div>
</div>;}
const HW={
  agenda:{t:"Agenda de hoje",r:(go)=><div style={{flex:1,display:"flex",minHeight:0}}><AgendaW go={go}/></div>},
  ponto:{t:"Registo de ponto",r:()=><PontoW/>},
  tarefas:{t:"As minhas tarefas",r:()=>[["Rever candidaturas QA","Hoje","warning"],["Aprovar folha de ponto","Amanhã","info"],["Onboarding — Ana Reis","Sex","neutral"]].map(([t,d,tone])=><div className="listrow" key={t}><span style={{width:88,flexShrink:0,display:"flex"}}><UIPill tone={tone} dot>{d}</UIPill></span><span style={{flex:1,fontWeight:500}}>{t}</span><I d={["m9 18 6-6-6-6"]} size={16} c="var(--ui-text-3)"/></div>)},
  aprovacoes:{t:"Pedidos e aprovações",r:(go)=>[["Férias — James Kim","24-26 mar"],["Falta — Rui Pinto","ontem"]].map(([t,d])=><div className="listrow" key={t}><div style={{flex:1}}><div style={{fontWeight:600,fontSize:"var(--ui-fs-sm)"}}>{t}</div><div className="muted" style={{fontSize:"var(--ui-fs-xs)"}}>{d}</div></div><UIButton size="sm" onClick={()=>go&&go("notifications")}>Aprovar</UIButton><UIButton size="sm" variant="ghost" onClick={()=>go&&go("notifications")}>Rejeitar</UIButton></div>)},
  comunicacoes:{t:"Comunicações",r:(go)=><React.Fragment>{(window.WFA_NEWS||[]).slice(0,2).map((p,i)=>
    <div key={p.id} onClick={()=>go&&go("news")} style={{cursor:"pointer",marginTop:i?10:0}}>
      <UIBanner tone={p.cat==="Evento"?"success":"info"} title={p.t}>{p.resumo}</UIBanner>
    </div>)}</React.Fragment>},
  aniversarios:{t:"Aniversários e datas",r:(go)=><div style={{display:"grid",gridTemplateColumns:"repeat(3,1fr)",gap:10}}>{[["Carla Dias","Faz anos hoje","var(--ui-success-bg)"],["Tomás Jervell","Faz anos sexta","var(--ui-warning-bg)"],["Ana Reis","2 anos de casa","var(--ui-info-bg)"]].map(([n,d,bg])=><div key={n} style={{background:bg,borderRadius:"var(--ui-r-md)",padding:"18px 10px 14px",display:"flex",flexDirection:"column",alignItems:"center",gap:9,textAlign:"center"}}><UIAvatar name={n} size="lg"/><div><div style={{fontWeight:600,fontSize:"var(--ui-fs-sm)"}}>{n}</div><div className="muted" style={{fontSize:"var(--ui-fs-xs)",marginTop:2}}>{d}</div></div></div>)}</div>},
  fora:{t:"Quem está fora",r:()=>[["Zain Franci","Férias","até 28 jul","warning"],["Sofia Melo","Baixa","hoje","danger"],["Rui Pinto","Teletrabalho","hoje","info"]].map(([n,t,d,tone])=><div className="listrow" key={n}><UIAvatar name={n} size="sm"/><span style={{flex:1,fontWeight:600,fontSize:"var(--ui-fs-sm)"}}>{n}</span><span className="muted" style={{fontSize:"var(--ui-fs-xs)"}}>{d}</span><UIPill tone={tone} dot>{t}</UIPill></div>)},
  novas:{t:"Novas caras",r:()=>[["Ana Reis","Data Analyst · Dados"],["João Alves","Backend · Engenharia"]].map(([n,r])=><div className="listrow" key={n}><UIAvatar name={n} size="md"/><div style={{flex:1}}><div style={{fontWeight:600}}>{n}</div><div className="muted" style={{fontSize:"var(--ui-fs-sm)"}}>{r}</div></div><UIButton size="sm" variant="outline" onClick={()=>go&&go("chat")}>Dizer olá</UIButton></div>)},
  horas:{t:"Resumo de horas",r:()=><React.Fragment><UIStat label="Esta semana" value="32h" delta="+4h" sublabel="de 40h contratadas"/><div style={{marginTop:12,height:8,borderRadius:999,background:"var(--ui-surface-3)"}}><div style={{width:"80%",height:"100%",borderRadius:999,background:"var(--ui-accent)"}}/></div></React.Fragment>},
  ferias:{t:"Saldo de férias",r:()=><React.Fragment><UIStat label="Disponíveis" value="14" sublabel="de 22 dias"/><div className="muted" style={{marginTop:10,fontSize:"var(--ui-fs-sm)"}}>Próximas: <b style={{color:"var(--ui-text)"}}>4–15 ago</b> (aprovadas)</div></React.Fragment>},
  inqueritos:{t:"Inquéritos abertos",r:(go)=>[["Inquérito de clima 2026","até sexta"],["Feedback onboarding","até 31 jul"]].map(([t,d])=><div className="listrow" key={t}><div style={{flex:1}}><div style={{fontWeight:600,fontSize:"var(--ui-fs-sm)"}}>{t}</div><div className="muted" style={{fontSize:"var(--ui-fs-xs)"}}>{d}</div></div><UIButton size="sm" variant="outline" onClick={()=>go&&go("surveys")}>Responder</UIButton></div>)},
};
const HW_DEF=[{id:"agenda",s:4,h:2},{id:"ponto",s:4,h:1},{id:"horas",s:3,h:1},{id:"tarefas",s:4,h:1},{id:"aprovacoes",s:3,h:1},{id:"ferias",s:4,h:1},{id:"comunicacoes",s:4,h:1},{id:"aniversarios",s:4,h:1},{id:"fora",s:4,h:1},{id:"novas",s:4,h:1},{id:"inqueritos",s:12,h:1}];
const HW_MAXH=3;
S.home=({go})=>{
  const [lay,setLay]=React.useState(()=>{try{const v=JSON.parse(localStorage.getItem("wf_home_layout_v5"));return Array.isArray(v)&&v.length?v.filter(x=>HW[x.id]).map(x=>({...x,s:Math.min(12,Math.max(2,x.s||4)),h:x.h||1})):HW_DEF;}catch(e){return HW_DEF;}});
  const [edit,setEdit]=React.useState(false);
  React.useEffect(()=>{localStorage.setItem("wf_home_layout_v5",JSON.stringify(lay));},[lay]);
  const drag=React.useRef(null);const [over,setOver]=React.useState(null);
  const drop=(i)=>{const f=drag.current;if(f==null||f===i){setOver(null);return;}const a=[...lay],[it]=a.splice(f,1);a.splice(i,0,it);setLay(a);drag.current=null;setOver(null);};
  const gridRef=React.useRef(null);const [gw,setGw]=React.useState(0);
  React.useLayoutEffect(()=>{
    const el=gridRef.current;if(!el)return;
    const host=el.parentElement||el;      // width of the host is NOT changed by the packing
    const step=w=>w<620?12:w<1000?6:w<1300?4:3;
    const read=()=>{const w=host.getBoundingClientRect().width;if(!w)return;
      setGw(p=>step(p)===step(w)?p:w);};   // commit only when the breakpoint changes
    read();
    const t1=window.setTimeout(read,120);
    window.addEventListener("resize",read);
    let ro=null;
    if(window.ResizeObserver){ro=new ResizeObserver(read);ro.observe(host);}
    return ()=>{window.clearTimeout(t1);window.removeEventListener("resize",read);if(ro)ro.disconnect();};
  },[]);
  // gw 0 = not measured yet; fall back to the widest floor so nothing flashes narrow
  const hidden=Object.keys(HW).filter(k=>!lay.some(x=>x.id===k));

  // drag a card's corner: snap to the 12-col grid and to whole rows
  const [rs,setRs]=React.useState(null);
  const startResize=(e,i,dir)=>{e.preventDefault();e.stopPropagation();
    const el=gridRef.current;const cs=getComputedStyle(el);const gap=parseFloat(cs.columnGap)||12;
    const colW=(el.clientWidth-gap*11)/12;const rowH=(parseFloat(cs.gridAutoRows)||168)+gap;
    const sx=dir.includes("e")?1:dir.includes("w")?-1:0;
    const sy=dir.includes("s")?1:dir.includes("n")?-1:0;
    setRs({i,dir,sx,sy,x0:e.clientX,y0:e.clientY,s0:lay[i].s,h0:lay[i].h||1,colW,rowH});};
  React.useEffect(()=>{if(!rs)return;
    const move=e=>{const ds=rs.sx?Math.round((e.clientX-rs.x0)/rs.colW)*rs.sx:0;
      const dh=rs.sy?Math.round((e.clientY-rs.y0)/rs.rowH)*rs.sy:0;
      setLay(l=>l.map((w,x)=>x===rs.i?{...w,s:Math.min(12,Math.max(2,rs.s0+ds)),h:Math.min(HW_MAXH,Math.max(1,rs.h0+dh))}:w));};
    const up=()=>setRs(null);
    window.addEventListener("pointermove",move);window.addEventListener("pointerup",up);
    return ()=>{window.removeEventListener("pointermove",move);window.removeEventListener("pointerup",up);};},[rs]);

  // no gaps, ever: every row is packed to 12 columns
  const packFor=React.useCallback(w=>{
    const floor=!w?4:w<620?12:w<1000?6:w<1300?4:3;
    const out=lay.map(x=>Math.max(floor,Math.min(12,x.s||4)));
    // Place onto a real 12-col x N-row occupancy map so a tall widget never leaves
    // the rest of its rows empty, then grow whatever ends each row that is short.
    const used=[];const at=r=>{while(used.length<=r)used.push(0);return used[r];};
    const owner=[];                     // per row: index of the last card placed on it
    const spanOf=[];const rowOf=[];const hOf=[];
    for(let i=0;i<out.length;i++){
      const h=Math.max(1,Math.min(3,lay[i].h||1));
      let r=0,free=0;
      for(let guard=0;guard<400;guard++,r++){
        free=12;for(let k=0;k<h;k++)free=Math.min(free,12-at(r+k));
        if(free>=Math.min(floor,12))break;
      }
      const span=Math.max(1,Math.min(out[i],free));
      out[i]=span;spanOf[i]=span;rowOf[i]=r;hOf[i]=h;
      for(let k=0;k<h;k++){used[r+k]=at(r+k)+span;owner[r+k]=i;}
    }
    // close short rows by growing their last occupant (only single-row cards, so
    // widening one cannot overflow another row it also spans)
    for(let r=0;r<used.length;r++){
      const gap=12-used[r];const i=owner[r];
      if(gap>0&&i!=null&&hOf[i]===1){out[i]=Math.min(12,out[i]+gap);used[r]+=gap;}
    }
    return out;},[lay]);
  const spans=packFor(gw);


  return <React.Fragment>
  <Head title="Bom dia, Hugo" desc={fmtLong(TODAY)+" · 3 itens precisam de ti"} actions={<UIButton variant={edit?"primary":"secondary"} onClick={()=>setEdit(!edit)} icon={<I d={edit?["M20 6 9 17l-5-5"]:["M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3Z"]} size={15}/>}>{edit?"Concluir":"Personalizar"}</UIButton>}/>
  {edit&&<UIBanner tone="neutral" title="A personalizar" style={{marginBottom:16}}>
    <div className="muted" style={{fontSize:"var(--ui-fs-sm)",marginTop:2}}>Arrasta o canto de um widget para o esticar, e o próprio widget para o mover. As larguras encaixam sempre na grelha, sem deixar espaços.</div>
    {hidden.length>0&&<div className="row" style={{gap:8,flexWrap:"wrap",marginTop:12}}>{hidden.map(k=><span key={k} onClick={()=>setLay([...lay,{id:k,s:4,h:1}])} style={{padding:"8px 12px",border:"1px dashed var(--ui-border-2)",borderRadius:999,fontSize:"var(--ui-fs-sm)",fontWeight:600,cursor:"pointer"}}>+ {HW[k].t}</span>)}</div>}
  </UIBanner>}
  <div className="dash" style={{display:"block",width:"100%"}}>
    <div className="wgrid" ref={gridRef} style={{width:"100%",minWidth:0,display:"grid",gridTemplateColumns:"repeat(12,minmax(0,1fr))",gridAutoRows:"minmax(168px,auto)",gap:"clamp(10px,1.2cqi,16px)",alignContent:"start"}}>
    {lay.map((w,i)=><UICard className="wcard" key={w.id} draggable={edit&&!rs}
      onDragStart={()=>{drag.current=i;}} onDragEnd={()=>{drag.current=null;setOver(null);}}
      onDragOver={e=>{e.preventDefault();if(over!==i)setOver(i);}} onDrop={()=>drop(i)}
      style={{"--sp":spans[i],gridColumn:`span ${spans[i]}`,gridRow:`span ${w.h||1}`,display:"flex",flexDirection:"column",minHeight:0,overflow:"hidden",position:"relative",
        outline:edit?(over===i?"2px solid var(--ui-data)":"2px dashed var(--ui-border-2)"):"none",outlineOffset:2,
        cursor:edit?(rs?"nwse-resize":"grab"):"default",opacity:rs&&rs.i!==i?0.6:1,transition:rs?"none":"opacity var(--ui-dur) var(--ui-ease)"}}>
      <div className="row" style={{marginBottom:10}}>
        <span style={{fontWeight:600,fontSize:"var(--ui-fs-h3)"}}>{HW[w.id].t}</span><div className="spring"/>
        {edit&&<React.Fragment>
          <span className="muted" style={{fontSize:"var(--ui-fs-xs)",fontVariantNumeric:"tabular-nums",marginRight:8}}>{spans[i]}×{w.h||1}</span>
          <span className="wdel" title="Remover" onClick={()=>setLay(lay.filter((_,x)=>x!==i))}><I d={["M18 6 6 18","m6 6 12 12"]} size={13}/></span>
        </React.Fragment>}
      </div>
      <div style={{flex:1,minHeight:0,overflow:"auto",display:"flex",flexDirection:"column"}}>{HW[w.id].r(go)}</div>
      {edit&&["n","s","e","w","ne","nw","se","sw"].map(d=><span key={d} className={"wgrip wg-"+d} title="Arrastar para redimensionar" onPointerDown={e=>startResize(e,i,d)}/>)}
    </UICard>)}
    </div>
  </div>
</React.Fragment>;};

const useSteps=(ref,a,b)=>{const [w,setW]=React.useState(9999);React.useEffect(()=>{const el=ref.current;if(!el||!window.ResizeObserver)return;const ro=new ResizeObserver(es=>setW(es[0].contentRect.width));ro.observe(el);return ()=>ro.disconnect();},[]);return {narrow:w<a,mid:w<b};};
S.inbox=({go})=>{
  const seed=[
    {subj:"Contrato para assinatura",unread:true,msgs:[{from:"Ana Reis",time:"09:24",att:["Contrato_2026.pdf"],body:["Olá Hugo,","Segue em anexo o contrato atualizado com as alterações que discutimos na reunião de segunda. Pedia-te que revisses a cláusula 4.2 (horário flexível) e assinasses digitalmente até sexta-feira.","Qualquer dúvida, diz."]}]},
    {subj:"Reunião comercial Q3",unread:true,msgs:[
      {from:"Tomás Jervell",time:"Ter 14:02",att:["Pipeline_Q3.xlsx"],body:["Boa tarde,","Podemos alinhar os números antes da reunião de quinta? Envio o pipeline atualizado em anexo."]},
      {from:"Marta Lopes",time:"Ter 15:40",att:[],body:["Por mim quinta às 10h funciona.","Aproveito para juntar os custos de deslocação do trimestre à discussão."]},
      {from:"Tomás Jervell",time:"09:12",att:[],body:["Fica então quinta às 10h, sala 2.","Hugo, consegues trazer os números do piloto?"]}]},
    {subj:"Pedido de troca de turno — 28 jul",unread:false,msgs:[
      {from:"Bruno Costa",time:"Ontem 09:10",att:[],body:["Olá!","Consegues trocar comigo o turno de dia 28 (manhã)? Tenho uma consulta marcada e só soube hoje."]},
      {from:"Hugo Montenegro",time:"Ontem 11:32",att:[],body:["Por mim tudo bem, Bruno. Fico com o teu de dia 30.","Vou aceitar o pedido nos Horários."]},
      {from:"Bruno Costa",time:"Ontem 11:50",att:[],body:["Obrigado! Fica combinado."]}]},
    {subj:"Folha de ponto aprovada",unread:true,msgs:[{from:"Sistema RH",time:"09:02",att:[],body:["A tua folha de ponto de junho foi aprovada por Tomás Machado.","Total registado: 168h · Horas extra: 4h · Ausências: 1 dia (consulta médica)."]}]},
    {subj:"Recibo de vencimento disponível",unread:false,msgs:[{from:"Sistema RH",time:"Seg",att:["Recibo_junho.pdf"],body:["O recibo de vencimento de junho já está disponível.","Podes consultá-lo em Perfil → Documentos. Este email é automático."]}]},
    {subj:"Formação obrigatória de julho",unread:false,msgs:[{from:"Formação",time:"Seg",att:[],body:["A sessão de higiene e segurança está marcada para dia 30 de julho às 9h00 no auditório.","Confirma a tua peículo até às 8h45. Estimativa: meio dia."]}]},
    {subj:"Aprovação de despesa pendente",unread:false,msgs:[{from:"Marta Lopes",time:"Sex",att:["Recibo_taxi.jpg"],body:["Olá,","Submeti a despesa da deslocação ao cliente (táxi, 84,50 €) e está à espera da tua aprovação desde quarta. Recibo em anexo."]}]},
    {subj:"Notas da retro de julho",unread:false,msgs:[{from:"Equipa Produto",time:"Sex",att:[],body:["Resumo das decisões da retrospetiva:","1. O onboarding novo entra no sprint 14. 2. As demos passam para quinta. 3. A Ana assume o contacto com o piloto."]}]},
    {subj:"Ganhou um voucher de 500 €!!!",unread:false,spam:true,msgs:[{from:"Promoções Incríveis",time:"Seg",att:[],body:["Parabéns! Foi selecionado para receber um voucher de 500 €.","Clique já no link para reclamar o seu prémio. Oferta válida por 24 horas!"]}]}];
  const last=m=>m.msgs[m.msgs.length-1];
  const parts=m=>[...new Set(m.msgs.map(x=>x.from))];
  const partLabel=m=>{const u=parts(m);return (u.length===1?u[0]:u.map(n=>n==="Hugo Montenegro"?"Tu":n.split(" ")[0]).join(", "))+(m.msgs.length>1?" ("+m.msgs.length+")":"");};
  const [mails,setMails]=React.useState(seed.map(m=>({...m,folder:m.spam?"spam":"inbox"})));const [folder,setFolder]=React.useState("inbox");const [sel,setSel]=React.useState(0);const [q,setQ]=React.useState("");const [xp,setXp]=React.useState({});
  const [lists,setLists]=React.useState(["Faturas","Clientes"]);const [adding,setAdding]=React.useState(false);const [newList,setNewList]=React.useState("");const [movePop,setMovePop]=React.useState(false);
  const [compose,setCompose]=React.useState(false);const [cTo,setCTo]=React.useState("");const [cSubj,setCSubj]=React.useState("");const [cBody,setCBody]=React.useState("");
  const [cToList,setCToList]=React.useState([]);const [showCc,setShowCc]=React.useState(false);const [showBcc,setShowBcc]=React.useState(false);const [cCc,setCCc]=React.useState("");const [cBcc,setCBcc]=React.useState("");const [cAtt,setCAtt]=React.useState([]);
  const directory=[["Ana Reis","ana.reis@xcope.ai"],["Bruno Costa","bruno.costa@xcope.ai"],["Marta Lopes","marta.lopes@xcope.ai"],["Tomás Jervell","tomas.jervell@xcope.ai"],["Tomás Machado","tomas.machado@xcope.ai"],["Equipa Produto","produto@xcope.ai"],["RH","rh@xcope.ai"]];
  const sugg=cTo.trim()?directory.filter(d=>!cToList.includes(d[1])&&(d[0]+d[1]).toLowerCase().includes(cTo.toLowerCase())).slice(0,4):[];
  const addTo=v=>{if(v&&!cToList.includes(v))setCToList(l=>[...l,v]);setCTo("");};
  const resetCompose=()=>{setCTo("");setCToList([]);setCSubj("");setCBody("");setCCc("");setCBcc("");setShowCc(false);setShowBcc(false);setCAtt([]);};
  const closeCompose=()=>{if(cToList.length||cTo.trim()||cSubj.trim()||cBody.trim()){setMails(ms=>[{subj:cSubj||"(sem assunto)",unread:false,folder:"drafts",msgs:[{from:"Hugo Montenegro",time:"Agora",att:cAtt,body:cBody?cBody.split("\n").filter(Boolean):["(rascunho vazio)"],to:cToList.join(", ")||cTo}]}, ...ms]);}resetCompose();setCompose(false);};
  const [replyMode,setReplyMode]=React.useState(null);const [replyText,setReplyText]=React.useState("");
  const folders=[["inbox","Caixa de entrada","mail"],["sent","Enviados","send"],["drafts","Rascunhos","doc"],["archive","Arquivados","folder"],["spam","Spam","shield"],["trash","Lixo","trash"]];
  const addList=()=>{const n=newList.trim();if(n&&!lists.includes(n))setLists(ls=>[...ls,n]);setNewList("");setAdding(false);};
  const list=mails.map((m,i)=>({...m,i})).filter(m=>m.folder===folder&&(q===""||(m.subj+" "+m.msgs.map(x=>x.from+" "+x.body.join(" ")).join(" ")).toLowerCase().includes(q.toLowerCase())));
  const cur=mails[sel]&&mails[sel].folder===folder?{...mails[sel],i:sel}:list[0];const unread=mails.filter(m=>m.unread&&m.folder==="inbox").length;
  const paneRef=React.useRef(null);const {narrow,mid}=useSteps(paneRef,820,1180);const [reading,setReading]=React.useState(false);
  const open=i=>{setSel(i);setXp({});setReplyMode(null);setReading(true);setMails(ms=>ms.map((m,j)=>j===i?{...m,unread:false}:m));};
  const archive=i=>{setMovePop(false);setMails(ms=>ms.map((m,j)=>j===i?{...m,folder:m.folder==="archive"?"inbox":"archive",unread:false}:m));};
  const moveTo=(i,dest)=>{setMovePop(false);setMails(ms=>ms.map((m,j)=>j===i?{...m,folder:dest,unread:false}:m));};
  const sendMail=(to,subj,text,att)=>{setMails(ms=>[{subj,unread:false,folder:"sent",msgs:[{from:"Hugo Montenegro",time:"Agora",att:att||[],body:text.split("\n").filter(Boolean),to}]}, ...ms]);setSel(0);};
  const appendReply=(i,text)=>{setMails(ms=>ms.map((m,j)=>j===i?{...m,msgs:[...m.msgs,{from:"Hugo Montenegro",time:"Agora",att:[],body:text.split("\n").filter(Boolean)}]}:m));};
  const taStyle={width:"100%",minHeight:110,resize:"vertical",padding:"12px 14px",border:"1px solid var(--ui-border)",borderRadius:"var(--ui-r-sm)",background:"var(--ui-surface)",color:"var(--ui-text)",fontFamily:"var(--font-sans)",fontSize:"var(--ui-fs-body)",lineHeight:1.5,outline:"none",boxSizing:"border-box"};
  return <React.Fragment><Head title="Caixa de entrada" desc={unread>0?unread+" por ler":"Sem mensagens por ler"} actions={<UIButton icon={<I d={P.plus} size={16}/>} onClick={()=>setCompose(true)}>Nova mensagem</UIButton>}/>
  <UICard style={{padding:0,overflow:"hidden",flex:1,display:"flex",flexDirection:"column"}}>
    <div ref={paneRef} style={{flex:1,minHeight:0,display:"grid",gridTemplateColumns:narrow?"minmax(0,1fr)":mid?"56px minmax(0,320px) minmax(0,1fr)":"minmax(0,210px) minmax(0,380px) minmax(0,1fr)"}}>
    <div style={{borderRight:"1px solid var(--ui-divider)",padding:mid?6:12,display:narrow?"none":"flex",flexDirection:"column",gap:2,overflow:"auto"}}>{folders.map(f=>{const n=f[0]==="inbox"?mails.filter(m=>m.folder==="inbox"&&m.unread).length:mails.filter(m=>m.folder===f[0]).length;
      return <div key={f[0]} title={f[1]} onClick={()=>{setFolder(f[0]);setQ("");}} className="row" style={{gap:10,padding:mid?"9px 0":"9px 12px",justifyContent:mid?"center":"flex-start",borderRadius:"var(--ui-r-sm)",cursor:"pointer",fontWeight:folder===f[0]?600:500,fontSize:"var(--ui-fs-sm)",background:folder===f[0]?"var(--ui-accent-weak)":"transparent",color:folder===f[0]?"var(--ui-text)":"var(--ui-text-2)"}}><I d={P[f[2]]} size={16}/>{!mid&&<span style={{flex:1}}>{f[1]}</span>}{!mid&&n>0&&<span className="muted" style={{fontSize:"var(--ui-fs-xs)",fontWeight:600}}>{n}</span>}</div>;})}
      <div className="muted" style={{fontSize:"var(--ui-fs-xs)",fontWeight:600,letterSpacing:"0.06em",textTransform:"uppercase",padding:"16px 12px 6px",display:mid?"none":"block"}}>Listas</div>
      {lists.map(l=>{const key="list:"+l;const n=mails.filter(m=>m.folder===key).length;
      return <div key={key} title={l} onClick={()=>{setFolder(key);setQ("");}} className="row" style={{gap:10,padding:mid?"9px 0":"9px 12px",justifyContent:mid?"center":"flex-start",borderRadius:"var(--ui-r-sm)",cursor:"pointer",fontWeight:folder===key?600:500,fontSize:"var(--ui-fs-sm)",background:folder===key?"var(--ui-accent-weak)":"transparent",color:folder===key?"var(--ui-text)":"var(--ui-text-2)"}}><I d={P.tag} size={15}/>{!mid&&<span style={{flex:1}}>{l}</span>}{!mid&&n>0&&<span className="muted" style={{fontSize:"var(--ui-fs-xs)",fontWeight:600}}>{n}</span>}</div>;})}
      {adding&&!mid?<div style={{padding:"4px 4px 0"}}><UIInput autoFocus placeholder="Nome da lista" value={newList} onChange={e=>setNewList(e.target.value)} onKeyDown={e=>{if(e.key==="Enter")addList();if(e.key==="Escape")setAdding(false);}} onBlur={addList}/></div>
      :<div className="row" title="Nova lista" onClick={()=>setAdding(true)} style={{gap:10,padding:mid?"9px 0":"9px 12px",justifyContent:mid?"center":"flex-start",borderRadius:"var(--ui-r-sm)",cursor:"pointer",fontSize:"var(--ui-fs-sm)",fontWeight:500,color:"var(--ui-text-3)"}}><I d={P.plus} size={15}/>{!mid&&<span>Nova lista</span>}</div>}</div>
    <div style={{borderRight:"1px solid var(--ui-divider)",display:narrow&&reading?"none":"flex",flexDirection:"column",minHeight:0}}>
      <div style={{padding:"12px 14px",borderBottom:"1px solid var(--ui-divider)",display:"flex",gap:8,alignItems:"center"}}>{narrow&&<UISelect value={folder} onChange={e=>{setFolder(e.target.value);setQ("");}} options={[...folders.map(f=>({value:f[0],label:f[1]})),...lists.map(l=>({value:"list:"+l,label:l}))]}/>}<div style={{flex:1}}><UIInput leading={<I d={P.search} size={15}/>} placeholder="Procurar mensagens…" value={q} onChange={e=>setQ(e.target.value)}/></div></div>
      <div style={{overflow:"auto",flex:1}}>
    {list.length===0&&<div className="muted" style={{padding:24,fontSize:"var(--ui-fs-sm)"}}>{q?"Sem resultados para \u00ab"+q+"\u00bb.":"Esta pasta est\u00e1 vazia."}</div>}{list.map(m=>
      <div key={m.i} onClick={()=>open(m.i)} style={{display:"flex",gap:12,padding:"14px 16px",borderBottom:"1px solid var(--ui-divider)",cursor:"pointer",background:cur&&cur.i===m.i?"var(--ui-accent-weak)":"transparent"}}>
        {AV(last(m).from==="Hugo Montenegro"&&m.msgs.length>1?m.msgs[0].from:last(m).from,"md")}
        <div style={{flex:1,minWidth:0,display:"flex",flexDirection:"column",gap:3}}>
          <div className="row"><span style={{fontWeight:m.unread?700:600,flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{partLabel(m)}</span><span className="muted" style={{fontSize:"var(--ui-fs-xs)"}}>{last(m).time}</span>{m.unread&&<span style={{width:8,height:8,borderRadius:999,background:"var(--ui-accent)",flexShrink:0}}></span>}</div>
          <div style={{fontWeight:m.unread?600:500,fontSize:"var(--ui-fs-sm)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{m.subj}</div>
          <div className="row" style={{gap:8}}><span className="muted" style={{flex:1,fontSize:"var(--ui-fs-sm)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{last(m).body[0]}</span>{m.msgs.some(x=>x.att.length>0)&&<I d={P.doc} size={13}/>}</div>
        </div>
      </div>)}</div></div>
    {cur?<div style={{padding:"clamp(14px,2cqi,24px)",overflow:"auto",display:narrow&&!reading?"none":"flex",flexDirection:"column",gap:16}}>
      {narrow&&<div className="row" style={{gap:8,cursor:"pointer",color:"var(--ui-accent)",fontWeight:600,fontSize:"var(--ui-fs-sm)"}} onClick={()=>setReading(false)}><I d={["M15 18l-6-6 6-6"]} size={16}/>Voltar à lista</div>}
      <div className="row" style={{alignItems:"flex-start",flexWrap:"wrap",gap:12}}>
        <div style={{flex:1}}><div style={{fontWeight:600,fontSize:"var(--ui-fs-h3)"}}>{cur.subj}</div><div className="muted" style={{fontSize:"var(--ui-fs-sm)"}}>{parts(cur).map(n=>n==="Hugo Montenegro"?"Tu":n).join(", ")}{last(cur).to?" · para "+last(cur).to:""}{cur.msgs.length>1?" · "+cur.msgs.length+" mensagens":""}</div></div>
        <div className="row" style={{gap:8,position:"relative"}}>
          <div className="ico-btn" title={folder==="archive"?"Restaurar":"Arquivar"} onClick={()=>archive(cur.i)}><I d={P.folder} size={16}/></div>
          <div className="ico-btn" title="Mover para lista" onClick={()=>setMovePop(v=>!v)}><I d={P.tag} size={16}/></div>
          <div className="ico-btn" title={folder==="spam"?"Não é spam":"Marcar como spam"} onClick={()=>moveTo(cur.i,folder==="spam"?"inbox":"spam")}><I d={P.shield} size={16}/></div>
          <div className="ico-btn" title="Lixo" onClick={()=>moveTo(cur.i,"trash")}><I d={P.trash} size={16}/></div>
          {movePop&&<div style={{position:"absolute",top:"calc(100% + 6px)",right:0,minWidth:180,background:"var(--ui-surface)",border:"1px solid var(--ui-border)",borderRadius:"var(--ui-r-sm)",boxShadow:"var(--ui-elev-2)",padding:6,zIndex:20,display:"flex",flexDirection:"column",gap:2}}>
            <div className="muted" style={{fontSize:"var(--ui-fs-xs)",fontWeight:600,letterSpacing:"0.06em",textTransform:"uppercase",padding:"6px 10px 2px"}}>Mover para</div>
            {lists.map(l=><div key={l} onClick={()=>moveTo(cur.i,"list:"+l)} className="row" style={{gap:8,padding:"8px 10px",borderRadius:6,cursor:"pointer",fontSize:"var(--ui-fs-sm)",fontWeight:500}} onMouseEnter={e=>e.currentTarget.style.background="var(--ui-surface-2)"} onMouseLeave={e=>e.currentTarget.style.background="transparent"}><I d={P.tag} size={14}/>{l}</div>)}
            {lists.length===0&&<div className="muted" style={{padding:"8px 10px",fontSize:"var(--ui-fs-sm)"}}>Sem listas ainda.</div>}
          </div>}
        </div>
      </div>
      {folder==="spam"&&<UIBanner tone="warning">Esta mensagem está marcada como spam. Os links e anexos estão bloqueados.</UIBanner>}
      <div style={{display:"flex",flexDirection:"column"}}>{cur.msgs.map((msg,j)=>{const isLast=j===cur.msgs.length-1;const openMsg=xp[j]!==undefined?xp[j]:isLast;
        return <div key={j} style={{borderBottom:isLast?"none":"1px solid var(--ui-divider)",padding:j===0?"0 0 16px":"16px 0"}}>
          <div className="row" style={{cursor:isLast?"default":"pointer",alignItems:"flex-start"}} onClick={()=>{if(!isLast)setXp(s=>({...s,[j]:!openMsg}));}}>
            {AV(msg.from,"md")}
            <div style={{flex:1,minWidth:0}}><div className="row"><span style={{fontWeight:600}}>{msg.from==="Hugo Montenegro"?"Tu":msg.from}</span><span className="muted" style={{fontSize:"var(--ui-fs-xs)"}}>{msg.time}</span></div>
              {!openMsg&&<div className="muted" style={{fontSize:"var(--ui-fs-sm)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{msg.body[0]}</div>}
            </div>
          </div>
          {openMsg&&<div style={{paddingLeft:44,marginTop:8,display:"flex",flexDirection:"column",gap:12}}>
            <div style={{fontSize:"var(--ui-fs-body)",lineHeight:1.65,color:"var(--ui-text-2)",display:"flex",flexDirection:"column",gap:10}}>{msg.body.map((p,k)=><p key={k} style={{margin:0}}>{p}</p>)}</div>
            {msg.att.length>0&&<div className="row" style={{gap:8,flexWrap:"wrap"}}>{msg.att.map(a=><span key={a} className="row" style={{gap:8,padding:"8px 14px",border:"1px solid var(--ui-border)",borderRadius:"var(--ui-r-sm)",fontSize:"var(--ui-fs-sm)",fontWeight:500,cursor:folder==="spam"?"not-allowed":"pointer",opacity:folder==="spam"?0.5:1}}><I d={P.doc} size={15}/>{a}</span>)}
              {cur.subj==="Contrato para assinatura"&&folder!=="spam"&&<UIButton size="sm" icon={<I d={P.pencil} size={14}/>} onClick={()=>go&&go("profile-documents")}>Rever e assinar</UIButton>}</div>}
          </div>}
        </div>;})}</div>
      {replyMode===null?<div className="row" style={{gap:10,paddingTop:4}}>
        <UIButton size="sm" variant="outline" onClick={()=>{setReplyMode("reply");setReplyText("");}}>Responder</UIButton>
        {parts(cur).filter(n=>n!=="Hugo Montenegro").length>1&&<UIButton size="sm" variant="outline" onClick={()=>{setReplyMode("all");setReplyText("");}}>Responder a todos</UIButton>}
        <UIButton size="sm" variant="ghost" onClick={()=>{setReplyMode("fwd");setReplyText("");}}>Reencaminhar</UIButton></div>
      :<div style={{border:"1px solid var(--ui-border)",borderRadius:"var(--ui-r-md)",padding:16,display:"flex",flexDirection:"column",gap:10}}>
        <div className="muted" style={{fontSize:"var(--ui-fs-sm)",fontWeight:600}}>{replyMode==="reply"?"Responder a "+[...parts(cur)].reverse().find(n=>n!=="Hugo Montenegro"):replyMode==="all"?"Responder a todos ("+parts(cur).filter(n=>n!=="Hugo Montenegro").join(", ")+")":"Reencaminhar \u00ab"+cur.subj+"\u00bb"}</div>
        {replyMode==="fwd"&&<UIInput placeholder="Para" value={cTo} onChange={e=>setCTo(e.target.value)}/>}
        <textarea autoFocus style={taStyle} placeholder="Escreve a tua mensagem…" value={replyText} onChange={e=>setReplyText(e.target.value)}></textarea>
        <div className="row" style={{gap:10}}><UIButton size="sm" disabled={!replyText.trim()} onClick={()=>{if(replyMode==="fwd"){sendMail(cTo||"—","Fwd: "+cur.subj,replyText);}else{appendReply(cur.i,replyText);}setReplyMode(null);setCTo("");}}>Enviar</UIButton><UIButton size="sm" variant="ghost" onClick={()=>setReplyMode(null)}>Cancelar</UIButton></div>
      </div>}
    </div>:<div className="muted" style={{display:narrow?"none":"flex",alignItems:"center",justifyContent:"center",fontSize:"var(--ui-fs-sm)"}}>Seleciona uma mensagem.</div>}</div>
  <UIModal open={compose} onClose={closeCompose} title="Nova mensagem" width={620}
    footer={<div className="row" style={{gap:10,width:"100%"}}>
      <UIButton variant="outline" size="sm" icon={<I d={P.doc} size={15}/>} onClick={()=>setCAtt(a=>[...a,["Relatorio.pdf","Foto.jpg","Folha_calculo.xlsx","Apresentacao.pdf"][a.length%4]])}>Anexar</UIButton>
      <div className="spring" style={{flex:1}}></div>
      <UIButton variant="ghost" onClick={closeCompose}>Guardar rascunho</UIButton>
      <UIButton disabled={!(cToList.length||cTo.trim())||!cSubj.trim()} onClick={()=>{sendMail(cToList.join(", ")||cTo,cSubj,cBody||"(sem texto)",cAtt);resetCompose();setCompose(false);setFolder("sent");}}>Enviar</UIButton></div>}>
    <div style={{display:"flex",flexDirection:"column",gap:12}}>
      <div><div className="row" style={{justifyContent:"space-between",marginBottom:6}}><span style={{fontSize:"var(--ui-fs-sm)",fontWeight:600}}>Para</span><span className="row" style={{gap:12}}>{!showCc&&<span className="muted" style={{fontSize:"var(--ui-fs-sm)",cursor:"pointer",fontWeight:500}} onClick={()=>setShowCc(true)}>Cc</span>}{!showBcc&&<span className="muted" style={{fontSize:"var(--ui-fs-sm)",cursor:"pointer",fontWeight:500}} onClick={()=>setShowBcc(true)}>Bcc</span>}</span></div>
        <div style={{display:"flex",flexWrap:"wrap",gap:8,padding:"8px 10px",border:"1px solid var(--ui-border)",borderRadius:"var(--ui-r-sm)",background:"var(--ui-surface)"}}>
          {cToList.map(t=><span key={t} className="row" style={{gap:8,padding:"4px 10px",borderRadius:999,background:"var(--ui-surface-2)",fontSize:"var(--ui-fs-sm)",fontWeight:500}}>{t}<span style={{cursor:"pointer",color:"var(--ui-text-3)"}} onClick={()=>setCToList(l=>l.filter(x=>x!==t))}>×</span></span>)}
          <input style={{flex:1,minWidth:160,border:"none",outline:"none",background:"transparent",color:"var(--ui-text)",fontFamily:"var(--font-sans)",fontSize:"var(--ui-fs-body)"}} placeholder={cToList.length?"":"Nome ou email…"} value={cTo} onChange={e=>setCTo(e.target.value)} onKeyDown={e=>{if(e.key==="Enter"&&cTo.trim())addTo(sugg[0]?sugg[0][1]:cTo.trim());if(e.key==="Backspace"&&!cTo&&cToList.length)setCToList(l=>l.slice(0,-1));}}/>
        </div>
        {sugg.length>0&&<div style={{border:"1px solid var(--ui-border)",borderRadius:"var(--ui-r-sm)",marginTop:4,overflow:"hidden",boxShadow:"var(--ui-elev-1)"}}>{sugg.map(d=><div key={d[1]} className="row" style={{gap:10,padding:"8px 12px",cursor:"pointer",fontSize:"var(--ui-fs-sm)"}} onMouseEnter={e=>e.currentTarget.style.background="var(--ui-surface-2)"} onMouseLeave={e=>e.currentTarget.style.background="transparent"} onClick={()=>addTo(d[1])}>{AV(d[0],"sm")}<span style={{fontWeight:600}}>{d[0]}</span><span className="muted">{d[1]}</span></div>)}</div>}
      </div>
      {showCc&&<UIInput label="Cc" placeholder="nome@xcope.ai" value={cCc} onChange={e=>setCCc(e.target.value)}/>}
      {showBcc&&<UIInput label="Bcc" placeholder="nome@xcope.ai" value={cBcc} onChange={e=>setCBcc(e.target.value)}/>}
      <UIInput label="Assunto" placeholder="Assunto" value={cSubj} onChange={e=>setCSubj(e.target.value)}/>
      <div><div style={{fontSize:"var(--ui-fs-sm)",fontWeight:600,marginBottom:6}}>Mensagem</div><textarea style={{...taStyle,minHeight:150}} placeholder="Escreve a tua mensagem…" value={cBody} onChange={e=>setCBody(e.target.value)}></textarea></div>
      {cAtt.length>0&&<div className="row" style={{gap:8,flexWrap:"wrap"}}>{cAtt.map((a,i)=><span key={i} className="row" style={{gap:8,padding:"6px 12px",border:"1px solid var(--ui-border)",borderRadius:"var(--ui-r-sm)",fontSize:"var(--ui-fs-sm)",fontWeight:500}}><I d={P.doc} size={14}/>{a}<span style={{cursor:"pointer",color:"var(--ui-text-3)"}} onClick={()=>setCAtt(l=>l.filter((_,j)=>j!==i))}>×</span></span>)}</div>}
    </div>
  </UIModal></UICard></React.Fragment>;};

// S.chat is defined in chat.jsx (Slack-parity messaging module)

// PENDING ITEM CONTRACT — any module emits this shape; the shell renders it without knowing the module.
// {id, module, moduleIcon, company, kind:"action"|"mention"|"info", title, detail, when, due?, actions:[{label,variant}], avatar?}
const PEND=[
  {id:1,module:"Pessoas",mi:"people",co:"norte",kind:"action",title:"Rui Pinto pediu 3 dias de férias",detail:"12-14 ago · saldo 18 dias",when:"há 10 min",due:"Responder até 28 jul",avatar:"Rui Pinto",actions:[{label:"Aprovar",variant:"primary"},{label:"Rejeitar",variant:"secondary"}]},
  {id:2,module:"Documentos",mi:"folder",co:"norte",kind:"action",title:"Contrato de Ana Reis para assinatura",detail:"Aditamento · 2 páginas",when:"há 3 h",due:"Hoje",avatar:"Ana Reis",actions:[{label:"Assinar",variant:"primary"},{label:"Ver",variant:"ghost"}]},
  {id:3,module:"Documentos",mi:"folder",co:"sul",kind:"action",title:"Certificado de formação de Sofia Melo caduca em 6 dias",detail:"Higiene e segurança no trabalho",when:"há 5 h",due:"31 jul",actions:[{label:"Agendar",variant:"primary"},{label:"Adiar",variant:"ghost"}]},
  {id:4,module:"Tickets",mi:"ticket",co:"norte",kind:"action",title:"Ticket #402 atribuído a ti",detail:"Acesso ao portal de despesas",when:"ontem",actions:[{label:"Abrir",variant:"primary"}]},
  {id:5,module:"Avaliações",mi:"survey",co:"tech",kind:"action",title:"Avaliação de desempenho de Zain Franci",detail:"Ciclo H1 2026 · em falta",when:"ontem",due:"1 ago",avatar:"Zain Franci",actions:[{label:"Preencher",variant:"primary"}]},
  {id:6,module:"Chat",mi:"chat",co:"norte",kind:"mention",title:"Carla Dias mencionou-te em #pessoas",detail:"@Hugo podes validar o plano de férias de agosto?",when:"há 1 h",avatar:"Carla Dias",actions:[{label:"Responder",variant:"secondary"}]},
  {id:7,module:"Recrutamento",mi:"career",co:"norte",kind:"mention",title:"Mira Mango mencionou-te numa candidatura",detail:"QA Tester · 2.ª fase",when:"há 4 h",avatar:"Mira Mango",actions:[{label:"Ver",variant:"secondary"}]},
  {id:8,module:"Pessoas",mi:"people",co:"norte",kind:"info",title:"Pedido de férias aprovado",detail:"James Kim · 24-26 mar",when:"há 2 h"},
  {id:9,module:"Ponto",mi:"clock",co:"norte",kind:"info",title:"Registaste saída às 18:04",detail:"8h 12m · ontem",when:"ontem"},
  {id:10,module:"Comunicações",mi:"bell",co:"tech",kind:"info",title:"Nova política de teletrabalho",detail:"Em vigor a 1 de agosto",when:"2 dias"},
];
S.notifications=()=>{const {scope,companies,done,setDone}=useCtx();
  const [tab,setTab]=React.useState("action");const [mod,setMod]=React.useState("all");
  const co=id=>companies.find(c=>c.id===id)||{};
  const inScope=PEND.filter(p=>scope.includes(p.co)&&!done.includes(p.id));
  const counts={action:inScope.filter(p=>p.kind==="action").length,mention:inScope.filter(p=>p.kind==="mention").length,info:inScope.length};
  const ALLMODS=[...new Set(PEND.map(p=>p.module))];
  const mods=ALLMODS;
  const avail=new Set(inScope.filter(p=>tab==="info"||p.kind===tab).map(p=>p.module));
  const list=inScope.filter(p=>(tab==="info"||p.kind===tab)&&(mod==="all"||p.module===mod));
  const resolve=id=>setDone(d=>[...d,id]);
  return <React.Fragment><Head scoped title="Pendentes" desc={counts.action>0?counts.action+" itens precisam de ti":"Nada à tua espera"} actions={<UIButton variant="outline" size="sm" onClick={()=>setDone(PEND.map(p=>p.id))}>Marcar tudo como tratado</UIButton>}/>
  <UICard style={{padding:0,overflow:"hidden",flex:1,display:"flex",flexDirection:"column"}}>
  <div style={{padding:"12px clamp(14px,2vw,20px) 0",borderBottom:"1px solid var(--ui-divider)"}}>
    <UITabs value={tab} onChange={v=>{setTab(v);setMod("all");}} items={[{value:"action",label:"Precisa de ti"+(counts.action?" · "+counts.action:"")},{value:"mention",label:"Menções"+(counts.mention?" · "+counts.mention:"")},{value:"info",label:"Tudo"}]}/>
    {mods.length>1&&<div className="row" style={{gap:8,flexWrap:"wrap",padding:"12px 0"}}>
      {["all",...mods].map(m=>{const on=m==="all"||avail.has(m);return <span key={m} onClick={()=>on&&setMod(m)} title={on?undefined:"Sem itens neste âmbito"} style={{cursor:on?"pointer":"default",opacity:on?1:0.38,fontSize:"var(--ui-fs-xs)",fontWeight:600,padding:"5px 11px",borderRadius:"var(--ui-r-pill)",border:"1px solid "+(mod===m?"transparent":"var(--ui-border)"),background:mod===m?"var(--ui-text)":"var(--ui-surface)",color:mod===m?"var(--ui-bg)":"var(--ui-text-2)",whiteSpace:"nowrap"}}>{m==="all"?"Todos os módulos":m}</span>;})}
    </div>}
  </div>
    {list.length===0?<div className="stub" style={{flex:1}}><div className="stub-ic"><I d={["M20 6 9 17l-5-5"]} size={28}/></div><div style={{fontSize:"var(--ui-fs-h3)",fontWeight:600,color:"var(--ui-text)"}}>Tudo tratado</div><div>Sem itens pendentes neste separador.</div></div>
    :<div style={{flex:1,overflow:"auto"}}>{list.map(p=>{const c=co(p.co);const multi=scope.length>1;
      return <div key={p.id} className="pend" style={{display:"flex",gap:16,padding:"16px clamp(14px,2vw,20px)",borderBottom:"1px solid var(--ui-divider)",alignItems:"flex-start"}}>
        {p.avatar?<UIAvatar name={p.avatar} size="md"/>:<div style={{width:38,height:38,borderRadius:"var(--ui-r-sm)",background:"var(--ui-surface-2)",color:"var(--ui-text-2)",display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0}}><I d={P[p.mi]||P.grid} size={18}/></div>}
        <div style={{flex:1,minWidth:0}}>
          <div className="row" style={{gap:8,marginBottom:3,flexWrap:"wrap"}}>
            <span className="row" style={{gap:5,fontSize:"var(--ui-fs-xs)",fontWeight:600,letterSpacing:"0.04em",textTransform:"uppercase",color:"var(--ui-text-3)"}}><I d={P[p.mi]||P.grid} size={12}/>{p.module}</span>
            {multi&&<span className="row" style={{gap:5,fontSize:"var(--ui-fs-xs)",color:"var(--ui-text-3)"}}><span style={{width:5,height:12,borderRadius:2,background:c.color}}></span>{c.short}</span>}
            {p.due&&<UIPill tone={p.due==="Hoje"?"danger":"warning"} size="sm">{p.due}</UIPill>}
          </div>
          <div style={{fontWeight:600,marginBottom:2}}>{p.title}</div>
          <div className="muted" style={{fontSize:"var(--ui-fs-sm)"}}>{p.detail}</div>
        </div>
        <div style={{display:"flex",flexDirection:"column",alignItems:"flex-end",gap:8,flexShrink:0}}>
          <span className="muted" style={{fontSize:"var(--ui-fs-xs)",whiteSpace:"nowrap"}}>{p.when}</span>
          <div style={{display:"grid",gridTemplateColumns:"100px 76px 32px",gap:8,alignItems:"center"}}>
            <div style={{gridColumn:1}}>{p.actions&&p.actions[0]&&<UIButton size="sm" variant="primary" onClick={()=>resolve(p.id)} style={{width:"100%",justifyContent:"center"}}>{p.actions[0].label}</UIButton>}</div>
            <div style={{gridColumn:2}}>{p.actions&&p.actions[1]&&<UIButton size="sm" variant="ghost" onClick={()=>resolve(p.id)} style={{width:"100%",justifyContent:"center"}}>{p.actions[1].label}</UIButton>}</div>
            <div className="ico-btn" title="Adiar para amanhã" onClick={()=>resolve(p.id)} style={{width:32,height:32,gridColumn:3}}><I d={P.away} size={15}/></div>
          </div>
        </div>
      </div>;})}</div>}
  </UICard></React.Fragment>;};

// S.tasks is defined in tasks.jsx (task board: list + kanban)

S["time-off"]=()=>{
  const SALDO={ferias:{total:22,usados:8},faltas:{total:null,usados:2}};
  const [rows,setRows]=React.useState([
    {id:1,p:"Férias de verão",t:"Férias",di:"04 ago",df:"15 ago",dias:10,s:"Aprovado",por:"Tomás Machado",quando:"há 3 dias"},
    {id:2,p:"Consulta médica",t:"Falta justificada",di:"29 jul",df:"29 jul",dias:1,s:"Pendente",por:null,quando:"ontem"},
    {id:3,p:"Dia pessoal",t:"Pessoal",di:"12 set",df:"12 set",dias:1,s:"Pendente",por:null,quando:"há 5 h"},
  ]);
  const [novo,setNovo]=React.useState(false);
  const [f,setF]=React.useState({t:"Férias",di:"",df:"",motivo:""});
  const [aviso,setAviso]=React.useState(null);
  const [sel,setSel]=React.useState(null);
  React.useEffect(()=>{if(!aviso)return;const x=setTimeout(()=>setAviso(null),3600);return ()=>clearTimeout(x);},[aviso]);

  const pendentes=rows.filter(r=>r.s==="Pendente").length;
  const feriasUsados=rows.filter(r=>r.t==="Férias"&&r.s==="Aprovado").reduce((n,r)=>n+r.dias,0);
  const disponiveis=SALDO.ferias.total-feriasUsados;
  const cur=sel?rows.find(r=>r.id===sel):null;

  const submeter=()=>{
    if(!f.di.trim()){setAviso("Indica a data de início.");return;}
    const dias=Math.max(1,Number(f.dias)||1);
    setRows(rs=>[{id:Date.now(),p:f.motivo.trim()||f.t,t:f.t,di:f.di,df:f.df||f.di,dias,s:"Pendente",por:null,quando:"agora"},...rs]);
    setF({t:"Férias",di:"",df:"",motivo:""});setNovo(false);
    setAviso("Pedido submetido. Segue para aprovação de Tomás Machado e aparece na fila dele.");
  };
  const cancelar=r=>{setRows(rs=>rs.filter(x=>x.id!==r.id));setSel(null);setAviso("Pedido cancelado.");};

  return <React.Fragment>
  <Head title="As minhas ausências" desc={disponiveis+" dias de férias disponíveis · "+pendentes+" pedidos a aguardar"}
    actions={<UIButton icon={<I d={P.plus} size={16}/>} onClick={()=>setNovo(true)}>Novo pedido</UIButton>}/>

  {aviso&&<UIBanner tone={/Indica/.test(aviso)?"warning":"success"} title={/Indica/.test(aviso)?"Falta informação":"Feito"} style={{marginBottom:16}}>{aviso}</UIBanner>}

  <div className="grid g3" style={{marginBottom:16}}>
    <UICard><UIStat label="Férias disponíveis" value={String(disponiveis)} sublabel={"de "+SALDO.ferias.total+" dias · "+feriasUsados+" aprovados"}/></UICard>
    <UICard><UIStat label="Faltas justificadas" value={String(SALDO.faltas.usados)} sublabel="este ano"/></UICard>
    <UICard><UIStat label="A aguardar aprovação" value={String(pendentes)} sublabel={pendentes?"com Tomás Machado":"nada pendente"}/></UICard>
  </div>

  <UICard style={{padding:0,overflow:"hidden",flex:1,minHeight:0,display:"flex",flexDirection:"column"}}>
    <div className="row" style={{padding:"16px 16px 12px"}}><span style={{fontWeight:600,fontSize:"var(--ui-fs-h3)"}}>Histórico de pedidos</span></div>
    <div style={{flex:1,minHeight:0,overflow:"auto",padding:"0 16px 16px"}}>
      <UIDataTable rows={rows} rowKey="id" pageSize={10} onRowClick={r=>setSel(r.id)}
        emptyState={<UIEmptyState title="Sem pedidos" description="Quando pedires uma ausência, aparece aqui." action={<UIButton size="sm" onClick={()=>setNovo(true)}>Novo pedido</UIButton>}/>}
        columns={[
          {key:"p",label:"Pedido",sortable:true,render:(v,r)=><span><span style={{fontWeight:600,display:"block"}}>{v}</span><span className="muted" style={{fontSize:"var(--ui-fs-sm)"}}>{r.quando}</span></span>},
          {key:"t",label:"Tipo",sortable:true,render:v=><UIPill>{v}</UIPill>},
          {key:"di",label:"Datas",render:(v,r)=><span style={{whiteSpace:"nowrap"}}>{r.di===r.df?r.di:r.di+" a "+r.df}</span>},
          {key:"dias",label:"Dias",sortable:true,align:"right",render:v=><span style={{fontVariantNumeric:"tabular-nums"}}>{v}</span>},
          {key:"s",label:"Estado",align:"right",render:(v,r)=><span className="row" style={{gap:8,justifyContent:"flex-end"}}>
            <UIPill tone={v==="Aprovado"?"success":v==="Recusado"?"danger":"warning"} dot>{v}</UIPill>
            {r.por&&<span className="muted" style={{fontSize:"var(--ui-fs-xs)",whiteSpace:"nowrap"}}>{r.por}</span>}</span>},
        ]}/>
    </div>
  </UICard>

  <UIDrawer open={!!cur} width={420} onClose={()=>setSel(null)}
    header={cur&&<span className="row" style={{gap:10}}><UIPill tone={cur.s==="Aprovado"?"success":cur.s==="Recusado"?"danger":"warning"} dot>{cur.s}</UIPill><UIPill>{cur.t}</UIPill></span>}
    footer={cur&&<React.Fragment><div className="spring"/><UIButton variant="ghost" onClick={()=>setSel(null)}>Fechar</UIButton>
      {cur.s==="Pendente"&&<UIButton variant="destructive" onClick={()=>cancelar(cur)}>Cancelar pedido</UIButton>}</React.Fragment>}>
    {cur&&<div style={{display:"flex",flexDirection:"column",gap:24}}>
      <div>
        <div style={{fontSize:"var(--ui-fs-h2)",fontWeight:600,letterSpacing:"var(--ui-ls-h2)"}}>{cur.p}</div>
        <div className="muted" style={{fontSize:"var(--ui-fs-sm)",marginTop:6}}>{cur.di===cur.df?cur.di:cur.di+" a "+cur.df} · {cur.dias} {cur.dias===1?"dia":"dias"}</div>
      </div>
      <div style={{display:"grid",gridTemplateColumns:"116px minmax(0,1fr)",gap:"12px 16px",alignItems:"center",fontSize:"var(--ui-fs-sm)"}}>
        <span className="muted">Submetido</span><span>{cur.quando}</span>
        <span className="muted">Aprovador</span><span>{cur.por||"Tomás Machado (a aguardar)"}</span>
        <span className="muted">Saldo depois</span><span style={{fontVariantNumeric:"tabular-nums"}}>{cur.t==="Férias"?(disponiveis-(cur.s==="Pendente"?cur.dias:0))+" dias":"não conta para férias"}</span>
      </div>
      {cur.s==="Pendente"&&<UIBanner tone="info" title="A aguardar decisão">Está na fila de Tomás Machado. Recebes a resposta na Inbox e o pedido aparece no calendário quando for aprovado.</UIBanner>}
      {cur.s==="Aprovado"&&<UIBanner tone="success" title="Aprovado">Já consta no calendário da equipa e nos Horários como exceção.</UIBanner>}
    </div>}
  </UIDrawer>

  <UIModal open={novo} onClose={()=>setNovo(false)} title="Novo pedido de ausência" width={520}
    footer={<div className="row" style={{gap:8}}><span className="muted" style={{fontSize:"var(--ui-fs-sm)"}}>Vai para aprovação de Tomás Machado</span><div className="spring"/><UIButton variant="ghost" onClick={()=>setNovo(false)}>Cancelar</UIButton><UIButton onClick={submeter}>Submeter pedido</UIButton></div>}>
    <div style={{display:"flex",flexDirection:"column",gap:16}}>
      <UISelect label="Tipo de ausência" value={f.t} onChange={e=>setF({...f,t:e.target.value})} options={["Férias","Falta justificada","Pessoal","Formação","Parental"]}/>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:16}}>
        <UIInput label="Início" placeholder="04 ago" value={f.di} onChange={e=>setF({...f,di:e.target.value})}/>
        <UIInput label="Fim" placeholder="15 ago" value={f.df} onChange={e=>setF({...f,df:e.target.value})}/>
        <UIInput label="Dias úteis" placeholder="10" value={f.dias||""} onChange={e=>setF({...f,dias:e.target.value})}/>
      </div>
      <UIInput label="Motivo" placeholder="Opcional" value={f.motivo} onChange={e=>setF({...f,motivo:e.target.value})}/>
      {f.t==="Férias"&&<div className="muted" style={{fontSize:"var(--ui-fs-sm)"}}>Tens {disponiveis} dias disponíveis. O saldo só é descontado depois da aprovação.</div>}
    </div>
  </UIModal>
  </React.Fragment>;
};

// S["clock-in"] is defined in clock.jsx (punch clock: today, history, locations, QR)

// S.calendar is defined in calendar.jsx

S.schedules=()=>{const shifts=[["Turno manhã","08:00-16:00","Engenharia","Ao vivo","danger"],["Turno tarde","16:00-00:00","Engenharia","8 pessoas","neutral"],["Turno noite","00:00-08:00","Operações","2 pessoas","neutral"]];
  return <React.Fragment><Head title="Horários" desc="Turnos e escalas · 24 jul" actions={<UIButton variant="outline" size="sm" icon={<I d={P.plus} size={15}/>}>Turno</UIButton>}/>
  <div style={{display:"flex",flexDirection:"column",gap:12}}>{shifts.map(([n,h,d,tag,tone])=><UICard key={n}><div className="row"><div style={{width:4,height:44,borderRadius:4,background:tone==="danger"?"var(--ui-danger)":"var(--ui-accent)"}}/><div style={{flex:1}}><div style={{fontWeight:600}}>{n}</div><div className="muted" style={{fontSize:"var(--ui-fs-sm)"}}>{h} · {d}</div></div><UIAvatarGroup size="sm" max={4} avatars={PEOPLE.slice(0,5).map(name=>({name}))}/><UIPill tone={tone} dot={tone==="danger"}>{tag}</UIPill></div></UICard>)}</div></React.Fragment>;};

// S["my-tickets"] and S["admin-tickets"] are defined in tickets.jsx

// S.surveys is defined in surveys.jsx


S["admin-employees"]=({go})=>{const {scope,companies}=useCtx();const cs=companies.filter(c=>scope.includes(c.id));const multi=cs.length>1;
  const rows=PEOPLE.slice(0,6).map((n,i)=>({name:n,co:cs[i%cs.length],role:["QA","UX","HR","BizDev","Data","Eng"][i]+" ",dept:["Eng","Produto","Pessoas","Comercial","Dados","Eng"][i],state:i%3===2?"Ausente":"Ativo",since:2020+i}));
  const [sel,setSel]=React.useState(null);
  return <React.Fragment><Head scoped title="Colaboradores" desc={cs.reduce((n,c)=>n+c.people,0)+" pessoas · "+cs.length+(cs.length>1?" empresas":" empresa")} actions={<UIButton icon={<I d={P.plus} size={16}/>}>Adicionar</UIButton>}/>
  <UICard style={{padding:0,overflow:"hidden",flex:1}}><div style={{padding:"12px 16px 16px"}}><UIDataTable columns={[{key:"name",label:"Colaborador",render:(v,r)=><span className="row" style={{gap:10,fontWeight:600}}>{AV(v)} {v}</span>},...(multi?[{key:"co",label:"Empresa",render:(v)=><span className="row" style={{gap:8}}><span style={{width:6,height:18,borderRadius:3,background:v.color,flexShrink:0}}></span><span style={{fontWeight:500}}>{v.short}</span></span>}]:[]),{key:"role",label:"Função"},{key:"dept",label:"Departamento"},{key:"state",label:"Estado",render:(v)=><UIPill tone={v==="Ativo"?"success":"warning"} dot>{v}</UIPill>},{key:"since",label:"Desde",align:"right"}]} rows={rows} onRowClick={r=>setSel(r)}/></div></UICard>
  <UIDrawer open={!!sel} width={420} onClose={()=>setSel(null)}
    header={sel&&<span className="row" style={{gap:12}}>{AV(sel.name,"md")}<span><span style={{fontWeight:600,display:"block"}}>{sel.name}</span><span className="muted" style={{fontSize:"var(--ui-fs-sm)"}}>{sel.role}· {sel.dept}</span></span></span>}
    footer={sel&&<React.Fragment><UIButton variant="outline" onClick={()=>{setSel(null);go&&go("chat");}}>Enviar mensagem</UIButton><div className="spring"/><UIButton variant="ghost" onClick={()=>setSel(null)}>Fechar</UIButton></React.Fragment>}>
    {sel&&<div style={{display:"flex",flexDirection:"column",gap:22}}>
      <div className="row" style={{gap:8,flexWrap:"wrap"}}>
        <UIPill tone={sel.state==="Ativo"?"success":"warning"} dot>{sel.state}</UIPill>
        {sel.co&&<UIPill><span className="row" style={{gap:6}}><span style={{width:8,height:8,borderRadius:3,background:sel.co.color}}/>{sel.co.name}</span></UIPill>}
      </div>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:16}}>
        {[["Função",sel.role],["Departamento",sel.dept],["Na empresa desde",sel.since],["Email",sel.name.toLowerCase().split(" ").join(".")+"@xcope.ai"]].map(([l,v])=>
          <div key={l}><div className="muted" style={{fontSize:"var(--ui-fs-xs)",fontWeight:600,letterSpacing:"0.06em",textTransform:"uppercase",marginBottom:4}}>{l}</div><div style={{fontWeight:500,overflow:"hidden",textOverflow:"ellipsis"}}>{v}</div></div>)}
      </div>
      <div className="row" style={{gap:10,padding:"12px 14px",borderRadius:"var(--ui-r-md)",background:"var(--ui-surface-2)",fontSize:"var(--ui-fs-sm)"}}>
        <I d={P.badge} size={16} c="var(--ui-text-3)"/>
        <span>Contrato sem termo · horário flexível · {sel.state==="Ausente"?"ausente hoje":"presente hoje"}</span>
      </div>
    </div>}
  </UIDrawer></React.Fragment>;};

S.group=()=>{const {companies}=useCtx();const acc=companies.filter(c=>!c.noAccess);
  const [sel,setSel]=React.useState(null);
  return <React.Fragment><Head title={GROUP.name} desc={"Visão consolidada · "+acc.length+" empresas · "+acc.reduce((n,c)=>n+c.people,0)+" pessoas"} actions={<UIButton variant="outline" size="sm" icon={<I d={P.exp} size={15}/>}>Exportar consolidado</UIButton>}/>
  <div className="grid g4" style={{marginBottom:16}}>{[["Pessoas",acc.reduce((n,c)=>n+c.people,0),"+12 este mês","up"],["Empresas",acc.length,"1 sem acesso",""],["Ausências hoje","14","5% da força",""],["Custo mensal","1,24 M€","+3,1% vs. junho","up"]].map(([l,v,d])=><UICard key={l}><UIStat label={l} value={String(v)} delta={d}/></UICard>)}</div>
  <UICard style={{padding:0,overflow:"hidden",flex:1}}>
    <div style={{padding:"16px 20px 8px",fontWeight:600,fontSize:"var(--ui-fs-h3)"}}>Empresas do grupo</div>
    <div style={{padding:"12px 16px 16px"}}><UIDataTable columns={[
      {key:"name",label:"Empresa",render:(v,r)=><span className="row" style={{gap:10,fontWeight:600}}><span style={{width:26,height:26,borderRadius:7,background:r.color,color:"#fff",fontWeight:600,fontSize:"var(--ui-fs-xs)",display:"flex",alignItems:"center",justifyContent:"center"}}>{r.short}</span>{v}</span>},
      {key:"city",label:"Sede"},{key:"people",label:"Pessoas",align:"right"},
      {key:"role",label:"O teu papel",render:(v,r)=><UIPill tone={r.noAccess?"neutral":"info"}>{v}</UIPill>}]} rows={companies} onRowClick={r=>setSel(r)}/></div>
  </UICard>
  <UIDrawer open={!!sel} width={420} onClose={()=>setSel(null)}
    header={sel&&<span className="row" style={{gap:12,fontWeight:600}}><span style={{width:30,height:30,borderRadius:8,background:sel.color,color:"#fff",fontWeight:600,fontSize:"var(--ui-fs-xs)",display:"flex",alignItems:"center",justifyContent:"center"}}>{sel.short}</span>{sel.name}</span>}
    footer={sel&&<React.Fragment><div className="spring"/><UIButton variant="ghost" onClick={()=>setSel(null)}>Fechar</UIButton></React.Fragment>}>
    {sel&&<div style={{display:"flex",flexDirection:"column",gap:22}}>
      <div className="row" style={{gap:8}}><UIPill tone={sel.noAccess?"neutral":"info"}>{sel.role}</UIPill>{sel.noAccess&&<UIPill tone="warning" dot>Sem acesso</UIPill>}</div>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:16}}>
        {[["Sede",sel.city],["Pessoas",sel.people],["Unidade",sel.name],["Grupo","Xcope"]].map(([l,v])=>
          <div key={l}><div className="muted" style={{fontSize:"var(--ui-fs-xs)",fontWeight:600,letterSpacing:"0.06em",textTransform:"uppercase",marginBottom:4}}>{l}</div><div style={{fontWeight:500}}>{v}</div></div>)}
      </div>
      {sel.noAccess
        ? <div className="row" style={{gap:10,padding:"12px 14px",borderRadius:"var(--ui-r-md)",background:"var(--ui-surface-2)",fontSize:"var(--ui-fs-sm)"}}><I d={P.shield} size={16} c="var(--ui-text-3)"/><span>Não tens acesso aos dados desta empresa. Pede acesso a um administrador do grupo.</span></div>
        : <div className="row" style={{gap:10,padding:"12px 14px",borderRadius:"var(--ui-r-md)",background:"var(--ui-surface-2)",fontSize:"var(--ui-fs-sm)"}}><I d={P.building||P.grid} size={16} c="var(--ui-text-3)"/><span>Usa o seletor no topo da barra lateral para trabalhar nesta empresa.</span></div>}
    </div>}
  </UIDrawer></React.Fragment>;};

S["admin-teams"]=()=>{const teams=[["Engenharia",42,"online"],["Produto",18,"online"],["Pessoas",9,"away"],["Comercial",23,"online"],["Operações",31,"online"],["Dados",7,"away"]];
  return <React.Fragment><Head title="Equipas" desc="6 equipas" actions={<UIButton icon={<I d={P.plus} size={16}/>}>Nova equipa</UIButton>}/>
  <div className="grid g3">{teams.map(([n,c])=><UICard key={n}><div style={{fontWeight:600,fontSize:"var(--ui-fs-h3)"}}>{n}</div><div className="muted" style={{fontSize:"var(--ui-fs-sm)",margin:"4px 0 12px"}}>{c} pessoas</div><UIAvatarGroup size="sm" max={5} avatars={PEOPLE.map(name=>({name}))}/></UICard>)}</div></React.Fragment>;};

S["admin-roles"]=()=>{const rows=[{r:"Administrador",u:3,p:"Acesso total"},{r:"CEO",u:5,p:"Pessoas, ausências, docs"},{r:"Diretor intermédio",u:12,p:"Equipa própria"},{r:"Trabalhador",u:227,p:"Self-service"}];
  const PERMS={"Administrador":["Acesso total a todas as áreas","Gestão de utilizadores e funções","Configuração do tenant e faturação","Auditoria e registos de atividade"],"CEO":["Pessoas: ler e editar em todo o grupo","Ausências: aprovar sem limite","Documentos: ler, editar e partilhar","Relatórios e custo com pessoal"],"Diretor intermédio":["Equipa própria: ler e editar","Ausências da equipa: aprovar","Relatórios de tempo da equipa"],"Trabalhador":["Self-service: perfil, ausências e despesas","Diretório: consultar","Tickets: abrir e acompanhar"]};
  const [sel,setSel]=React.useState(null);
  return <React.Fragment><Head title="Funções e permissões" desc="Modelo de acessos (RBAC) — configurável por tenant" actions={<UIButton icon={<I d={P.plus} size={16}/>}>Nova função</UIButton>}/>
  <UIBanner tone="info" title="Camada de acessos" style={{marginBottom:16}}>Cada tenant define a sua hierarquia. As páginas são as mesmas; as funções decidem o que cada pessoa vê e pode fazer.</UIBanner>
  <UICard style={{padding:0,overflow:"hidden"}}><div style={{padding:"12px 16px 16px"}}><UIDataTable columns={[{key:"r",label:"Função",render:(v)=><span className="row" style={{gap:8,fontWeight:600}}><I d={P.shield} size={16} c="var(--ui-text-3)"/>{v}</span>},{key:"u",label:"Utilizadores"},{key:"p",label:"Permissões",align:"right",render:(v)=><span className="muted">{v}</span>}]} rows={rows} onRowClick={r=>setSel(r)}/></div></UICard>
  <UIDrawer open={!!sel} width={420} onClose={()=>setSel(null)}
    header={sel&&<span className="row" style={{gap:10,fontWeight:600}}><I d={P.shield} size={18} c="var(--ui-text-3)"/>{sel.r}</span>}
    footer={sel&&<React.Fragment><div className="spring"/><UIButton variant="ghost" onClick={()=>setSel(null)}>Fechar</UIButton></React.Fragment>}>
    {sel&&<div style={{display:"flex",flexDirection:"column",gap:22}}>
      <div className="row" style={{gap:8}}><UIPill tone="info">{sel.u} {sel.u===1?"utilizador":"utilizadores"}</UIPill><UIPill>{sel.p}</UIPill></div>
      <div>
        <div className="muted" style={{fontSize:"var(--ui-fs-xs)",fontWeight:600,letterSpacing:"0.06em",textTransform:"uppercase",marginBottom:10}}>O que esta função pode fazer</div>
        {(PERMS[sel.r]||[]).map(p=><div key={p} className="row" style={{gap:10,padding:"9px 0",borderBottom:"1px solid var(--ui-divider)",fontSize:"var(--ui-fs-sm)"}}>
          <I d={["m5 12 4.5 4.5L19 7"]} size={15} c="var(--ui-success)"/><span>{p}</span></div>)}
      </div>
      <div className="muted" style={{fontSize:"var(--ui-fs-sm)"}}>As permissões aplicam-se por tenant. Alterações entram em vigor no próximo início de sessão.</div>
    </div>}
  </UIDrawer></React.Fragment>;};

S["admin-org"]=()=>{const box=(n,r,accent)=><div style={{padding:"12px 16px",borderRadius:"var(--ui-r-md)",border:"1px solid var(--ui-border-2)",background:accent?"var(--ui-accent)":"var(--ui-surface)",color:accent?"var(--ui-on-accent)":"var(--ui-text)",textAlign:"center",minWidth:150}}><div style={{fontWeight:600}}>{n}</div><div style={{fontSize:"var(--ui-fs-sm)",opacity:0.8}}>{r}</div></div>;
  return <React.Fragment><Head title="Organograma" desc="Estrutura da empresa"/>
  <UICard><div style={{display:"flex",flexDirection:"column",alignItems:"center",gap:22,padding:"12px 0"}}>
    {box("Hugo Montenegro","CEO",true)}
    <div style={{display:"flex",gap:24}}>{[["Hugo Montenegro","Diretora RH"],["Tomás Jervell","BizDev"],["Rui Pinto","Eng Lead"]].map(([n,r])=>box(n,r))}</div>
    <div style={{display:"flex",gap:16,flexWrap:"wrap",justifyContent:"center"}}>{PEOPLE.slice(0,5).map(n=>box(n,"Colaborador"))}</div>
  </div></UICard></React.Fragment>;};

// S.settings (Definições) é definido em hr.jsx: aparência, conta, notificações, organização, integrações e faturação.

// stubs for the remaining routes
const STUBS={};
Object.keys(STUBS).forEach(k=>{S[k]=()=>{const [ic,t,d]=STUBS[k];return <React.Fragment><Head title={LABELS[k]||t}/><UICard style={{flex:1,display:"flex",flexDirection:"column",justifyContent:"center"}}><Stub icon={ic} desc={d}/></UICard></React.Fragment>;};});

