// charts.jsx — hand-rolled svg charts (no deps)

// ---------- Line / area chart (Curva S) ----------
function CurveS({ data, height = 220 }) {
  const w = 720;
  const h = height;
  const pad = { l: 30, r: 20, t: 20, b: 28 };
  const W = w - pad.l - pad.r;
  const H = h - pad.t - pad.b;
  const n = data.length;
  const xAt = (i) => pad.l + (i / (n - 1)) * W;
  const yAt = (v) => pad.t + H - (v / 100) * H;

  const plannedPath = data.map((d, i) => `${i ? "L" : "M"}${xAt(i)},${yAt(d.planned)}`).join(" ");
  const realizedPts = data.filter(d => d.realized != null);
  const realizedPath = realizedPts
    .map((d, i) => {
      const idx = data.findIndex(x => x.m === d.m);
      return `${i ? "L" : "M"}${xAt(idx)},${yAt(d.realized)}`;
    }).join(" ");

  const areaPath = plannedPath + ` L${xAt(n - 1)},${pad.t + H} L${xAt(0)},${pad.t + H} Z`;

  return (
    <svg viewBox={`0 0 ${w} ${h}`} width="100%" style={{ display: "block" }}>
      {/* grid */}
      {[0, 25, 50, 75, 100].map((v) => (
        <g key={v}>
          <line x1={pad.l} x2={w - pad.r} y1={yAt(v)} y2={yAt(v)} stroke="#EAEAEA" strokeDasharray={v === 0 ? "0" : "3 3"} />
          <text x={pad.l - 6} y={yAt(v) + 3} fontSize="9" fill="#999" textAnchor="end" fontFamily="JetBrains Mono">{v}</text>
        </g>
      ))}
      {/* area */}
      <path d={areaPath} fill="#0A0A0A" opacity="0.04" />
      {/* planned (dashed) */}
      <path d={plannedPath} stroke="#999" strokeWidth="1.5" strokeDasharray="4 3" fill="none" />
      {/* realized (solid) */}
      <path d={realizedPath} stroke="#0A0A0A" strokeWidth="2" fill="none" />
      {/* realized points */}
      {realizedPts.map((d, i) => {
        const idx = data.findIndex(x => x.m === d.m);
        return <circle key={i} cx={xAt(idx)} cy={yAt(d.realized)} r="2.5" fill="#fff" stroke="#0A0A0A" strokeWidth="1.5" />;
      })}
      {/* x labels */}
      {data.map((d, i) => (
        i % 2 === 0 ? (
          <text key={i} x={xAt(i)} y={h - 8} fontSize="9" fill="#999" textAnchor="middle" fontFamily="JetBrains Mono">{d.m}</text>
        ) : null
      ))}
      {/* today marker */}
      {(() => {
        const lastReal = realizedPts.length - 1;
        const idx = data.findIndex(x => x.m === realizedPts[lastReal].m);
        return (
          <g>
            <line x1={xAt(idx)} x2={xAt(idx)} y1={pad.t} y2={pad.t + H} stroke="#dc2626" strokeWidth="1" strokeDasharray="2 2" />
            <circle cx={xAt(idx)} cy={yAt(realizedPts[lastReal].realized)} r="4" fill="#dc2626" />
          </g>
        );
      })()}
    </svg>
  );
}

