/* ============================================================
   VKTR TCO — Screen 6: Recommendation / Report  v1.2
   Changes from v1.1:
   - 8 TCO rows (added AdBlue row; Labor row removed)
   - Labor disclaimer Alert below TCO table
   - Monthly Cost KPI card (5th KPI)
   - ⚠ Estimasi footnote on print/PDF when placeholder vehicle
   - Footer updated: "Version V1.2"
   ============================================================ */

function GroupedBarChart({ a, b, yrLabel }) {
  const W = 860, H = 240, pad = { t: 14, r: 12, b: 28, l: 52 };
  const n = a.length;
  const max = Math.ceil(Math.max(...a, ...b));
  const cw = (W - pad.l - pad.r) / n;
  const bw = Math.min(28, cw / 3.2);
  const plotH = H - pad.t - pad.b;
  const y = (v) => pad.t + plotH - (v / max) * plotH;
  const ticks = Array.from({ length: 5 }, (_, i) => (max / 4) * i);
  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%" style={{ display: "block" }}>
      {ticks.map((t, i) => (
        <g key={i}>
          <line x1={pad.l} x2={W - pad.r} y1={y(t)} y2={y(t)} stroke="var(--border)" strokeWidth="1" />
          <text x={pad.l - 8} y={y(t) + 4} textAnchor="end" fontSize="10" fill="var(--text-muted)">{t.toFixed(0)} M</text>
        </g>
      ))}
      {a.map((va, i) => {
        const cx = pad.l + cw * i + cw / 2;
        return (
          <g key={i}>
            <rect x={cx - bw - 3} y={y(va)} width={bw} height={plotH - (y(va) - pad.t)} rx="3" fill="var(--c-primary)" />
            <rect x={cx + 3} y={y(b[i])} width={bw} height={plotH - (y(b[i]) - pad.t)} rx="3" fill="var(--c-accent)" />
            <text x={cx} y={H - pad.b + 16} textAnchor="middle" fontSize="10.5" fill="var(--text-muted)">{yrLabel} {i + 1}</text>
          </g>
        );
      })}
    </svg>
  );
}

/* ---- v1.7.7: Customer-bears vs. VKTR-bears stacked bar, one per vehicle ----
   Shows the risk/cost-EXPOSURE split (customerDirect vs. vktrBorneRaw, both
   pre-markup) -- distinct from the headline KPI's customerTotalPayment,
   which is what the customer actually spends (including the marked-up rate
   they pay VKTR for VKTR-borne buckets). This chart answers "who is
   financially on the hook for which cost," the redesign's core question. */
// ---- Who Bears What: 100%-stacked percentage bar + per-bucket table (v1.7.7 Wave 4) ----
function BearerPercentBar({ customerPct, vktrPct, lang }) {
  return (
    <div>
      <div style={{ display: "flex", height: 22, borderRadius: 5, overflow: "hidden", border: "1px solid var(--border)" }}>
        {customerPct > 0 && (
          <div style={{ width: `${customerPct}%`, background: "var(--c-primary)", display: "flex", alignItems: "center", justifyContent: "center" }}>
            {customerPct >= 12 && <span style={{ fontSize: 10, fontWeight: 700, color: "#fff" }}>{customerPct.toFixed(0)}%</span>}
          </div>
        )}
        {vktrPct > 0 && (
          <div style={{ width: `${vktrPct}%`, background: "var(--c-accent)", display: "flex", alignItems: "center", justifyContent: "center" }}>
            {vktrPct >= 12 && <span style={{ fontSize: 10, fontWeight: 700, color: "#fff" }}>{vktrPct.toFixed(0)}%</span>}
          </div>
        )}
      </div>
    </div>
  );
}

function BucketBearerCard({ bm, veh, lang }) {
  const rawTotal = bm.customerDirect + bm.vktrBorneRaw;
  const customerPct = rawTotal > 0 ? (bm.customerDirect / rawTotal) * 100 : 0;
  const vktrPct = rawTotal > 0 ? (bm.vktrBorneRaw / rawTotal) * 100 : 0;
  return (
    <div className="veh-col">
      <div style={{ fontWeight: 700, fontSize: 13, marginBottom: 6 }}>{veh.name}</div>
      <BearerPercentBar customerPct={customerPct} vktrPct={vktrPct} lang={lang} />
      <table className="sbs-table" style={{ marginTop: 10 }}>
        <thead>
          <tr>
            <th>{tr(lang, "Bucket", "Kelompok")}</th>
            <th>{tr(lang, "Rp (raw)", "Rp (riil)")}</th>
            <th>{tr(lang, "Bearer", "Ditanggung")}</th>
          </tr>
        </thead>
        <tbody>
          {window.EXPENSE_BUCKET_KEYS.map(k => {
            const b = bm.buckets[k];
            const lbl = window.EXPENSE_BUCKET_LABELS[k];
            return (
              <tr key={k}>
                <td className="lbl">{tr(lang, lbl.en, lbl.id)}</td>
                <td className="num">{fmt.rpShort(b.raw)}</td>
                <td>
                  <Badge kind={b.bearer === "vktr" ? "vktr" : "muted"}>
                    {b.bearer === "vktr" ? tr(lang, "VKTR", "VKTR") : tr(lang, "Customer", "Pelanggan")}
                  </Badge>
                </td>
              </tr>
            );
          })}
          <tr className="total">
            <td className="lbl">{tr(lang, "Total (raw)", "Total (riil)")}</td>
            <td className="num">{fmt.rp(rawTotal)}</td>
            <td></td>
          </tr>
        </tbody>
      </table>
    </div>
  );
}

function BucketBearerBreakdown({ bmA, bmB, vA, vB, lang }) {
  return (
    <div className="vs-grid">
      <BucketBearerCard bm={bmA} veh={vA} lang={lang} />
      <div className="vs-divider"><span>VS</span></div>
      <BucketBearerCard bm={bmB} veh={vB} lang={lang} />
    </div>
  );
}

/* ---- Charging-schedule Gantt, per group (v1.7.8, §7.10) ---- */
// One stacked horizontal bar per shift/batch GROUP, not per vehicle: Drive
// (gray) / Charge (orange) segments in hours. No "wait/queue" segment --
// groups are pre-scheduled into non-competing slots by construction (see
// window.simulateChargingSchedule, data.jsx). Each row is annotated with
// its unit count for backtracking/readability, and this scales cleanly to
// any shift count or fleet size since row count = group count, not fleet size.
const GANTT_COLORS = { drive: "#94A3B8", charge: "#F59E0B" };
function ChargingGanttChart({ sim, lang }) {
  if (!sim || !sim.ganttRows.length) return null;
  const W = 860;
  const rowH = 24, rowGap = 8, labelW = 150, padT = 8, axisH = 16, legendH = 20;
  const rows = sim.ganttRows;
  const plotBottom = padT + rows.length * (rowH + rowGap);
  const H = plotBottom + axisH + legendH;
  const plotW = W - labelW - 10;
  const hoursToX = (h) => (h / sim.horizonHours) * plotW;
  const hourTicks = [];
  for (let h = 0; h <= sim.horizonHours; h += 6) hourTicks.push(h);
  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%" style={{ display: "block" }}>
      {hourTicks.map(h => (
        <g key={h}>
          <line x1={labelW + hoursToX(h)} x2={labelW + hoursToX(h)} y1={padT} y2={plotBottom} stroke="var(--border)" strokeWidth="1" />
          <text x={labelW + hoursToX(h)} y={plotBottom + 12} textAnchor="middle" fontSize="9" fill="var(--text-muted)">{h}h</text>
        </g>
      ))}
      {rows.map((row, i) => {
        const y = padT + i * (rowH + rowGap);
        let cursor = 0;
        return (
          <g key={row.label}>
            <text x={labelW - 6} y={y + rowH / 2 + 4} textAnchor="end" fontSize="10.5" fontWeight="600" fill="var(--text)">
              {row.label} · {fmt.num(row.count)} {tr(lang, "units", "unit")}
            </text>
            {row.segments.map((seg, si) => {
              const x0 = labelW + hoursToX(cursor);
              const w = Math.max(0, hoursToX(seg.hours));
              cursor += seg.hours;
              return <rect key={si} x={x0} y={y} width={w} height={rowH} rx="3" fill={GANTT_COLORS[seg.type]} />;
            })}
          </g>
        );
      })}
      <g transform={`translate(${labelW}, ${plotBottom + axisH + 14})`}>
        {[["drive", "Driving/Operating", "Berjalan/Operasi"], ["charge", "Charging (whole group at once)", "Isi Daya (satu kelompok bersamaan)"]].map(([k, en, id], i) => (
          <g key={k} transform={`translate(${i * 200}, 0)`}>
            <rect width="10" height="10" y="-9" fill={GANTT_COLORS[k]} />
            <text x="15" fontSize="10" fill="var(--text-muted)">{tr(lang, en, id)}</text>
          </g>
        ))}
      </g>
    </svg>
  );
}

/* ---- Cumulative total project cost line chart (CAPEX + OPEX over horizon) ---- */
function fmtBn(v) {
  return (v / 1e9).toLocaleString("id-ID", { minimumFractionDigits: 1, maximumFractionDigits: 1 });
}

// Piecewise-linear intersection of two series — returns {x: fractional year, value} or null
function findBEP(a, b) {
  for (let i = 0; i < a.length - 1; i++) {
    const d0 = a[i] - b[i];
    const d1 = a[i + 1] - b[i + 1];
    if (d0 === 0) return { x: i, value: a[i] };
    if ((d0 > 0) !== (d1 > 0)) {
      const frac = d0 / (d0 - d1);
      return { x: i + frac, value: a[i] + frac * (a[i + 1] - a[i]) };
    }
  }
  return null;
}

function ValueBubble({ x, y, dx, dy, anchor, text, color }) {
  const w = Math.max(58, text.length * 5.7 + 14);
  const h = 19;
  const bx = x + dx - (anchor === "end" ? w : anchor === "middle" ? w / 2 : 0);
  return (
    <g>
      <rect x={bx} y={y + dy - h / 2} width={w} height={h} rx="4" fill={color} opacity="0.94" />
      <text x={bx + w / 2} y={y + dy + 4} textAnchor="middle" fontSize="10" fontWeight="700" fill="#fff">{text}</text>
    </g>
  );
}

function CumulativeCostChart({ a, b, yrLabel, lang, labelA, labelB }) {
  const W = 860, H = 300, pad = { t: 34, r: 70, b: 50, l: 60 };
  const n = a.length; // horizon + 1 (Year 0..horizon)
  const max = Math.max(...a, ...b) / 1e9;
  const plotW = W - pad.l - pad.r;
  const plotH = H - pad.t - pad.b;
  const x = (i) => pad.l + (n > 1 ? (plotW * i) / (n - 1) : 0);
  const y = (v) => pad.t + plotH - (v / 1e9 / max) * plotH;
  const ticks = Array.from({ length: 5 }, (_, i) => (max / 4) * i);
  const path = (arr) => arr.map((v, i) => `${i === 0 ? "M" : "L"} ${x(i)} ${y(v)}`).join(" ");

  const bep = findBEP(a, b);
  const aHigherAtStart = a[0] >= b[0];
  const aHigherAtEnd = a[n - 1] >= b[n - 1];

  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%" style={{ display: "block" }}>
      {/* Axis subheaders */}
      <text x={4} y={12} fontSize="10.5" fontWeight="700" fill="var(--text-muted)">
        {tr(lang, "Y: Cumulative cost (IDR Billion, undiscounted)", "Y: Biaya kumulatif (Miliar IDR, belum didiskon)")}
      </text>
      <text x={pad.l + plotW / 2} y={H - 4} textAnchor="middle" fontSize="10.5" fontWeight="700" fill="var(--text-muted)">
        {tr(lang, "X: Project year (0 = initial investment)", "X: Tahun proyek (0 = investasi awal)")}
      </text>

      {ticks.map((t, i) => (
        <g key={i}>
          <line x1={pad.l} x2={W - pad.r} y1={y(t * 1e9)} y2={y(t * 1e9)} stroke="var(--border)" strokeWidth="1" />
          <text x={pad.l - 8} y={y(t * 1e9) + 4} textAnchor="end" fontSize="10" fill="var(--text-muted)">{t.toFixed(0)} B</text>
        </g>
      ))}
      <path d={path(a)} fill="none" stroke="var(--c-primary)" strokeWidth="2.5" />
      <path d={path(b)} fill="none" stroke="var(--c-accent)" strokeWidth="2.5" />
      {a.map((v, i) => <circle key={"a" + i} cx={x(i)} cy={y(v)} r="3" fill="var(--c-primary)" />)}
      {b.map((v, i) => <circle key={"b" + i} cx={x(i)} cy={y(v)} r="3" fill="var(--c-accent)" />)}
      {a.map((v, i) => (
        <text key={"t" + i} x={x(i)} y={H - pad.b + 16} textAnchor="middle" fontSize="10.5" fill="var(--text-muted)">
          {i === 0 ? "0" : i}
        </text>
      ))}
      <text x={pad.l + plotW / 2} y={H - pad.b + 32} textAnchor="middle" fontSize="10.5" fill="var(--text-muted)">{yrLabel}</text>

      {/* Year 0 value bubbles */}
      <ValueBubble x={x(0)} y={y(a[0])} dx={6} dy={aHigherAtStart ? -13 : 13} anchor="start" color="var(--c-primary)"
        text={`${labelA} Y0: ${fmtBn(a[0])} B`} />
      <ValueBubble x={x(0)} y={y(b[0])} dx={6} dy={aHigherAtStart ? 13 : -13} anchor="start" color="var(--c-accent)"
        text={`${labelB} Y0: ${fmtBn(b[0])} B`} />

      {/* Final year value bubbles */}
      <ValueBubble x={x(n - 1)} y={y(a[n - 1])} dx={-6} dy={aHigherAtEnd ? -13 : 13} anchor="end" color="var(--c-primary)"
        text={`${labelA}: ${fmtBn(a[n - 1])} B`} />
      <ValueBubble x={x(n - 1)} y={y(b[n - 1])} dx={-6} dy={aHigherAtEnd ? 13 : -13} anchor="end" color="var(--c-accent)"
        text={`${labelB}: ${fmtBn(b[n - 1])} B`} />

      {/* BEP marker — point where cumulative cost curves intersect */}
      {bep && (
        <g>
          <circle cx={x(bep.x)} cy={y(bep.value)} r="5" fill="none" stroke="#F59E0B" strokeWidth="2.5" />
          <circle cx={x(bep.x)} cy={y(bep.value)} r="2" fill="#F59E0B" />
          <ValueBubble x={x(bep.x)} y={y(bep.value)} dx={0} dy={-22} anchor="middle" color="#F59E0B"
            text={`BEP ${tr(lang, "Yr", "Th")} ${bep.x.toFixed(1)}: ${fmtBn(bep.value)} B`} />
        </g>
      )}
    </svg>
  );
}

/* ---- Cost distribution donut (per vehicle, v1.5) ---- */
const DONUT_COLORS = ["#0F1E27", "#1C3B49", "#00A651", "#16B364", "#0EA5E9", "#F59E0B", "#A855F7"];

