/* global React */
/* ===========================================================
   VOLTLAB · SPDA — Dimensionamento Completo
   ABNT NBR 5419:2026 (Partes 1, 2, 3 e 4)

   Aba 1 · Análise de Risco        (Parte 2)
   Aba 2 · SPDA Externo            (Parte 3)
   Aba 3 · SPDA Interno / MPS/DPS  (Parte 4)
=========================================================== */
const { useState, useMemo, useEffect } = React;

const usePersist = (key, init) =>
  window.useLocalStorage ? window.useLocalStorage(key, init) : React.useState(init);

/* ─── UI atoms (re-exposed locally so this file is standalone) ─── */
const RIcon = ({ n, sz = 16 }) => {
  const p = { width: sz, height: sz, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round" };
  const paths = {
    ok:   <polyline points="20 6 9 17 4 12"/>,
    warn: <><path d="M10.3 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></>,
    info: <><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></>,
    bolt: <path d="M13 2L4 14h7l-2 8 9-12h-7z"/>,
    shield: <><path d="M12 2l8 4v6c0 5-3.5 8.5-8 10-4.5-1.5-8-5-8-10V6z"/><path d="M9 12l2 2 4-4"/></>,
    zap: <path d="M13 2L4 14h7l-2 8 9-12h-7z"/>,
  };
  return <svg {...p}>{paths[n]}</svg>;
};

/* ─── Design-system components ──────────────────────────────── */
function FieldBlock({ label, hint, children }) {
  return (
    <div className="vl-field">
      <label className="vl-field-label">
        <span>{label}</span>
        {hint && <span className="vl-field-hint">{hint}</span>}
      </label>
      {children}
    </div>
  );
}

function NumberInput({ value, onChange, suffix, step, min }) {
  return (
    <div className="vl-input">
      <input type="number" value={value}
        onChange={e => onChange(e.target.value)}
        step={step ?? "0.1"} min={min ?? "0"}/>
      {suffix && <span className="vl-input-suffix">{suffix}</span>}
    </div>
  );
}

function Seg({ value, onChange, options }) {
  return (
    <div className="seg">
      {options.map(o => (
        <button key={o.value}
          className={value === o.value ? "is-active" : ""}
          onClick={() => onChange(o.value)}>
          {o.label}
        </button>
      ))}
    </div>
  );
}

function ResultBig({ label, value, unit, status }) {
  return (
    <div className={"vl-result-big " + (status ? "vl-result-" + status : "")}>
      <div className="vl-result-corner vl-result-corner-tl"/>
      <div className="vl-result-corner vl-result-corner-tr"/>
      <div className="vl-result-corner vl-result-corner-bl"/>
      <div className="vl-result-corner vl-result-corner-br"/>
      <div className="vl-result-label">{label}</div>
      <div className="vl-result-row">
        <span className="readout vl-result-val">{value}</span>
        <em>{unit}</em>
      </div>
    </div>
  );
}

function MetricCell({ label, value, unit, status }) {
  return (
    <div className={"vl-metric " + (status ? "vl-metric-" + status : "")}>
      <div className="vl-metric-label">{label}</div>
      <div className="vl-metric-value">
        <span className="readout">{value}</span>
        {unit && <em>{unit}</em>}
      </div>
    </div>
  );
}

function StatusBanner({ kind, children }) {
  const icon = kind === "ok" ? "ok" : "warn";
  return (
    <div className={"vl-banner vl-banner-" + kind}>
      <RIcon n={icon} sz={16}/>
      <span>{children}</span>
    </div>
  );
}

function MemoryStep({ n, title, isFormula, children }) {
  return (
    <div className="vl-mem-step">
      <div className="vl-mem-step-head">
        <span className="vl-mem-step-n">{String(n).padStart(2, "0")}</span>
        <span className="vl-mem-step-title">{title}</span>
      </div>
      <div className={"vl-mem-step-body " + (isFormula ? "is-formula" : "")}>{children}</div>
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════════
   TABELAS NORMATIVAS EMBUTIDAS
   Fonte: ABNT NBR 5419-2:2026 e NBR 5419-3:2026
════════════════════════════════════════════════════════════════ */

/* Tabela 4 / NBR 5419-2 — Risco Tolerável */
const RT = { R1: 1e-5, R3: 1e-4 };

/* Tabela A.1 — Fator de localização CD */
const TAB_CD = [
  { value: "0.25", label: "Rodeada por objetos mais altos" },
  { value: "0.5",  label: "Rodeada por objetos da mesma altura" },
  { value: "1",    label: "Estrutura isolada" },
  { value: "2",    label: "Isolada no topo de colina/morro" },
];

/* Tabela A.2 — Fator de instalação da linha CI */
const TAB_CI = [
  { value: "1",    label: "Aérea" },
  { value: "0.5",  label: "Enterrada" },
  { value: "0.01", label: "Enterrada em malha aterramento" },
];

/* Tabela A.3 — Fator tipo de linha CT */
const TAB_CT = [
  { value: "1",   label: "Energia BT ou sinal" },
  { value: "0.2", label: "Energia AT (com trafo AT/BT)" },
];

/* Tabela A.4 — Fator ambiental CE */
const TAB_CE = [
  { value: "1",    label: "Rural" },
  { value: "0.5",  label: "Suburbano" },
  { value: "0.1",  label: "Urbano" },
  { value: "0.01", label: "Urbano c/ struct. > 20m" },
];

/* Tabela B.1 — PTA (medidas contra tensão toque/passo) */
const TAB_PTA = [
  { value: "1",    label: "Nenhuma medida" },
  { value: "0.1",  label: "Avisos visíveis" },
  { value: "0.01", label: "Isolação elétrica (toque) ou malha equip. solo (passo)" },
  { value: "0.001",label: "Estrutura metálica / concreto armado c/ descida natural" },
];

/* Tabela B.2 — PB: prob. danos físicos por NP */
const TAB_PB = [
  { value: "1",     label: "Sem SPDA" },
  { value: "0.2",   label: "SPDA NP IV" },
  { value: "0.1",   label: "SPDA NP III" },
  { value: "0.05",  label: "SPDA NP II" },
  { value: "0.02",  label: "SPDA NP I" },
  { value: "0.01",  label: "SPDA NP I + descida natural concreto" },
  { value: "0.001", label: "Cobertura metálica natural + descida natural" },
];

/* Tabela B.3 — PSPD */
const TAB_PSPD = [
  { value: "1",    label: "Sem sistema coordenado de DPS" },
  { value: "0.05", label: "DPS NP III-IV" },
  { value: "0.02", label: "DPS NP II" },
  { value: "0.01", label: "DPS NP I" },
];

/* Tabela B.4 — CLD (fator blindagem/aterramento da linha) */
const TAB_CLD = [
  { value: "1",   label: "Linha aérea ou subterr. sem blindagem" },
  { value: "0.5", label: "Linha com neutro multiaterrado" },
  { value: "0.3", label: "Subterr. blindada, blindagem não equip." },
  { value: "0.1", label: "Aérea blindada, blindagem não equip." },
  { value: "0",   label: "Blindagem equip. ao mesmo barramento" },
];

/* Tabela C.2 — Valores típicos LT, LF, LO */
const TAB_LOSSES = {
  "residencial":     { LT: 1e-2, LF: 1e-2,    LO: 1e-3, label: "Residencial / Outros" },
  "industrial":      { LT: 1e-2, LF: 2e-2,    LO: 1e-3, label: "Industrial / Comercial" },
  "publico":         { LT: 1e-2, LF: 5e-2,    LO: 1e-3, label: "Público (igreja, museu, entret.)" },
  "hospital":        { LT: 1e-2, LF: 1e-1,    LO: 1e-2, label: "Hospital / Hotel / Escola / Cívico" },
  "hospital_uti":    { LT: 1e-2, LF: 1e-1,    LO: 1e-2, label: "Hospital (UTI / Bloco cirúrgico)" },
  "explosao":        { LT: 1e-2, LF: 1e-1,    LO: 1e-1, label: "Risco de explosão" },
};

/* Tabela C.3 — Fator rt (tipo de solo/piso) */
const TAB_RT_SOLO = [
  { value: "0.01",    label: "Terra / Concreto" },
  { value: "0.001",   label: "Mármore / Cerâmica" },
  { value: "0.0001",  label: "Brita / Tapete / Carpete" },
  { value: "0.00001", label: "Asfalto / Linóleo / Madeira" },
];

/* Tabela C.4 — Fator rp (combate incêndio) */
const TAB_RP = [
  { value: "1",   label: "Nenhuma providência" },
  { value: "0.5", label: "Extintores / alarme manual / compartimentos" },
  { value: "0.2", label: "Instalações automáticas de supressão ou alarme" },
];

/* Tabela C.5 — Fator rf (risco incêndio/explosão) */
const TAB_RF = [
  { value: "0",    label: "Sem incêndio / sem explosão" },
  { value: "0.001",label: "Risco baixo de incêndio (< 400 MJ/m²)" },
  { value: "0.01", label: "Risco normal de incêndio (400–800 MJ/m²)" },
  { value: "0.1",  label: "Risco alto de incêndio (> 800 MJ/m²) / explosão Zonas 1,21" },
  { value: "1",    label: "Explosão — Zonas 0, 20 e explosivos sólidos" },
];

/* Tabela C.6 — Fator hz (perigo especial) */
const TAB_HZ = [
  { value: "1",  label: "Sem perigo especial" },
  { value: "2",  label: "Baixo pânico (≤ 2 andares, ≤ 100 pessoas)" },
  { value: "5",  label: "Pânico médio (100–1000 pessoas) / Dif. evacuação" },
  { value: "10", label: "Alto pânico (> 1000 pessoas)" },
];

/* Tabela C.7 — Fator rs (tipo estrutura) */
const TAB_RS = [
  { value: "2", label: "Simples (madeira / alvenaria)" },
  { value: "1", label: "Robusta (metálica / concreto armado)" },
];

/* ─── NBR 5419-3: Parâmetros SPDA Externo por NP ─────────────
   Fonte: ABNT NBR 5419-3:2026 (Tabelas 1 e 2)
   r  = raio esfera rolante (m)
   mesh = módulo malha subsistema captação (m)
   angle_10m = ângulo proteção para h=10m (graus)  — franklin
   angle_20m = ângulo para h=20m (graus)
   angle_30m = ângulo para h=30m (graus)
   descidas_max = dist. máx. entre descidas (m)
   aterr_tipo = tipo recomendado eletrodo aterramento
*/
const SPDA_EXT = {
  "I":   { r: 20,  mesh: 5,  angle_10: 75, angle_20: 70, angle_30: 65, descidas_max: 10, label: "Nível I" },
  "II":  { r: 30,  mesh: 10, angle_10: 70, angle_20: 60, angle_30: 55, descidas_max: 10, label: "Nível II" },
  "III": { r: 45,  mesh: 15, angle_10: 60, angle_20: 50, angle_30: 45, descidas_max: 15, label: "Nível III" },
  "IV":  { r: 60,  mesh: 20, angle_10: 50, angle_20: 45, angle_30: 43, descidas_max: 20, label: "Nível IV" },
};

/* ─── Seções mínimas condutores SPDA Externo ────────────────── */
const SECAO_MIN_CAPTACAO = {
  "I":   { Cu: 50, Al: 70, Fe: 50,  label: "Cap." },
  "II":  { Cu: 50, Al: 70, Fe: 50,  label: "Cap." },
  "III": { Cu: 50, Al: 70, Fe: 50,  label: "Cap." },
  "IV":  { Cu: 50, Al: 70, Fe: 50,  label: "Cap." },
};
const SECAO_MIN_DESCIDA = {
  "I":   { Cu: 50, Al: 70, Fe: 50 },
  "II":  { Cu: 50, Al: 70, Fe: 50 },
  "III": { Cu: 25, Al: 35, Fe: 50 },
  "IV":  { Cu: 16, Al: 25, Fe: 50 },
};
const SECAO_MIN_ATERR = {
  "I":   { Cu: 50, Al: 70, Fe: 80 },
  "II":  { Cu: 50, Al: 70, Fe: 80 },
  "III": { Cu: 16, Al: 25, Fe: 50 },
  "IV":  { Cu: 16, Al: 25, Fe: 50 },
};

/* ─── SPDA Interno / DPS ─────────────────────────────────────── */
/* Correntes Iimp mínimas por NP (kA) — classe I (10/350µs)
   Fonte: NBR 5419-1:2026, Anexo B e NBR 5419-4:2026, Anexo C/D
   50% vai pro aterramento, 50% retorna pelas linhas
   Sistema trifásico: Iimp = 50% × Imax / 4 condutores = 12.5% × Imax */
const DPS_DATA = {
  "I":   { Imax: 200, Iimp_classe1: 25, In_classe2: 20, Up_max: 2.5, label: "NP I" },
  "II":  { Imax: 150, Iimp_classe1: 18.75, In_classe2: 15, Up_max: 2.5, label: "NP II" },
  "III": { Imax: 100, Iimp_classe1: 12.5, In_classe2: 10, Up_max: 2.5, label: "NP III/IV" },
  "IV":  { Imax: 100, Iimp_classe1: 12.5, In_classe2: 10, Up_max: 2.5, label: "NP III/IV" },
};

/* ─── Mapa NP → Classe visual ───────────────────────────────── */
const NP_LABEL = { "I": "Classe I", "II": "Classe II", "III": "Classe III", "IV": "Classe IV" };
const NP_COLOR = { "I": "danger", "II": "warn", "III": "warn", "IV": "ok" };

/* ═══════════════════════════════════════════════════════════════
   TABELAS DE PROJETO — DIMENSIONAMENTO SPDA
════════════════════════════════════════════════════════════════ */

/* Tabela B.2 → PB por NP (para iteração automática do nível) */
const PB_POR_NP = { "IV": 0.2, "III": 0.1, "II": 0.05, "I": 0.02 };
/* Tabela B.3 → PSPD recomendado por NP */
const PSPD_POR_NP = { "IV": 0.05, "III": 0.05, "II": 0.02, "I": 0.01 };

/* Tabela 7 NBR 5419-3 — Coeficiente ki para distância de segurança s */
const KI_POR_NP = { "I": 0.08, "II": 0.06, "III": 0.04, "IV": 0.04 };

/* Coeficiente km — material da separação (NBR 5419-3 Tab. 6) */
const TAB_KM = [
  { value: "1",   label: "Ar" },
  { value: "0.5", label: "Concreto / alvenaria" },
];

/* Tipo de cobertura (define captação preferencial) */
const TAB_COBERTURA = [
  { value: "plana",     label: "Plana (malha)" },
  { value: "inclinada", label: "Inclinada (cumeeira+beiral)" },
  { value: "metalica",  label: "Metálica (natural)" },
];

/* Tipo de eletrodo de aterramento (override do usuário) */
const TAB_TIPO_ATERR = [
  { value: "A", label: "Tipo A — hastes/radiais" },
  { value: "B", label: "Tipo B — anel/malha" },
];

/* Categoria de instalação (Uw) — IEC 60364-4-44 */
const TAB_UW = [
  { value: "1.5", label: "Cat. I (1,5 kV) — eletrônico" },
  { value: "2.5", label: "Cat. II (2,5 kV) — eletrodomést." },
  { value: "4.0", label: "Cat. III (4,0 kV) — QGBT" },
  { value: "6.0", label: "Cat. IV (6,0 kV) — entrada" },
];

/* Comprimento mínimo l1 da haste (Tipo A) — Fig. 3 NBR 5419-3:2026
   Interpolação linear sobre a curva. ρ em Ω·m → l1 em m. */
function calcL1Haste(NP, rho) {
  if (rho <= 500) return 5;
  if (NP === "III" || NP === "IV") return 5;
  if (NP === "II") {
    if (rho <= 1500) return 5 + (rho - 500) * 5 / 1000;
    if (rho <= 2500) return 10 + (rho - 1500) * 10 / 1000;
    return 20 + (rho - 2500) * 10 / 500;
  }
  // NP I
  if (rho <= 1000) return 5 + (rho - 500) * 5 / 500;
  if (rho <= 2000) return 10 + (rho - 1000) * 20 / 1000;
  return 30 + (rho - 2000) * 40 / 1000;
}

/* Raio médio re do eletrodo Tipo B — Fig. 3 NBR 5419-3:2026 */
function calcReAnel(NP, rho) {
  if (rho <= 500) return 5;
  if (NP === "III" || NP === "IV") return 5;
  if (NP === "II") {
    if (rho <= 1000) return 5 + (rho - 500) * 3 / 500;
    if (rho <= 2000) return 8 + (rho - 1000) * 7 / 1000;
    return 15 + (rho - 2000) * 9 / 1000;
  }
  // NP I
  if (rho <= 1000) return 5 + (rho - 500) * 7 / 500;
  if (rho <= 2000) return 12 + (rho - 1000) * 21 / 1000;
  return 33 + (rho - 2000) * 47 / 1000;
}

/* ═══════════════════════════════════════════════════════════════
   MOTOR DE CÁLCULO CENTRAL — tudo via useMemo
════════════════════════════════════════════════════════════════ */
function calcularSPDA(inp) {
  /* ──── 1. Geometria ────────────────────────────────────────── */
  const L = parseFloat(inp.L) || 0;
  const W = parseFloat(inp.W) || 0;
  const H = parseFloat(inp.H) || 0;
  if (L <= 0 || W <= 0 || H <= 0) return null;

  /* ──── 2. Áreas de exposição (Anexo A NBR 5419-2:2026) ────── */
  const H3 = 3 * H;
  const AD = L * W + 2 * H3 * (L + W) + Math.PI * H3 * H3;
  const AM = 2 * 500 * (L + W) + Math.PI * 500 * 500;
  const LL = parseFloat(inp.LL) || 1000;
  const AL = 40 * LL;
  const AI = 4000 * LL;

  /* ──── 3. Eventos perigosos N (Eqs. A.3–A.10) ─────────────── */
  const NG = parseFloat(inp.NG) || 0;
  const CD = parseFloat(inp.CD) || 1;
  const CI = parseFloat(inp.CI) || 1;
  const CT = parseFloat(inp.CT) || 1;
  const CE = parseFloat(inp.CE) || 1;
  const ND = NG * AD * CD * 1e-6;
  const NM = NG * AM * 1e-6;
  const NL = NG * AL * CI * CT * CE * 1e-6;
  const NI = NG * AI * CI * CT * CE * 1e-6;

  /* ──── 4. Inputs de probabilidade / perdas ─────────────────── */
  const PTA = parseFloat(inp.PTA) || 1;
  const PB_user = parseFloat(inp.PB) || 1;
  const PSPD_user = parseFloat(inp.PSPD) || 1;
  const CLD = parseFloat(inp.CLD) || 1;

  const tipoEst = inp.tipoEst || "residencial";
  const losses = TAB_LOSSES[tipoEst] || TAB_LOSSES["residencial"];
  const rt = parseFloat(inp.rt) || 0.01;
  const rp = parseFloat(inp.rp) || 1;
  const rf = parseFloat(inp.rf) || 0.01;
  const hz = parseFloat(inp.hz) || 1;
  const rs = parseFloat(inp.rs) || 1;
  const nz_nt = parseFloat(inp.nz_nt) || 1;
  const tz_h = parseFloat(inp.tz_h) || 8760;
  const f_occ = nz_nt * (tz_h / 8760);

  const LA = rt * losses.LT * f_occ * rs;
  const LB = rp * rf * hz * losses.LF * f_occ * rs;
  const LC = losses.LO * f_occ * rs;
  const LU = rt * losses.LT * f_occ * rs;
  const LV = rp * rf * hz * losses.LF * f_occ * rs;
  const LW = losses.LO * f_occ * rs;
  const LM = losses.LO * f_occ * rs;
  const LZ = losses.LO * f_occ * rs;

  /* ──── 5. Função para calcular R1/R3 dado PB e PSPD ─────────── */
  const calcRisks = (PB, PSPD) => {
    const PA = PTA * PB;
    const PC = PSPD * CLD;
    const PM = PSPD;
    const PU = PTA;
    const PV = PB;
    const PW = PSPD * CLD;
    const PZ = PSPD;
    const RA = ND * PA * LA;
    const RB = ND * PB * LB;
    const RC = ND * PC * LC;
    const RM = NM * PM * LM;
    const RU = NL * PU * LU;
    const RV = NL * PV * LV;
    const RW = NL * PW * LW;
    const RZ = NI * PZ * LZ;
    const R1 = RA + RB + RC + RM + RU + RV + RW + RZ;
    const R3 = RB + RV;
    return { PA, PB, PC, PM, PU, PV, PW, PZ, RA, RB, RC, RM, RU, RV, RW, RZ, R1, R3 };
  };

  /* ──── 6. Risco com proteção atual informada pelo usuário ──── */
  const atual = calcRisks(PB_user, PSPD_user);
  const needsSpda = atual.R1 > RT.R1 || atual.R3 > RT.R3;

  /* ──── 7. ITERAÇÃO DO NP (NBR 5419-2 §5.5) ──────────────────
     Tenta NP IV → III → II → I até R1 ≤ RT1 e R3 ≤ RT3.       */
  let NP = null, recom = null;
  if (needsSpda) {
    for (const np of ["IV", "III", "II", "I"]) {
      const tentativa = calcRisks(PB_POR_NP[np], PSPD_POR_NP[np]);
      if (tentativa.R1 <= RT.R1 && tentativa.R3 <= RT.R3) {
        NP = np;
        recom = tentativa;
        break;
      }
    }
    if (!NP) {  // Mesmo NP I + medidas máximas não basta
      NP = "I";
      recom = calcRisks(0.001, 0.01);  // SPDA NP I + cobertura natural + DPS NP I
    }
  }

  /* ──── 8. SPDA EXTERNO — Parâmetros NBR 5419-3:2026 ────────── */
  const ext = NP ? SPDA_EXT[NP] : null;
  let perimetro = 0, nDescidas = 0, espDescidas = 0;
  if (ext) {
    perimetro = 2 * (L + W);
    espDescidas = ext.descidas_max;
    /* NBR 5419-3 §5.3.5: mínimo 2 descidas em qualquer NP */
    nDescidas = Math.max(2, Math.ceil(perimetro / espDescidas));
  }

  /* ──── 9. DIMENSIONAMENTO DA CAPTAÇÃO ───────────────────────
     Malha sobre toda a cobertura (método mais comum):
     n_linhas_X = ceil(W/malha)+1, n_linhas_Y = ceil(L/malha)+1
     L_malha = n_linhas_X × L + n_linhas_Y × W                  */
  const cobertura = inp.cobertura || "plana";
  const malhaSize = ext ? ext.mesh : 0;
  let nLinX = 0, nLinY = 0, LMalha = 0;
  if (ext) {
    nLinX = Math.ceil(W / malhaSize) + 1;
    nLinY = Math.ceil(L / malhaSize) + 1;
    LMalha = nLinX * L + nLinY * W;
  }
  /* Comprimento de descidas (H + 1m de conexão ao aterramento) */
  const LDesc = ext ? nDescidas * (H + 1) : 0;
  const LCaboTotal = LMalha + LDesc;

  /* ──── 10. ATERRAMENTO ────────────────────────────────────── */
  const rho = parseFloat(inp.rho_solo) || 300;
  /* NP I e II → Tipo B obrigatório; NP III/IV pode ser A ou B */
  const tipoAterrUser = inp.tipoAterr || "B";
  const tipoAterr = (NP === "I" || NP === "II") ? "B" : tipoAterrUser;
  const areaTopo = L * W;
  const reCalc = Math.sqrt(areaTopo / Math.PI);  // raio equivalente da estrutura
  let l1_haste = 0, reReq = 0, anelL = 0, hastesAdicionais = 0;
  if (ext) {
    if (tipoAterr === "A") {
      l1_haste = calcL1Haste(NP, rho);
    } else {
      reReq = calcReAnel(NP, rho);
      anelL = perimetro + 8;  // anel 1m afastado da estrutura
      if (reReq > reCalc) {
        const extra = reReq - reCalc;
        hastesAdicionais = Math.max(2, Math.ceil(extra / 5));
      }
    }
  }

  /* ──── 11. DISTÂNCIA DE SEGURANÇA s (Eq. NBR 5419-3 §6.3) ───
     s = ki × kc × L / km
     kc simplificado para malha + anel: kc ≈ 1/n + 0,1          */
  const km = parseFloat(inp.km) || 1;
  const ki = NP ? KI_POR_NP[NP] : 0;
  const kc = ext ? Math.max(0.1, 1 / nDescidas + 0.1) : 0;
  const s = ext ? (ki * kc * H) / km : 0;

  /* ──── 12. SPDA INTERNO / DPS ─────────────────────────────── */
  const dps = NP ? DPS_DATA[NP] : null;
  const Uw = parseFloat(inp.Uw) || 2.5;
  const Lcabo = parseFloat(inp.Lcabo) || 5;
  /* Tensão efetiva no equipamento considerando indução nos cabos:
     Lcabo ≤ 10m: Up_ef ≈ Up × (1 + Lcabo/20)
     Lcabo > 10m: oscilação dobra → Up_ef ≈ 2 × Up              */
  const Up_dps = dps ? dps.Up_max : 2.5;
  const Up_ef = Lcabo > 10 ? Up_dps * 2 : Up_dps * (1 + Lcabo / 20);
  const dpsOk = Up_ef <= Uw;

  /* ZPR */
  const zpr = {
    ZPR0: "Exterior (sem proteção)",
    ZPR1: "Interior — SPDA externo como fronteira",
    ZPR2: "Sala/ambiente interno — blindagem (malha ≤ 5m)",
    ZPR3: "Equipamento / rack — gabinete blindado",
  };

  return {
    /* Áreas e eventos */
    AD, AM, AL, AI, ND, NM, NL, NI,
    LA, LB, LC, LU, LV, LW, LM, LZ,
    /* Análise de risco — estado atual e recomendado */
    atual, recom, needsSpda, NP,
    PA: atual.PA, PB: PB_user, PC: atual.PC, PM: atual.PM,
    PU: atual.PU, PV: atual.PV, PW: atual.PW, PZ: atual.PZ,
    RA: atual.RA, RB: atual.RB, RC: atual.RC, RM: atual.RM,
    RU: atual.RU, RV: atual.RV, RW: atual.RW, RZ: atual.RZ,
    R1: atual.R1, R3: atual.R3,
    /* SPDA Externo — parâmetros + projeto */
    ext, perimetro, nDescidas, espDescidas,
    rEsfera: ext ? ext.r : null, malha: malhaSize,
    ang10: ext ? ext.angle_10 : null,
    ang20: ext ? ext.angle_20 : null,
    ang30: ext ? ext.angle_30 : null,
    cobertura, nLinX, nLinY, LMalha, LDesc, LCaboTotal,
    /* Aterramento */
    tipoAterr, rho, l1_haste, reCalc, reReq, anelL, hastesAdicionais,
    /* Distância de segurança */
    s, ki, kc, km,
    /* SPDA Interno / DPS */
    dps, zpr, Uw, Lcabo, Up_dps, Up_ef, dpsOk,
    /* Inputs espelhados para memória de cálculo */
    L, W, H, NG, CD, LL, H3,
  };
}

/* ═══════════════════════════════════════════════════════════════
   COMPONENTE PRINCIPAL
════════════════════════════════════════════════════════════════ */
function SPDA() {
  const [tab, setTab] = useState("risco");

  /* ─── Aba 1: Dados da Estrutura ──────────────────────────── */
  const [L, setL]     = usePersist("vl_spda_L", "30");
  const [W, setW]     = usePersist("vl_spda_W", "20");
  const [H, setH]     = usePersist("vl_spda_H", "10");
  const [NG, setNG]   = usePersist("vl_spda_NG", "5");
  const [CD, setCD]   = usePersist("vl_spda_CD", "1");
  const [LL, setLL]   = usePersist("vl_spda_LL", "500");
  const [CI, setCI]   = usePersist("vl_spda_CI", "1");
  const [CT, setCT]   = usePersist("vl_spda_CT", "1");
  const [CE, setCE]   = usePersist("vl_spda_CE", "0.5");

  /* ─── Aba 1: Probabilidades ──────────────────────────────── */
  const [PTA,  setPTA]  = usePersist("vl_spda_PTA",  "1");
  const [PB,   setPB]   = usePersist("vl_spda_PB",   "1");
  const [PSPD, setPSPD] = usePersist("vl_spda_PSPD", "1");
  const [CLD,  setCLD]  = usePersist("vl_spda_CLD",  "1");

  /* ─── Aba 1: Perdas ─────────────────────────────────────── */
  const [tipoEst, setTipoEst] = usePersist("vl_spda_tipo", "residencial");
  const [rt,  setRt]  = usePersist("vl_spda_rt",  "0.01");
  const [rp,  setRp]  = usePersist("vl_spda_rp",  "1");
  const [rf,  setRf]  = usePersist("vl_spda_rf",  "0.01");
  const [hz,  setHz]  = usePersist("vl_spda_hz",  "1");
  const [rs,  setRs]  = usePersist("vl_spda_rs",  "1");
  const [nz_nt, setNzNt] = usePersist("vl_spda_nznt", "1");
  const [tz_h,  setTzH]  = usePersist("vl_spda_tzh",  "8760");

  /* ─── Aba 2: Inputs de Projeto (SPDA Externo) ──────────── */
  const [rho_solo, setRhoSolo]   = usePersist("vl_spda_rho",    "300");
  const [cobertura, setCobertura] = usePersist("vl_spda_cobert", "plana");
  const [tipoAterr, setTipoAterr] = usePersist("vl_spda_taterr", "B");
  const [km, setKm]               = usePersist("vl_spda_km",     "1");

  /* ─── Aba 3: Inputs de Projeto (SPDA Interno / DPS) ───── */
  const [Uw, setUw]       = usePersist("vl_spda_Uw",    "2.5");
  const [Lcabo, setLcabo] = usePersist("vl_spda_Lcabo", "5");

  /* ─── Motor ─────────────────────────────────────────────── */
  const inp = { L, W, H, NG, CD, LL, CI, CT, CE, PTA, PB, PSPD, CLD,
    tipoEst, rt, rp, rf, hz, rs, nz_nt, tz_h,
    rho_solo, cobertura, tipoAterr, km, Uw, Lcabo };
  const calc = useMemo(() => calcularSPDA(inp), [
    L, W, H, NG, CD, LL, CI, CT, CE, PTA, PB, PSPD, CLD,
    tipoEst, rt, rp, rf, hz, rs, nz_nt, tz_h,
    rho_solo, cobertura, tipoAterr, km, Uw, Lcabo
  ]);

  /* ─── Export hook ───────────────────────────────────────── */
  useEffect(() => {
    window._VL_lastExport = () => calc ? ({
      modulo: "spda-nbr5419-2026",
      norma: "ABNT NBR 5419:2026 (Partes 1–4)",
      geradoEm: new Date().toLocaleString("pt-BR"),
      entradas: {
        comprimento_m: L, largura_m: W, altura_m: H,
        densidade_ng: NG, fator_cd: CD, comprimento_linha_m: LL,
        tipo_estrutura: tipoEst,
        resistividade_solo: rho_solo, tipo_cobertura: cobertura,
        tipo_aterramento: tipoAterr, material_separacao_km: km,
        uw_equipamento_kV: Uw, distancia_dps_equip_m: Lcabo,
      },
      resultado: {
        R1: calc.R1.toExponential(2), R3: calc.R3.toExponential(2),
        RT1: "1e-5", RT3: "1e-4",
        necessita_spda: calc.needsSpda,
        nivel_protecao: calc.NP || "—",
        R1_recomendado: calc.recom ? calc.recom.R1.toExponential(2) : "—",
      },
      spda_externo: calc.ext ? {
        raio_esfera_m: calc.rEsfera,
        malha: `${calc.malha}×${calc.malha} m`,
        n_descidas: calc.nDescidas,
        esp_max_descidas_m: calc.espDescidas,
        L_malha_captacao_m: calc.LMalha.toFixed(1),
        L_descidas_m: calc.LDesc.toFixed(1),
        L_cabo_total_m: calc.LCaboTotal.toFixed(1),
        tipo_aterramento: calc.tipoAterr,
        l1_haste_m: calc.tipoAterr === "A" ? calc.l1_haste.toFixed(1) : "—",
        anel_perimetro_m: calc.tipoAterr === "B" ? calc.anelL.toFixed(1) : "—",
        re_requerido_m: calc.reReq ? calc.reReq.toFixed(1) : "—",
        hastes_adicionais: calc.hastesAdicionais,
        distancia_seguranca_s_m: calc.s.toFixed(3),
      } : null,
      spda_interno: calc.dps ? {
        iimp_kA: calc.dps.Iimp_classe1,
        in_classe2_kA: calc.dps.In_classe2,
        up_max_kV: calc.dps.Up_max,
        up_efetivo_kV: calc.Up_ef.toFixed(2),
        uw_equipamento_kV: calc.Uw,
        coordenacao_ok: calc.dpsOk,
      } : null,
    }) : null;
    return () => { window._VL_lastExport = null; };
  }, [calc]);

  const fmt = (v, digits = 2) => {
    if (!isFinite(v) || v === 0) return "0,00";
    if (Math.abs(v) < 1e-3) return v.toExponential(2);
    return v.toFixed(digits).replace(".", ",");
  };
  const fmtExp = (v) => v.toExponential(2).replace("e-", "×10⁻").replace("e+", "×10⁺");

  const tabList = [
    { id: "risco",   label: "① Análise de Risco", eyebrow: "PARTES 1 & 2" },
    { id: "externo", label: "② SPDA Externo",      eyebrow: "PARTE 3" },
    { id: "interno", label: "③ SPDA Interno / DPS",eyebrow: "PARTE 4" },
  ];

  const npStatus = calc?.NP ? NP_COLOR[calc.NP] : "ok";

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--gap-grid,20px)" }}>

      {/* ── Tabs ────────────────────────────────────────────── */}
      <div style={{ display: "flex", gap: 4, background: "var(--bg-0)", padding: 4, borderRadius: 10, border: "1px solid var(--border)" }}>
        {tabList.map(t => (
          <button key={t.id} onClick={() => setTab(t.id)}
            style={{
              flex: 1, padding: "10px 8px", borderRadius: 7, cursor: "pointer", transition: "all .18s",
              border: "1px solid transparent",
              background: tab === t.id ? "var(--accent-soft)" : "transparent",
              borderColor: tab === t.id ? "oklch(72% 0.18 245 / 0.3)" : "transparent",
              color: tab === t.id ? "var(--accent)" : "var(--fg-mute)",
            }}>
            <div style={{ fontFamily: "var(--ff-mono)", fontSize: 9, letterSpacing: "0.12em", textTransform: "uppercase", marginBottom: 2, color: tab === t.id ? "var(--accent)" : "var(--fg-faint)" }}>{t.eyebrow}</div>
            <div style={{ fontSize: 13, fontWeight: 600 }}>{t.label}</div>
          </button>
        ))}
      </div>

      {/* ══════════════════════════════════════════════════════
          ABA 1 — ANÁLISE DE RISCO (NBR 5419-2)
         ══════════════════════════════════════════════════════ */}
      {tab === "risco" && (
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "var(--gap-grid,20px)", alignItems: "start" }}>

          {/* COLUNA ESQUERDA: Entradas */}
          <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>

            {/* Dimensões */}
            <div className="panel">
              <div className="panel-head">
                <div><div className="panel-eyebrow">GEOMETRIA DA ESTRUTURA · NBR 5419-2 ANEXO A</div><h3>Dimensões</h3></div>
              </div>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12 }}>
                <FieldBlock label="Comprimento L">
                  <NumberInput value={L} onChange={setL} suffix="m" step="0.5" min="1"/>
                </FieldBlock>
                <FieldBlock label="Largura W">
                  <NumberInput value={W} onChange={setW} suffix="m" step="0.5" min="1"/>
                </FieldBlock>
                <FieldBlock label="Altura H">
                  <NumberInput value={H} onChange={setH} suffix="m" step="0.5" min="1"/>
                </FieldBlock>
              </div>
              <FieldBlock label="Densidade de descargas NG" hint="Tabela F.1 — ver mapa municipal">
                <NumberInput value={NG} onChange={setNG} suffix="raios/km²/ano" step="0.5" min="0.1"/>
              </FieldBlock>
              <FieldBlock label="Fator de localização CD" hint="Tabela A.1">
                <Seg value={CD} onChange={setCD} options={TAB_CD}/>
              </FieldBlock>
            </div>

            {/* Linha Elétrica */}
            <div className="panel">
              <div className="panel-head">
                <div><div className="panel-eyebrow">LINHA ELÉTRICA CONECTADA · FONTES S3 E S4</div><h3>Parâmetros da linha</h3></div>
              </div>
              <FieldBlock label="Comprimento do trecho LL" hint="≤ 1000 m (usar 1000 m se desconhecido)">
                <NumberInput value={LL} onChange={setLL} suffix="m" step="50" min="0"/>
              </FieldBlock>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
                <FieldBlock label="Instalação CI" hint="Tabela A.2">
                  <Seg value={CI} onChange={setCI} options={TAB_CI}/>
                </FieldBlock>
                <FieldBlock label="Tipo CT" hint="Tabela A.3">
                  <Seg value={CT} onChange={setCT} options={TAB_CT}/>
                </FieldBlock>
              </div>
              <FieldBlock label="Ambiente CE" hint="Tabela A.4">
                <Seg value={CE} onChange={setCE} options={TAB_CE}/>
              </FieldBlock>
            </div>

            {/* Probabilidades */}
            <div className="panel">
              <div className="panel-head">
                <div><div className="panel-eyebrow">PROBABILIDADES DE DANOS · ANEXO B</div><h3>Medidas de proteção existentes</h3></div>
              </div>
              <FieldBlock label="Proteção contra tensões toque/passo PTA" hint="Tabela B.1">
                <Seg value={PTA} onChange={setPTA} options={TAB_PTA}/>
              </FieldBlock>
              <FieldBlock label="SPDA (prob. danos físicos PB)" hint="Tabela B.2">
                <Seg value={PB} onChange={setPB} options={TAB_PB}/>
              </FieldBlock>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
                <FieldBlock label="DPS coordenado PSPD" hint="Tabela B.3">
                  <Seg value={PSPD} onChange={setPSPD} options={TAB_PSPD}/>
                </FieldBlock>
                <FieldBlock label="Blindagem linha CLD" hint="Tabela B.4">
                  <Seg value={CLD} onChange={setCLD} options={TAB_CLD}/>
                </FieldBlock>
              </div>
            </div>

            {/* Perdas */}
            <div className="panel">
              <div className="panel-head">
                <div><div className="panel-eyebrow">FATORES DE PERDA · ANEXO C</div><h3>Características da estrutura</h3></div>
              </div>
              <FieldBlock label="Tipo de estrutura" hint="Define LT, LF, LO — Tabela C.2">
                <Seg value={tipoEst} onChange={setTipoEst} options={
                  Object.entries(TAB_LOSSES).map(([k, v]) => ({ value: k, label: v.label }))
                }/>
              </FieldBlock>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
                <FieldBlock label="Tipo de solo/piso rt" hint="Tabela C.3">
                  <Seg value={rt} onChange={setRt} options={TAB_RT_SOLO}/>
                </FieldBlock>
                <FieldBlock label="Tipo de estrutura rs" hint="Tabela C.7">
                  <Seg value={rs} onChange={setRs} options={TAB_RS}/>
                </FieldBlock>
              </div>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
                <FieldBlock label="Combate a incêndio rp" hint="Tabela C.4">
                  <Seg value={rp} onChange={setRp} options={TAB_RP}/>
                </FieldBlock>
                <FieldBlock label="Risco de incêndio rf" hint="Tabela C.5">
                  <Seg value={rf} onChange={setRf} options={TAB_RF}/>
                </FieldBlock>
              </div>
              <FieldBlock label="Perigo especial hz" hint="Tabela C.6 — pânico, evacuação">
                <Seg value={hz} onChange={setHz} options={TAB_HZ}/>
              </FieldBlock>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
                <FieldBlock label="Fração de pessoas nz/nt" hint="Ex: 0,5 → metade da estrutura ocupada">
                  <NumberInput value={nz_nt} onChange={setNzNt} suffix="" step="0.05" min="0.01"/>
                </FieldBlock>
                <FieldBlock label="Horas de ocupação/ano tz" hint="Máx. 8760 h/ano">
                  <NumberInput value={tz_h} onChange={setTzH} suffix="h/ano" step="100" min="1"/>
                </FieldBlock>
              </div>
            </div>
          </div>

          {/* COLUNA DIREITA: Resultados */}
          <div style={{ display: "flex", flexDirection: "column", gap: 16, position: "sticky", top: 0 }}>

            {!calc && (
              <div className="panel"><StatusBanner kind="info">Preencha as dimensões e NG para calcular.</StatusBanner></div>
            )}

            {calc && (
              <>
                {/* Resultado principal */}
                <div className="panel">
                  <div className="panel-head">
                    <div><div className="panel-eyebrow">RESULTADO PRINCIPAL · R1 e R3</div><h3>Riscos calculados</h3></div>
                  </div>

                  <ResultBig
                    label="RISCO R1 — PERDA DE VIDA HUMANA"
                    value={fmtExp(calc.R1)}
                    unit="ano⁻¹"
                    status={calc.R1 > RT.R1 ? "danger" : "ok"}
                  />
                  <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, marginBottom: 12 }}>
                    <MetricCell label="RT1 (tolerável)" value="10⁻⁵" unit="ano⁻¹" status="ok"/>
                    <MetricCell label="R1 / RT1" value={fmt(calc.R1 / RT.R1, 1) + "×"} status={calc.R1 > RT.R1 ? "danger" : "ok"}/>
                  </div>

                  <ResultBig
                    label="RISCO R3 — PATRIMÔNIO CULTURAL"
                    value={fmtExp(calc.R3)}
                    unit="ano⁻¹"
                    status={calc.R3 > RT.R3 ? "warn" : "ok"}
                  />
                  <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, marginBottom: 12 }}>
                    <MetricCell label="RT3 (tolerável)" value="10⁻⁴" unit="ano⁻¹" status="ok"/>
                    <MetricCell label="R3 / RT3" value={fmt(calc.R3 / RT.R3, 1) + "×"} status={calc.R3 > RT.R3 ? "warn" : "ok"}/>
                  </div>

                  {calc.needsSpda
                    ? <StatusBanner kind="danger">SPDA NECESSÁRIO — R1 ou R3 acima do tolerável (NBR 5419-2, 5.4.4)</StatusBanner>
                    : <StatusBanner kind="ok">Sem necessidade de SPDA — Risco dentro do tolerável (NBR 5419-2, 5.4.3)</StatusBanner>
                  }

                  {calc.NP && (
                    <div style={{ marginTop: 14, padding: "14px 18px", borderRadius: 10, background: "var(--accent-soft)", border: "1px solid oklch(72% 0.18 245/0.3)", textAlign: "center" }}>
                      <div style={{ fontFamily: "var(--ff-mono)", fontSize: 10, letterSpacing: "0.16em", color: "var(--accent)", textTransform: "uppercase", marginBottom: 4 }}>NÍVEL DE PROTEÇÃO RECOMENDADO</div>
                      <div style={{ fontFamily: "var(--ff-display)", fontSize: 32, fontWeight: 700, color: "var(--fg)", letterSpacing: "-0.02em" }}>NP {calc.NP}</div>
                      <div style={{ fontFamily: "var(--ff-mono)", fontSize: 12, color: "var(--fg-mute)", marginTop: 2 }}>{NP_LABEL[calc.NP]} · ABNT NBR 5419</div>
                    </div>
                  )}
                </div>

                {/* Componentes de risco detalhados */}
                <div className="panel">
                  <div className="panel-head">
                    <div><div className="panel-eyebrow">COMPONENTES DE RISCO · TABELA 6</div><h3>Decomposição de R1</h3></div>
                  </div>
                  <div className="vl-mini-grid" style={{ gridTemplateColumns: "1fr 1fr 1fr 1fr" }}>
                    <MetricCell label="RA" value={fmtExp(calc.RA)} status={calc.RA > 0 ? "ok" : undefined}/>
                    <MetricCell label="RB" value={fmtExp(calc.RB)} status={calc.RB > 0 ? "ok" : undefined}/>
                    <MetricCell label="RC" value={fmtExp(calc.RC)} status={calc.RC > 0 ? "ok" : undefined}/>
                    <MetricCell label="RM" value={fmtExp(calc.RM)} status={calc.RM > 0 ? "ok" : undefined}/>
                  </div>
                  <div className="vl-mini-grid" style={{ gridTemplateColumns: "1fr 1fr 1fr 1fr" }}>
                    <MetricCell label="RU" value={fmtExp(calc.RU)} status={calc.RU > 0 ? "ok" : undefined}/>
                    <MetricCell label="RV" value={fmtExp(calc.RV)} status={calc.RV > 0 ? "ok" : undefined}/>
                    <MetricCell label="RW" value={fmtExp(calc.RW)} status={calc.RW > 0 ? "ok" : undefined}/>
                    <MetricCell label="RZ" value={fmtExp(calc.RZ)} status={calc.RZ > 0 ? "ok" : undefined}/>
                  </div>
                </div>

                {/* Número de eventos */}
                <div className="panel">
                  <div className="panel-head">
                    <div><div className="panel-eyebrow">EVENTOS PERIGOSOS / ANO · ANEXO A</div><h3>ND / NM / NL / NI</h3></div>
                  </div>
                  <div className="vl-mini-grid" style={{ gridTemplateColumns: "1fr 1fr" }}>
                    <MetricCell label="ND (raios na estrutura)" value={calc.ND.toExponential(3)} unit="eventos/ano"/>
                    <MetricCell label="NM (raios próx. estrut.)" value={calc.NM.toExponential(3)} unit="eventos/ano"/>
                  </div>
                  <div className="vl-mini-grid" style={{ gridTemplateColumns: "1fr 1fr" }}>
                    <MetricCell label="NL (raios na linha)" value={calc.NL.toExponential(3)} unit="eventos/ano"/>
                    <MetricCell label="NI (raios próx. linha)" value={calc.NI.toExponential(3)} unit="eventos/ano"/>
                  </div>
                </div>

                {/* Memória de cálculo */}
                <div className="panel">
                  <div className="panel-head">
                    <div><div className="panel-eyebrow">MEMÓRIA DE CÁLCULO</div><h3>Passo a passo</h3></div>
                  </div>
                  <div className="vl-memory">
                    <MemoryStep n={1} title="Área de exposição AD" isFormula>
                      AD = L×W + 2×(3H)×(L+W) + π×(3H)² = {calc.L}×{calc.W} + 2×{fmt(calc.H3,1)}×{calc.L+calc.W} + π×{fmt(calc.H3,1)}² = <b className="readout">{fmt(calc.AD,1)} m²</b>
                    </MemoryStep>
                    <MemoryStep n={2} title="Eventos ND" isFormula>
                      ND = NG × AD × CD × 10⁻⁶ = {calc.NG} × {fmt(calc.AD,0)} × {calc.CD} × 10⁻⁶ = <b className="readout">{calc.ND.toExponential(3)}</b>
                    </MemoryStep>
                    <MemoryStep n={3} title="Eventos NL" isFormula>
                      NL = NG × AL × CI × CT × CE × 10⁻⁶ = {calc.NG} × {fmt(calc.AL,0)} × {calc.CI} × {calc.CT} × {calc.CE} × 10⁻⁶ = <b className="readout">{calc.NL.toExponential(3)}</b>
                    </MemoryStep>
                    <MemoryStep n={4} title="Componente RB (maior contribuinte usual)">
                      RB = ND × PB × LB = {calc.ND.toExponential(2)} × {PB} × {fmt(calc.LB,5)} = <b className="readout">{calc.RB.toExponential(2)}</b>
                    </MemoryStep>
                    <MemoryStep n={5} title="Risco total R1">
                      R1 = RA+RB+RC+RM+RU+RV+RW+RZ = <b className="readout">{fmtExp(calc.R1)}</b> {calc.R1 > RT.R1 ? "⚠ > RT1=10⁻⁵" : "✓ ≤ RT1=10⁻⁵"}
                    </MemoryStep>
                  </div>
                </div>
              </>
            )}
          </div>
        </div>
      )}

      {/* ══════════════════════════════════════════════════════
          ABA 2 — SPDA EXTERNO (NBR 5419-3)
         ══════════════════════════════════════════════════════ */}
      {tab === "externo" && (
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "var(--gap-grid,20px)", alignItems: "start" }}>

          {/* COLUNA ESQUERDA: Inputs de projeto + Parâmetros NP */}
          <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>

            {!calc?.NP && (
              <div className="panel">
                <StatusBanner kind="info">Complete a Aba 1 — Análise de Risco para dimensionar o SPDA Externo.</StatusBanner>
              </div>
            )}

            {calc?.NP && (
              <>
                {/* Inputs de projeto */}
                <div className="panel">
                  <div className="panel-head">
                    <div><div className="panel-eyebrow">DADOS DO LOCAL · PROJETO</div><h3>Parâmetros de campo</h3></div>
                  </div>
                  <FieldBlock label="Resistividade do solo ρ" hint="Medir por Wenner — NBR 7117">
                    <NumberInput value={rho_solo} onChange={setRhoSolo} suffix="Ω·m" step="50" min="10"/>
                  </FieldBlock>
                  <FieldBlock label="Tipo de cobertura" hint="Define o método de captação predominante">
                    <Seg value={cobertura} onChange={setCobertura} options={TAB_COBERTURA}/>
                  </FieldBlock>
                  <FieldBlock label="Tipo de eletrodo de aterramento" hint="NP I/II → Tipo B obrigatório">
                    <Seg
                      value={calc.NP === "I" || calc.NP === "II" ? "B" : tipoAterr}
                      onChange={setTipoAterr}
                      options={TAB_TIPO_ATERR}/>
                  </FieldBlock>
                  <FieldBlock label="Material entre SPDA e partes internas (km)" hint="Eq. NBR 5419-3 §6.3">
                    <Seg value={km} onChange={setKm} options={TAB_KM}/>
                  </FieldBlock>
                </div>

                {/* Parâmetros do NP */}
                <div className="panel">
                  <div className="panel-head">
                    <div><div className="panel-eyebrow">NÍVEL DE PROTEÇÃO · NBR 5419-3:2026</div><h3>Parâmetros normativos NP {calc.NP}</h3></div>
                  </div>
                  <div style={{ padding: "14px 0", textAlign: "center", borderBottom: "1px solid var(--border)", marginBottom: 14 }}>
                    <div style={{ fontFamily: "var(--ff-display)", fontSize: 40, fontWeight: 700, color: "var(--fg)", letterSpacing: "-0.03em", lineHeight: 1 }}>NP {calc.NP}</div>
                    <div style={{ fontFamily: "var(--ff-mono)", fontSize: 10, color: "var(--fg-mute)", marginTop: 4 }}>Tabelas 1 e 2 — NBR 5419-3:2026</div>
                  </div>
                  <div className="vl-mini-grid" style={{ gridTemplateColumns: "1fr 1fr 1fr" }}>
                    <MetricCell label="Esfera rolante r" value={calc.rEsfera} unit="m" status="ok"/>
                    <MetricCell label="Malha máx." value={`${calc.malha}×${calc.malha}`} unit="m" status="ok"/>
                    <MetricCell label="Esp. descidas" value={calc.espDescidas} unit="m" status="ok"/>
                  </div>
                  <div className="vl-mini-grid" style={{ gridTemplateColumns: "1fr 1fr 1fr" }}>
                    <MetricCell label="Ângulo h=10m" value={calc.ang10 + "°"} status="ok"/>
                    <MetricCell label="Ângulo h=20m" value={calc.ang20 + "°"} status="ok"/>
                    <MetricCell label="Ângulo h=30m" value={calc.ang30 + "°"} status="ok"/>
                  </div>
                </div>

                {/* Seções mínimas */}
                <div className="panel">
                  <div className="panel-head">
                    <div><div className="panel-eyebrow">SEÇÕES MÍNIMAS · TABELA 6 NBR 5419-3</div><h3>Materiais dos condutores</h3></div>
                  </div>
                  <div style={{ overflowX: "auto", border: "1px solid var(--border)", borderRadius: 8 }}>
                    <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 12 }}>
                      <thead>
                        <tr style={{ background: "var(--bg-0)" }}>
                          {["Subsistema", "Cu (mm²)", "Al (mm²)", "Fe (mm²)"].map(h => (
                            <th key={h} style={{ padding: "8px 12px", textAlign: "left", fontFamily: "var(--ff-mono)", fontSize: 10, color: "var(--fg-mute)", letterSpacing: "0.1em", textTransform: "uppercase", borderBottom: "1px solid var(--border)" }}>{h}</th>
                          ))}
                        </tr>
                      </thead>
                      <tbody>
                        {[
                          { label: "Captação",    s: SECAO_MIN_CAPTACAO[calc.NP] },
                          { label: "Descida",     s: SECAO_MIN_DESCIDA[calc.NP] },
                          { label: "Aterramento", s: SECAO_MIN_ATERR[calc.NP] },
                        ].map(row => (
                          <tr key={row.label} style={{ borderBottom: "1px solid var(--border)" }}>
                            <td className="mono" style={{ padding: "8px 12px", color: "var(--accent)", fontWeight: 600 }}>{row.label}</td>
                            <td className="mono" style={{ padding: "8px 12px" }}>{row.s.Cu}</td>
                            <td className="mono" style={{ padding: "8px 12px" }}>{row.s.Al}</td>
                            <td className="mono" style={{ padding: "8px 12px" }}>{row.s.Fe}</td>
                          </tr>
                        ))}
                      </tbody>
                    </table>
                  </div>
                </div>
              </>
            )}
          </div>

          {/* COLUNA DIREITA: Dimensionamento do projeto */}
          {calc?.NP && (
            <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>

              {/* Captação dimensionada */}
              <div className="panel">
                <div className="panel-head">
                  <div><div className="panel-eyebrow">SUBSISTEMA DE CAPTAÇÃO · DIMENSIONADO</div><h3>Malha sobre a cobertura</h3></div>
                </div>
                <ResultBig label="COMPRIMENTO TOTAL DE CABO DE CAPTAÇÃO" value={fmt(calc.LMalha, 1)} unit="m" status="ok"/>
                <div className="vl-mini-grid" style={{ gridTemplateColumns: "1fr 1fr" }}>
                  <MetricCell label="Linhas transversais" value={calc.nLinX} unit={`× ${fmt(calc.L)} m`} status="ok"/>
                  <MetricCell label="Linhas longitudinais" value={calc.nLinY} unit={`× ${fmt(calc.W)} m`} status="ok"/>
                </div>
                <StatusBanner kind="info">
                  Malha {calc.malha}×{calc.malha} m sobre cobertura de {fmt(calc.L)}×{fmt(calc.W)} m → {calc.nLinX} × {fmt(calc.L)} m + {calc.nLinY} × {fmt(calc.W)} m = <b>{fmt(calc.LMalha, 1)} m</b>.
                </StatusBanner>
              </div>

              {/* Descidas dimensionadas */}
              <div className="panel">
                <div className="panel-head">
                  <div><div className="panel-eyebrow">SUBSISTEMA DE DESCIDA · DIMENSIONADO</div><h3>Condutores verticais</h3></div>
                </div>
                <div className="vl-mini-grid" style={{ gridTemplateColumns: "1fr 1fr 1fr" }}>
                  <MetricCell label="Nº descidas" value={calc.nDescidas} unit="un." status="ok"/>
                  <MetricCell label="Perímetro" value={fmt(calc.perimetro)} unit="m" status="ok"/>
                  <MetricCell label="Cabo descidas" value={fmt(calc.LDesc, 1)} unit="m" status="ok"/>
                </div>
                <StatusBanner kind="info">
                  {calc.nDescidas} descidas distribuídas no perímetro (mín. 2 por NBR 5419-3 §5.3.5) · espaçamento máx. {calc.espDescidas} m · comprimento total {fmt(calc.LDesc, 1)} m (H+1m por descida).
                </StatusBanner>
              </div>

              {/* Aterramento dimensionado */}
              <div className="panel">
                <div className="panel-head">
                  <div><div className="panel-eyebrow">SUBSISTEMA DE ATERRAMENTO · DIMENSIONADO</div><h3>Eletrodo Tipo {calc.tipoAterr}</h3></div>
                </div>
                {calc.tipoAterr === "A" ? (
                  <>
                    <ResultBig
                      label={`COMPRIMENTO MÍN. l1 POR HASTE (ρ = ${calc.rho} Ω·m)`}
                      value={fmt(calc.l1_haste, 1)} unit="m" status="ok"/>
                    <div className="vl-mini-grid" style={{ gridTemplateColumns: "1fr 1fr" }}>
                      <MetricCell label="Mín. 2 hastes/descida" value={calc.nDescidas * 2} unit="hastes" status="ok"/>
                      <MetricCell label="Total cabo radial est." value={fmt(calc.nDescidas * calc.l1_haste, 1)} unit="m" status="ok"/>
                    </div>
                    <StatusBanner kind="info">
                      Por descida: 2 hastes verticais de {fmt(calc.l1_haste, 1)} m ou 1 condutor radial de {fmt(calc.l1_haste * 2, 1)} m (Fig. 3 NBR 5419-3:2026).
                    </StatusBanner>
                  </>
                ) : (
                  <>
                    <ResultBig label={`ANEL PERIMETRAL — COMPRIMENTO TOTAL`} value={fmt(calc.anelL, 1)} unit="m" status="ok"/>
                    <div className="vl-mini-grid" style={{ gridTemplateColumns: "1fr 1fr 1fr" }}>
                      <MetricCell label="re estrutura" value={fmt(calc.reCalc, 1)} unit="m" status="ok"/>
                      <MetricCell label="re necessário" value={fmt(calc.reReq, 1)} unit="m" status={calc.reReq > calc.reCalc ? "warn" : "ok"}/>
                      <MetricCell label="Hastes radiais extra" value={calc.hastesAdicionais} unit="un." status={calc.hastesAdicionais > 0 ? "warn" : "ok"}/>
                    </div>
                    <StatusBanner kind={calc.hastesAdicionais > 0 ? "warn" : "ok"}>
                      {calc.hastesAdicionais > 0
                        ? `Solo de alta resistividade (ρ=${calc.rho} Ω·m): re necessário (${fmt(calc.reReq,1)} m) > re da estrutura (${fmt(calc.reCalc,1)} m). Adicionar ${calc.hastesAdicionais} hastes radiais para complementar.`
                        : `re da estrutura (${fmt(calc.reCalc,1)} m) ≥ re necessário (${fmt(calc.reReq,1)} m). Apenas o anel atende.`}
                    </StatusBanner>
                    <p style={{ fontSize: 11, color: "var(--fg-mute)", marginTop: 8, lineHeight: 1.6 }}>
                      Anel a 0,5 m de profundidade, 1 m afastado da estrutura · seção mín. {SECAO_MIN_ATERR[calc.NP].Cu} mm² Cu ou {SECAO_MIN_ATERR[calc.NP].Fe} mm² Fe.
                    </p>
                  </>
                )}
              </div>

              {/* Distância de segurança s */}
              <div className="panel">
                <div className="panel-head">
                  <div><div className="panel-eyebrow">DISTÂNCIA DE SEGURANÇA · NBR 5419-3 §6.3</div><h3>Separação SPDA × partes internas</h3></div>
                </div>
                <ResultBig label="DISTÂNCIA DE SEGURANÇA s" value={fmt(calc.s, 3)} unit="m" status="ok"/>
                <div className="vl-mini-grid" style={{ gridTemplateColumns: "1fr 1fr 1fr 1fr" }}>
                  <MetricCell label="ki (NP)" value={calc.ki} status="ok"/>
                  <MetricCell label="kc" value={fmt(calc.kc, 2)} status="ok"/>
                  <MetricCell label="km" value={calc.km} status="ok"/>
                  <MetricCell label="L (altura)" value={calc.H} unit="m" status="ok"/>
                </div>
                <StatusBanner kind="info">
                  s = ki × kc × L / km = {calc.ki} × {fmt(calc.kc, 2)} × {calc.H} / {calc.km} = <b>{fmt(calc.s, 3)} m</b>. Partes metálicas internas devem estar a no mínimo essa distância das descidas, OU equipotencializadas.
                </StatusBanner>
              </div>

              {/* Lista de materiais */}
              <div className="panel">
                <div className="panel-head">
                  <div><div className="panel-eyebrow">LISTA DE MATERIAIS (BoM)</div><h3>Resumo do projeto</h3></div>
                </div>
                <div style={{ overflowX: "auto", border: "1px solid var(--border)", borderRadius: 8 }}>
                  <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 12 }}>
                    <thead>
                      <tr style={{ background: "var(--bg-0)" }}>
                        {["Item", "Qtd.", "Unid."].map(h => (
                          <th key={h} style={{ padding: "8px 12px", textAlign: "left", fontFamily: "var(--ff-mono)", fontSize: 10, color: "var(--fg-mute)", letterSpacing: "0.1em", textTransform: "uppercase", borderBottom: "1px solid var(--border)" }}>{h}</th>
                        ))}
                      </tr>
                    </thead>
                    <tbody>
                      {[
                        { item: `Cabo Cu nu ${SECAO_MIN_CAPTACAO[calc.NP].Cu} mm² — captação`, qtd: fmt(calc.LMalha, 1), un: "m" },
                        { item: `Cabo Cu nu ${SECAO_MIN_DESCIDA[calc.NP].Cu} mm² — descidas`, qtd: fmt(calc.LDesc, 1), un: "m" },
                        calc.tipoAterr === "A"
                          ? { item: `Haste de aterramento Cu/Aço L ≥ ${fmt(calc.l1_haste,1)} m`, qtd: calc.nDescidas * 2, un: "un." }
                          : { item: `Cabo Cu nu ${SECAO_MIN_ATERR[calc.NP].Cu} mm² — anel`, qtd: fmt(calc.anelL, 1), un: "m" },
                        calc.tipoAterr === "B" && calc.hastesAdicionais > 0
                          ? { item: "Haste radial complementar", qtd: calc.hastesAdicionais, un: "un." } : null,
                        { item: "Conector de medição (TAP)", qtd: calc.nDescidas, un: "un." },
                        { item: "Caixa de inspeção", qtd: calc.nDescidas, un: "un." },
                        { item: "Suporte/isolador para cabo", qtd: Math.ceil(calc.LCaboTotal / 1.5), un: "un." },
                      ].filter(Boolean).map((r, i) => (
                        <tr key={i} style={{ borderBottom: "1px solid var(--border)" }}>
                          <td style={{ padding: "8px 12px", fontSize: 12, color: "var(--fg-dim)" }}>{r.item}</td>
                          <td className="mono" style={{ padding: "8px 12px", color: "var(--accent)", fontWeight: 600 }}>{r.qtd}</td>
                          <td className="mono" style={{ padding: "8px 12px" }}>{r.un}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              </div>

              {/* Memória de cálculo */}
              <div className="panel">
                <div className="panel-head">
                  <div><div className="panel-eyebrow">MEMÓRIA DE CÁLCULO</div><h3>SPDA Externo</h3></div>
                </div>
                <div className="vl-memory">
                  <MemoryStep n={1} title="Perímetro da estrutura" isFormula>
                    P = 2 × (L + W) = 2 × ({calc.L} + {calc.W}) = <b className="readout">{fmt(calc.perimetro)} m</b>
                  </MemoryStep>
                  <MemoryStep n={2} title={`Nº de descidas (NP ${calc.NP})`}>
                    n = max(2, ceil(P / d_max)) = max(2, ceil({fmt(calc.perimetro)}/{calc.espDescidas})) = <b className="readout">{calc.nDescidas}</b>
                  </MemoryStep>
                  <MemoryStep n={3} title="Comprimento de cabo da malha" isFormula>
                    L_malha = nx × L + ny × W = {calc.nLinX} × {fmt(calc.L)} + {calc.nLinY} × {fmt(calc.W)} = <b className="readout">{fmt(calc.LMalha, 1)} m</b>
                  </MemoryStep>
                  {calc.tipoAterr === "A" ? (
                    <MemoryStep n={4} title={`Comprimento l1 (Tipo A, ρ=${calc.rho} Ω·m)`}>
                      Fig. 3 NBR 5419-3 → l1 mín = <b className="readout">{fmt(calc.l1_haste, 1)} m</b> por haste
                    </MemoryStep>
                  ) : (
                    <MemoryStep n={4} title={`Raio médio re (Tipo B, ρ=${calc.rho} Ω·m)`}>
                      re necessário = <b className="readout">{fmt(calc.reReq, 1)} m</b> · re estrutura = <b className="readout">{fmt(calc.reCalc, 1)} m</b>
                    </MemoryStep>
                  )}
                  <MemoryStep n={5} title="Distância de segurança s" isFormula>
                    s = ki × kc × L / km = {calc.ki} × {fmt(calc.kc, 2)} × {calc.H} / {calc.km} = <b className="readout">{fmt(calc.s, 3)} m</b>
                  </MemoryStep>
                </div>
              </div>

            </div>
          )}
        </div>
      )}

      {/* ══════════════════════════════════════════════════════
          ABA 3 — SPDA INTERNO / MPS / DPS (NBR 5419-4)
         ══════════════════════════════════════════════════════ */}
      {tab === "interno" && (
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "var(--gap-grid,20px)", alignItems: "start" }}>
          <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>

            {!calc?.NP && (
              <div className="panel">
                <StatusBanner kind="info">Complete a Aba 1 para calcular as MPS e DPS.</StatusBanner>
              </div>
            )}

            {calc?.NP && (
              <>
                {/* Inputs de projeto DPS */}
                <div className="panel">
                  <div className="panel-head">
                    <div><div className="panel-eyebrow">DADOS DO EQUIPAMENTO · PROJETO DPS</div><h3>Parâmetros de instalação</h3></div>
                  </div>
                  <FieldBlock label="Tensão suportável Uw do equipamento" hint="IEC 60364-4-44 — categoria">
                    <Seg value={Uw} onChange={setUw} options={TAB_UW}/>
                  </FieldBlock>
                  <FieldBlock label="Distância DPS → equipamento (Lcabo)" hint="≤10m: Up_ef ≈ Up · >10m: oscilação dobra Up">
                    <NumberInput value={Lcabo} onChange={setLcabo} suffix="m" step="0.5" min="0"/>
                  </FieldBlock>
                </div>

                {/* ZPR */}
                <div className="panel">
                  <div className="panel-head">
                    <div><div className="panel-eyebrow">ZONAS DE PROTEÇÃO CONTRA RAIOS · NBR 5419-4 SEC. 4.3</div><h3>Conceito de ZPR</h3></div>
                  </div>
                  {Object.entries(calc.zpr).map(([key, desc]) => (
                    <div key={key} style={{ display: "flex", gap: 12, padding: "10px 0", borderBottom: "1px solid oklch(28% 0.012 240/0.4)" }}>
                      <div style={{ fontFamily: "var(--ff-mono)", fontSize: 12, color: "var(--accent)", fontWeight: 700, minWidth: 48 }}>{key}</div>
                      <div style={{ fontSize: 12, color: "var(--fg-dim)", lineHeight: 1.5 }}>{desc}</div>
                    </div>
                  ))}
                  <StatusBanner kind="info" style={{ marginTop: 10 }}>
                    Todas as linhas elétricas que cruzam fronteiras de ZPR devem ter DPS ou interface isolante instalada no ponto de cruzamento (NBR 5419-4, 5.5).
                  </StatusBanner>
                </div>

                {/* Equipotencialização */}
                <div className="panel">
                  <div className="panel-head">
                    <div><div className="panel-eyebrow">EQUIPOTENCIALIZAÇÃO · NBR 5419-4 SEC. 5</div><h3>Seções mínimas</h3></div>
                  </div>
                  <div style={{ overflowX: "auto", border: "1px solid var(--border)", borderRadius: 8 }}>
                    <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 12 }}>
                      <thead>
                        <tr style={{ background: "var(--bg-0)" }}>
                          {["Componente", "Cu (mm²)", "Al (mm²)", "Fe (mm²)"].map(h => (
                            <th key={h} style={{ padding: "8px 12px", textAlign: "left", fontFamily: "var(--ff-mono)", fontSize: 10, color: "var(--fg-mute)", letterSpacing: "0.1em", textTransform: "uppercase", borderBottom: "1px solid var(--border)" }}>{h}</th>
                          ))}
                        </tr>
                      </thead>
                      <tbody>
                        {[
                          { comp: "Barras de equipotencializ.", Cu: 50, Al: "—", Fe: 50 },
                          { comp: "Condut. barra → aterramento", Cu: 50, Al: "—", Fe: 70 },
                          { comp: "Condut. entre barras (corrente signif.)", Cu: 16, Al: 25, Fe: 50 },
                          { comp: "Partes metálicas internas → barra", Cu: 6, Al: 10, Fe: 16 },
                          { comp: "Interlig. DPS classe I", Cu: 16, Al: "—", Fe: "—" },
                          { comp: "Interlig. DPS classe II", Cu: 6, Al: "—", Fe: "—" },
                          { comp: "Interlig. DPS classe III", Cu: 2.5, Al: "—", Fe: "—" },
                        ].map(r => (
                          <tr key={r.comp} style={{ borderBottom: "1px solid var(--border)" }}>
                            <td style={{ padding: "8px 12px", fontSize: 12, color: "var(--fg-dim)" }}>{r.comp}</td>
                            <td className="mono" style={{ padding: "8px 12px", color: "var(--accent)" }}>{r.Cu}</td>
                            <td className="mono" style={{ padding: "8px 12px" }}>{r.Al}</td>
                            <td className="mono" style={{ padding: "8px 12px" }}>{r.Fe}</td>
                          </tr>
                        ))}
                      </tbody>
                    </table>
                  </div>
                  <p style={{ fontSize: 11, color: "var(--fg-mute)", marginTop: 8, lineHeight: 1.6 }}>
                    Fonte: NBR 5419-4:2026, Tabela 1. Ligação equipotencial em rede: malha típica ≤ 5 m × 5 m (Seção 5.3).
                  </p>
                </div>
              </>
            )}
          </div>

          {/* Coluna direita: DPS */}
          {calc?.NP && (
            <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
              {/* DPS — Especificação por NP */}
              <div className="panel">
                <div className="panel-head">
                  <div><div className="panel-eyebrow">SISTEMA COORDENADO DE DPS · NBR 5419-4 ANEXO C</div><h3>Dispositivos de Proteção contra Surtos</h3></div>
                </div>

                <ResultBig
                  label={`Iimp NA ENTRADA (CLASSE I · NP ${calc.NP})`}
                  value={calc.dps?.Iimp_classe1.toFixed(2) || "—"}
                  unit="kA (10/350 µs)"
                  status={npStatus}
                />

                <div className="vl-mini-grid" style={{ gridTemplateColumns: "1fr 1fr 1fr" }}>
                  <MetricCell label="Imáx NP" value={calc.dps?.Imax} unit="kA" status="ok"/>
                  <MetricCell label="In Classe II" value={calc.dps?.In_classe2} unit="kA (8/20µs)" status="ok"/>
                  <MetricCell label="Up máx. recom." value={calc.dps?.Up_max} unit="kV" status="ok"/>
                </div>

                <StatusBanner kind={calc.NP === "I" ? "danger" : calc.NP === "II" ? "warn" : "info"}>
                  {calc.NP === "I"
                    ? "NP I: DPS Classe I obrigatório (10/350µs · Iimp ≥ 25 kA) na entrada do quadro elétrico (fronteira ZPR 0→1)."
                    : calc.NP === "II"
                    ? "NP II: DPS Classe I na entrada (Iimp ≥ 18,75 kA) + Classe II nos quadros secundários (fronteira ZPR 1→2)."
                    : "NP III/IV: DPS Classe I/II na entrada (Iimp ≥ 12,5 kA). DPS Classe II nos circuitos terminais."}
                </StatusBanner>
              </div>

              {/* Verificação de coordenação */}
              <div className="panel">
                <div className="panel-head">
                  <div><div className="panel-eyebrow">VERIFICAÇÃO DE COORDENAÇÃO · NBR 5419-4 §C.2.1</div><h3>Up efetivo vs. Uw do equipamento</h3></div>
                </div>
                <ResultBig
                  label="TENSÃO EFETIVA NO EQUIPAMENTO Up_ef"
                  value={fmt(calc.Up_ef, 2)} unit="kV"
                  status={calc.dpsOk ? "ok" : "danger"}
                />
                <div className="vl-mini-grid" style={{ gridTemplateColumns: "1fr 1fr 1fr" }}>
                  <MetricCell label="Up do DPS" value={calc.Up_dps} unit="kV" status="ok"/>
                  <MetricCell label="Distância Lcabo" value={calc.Lcabo} unit="m" status={calc.Lcabo > 10 ? "warn" : "ok"}/>
                  <MetricCell label="Uw equipamento" value={calc.Uw} unit="kV" status="ok"/>
                </div>
                <StatusBanner kind={calc.dpsOk ? "ok" : "danger"}>
                  {calc.dpsOk
                    ? `Coordenação OK — Up_ef (${fmt(calc.Up_ef,2)} kV) ≤ Uw (${calc.Uw} kV). DPS no quadro protege o equipamento.`
                    : `INSUFICIENTE — Up_ef (${fmt(calc.Up_ef,2)} kV) > Uw (${calc.Uw} kV). ${calc.Lcabo > 10
                        ? "Instale DPS adicional (Classe III) a menos de 10 m do equipamento."
                        : "Use DPS com menor Up ou eleve a categoria do equipamento."}`}
                </StatusBanner>
              </div>

              {/* Plano de instalação de DPS */}
              <div className="panel">
                <div className="panel-head">
                  <div><div className="panel-eyebrow">PLANO DE INSTALAÇÃO DE DPS</div><h3>Localização e especificação</h3></div>
                </div>
                <div style={{ overflowX: "auto", border: "1px solid var(--border)", borderRadius: 8 }}>
                  <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 12 }}>
                    <thead>
                      <tr style={{ background: "var(--bg-0)" }}>
                        {["Local", "Classe", "Iimp / In", "Up máx."].map(h => (
                          <th key={h} style={{ padding: "8px 12px", textAlign: "left", fontFamily: "var(--ff-mono)", fontSize: 10, color: "var(--fg-mute)", letterSpacing: "0.1em", textTransform: "uppercase", borderBottom: "1px solid var(--border)" }}>{h}</th>
                        ))}
                      </tr>
                    </thead>
                    <tbody>
                      {[
                        {
                          local: "Entrada (QGBT) — ZPR 0→1",
                          classe: "Classe I (B)",
                          corr: `Iimp ≥ ${calc.dps?.Iimp_classe1.toFixed(2)} kA (10/350µs)`,
                          up: "≤ 4,0 kV",
                        },
                        {
                          local: "Quadros secundários — ZPR 1→2",
                          classe: "Classe II (C)",
                          corr: `In ≥ ${calc.dps?.In_classe2} kA (8/20µs)`,
                          up: "≤ 2,5 kV",
                        },
                        {
                          local: "Próximo equip. sensível — ZPR 2→3",
                          classe: "Classe III (D)",
                          corr: "In ≥ 5 kA (8/20µs)",
                          up: "≤ 1,5 kV",
                        },
                      ].map(r => (
                        <tr key={r.local} style={{ borderBottom: "1px solid var(--border)" }}>
                          <td style={{ padding: "8px 12px", fontSize: 12, color: "var(--fg-dim)" }}>{r.local}</td>
                          <td className="mono" style={{ padding: "8px 12px", color: "var(--accent)", fontWeight: 600 }}>{r.classe}</td>
                          <td className="mono" style={{ padding: "8px 12px" }}>{r.corr}</td>
                          <td className="mono" style={{ padding: "8px 12px" }}>{r.up}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
                <p style={{ fontSize: 11, color: "var(--fg-mute)", marginTop: 8, lineHeight: 1.6 }}>
                  Cada cruzamento de ZPR exige DPS ou interface isolante (NBR 5419-4 §5.5). Cabo Cu mín. 16 mm² (Cl. I), 6 mm² (Cl. II), 2,5 mm² (Cl. III) — Tabela 1.
                </p>

                <div className="vl-memory" style={{ marginTop: 16 }}>
                  <div className="vl-memory-eyebrow">MEMÓRIA — DPS</div>
                  <MemoryStep n={1} title="Distribuição de corrente (50/50)" isFormula>
                    50% no aterramento · 50% pelas linhas → {calc.dps?.Imax} × 0,5 / 4 cond. = <b className="readout">{calc.dps?.Iimp_classe1.toFixed(2)} kA</b> por DPS
                  </MemoryStep>
                  <MemoryStep n={2} title="Tensão efetiva considerando indução nos cabos" isFormula>
                    {calc.Lcabo > 10
                      ? `Lcabo > 10m → oscilação dobra: Up_ef = 2 × ${calc.Up_dps} = `
                      : `Lcabo ≤ 10m → Up_ef = Up × (1 + Lcabo/20) = ${calc.Up_dps} × (1 + ${calc.Lcabo}/20) = `}
                    <b className="readout">{fmt(calc.Up_ef, 2)} kV</b>
                  </MemoryStep>
                  <MemoryStep n={3} title="Condição de proteção">
                    Up_ef ≤ Uw → {fmt(calc.Up_ef, 2)} ≤ {calc.Uw} → <b className="readout">{calc.dpsOk ? "ATENDE" : "NÃO ATENDE"}</b>
                  </MemoryStep>
                </div>
              </div>

              {/* Blindagem */}
              <div className="panel">
                <div className="panel-head">
                  <div><div className="panel-eyebrow">BLINDAGEM MAGNÉTICA E ROTEAMENTO · SEC. 6</div><h3>Recomendações MPS</h3></div>
                </div>
                {[
                  { titulo: "Malha de equipotencialização interna", desc: "Largura típica ≤ 5 m × 5 m. Interligar estruturas metálicas, trilhos de elevador, tubulações, bandejas de cabos, armações de janelas (NBR 5419-4, 5.3)." },
                  { titulo: "Roteamento de linhas internas", desc: "Minimizar área dos laços de indução. Instalar cabos de energia e sinal próximos e paralelos. KS3 = 0,01 para cabos no mesmo eletroduto (Tabela B.5 da NBR 5419-2)." },
                  { titulo: "Blindagem de cabos externos", desc: "Blindagem interligada ao mesmo barramento de equipotencialização do equipamento → CLD = 0 (linha completamente blindada). Reduz PC significativamente." },
                  { titulo: "Interfaces isolantes", desc: "Usar para bloquear surtos conduzidos quando DPS não for suficiente. Fibra óptica (sem metálico) = zero corrente conduzida entre ZPRs (NBR 5419-4, Sec. 8)." },
                ].map(item => (
                  <div key={item.titulo} style={{ padding: "12px 0", borderBottom: "1px solid oklch(28% 0.012 240/0.4)" }}>
                    <div style={{ fontFamily: "var(--ff-mono)", fontSize: 11, color: "var(--accent)", fontWeight: 600, marginBottom: 4 }}>▸ {item.titulo}</div>
                    <div style={{ fontSize: 12, color: "var(--fg-dim)", lineHeight: 1.6 }}>{item.desc}</div>
                  </div>
                ))}
              </div>

              {/* Inspeção */}
              <div className="panel">
                <div className="panel-head">
                  <div><div className="panel-eyebrow">INSPEÇÃO E MANUTENÇÃO · NBR 5419-4 SEC. 9</div><h3>Periodicidade recomendada</h3></div>
                </div>
                <div className="vl-mini-grid" style={{ gridTemplateColumns: "1fr 1fr" }}>
                  <MetricCell label="Inspeção visual" value={calc.NP === "I" ? "Anual" : "Bienal"} status="ok"/>
                  <MetricCell label="Inspeção completa" value={calc.NP === "I" ? "1 ano" : calc.NP === "II" ? "2 anos" : "4 anos"} status="ok"/>
                </div>
                <StatusBanner kind="warn">
                  Inspecionar imediatamente após suspeita de descarga direta na estrutura (contador de raios ou danos visíveis) — NBR 5419-4, 9.2.2-e).
                </StatusBanner>
              </div>
            </div>
          )}
        </div>
      )}

      {/* ── Referência normativa ─────────────────────────────── */}
      <div className="panel">
        <div className="panel-head">
          <div><div className="panel-eyebrow">REFERÊNCIA NORMATIVA</div><h3>ABNT NBR 5419:2026 — Proteção contra descargas atmosféricas</h3></div>
          <span className="dim mono small">2ª edição · 10.03.2026</span>
        </div>
        <div className="ref-table">
          <div className="ref-head" style={{ gridTemplateColumns: "80px 1fr 1.5fr 1fr" }}>
            <span>PARTE</span><span>TÍTULO</span><span>ESCOPO PRINCIPAL</span><span>MÓDULO</span>
          </div>
          {[
            { parte: "Parte 1", titulo: "Princípios gerais", escopo: "Parâmetros corrente descarga, esfera rolante, gaiola Faraday", modulo: "Base" },
            { parte: "Parte 2", titulo: "Análise de risco", escopo: "Cálculo de R1, R3 · Determinação do NP · Fórmulas ND, NL, probabilidades PX", modulo: "Aba 1" },
            { parte: "Parte 3", titulo: "Danos físicos e perigos à vida", escopo: "SPDA externo: captação, descida, aterramento · Seções mínimas · Distância de segurança", modulo: "Aba 2" },
            { parte: "Parte 4", titulo: "Sistemas elétricos e eletrônicos internos", escopo: "ZPR · Equipotencialização em rede · Sistema coordenado DPS · Seleção Up/Iimp", modulo: "Aba 3" },
          ].map(r => (
            <div key={r.parte} className="ref-row" style={{ gridTemplateColumns: "80px 1fr 1.5fr 1fr" }}>
              <span className="mono"><b>{r.parte}</b></span>
              <span>{r.titulo}</span>
              <span className="dim" style={{ fontSize: 12 }}>{r.escopo}</span>
              <span><span className="pill pill-ok">{r.modulo}</span></span>
            </div>
          ))}
        </div>
      </div>

    </div>
  );
}

window.VL_SPDA = SPDA;