// ---------- Fisico x Financeiro (mesma logica do admin, estilo minimalista) ----------
// data: [{ mes, progressoFisico, progressoFinanceiro }]
// Segue a linguagem visual do portal: fisico = solido preto + area, financeiro = tracejado cinza.
// Hover: linha guia vertical + tooltip flutuante com valores.
function FisicoFinanceiro({ data, height = 220 }) {
  if (!data || !data.length) return null;
  const w = 720, h = height;
  const pad = { l: 30, r: 20, t: 20, b: 28 };
  const W = w - pad.l - pad.r;
  const H = h - pad.t - pad.b;
  const n = data.length;
  const xAt = (i) => pad.l + (n === 1 ? W / 2 : (i / (n - 1)) * W);
  const yAt = (v) => pad.t + H - (v / 100) * H;

  const [hoverIdx, setHoverIdx] = React.useState(null);
  const containerRef = React.useRef(null);
  const [containerRect, setContainerRect] = React.useState({ width: w, height: h });

  React.useLayoutEffect(() => {
    if (!containerRef.current) return;
    const update = () => {
      const r = containerRef.current?.getBoundingClientRect();
      if (r) setContainerRect({ width: r.width, height: r.height });
    };
    update();
    const ro = new ResizeObserver(update);
    ro.observe(containerRef.current);
    return () => ro.disconnect();
  }, []);

  const fisicoPath = data
    .map((d, i) => `${i ? "L" : "M"}${xAt(i)},${yAt(d.progressoFisico ?? 0)}`)
    .join(" ");
  const finPath = data
    .map((d, i) => `${i ? "L" : "M"}${xAt(i)},${yAt(d.progressoFinanceiro ?? 0)}`)
    .join(" ");
  const areaPath =
    fisicoPath + ` L${xAt(n - 1)},${pad.t + H} L${xAt(0)},${pad.t + H} Z`;

  // Rotulo de mes compacto: YYYY-MM -> mmm/yy
  const fmtMes = (m) => {
    const mm = String(m).match(/^(\d{4})-(\d{2})/);
    if (!mm) return m;
    const d = new Date(Number(mm[1]), Number(mm[2]) - 1, 1);
    return d.toLocaleDateString("pt-BR", { month: "short", year: "2-digit" }).replace(".", "").replace(" de ", "/");
  };
  const fmtMesFull = (m) => {
    const mm = String(m).match(/^(\d{4})-(\d{2})/);
    if (!mm) return m;
    const d = new Date(Number(mm[1]), Number(mm[2]) - 1, 1);
    return d.toLocaleDateString("pt-BR", { month: "long", year: "numeric" });
  };

  const lastIdx = n - 1;

  // Escala para converter coordenadas SVG em pixels do container
  const scaleX = containerRect.width / w;
  const scaleY = containerRect.height / h;
  const sxPx = (svgX) => svgX * scaleX;
  const syPx = (svgY) => svgY * scaleY;

  // Tooltip position — centraliza proximo ao ponto, evitando cortar a borda
  const tooltipW = 180;
  const tooltipData = hoverIdx != null ? data[hoverIdx] : null;
  let tooltipLeft = 0;
  let tooltipTop = 0;
  if (tooltipData != null) {
    const px = sxPx(xAt(hoverIdx));
    tooltipLeft = Math.max(8, Math.min(containerRect.width - tooltipW - 8, px - tooltipW / 2));
    tooltipTop = Math.max(8, syPx(Math.min(yAt(tooltipData.progressoFisico ?? 0), yAt(tooltipData.progressoFinanceiro ?? 0))) - 78);
  }

  return (
    <div ref={containerRef} style={{ position: "relative", width: "100%" }}>
      <svg
        viewBox={`0 0 ${w} ${h}`}
        width="100%"
        style={{ display: "block" }}
        onMouseLeave={() => setHoverIdx(null)}
      >
        {/* grid horizontal */}
        {[0, 25, 50, 75, 100].map((v) => (
          <g key={v}>
            <line
              x1={pad.l}
              x2={w - pad.r}
              y1={yAt(v)}
              y2={yAt(v)}
              stroke="#EAEAEA"
              strokeDasharray={v === 0 ? "0" : "3 3"}
            />
            <text
              x={pad.l - 6}
              y={yAt(v) + 3}
              fontSize="9"
              fill="#999"
              textAnchor="end"
              fontFamily="JetBrains Mono"
            >
              {v}
            </text>
          </g>
        ))}
        {/* area sutil sob fisico */}
        <path d={areaPath} fill="#0A0A0A" opacity="0.04" />
        {/* linha financeiro (tracejada, cinza) */}
        <path d={finPath} stroke="#999" strokeWidth="1.5" strokeDasharray="4 3" fill="none" />
        {/* linha fisico (solida, preta) */}
        <path d={fisicoPath} stroke="#0A0A0A" strokeWidth="2" fill="none" />

        {/* guia vertical no hover */}
        {hoverIdx != null && (
          <line
            x1={xAt(hoverIdx)}
            x2={xAt(hoverIdx)}
            y1={pad.t}
            y2={pad.t + H}
            stroke="#0A0A0A"
            strokeWidth="1"
            strokeDasharray="2 3"
            opacity="0.35"
            pointerEvents="none"
          />
        )}

        {/* pontos fisico */}
        {data.map((d, i) => (
          <circle
            key={"p-" + i}
            cx={xAt(i)}
            cy={yAt(d.progressoFisico ?? 0)}
            r={hoverIdx === i ? "4" : "2.5"}
            fill={hoverIdx === i ? "#0A0A0A" : "#fff"}
            stroke="#0A0A0A"
            strokeWidth="1.5"
            pointerEvents="none"
          />
        ))}

        {/* pontos financeiro no hover (sem marcador constante pra nao poluir) */}
        {hoverIdx != null && (
          <circle
            cx={xAt(hoverIdx)}
            cy={yAt(data[hoverIdx].progressoFinanceiro ?? 0)}
            r="3"
            fill="#fff"
            stroke="#999"
            strokeWidth="1.5"
            pointerEvents="none"
          />
        )}

        {/* marcador "hoje" (sempre visivel, salvo quando hover sobre ele) */}
        {lastIdx >= 0 && hoverIdx !== lastIdx && (
          <g pointerEvents="none">
            <line
              x1={xAt(lastIdx)}
              x2={xAt(lastIdx)}
              y1={pad.t}
              y2={pad.t + H}
              stroke="#dc2626"
              strokeWidth="1"
              strokeDasharray="2 2"
            />
            <circle
              cx={xAt(lastIdx)}
              cy={yAt(data[lastIdx].progressoFisico ?? 0)}
              r="4"
              fill="#dc2626"
            />
          </g>
        )}

        {/* x labels */}
        {data.map((d, i) =>
          (i === 0 || i === n - 1 || i % Math.max(1, Math.floor(n / 6)) === 0) ? (
            <text
              key={"x-" + i}
              x={xAt(i)}
              y={h - 8}
              fontSize="9"
              fill="#999"
              textAnchor="middle"
              fontFamily="JetBrains Mono"
              pointerEvents="none"
            >
              {fmtMes(d.mes)}
            </text>
          ) : null
        )}

        {/* hit areas invisiveis (uma faixa por ponto) */}
        {data.map((_, i) => {
          const centerX = xAt(i);
          const halfStep = n > 1 ? (W / (n - 1)) / 2 : W / 2;
          const hitX = Math.max(pad.l, centerX - halfStep);
          const hitW = Math.min(w - pad.r, centerX + halfStep) - hitX;
          return (
            <rect
              key={"hit-" + i}
              x={hitX}
              y={pad.t}
              width={hitW}
              height={H}
              fill="transparent"
              style={{ cursor: "crosshair" }}
              onMouseEnter={() => setHoverIdx(i)}
            />
          );
        })}
      </svg>

      {/* Tooltip flutuante */}
      {tooltipData && (
        <div
          style={{
            position: "absolute",
            left: tooltipLeft,
            top: tooltipTop,
            width: tooltipW,
            background: "#fff",
            border: "1px solid var(--border, #EAEAEA)",
            borderRadius: 8,
            padding: "10px 12px",
            boxShadow: "0 8px 24px rgba(0,0,0,0.08)",
            fontSize: 12,
            pointerEvents: "none",
            transition: "left 0.08s ease, top 0.08s ease",
            zIndex: 2,
          }}
        >
          <div
            className="mono"
            style={{
              fontSize: 10,
              color: "#999",
              textTransform: "uppercase",
              letterSpacing: "0.06em",
              marginBottom: 6,
            }}
          >
            {fmtMesFull(tooltipData.mes)}
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 10, marginBottom: 4 }}>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 6, color: "#3A3A3A" }}>
              <i style={{ display: "inline-block", width: 10, height: 10, background: "#0A0A0A", borderRadius: 2 }} />
              Fisico
            </span>
            <span className="mono" style={{ fontWeight: 500, color: "#0A0A0A" }}>
              {(Number(tooltipData.progressoFisico) || 0).toFixed(1)}%
            </span>
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 10 }}>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 6, color: "#3A3A3A" }}>
              <i style={{ display: "inline-block", width: 10, height: 10, background: "#999", borderRadius: 2 }} />
              Financeiro
            </span>
            <span className="mono" style={{ fontWeight: 500, color: "#0A0A0A" }}>
              {(Number(tooltipData.progressoFinanceiro) || 0).toFixed(1)}%
            </span>
          </div>
          <div
            style={{
              marginTop: 6,
              paddingTop: 6,
              borderTop: "1px solid #EAEAEA",
              display: "flex",
              justifyContent: "space-between",
              fontSize: 11,
              color: "#666",
            }}
          >
            <span>Diferenca</span>
            <span className="mono">
              {(
                (Number(tooltipData.progressoFisico) || 0) -
                (Number(tooltipData.progressoFinanceiro) || 0)
              ).toFixed(1)} pp
            </span>
          </div>
        </div>
      )}
    </div>
  );
}