function DonutChart({ segments, size = 130, strokeWidth = 20 }) {
  const total = segments.reduce((sum, x) => sum + x.value, 0) || 1;
  const r = (size - strokeWidth) / 2;
  const cx = size / 2, cy = size / 2;
  const circumference = 2 * Math.PI * r;
  let acc = 0;
  return (
    <svg viewBox={`0 0 ${size} ${size}`} width={size} height={size} style={{ flex: "none" }}>
      <g transform={`rotate(-90 ${cx} ${cy})`}>
        <circle cx={cx} cy={cy} r={r} fill="none" stroke="var(--border)" strokeWidth={strokeWidth} />
        {segments.map((seg, i) => {
          const frac = seg.value / total;
          const dash = frac * circumference;
          const offset = -acc * circumference;
          acc += frac;
          return (
            <circle key={i} cx={cx} cy={cy} r={r} fill="none" stroke={seg.color} strokeWidth={strokeWidth}
              strokeDasharray={`${dash} ${circumference - dash}`} strokeDashoffset={offset} />
          );
        })}
      </g>
    </svg>
  );
}

function CostDonut({ veh, rows, side, lang }) {
  const segs = rows
    .filter(r => !r.residual)
    .map((r, i) => ({
      label: lang === "en" ? r.en : r.id,
      value: Math.max(0, r[side]),
      color: DONUT_COLORS[i % DONUT_COLORS.length],
    }))
    .filter(seg => seg.value > 0);
  const total = segs.reduce((sum, x) => sum + x.value, 0) || 1;
  return (
    <div className="donut-block">
      <div className="donut-head">
        <Badge kind={veh.powertrain === "EV" ? "ev" : "ice"}>{veh.powertrain}</Badge>
        <span className="donut-name">{veh.name}</span>
      </div>
      <div className="donut-body">
        <DonutChart segments={segs} />
        <div className="donut-legend">
          {segs.map((seg, i) => (
            <div key={i} className="dl-row">
              <span className="dl-sw" style={{ background: seg.color }}></span>
              <span className="dl-lbl">{seg.label}</span>
              <span className="dl-pct">{((seg.value / total) * 100).toFixed(1)}%</span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

/* ---- Print-only input summary ---- */
function SummaryRow({ label, sub, value }) {
  return (
    <div className="psum-row">
      <div className="psum-k">{label}{sub && <small>{sub}</small>}</div>
      <div className="psum-v">{value || "—"}</div>
    </div>
  );
}

function PrintSummary({ s, lang }) {
  const L = (en, id) => tr(lang, en, id);
  const terrain = s.terrainManual ? s.terrainManual + " · manual" : "—";
  const rc = window.computeRitaseCycle ? window.computeRitaseCycle(s) : null;
  const annualKmResolved = window.resolveAnnualKm ? window.resolveAnnualKm(s) : s.annualKm;
  const vA = findVeh(s.vehA), vB = findVeh(s.vehB);
  // Real infra summary for the print sheet — replaces the old legacy
  // simple-mode infraCharging/infraSwap/infraSite/infraGreen picks, which
  // were removed from the UI back in the V1.3 EVCS rebuild and have shown
  // nothing but "—" since (the fields were never deleted, just orphaned).
  const evVeh = window.getEvVehicle ? window.getEvVehicle(s) : null;
  const evInfraMode = evVeh ? (window.EV_INFRA[evVeh.id] || "charge") : null;
  const infraSizing = evVeh ? window.computeSizing(s) : null;
  const infraCapexCalc = (evVeh && !s.depotBom && infraSizing) ? window.computeCapex(s, infraSizing) : null;
  const infraTotal = s.depotBom ? s.depotBom.tcoCapex : (infraCapexCalc ? infraCapexCalc.tcoCapex : 0);
  const infraSource = s.depotBom ? L("Depot Design", "Desain Depot") : L("Sizing Engine", "Mesin Perhitungan");
  const vehLine = (v, price) => v
    ? `${v.name} · ${v.powertrain}${v.vktr ? " · VKTR" : ""} · GVW ${v.gvw ? fmt.num(v.gvw) : "—"} kg · ${fmt.rpShort(price ?? v.price)}`
    : "—";

  const Section = ({ n, en, id, children }) => (
    <div className="psum-section">
      <div className="psum-head">
        <span className="psum-n">{n}</span>{lang === "en" ? en : id}
        <small>{lang === "en" ? id : en}</small>
      </div>
      <div className="psum-grid">{children}</div>
    </div>
  );

  return (
    <div className="print-only print-summary">
      <div className="psum-cover">
        <img src="assets/vktr-dark-horizontal.png" alt="VKTR" />
        <h1>{L("Analysis Input Summary", "Ringkasan Input Analisis")}</h1>
        <div className="psum-sub">{s.company} · {s.city}</div>
      </div>

      <Section n="1" en="Customer Profile" id="Profil Pelanggan">
        <SummaryRow label={L("Company", "Perusahaan")} value={s.company} />
        <SummaryRow label={L("Contact Person", "Nama PIC")} value={s.contact} />
        <SummaryRow label={L("Industry", "Industri")} value={s.industry} />
        <SummaryRow label={L("City", "Kota")} value={s.city} />
        <SummaryRow label={L("Notes", "Catatan")} value={s.notes} />
      </Section>

      <Section n="2" en="Vehicle Selection" id="Pemilihan Kendaraan">
        <SummaryRow label={L("Vehicle A", "Kendaraan A")} value={vehLine(vA, s.priceA)} />
        <SummaryRow label={L("Vehicle B", "Kendaraan B")} value={vehLine(vB, s.priceB)} />
      </Section>

      <Section n="3" en="Operation" id="Skenario Operasional">
        <SummaryRow label={L("Annual Mileage", "Jarak Tempuh Tahunan")} value={fmt.num(Math.round(annualKmResolved)) + " km/" + L("yr", "thn") + (rc ? " (" + L("computed", "terhitung") + ")" : "")} />
        <SummaryRow label={L("Ritase Distance", "Jarak Ritase")} value={rc ? fmt.num(Math.round(rc.RD)) + " km" : "—"} />
        <SummaryRow label={L("Fleet Size", "Jumlah Unit")} value={s.fleetSize + " " + L("units", "unit")} />
        <SummaryRow label={L("Analysis Horizon", "Horizon Analisis")} value={s.horizon + " " + L("years", "tahun")} />
        <SummaryRow label={L("Terrain", "Medan")} value={terrain} />
      </Section>

      <Section n="4" en="Infrastructure" id="Infrastruktur">
        <SummaryRow label={L("EV Charging Mode", "Mode Pengisian EV")} value={evInfraMode
          ? (evInfraMode === "both" ? L("Charge + Swap", "Isi Daya + Tukar") : evInfraMode === "swap" ? L("Battery Swap", "Tukar Baterai") : L("Charging", "Isi Daya"))
          : "—"} />
        <SummaryRow label={L("Infrastructure Source", "Sumber Infrastruktur")} value={evVeh ? infraSource : "—"} />
        <SummaryRow label={L("Infrastructure CAPEX", "CAPEX Infrastruktur")} value={evVeh ? fmt.rp(infraTotal) : "—"} />
      </Section>

      <Section n="5" en="Financial Assumptions" id="Asumsi Keuangan">
        <SummaryRow label={L("Payment Method — Vehicle A", "Metode Pembayaran — Kendaraan A")} value={s.paymentA === "loan" ? L("Loan / Credit", "Kredit") : L("Cash", "Tunai")} />
        <SummaryRow label={L("Payment Method — Vehicle B", "Metode Pembayaran — Kendaraan B")} value={s.paymentB === "loan" ? L("Loan / Credit", "Kredit") : L("Cash", "Tunai")} />
        {(s.paymentA === "loan" || s.paymentB === "loan") && <SummaryRow label={L("Interest Rate", "Suku Bunga")} value={s.interest + "% flat/" + L("yr", "thn")} />}
        {(s.paymentA === "loan" || s.paymentB === "loan") && <SummaryRow label={L("Down Payment", "Uang Muka")} value={s.downPayment + "%"} />}
        {(s.paymentA === "loan" || s.paymentB === "loan") && <SummaryRow label={L("Loan Duration", "Tenor")} value={s.tenor + " " + L("years", "tahun")} />}
        {(s.paymentA === "loan" || s.paymentB === "loan") && <SummaryRow label={L("Interest Method", "Metode Bunga")} value={s.loanInterestMethod === "amortizing" ? L("Amortizing", "Amortizing") : L("Flat", "Flat")} />}
        <SummaryRow label={L("EV Residual Value Method", "Metode Nilai Sisa EV")} value={(s.residualValueMethod ?? "soh") === "soh" ? L("SOH-linked", "Terkait SOH") : L("Fixed schedule", "Skedul Tetap")} />
        <SummaryRow label={L("Diesel Price", "Harga Solar")} value={fmt.rp(s.diesel) + "/L"} />
        <SummaryRow label={L("Electricity Tariff", "Tarif Listrik")} value={fmt.rp(s.electricity) + "/kWh"} />
        <SummaryRow label={L("AdBlue Price", "Harga AdBlue")} value={s.adblue > 0 ? fmt.rp(s.adblue) + "/L · " + L(`diesel + AdBlue (${s.adblueDose}% dose)`, `solar + AdBlue (dosis ${s.adblueDose}%)`) : L("Pure diesel (no AdBlue)", "Solar murni (tanpa AdBlue)")} />
        <SummaryRow label={L("Cost Inflation", "Inflasi Biaya")} value={(s.inflation ?? 5) + "%/" + L("yr", "thn")} />
        <SummaryRow label={L("Discount Rate / WACC", "Tingkat Diskonto")} value={s.wacc + "%/" + L("yr", "thn")} />
        <SummaryRow label={L("Carbon Credit", "Kredit Karbon")} value={fmt.rp(s.carbon) + "/ton CO₂"} />
        <SummaryRow label={L("Diesel Emission Factor", "Faktor Emisi Solar")} value={window.CO2.diesel_kg_per_liter + " kgCO2/L (" + L("well-to-wheel", "well-to-wheel") + ")"} />
        <SummaryRow label={L("Grid Emission Factor", "Faktor Emisi Jaringan")} value={window.CO2.grid_kg_per_kwh + " kgCO2/kWh (" + L("Indonesia national average", "rata-rata nasional Indonesia") + ")"} />
        <SummaryRow label={L("Embodied Manufacturing CO2", "CO2 Manufaktur Tertanam")} value={s.includeEmbodiedCo2
          ? L("Included", "Disertakan") + ` (${s.evBatteryMfgCo2PerKwh ?? 74} kgCO2/kWh)`
          : L("Not included (default)", "Tidak disertakan (default)")} />
      </Section>
    </div>
  );
}

function Screen6({ s, set }) {
  const { lang } = useLang();
  const L = (en, id) => tr(lang, en, id);
  const [includeInputs, setIncludeInputs] = React.useState(true);
  const R = React.useMemo(() => window.computeTCO(s), [s]);
  // True unoverridden per-year defaults — used by the Yearly Expense Editor
  // (Details tab) so its ValueFlag "reset" always points at the platform's
  // computed default, not whatever the user already overrode.
  const Rdefault = React.useMemo(() => window.computeTCO({ ...s, yearlyOverrides: {} }), [s]);
  const vA = findVeh(s.vehA), vB = findVeh(s.vehB);

  // Guard: both vehicles must be selected and engine must return valid result
  if (!vA || !vB || !R) {
    return (
      <div className="card" style={{ textAlign: "center", padding: 40 }}>
        <WarnHint label={tr(lang, "Select Vehicles", "Pilih Kendaraan")}
          note={tr(lang, "Please select vehicles in Step 2 to generate the TCO report.", "Pilih kendaraan di Langkah 2 untuk menghasilkan laporan TCO.")} />
      </div>
    );
  }

  // ---- v1.3: Infrastructure sizing & EVCS CAPEX (for new report sections) ----
  const sizing = React.useMemo(() => window.computeSizing(s), [s]);
  const capex  = React.useMemo(() => (sizing ? window.computeCapex(s, sizing) : null), [s, sizing]);
  // v1.5: Depot Design (Screen 4 -> Depot Design tab) is the live infra
  // CAPEX/OPEX source once it has computed a result — see infraForVeh() in
  // data.jsx and DEPOT_INTEGRATION_HANDOVER.md. `capex` above stays TCO's
  // own independent Sizing Engine estimate, shown for reference only below.
  const depotActive = !!s.depotBom;
  const infraGrandTotal = depotActive ? s.depotBom.tcoCapex : (capex ? capex.tcoCapex : 0);
  const ecosystemOpt   = (window.ECOSYSTEM_OPTIONS || []).find(e => e.id === s.ecosystemId);
  const presetOpt      = (window.INFRA_PROFILES?.PRESETS || []).find(p => p.id === s.screen4_activePresetId);
  const projectStartLabel = s.projectStartDate
    ? new Date(s.projectStartDate).toLocaleDateString(lang === "en" ? "en-US" : "id-ID", { month: "long", year: "numeric" })
    : null;

  // v1.7.6: Lead Time module (informational only -- does not feed R/computeTCO()).
  const leadTimeA = React.useMemo(() => window.computeLeadTime(s.vehA, s.fleetSize, s.payloadBuildA), [s.vehA, s.fleetSize, s.payloadBuildA]);
  const leadTimeB = React.useMemo(() => window.computeLeadTime(s.vehB, s.fleetSize, s.payloadBuildB), [s.vehB, s.fleetSize, s.payloadBuildB]);

  const sanityIssues = window.checkResultSanity(R, s);
  const rows   = R.rows;
  // Residual Value row is always shown for reference, but only counted into
  // Total TCO/Savings when includeResidualInTco is on (off by default — see
  // data.jsx vehicleCalc, matches VKTR's own cash-cost TCOO convention).
  const totalA = rows.reduce((sum, r) => sum + ((r.residual && !s.includeResidualInTco) ? 0 : r.a), 0);
  const totalB = rows.reduce((sum, r) => sum + ((r.residual && !s.includeResidualInTco) ? 0 : r.b), 0);
  const savings = Math.abs(totalA - totalB);
  const aWins = totalA < totalB;
  const winnerName = aWins ? vA.name : vB.name;
  const loserName  = aWins ? vB.name : vA.name;
  const today = new Date(2026, 5, 9).toLocaleDateString(lang === "en" ? "en-GB" : "id-ID", { day: "numeric", month: "long", year: "numeric" });
  const unitW = L("units", "unit"), yrW = L("years", "tahun"), kmW = L("km/yr", "km/thn");
  const locale = lang === "en" ? "en-US" : "id-ID";

  // ---- v1.7.7: Customer/VKTR expense-bucket model ----
  // Headline KPIs that are simple lifetime totals (Savings, Rp/km, Rp/ton-km)
  // now reflect ONLY what the customer actually pays (direct + whatever they
  // pay VKTR for VKTR-borne buckets) per explicit direction -- NOT the raw
  // ownership TCO, which is what the pre-v1.7.7 engine always showed. NPV/
  // IRR/Payback/the cumulative chart are NOT bucket-aware yet -- they need a
  // real year-by-year bucket cash-flow model this pass doesn't build (the
  // design proposal itself only specifies lifetime totals, no per-year
  // breakdown) -- still reflect full ownership cost, flagged below.
  const bmA = window.computeExpenseBuckets(s, "A");
  const bmB = window.computeExpenseBuckets(s, "B");

  // v1.7.7 Wave 3: EV-side charging-queue simulation (§7.10) -- null when
  // neither A nor B is an EV, or when the fleet/sizing inputs aren't
  // populated yet. See window.simulateChargingSchedule (data.jsx).
  const chargingSim = window.simulateChargingSchedule ? window.simulateChargingSchedule(s) : null;

  // ---- v1.6: B-vs-A KPI framing ----
  // Total Savings: positive = B is cheaper than A (savings from choosing B over A)
  const bvsaSavings = (bmA && bmB) ? (bmA.customerTotalPayment - bmB.customerTotalPayment) : -R.savings;
  // CO₂ Reduction: positive = B emits less CO₂ than A over the horizon
  const co2Reduction = R.co2A - R.co2B;
  // Payback (B vs A): years for B's higher upfront cost (vs A) to be recovered via B's lower OPEX (vs A)
  const paybackBvA = R.paybackNote === "no_premium"
    ? "—"
    : R.paybackNote === "beyond_horizon"
    ? L(`> ${s.horizon} yr`, `> ${s.horizon} thn`)
    : `${R.payback.toLocaleString(locale, { maximumFractionDigits: 1 })} ${yrW}`;

  // ---- winner-oriented framing (Key Takeaways / Decision Points) ----
  const paybackWinnerText = R.paybackWinnerNote === "no_premium"
    ? L("no upfront premium", "tanpa premium awal")
    : R.paybackWinnerNote === "beyond_horizon"
    ? L("beyond the analysis horizon", "di luar horizon analisis")
    : `${R.paybackWinner.toLocaleString(locale, { maximumFractionDigits: 1 })} ${yrW}`;
  // co2Winner: positive = the winning vehicle emits less CO₂ than the alternative
  const co2Winner = R.aWinsTco ? (R.co2B - R.co2A) : (R.co2A - R.co2B);

  const irrText = R.irr != null ? `${R.irr.toLocaleString(locale, { maximumFractionDigits: 1 })}%` : "—";

  // ---- v1.7.8: explicit IRR-vs-WACC hurdle-rate verdict ----
  // WACC (s.wacc) is used in exactly one place in the engine: the NPV
  // discount rate (data.jsx computeTCO's npvAt). IRR is computed
  // independently via bisection search on that same npvAt -- it does NOT
  // take WACC as an input, it IS the break-even discount rate itself. So
  // "IRR > WACC" and "NPV > 0" carry the same verdict for a conventional
  // single-sign-change cash flow (which this B-vs-A savings stream is):
  // the switch clears your cost-of-capital hurdle and is expected to
  // create value; below it, the switch may not be worth the premium at
  // your assumed WACC (a modeling input, not a fact about the vehicles).
  const waccPct = s.wacc;
  const hasIrr = R.irr != null;
  const irrClearsWacc = hasIrr && R.irr > waccPct;

  // ⚠ Estimasi footnote check
  const selectedVehicles = [vA, vB];
  const hasEstimasi = selectedVehicles.some(v => v && (v.placeholder || v.pmEstimate));

  // ---- v1.5: takeaways / decision points helper data ----
  // Look up rows by label rather than fixed index — the array has grown
  // (insurance/battery rows added since, driver row removed in v1.7.8) and
  // a hardcoded index here previously went stale, silently zeroing out
  // Infra CAPEX/OPEX and Residual Value in this section once those new
  // rows shifted everyone
  // after them. Find by `r.en` instead so future row insertions can't repeat it.
  const rowByLabel = (en) => rows.find(r => r.en === en) || { a: 0, b: 0 };
  const infraCapexRow = rowByLabel("Infra CAPEX");
  const infraOpexRow  = rowByLabel("Infra OPEX");
  const insuranceRow  = rowByLabel("Lifetime Insurance Cost");
  const batteryRow    = rowByLabel("Battery Replacement Cost (EV)");
  const residualRowLookup = rows.find(r => r.residual) || { a: 0, b: 0 };

  const winnerVeh = aWins ? vA : vB;
  const loserVeh  = aWins ? vB : vA;
  const winnerMonthly = aWins ? R.monthlyA : R.monthlyB;
  const loserMonthly  = aWins ? R.monthlyB : R.monthlyA;
  const winnerCapex = aWins ? rows[0].a : rows[0].b;
  const loserCapex  = aWins ? rows[0].b : rows[0].a;
  const winnerInfraCapex = aWins ? infraCapexRow.a : infraCapexRow.b;
  const loserInfraCapex  = aWins ? infraCapexRow.b : infraCapexRow.a;

  const nonResidualRows = rows.filter(r => !r.residual);
  const biggestDriver = nonResidualRows.reduce((best, r) => {
    const d = Math.abs(r.a - r.b);
    return (!best || d > best.d) ? { row: r, d } : best;
  }, null);

  // ---- v1.6: Side-by-Side Comparison (5-row merged summary) ----
  // v1.7.12: now the bucket-aware CUSTOMER payment view
  // (bmA/bmB.customerRowsBreakdown, data.jsx computeExpenseBuckets) when
  // both vehicles resolve a bucket model -- same basis as the Cost/km
  // headline and the cumulative chart above, not the raw ownership cost
  // regardless of who bears it. Residual value is NOT a separate row in
  // this view: whenever applyResaleReliefInUnit is on, bucketRaw.UNIT
  // already nets the relief amount, so it's folded into Upfront Price
  // instead of being double-counted as a second line (unlike the raw-TCO
  // fallback below, where netting is conditional on includeResidualInTco --
  // a different toggle for a different, non-bucket-aware model). A
  // Subscription Payment row appears only when at least one vehicle has a
  // VKTR-borne bucket (subscriptionAnnual > 0).
  const useCustomerRows = !!(bmA && bmB);
  const hasSubscriptionRow = useCustomerRows && (bmA.subscriptionAnnual > 0 || bmB.subscriptionAnnual > 0);
  const residualIncludedNow = !!s.includeResidualInTco;
  const resaleReliefAppliedNow = !!s.applyResaleReliefInUnit;
  const sbsRowsBase = useCustomerRows ? [
    { label: resaleReliefAppliedNow
        ? L("Upfront Price (net of Resale Relief)", "Harga Awal (bersih dari Keringanan Jual Kembali)")
        : L("Upfront Price", "Harga Awal"),
      a: bmA.customerRowsBreakdown.upfrontPrice, b: bmB.customerRowsBreakdown.upfrontPrice, lowerBetter: true },
    { label: L("Energy (Lifetime)", "Energi (Seumur Hidup)"),
      a: bmA.customerRowsBreakdown.energyLifetime, b: bmB.customerRowsBreakdown.energyLifetime, lowerBetter: true },
    { label: L("Maintenance & Other Opex", "Perawatan & Opex Lain"),
      a: bmA.customerRowsBreakdown.maintOtherOpex, b: bmB.customerRowsBreakdown.maintOtherOpex, lowerBetter: true },
    ...(hasSubscriptionRow ? [{
      label: L("Subscription Payment (VKTR-borne)", "Pembayaran Langganan (ditanggung VKTR)"),
      a: bmA.customerRowsBreakdown.subscriptionPayment, b: bmB.customerRowsBreakdown.subscriptionPayment, lowerBetter: true }] : []),
    { label: L("Total TCO (Customer Payment)", "Total TCO (Pembayaran Pelanggan)"),
      a: bmA.customerTotalPayment, b: bmB.customerTotalPayment, lowerBetter: true, isTotal: true },
  ] : [
    { label: L("Upfront Price", "Harga Awal"),         a: rows[0].a + rows[1].a + infraCapexRow.a, b: rows[0].b + rows[1].b + infraCapexRow.b, lowerBetter: true  },
    { label: L("Energy (Lifetime)", "Energi (Seumur Hidup)"), a: rows[2].a + rows[3].a,       b: rows[2].b + rows[3].b,             lowerBetter: true  },
    { label: L("Maintenance & Other Opex", "Perawatan & Opex Lain"),
      a: rows[4].a + infraOpexRow.a + insuranceRow.a + batteryRow.a,
      b: rows[4].b + infraOpexRow.b + insuranceRow.b + batteryRow.b,
      lowerBetter: true },
    { label: residualIncludedNow ? L("Residual (Credit)", "Nilai Sisa (Kredit)") : L("Residual (Credit, not included below)", "Nilai Sisa (Kredit, tidak termasuk di bawah)"),
      a: residualIncludedNow ? -residualRowLookup.a : 0, b: residualIncludedNow ? -residualRowLookup.b : 0, lowerBetter: false },
    { label: L("Total TCO", "Total TCO"),              a: totalA,                            b: totalB,                            lowerBetter: true,  isTotal: true },
  ];
  const sbsRows = sbsRowsBase.map(r => {
    const diff = Math.abs(r.a - r.b);
    const base = Math.max(r.a, r.b);
    const pct  = base > 0 ? (diff / base) * 100 : 0;
    const better = r.a === r.b ? null : (r.lowerBetter ? (r.a < r.b ? "A" : "B") : (r.a > r.b ? "A" : "B"));
    return { ...r, diff, pct, better };
  });
  const aLeads = sbsRows.filter(r => !r.isTotal && r.better === "A");
  const bLeads = sbsRows.filter(r => !r.isTotal && r.better === "B");

  const cell = (v, isResidual, isWinCol) => (
    <td className={"num" + (isResidual ? " residual" : "") + (isWinCol ? " win-border" : "")}>
      {isResidual ? "−" : ""}{fmt.rpShort(Math.abs(v))}
    </td>
  );
  const rowLabel = (r) => (
    <td className="lbl">{lang === "en" ? r.en : r.id}<small>{lang === "en" ? r.id : r.en}</small></td>
  );
  const deltaCell = (a, b) => {
    const d = a - b;
    if (Math.abs(d) < 1) return <td className="num delta">—</td>;
    const favA = d < 0;
    return (
      <td className={"num delta " + (favA ? "fav-a" : "fav-b")}>
        {favA ? "A " : "B "}−{fmt.rpShort(Math.abs(d))}
      </td>
    );
  };

  function doPrint() { window.print(); }
  const activeTab = s.screen6_activeTab || 0;

  return (
   <React.Fragment>
    {includeInputs && <PrintSummary s={s} lang={lang} />}
    <div className={"report" + (includeInputs ? " report-after-summary" : "")}>

      {/* A: header */}
      <div className="report-header">
        <div className="rh-left">
          <img src="assets/vktr-dark-horizontal.png" alt="VKTR" />
          <h1>{L("TCO (Total Cost of Ownership) Competitive Analysis Results", "Hasil Analisis Kompetitif TCO (Total Cost of Ownership)")}</h1>
          <div className="rh-subtitle">
            {vA.name} vs {vB.name} · {s.fleetSize} {unitW} · {s.horizon} {yrW} · {fmt.num(Math.round(window.resolveAnnualKm(s)))} {kmW}
            {(s.inflation ?? 5) > 0 && <span> · {s.inflation ?? 5}% {L("inflation", "inflasi")}</span>}
          </div>
        </div>
        <div className="rh-right">
          <div className="rh-company">{s.company}</div>
          <div className="rh-date">{s.city} · {today}</div>
        </div>
      </div>

      {/* Result sanity guard (v1.7.5) -- see checkResultSanity() in data.jsx.
          A class of bug no test suite catches because it only manifests on
          a specific real input combination; surfaced visibly here, not
          just logged to console, since this is what a customer would see. */}
      {sanityIssues.length > 0 && (
        <div className="sanity-banner">
          {sanityIssues.map((issue, i) => (
            <Alert key={i} kind={issue.sev === "error" ? "error" : "warn"}>
              <Tr en={issue.en} id={issue.id} />
            </Alert>
          ))}
        </div>
      )}

      {/* Tabs: Summary / Details / Calculation Steps */}
      <div className="report-tab-bar">
        <button className={"report-tab" + (activeTab === 0 ? " active" : "")} onClick={() => set("screen6_activeTab", 0)}>
          {L("Summary", "Ringkasan")}
        </button>
        <button className={"report-tab" + (activeTab === 1 ? " active" : "")} onClick={() => set("screen6_activeTab", 1)}>
          {L("Details", "Detail")}
        </button>
        <button className={"report-tab" + (activeTab === 2 ? " active" : "")} onClick={() => set("screen6_activeTab", 2)}>
          {L("Calculation Steps", "Langkah Kalkulasi")}
        </button>
      </div>

      {/* ============================================================
          TAB 1: SUMMARY — plots, comparison, verdict
          ============================================================ */}
      <div className={"report-tab-panel" + (activeTab === 0 ? " active" : "")}>

      {!depotActive && (s.fleetSize || 0) < 5 && capex && (
        <WarnHint label={L("Small Fleet", "Armada Kecil")}
          note={L(
            `The KPIs below load the electrical CAPEX of a standalone charging depot (${fmt.rp(capex.tcoCapex)}) onto a fleet of just ${s.fleetSize || 0} vehicle(s) — nobody builds a whole depot for that few trucks. This will make the EV side look far worse than a real fleet-scale deployment. See Infrastructure → CAPEX Breakdown for detail, or raise Fleet Size to a realistic deployment scale.`,
            `KPI di bawah membebankan CAPEX elektrikal depot pengisian mandiri (${fmt.rp(capex.tcoCapex)}) ke armada hanya ${s.fleetSize || 0} kendaraan — tidak ada yang membangun depot penuh untuk sejumlah truk sekecil itu. Ini akan membuat sisi EV terlihat jauh lebih buruk dibanding deployment skala armada yang nyata. Lihat Infrastruktur → Rincian CAPEX untuk detail, atau naikkan Jumlah Armada ke skala deployment yang realistis.`)} />
      )}

      {/* B: KPI cards — all 4 headings compare B to A */}
      <div className="kpi-row">
        <div className="kpi">
          <div className="kic">💰</div>
          <div className={"kval" + (bvsaSavings > 0 ? " green" : bvsaSavings < 0 ? " red" : "")}>
            {bvsaSavings >= 0 ? "+" : "−"}{fmt.rpShort(Math.abs(bvsaSavings))}
          </div>
          <div className="klbl">
            {L("Customer Total Savings", "Penghematan Total Pelanggan")}
            <InfoHint note={L(
              "What the customer actually pays, not raw ownership TCO — reflects the Expense Bucket Toggle on Screen 5 (direct-paid buckets + whatever the customer pays VKTR, marked up, for VKTR-borne buckets). Change the toggle to see this shift.",
              "Yang benar-benar dibayar pelanggan, bukan TCO kepemilikan mentah — mencerminkan Toggle Kelompok Biaya di Layar 5 (kelompok yang dibayar langsung + apa yang dibayar pelanggan ke VKTR, dengan markup, untuk kelompok yang ditanggung VKTR). Ubah toggle untuk melihat perubahannya.")} />
          </div>
          <div className="ksub">{L("B vs A · negative = B costs the customer more than A", "B vs A · negatif = B lebih mahal bagi pelanggan dari A")}</div>
        </div>
        <div className="kpi">
          <div className="kic">⏱</div>
          <div className="kval">{paybackBvA}</div>
          <div className="klbl">{L("Payback Period", "Periode Balik Modal")}</div>
          <div className="ksub">{L("B vs A · time for B's extra upfront cost (if any) to be recovered by B's lower running cost", "B vs A · waktu pengembalian biaya awal tambahan B (jika ada) melalui biaya operasional B yang lebih rendah")}</div>
        </div>
        <div className="kpi">
          <div className={"kval" + (co2Reduction > 0 ? " green" : co2Reduction < 0 ? " red" : "")}>
            <span className="kic" style={{ display: "block", fontSize: 18 }}>🌿</span>
            {co2Reduction >= 0 ? "+" : "−"}{Math.abs(co2Reduction).toLocaleString(locale, { maximumFractionDigits: 1 })} {L("tons", "ton")}
          </div>
          <div className="klbl">
            {L("CO₂ Reduction", "Reduksi CO₂")}
            <InfoHint note={L(
              "This is an operational, well-to-wheel comparison (combustion/grid generation + upstream fuel production for both sides), not full lifecycle emissions — vehicle/battery manufacturing is excluded unless you enable \"Life-Cycle CO2\" on Screen 5. A negative reading is still a real possible outcome, not necessarily an error, if an EV's per-km operational footprint is genuinely higher than a fuel-efficient ICE vehicle's under Indonesia's current grid mix. See Results → Details → CO2 / Emissions Breakdown for the exact factors used, or Calculation Steps for the formula.",
              "Ini adalah perbandingan operasional, well-to-wheel (pembakaran/pembangkitan listrik + produksi bahan bakar hulu untuk kedua sisi), bukan emisi siklus hidup penuh — manufaktur kendaraan/baterai tidak disertakan kecuali Anda mengaktifkan \"CO2 Siklus Hidup\" di Layar 5. Hasil negatif tetap kemungkinan nyata, bukan berarti kesalahan, jika jejak operasional per-km EV memang lebih tinggi dari kendaraan ICE yang hemat bahan bakar di bawah campuran jaringan listrik Indonesia saat ini. Lihat Hasil → Detail → Rincian CO2 / Emisi untuk faktor yang tepat, atau Langkah Kalkulasi untuk formula."
            )} />
          </div>
          <div className="ksub">{L("B vs A · negative = B emits more CO₂ than A over the horizon", "B vs A · negatif = B mengemisi CO₂ lebih banyak dari A selama horizon")}</div>
        </div>
        <div className="kpi">
          <div className="kic">📅</div>
          <div className="kval" style={{ fontSize: 15 }}>
            <span style={{ color: "var(--c-accent)" }}>{fmt.rpShort(R.monthlyB)}</span>
            <span style={{ fontSize: 11, color: "var(--text-muted)", margin: "0 4px" }}> vs </span>
            <span style={{ color: "var(--c-primary)" }}>{fmt.rpShort(R.monthlyA)}</span>
          </div>
          <div className="klbl">{L("Monthly Cost / Unit", "Biaya Bulanan / Unit")}</div>
          <div className="ksub">{L("B vs A · depreciation + maintenance per unit", "B vs A · depresiasi + perawatan per unit")}</div>
        </div>
      </div>

      {/* Unit economics (v1.6) — always shown, powertrain-aware. All-in and
          ton-km rows are directly comparable A vs B; native energy unit
          (Rp/L vs Rp/kWh) is not — it's shown per-vehicle in its own unit. */}
      <div className="kpi-row" style={{ marginTop: 10 }}>
        <div className="kpi">
          <div className="kic">📏</div>
          <div className="kval" style={{ fontSize: 15 }}>
            <span style={{ color: "var(--c-accent)" }}>{fmt.rp(bmB ? bmB.rates.customerTotalPayment.km : R.B.allInRpKm)}</span>
            <span style={{ fontSize: 11, color: "var(--text-muted)", margin: "0 4px" }}> vs </span>
            <span style={{ color: "var(--c-primary)" }}>{fmt.rp(bmA ? bmA.rates.customerTotalPayment.km : R.A.allInRpKm)}</span>
          </div>
          <div className="klbl">{L("Customer Cost / km", "Biaya Pelanggan / km")}</div>
          <div className="ksub">{L("B vs A · customer's total payment ÷ lifetime km — directly comparable", "B vs A · total bayar pelanggan ÷ km seumur hidup — dapat dibandingkan langsung")}</div>
        </div>
        {bmA && bmB && (bmA.rates.customerTotalPayment.tonKm > 0 || bmB.rates.customerTotalPayment.tonKm > 0) && (
          <div className="kpi">
            <div className="kic">⚖️</div>
            <div className="kval" style={{ fontSize: 15 }}>
              <span style={{ color: "var(--c-accent)" }}>{fmt.rp(bmB.rates.customerTotalPayment.tonKm)}</span>
              <span style={{ fontSize: 11, color: "var(--text-muted)", margin: "0 4px" }}> vs </span>
              <span style={{ color: "var(--c-primary)" }}>{fmt.rp(bmA.rates.customerTotalPayment.tonKm)}</span>
            </div>
            <div className="klbl">{L("Customer Cost / ton-km", "Biaya Pelanggan / ton-km")}</div>
            <div className="ksub">{L("B vs A · normalized by payload carried, not just distance", "B vs A · dinormalisasi berdasarkan muatan, bukan hanya jarak")}</div>
          </div>
        )}
        {bmA && bmB && (bmA.loanAnnual > 0 || bmB.loanAnnual > 0) && (
          <div className="kpi">
            <div className="kic">🏦</div>
            <div className="kval" style={{ fontSize: 15 }}>
              <span style={{ color: "var(--c-accent)" }}>{fmt.rpShort(bmB.loanAnnual)}</span>
              <span style={{ fontSize: 11, color: "var(--text-muted)", margin: "0 4px" }}> vs </span>
              <span style={{ color: "var(--c-primary)" }}>{fmt.rpShort(bmA.loanAnnual)}</span>
            </div>
            <div className="klbl">
              {L("Loan Expense / yr", "Beban Kredit / thn")}
              <InfoHint note={L(
                "The customer's annual loan-financing cost for the customer-borne UNIT purchase (0 if that vehicle's Payment Method on Screen 5 is Cash). Spread evenly across the horizon for a consistent yearly figure.",
                "Beban pembiayaan kredit tahunan pelanggan untuk pembelian UNIT yang ditanggung pelanggan (0 jika Metode Pembayaran kendaraan itu di Layar 5 adalah Tunai). Diratakan di seluruh horizon untuk angka tahunan yang konsisten.")} />
            </div>
            <div className="ksub">{L("B vs A · only nonzero under Loan", "B vs A · hanya nonzero jika Kredit")}</div>
          </div>
        )}
        {bmA && bmB && (bmA.subscriptionAnnual > 0 || bmB.subscriptionAnnual > 0) && (
          <div className="kpi">
            <div className="kic">📋</div>
            <div className="kval" style={{ fontSize: 15 }}>
              <span style={{ color: "var(--c-accent)" }}>{fmt.rpShort(bmB.subscriptionAnnual)}</span>
              <span style={{ fontSize: 11, color: "var(--text-muted)", margin: "0 4px" }}> vs </span>
              <span style={{ color: "var(--c-primary)" }}>{fmt.rpShort(bmA.subscriptionAnnual)}</span>
            </div>
            <div className="klbl">
              {L("Subscription Expense / yr", "Beban Sewa / thn")}
              <InfoHint note={L(
                "What the customer pays VKTR annually (marked up) for whichever Expense Buckets are VKTR-borne (Screen 5 toggle) — starts once the vehicle is delivered, priced to recover VKTR's cost basis within the Subscription Term (Screen 5, default 5 years), then renews at this same rate for the rest of the Horizon since VKTR still carries those buckets — years beyond the term are pure margin for VKTR. If Payment Method is Loan, this runs concurrently with the Loan Expense above, not instead of it — check both, they're two separate real cash-outflow streams, not a double-charge of the same thing.",
                "Yang dibayar pelanggan ke VKTR setiap tahun (dengan markup) untuk Kelompok Biaya yang ditanggung VKTR (toggle Layar 5) — dimulai setelah kendaraan dikirim, diberi harga untuk menutup biaya VKTR dalam Jangka Waktu Sewa (Layar 5, default 5 tahun), lalu diperpanjang dengan tarif yang sama untuk sisa Horizon karena VKTR tetap menanggung kelompok tersebut — tahun-tahun setelah jangka waktu adalah murni margin VKTR. Jika Metode Pembayaran adalah Kredit, ini berjalan bersamaan dengan Beban Kredit di atas, bukan menggantikannya — keduanya aliran kas riil terpisah, bukan penagihan ganda untuk hal yang sama.")} />
            </div>
            <div className="ksub">{L("B vs A · 0 if no bucket is VKTR-borne", "B vs A · 0 jika tak ada kelompok ditanggung VKTR")}</div>
          </div>
        )}
      </div>

      {/* v1.7.7: Customer/VKTR expense-bearing split -- who is financially
          exposed to which cost bucket, per vehicle. See Screen 5 -> Expense
          Bucket Toggle to change the split. */}
      {bmA && bmB && (
        <div className="card" style={{ padding: 18, marginTop: 14 }}>
          <div className="chart-title" style={{ display: "flex", alignItems: "center", gap: 6 }}>
            {L("Customer vs. VKTR — Who Bears What", "Pelanggan vs. VKTR — Siapa Menanggung Apa")}
            <InfoHint note={L(
              "Pre-markup cost exposure per vehicle, split by the Expense Bucket Toggle on Screen 5 -- distinct from the Customer Total Savings KPI above, which includes VKTR's markup on the buckets it bears (what the customer actually pays VKTR for those buckets, not VKTR's raw cost).",
              "Eksposur biaya sebelum markup per kendaraan, dibagi berdasarkan Toggle Kelompok Biaya di Layar 5 -- berbeda dari KPI Penghematan Total Pelanggan di atas, yang menyertakan markup VKTR pada kelompok yang ditanggungnya (yang benar-benar dibayar pelanggan ke VKTR untuk kelompok tersebut, bukan biaya riil VKTR).")} />
          </div>
          <BucketBearerBreakdown bmA={bmA} bmB={bmB} vA={vA} vB={vB} lang={lang} />
        </div>
      )}

      {/* v1.7.7 Wave 3: Ritase / charging-queue simulation (§7.10) -- EV-side
          only, null when neither A nor B is EV or fleet/sizing inputs are
          incomplete. Purely operational visualization, does not affect TCO
          figures above. */}
      {chargingSim && (() => {
        const rc = chargingSim.ritaseCycle;
        return (
        <div className="card" style={{ padding: 18, marginTop: 14 }}>
          <div className="chart-title" style={{ display: "flex", alignItems: "center", gap: 6 }}>
            {L("Charging Schedule Simulation", "Simulasi Jadwal Charging")}
            <InfoHint note={L(
              `Ritase-Cycle charging schedule for ${chargingSim.veh.name}: the day divides into ${rc.Z_CC} repeating charging cycle(s) (${(rc.CC/60).toFixed(1)}h each); each cycle runs ${rc.Z_TG} fleet-wide scheduled group(s) through a sequential ${chargingSim.chargeHours.toFixed(1)}h charging slot (${chargingSim.veh.name && rc.isSwap ? "swap" : "plug"} session), then a ${(rc.US/60).toFixed(1)}h unscheduled/opportunistic window. Groups are fixed for the whole deployment -- the same roster charges in the same slot every cycle. ${chargingSim.groupCount} group(s), ${chargingSim.minGroupSize === chargingSim.maxGroupSize ? chargingSim.minGroupSize : chargingSim.minGroupSize + "-" + chargingSim.maxGroupSize} units/group. Purely operational -- does not affect the TCO figures above. See CALCULATION_ENGINE.md §10.`,
              `Jadwal charging Siklus-Ritase untuk ${chargingSim.veh.name}: satu hari terbagi ${rc.Z_CC} siklus pengisian berulang (${(rc.CC/60).toFixed(1)} jam tiap siklus); tiap siklus menjalankan ${rc.Z_TG} grup terjadwal (seluruh armada) secara berurutan melalui slot pengisian ${chargingSim.chargeHours.toFixed(1)} jam (sesi ${rc.isSwap ? "swap" : "colok"}), lalu jendela tidak terjadwal/oportunistik ${(rc.US/60).toFixed(1)} jam. Grup tetap sepanjang masa operasi -- roster yang sama mengisi daya di slot yang sama setiap siklus. ${chargingSim.groupCount} kelompok, ${chargingSim.minGroupSize === chargingSim.maxGroupSize ? chargingSim.minGroupSize : chargingSim.minGroupSize + "-" + chargingSim.maxGroupSize} unit/kelompok. Murni operasional -- tidak memengaruhi angka TCO di atas. Lihat CALCULATION_ENGINE.md §10.`
            )} />
          </div>
          <div className="kpi-row" style={{ marginTop: 10 }}>
            <div className="kpi">
              <div className="kval" style={{ fontSize: 15 }}>
                {chargingSim.stats.groupCount} {L("groups", "kelompok")} · {chargingSim.minGroupSize === chargingSim.maxGroupSize ? `${fmt.num(chargingSim.minGroupSize)}` : `${fmt.num(chargingSim.minGroupSize)}-${fmt.num(chargingSim.maxGroupSize)}`}
              </div>
              <div className="klbl">{L("Groups · Units/Group", "Kelompok · Unit/Kelompok")}</div>
              <div className="ksub">
                {fmt.num(chargingSim.fleetSize)} {L("units total", "total unit")}
                {chargingSim.stats.groupGateViolated && (
                  <> · <WarnHint label={L("Group count adjusted", "Jumlah grup disesuaikan")}
                    note={L(`Proposed ${rc.PZ_TG} groups exceeds the ${rc.Z_TPG} slots that fit in one ${(rc.CC/60).toFixed(1)}h cycle -- auto-adjusted down to ${rc.Z_TG}. Reduce the proposed group count, use a shorter charging shift (SS), or add a cycle (Screen 4 -> Fleet & Charging).`,
                      `Usulan ${rc.PZ_TG} grup melebihi ${rc.Z_TPG} slot yang muat dalam satu siklus ${(rc.CC/60).toFixed(1)} jam -- disesuaikan otomatis ke ${rc.Z_TG}. Kurangi usulan jumlah grup, gunakan shift pengisian (SS) lebih pendek, atau tambah siklus (Layar 4 -> Armada & Pengisian).`)} /></>
                )}
              </div>
            </div>
            <div className="kpi">
              <div className="kval" style={{ fontSize: 15 }}>{rc.Z_CC} {L("cycles/day", "siklus/hari")}</div>
              <div className="klbl">{L("Charging Cycles (Z_CC)", "Siklus Pengisian (Z_CC)")}</div>
              <div className="ksub">
                {chargingSim.chargeHours.toFixed(1)}{L("h session", "j sesi")}
                {chargingSim.stats.cycleGateViolated && (
                  <> · <WarnHint label={L("Cycle count adjusted", "Jumlah siklus disesuaikan")}
                    note={L(`Proposed ${rc.PZ_CC} cycles/day didn't leave enough time for one group's drive-until-empty + charge (${(rc.TOT_OC/60).toFixed(1)}h needed) -- auto-adjusted down to ${rc.Z_CC}. Reduce the proposed cycle count, shorten Ritase Distance, or use a shorter charging shift (SS).`,
                      `Usulan ${rc.PZ_CC} siklus/hari tidak menyisakan cukup waktu untuk satu grup berjalan-hingga-habis + isi daya (butuh ${(rc.TOT_OC/60).toFixed(1)} jam) -- disesuaikan otomatis ke ${rc.Z_CC}. Kurangi usulan jumlah siklus, persingkat Jarak Ritase, atau gunakan shift pengisian (SS) lebih pendek.`)} /></>
                )}
              </div>
            </div>
            <div className="kpi">
              <div className="kval" style={{ fontSize: 15 }}>
                {chargingSim.stats.utilizationPct.toFixed(0)}%
              </div>
              <div className="klbl">{L("Depot Utilization", "Utilisasi Depot")}</div>
              <div className="ksub">{chargingSim.chargerCount} {L("charger(s)", "charger")}</div>
            </div>
          </div>
          <div style={{ marginTop: 14, overflowX: "auto" }}>
            <ChargingGanttChart sim={chargingSim} lang={lang} />
          </div>
        </div>
        );
      })()}

      {/* v1.8 (2026-07-17): Day-1 ramp-up (§10.8 CALCULATION_ENGINE.md) --
          groups can't all begin their first drive stint simultaneously (or
          they'd all need to charge at once, defeating the sequential-slot
          stagger), so each group's first-ever departure is delayed by
          (groupIndex-1) x SS to seed the rotation. Day 1 only: fleet-wide
          ritase/payload is reduced vs. steady state; Day 2 onward every
          group has completed one staggered entry and the fleet runs the
          steady-state Z_DR/TP_D figures every day thereafter. One-time
          depot-startup fact, not a recurring year-over-year pattern -- does
          not touch the multi-year cumulative chart above. */}
      {chargingSim && chargingSim.ritaseCycle && chargingSim.ritaseCycle.Z_TG > 1 && (() => {
        const rc = chargingSim.ritaseCycle;
        const rampPct = rc.steady.fleetRitase > 0 ? (rc.day1.fleetRitase / rc.steady.fleetRitase) * 100 : 100;
        return (
        <div className="card" style={{ padding: 18, marginTop: 14 }}>
          <div className="chart-title" style={{ display: "flex", alignItems: "center", gap: 6 }}>
            {L("Day 1 Ramp-Up vs. Steady State", "Ramp-Up Hari 1 vs. Kondisi Stabil")}
            <InfoHint note={L(
              `Groups are staggered into their scheduled slots one-by-one on Day 1 (group ${rc.Z_TG}'s first departure is delayed ${((rc.Z_TG - 1) * rc.SS / 60).toFixed(1)}h behind group 1's), so Day 1's fleet-wide ritase and payload are lower than every day from Day 2 onward, when the whole fleet has settled into the steady rotation.`,
              `Grup dijadwalkan masuk slot terjadwalnya satu per satu pada Hari 1 (keberangkatan pertama grup ${rc.Z_TG} tertunda ${((rc.Z_TG - 1) * rc.SS / 60).toFixed(1)} jam di belakang grup 1), sehingga ritase dan muatan armada di Hari 1 lebih rendah dibanding setiap hari mulai Hari 2, saat seluruh armada sudah masuk rotasi stabil.`
            )} />
          </div>
          <div className="kpi-row" style={{ marginTop: 10 }}>
            <div className="kpi">
              <div className="kval" style={{ fontSize: 15 }}>{fmt.num(rc.day1.fleetRitase)} {L("ritase", "ritase")}</div>
              <div className="klbl">{L("Day 1 Fleet Ritase", "Ritase Armada Hari 1")}</div>
              <div className="ksub">{fmt.num(Math.round(rc.day1.fleetPayload))} kg</div>
            </div>
            <div className="kpi">
              <div className="kval" style={{ fontSize: 15 }}>{fmt.num(rc.steady.fleetRitase)} {L("ritase", "ritase")}</div>
              <div className="klbl">{L("Day 2+ Fleet Ritase (steady state)", "Ritase Armada Hari 2+ (stabil)")}</div>
              <div className="ksub">{fmt.num(Math.round(rc.steady.fleetPayload))} kg</div>
            </div>
            <div className="kpi">
              <div className="kval" style={{ fontSize: 15 }}>{rampPct.toFixed(0)}%</div>
              <div className="klbl">{L("Day 1 vs. Steady State", "Hari 1 vs. Kondisi Stabil")}</div>
              <div className="ksub">{L("of steady-state daily throughput", "dari throughput harian stabil")}</div>
            </div>
          </div>
          {/* v1.7.8: cumulative payload delivered over longer horizons, per
              Rija's request -- steady-state daily figure (Day 1's reduced
              ramp-up throughput is a one-time startup fact, not
              representative of ongoing delivery) scaled to month/year/full
              analysis horizon. */}
          <div className="kpi-row" style={{ marginTop: 10 }}>
            <div className="kpi">
              <div className="kval" style={{ fontSize: 15 }}>{fmt.num(Math.round(rc.steady.fleetPayload * (rc.operatingDaysPerYear / 12)))} kg</div>
              <div className="klbl">{L("Monthly Payload (steady state)", "Muatan Bulanan (kondisi stabil)")}</div>
            </div>
            <div className="kpi">
              <div className="kval" style={{ fontSize: 15 }}>{fmt.num(Math.round(rc.steady.fleetPayload * rc.operatingDaysPerYear))} kg</div>
              <div className="klbl">{L("Yearly Payload (steady state)", "Muatan Tahunan (kondisi stabil)")}</div>
            </div>
            <div className="kpi">
              <div className="kval" style={{ fontSize: 15 }}>{fmt.num(Math.round(rc.steady.fleetPayload * rc.operatingDaysPerYear * s.horizon))} kg</div>
              <div className="klbl">{L(`Total Payload (${s.horizon}yr horizon)`, `Total Muatan (horizon ${s.horizon}th)`)}</div>
            </div>
          </div>
        </div>
        );
      })()}

      {/* Total Lead Time (v1.7.6) — informational only, does not affect TCO figures above */}
      <div className="card" style={{ padding: 18, marginTop: 14 }}>
        <div className="chart-title" style={{ display: "flex", alignItems: "center", gap: 6 }}>
          {L("Total Lead Time", "Total Lead Time")}
          <InfoHint note={L(
            "Order-to-delivery estimate, assuming the full fleet order is delivered together (conservative) — real deliveries are often staggered in batches and may be faster. Affected by fleet size (Screen 3) and each vehicle's configuration (Payload Build, Screen 2). Purely informational — does not affect the TCO figures above.",
            "Estimasi order-hingga-terkirim, mengasumsikan seluruh pesanan armada dikirim bersamaan (konservatif) — pengiriman nyata sering bertahap dan bisa lebih cepat. Dipengaruhi oleh jumlah armada (Layar 3) dan konfigurasi tiap kendaraan (Payload Build, Layar 2). Murni informatif — tidak memengaruhi angka TCO di atas."
          )} />
        </div>
        <div className="kpi-row" style={{ marginTop: 10 }}>
          {[["A", vA, leadTimeA, "var(--c-primary)"], ["B", vB, leadTimeB, "var(--c-accent)"]].map(([slotLabel, v, lt, color]) => (
            <div className="kpi" key={slotLabel}>
              <div className="kval" style={{ color, fontSize: 15 }}>
                {lt.total != null
                  ? `${fmt.num(Math.round(lt.total))} ${L("days", "hari")} (~${(lt.total / 30.44).toFixed(1)} ${L("mo", "bln")})`
                  : "—"}
              </div>
              <div className="klbl">{L(`Vehicle ${slotLabel}`, `Kendaraan ${slotLabel}`)} · {SEGMENT_LABEL[v.segment]?.[lang] || v.segment}</div>
              <div className="ksub">
                {lt.estimated
                  ? L("Estimated (modeled, not measured)", "Estimasi (dimodelkan, bukan diukur)")
                  : lt.payloadBuildFixedIncluded
                    ? L("Real PMO data · Payload Build included", "Data PMO nyata · Payload Build termasuk")
                    : L(`Real PMO data · Payload Build ${lt.payloadBuildApplied ? "on" : "off"}`, `Data PMO nyata · Payload Build ${lt.payloadBuildApplied ? "aktif" : "nonaktif"}`)}
              </div>
            </div>
          ))}
        </div>
        <div style={{ marginTop: 10, fontSize: 13.5 }}>
          {leadTimeA.total != null && leadTimeB.total != null && (
            leadTimeA.total === leadTimeB.total
              ? L(`${vA.name} and ${vB.name} have the same total lead time.`, `${vA.name} dan ${vB.name} memiliki total lead time yang sama.`)
              : leadTimeA.total < leadTimeB.total
                ? L(`Vehicle A (${vA.name}) has a faster total lead time — ${fmt.num(Math.round(leadTimeB.total - leadTimeA.total))} days shorter than Vehicle B.`, `Kendaraan A (${vA.name}) memiliki total lead time lebih cepat — ${fmt.num(Math.round(leadTimeB.total - leadTimeA.total))} hari lebih singkat dari Kendaraan B.`)
                : L(`Vehicle B (${vB.name}) has a faster total lead time — ${fmt.num(Math.round(leadTimeA.total - leadTimeB.total))} days shorter than Vehicle A.`, `Kendaraan B (${vB.name}) memiliki total lead time lebih cepat — ${fmt.num(Math.round(leadTimeA.total - leadTimeB.total))} hari lebih singkat dari Kendaraan A.`)
          )}
          {(leadTimeA.total == null || leadTimeB.total == null) &&
            L("Lead time unavailable for one or both vehicles.", "Lead time tidak tersedia untuk satu atau kedua kendaraan.")}
        </div>
        <div style={{ marginTop: 6, fontSize: 12, color: "var(--text-muted)" }}>
          {L(`Fleet size used: ${s.fleetSize || 0} units`, `Jumlah armada yang digunakan: ${s.fleetSize || 0} unit`)}
        </div>
      </div>

      {/* C-depot: Depot Design — final selected layout + summary (v1.5) */}
      {depotActive && s.depotMetrics && (
        <div className="card" style={{ padding: 18 }}>
          <div className="chart-title" style={{ marginBottom: 12 }}>
            {L("Depot Design — Selected Layout", "Desain Depot — Tata Letak Terpilih")}
          </div>
          <div style={{ display: "flex", gap: 18, flexWrap: "wrap", alignItems: "flex-start" }}>
            {s.depotMetrics.layoutSvg ? (
              <div style={{ flex: "1 1 360px", minWidth: 280, maxWidth: 520, border: "1px solid var(--border)", borderRadius: 8, overflow: "hidden" }}
                dangerouslySetInnerHTML={{ __html: s.depotMetrics.layoutSvg }} />
            ) : (
              <div style={{ flex: "1 1 360px", color: "var(--text-muted)", fontSize: 12 }}>
                {L("No layout snapshot received yet — open Screen 4 → Depot Design and generate/select a plan.", "Belum ada tangkapan tata letak — buka Layar 4 → Desain Depot dan buat/pilih rencana.")}
              </div>
            )}
            <div className="spec-grid" style={{ flex: "1 1 220px" }}>
              <div className="spec-cell">
                <div className="sk">{L("Selected Design", "Desain Terpilih")}</div>
                <div className="sv">{s.depotMetrics.planSummary?.planName || (s.depotMetrics.planSummary?.source === "studio" ? L("Studio Mode", "Mode Studio") : "—")}</div>
              </div>
              <div className="spec-cell">
                <div className="sk">{L("Bays", "Petak")}</div>
                <div className="sv">{fmt.num(s.depotMetrics.planSummary?.bayCount ?? s.depotMetrics.bayCount ?? 0)}</div>
              </div>
              <div className="spec-cell">
                <div className="sk">{L("Dispensers", "Dispenser")}</div>
                <div className="sv">{fmt.num(s.depotMetrics.planSummary?.dispCount ?? s.depotMetrics.dispCount ?? 0)}</div>
              </div>
              {(() => {
                const bays = s.depotMetrics.planSummary?.bayCount ?? s.depotMetrics.bayCount ?? 0;
                const disp = s.depotMetrics.planSummary?.dispCount ?? s.depotMetrics.dispCount ?? 0;
                const nz = s.depotMetrics.planSummary?.nozzles ?? s.depotMetrics.nozzles ?? 0;
                return (
                  <>
                    <div className="spec-cell">
                      <div className="sk">{L("Nozzles", "Nozzle")}</div>
                      <div className="sv">{fmt.num(nz)}</div>
                    </div>
                    <div className="spec-cell">
                      <div className="sk">{L("Nozzles per Bay", "Nozzle per Petak")}</div>
                      <div className="sv">{bays > 0 ? (nz / bays).toFixed(1) : "—"}</div>
                    </div>
                    <div className="spec-cell">
                      <div className="sk">{L("Dispensers per Bay", "Dispenser per Petak")}</div>
                      <div className="sv">{bays > 0 ? (disp / bays).toFixed(2) : "—"}</div>
                    </div>
                  </>
                );
              })()}
              <div className="spec-cell">
                <div className="sk">{L("Transformer", "Trafo")}</div>
                <div className="sv">{fmt.num(Math.round(s.depotMetrics.planSummary?.trafoKVA ?? s.depotMetrics.trafoKVA ?? 0))} kVA</div>
              </div>
              <div className="spec-cell">
                <div className="sk">{L("Site Area", "Luas Lokasi")}</div>
                <div className="sv">{fmt.num(s.depotMetrics.siteArea ?? 0)} m²</div>
              </div>
              <div className="spec-cell">
                <div className="sk">{L("Depot CAPEX (in TCO scope)", "CAPEX Depot (lingkup TCO)")}</div>
                <div className="sv">{fmt.rp(infraGrandTotal)}</div>
              </div>
            </div>
          </div>
          {/* v1.7.8: the excluded-CAPEX and undersized-provisioning warnings
              that used to sit here are gone -- see the matching removal note
              in screens.jsx's Tab6DepotDesign for why. */}
        </div>
      )}

      {/* C-bis: Side-by-Side Comparison */}
      <div className="card" style={{ padding: 0, overflow: "hidden" }}>
        <div style={{ padding: "18px 20px 0" }}>
          <div className="chart-title">
            {L("Side-by-Side Comparison", "Perbandingan Berdampingan")}
            {useCustomerRows && <InfoHint note={L(
              "Reflects what the CUSTOMER actually pays under the current Expense Bucket Toggle (Screen 5) -- capital cost only for customer-owned buckets, plus subscription payments to VKTR for any VKTR-borne buckets. Same basis as the Cost/km headline and the cumulative chart above.",
              "Mencerminkan yang benar-benar dibayar PELANGGAN sesuai Toggle Kelompok Biaya saat ini (Layar 5) -- biaya modal hanya untuk kelompok milik pelanggan, ditambah pembayaran langganan ke VKTR untuk kelompok yang ditanggung VKTR. Basis yang sama dengan headline Cost/km dan grafik kumulatif di atas.")} />}
          </div>
        </div>
        <table className="sbs-table" style={{ marginTop: 12 }}>
          <thead>
            <tr>
              <th>{L("Cost Segment", "Segmen Biaya")}</th>
              <th>{vA.name}</th>
              <th>{vB.name}</th>
              <th>{L("Δ Difference", "Δ Selisih")}</th>
              <th>{L("Better", "Lebih Baik")}</th>
            </tr>
          </thead>
          <tbody>
            {sbsRows.map((r, i) => (
              <tr key={i} className={r.isTotal ? "total" : ""}>
                <td className="lbl">{r.label}</td>
                <td className={"num" + (r.better === "A" ? " better" : "")}>{fmt.rpShort(r.a)}</td>
                <td className={"num" + (r.better === "B" ? " better" : "")}>{fmt.rpShort(r.b)}</td>
                <td className="diff">
                  {fmt.rpShort(r.diff)}
                  <small>{r.pct.toFixed(1)}%</small>
                </td>
                <td>
                  {r.better && <span className={"sbs-better-badge " + r.better.toLowerCase()}>{r.better}</span>}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {/* C2: Cost distribution donuts */}
      <div className="card chart-card">
        <div className="chart-title">{L("Cost Distribution per Vehicle", "Distribusi Biaya per Kendaraan")}</div>
        <div className="donut-row" style={{ marginTop: 12 }}>
          <CostDonut veh={vA} rows={rows} side="a" lang={lang} />
          <CostDonut veh={vB} rows={rows} side="b" lang={lang} />
        </div>
      </div>

      {/* E: Annual chart */}
      <div className="card chart-card">
        <div className="chart-title">{L("Annual OPEX (IDR Billion)", "Biaya Operasional per Tahun (Miliar IDR)")}</div>
        <div className="chart-legend">
          <div className="lg"><span className="sw" style={{ background: "var(--c-primary)" }}></span>{vA.name}</div>
          <div className="lg"><span className="sw" style={{ background: "var(--c-accent)" }}></span>{vB.name}</div>
        </div>
        <GroupedBarChart a={R.annualA} b={R.annualB} yrLabel={L("Yr", "Thn")} />
      </div>

      {/* E2: Cumulative total project cost chart -- v1.7.12: now the
          bucket-aware CUSTOMER payment stream (bmA/bmB.customerCumulative,
          computeExpenseBuckets/data.jsx) when both vehicles resolve a
          bucket model, matching the Cost/km headline's basis -- not the
          raw ownership CAPEX+OPEX total regardless of who bears it. Falls
          back to the raw R.cumulativeA/B (pre-v1.7.12 behavior) only if
          the bucket model can't resolve for some reason. */}
      {(() => {
        const useCustomerCumulative = !!(bmA && bmB);
        const cumA = useCustomerCumulative ? bmA.customerCumulative : R.cumulativeA;
        const cumB = useCustomerCumulative ? bmB.customerCumulative : R.cumulativeB;
        const hasSubscription = useCustomerCumulative && (bmA.subscriptionAnnual > 0 || bmB.subscriptionAnnual > 0);
        return (
          <div className="card chart-card">
            <div className="chart-title">
              {L("Cumulative Total Project Cost (IDR Billion)", "Total Biaya Proyek Kumulatif (Miliar IDR)")}
              <InfoHint note={useCustomerCumulative ? L(
                "This chart now shows what the CUSTOMER actually pays over the analysis horizon -- capital cost only for buckets they own outright (Expense Bucket Toggle, Screen 5), plus subscription payments to VKTR for any buckets VKTR carries -- matching the Results headline Cost/km figures. Residual value is already netted into Year 0's upfront cost for customer-owned buckets, not shown as a separate credit. Buckets VKTR carries cost the customer $0 upfront (VKTR owns that asset); their cost instead flows in as a level subscription payment from Year 1 onward, renewing at the same rate past the Subscription Term.",
                "Grafik ini kini menunjukkan yang benar-benar dibayar PELANGGAN selama horizon analisis -- hanya biaya modal untuk kelompok yang dimiliki penuh (Toggle Kelompok Biaya, Layar 5), ditambah pembayaran langganan ke VKTR untuk kelompok yang ditanggung VKTR -- sesuai basis Cost/km pada headline Layar Hasil. Nilai residu sudah dikurangkan ke biaya awal Tahun 0 untuk kelompok milik pelanggan, tidak ditampilkan sebagai kredit terpisah. Kelompok yang ditanggung VKTR tidak membebani pelanggan di Tahun 0 (asetnya milik VKTR); biayanya mengalir sebagai pembayaran langganan rata setiap tahun mulai Tahun 1, diperpanjang dengan tarif yang sama setelah Jangka Waktu Sewa berakhir."
              ) : L(
                "This chart shows the running total of CAPEX (incl. EVCS infrastructure investment), financing cost, and accumulated OPEX over the analysis horizon — without netting out residual value, which is only realized at end-of-life. It highlights the EV's higher upfront cost (vehicle price + charging infrastructure) versus its typically lower ongoing OPEX, and the point at which the cumulative cost lines cross.",
                "Grafik ini menunjukkan akumulasi total CAPEX (termasuk investasi infrastruktur EVCS), biaya pembiayaan, dan OPEX kumulatif selama horizon analisis — tanpa mengurangi nilai residu, yang baru terealisasi di akhir masa pakai. Grafik ini menyoroti biaya awal EV yang lebih tinggi (harga kendaraan + infrastruktur pengisian) dibandingkan OPEX berjalan yang umumnya lebih rendah, serta titik perpotongan kedua garis biaya kumulatif.")} />
            </div>
            <div className="chart-legend">
              <div className="lg"><span className="sw" style={{ background: "var(--c-primary)" }}></span>{vA.name}</div>
              <div className="lg"><span className="sw" style={{ background: "var(--c-accent)" }}></span>{vB.name}</div>
              {hasSubscription && <span className="assumption-tag" style={{ textTransform: "none" }}>
                {L("Includes subscription payments", "Termasuk pembayaran langganan")}
              </span>}
            </div>
            <CumulativeCostChart a={cumA} b={cumB} yrLabel={L("Year", "Tahun")} lang={lang} labelA={vA.name} labelB={vB.name} />
          </div>
        );
      })()}

      {/* C3+F1.5+F2: Key Takeaways (v1.7.8: fused with Cost Segment
          Leadership + Decision Points into one compact bullet card, per
          Rija's explicit request to shorten Tab 1 -- same underlying data
          (aLeads/bLeads/biggestDriver/paybackWinnerText/co2Winner), just
          condensed to one line each instead of a full sentence, and the
          IRR-vs-WACC hurdle-rate verdict leads the card as the headline
          "is this worth it" line. */}
      <div className="card takeaways-card">
        <h3>📌 {L("Key Takeaways", "Poin-Poin Utama")}</h3>
        {hasIrr && (
          <div className={"irr-verdict" + (irrClearsWacc ? " pos" : " neg")}>
            {irrClearsWacc ? "✅" : "⚠️"}{" "}
            {irrClearsWacc
              ? L(`IRR ${irrText} clears your ${waccPct}% WACC hurdle — this switch is expected to create value.`,
                  `IRR ${irrText} melampaui ambang WACC ${waccPct}% Anda — perpindahan ini diperkirakan menciptakan nilai.`)
              : L(`IRR ${irrText} is below your ${waccPct}% WACC hurdle — this switch may not create value at your cost of capital.`,
                  `IRR ${irrText} di bawah ambang WACC ${waccPct}% Anda — perpindahan ini mungkin tidak menciptakan nilai pada biaya modal Anda.`)}
          </div>
        )}
        <ul className="takeaways-list compact">
          <li>
            <b>{winnerName}</b> {L("saves", "hemat")} <b>{fmt.rpShort(savings)}</b> {L("vs", "vs")} {loserName} {L(`over ${s.horizon}yr`, `selama ${s.horizon}thn`)}
            {R.paybackWinnerNote === null && <> · {L("payback", "BEP")} <b>{paybackWinnerText}</b></>}
          </li>
          {co2Winner > 0 && (
            <li>{L("Avoids", "Hindari")} <b>{co2Winner.toLocaleString(locale, { maximumFractionDigits: 1 })}t CO₂</b> {L("vs", "vs")} {loserName}.</li>
          )}
          {aLeads.length > 0 && <li><b>{vA.name}</b> {L("leads", "unggul")}: {aLeads.map(r => r.label).join(", ")}</li>}
          {bLeads.length > 0 && <li><b>{vB.name}</b> {L("leads", "unggul")}: {bLeads.map(r => r.label).join(", ")}</li>}
          {biggestDriver && biggestDriver.d > 1 && (
            <li>{L("Biggest driver", "Selisih terbesar")}: <b>{L(biggestDriver.row.en, biggestDriver.row.id)}</b> (Δ{fmt.rpShort(biggestDriver.d)})</li>
          )}
          {hasEstimasi && (
            <li>⚠ {L("Some specs are estimated — confirm with OEM.", "Sebagian spesifikasi bersifat estimasi — konfirmasi dengan OEM.")}</li>
          )}
        </ul>
      </div>

      {/* G: Recommendation (v1.7.8: compacted to one dense sentence + a
          one-word verdict, per Rija's request -- was ~5 sentences). */}
      <div className="reco-box">
        <h3>💡 {L("Recommendation", "Rekomendasi")}</h3>
        <p>
          <b>{winnerName}</b> — {L("saves", "hemat")} <span className="hl">{fmt.rpShort(savings)}</span> {L(`over ${s.horizon}yr`, `selama ${s.horizon}thn`)}
          {R.paybackWinnerNote === null && <>, {L("payback", "BEP")} <b>{paybackWinnerText}</b></>}
          {hasIrr && <>, IRR <b>{irrText}</b> {irrClearsWacc ? L("clears", "melampaui") : L("below", "di bawah")} {waccPct}% WACC</>}
          {co2Winner > 0 && <>, {L("avoids", "hindari")} <b>{co2Winner.toLocaleString(locale, { maximumFractionDigits: 1 })}t CO₂</b></>}.{" "}
          {(irrClearsWacc || R.paybackWinnerNote === null) ? L("Recommended.", "Direkomendasikan.") : L("Marginal — review assumptions.", "Marjinal — tinjau asumsi.")}
        </p>
      </div>

      </div>
      {/* ============== END TAB 1: SUMMARY ============== */}

      {/* ============================================================
          TAB 2: DETAILS — numbers, OPEX, CAPEX, all model results
          ============================================================ */}
      <div className={"report-tab-panel" + (activeTab === 1 ? " active" : "")}>

      {/* A1: Customer & Project Context (v1.3) */}
      {s.ecosystemId && (
        <div className="card" style={{ padding: 18 }}>
          <div className="chart-title" style={{ marginBottom: 12 }}>
            {L("Customer & Project Context", "Konteks Pelanggan & Proyek")}
          </div>
          <div className="spec-grid">
            <div className="spec-cell">
              <div className="sk">{L("Ecosystem", "Ekosistem")}</div>
              <div className="sv">{ecosystemOpt ? `${ecosystemOpt.icon} ${L(ecosystemOpt.label, ecosystemOpt.labelId)}` : "—"}</div>
            </div>
            <div className="spec-cell">
              <div className="sk">{L("Preset", "Preset")}</div>
              <div className="sv">{presetOpt ? presetOpt.label : L("Custom (no preset)", "Kustom (tanpa preset)")}</div>
            </div>
            <div className="spec-cell">
              <div className="sk">{L("Fleet Size", "Jumlah Armada")}</div>
              <div className="sv">{fmt.num(s.fleetSize)} {unitW}</div>
            </div>
            <div className="spec-cell">
              <div className="sk">{L("Start Date", "Tanggal Mulai")}</div>
              <div className="sv">{projectStartLabel || "—"}</div>
            </div>
          </div>
        </div>
      )}

      {/* C: TCO comparison table */}
      <div className="card" style={{ padding: 0, overflow: "hidden" }}>
        <table className="tco-table">
          <thead>
            <tr>
              <th style={{ width: "44%" }}></th>
              <th>
                <div className="colhead">
                  <div className="badges">
                    <Badge kind={vA.powertrain === "EV" ? "ev" : "ice"}>{vA.powertrain}</Badge>
                    {vA.vktr && <Badge kind="vktr">VKTR</Badge>}
                    {vA.placeholder && <Badge kind="warn">⚠ Est.</Badge>}
                    {aWins && <Badge kind="win">🏆 {L("Lowest", "Hemat")}</Badge>}
                  </div>
                  <span className="cn">{vA.name}</span>
                </div>
              </th>
              <th>
                <div className="colhead">
                  <div className="badges">
                    <Badge kind={vB.powertrain === "EV" ? "ev" : "ice"}>{vB.powertrain}</Badge>
                    {vB.vktr && <Badge kind="vktr">VKTR</Badge>}
                    {vB.placeholder && <Badge kind="warn">⚠ Est.</Badge>}
                    {!aWins && <Badge kind="win">🏆 {L("Lowest", "Hemat")}</Badge>}
                  </div>
                  <span className="cn">{vB.name}</span>
                </div>
              </th>
              <th style={{ width: "13%" }}>{L("Delta (A vs B)", "Selisih (A vs B)")}</th>
            </tr>
          </thead>
          <tbody>
            {rows.map((r, i) => (
              <tr key={i}>
                {rowLabel(r)}
                {cell(r.a, r.residual, aWins)}
                {cell(r.b, r.residual, !aWins)}
                {deltaCell(r.a, r.b)}
              </tr>
            ))}
            <tr className="total">
              <td className="lbl" style={{ color: "#fff" }}>{L("Total TCO", "Total TCO")}<small>{L("Total TCO", "Total TCO")}</small></td>
              <td className={"num" + (aWins ? " win-border" : "")}>{fmt.rpShort(totalA)}</td>
              <td className={"num" + (!aWins ? " win-border" : "")}>{fmt.rpShort(totalB)}</td>
              {deltaCell(totalA, totalB)}
            </tr>
          </tbody>
        </table>
      </div>

      {/* Total Lead Time detail (v1.7.6) — per-phase breakdown for real-PMO-data
          vehicles; a competitor/no-data side shows only its estimated total,
          never fabricated phase numbers. */}
      <div className="card" style={{ padding: 0, overflow: "hidden" }}>
        <table className="tco-table">
          <thead>
            <tr>
              <th style={{ width: "44%" }}>{L("Lead Time Phase", "Fase Lead Time")}</th>
              <th><div className="colhead"><span className="cn">{vA.name}</span></div></th>
              <th><div className="colhead"><span className="cn">{vB.name}</span></div></th>
            </tr>
          </thead>
          <tbody>
            {[
              ["internalProcess", "Internal Process", "Proses Internal"],
              ["principalProduction", "Principal Production", "Produksi Prinsipal"],
              ["shipping", "Shipping to Indonesia", "Pengiriman ke Indonesia"],
              ["customs", "Customs & Handling", "Bea Cukai & Penanganan"],
              ["chassisAssembly", "Chassis Assembly", "Perakitan Sasis"],
              ["bodyBuilder", "Body Builder", "Karoseri"],
              ["finalPdi", "Final PDI", "PDI Akhir"],
              ["delivery", "Delivery", "Pengiriman"],
              ["vehicleRegistration", "Vehicle Registration", "Registrasi Kendaraan"],
            ].map(([key, en, id]) => (leadTimeA.estimated && leadTimeB.estimated) ? null : (
              <tr key={key}>
                <td className="lbl">{L(en, id)}</td>
                <td className="num">{leadTimeA.estimated ? "—" : `${fmt.num(Math.round(leadTimeA.phases[key]))} ${L("d", "hr")}`}</td>
                <td className="num">{leadTimeB.estimated ? "—" : `${fmt.num(Math.round(leadTimeB.phases[key]))} ${L("d", "hr")}`}</td>
              </tr>
            ))}
            {(leadTimeA.payloadBuildApplied || leadTimeB.payloadBuildApplied) && (
              <tr>
                <td className="lbl">{L("Payload Build (optional)", "Payload Build (opsional)")}</td>
                <td className="num">{leadTimeA.estimated ? "—" : (leadTimeA.payloadBuildApplied ? `${fmt.num(Math.round(leadTimeA.payloadBuildDays))} ${L("d", "hr")}` : L("off", "nonaktif"))}</td>
                <td className="num">{leadTimeB.estimated ? "—" : (leadTimeB.payloadBuildApplied ? `${fmt.num(Math.round(leadTimeB.payloadBuildDays))} ${L("d", "hr")}` : L("off", "nonaktif"))}</td>
              </tr>
            )}
            <tr className="total">
              <td className="lbl" style={{ color: "#fff" }}>{L("Total Lead Time", "Total Lead Time")}</td>
              <td className="num">
                {leadTimeA.total != null ? `${fmt.num(Math.round(leadTimeA.total))} ${L("days", "hari")}` : "—"}
                {leadTimeA.estimated && <InfoHint note={L("Estimated — modeled from import type, segment, and powertrain; no real PMO data behind this vehicle.", "Estimasi — dimodelkan dari tipe impor, segmen, dan jenis penggerak; tidak ada data PMO nyata di balik kendaraan ini.")} />}
              </td>
              <td className="num">
                {leadTimeB.total != null ? `${fmt.num(Math.round(leadTimeB.total))} ${L("days", "hari")}` : "—"}
                {leadTimeB.estimated && <InfoHint note={L("Estimated — modeled from import type, segment, and powertrain; no real PMO data behind this vehicle.", "Estimasi — dimodelkan dari tipe impor, segmen, dan jenis penggerak; tidak ada data PMO nyata di balik kendaraan ini.")} />}
              </td>
            </tr>
          </tbody>
        </table>
      </div>

      {/* C5: Infrastructure Configuration Summary (v1.3) */}
      {sizing && (() => {
        const chargingTypeLabels = {
          ac:     { en: "AC",      id: "AC" },
          dc:     { en: "DC",      id: "DC" },
          dcfast: { en: "DC Fast", id: "DC Cepat" },
        };
        const chargingTypeLabel = chargingTypeLabels[sizing.chargingType]
          ? L(chargingTypeLabels[sizing.chargingType].en, chargingTypeLabels[sizing.chargingType].id)
          : (sizing.chargingType || "—");
        const readinessIcon = { green: "🟢", yellow: "🟡", red: "🔴" }[sizing.readiness] || "⚪";
        const readinessMsg = sizing.readiness === "green"
          ? L("Existing infrastructure sufficient", "Infrastruktur eksisting mencukupi")
          : sizing.existingKva == null
          ? L("Readiness unknown — site power data not provided", "Kesiapan tidak diketahui — data daya lokasi belum diisi")
          : sizing.readiness === "yellow"
          ? L(`Minor upgrade required (+${sizing.increasePct.toFixed(0)}%)`, `Perlu upgrade kecil (+${sizing.increasePct.toFixed(0)}%)`)
          : L(`Major upgrade required (+${sizing.increasePct.toFixed(0)}%)`, `Perlu upgrade besar (+${sizing.increasePct.toFixed(0)}%)`);
        return (
          <div className="card" style={{ padding: 18 }}>
            <div className="chart-title" style={{ marginBottom: 12 }}>
              {L("Infrastructure Configuration Summary", "Ringkasan Konfigurasi Infrastruktur")}
            </div>
            <div className="spec-grid">
              <div className="spec-cell">
                <div className="sk">{L("Charging Mode", "Mode Pengisian Daya")}</div>
                <div className="sv">{chargingTypeLabel} — {sizing.chargingWindowHours} {L("hrs/day", "jam/hari")}</div>
              </div>
              <div className="spec-cell">
                <div className="sk">{L("Recommended Chargers", "Charger Rekomendasi")}</div>
                <div className="sv">{fmt.num(sizing.chargerCount)} {L("units", "unit")} × {sizing.chargerRatingKw} kW</div>
              </div>
              <div className="spec-cell">
                <div className="sk">{L("Transformer Required", "Trafo Dibutuhkan")}</div>
                <div className="sv">{fmt.num(Math.round(sizing.transformerKva))} kVA</div>
              </div>
              <div className="spec-cell">
                <div className="sk">{L("Infrastructure Status", "Status Infrastruktur")}</div>
                <div className="sv">{readinessIcon} {readinessMsg}</div>
              </div>
            </div>
          </div>
        );
      })()}

      {/* C6: EVCS CAPEX Breakdown Table (v1.3) — or Depot Design's own breakdown when active (v1.5) */}
      {depotActive ? (
        <div className="card" style={{ padding: 0, overflow: "hidden" }}>
          <div style={{ padding: "18px 20px 0" }}>
            <div className="chart-title">{L("Infrastructure CAPEX/OPEX — sourced from Depot Design", "CAPEX/OPEX Infrastruktur — bersumber dari Desain Depot")}</div>
          </div>
          <table className="sbs-table" style={{ marginTop: 12 }}>
            <thead>
              <tr>
                <th>{L("Category", "Kategori")}</th>
                <th>{L("Items", "Item")}</th>
                <th>{L("CAPEX (IDR)", "CAPEX (IDR)")}</th>
                <th>{L("OPEX/yr (IDR)", "OPEX/thn (IDR)")}</th>
              </tr>
            </thead>
            <tbody>
              {DEPOT_CATEGORY_ORDER.filter(key => {
                const c = s.depotBom.byCategory[key];
                const inScope = !s.depotBomInclude || s.depotBomInclude[key];
                return c && inScope && (c.capex > 0 || c.opex > 0);
              }).map(key => {
                const cat = s.depotBom.byCategory[key];
                const lbl = DEPOT_CATEGORY_LABELS[key] || { en: key, id: key };
                const itemsLabel = Object.entries(cat.items || {}).filter(([, v]) => v)
                  .map(([k]) => DEPOT_ITEM_LABELS[k] || k).join(", ") || "—";
                return (
                  <tr key={key}>
                    <td className="lbl">{L(lbl.en, lbl.id)}</td>
                    <td>{itemsLabel}</td>
                    <td className="num">{fmt.rp(cat.capex)}</td>
                    <td className="num">{fmt.rp(cat.opex)}</td>
                  </tr>
                );
              })}
              <tr className="total">
                <td className="lbl">{L("Total (in TCO scope)", "Total (dalam lingkup TCO)")}</td>
                <td></td>
                <td className="num">{fmt.rp(s.depotBom.tcoCapex)}</td>
                <td className="num">{fmt.rp(s.depotBom.tcoOpex)}</td>
              </tr>
            </tbody>
          </table>
          <div style={{ padding: "0 20px 16px", fontSize: 11, color: "var(--text-muted)" }}>
            {L("\"In TCO scope\" reflects which Depot Design categories are toggled on for TCO in the depot tool's own BOM/Cost tab (defaults to charging equipment only).",
               "\"Dalam lingkup TCO\" mencerminkan kategori Desain Depot mana yang diaktifkan untuk TCO di tab BOM/Cost milik alat depot sendiri (default hanya peralatan pengisian).")}
          </div>
        </div>
      ) : (sizing && capex && (
        <div className="card" style={{ padding: 0, overflow: "hidden" }}>
          <div style={{ padding: "18px 20px 0" }}>
            <div className="chart-title">{L("EVCS CAPEX Breakdown", "Rincian CAPEX SPKLU")}</div>
          </div>
          <table className="sbs-table" style={{ marginTop: 12 }}>
            <thead>
              <tr>
                <th>{L("Category", "Kategori")}</th>
                <th>{L("Items", "Item")}</th>
                <th>{L("Amount (IDR)", "Jumlah (IDR)")}</th>
              </tr>
            </thead>
            <tbody>
              {[
                { code: "A", label: L("Charger Equipment", "Peralatan Pengisian Daya"), data: capex.A, applicable: capex.chargeApplicable },
                { code: "B", label: L("Electrical Infrastructure", "Infrastruktur Kelistrikan"), data: capex.B, applicable: true },
                { code: "C", label: L("Civil Works", "Pekerjaan Sipil"), data: capex.C, applicable: true },
                { code: "D", label: L("Utility Upgrade", "Upgrade Utilitas"), data: capex.D, applicable: true },
                { code: "E", label: L("Software", "Perangkat Lunak"), data: capex.E, applicable: true },
              ].map((cat, i) => (
                <tr key={i} style={!cat.applicable ? { opacity: 0.5 } : undefined}>
                  <td className="lbl">{cat.code}. {cat.label}</td>
                  <td>{cat.applicable ? cat.data.items.filter(it => it.value > 0).map(it => it.label).join(", ") || "—" : L("NOT APPLICABLE", "TIDAK BERLAKU")}</td>
                  <td className="num">{cat.applicable ? fmt.rp(cat.data.total) : "—"}</td>
                </tr>
              ))}
              {capex.salvageCredit > 0 && (
                <tr>
                  <td className="lbl">{L("Salvage Credit (Replacement)", "Kredit Sisa Aset (Penggantian)")}</td>
                  <td>—</td>
                  <td className="num">−{fmt.rp(capex.salvageCredit)}</td>
                </tr>
              )}
              <tr className="total">
                <td className="lbl">{L("Total EVCS CAPEX (full facility)", "Total CAPEX SPKLU (fasilitas penuh)")}</td>
                <td></td>
                <td className="num">{fmt.rp(capex.total)}</td>
              </tr>
              <tr className="total">
                <td className="lbl">{L("In TCO scope (A+B, Electrical only)", "Dalam lingkup TCO (A+B, Elektrikal saja)")}</td>
                <td>{L("C/D/E + all OPEX: Helio Sinar Energi's", "C/D/E + semua OPEX: milik Helio Sinar Energi")}</td>
                <td className="num">{fmt.rp(capex.tcoCapex)}</td>
              </tr>
              <tr>
                <td className="lbl">{L("Annual EVCS OPEX (in TCO scope)", "OPEX SPKLU Tahunan (dalam lingkup TCO)")}</td>
                <td></td>
                <td className="num">{fmt.rp(0)}</td>
              </tr>
            </tbody>
          </table>
        </div>
      ))}

      {/* C6b: Maintenance Breakdown (v1.5) — same per-part table as Screen 2's Audit tab, shown here too so the Results screen doesn't require flipping back to audit it */}
      <div className="card" style={{ padding: 18 }}>
        <div className="chart-title" style={{ marginBottom: 4, display: "flex", alignItems: "center" }}>
          {L("Maintenance Breakdown", "Rincian Perawatan")}
          <InfoHint note={L("Year 1 shown below — this parts breakdown is the maintenance cost source in the TCO calculation above unless a manual override is set (see badge per vehicle).", "Tahun 1 ditampilkan di bawah — rincian komponen ini adalah sumber biaya perawatan dalam perhitungan TCO di atas kecuali override manual diatur (lihat badge per kendaraan).")} />
        </div>
        <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
          <MaintenanceBreakdownTable veh={vA} annualKm={window.resolveAnnualKm(s)} lang={lang} s={s} overrideKey="maintOverrideA" selectedYear={1}
            tyreTier={s.tyreTierA} tyreTierPriceOverrides={s.tyreTierPriceOverrides}
            onTierChange={v => set("tyreTierA", v)} onPriceChange={(key, val) => set("tyreTierPriceOverrides", { ...(s.tyreTierPriceOverrides || {}), [key]: val })}
            groupOverrides={s.maintGroupOverrides?.A}
            onGroupOverrideChange={(g, val) => {
              const next = { ...(s.maintGroupOverrides || {}) };
              const slotNext = { ...(next.A || {}) };
              if (val == null) delete slotNext[g]; else slotNext[g] = val;
              next.A = slotNext;
              set("maintGroupOverrides", next);
            }} />
          <MaintenanceBreakdownTable veh={vB} annualKm={window.resolveAnnualKm(s)} lang={lang} s={s} overrideKey="maintOverrideB" selectedYear={1}
            tyreTier={s.tyreTierB} tyreTierPriceOverrides={s.tyreTierPriceOverrides}
            onTierChange={v => set("tyreTierB", v)} onPriceChange={(key, val) => set("tyreTierPriceOverrides", { ...(s.tyreTierPriceOverrides || {}), [key]: val })}
            groupOverrides={s.maintGroupOverrides?.B}
            onGroupOverrideChange={(g, val) => {
              const next = { ...(s.maintGroupOverrides || {}) };
              const slotNext = { ...(next.B || {}) };
              if (val == null) delete slotNext[g]; else slotNext[g] = val;
              next.B = slotNext;
              set("maintGroupOverrides", next);
            }} />
        </div>
      </div>

      {/* C6c: Financial Breakdown (v1.5) — itemizes the aggregate "Financing Cost" row */}
      <div className="card" style={{ padding: 18 }}>
        <div className="chart-title" style={{ marginBottom: 12 }}>{L("Financial Breakdown", "Rincian Pembiayaan")}</div>
        <table className="sbs-table">
          <thead>
            <tr>
              <th>{L("Item", "Item")}</th>
              <th>{vA.name}</th>
              <th>{vB.name}</th>
            </tr>
          </thead>
          <tbody>
            <tr><td className="lbl">{L("Payment Method", "Metode Pembayaran")}</td>
              <td>{s.paymentA === "loan" ? L("Loan", "Kredit") : L("Cash", "Tunai")}</td>
              <td>{s.paymentB === "loan" ? L("Loan", "Kredit") : L("Cash", "Tunai")}</td></tr>
            {(s.paymentA === "loan" || s.paymentB === "loan") && (<>
              <tr><td className="lbl">{L("Unit Price", "Harga Unit")}</td><td className="num">{fmt.rp(s.priceA ?? vA.price)}</td><td className="num">{fmt.rp(s.priceB ?? vB.price)}</td></tr>
              <tr><td className="lbl">{L("Fleet CAPEX", "CAPEX Armada")}</td><td className="num">{fmt.rp(rows[0].a)}</td><td className="num">{fmt.rp(rows[0].b)}</td></tr>
              <tr><td className="lbl">{L("Down Payment", "Uang Muka")}</td>
                <td className="num">{s.paymentA === "loan" ? `${s.downPayment}%` : "—"}</td>
                <td className="num">{s.paymentB === "loan" ? `${s.downPayment}%` : "—"}</td></tr>
              <tr><td className="lbl">{L("Financed Principal", "Pokok Dibiayai")}</td>
                <td className="num">{s.paymentA === "loan" ? fmt.rp(rows[0].a * (1 - (s.downPayment || 0) / 100)) : "—"}</td>
                <td className="num">{s.paymentB === "loan" ? fmt.rp(rows[0].b * (1 - (s.downPayment || 0) / 100)) : "—"}</td></tr>
              <tr><td className="lbl">{L("Interest Rate (flat/yr)", "Bunga (flat/thn)")}</td>
                <td className="num">{s.paymentA === "loan" ? `${s.interest}%` : "—"}</td>
                <td className="num">{s.paymentB === "loan" ? `${s.interest}%` : "—"}</td></tr>
              <tr><td className="lbl">{L("Annual Financing Cost", "Biaya Pembiayaan/Thn")}</td>
                <td className="num">{s.paymentA === "loan" ? fmt.rp(rows[0].a * (1 - (s.downPayment || 0) / 100) * ((s.interest || 0) / 100)) : "—"}</td>
                <td className="num">{s.paymentB === "loan" ? fmt.rp(rows[0].b * (1 - (s.downPayment || 0) / 100) * ((s.interest || 0) / 100)) : "—"}</td></tr>
              <tr><td className="lbl">{L("Loan Tenor", "Tenor Kredit")}</td>
                <td className="num">{s.paymentA === "loan" ? `${s.tenor} ${yrW}` : "—"}</td>
                <td className="num">{s.paymentB === "loan" ? `${s.tenor} ${yrW}` : "—"}</td></tr>
            </>)}
            <tr className="total"><td className="lbl">{L("Total Financing Cost", "Total Biaya Pembiayaan")}</td><td className="num">{fmt.rp(rows[1].a)}</td><td className="num">{fmt.rp(rows[1].b)}</td></tr>
          </tbody>
        </table>
      </div>

      {/* C6d: Yearly Expense Editor (v1.5/§task30) — DB default + per-year
          user override for the platform's 4 recurring-cost sections. */}
      <div className="card" style={{ padding: 18 }}>
        <div className="chart-title" style={{ marginBottom: 4, display: "flex", alignItems: "center" }}>
          {L("Yearly Expense Editor", "Editor Biaya Tahunan")}
          <InfoHint note={L("Override any single year's cost below — the computed default still applies to every year you haven't touched. Click the ● marker to reset a cell.",
             "Timpa biaya tahun tertentu di bawah — default yang dihitung tetap berlaku untuk tahun yang belum Anda ubah. Klik penanda ● untuk reset sel.")} />
        </div>
        <YearlyExpenseEditor s={s} set={set} lang={lang} category="energy"
          title={L("Operation — Energy / Fuel Cost", "Operasional — Biaya Energi / BBM")}
          defaultsA={Rdefault.yearlyA.energy} defaultsB={Rdefault.yearlyB.energy}
          labelA={vA.name} labelB={vB.name} />
        {(Rdefault.yearlyA.adblue.some(v => v > 0) || Rdefault.yearlyB.adblue.some(v => v > 0)) && (
          <YearlyExpenseEditor s={s} set={set} lang={lang} category="adblue"
            title={L("Operation — AdBlue Cost", "Operasional — Biaya AdBlue")}
            defaultsA={Rdefault.yearlyA.adblue} defaultsB={Rdefault.yearlyB.adblue}
            labelA={vA.name} labelB={vB.name} />
        )}
        <YearlyExpenseEditor s={s} set={set} lang={lang} category="maintenance"
          title={L("Maintenance Cost", "Biaya Perawatan")}
          defaultsA={Rdefault.yearlyA.maintenance} defaultsB={Rdefault.yearlyB.maintenance}
          labelA={vA.name} labelB={vB.name} />
        <YearlyExpenseEditor s={s} set={set} lang={lang} category="infrastructure"
          title={L("Infrastructure OPEX", "OPEX Infrastruktur")}
          defaultsA={Rdefault.yearlyA.infrastructure} defaultsB={Rdefault.yearlyB.infrastructure}
          labelA={vA.name} labelB={vB.name} />
        <YearlyExpenseEditor s={s} set={set} lang={lang} category="financing"
          title={L("Financial — Financing Cost", "Keuangan — Biaya Pembiayaan")}
          defaultsA={Rdefault.yearlyA.financing} defaultsB={Rdefault.yearlyB.financing}
          labelA={vA.name} labelB={vB.name} />
        {(Rdefault.yearlyA.insurance.some(v => v > 0) || Rdefault.yearlyB.insurance.some(v => v > 0)) && (
          <YearlyExpenseEditor s={s} set={set} lang={lang} category="insurance"
            title={L("Financial — Insurance Cost", "Keuangan — Biaya Asuransi")}
            defaultsA={Rdefault.yearlyA.insurance} defaultsB={Rdefault.yearlyB.insurance}
            labelA={vA.name} labelB={vB.name} />
        )}
      </div>

      {/* C6e: CO2 / Emissions Breakdown (v1.8) — the CO2 Reduction KPI had
          zero audit trail anywhere in the platform before this; itemizes
          the exact energy consumption, emission factor, and (opt-in)
          embodied manufacturing CO2 driving that number. */}
      <div className="card" style={{ padding: 18 }}>
        <div className="chart-title" style={{ marginBottom: 4, display: "flex", alignItems: "center" }}>
          {L("CO₂ / Emissions Breakdown", "Rincian CO₂ / Emisi")}
          <InfoHint note={L("Operational figures are well-to-wheel (combustion/grid generation + upstream fuel production), computed with the same energy consumption assumption used for cost above — not the catalog's raw spec.",
             "Angka operasional adalah well-to-wheel (pembakaran/pembangkitan listrik + produksi bahan bakar hulu), dihitung dengan asumsi konsumsi energi yang sama dengan biaya di atas — bukan spesifikasi mentah katalog.")} />
        </div>
        <table className="sbs-table">
          <thead>
            <tr><th>{L("Item", "Item")}</th><th>{vA.name}</th><th>{vB.name}</th></tr>
          </thead>
          <tbody>
            <tr><td className="lbl">{L("Powertrain", "Jenis Penggerak")}</td><td>{vA.powertrain}</td><td>{vB.powertrain}</td></tr>
            <tr><td className="lbl">{L("Energy Consumption Used", "Konsumsi Energi Digunakan")}</td>
              <td className="num">{fmt.num(R.A.ecNum)} {vA.powertrain === "EV" ? "kWh/km" : "L/100km"}</td>
              <td className="num">{fmt.num(R.B.ecNum)} {vB.powertrain === "EV" ? "kWh/km" : "L/100km"}</td></tr>
            <tr><td className="lbl">{L("Emission Factor", "Faktor Emisi")}</td>
              <td className="num">{vA.powertrain === "EV" ? `${fmt.num(window.CO2.grid_kg_per_kwh)} kgCO2/kWh` : `${fmt.num(window.CO2.diesel_kg_per_liter)} kgCO2/L`}
                <SourceTag source="research" note={vA.powertrain === "EV"
                  ? L("Indonesia national grid average, 2023 (Ember/Statista).", "Rata-rata jaringan listrik nasional Indonesia, 2023 (Ember/Statista).")
                  : L("Well-to-wheel: 2.56 kgCO2/L tank-to-wheel (combustion) + 0.61 kgCO2/L well-to-tank (extraction/refining/transport).", "Well-to-wheel: 2,56 kgCO2/L tank-to-wheel (pembakaran) + 0,61 kgCO2/L well-to-tank (ekstraksi/pengilangan/transportasi).")} /></td>
              <td className="num">{vB.powertrain === "EV" ? `${fmt.num(window.CO2.grid_kg_per_kwh)} kgCO2/kWh` : `${fmt.num(window.CO2.diesel_kg_per_liter)} kgCO2/L`}
                <SourceTag source="research" note={vB.powertrain === "EV"
                  ? L("Indonesia national grid average, 2023 (Ember/Statista).", "Rata-rata jaringan listrik nasional Indonesia, 2023 (Ember/Statista).")
                  : L("Well-to-wheel: 2.56 kgCO2/L tank-to-wheel (combustion) + 0.61 kgCO2/L well-to-tank (extraction/refining/transport).", "Well-to-wheel: 2,56 kgCO2/L tank-to-wheel (pembakaran) + 0,61 kgCO2/L well-to-tank (ekstraksi/pengilangan/transportasi).")} /></td></tr>
            <tr><td className="lbl">{L("Annual CO2 (fleet)", "CO2 Tahunan (armada)")}</td>
              <td className="num">{fmt.num(Math.round(R.co2A / (s.horizon || 1)))} t</td>
              <td className="num">{fmt.num(Math.round(R.co2B / (s.horizon || 1)))} t</td></tr>
            <tr className="total"><td className="lbl">{L("Lifetime Operational CO2", "CO2 Operasional Seumur Hidup")}</td>
              <td className="num">{fmt.num(Math.round(R.co2A))} t</td>
              <td className="num">{fmt.num(Math.round(R.co2B))} t</td></tr>
            {s.includeEmbodiedCo2 && (<>
              <tr><td className="lbl">{L("Battery Capacity", "Kapasitas Baterai")}</td>
                <td className="num">{vA.powertrain === "EV" ? `${fmt.num(vA.batteryKwh)} kWh` : "—"}</td>
                <td className="num">{vB.powertrain === "EV" ? `${fmt.num(vB.batteryKwh)} kWh` : "—"}</td></tr>
              <tr><td className="lbl">{L("Embodied Mfg. CO2 (one-time)", "CO2 Manufaktur Tertanam (satu kali)")}</td>
                <td className="num">{R.A.embodiedCo2 == null
                  ? <span title={L("Not modeled — no reliable per-vehicle default exists for ICE manufacturing CO2 in this catalog.", "Tidak dimodelkan — tidak ada default per-kendaraan yang andal untuk CO2 manufaktur ICE di katalog ini.")}>{L("not modeled", "tidak dimodelkan")}</span>
                  : `${fmt.num(Math.round(R.A.embodiedCo2))} t`}</td>
                <td className="num">{R.B.embodiedCo2 == null
                  ? <span title={L("Not modeled — no reliable per-vehicle default exists for ICE manufacturing CO2 in this catalog.", "Tidak dimodelkan — tidak ada default per-kendaraan yang andal untuk CO2 manufaktur ICE di katalog ini.")}>{L("not modeled", "tidak dimodelkan")}</span>
                  : `${fmt.num(Math.round(R.B.embodiedCo2))} t`}
                  <SourceTag source="assumption" note={L(`${fmt.num(s.evBatteryMfgCo2PerKwh ?? 74)} kgCO2/kWh, NMC811 cradle-to-gate median (peer-reviewed battery LCA studies) — pending Indonesia-specific battery supply chain data.`, `${fmt.num(s.evBatteryMfgCo2PerKwh ?? 74)} kgCO2/kWh, median cradle-to-gate NMC811 (studi LCA baterai peer-review) — menunggu data rantai pasok baterai spesifik Indonesia.`)} /></td></tr>
              <tr className="total"><td className="lbl">{L("Life-Cycle CO2 (operational + embodied)", "CO2 Siklus Hidup (operasional + tertanam)")}</td>
                <td className="num">{fmt.num(Math.round(R.lifeCycleCo2A))} t</td>
                <td className="num">{fmt.num(Math.round(R.lifeCycleCo2B))} t</td></tr>
              <tr><td className="lbl">{L("Carbon Payback Distance", "Jarak Balik Modal Karbon")}</td>
                <td colSpan={2}>{R.carbonPaybackKm != null
                  ? L(`${fmt.num(Math.round(R.carbonPaybackKm))} km — after this distance, the lower-CO2/km vehicle's operational advantage offsets its embodied manufacturing footprint.`,
                       `${fmt.num(Math.round(R.carbonPaybackKm))} km — setelah jarak ini, keunggulan operasional kendaraan CO2/km lebih rendah mengimbangi jejak manufaktur tertanamnya.`)
                  : L("No payback under these inputs — the EV's operational CO2/km is not lower than the ICE's, so its embodied manufacturing footprint is never offset.",
                       "Tidak ada balik modal dengan input ini — CO2/km operasional EV tidak lebih rendah dari ICE, sehingga jejak manufaktur tertanamnya tidak pernah terimbangi.")}</td></tr>
            </>)}
          </tbody>
        </table>
      </div>

      {/* C7: Budget vs. Actual (v1.3, only if budget cap set) — uses Depot Design's total when active */}
      {(depotActive || (sizing && capex)) && s.infraBudgetCap != null && (
        <div className="card" style={{ padding: 18 }}>
          <div className="chart-title" style={{ marginBottom: 12 }}>
            {L("Budget vs. Actual", "Anggaran vs. Realisasi")}
          </div>
          <div className="spec-grid">
            <div className="spec-cell">
              <div className="sk">{L("Infrastructure Budget Cap", "Batas Anggaran Infrastruktur")}</div>
              <div className="sv">{fmt.rp(s.infraBudgetCap)}</div>
            </div>
            <div className="spec-cell">
              <div className="sk">{depotActive ? L("Depot Design CAPEX", "CAPEX Desain Depot") : L("Computed EVCS CAPEX", "CAPEX SPKLU Terhitung")}</div>
              <div className="sv">{fmt.rp(infraGrandTotal)}</div>
            </div>
            <div className="spec-cell">
              <div className="sk">{L("Delta", "Selisih")}</div>
              <div className="sv" style={{ color: infraGrandTotal > s.infraBudgetCap ? "var(--danger)" : "var(--c-accent)" }}>
                {infraGrandTotal > s.infraBudgetCap ? "+" : "−"}{fmt.rpShort(Math.abs(infraGrandTotal - s.infraBudgetCap))}
              </div>
            </div>
            <div className="spec-cell">
              <div className="sk">{L("Status", "Status")}</div>
              <div className="sv">{infraGrandTotal > s.infraBudgetCap
                ? L("⚠ OVER BUDGET", "⚠ MELEBIHI ANGGARAN")
                : L("✅ WITHIN BUDGET", "✅ SESUAI ANGGARAN")}</div>
            </div>
          </div>
        </div>
      )}

      {/* D: Labor disclaimer */}
      <div style={{ marginTop: 12 }} className="audit-caption">
        {L("Scope Note", "Catatan Cakupan")}
        <InfoHint note={L(
          "Labor costs (drivers, technicians, operational staff) are out of scope for this platform, per VKTR team decision, and are not modeled anywhere in this TCO comparison — not assumed to be zero-impact, simply not part of what this analysis covers. The one exception is depot security staffing, a facility cost tracked inside the Depot Design tool (Screen 4 → Depot Design), separate from vehicle operation.",
          "Biaya tenaga kerja (pengemudi, teknisi, dan staf operasional) di luar lingkup platform ini, sesuai keputusan tim VKTR, dan tidak dimodelkan di mana pun dalam perbandingan TCO ini — bukan diasumsikan berdampak nol, memang bukan bagian dari cakupan analisis ini. Satu pengecualian adalah staf keamanan depot, biaya fasilitas yang dilacak di dalam alat Desain Depot (Layar 4 → Desain Depot), terpisah dari operasional kendaraan.")} />
      </div>

      {/* F: Additional metrics */}
      <div className="metrics-row">
        <div className="metric-box">
          <div className="mk">{L("EV Savings IRR", "IRR Penghematan EV")}</div>
          <div className="mv">{irrText}<small>{L("Internal rate of return on incremental EV investment", "Internal rate of return atas investasi tambahan EV")}</small></div>
        </div>
        <div className="metric-box">
          <div className="mk">{L("Carbon Credit Value", "Nilai Kredit Karbon")}</div>
          <div className="mv">{fmt.rpShort(Math.abs(co2Winner) * s.carbon * 1000)}<small>{Math.abs(co2Winner).toLocaleString(locale, { maximumFractionDigits: 1 })} {L("tons", "ton")} × {fmt.rp(s.carbon)}/{L("ton CO₂", "ton CO₂")} ({L(`${winnerName} vs ${loserName}`, `${winnerName} vs ${loserName}`)})</small></div>
        </div>
      </div>

      </div>
      {/* ============== END TAB 2: DETAILS ============== */}

      {/* ============================================================
          TAB 3: CALCULATION STEPS — TCO Stream Map
          ============================================================ */}
      <div className={"report-tab-panel" + (activeTab === 2 ? " active" : "")}>

      {/* F3: TCO Stream Map — click-through calculation audit trail (v1.4) */}
      <div className="card" style={{ padding: 18 }}>
        <div className="chart-title" style={{ marginBottom: 12 }}>
          {L("TCO Stream Map", "Peta Aliran TCO")}
          <InfoHint note={L(
            "Click a phase to drill into its calculation steps, then click a step to see the formula, live values for both vehicles, and (with Expert Mode) the variable definitions and audit source.",
            "Klik sebuah fase untuk melihat langkah-langkah kalkulasinya, lalu klik sebuah langkah untuk melihat formula, nilai langsung kedua kendaraan, dan (dengan Mode Ahli) definisi variabel serta sumber audit.")} />
        </div>
        <StreamMap s={s} set={set} R={R} sizing={sizing} capex={capex} vA={vA} vB={vB} lang={lang} />
      </div>

      </div>
      {/* ============== END TAB 3: CALCULATION STEPS ============== */}

      {/* H: ⚠ Estimasi footnote — print/PDF only when placeholder vehicle selected */}
      {hasEstimasi && (
        <div className="estimasi-footnote">
          <Tr
            en="* Data marked ⚠ Estimasi are segment estimates pending OEM confirmation. Actual figures may differ."
            id="* Data yang ditandai ⚠ Estimasi adalah perkiraan berdasarkan segmen kendaraan dan belum dikonfirmasi oleh OEM. Angka aktual dapat berbeda." />
        </div>
      )}

      {/* I: Actions */}
      <div className="report-actions">
        <label className="inc-toggle">
          <input type="checkbox" checked={includeInputs} onChange={e => setIncludeInputs(e.target.checked)} />
          {L("Include input summary (Profile → Financials)", "Sertakan ringkasan input (Profil → Keuangan)")}
        </label>
        <div className="ra-spacer" />
        <button className="btn btn-ghost" onClick={doPrint}>🖨 {L("Print", "Cetak")}</button>
        <button className="btn btn-accent" onClick={doPrint}>📄 {L("Export PDF (A4)", "Ekspor PDF (A4)")}</button>
      </div>

    </div>
   </React.Fragment>
  );
}

Object.assign(window, { Screen6 });
