// ===== Finanzas: ingresos (cobros) vs gastos + análisis =====
function Finanzas({ orders, expenses, setExpenses, sales = [], inventory = [], attendance = [], users = [], currentUser }){
  const [modal, setModal] = React.useState(false);
  const [cierre, setCierre] = React.useState(false);
  const [month, setMonth] = React.useState("all");
  const [fTech, setFTech] = React.useState("all");
  const [fDevice, setFDevice] = React.useState("all");
  const [fMethod, setFMethod] = React.useState("all");

  // helpers de composición de una orden
  const partsChargeOf = o => orderParts(o).reduce((s,p)=>s+(+p.price||0)*(+p.qty||1),0);
  const laborOf = o => Math.max(0, (+o.estimate||0) - partsChargeOf(o));

  // ---- ingresos (base caja: pagos + ventas), etiquetados para filtrar ----
  const incomeEvents = [];
  orders.forEach(o=>{
    orderPayments(o).forEach((p,i)=>{
      incomeEvents.push({ id:o.id+"-p"+i, t:p.t, amount:+p.amount||0, concept:`Cobro orden #${o.num}`, sub:`${o.brand} ${o.model} · ${p.method||"pago"}`, num:o.num, tech:o.techId, device:o.device, method:p.method||"efectivo" });
    });
  });
  sales.filter(s=>!s.voided).forEach(s=>{
    incomeEvents.push({ id:s.id, t:s.date, amount:+s.total||0, concept:`Venta mostrador #${s.num}`, sub:`${s.items.length} artículo(s) · ${s.method}`, num:s.num, tech:null, device:null, method:s.method });
  });

  const allMonths = Array.from(new Set([...incomeEvents.map(e=>monthKey(e.t)), ...expenses.map(e=>monthKey(e.date))])).sort().reverse();
  const inRange = (iso)=> month==="all" || monthKey(iso)===month;
  const attrActive = fTech!=="all" || fDevice!=="all" || fMethod!=="all";
  const matchAttr = (ev)=> (fTech==="all" || ev.tech===fTech) && (fDevice==="all" || ev.device===fDevice) && (fMethod==="all" || ev.method===fMethod);

  const fIncomeEvents = incomeEvents.filter(e=> inRange(e.t) && matchAttr(e));
  const income = fIncomeEvents.reduce((s,e)=>s+e.amount,0);
  // los gastos no tienen técnico/equipo/método → se excluyen cuando hay filtros de atributo activos
  const fExpenses = expenses.filter(e=> inRange(e.date) && !attrActive);
  const expense = fExpenses.reduce((s,e)=>s+e.amount,0);
  const profit = income - expense;
  const margin = income>0 ? Math.round((profit/income)*100) : 0;

  // ---- análisis de facturación (base devengado: presupuestos + ventas del periodo) ----
  const ordersScope = orders.filter(o => (month==="all"||monthKey(o.createdAt)===month) && (fTech==="all"||o.techId===fTech) && (fDevice==="all"||o.device===fDevice));
  const salesScope = sales.filter(s => !s.voided && (month==="all"||monthKey(s.date)===month) && (fMethod==="all"||s.method===fMethod) && fTech==="all" && fDevice==="all");
  const laborRev = ordersScope.reduce((s,o)=>s+laborOf(o),0);
  const partsRev = ordersScope.reduce((s,o)=>s+partsChargeOf(o),0) + salesScope.reduce((s,sl)=>s+sl.items.reduce((a,i)=>a+(i.price*i.qty),0),0);
  const partsCost = ordersScope.reduce((s,o)=>s+orderPartsCost(o),0) + salesScope.reduce((s,sl)=>s+sl.items.reduce((a,i)=>a+((i.cost||0)*i.qty),0),0);
  const partsMargin = partsRev - partsCost;
  const markup = partsCost>0 ? Math.round((partsRev/partsCost-1)*100) : 0;
  const facturado = laborRev + partsRev;
  const txCount = ordersScope.length + salesScope.length;
  const ticketProm = txCount>0 ? facturado/txCount : 0;
  const laborShare = facturado>0 ? Math.round((laborRev/facturado)*100) : 0;

  // ---- cuentas por cobrar + antigüedad ----
  const pend = orders.filter(o => o.status!=="entregado" && orderBalance(o)>0 && (fTech==="all"||o.techId===fTech) && (fDevice==="all"||o.device===fDevice));
  const receivable = pend.reduce((s,o)=> s + orderBalance(o), 0);
  const aging = { b0:0, b30:0, b60:0, b90:0 };
  const agingCount = { b0:0, b30:0, b60:0, b90:0 };
  pend.forEach(o=>{
    const days = (Date.now() - new Date(o.createdAt).getTime())/864e5;
    const bal = orderBalance(o);
    const k = days<=30?"b0":days<=60?"b30":days<=90?"b60":"b90";
    aging[k]+=bal; agingCount[k]+=1;
  });

  // ---- ingresos estimados en proceso (no entregadas, sin facturar) ----
  const inProcess = orders.filter(o => o.status!=="entregado" && (fTech==="all"||o.techId===fTech) && (fDevice==="all"||o.device===fDevice));
  const inProcessValue = inProcess.reduce((s,o)=> s + (+o.estimate||0), 0);

  // ---- inventario ----
  const invValue = inventory.reduce((s,i)=> s + i.stock*i.cost, 0);
  const reorderAmount = inventory.filter(i=>i.stock<i.min).reduce((s,i)=> s + (i.min-i.stock)*i.cost, 0);
  const lowCount = inventory.filter(i=>i.stock<=i.min).length;

  // expense by category
  const byCat = EXPENSE_CATEGORIES.map(c=>({ ...c, total: fExpenses.filter(e=>e.cat===c.id).reduce((s,e)=>s+e.amount,0) })).filter(c=>c.total>0).sort((a,b)=>b.total-a.total);
  const maxCat = Math.max(...byCat.map(c=>c.total), 1);

  // monthly trend (respeta filtros de atributo en ingresos)
  const trend = allMonths.slice(0,6).reverse().map(m=>{
    const inc = incomeEvents.filter(e=>monthKey(e.t)===m && matchAttr(e)).reduce((s,e)=>s+e.amount,0);
    const exp = attrActive ? 0 : expenses.filter(e=>monthKey(e.date)===m).reduce((s,e)=>s+e.amount,0);
    return { m, inc, exp };
  });
  const maxTrend = Math.max(...trend.flatMap(t=>[t.inc,t.exp]), 1);

  // combined ledger
  const ledger = [
    ...fIncomeEvents.map(e=>({ ...e, type:"in", date:e.t })),
    ...fExpenses.map(e=>({ ...e, type:"out", concept:e.concept, sub:`${getExpCat(e.cat).label} · ${e.supplier}` })),
  ].sort((a,b)=> new Date(b.date)-new Date(a.date));

  function addExpense(e){ setExpenses(prev=>[e, ...prev]); setModal(false); }
  function clearFilters(){ setFTech("all"); setFDevice("all"); setFMethod("all"); }

  // ---- Tanda B: proyección de flujo de caja, rentabilidad por técnico, abandonados ----
  const DAY = 864e5; const nowMs = Date.now();
  const last30Income = incomeEvents.filter(e => (nowMs - new Date(e.t).getTime()) <= 30*DAY).reduce((s,e)=>s+e.amount,0);
  const last30Expense = expenses.filter(e => (nowMs - new Date(e.date).getTime()) <= 30*DAY).reduce((s,e)=>s+e.amount,0);
  const avgDailyIncome = last30Income/30;
  const avgDailyExpense = last30Expense/30;
  const monthlyFixed = expenses.filter(e => ["renta","servicios","sueldos"].includes(e.cat) && (nowMs-new Date(e.date).getTime())<=45*DAY).reduce((s,e)=>s+e.amount,0);
  const projDailyNet = avgDailyIncome - avgDailyExpense;
  const proj30 = projDailyNet*30;
  const fcPoints = []; for(let d=0; d<=30; d++) fcPoints.push(projDailyNet*d);
  const fcMin = Math.min(0, ...fcPoints); const fcMax = Math.max(0, ...fcPoints);
  const FW=300, FH=104, FP=10;
  const fcX = d => FP + (d/30)*(FW-2*FP);
  const fcY = v => { const range=(fcMax-fcMin)||1; return FH-FP - ((v-fcMin)/range)*(FH-2*FP); };
  const fcPath = fcPoints.map((v,d)=>`${d===0?"M":"L"}${fcX(d).toFixed(1)} ${fcY(v).toFixed(1)}`).join(" ");
  const fcArea = `${fcPath} L${fcX(30).toFixed(1)} ${fcY(0).toFixed(1)} L${fcX(0).toFixed(1)} ${fcY(0).toFixed(1)} Z`;
  const fcPositive = proj30>=0;

  // rentabilidad por técnico (cruce reloj × ingresos)
  const techStats = TECHS.map(tt=>{
    const recs = attendance.filter(r => r.userId===tt.id && inRange(r.in));
    const hours = recs.reduce((s,r)=>s+attHours(r),0);
    const inc = incomeEvents.filter(e => e.tech===tt.id && inRange(e.t)).reduce((s,e)=>s+e.amount,0);
    const closed = orders.filter(o => o.techId===tt.id && o.status==="entregado" && inRange(o.createdAt)).length;
    return { tt, hours, inc, closed, perHour: hours>0 ? inc/hours : 0 };
  }).filter(s => s.hours>0 || s.inc>0).sort((a,b)=> b.perHour-a.perHour);
  const maxPerHour = Math.max(...techStats.map(s=>s.perHour), 1);

  // equipos abandonados / no reclamados (listo > 30 días sin entregar, o rechazado/no reparado)
  const ABANDON_DAYS = 30;
  const abandoned = orders.filter(o => (o.status==="listo" && (nowMs-new Date(o.createdAt).getTime()) > ABANDON_DAYS*DAY) || ["rechazado","no_reparado"].includes(o.outcome));
  const abandonLoss = abandoned.reduce((s,o)=> s + orderPartsCost(o), 0);
  const abandonRate = orders.length>0 ? Math.round((abandoned.length/orders.length)*100) : 0;

  const monthName = month==="all" ? "Todo el periodo" : monthLabel(month+"-01");
  const techs = TECHS;

  const selStyle = { appearance:"none", padding:"9px 30px 9px 12px", fontSize:13, fontWeight:600, color:"var(--ink-2)", border:"1px solid var(--line)", borderRadius:10, background:"var(--surface)", cursor:"pointer" };
  const Sel = ({ value, onChange, children }) => (
    <div style={{ position:"relative" }}>
      <select value={value} onChange={e=>onChange(e.target.value)} style={selStyle}>{children}</select>
      <Icon name="chevronDown" size={14} style={{ position:"absolute", right:9, top:"50%", transform:"translateY(-50%)", color:"var(--faint)", pointerEvents:"none" }} />
    </div>
  );

  return (
    <div style={{ display:"flex", flexDirection:"column", gap:16, animation:"fadeUp .35s ease" }}>
      {/* header + filtros */}
      <div style={{ display:"flex", alignItems:"center", gap:10, flexWrap:"wrap" }}>
        <div style={{ position:"relative" }}>
          <select value={month} onChange={e=>setMonth(e.target.value)}
            style={{ ...selStyle, fontSize:14, fontWeight:700, color:"var(--ink)", padding:"9px 34px 9px 14px", textTransform:"capitalize" }}>
            <option value="all">Todo el periodo</option>
            {allMonths.map(m=><option key={m} value={m} style={{ textTransform:"capitalize" }}>{monthLabel(m+"-01")}</option>)}
          </select>
          <Icon name="chevronDown" size={15} style={{ position:"absolute", right:12, top:"50%", transform:"translateY(-50%)", color:"var(--faint)", pointerEvents:"none" }} />
        </div>
        <div style={{ width:1, height:24, background:"var(--line)" }} />
        <Sel value={fTech} onChange={setFTech}><option value="all">Todo técnico</option>{techs.map(t=><option key={t.id} value={t.id}>{t.name}</option>)}</Sel>
        <Sel value={fDevice} onChange={setFDevice}><option value="all">Toda categoría</option>{DEVICE_TYPES.map(d=><option key={d.id} value={d.id}>{d.label}</option>)}</Sel>
        <Sel value={fMethod} onChange={setFMethod}><option value="all">Todo pago</option><option value="efectivo">Efectivo</option><option value="tarjeta">Tarjeta</option><option value="transferencia">Transferencia</option></Sel>
        {attrActive && <button onClick={clearFilters} style={{ display:"inline-flex", alignItems:"center", gap:5, border:"none", background:"transparent", color:"var(--accent-ink)", fontSize:12.5, fontWeight:600 }}><Icon name="x" size={14} /> Limpiar filtros</button>}
        <div style={{ marginLeft:"auto", display:"flex", gap:8 }}>
          <Btn variant="secondary" icon="wallet" onClick={()=>setCierre(true)}>Cierre de caja</Btn>
          <Btn icon="plus" onClick={()=>setModal(true)}>Registrar gasto</Btn>
        </div>
      </div>

      {attrActive && (
        <div style={{ display:"flex", alignItems:"center", gap:8, fontSize:12.5, color:"var(--muted)", marginTop:-6 }}>
          <Icon name="filter" size={14} /> Mostrando solo ingresos filtrados. Los gastos generales se ocultan mientras filtras por técnico, categoría o método.
        </div>
      )}

      {/* alerta de liquidez */}
      {profit<0 && (
        <Card pad={14} style={{ background:"var(--danger-soft)", borderColor:"oklch(0.82 0.12 25)" }}>
          <div style={{ display:"flex", alignItems:"center", gap:11 }}>
            <span style={{ width:36, height:36, borderRadius:10, flexShrink:0, display:"flex", alignItems:"center", justifyContent:"center", background:"var(--surface)", color:"var(--danger)" }}><Icon name="warning" size={20} /></span>
            <div>
              <div style={{ fontSize:14, fontWeight:800, color:"var(--danger)" }}>Alerta de liquidez</div>
              <div style={{ fontSize:12.5, color:"var(--ink-2)", marginTop:1 }}>El balance del periodo es negativo ({fmtMoney(profit)}). Revisa gastos o acelera cobros pendientes ({fmtMoney(receivable)} por cobrar).</div>
            </div>
          </div>
        </Card>
      )}

      {/* P&L cards */}
      <div style={{ display:"grid", gridTemplateColumns:"repeat(4,1fr)", gap:16 }}>
        <Card pad={20} style={{ borderColor:"oklch(0.88 0.06 155)" }}>
          <div style={{ display:"flex", alignItems:"center", gap:9, color:"var(--st-listo)" }}><Icon name="arrowRight" size={18} style={{ transform:"rotate(-45deg)" }} /><span style={{ fontSize:13, fontWeight:700 }}>Ingresos</span></div>
          <div className="mono" style={{ fontSize:30, fontWeight:800, marginTop:10, letterSpacing:"-0.02em", color:"var(--st-listo)" }}>{fmtMoney(income)}</div>
          <div style={{ fontSize:12.5, color:"var(--muted)", marginTop:2 }}>cobros a clientes</div>
        </Card>
        <Card pad={20} style={{ borderColor:"oklch(0.86 0.09 25)" }}>
          <div style={{ display:"flex", alignItems:"center", gap:9, color:"var(--danger)" }}><Icon name="arrowRight" size={18} style={{ transform:"rotate(45deg)" }} /><span style={{ fontSize:13, fontWeight:700 }}>Gastos</span></div>
          <div className="mono" style={{ fontSize:30, fontWeight:800, marginTop:10, letterSpacing:"-0.02em", color:"var(--danger)" }}>{fmtMoney(expense)}</div>
          <div style={{ fontSize:12.5, color:"var(--muted)", marginTop:2 }}>compras y operación</div>
        </Card>
        <Card pad={20} style={{ background: profit>=0?"linear-gradient(135deg, var(--accent-soft), var(--surface))":"var(--danger-soft)", borderColor: profit>=0?"oklch(0.84 0.07 256)":"oklch(0.82 0.12 25)" }}>
          <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between" }}>
            <div style={{ display:"flex", alignItems:"center", gap:9, color: profit>=0?"var(--accent-ink)":"var(--danger)" }}><Icon name="chart" size={18} /><span style={{ fontSize:13, fontWeight:700 }}>Ganancia neta</span></div>
            {profit<0 && <span style={{ fontSize:10, fontWeight:800, color:"#fff", background:"var(--danger)", padding:"2px 7px", borderRadius:99 }}>ALERTA</span>}
          </div>
          <div className="mono" style={{ fontSize:30, fontWeight:800, marginTop:10, letterSpacing:"-0.02em", color: profit>=0?"var(--accent-ink)":"var(--danger)" }}>{fmtMoney(profit)}</div>
          <div style={{ fontSize:12.5, color:"var(--muted)", marginTop:2 }}>margen {margin}% · {monthName.toLowerCase()}</div>
        </Card>
        <Card pad={20} style={{ borderColor:"oklch(0.86 0.08 70)" }}>
          <div style={{ display:"flex", alignItems:"center", gap:9, color:"var(--st-entrada)" }}><Icon name="clock" size={18} /><span style={{ fontSize:13, fontWeight:700 }}>Por cobrar</span></div>
          <div className="mono" style={{ fontSize:30, fontWeight:800, marginTop:10, letterSpacing:"-0.02em", color:"var(--st-entrada)" }}>{fmtMoney(receivable)}</div>
          <div style={{ fontSize:12.5, color:"var(--muted)", marginTop:2 }}>{pend.length} {pend.length===1?"orden pendiente":"órdenes pendientes"}</div>
        </Card>
      </div>

      {/* análisis de rentabilidad */}
      <div style={{ display:"grid", gridTemplateColumns:"repeat(4,1fr)", gap:16 }}>
        <AnalysisCard icon="orders" hue={256} label="Ticket promedio" value={fmtMoney(ticketProm)} sub={`${txCount} ${txCount===1?"transacción":"transacciones"} · facturado ${fmtMoney(facturado)}`} />
        <AnalysisCard icon="tools" hue={200} label="Mano de obra" value={fmtMoney(laborRev)} sub={`${laborShare}% de la facturación · ~100% margen`} />
        <AnalysisCard icon="chip" hue={155} label="Repuestos (margen)" value={fmtMoney(partsMargin)} sub={`venta ${fmtMoney(partsRev)} · costo ${fmtMoney(partsCost)}`} />
        <AnalysisCard icon="chart" hue={70} label="Markup repuestos" value={markup+"%"} sub="ganancia sobre el costo de piezas" emph />
      </div>

      {/* cobrar (aging) + en proceso + inventario */}
      <div style={{ display:"grid", gridTemplateColumns:"1.3fr 1fr", gap:16, alignItems:"start" }}>
        {/* aging AR */}
        <Card>
          <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between", marginBottom:4 }}>
            <h3 style={{ fontSize:15.5, fontWeight:700, margin:0 }}>Antigüedad de cuentas por cobrar</h3>
            <span className="mono" style={{ fontSize:14, fontWeight:800, color:"var(--st-entrada)" }}>{fmtMoney(receivable)}</span>
          </div>
          <p style={{ fontSize:12.5, color:"var(--muted)", margin:"0 0 16px" }}>Saldo pendiente de equipos sin entregar, por tiempo de espera</p>
          {receivable===0 ? <p style={{ fontSize:13, color:"var(--faint)", fontStyle:"italic" }}>Sin saldos pendientes. ¡Todo cobrado!</p> : (
            <div style={{ display:"flex", flexDirection:"column", gap:12 }}>
              {[["b0","0 – 30 días","oklch(0.62 0.14 155)"],["b30","31 – 60 días","oklch(0.72 0.14 80)"],["b60","61 – 90 días","oklch(0.68 0.16 50)"],["b90","Más de 90 días","oklch(0.58 0.19 25)"]].map(([k,label,color])=>{
                const amt = aging[k]; const cnt = agingCount[k];
                const pct = receivable>0 ? (amt/receivable)*100 : 0;
                return (
                  <div key={k}>
                    <div style={{ display:"flex", justifyContent:"space-between", fontSize:13, marginBottom:5 }}>
                      <span style={{ display:"inline-flex", alignItems:"center", gap:7, fontWeight:600, color:"var(--ink-2)" }}>
                        <span style={{ width:9, height:9, borderRadius:3, background:color }} /> {label}
                        {k==="b90" && amt>0 && <span style={{ fontSize:10.5, fontWeight:700, color:"var(--danger)", background:"var(--danger-soft)", padding:"1px 7px", borderRadius:99 }}>RIESGO</span>}
                      </span>
                      <span><span style={{ fontSize:11.5, color:"var(--faint)", marginRight:8 }}>{cnt} {cnt===1?"orden":"órdenes"}</span><span className="mono" style={{ fontWeight:700 }}>{fmtMoney(amt)}</span></span>
                    </div>
                    <div style={{ height:8, borderRadius:99, background:"var(--line-2)", overflow:"hidden" }}>
                      <div style={{ width:`${pct}%`, height:"100%", borderRadius:99, background:color, minWidth: amt>0?6:0 }} />
                    </div>
                  </div>
                );
              })}
            </div>
          )}
        </Card>

        {/* en proceso + inventario salud */}
        <div style={{ display:"flex", flexDirection:"column", gap:16 }}>
          <Card pad={18} style={{ background:"linear-gradient(135deg, var(--accent-soft), var(--surface))", borderColor:"oklch(0.85 0.06 256)" }}>
            <div style={{ display:"flex", alignItems:"center", gap:9, color:"var(--accent-ink)" }}><Icon name="box" size={18} /><span style={{ fontSize:13, fontWeight:700 }}>Ingresos estimados en proceso</span></div>
            <div className="mono" style={{ fontSize:28, fontWeight:800, marginTop:9, letterSpacing:"-0.02em", color:"var(--accent-ink)" }}>{fmtMoney(inProcessValue)}</div>
            <div style={{ fontSize:12.5, color:"var(--muted)", marginTop:2 }}>{inProcess.length} equipos en reparación/listos por facturar</div>
          </Card>
          <Card pad={18}>
            <div style={{ display:"flex", alignItems:"center", gap:9, marginBottom:12 }}><Icon name="chip" size={18} style={{ color:"var(--ink-2)" }} /><h3 style={{ fontSize:14.5, fontWeight:700, margin:0 }}>Salud del inventario</h3></div>
            <div style={{ display:"flex", justifyContent:"space-between", padding:"6px 0", borderBottom:"1px solid var(--line-2)" }}>
              <span style={{ fontSize:13, color:"var(--muted)" }}>Valor en estantería (costo)</span>
              <span className="mono" style={{ fontSize:14, fontWeight:700 }}>{fmtMoney(invValue)}</span>
            </div>
            <div style={{ display:"flex", justifyContent:"space-between", padding:"6px 0", borderBottom:"1px solid var(--line-2)" }}>
              <span style={{ fontSize:13, color:"var(--muted)" }}>Artículos bajo mínimo</span>
              <span className="mono" style={{ fontSize:14, fontWeight:700, color: lowCount?"var(--st-entrada)":"var(--ink)" }}>{lowCount}</span>
            </div>
            <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center", padding:"9px 11px", marginTop:10, borderRadius:9, background: reorderAmount>0?"var(--st-entrada-soft)":"var(--surface-2)" }}>
              <span style={{ fontSize:12.5, fontWeight:600, color: reorderAmount>0?"var(--st-entrada)":"var(--muted)" }}>A liberar para reorden</span>
              <span className="mono" style={{ fontSize:15, fontWeight:800, color: reorderAmount>0?"var(--st-entrada)":"var(--ink)" }}>{fmtMoney(reorderAmount)}</span>
            </div>
          </Card>
        </div>
      </div>

      <div style={{ display:"grid", gridTemplateColumns:"1.4fr 1fr", gap:16, alignItems:"start" }}>
        {/* monthly trend */}
        <Card>
          <h3 style={{ fontSize:15.5, fontWeight:700, margin:"0 0 4px" }}>Ingresos vs gastos por mes</h3>
          <p style={{ fontSize:12.5, color:"var(--muted)", margin:"0 0 20px" }}>Últimos {trend.length} meses con actividad</p>
          <div style={{ display:"flex", alignItems:"flex-end", justifyContent:"space-around", gap:14, height:180 }}>
            {trend.map(t=>(
              <div key={t.m} style={{ flex:1, display:"flex", flexDirection:"column", alignItems:"center", gap:8, minWidth:0 }}>
                <div style={{ display:"flex", alignItems:"flex-end", gap:5, height:140, width:"100%", justifyContent:"center" }}>
                  <div title={`Ingresos ${fmtMoney(t.inc)}`} style={{ width:18, height:`${(t.inc/maxTrend)*100}%`, minHeight:4, borderRadius:"5px 5px 0 0", background:"var(--st-listo)" }} />
                  <div title={`Gastos ${fmtMoney(t.exp)}`} style={{ width:18, height:`${(t.exp/maxTrend)*100}%`, minHeight:4, borderRadius:"5px 5px 0 0", background:"var(--danger)" }} />
                </div>
                <span style={{ fontSize:11.5, color:"var(--muted)", fontWeight:600, textTransform:"capitalize" }}>{new Date(t.m+"-01").toLocaleDateString("es-ES",{month:"short"})}</span>
              </div>
            ))}
          </div>
          <div style={{ display:"flex", gap:18, justifyContent:"center", marginTop:14, paddingTop:14, borderTop:"1px solid var(--line-2)" }}>
            <Legend color="var(--st-listo)" label="Ingresos" />
            <Legend color="var(--danger)" label="Gastos" />
          </div>
        </Card>

        {/* expense breakdown */}
        <Card>
          <h3 style={{ fontSize:15.5, fontWeight:700, margin:"0 0 18px" }}>Gastos por categoría</h3>
          {byCat.length===0 ? <p style={{ fontSize:13, color:"var(--faint)", fontStyle:"italic" }}>Sin gastos en este periodo.</p> : (
            <div style={{ display:"flex", flexDirection:"column", gap:13 }}>
              {byCat.map(c=>(
                <div key={c.id}>
                  <div style={{ display:"flex", justifyContent:"space-between", fontSize:13, marginBottom:5 }}>
                    <span style={{ fontWeight:600, color:"var(--ink-2)" }}>{c.label}</span>
                    <span className="mono" style={{ fontWeight:700 }}>{fmtMoney(c.total)}</span>
                  </div>
                  <div style={{ height:8, borderRadius:99, background:"var(--line-2)", overflow:"hidden" }}>
                    <div style={{ width:`${(c.total/maxCat)*100}%`, height:"100%", borderRadius:99, background:`oklch(0.62 0.14 ${c.hue})` }} />
                  </div>
                </div>
              ))}
            </div>
          )}
        </Card>
      </div>

      {/* Tanda B: proyección de flujo de caja + equipos no reclamados */}
      <div style={{ display:"grid", gridTemplateColumns:"1.5fr 1fr", gap:16, alignItems:"start" }}>
        <Card>
          <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between", marginBottom:4 }}>
            <h3 style={{ fontSize:15.5, fontWeight:700, margin:0 }}>Proyección de flujo de caja</h3>
            <span style={{ fontSize:12, fontWeight:600, color:"var(--muted)" }}>Próximos 30 días</span>
          </div>
          <p style={{ fontSize:12.5, color:"var(--muted)", margin:"0 0 14px" }}>Estimación según el promedio de ingresos y gastos de los últimos 30 días</p>
          <svg viewBox={`0 0 ${FW} ${FH}`} preserveAspectRatio="none" style={{ width:"100%", height:120, display:"block" }}>
            <line x1={fcX(0)} y1={fcY(0)} x2={fcX(30)} y2={fcY(0)} stroke="var(--line)" strokeWidth="1" strokeDasharray="3 3" />
            <path d={fcArea} fill={fcPositive?"oklch(0.62 0.14 155 / 0.12)":"oklch(0.58 0.19 25 / 0.12)"} stroke="none" />
            <path d={fcPath} fill="none" stroke={fcPositive?"var(--st-listo)":"var(--danger)"} strokeWidth="2.5" strokeLinejoin="round" />
            <circle cx={fcX(30)} cy={fcY(proj30)} r="4" fill={fcPositive?"var(--st-listo)":"var(--danger)"} />
          </svg>
          <div style={{ display:"flex", justifyContent:"space-between", fontSize:11, color:"var(--faint)", marginTop:2 }}><span>Hoy</span><span>+15 días</span><span>+30 días</span></div>
          <div style={{ display:"grid", gridTemplateColumns:"repeat(4,1fr)", gap:10, marginTop:16, paddingTop:14, borderTop:"1px solid var(--line-2)" }}>
            <FcStat label="Ingreso diario prom." value={fmtMoney(avgDailyIncome)} />
            <FcStat label="Gasto diario prom." value={fmtMoney(avgDailyExpense)} />
            <FcStat label="Fijos al mes" value={fmtMoney(monthlyFixed)} hint="renta · servicios · sueldos" />
            <FcStat label="Proyección 30 días" value={(proj30>=0?"+":"")+fmtMoney(proj30)} tone={fcPositive?"ok":"bad"} />
          </div>
        </Card>

        <Card style={{ borderColor: abandoned.length?"oklch(0.84 0.1 50)":"var(--line)" }}>
          <div style={{ display:"flex", alignItems:"center", gap:9, marginBottom:4 }}>
            <span style={{ width:34, height:34, borderRadius:9, flexShrink:0, display:"flex", alignItems:"center", justifyContent:"center", background: abandoned.length?"var(--st-entrada-soft)":"var(--surface-2)", color: abandoned.length?"var(--st-entrada)":"var(--muted)" }}><Icon name="warning" size={19} /></span>
            <h3 style={{ fontSize:15, fontWeight:700, margin:0 }}>Equipos no reclamados</h3>
          </div>
          <p style={{ fontSize:12.5, color:"var(--muted)", margin:"0 0 14px" }}>Listos hace +30 días sin retirar o con presupuesto rechazado</p>
          <div style={{ display:"flex", gap:20 }}>
            <div><div className="mono" style={{ fontSize:28, fontWeight:800, letterSpacing:"-0.02em" }}>{abandoned.length}</div><div style={{ fontSize:12, color:"var(--muted)" }}>equipos</div></div>
            <div><div className="mono" style={{ fontSize:28, fontWeight:800, letterSpacing:"-0.02em", color:"var(--st-entrada)" }}>{abandonRate}%</div><div style={{ fontSize:12, color:"var(--muted)" }}>de las órdenes</div></div>
          </div>
          <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center", padding:"9px 11px", marginTop:14, borderRadius:9, background: abandonLoss>0?"var(--danger-soft)":"var(--surface-2)" }}>
            <span style={{ fontSize:12.5, fontWeight:600, color: abandonLoss>0?"var(--danger)":"var(--muted)" }}>Repuestos invertidos (pérdida)</span>
            <span className="mono" style={{ fontSize:15, fontWeight:800, color: abandonLoss>0?"var(--danger)":"var(--ink)" }}>{fmtMoney(abandonLoss)}</span>
          </div>
        </Card>
      </div>

      {/* rentabilidad por técnico */}
      <Card pad={0}>
        <div style={{ padding:"16px 20px", borderBottom:"1px solid var(--line)" }}>
          <h3 style={{ fontSize:15.5, fontWeight:700, margin:0 }}>Rentabilidad por técnico</h3>
          <p style={{ fontSize:12.5, color:"var(--muted)", margin:"3px 0 0" }}>Retorno por hora laborada — cruce del reloj de asistencia con los ingresos generados</p>
        </div>
        {techStats.length===0 ? <div style={{ padding:"40px", textAlign:"center", color:"var(--faint)", fontSize:13 }}>Sin datos de asistencia o ingresos en este periodo.</div> : (
        <div style={{ overflowX:"auto" }}>
          <table style={{ width:"100%", borderCollapse:"collapse", minWidth:640 }}>
            <thead><tr style={{ height:36, background:"var(--surface-2)" }}>
              {["Técnico","Horas","Órdenes cerradas","Ingresos","Retorno / hora"].map((h,i)=>(
                <th key={i} style={{ textAlign: i===0?"left":i>=3?"right":"center", padding:"0 16px", fontSize:11.5, fontWeight:700, letterSpacing:"0.04em", textTransform:"uppercase", color:"var(--faint)" }}>{h}</th>
              ))}
            </tr></thead>
            <tbody>
              {techStats.map((s,idx)=>(
                <tr key={s.tt.id} style={{ height:54, borderBottom: idx<techStats.length-1?"1px solid var(--line-2)":"none" }}>
                  <td style={{ padding:"0 16px" }}>
                    <div style={{ display:"flex", alignItems:"center", gap:10 }}>
                      <Avatar name={s.tt.name} initials={s.tt.initials} hue={s.tt.hue} size={32} />
                      <div><div style={{ fontSize:13.5, fontWeight:700 }}>{s.tt.name}</div><div style={{ fontSize:11.5, color:"var(--muted)" }}>{s.tt.role}</div></div>
                    </div>
                  </td>
                  <td style={{ padding:"0 16px", textAlign:"center" }} className="mono"><span style={{ fontSize:13, fontWeight:600 }}>{fmtHours(s.hours)}</span></td>
                  <td style={{ padding:"0 16px", textAlign:"center" }} className="mono"><span style={{ fontSize:13.5, fontWeight:600 }}>{s.closed}</span></td>
                  <td style={{ padding:"0 16px", textAlign:"right" }} className="mono"><span style={{ fontSize:13.5, fontWeight:600 }}>{fmtMoney(s.inc)}</span></td>
                  <td style={{ padding:"0 16px" }}>
                    <div style={{ display:"flex", alignItems:"center", gap:9, justifyContent:"flex-end" }}>
                      <div style={{ width:70, height:6, borderRadius:99, background:"var(--line-2)", overflow:"hidden" }}><div style={{ width:`${(s.perHour/maxPerHour)*100}%`, height:"100%", borderRadius:99, background:`oklch(0.6 0.13 ${s.tt.hue})` }} /></div>
                      <span className="mono" style={{ fontSize:14, fontWeight:800, width:74, textAlign:"right" }}>{fmtMoney(s.perHour)}/h</span>
                    </div>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
        )}
      </Card>

      {/* ledger */}
      <Card pad={0}>
        <div style={{ padding:"16px 20px", borderBottom:"1px solid var(--line)" }}>
          <h3 style={{ fontSize:15.5, fontWeight:700, margin:0 }}>Movimientos</h3>
          <p style={{ fontSize:12.5, color:"var(--muted)", margin:"3px 0 0" }}>{ledger.length} movimientos · {monthName.toLowerCase()}</p>
        </div>
        <div>
          {ledger.map((m,i)=>(
            <div key={m.id||i} style={{ display:"flex", alignItems:"center", gap:13, padding:"13px 20px", borderBottom: i<ledger.length-1?"1px solid var(--line-2)":"none" }}>
              <span style={{ width:36, height:36, borderRadius:10, flexShrink:0, display:"flex", alignItems:"center", justifyContent:"center",
                background: m.type==="in"?"var(--st-listo-soft)":"var(--danger-soft)", color: m.type==="in"?"var(--st-listo)":"var(--danger)" }}>
                <Icon name="arrowRight" size={17} style={{ transform: m.type==="in"?"rotate(-45deg)":"rotate(45deg)" }} />
              </span>
              <div style={{ flex:1, minWidth:0 }}>
                <div style={{ fontSize:13.5, fontWeight:600 }}>{m.concept}</div>
                <div style={{ fontSize:12, color:"var(--muted)" }}>{m.sub}</div>
              </div>
              <span style={{ fontSize:12, color:"var(--faint)" }}>{fmtDate(m.date)}</span>
              <span className="mono" style={{ fontSize:14, fontWeight:700, width:96, textAlign:"right", color: m.type==="in"?"var(--st-listo)":"var(--danger)" }}>
                {m.type==="in"?"+":"−"}{fmtMoney(m.amount)}
              </span>
            </div>
          ))}
          {ledger.length===0 && <div style={{ padding:"48px", textAlign:"center", color:"var(--faint)" }}>Sin movimientos en este periodo.</div>}
        </div>
      </Card>

      {modal && <ExpenseModal user={currentUser} onSave={addExpense} onClose={()=>setModal(false)} />}
      {cierre && <CierreCajaModal incomeEvents={incomeEvents} expenses={expenses} onClose={()=>setCierre(false)} />}
    </div>
  );
}

function AnalysisCard({ icon, hue, label, value, sub, emph }){
  return (
    <Card pad={18} style={emph?{ borderColor:`oklch(0.85 0.08 ${hue})` }:{}}>
      <div style={{ display:"flex", alignItems:"center", gap:8 }}>
        <span style={{ width:30, height:30, borderRadius:8, display:"flex", alignItems:"center", justifyContent:"center", background:`oklch(0.95 0.04 ${hue})`, color:`oklch(0.5 0.13 ${hue})` }}><Icon name={icon} size={16} /></span>
        <span style={{ fontSize:13, fontWeight:700, color:"var(--ink-2)" }}>{label}</span>
      </div>
      <div className="mono" style={{ fontSize:25, fontWeight:800, marginTop:11, letterSpacing:"-0.02em" }}>{value}</div>
      <div style={{ fontSize:11.5, color:"var(--faint)", marginTop:3, lineHeight:1.4 }}>{sub}</div>
    </Card>
  );
}

function Legend({ color, label }){
  return <span style={{ display:"inline-flex", alignItems:"center", gap:7, fontSize:12.5, color:"var(--muted)", fontWeight:600 }}><span style={{ width:11, height:11, borderRadius:3, background:color }} />{label}</span>;
}

function ExpenseModal({ user, onSave, onClose }){
  const [f, setF] = React.useState({ cat:"repuestos", concept:"", supplier:"", amount:"", date:new Date().toISOString().slice(0,10) });
  const [touched, setTouched] = React.useState(false);
  function up(k,v){ setF(p=>({ ...p, [k]:v })); }
  const valid = f.concept.trim() && +f.amount>0;
  function save(){
    setTouched(true); if(!valid) return;
    onSave({ id:"e_"+Date.now(), date:new Date(f.date).toISOString(), cat:f.cat, concept:f.concept.trim(), supplier:f.supplier.trim()||"—", amount:+f.amount });
  }
  return (
    <ModalShell title="Registrar gasto / compra" onClose={onClose} maxWidth={460}>
      <div style={{ padding:"20px 22px", display:"flex", flexDirection:"column", gap:14 }}>
        <Field label="Concepto" required>
          <TextInput value={f.concept} autoFocus onChange={e=>up("concept",e.target.value)} placeholder="ej. Compra de pantallas iPhone" style={touched&&!f.concept.trim()?{borderColor:"var(--danger)"}:{}} />
        </Field>
        <Field label="Categoría">
          <div style={{ display:"flex", flexWrap:"wrap", gap:7 }}>
            {EXPENSE_CATEGORIES.map(c=>{
              const sel = f.cat===c.id;
              return (
                <button key={c.id} onClick={()=>up("cat",c.id)} style={{ padding:"7px 12px", borderRadius:99, fontSize:12.5, fontWeight:600, cursor:"pointer",
                  border:`1px solid ${sel?`oklch(0.6 0.13 ${c.hue})`:"var(--line)"}`, background: sel?`oklch(0.96 0.04 ${c.hue})`:"var(--surface)", color: sel?`oklch(0.45 0.14 ${c.hue})`:"var(--ink-2)" }}>{c.label}</button>
              );
            })}
          </div>
        </Field>
        <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:14 }}>
          <Field label="Monto (US$)" required>
            <TextInput type="number" min="0" value={f.amount} onChange={e=>up("amount",e.target.value)} placeholder="0.00" style={{ fontFamily:"var(--mono)", fontSize:17, ...(touched&&!(+f.amount>0)?{borderColor:"var(--danger)"}:{}) }} />
          </Field>
          <Field label="Fecha">
            <TextInput type="date" value={f.date} onChange={e=>up("date",e.target.value)} />
          </Field>
        </div>
        <Field label="Proveedor">
          <TextInput value={f.supplier} onChange={e=>up("supplier",e.target.value)} placeholder="Nombre del proveedor" />
        </Field>
      </div>
      <div style={{ display:"flex", justifyContent:"flex-end", gap:10, padding:"16px 22px", borderTop:"1px solid var(--line)" }}>
        <Btn variant="secondary" onClick={onClose}>Cancelar</Btn>
        <Btn icon="check" disabled={touched&&!valid} onClick={save}>Registrar gasto</Btn>
      </div>
    </ModalShell>
  );
}

function FcStat({ label, value, hint, tone }){
  const color = tone==="ok" ? "var(--st-listo)" : tone==="bad" ? "var(--danger)" : "var(--ink)";
  return (
    <div>
      <div className="mono" style={{ fontSize:15, fontWeight:800, color, letterSpacing:"-0.01em" }}>{value}</div>
      <div style={{ fontSize:11, color:"var(--muted)", fontWeight:600, marginTop:1 }}>{label}</div>
      {hint && <div style={{ fontSize:10, color:"var(--faint)" }}>{hint}</div>}
    </div>
  );
}

function CierreCajaModal({ incomeEvents, expenses, onClose }){
  const today = new Date();
  const todayIn = incomeEvents.filter(e => sameDay(e.t, today));
  const byMethod = { efectivo:0, tarjeta:0, transferencia:0 };
  todayIn.forEach(e=>{ byMethod[e.method] = (byMethod[e.method]||0) + e.amount; });
  const totalIn = todayIn.reduce((s,e)=>s+e.amount,0);
  const todayExp = expenses.filter(e => sameDay(e.date, today));
  const expTotal = todayExp.reduce((s,e)=>s+e.amount,0);
  const cashExpected = (byMethod.efectivo||0) - expTotal;
  const [counted, setCounted] = React.useState("");
  const [closed, setClosed] = React.useState(false);
  const diff = counted==="" ? null : (+counted - cashExpected);
  const METHODS = [["efectivo","Efectivo","wallet"],["tarjeta","Tarjeta","chart"],["transferencia","Transferencia","sms"]];
  return (
    <ModalShell title="Cierre de caja diario" onClose={onClose} maxWidth={460}>
      <div style={{ padding:"18px 22px", display:"flex", flexDirection:"column", gap:14 }}>
        <div style={{ fontSize:12.5, color:"var(--muted)" }}>{today.toLocaleDateString("es-ES",{weekday:"long",day:"numeric",month:"long",year:"numeric"})} · {todayIn.length} ingresos del día</div>

        <div style={{ display:"flex", flexDirection:"column", gap:8 }}>
          {METHODS.map(([id,l,ic])=>(
            <div key={id} style={{ display:"flex", alignItems:"center", gap:11, padding:"10px 12px", borderRadius:10, background:"var(--surface-2)" }}>
              <span style={{ width:30, height:30, borderRadius:8, display:"flex", alignItems:"center", justifyContent:"center", background:"var(--surface)", color:"var(--ink-2)" }}><Icon name={ic} size={16} /></span>
              <span style={{ flex:1, fontSize:13.5, fontWeight:600 }}>{l}</span>
              <span className="mono" style={{ fontSize:14, fontWeight:700 }}>{fmtMoney(byMethod[id]||0)}</span>
            </div>
          ))}
          <div style={{ display:"flex", alignItems:"center", gap:11, padding:"6px 12px" }}>
            <span style={{ flex:1, fontSize:12.5, color:"var(--danger)", fontWeight:600 }}>− Gastos del día</span>
            <span className="mono" style={{ fontSize:13.5, fontWeight:700, color:"var(--danger)" }}>{fmtMoney(expTotal)}</span>
          </div>
        </div>

        <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center", padding:"12px 14px", borderRadius:10, background:"var(--accent-soft)" }}>
          <span style={{ fontSize:13.5, fontWeight:700, color:"var(--accent-ink)" }}>Efectivo esperado en caja</span>
          <span className="mono" style={{ fontSize:18, fontWeight:800, color:"var(--accent-ink)" }}>{fmtMoney(cashExpected)}</span>
        </div>

        <Field label="Efectivo contado (arqueo)">
          <TextInput type="number" min="0" value={counted} onChange={e=>setCounted(e.target.value)} placeholder="0.00" style={{ fontFamily:"var(--mono)", fontSize:16 }} />
        </Field>
        {diff!==null && (
          <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center", padding:"10px 13px", borderRadius:9,
            background: Math.abs(diff)<0.01?"var(--st-listo-soft)":"var(--danger-soft)", color: Math.abs(diff)<0.01?"var(--st-listo)":"var(--danger)" }}>
            <span style={{ fontSize:13, fontWeight:700 }}>{Math.abs(diff)<0.01?"Caja cuadrada ✓":diff>0?"Sobrante":"Faltante"}</span>
            <span className="mono" style={{ fontSize:15, fontWeight:800 }}>{(diff>0?"+":"")+fmtMoney(diff)}</span>
          </div>
        )}
        <div style={{ fontSize:11, color:"var(--faint)", display:"flex", alignItems:"center", gap:6 }}><Icon name="warning" size={13} /> Total ingresado hoy (todos los métodos): <strong className="mono">{fmtMoney(totalIn)}</strong></div>
      </div>
      <div style={{ display:"flex", justifyContent:"flex-end", gap:10, padding:"14px 22px", borderTop:"1px solid var(--line)" }}>
        <Btn variant="secondary" onClick={onClose}>Cerrar</Btn>
        <Btn icon={closed?"check":"print"} onClick={()=>setClosed(true)}>{closed?"Caja cerrada":"Confirmar cierre"}</Btn>
      </div>
    </ModalShell>
  );
}

Object.assign(window, { Finanzas, Legend, ExpenseModal, AnalysisCard, FcStat, CierreCajaModal });