// ---------- Progresso vs mao de obra (espelha admin ResumoAnalytics) ----------
// data: [{ mes: "YYYY-MM", trabalhadores: N, progresso: 0-100 }]
// Bars = trabalhadores (eixo esquerdo, auto-escala)
// Line = progresso % (eixo direito, 0-100)
// Cores iguais ao admin: laranja #f59e0b bars, verde #10b981 line.
function ExecTeam({ data, height = 220 }) {
  if (!data || !data.length) return null;
  const w = 720, h = height;
  const pad = { l: 32, r: 40, t: 20, b: 28 };
  const W = w - pad.l - pad.r, H = h - pad.t - pad.b;
  const n = data.length;
  const bw = (W / n) * 0.55;

  // Leitura com fallback pros aliases antigos (m/exec/team)
  const getTrab = (d) => Number(d.trabalhadores ?? d.team ?? 0);
  const getProg = (d) => Number(d.progresso ?? d.exec ?? 0);
  const getMes = (d) => d.mes ?? d.m;

  // Auto-escala eixo esq (trabalhadores) arredondado para cima ate multiplo util
  const rawMaxTrab = Math.max(...data.map(getTrab), 0);
  const maxTrab = rawMaxTrab <= 0
    ? 4
    : rawMaxTrab <= 4
      ? Math.max(4, Math.ceil(rawMaxTrab * 1.3))
      : Math.ceil(rawMaxTrab * 1.3 / 5) * 5;
  const maxProg = 100;

  const leftY = (v) => pad.t + H - (v / maxTrab) * H;
  const rightY = (v) => pad.t + H - (v / maxProg) * H;

  const linePath = data.map((d, i) => {
    const x = pad.l + (i + 0.5) * (W / n);
    return `${i ? "L" : "M"}${x},${rightY(getProg(d))}`;
  }).join(" ");

  const fmtMes = (m) => {
    const mm = String(m).match(/^(\d{4})-(\d{2})/);
    if (!mm) return m;
    const d = new Date(Number(mm[1]), Number(mm[2]) - 1, 1);
    return d.toLocaleDateString("pt-BR", { month: "short", year: "2-digit" }).replace(".", "").replace(" de ", "/");
  };
  const fmtMesFull = (m) => {
    const mm = String(m).match(/^(\d{4})-(\d{2})/);
    if (!mm) return m;
    const d = new Date(Number(mm[1]), Number(mm[2]) - 1, 1);
    return d.toLocaleDateString("pt-BR", { month: "long", year: "numeric" });
  };

  const [hoverIdx, setHoverIdx] = React.useState(null);
  const containerRef = React.useRef(null);
  const [rect, setRect] = React.useState({ width: w, height: h });
  React.useLayoutEffect(() => {
    if (!containerRef.current) return;
    const update = () => {
      const r = containerRef.current?.getBoundingClientRect();
      if (r) setRect({ width: r.width, height: r.height });
    };
    update();
    const ro = new ResizeObserver(update);
    ro.observe(containerRef.current);
    return () => ro.disconnect();
  }, []);
  const scaleX = rect.width / w;
  const scaleY = rect.height / h;

  const tooltipW = 210;
  const tooltipData = hoverIdx != null ? data[hoverIdx] : null;
  let tooltipLeft = 0, tooltipTop = 0;
  if (tooltipData != null) {
    const px = (pad.l + (hoverIdx + 0.5) * (W / n)) * scaleX;
    tooltipLeft = Math.max(8, Math.min(rect.width - tooltipW - 8, px - tooltipW / 2));
    const topCandY = Math.min(leftY(getTrab(tooltipData)), rightY(getProg(tooltipData)));
    tooltipTop = Math.max(8, topCandY * scaleY - 84);
  }

  // Ticks do eixo direito (progresso %)
  const rightTicks = [0, 25, 50, 75, 100];
  // Ticks do eixo esquerdo (trabalhadores) — 0, meio, max
  const leftTicks = [0, Math.round(maxTrab / 2), maxTrab];

  // Paleta monocromatica do portal (coerente com "Fisico vs Financeiro")
  const BAR_COLOR = "#0A0A0A";   // preto solido (peso visual da contagem de pessoas)
  const LINE_COLOR = "#999";     // cinza medio (metrica de progresso em %)

  return (
    <div ref={containerRef} style={{ position: "relative", width: "100%" }}>
      <svg
        viewBox={`0 0 ${w} ${h}`}
        width="100%"
        style={{ display: "block" }}
        onMouseLeave={() => setHoverIdx(null)}
      >
        {/* grid horizontal (linhas na mesma posicao do eixo direito = 25/50/75/100%) */}
        {rightTicks.map((v) => (
          <line
            key={"g-" + v}
            x1={pad.l}
            x2={w - pad.r}
            y1={rightY(v)}
            y2={rightY(v)}
            stroke="#EAEAEA"
            strokeDasharray={v === 0 ? "0" : "3 3"}
          />
        ))}

        {/* eixo esquerdo: trabalhadores (inteiros) */}
        {leftTicks.map((v, i) => (
          <text
            key={"lt-" + i}
            x={pad.l - 6}
            y={leftY(v) + 3}
            fontSize="9"
            fill="#999"
            textAnchor="end"
            fontFamily="JetBrains Mono"
          >
            {v}
          </text>
        ))}
        {/* eixo direito: progresso % */}
        {rightTicks.map((v) => (
          <text
            key={"rt-" + v}
            x={w - pad.r + 6}
            y={rightY(v) + 3}
            fontSize="9"
            fill="#999"
            fontFamily="JetBrains Mono"
          >
            {v}%
          </text>
        ))}

        {/* guia vertical no hover (desenhado antes das barras pra ficar atras) */}
        {hoverIdx != null && (
          <line
            x1={pad.l + (hoverIdx + 0.5) * (W / n)}
            x2={pad.l + (hoverIdx + 0.5) * (W / n)}
            y1={pad.t}
            y2={pad.t + H}
            stroke="#0A0A0A"
            strokeWidth="1"
            strokeDasharray="2 3"
            opacity="0.2"
            pointerEvents="none"
          />
        )}

        {/* barras trabalhadores */}
        {data.map((d, i) => {
          const x = pad.l + i * (W / n) + (W / n - bw) / 2;
          const v = Math.max(0, getTrab(d));
          const bh = (v / maxTrab) * H;
          const by = pad.t + H - bh;
          return (
            <g key={"bar-" + i}>
              <rect
                x={x}
                y={by}
                width={bw}
                height={Math.max(0, bh)}
                fill={BAR_COLOR}
                opacity={hoverIdx == null || hoverIdx === i ? 1 : 0.55}
                rx="2"
                pointerEvents="none"
              />
              <text
                x={x + bw / 2}
                y={h - 8}
                fontSize="9"
                fill="#999"
                textAnchor="middle"
                fontFamily="JetBrains Mono"
                pointerEvents="none"
              >
                {fmtMes(getMes(d))}
              </text>
            </g>
          );
        })}

        {/* linha progresso (cinza solida — estilo do portal) */}
        <path
          d={linePath}
          stroke={LINE_COLOR}
          strokeWidth="1.5"
          fill="none"
          strokeLinejoin="round"
          strokeLinecap="round"
          pointerEvents="none"
        />
        {data.map((d, i) => {
          const x = pad.l + (i + 0.5) * (W / n);
          return (
            <circle
              key={"dot-" + i}
              cx={x}
              cy={rightY(getProg(d))}
              r={hoverIdx === i ? "3.5" : "2.5"}
              fill="#fff"
              stroke={LINE_COLOR}
              strokeWidth="1.5"
              pointerEvents="none"
            />
          );
        })}

        {/* hit areas */}
        {data.map((_, i) => {
          const x = pad.l + i * (W / n);
          const wSlot = W / n;
          return (
            <rect
              key={"hit-" + i}
              x={x}
              y={pad.t}
              width={wSlot}
              height={H}
              fill="transparent"
              style={{ cursor: "crosshair" }}
              onMouseEnter={() => setHoverIdx(i)}
            />
          );
        })}
      </svg>

      {/* Tooltip */}
      {tooltipData && (
        <div
          style={{
            position: "absolute",
            left: tooltipLeft,
            top: tooltipTop,
            width: tooltipW,
            background: "#fff",
            border: "1px solid var(--border, #EAEAEA)",
            borderRadius: 8,
            padding: "10px 12px",
            boxShadow: "0 8px 24px rgba(0,0,0,0.08)",
            fontSize: 12,
            pointerEvents: "none",
            transition: "left 0.08s ease, top 0.08s ease",
            zIndex: 2,
          }}
        >
          <div
            className="mono"
            style={{
              fontSize: 10,
              color: "#999",
              textTransform: "uppercase",
              letterSpacing: "0.06em",
              marginBottom: 6,
            }}
          >
            {fmtMesFull(getMes(tooltipData))}
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 10, marginBottom: 4 }}>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 6, color: "#3A3A3A" }}>
              <i style={{ display: "inline-block", width: 10, height: 10, background: BAR_COLOR, borderRadius: 2 }} />
              Trabalhadores
            </span>
            <span className="mono" style={{ fontWeight: 500, color: "#0A0A0A" }}>
              {getTrab(tooltipData).toFixed(0)} {getTrab(tooltipData) === 1 ? "pessoa" : "pessoas"}
            </span>
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 10 }}>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 6, color: "#3A3A3A" }}>
              <i style={{ display: "inline-block", width: 10, height: 10, background: LINE_COLOR, borderRadius: 2 }} />
              Progresso
            </span>
            <span className="mono" style={{ fontWeight: 500, color: "#0A0A0A" }}>
              {getProg(tooltipData).toFixed(0)}%
            </span>
          </div>
        </div>
      )}
    </div>
  );
}

