+ {/* Encabezado minimalista */}
+
+
+
+ Cobranza por rango de vencimiento
+
+
+ {MESES_N[Number(mes)-1]} {ano} · por día de vencimiento (mes en curso)
+
+
+
+ {SERIES.map((s) => (
+
+
+ {s.label}
+
+ ))}
+
+
+
+ {!hayDatos ? (
+
+ No hay cuotas en curso con los filtros actuales.
+
+ ) : (
+
+
+ {/* Grid horizontal suave */}
+ {[0, 0.25, 0.5, 0.75, 1].map((t, i) => {
+ const y = y0 - t * plotH;
+ return (
+
+ {i !== 0 && }
+
+ {fmtEje(t * techo)}
+
+
+ );
+ })}
+
+ {/* Línea vertical que separa VENCIDO (grupo 0) de los grupos en curso */}
+
+
+ {/* Banda sutil al pasar el mouse */}
+ {GRUPOS.map((grp, gi) => {
+ const bandX = padL + gi * gW;
+ const activo = hover === gi;
+ return (
+ setHover(gi)} onMouseLeave={() => setHover(null)} />
+ );
+ })}
+
+ {/* Barras planas, finas, minimalistas */}
+ {GRUPOS.map((grp, gi) => {
+ const gx = padL + gi * gW + (gW * 0.22);
+ return (
+
+ {SERIES.map((s, si) => {
+ const v = data[gi][s.k];
+ const h = Math.max(v > 0 ? 2 : 0, yScale(v)); // mínimo visible si hay valor
+ const x = gx + si * bW;
+ const y = y0 - h;
+ const dim = hover != null && hover !== gi;
+ return (
+
+ );
+ })}
+ {grp.label}
+ {data[gi].n} cuota{data[gi].n === 1 ? "" : "s"}
+
+ );
+ })}
+
+
+
+
+ )}
+
+ {/* Tooltip minimalista (claro, sobrio) */}
+ {hover != null && hayDatos && (() => {
+ const d = data[hover];
+ const leftPct = ((padL + hover * gW + gW / 2) / W) * 100;
+ return (
+
+
+ {GRUPOS[hover].vencido ? "Vencido (mes anterior)" : `Vencen del ${GRUPOS[hover].label}`}
+
+
+ {d.n} cuota{d.n === 1 ? "" : "s"}
+
+ {SERIES.map((s) => (
+
+
+
+ {s.label}
+
+
+ {fmtMoneda(d[s.k])}
+
+
+ ))}
+
+ );
+ })()}
+
+ );
+}
+
// Mini-calendario. Muestra el mes/año del filtro, fijo. Al elegir un día filtra
// por F. Vencimiento (<= ese día). Para ver todo, elegir el último día del mes.
function MiniCalendario({ ano, mes, sel, onSelect, onClose }) {