// ---------- Donut ----------
function Donut({ value, size = 120, stroke = 12, label, sub }) {
  const r = (size - stroke) / 2;
  const c = 2 * Math.PI * r;
  const off = c * (1 - value);
  return (
    <div style={{ position: "relative", width: size, height: size }}>
      <svg width={size} height={size}>
        <circle cx={size / 2} cy={size / 2} r={r} stroke="#EAEAEA" strokeWidth={stroke} fill="none" />
        <circle cx={size / 2} cy={size / 2} r={r} stroke="#0A0A0A" strokeWidth={stroke} fill="none"
          strokeDasharray={c} strokeDashoffset={off} strokeLinecap="round"
          transform={`rotate(-90 ${size / 2} ${size / 2})`} />
      </svg>
      <div style={{ position: "absolute", inset: 0, display: "grid", placeItems: "center", textAlign: "center" }}>
        <div>
          <div className="mono num" style={{ fontSize: 22, fontWeight: 500, letterSpacing: "-0.02em" }}>{Math.round(value * 100)}%</div>
          {label && <div style={{ fontSize: 10, color: "#999", textTransform: "uppercase", letterSpacing: "0.06em", marginTop: 2 }}>{label}</div>}
          {sub && <div style={{ fontSize: 10, color: "#bdbdbd", fontFamily: "JetBrains Mono", marginTop: 2 }}>{sub}</div>}
        </div>
      </div>
    </div>
  );
}

// ---------- Execution bars ----------
function ExecBars({ data }) {
  return (
    <div className="stack" style={{ gap: 10 }}>
      {data.map((d, i) => (
        <div key={i} style={{ display: "grid", gridTemplateColumns: "110px 1fr 70px", gap: 12, alignItems: "center" }}>
          <div style={{ fontSize: 12, color: "#3A3A3A", fontWeight: 500 }}>{d.phase}</div>
          <div style={{ position: "relative" }}>
            <div style={{ height: 10, background: "#F5F5F5", borderRadius: 2, position: "relative" }}>
              {/* planned marker */}
              <div style={{
                position: "absolute", top: -2, bottom: -2,
                left: `${d.planned * 100}%`, width: 2,
                background: "#999"
              }} />
              {/* actual bar */}
              <div style={{
                height: "100%", width: `${d.actual * 100}%`,
                background: "#0A0A0A", borderRadius: 2
              }} />
            </div>
          </div>
          <div className="mono num" style={{ fontSize: 11, color: "#666", textAlign: "right" }}>
            {Math.round(d.actual * 100)}% / {Math.round(d.planned * 100)}%
          </div>
        </div>
      ))}
    </div>
  );
}

// ---------- Sparkline ----------
function Sparkline({ values, height = 36, color = "#0A0A0A" }) {
  const w = 120, h = height;
  const max = Math.max(...values);
  const min = Math.min(...values);
  const rng = max - min || 1;
  const pts = values.map((v, i) => `${(i / (values.length - 1)) * w},${h - ((v - min) / rng) * h * 0.85 - h * 0.08}`).join(" ");
  return (
    <svg viewBox={`0 0 ${w} ${h}`} width="100%" height={h} preserveAspectRatio="none">
      <polyline points={pts} fill="none" stroke={color} strokeWidth="1.5" />
    </svg>
  );
}

Object.assign(window, { CurveS, ExecTeam, Donut, ExecBars, Sparkline });
