/* global React */
/* ===========================================================
   VOLTLAB · DIAGRAMAS UNIFILARES v2
   Editor completo com estilos embutidos — não depende de app.css
=========================================================== */
const { useState, useRef, useEffect, useMemo, useCallback } = React;

// ─── Persistência ────────────────────────────────────────────────────────────
const usePersist = (key, initial) => {
  if (window.useLocalStorage) return window.useLocalStorage(key, initial);
  return React.useState(initial);
};

// ─── CSS embutido ─────────────────────────────────────────────────────────────
const UNI_CSS = `
.uni-shell {
  display: grid;
  grid-template-columns: 220px 1fr 260px;
  height: calc(100vh - 64px);
  background: var(--bg-0, #0a0e14);
  color: var(--fg, #c8d8f0);
  font-family: "IBM Plex Sans", sans-serif;
  overflow: hidden;
}

/* ── Palette ── */
.uni-palette {
  background: var(--bg-1, #0f1520);
  border-right: 1px solid var(--border, rgba(100,160,255,0.1));
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.uni-palette-head {
  padding: 14px 16px 10px;
  border-bottom: 1px solid var(--border, rgba(100,160,255,0.1));
}
.uni-palette-eyebrow {
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  letter-spacing: .12em;
  color: var(--accent, #3d8bff);
  margin-bottom: 2px;
}
.uni-palette-sub {
  font-size: 11px;
  color: var(--fg-dim, #6a8ab0);
}
.uni-palette-scroll {
  overflow-y: auto;
  flex: 1;
  padding: 8px 0;
}
.uni-pgroup-title {
  font-family: "JetBrains Mono", monospace;
  font-size: 9px;
  letter-spacing: .15em;
  color: var(--fg-mute, #3a5070);
  padding: 10px 16px 4px;
  text-transform: uppercase;
}
.uni-pitem {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  background: none;
  border: none;
  padding: 7px 14px;
  cursor: pointer;
  color: var(--fg, #c8d8f0);
  border-radius: 0;
  transition: background .12s;
  text-align: left;
}
.uni-pitem:hover { background: rgba(61,139,255,0.08); }
.uni-pitem.tone-warn { color: var(--warn, #f2b043); }
.uni-pitem.tone-ok   { color: var(--ok,   #5be38c); }
.uni-pitem-icon {
  flex-shrink: 0;
  opacity: .85;
}
.uni-pitem-meta b { font-size: 12px; display: block; }
.uni-pitem-meta em { font-size: 10px; color: var(--fg-dim, #6a8ab0); font-style: normal; }

/* ── Stage ── */
.uni-stage {
  position: relative;
  overflow: hidden;
  background: var(--bg-0, #0a0e14);
  cursor: grab;
}
.uni-stage:active { cursor: grabbing; }

.uni-topbar {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 14px;
  background: linear-gradient(to bottom, var(--bg-1,#0f1520) 60%, transparent);
  gap: 8px;
}
.uni-topbar-l, .uni-topbar-r {
  display: flex;
  align-items: center;
  gap: 8px;
}
.uni-pill {
  display: flex;
  align-items: center;
  gap: 6px;
  background: rgba(61,139,255,0.08);
  border: 1px solid rgba(61,139,255,0.15);
  border-radius: 20px;
  padding: 3px 10px;
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  color: var(--fg-dim, #6a8ab0);
}
.uni-toggle {
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  background: none;
  border: 1px solid var(--border, rgba(100,160,255,0.12));
  border-radius: 4px;
  padding: 4px 10px;
  color: var(--fg-dim, #6a8ab0);
  cursor: pointer;
  transition: all .15s;
}
.uni-toggle.is-on {
  background: rgba(61,139,255,0.12);
  color: var(--accent, #3d8bff);
  border-color: rgba(61,139,255,0.3);
}
.uni-coord {
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  color: var(--fg-mute, #3a5070);
}
.uni-iconbtn {
  background: none;
  border: 1px solid var(--border, rgba(100,160,255,0.12));
  border-radius: 5px;
  width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  color: var(--fg-dim, #6a8ab0);
  transition: all .15s;
}
.uni-iconbtn:hover {
  background: rgba(61,139,255,0.1);
  color: var(--accent, #3d8bff);
  border-color: rgba(61,139,255,0.25);
}
.uni-btn-ghost {
  background: none;
  border: 1px solid var(--border, rgba(100,160,255,0.12));
  border-radius: 5px;
  padding: 5px 12px;
  cursor: pointer;
  color: var(--fg-dim, #6a8ab0);
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  display: flex; align-items: center; gap: 5px;
  transition: all .15s;
}
.uni-btn-ghost:hover {
  background: rgba(61,139,255,0.08);
  color: var(--accent, #3d8bff);
}

.uni-svg {
  width: 100%;
  height: 100%;
  display: block;
}

.uni-empty-hint text { font-family: "IBM Plex Sans", sans-serif; }

.uni-bottombar {
  position: absolute;
  bottom: 0; left: 0; right: 0;
  background: linear-gradient(to top, var(--bg-1,#0f1520) 60%, transparent);
  padding: 8px 16px;
  display: flex;
  gap: 20px;
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  color: var(--fg-mute, #3a5070);
  align-items: center;
}
.uni-bottombar b { color: var(--fg, #c8d8f0); }
.uni-bottombar .readout { color: var(--accent, #3d8bff); }
.uni-help { margin-left: auto; color: var(--fg-mute, #3a5070); font-size: 9px; }

/* ── Nodes SVG ── */
.uni-node-card {
  fill: var(--bg-1, #0f1520);
  stroke: var(--border-2, rgba(100,160,255,0.2));
  stroke-width: 1;
  rx: 8;
  transition: all .15s;
}
.uni-node.tone-warn .uni-node-card { stroke: rgba(242,176,67,0.35); }
.uni-node.tone-ok   .uni-node-card { stroke: rgba(91,227,140,0.35); }
.uni-node.is-sel .uni-node-card {
  stroke: var(--accent, #3d8bff);
  stroke-width: 1.5;
  filter: drop-shadow(0 0 8px var(--accent-glow, rgba(61,139,255,0.4)));
}
.uni-node.tone-warn.is-sel .uni-node-card { stroke: #f2b043; filter: drop-shadow(0 0 8px rgba(242,176,67,0.4)); }
.uni-node.tone-ok.is-sel   .uni-node-card { stroke: #5be38c; filter: drop-shadow(0 0 8px rgba(91,227,140,0.4)); }

.uni-node-label { font-family: "JetBrains Mono", monospace; font-size: 9.5px; fill: var(--fg-dim, #6a8ab0); }
.uni-node.is-sel .uni-node-label { fill: var(--accent, #3d8bff); }
.uni-node-foot { font-family: "JetBrains Mono", monospace; font-size: 8.5px; fill: var(--fg-mute, #3a5070); }
.uni-node.tone-warn .uni-node-foot { fill: rgba(242,176,67,0.7); }
.uni-node.tone-ok   .uni-node-foot { fill: rgba(91,227,140,0.6); }
.uni-glyph { color: var(--fg-dim, #6a8ab0); }
.uni-node.tone-warn .uni-glyph { color: #f2b043; }
.uni-node.tone-ok   .uni-glyph { color: #5be38c; }
.uni-node.is-sel .uni-glyph { color: var(--accent, #3d8bff); }

/* connections */
.uni-conn {
  fill: none;
  stroke: var(--border-2, rgba(100,160,255,0.25));
  stroke-width: 1.5;
}

/* ── Inspector ── */
.uni-insp {
  background: var(--bg-1, #0f1520);
  border-left: 1px solid var(--border, rgba(100,160,255,0.1));
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  padding: 16px;
  gap: 0;
}
.uni-insp-eyebrow {
  font-family: "JetBrains Mono", monospace;
  font-size: 9px;
  letter-spacing: .14em;
  color: var(--accent, #3d8bff);
  margin-bottom: 4px;
}
.uni-insp h3 {
  font-size: 14px;
  font-weight: 600;
  margin: 0 0 2px;
  color: var(--fg, #c8d8f0);
}
.uni-insp-sub {
  font-size: 10px;
  color: var(--fg-mute, #3a5070);
  font-family: "JetBrains Mono", monospace;
  margin-bottom: 14px;
}
.uni-section {
  margin-top: 14px;
  border-top: 1px solid var(--border, rgba(100,160,255,0.08));
  padding-top: 12px;
}
.uni-section-title {
  font-family: "JetBrains Mono", monospace;
  font-size: 9px;
  letter-spacing: .12em;
  color: var(--fg-mute, #3a5070);
  margin-bottom: 10px;
}
.uni-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 10px;
}
.uni-field label {
  font-size: 11px;
  color: var(--fg-dim, #6a8ab0);
}
.uni-field input {
  background: rgba(0,0,0,0.3);
  border: 1px solid var(--border, rgba(100,160,255,0.12));
  border-radius: 5px;
  color: var(--fg, #c8d8f0);
  padding: 6px 10px;
  font-family: "JetBrains Mono", monospace;
  font-size: 12px;
  width: 100%;
  box-sizing: border-box;
  outline: none;
  transition: border-color .15s;
}
.uni-field input:focus { border-color: var(--accent, #3d8bff); }
.uni-field-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 6px;
  align-items: center;
  margin-bottom: 8px;
}
.uni-field-row label { font-size: 11px; color: var(--fg-dim, #6a8ab0); }
.uni-field-row input {
  background: rgba(0,0,0,0.3);
  border: 1px solid var(--border, rgba(100,160,255,0.12));
  border-radius: 5px;
  color: var(--fg, #c8d8f0);
  padding: 5px 8px;
  font-family: "JetBrains Mono", monospace;
  font-size: 12px;
  width: 90px;
  text-align: right;
  outline: none;
}
.uni-field-unit { font-size: 10px; color: var(--fg-mute, #3a5070); font-family: "JetBrains Mono", monospace; }
.uni-stat-card {
  background: rgba(0,0,0,0.2);
  border: 1px solid var(--border, rgba(100,160,255,0.08));
  border-radius: 6px;
  padding: 10px 12px;
  margin-bottom: 8px;
}
.uni-stat-card span { font-size: 10px; color: var(--fg-mute, #3a5070); display: block; margin-bottom: 2px; }
.uni-stat-card b { font-family: "JetBrains Mono", monospace; font-size: 18px; color: var(--accent, #3d8bff); }
.uni-stat-card em { font-size: 11px; color: var(--fg-dim, #6a8ab0); font-style: normal; }
.uni-stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.uni-del-btn {
  width: 100%;
  background: rgba(248,100,100,0.06);
  border: 1px solid rgba(248,100,100,0.2);
  border-radius: 6px;
  color: #f87171;
  padding: 8px;
  cursor: pointer;
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  margin-top: 12px;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  transition: all .15s;
}
.uni-del-btn:hover { background: rgba(248,100,100,0.12); }
.uni-parent-select {
  background: rgba(0,0,0,0.3);
  border: 1px solid var(--border, rgba(100,160,255,0.12));
  border-radius: 5px;
  color: var(--fg, #c8d8f0);
  padding: 6px 8px;
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  width: 100%;
  outline: none;
  margin-bottom: 8px;
}
.uni-type-list { display: flex; flex-direction: column; gap: 4px; }
.uni-type-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 8px;
  border-radius: 5px;
  background: rgba(0,0,0,0.2);
  font-size: 11px;
}
.uni-type-row.tone-warn { color: #f2b043; }
.uni-type-row.tone-ok   { color: #5be38c; }
.uni-type-count { margin-left: auto; font-family: "JetBrains Mono", monospace; font-size: 12px; }
.uni-tip {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  background: rgba(61,139,255,0.05);
  border: 1px solid rgba(61,139,255,0.1);
  border-radius: 6px;
  padding: 10px;
  margin-top: 14px;
  font-size: 11px;
  color: var(--fg-dim, #6a8ab0);
  line-height: 1.5;
}
.uni-clear-btn {
  width: 100%;
  background: none;
  border: 1px solid var(--border, rgba(100,160,255,0.12));
  border-radius: 6px;
  color: var(--fg-dim, #6a8ab0);
  padding: 8px;
  cursor: pointer;
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  margin-top: 10px;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  transition: all .15s;
}
.uni-clear-btn:hover { border-color: #f87171; color: #f87171; }
`;

// ─── Injetar CSS uma vez ──────────────────────────────────────────────────────
function injectCSS() {
  if (document.getElementById("vl-uni-styles")) return;
  const el = document.createElement("style");
  el.id = "vl-uni-styles";
  el.textContent = UNI_CSS;
  document.head.appendChild(el);
}

// ─── Símbolos unifilares ──────────────────────────────────────────────────────
const GLYPHS = {
  concessionaria: (
    <g strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <line x1="30" y1="4"  x2="30" y2="18"/>
      <circle cx="30" cy="30" r="12"/>
      <polyline points="24,25 30,35 36,25"/>
      <line x1="30" y1="42" x2="30" y2="56"/>
      <text x="30" y="56" textAnchor="middle" fontSize="7" fontFamily="JetBrains Mono" stroke="none" fill="currentColor">UTIL</text>
    </g>
  ),
  medidor: (
    <g strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <line x1="30" y1="4" x2="30" y2="14"/>
      <rect x="12" y="14" width="36" height="28" rx="2"/>
      <text x="30" y="32" textAnchor="middle" fontSize="12" fontFamily="Space Grotesk" fontWeight="700" stroke="none" fill="currentColor">Wh</text>
      <line x1="30" y1="42" x2="30" y2="56"/>
    </g>
  ),
  transformador: (
    <g strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <line x1="30" y1="4" x2="30" y2="14"/>
      <circle cx="22" cy="22" r="9"/>
      <circle cx="38" cy="22" r="9"/>
      <line x1="30" y1="31" x2="30" y2="56"/>
      <text x="30" y="50" textAnchor="middle" fontSize="7" fontFamily="JetBrains Mono" stroke="none" fill="currentColor">Δ / Y</text>
    </g>
  ),
  disjuntor: (
    <g strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <line x1="30" y1="4" x2="30" y2="16"/>
      <rect x="18" y="16" width="24" height="22" rx="2"/>
      <line x1="22" y1="20" x2="38" y2="36" strokeLinecap="round"/>
      <circle cx="22" cy="20" r="2" fill="currentColor" stroke="none"/>
      <circle cx="38" cy="36" r="2" fill="currentColor" stroke="none"/>
      <line x1="30" y1="38" x2="30" y2="56"/>
    </g>
  ),
  dr: (
    <g strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <line x1="30" y1="4" x2="30" y2="16"/>
      <rect x="16" y="16" width="28" height="22" rx="2"/>
      <line x1="21" y1="20" x2="37" y2="36" strokeLinecap="round"/>
      <circle cx="21" cy="20" r="2" fill="currentColor" stroke="none"/>
      <text x="30" y="48" textAnchor="middle" fontSize="8" fontFamily="JetBrains Mono" stroke="none" fill="currentColor">IDR</text>
      <line x1="30" y1="38" x2="30" y2="42"/>
    </g>
  ),
  dps: (
    <g strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <line x1="30" y1="4" x2="30" y2="14"/>
      <rect x="18" y="14" width="24" height="22" rx="2"/>
      <text x="30" y="29" textAnchor="middle" fontSize="9" fontFamily="JetBrains Mono" stroke="none" fill="currentColor">DPS</text>
      <line x1="30" y1="36" x2="30" y2="44"/>
      <line x1="18" y1="44" x2="42" y2="44"/>
      <line x1="20" y1="49" x2="40" y2="49"/>
      <line x1="24" y1="54" x2="36" y2="54"/>
    </g>
  ),
  barramento: (
    <g strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <line x1="30" y1="4" x2="30" y2="16"/>
      <rect x="6" y="16" width="48" height="8" rx="1" fill="currentColor" fillOpacity="0.4"/>
      <rect x="6" y="16" width="48" height="8" rx="1"/>
      <line x1="16" y1="24" x2="16" y2="40"/>
      <line x1="30" y1="24" x2="30" y2="40"/>
      <line x1="44" y1="24" x2="44" y2="40"/>
    </g>
  ),
  quadro: (
    <g strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <line x1="30" y1="4" x2="30" y2="12"/>
      <rect x="10" y="12" width="40" height="38" rx="2"/>
      <line x1="10" y1="20" x2="50" y2="20"/>
      <text x="30" y="17" textAnchor="middle" fontSize="6" fontFamily="JetBrains Mono" stroke="none" fill="currentColor" letterSpacing="1">QD</text>
      <line x1="18" y1="28" x2="24" y2="36" strokeLinecap="round"/>
      <line x1="28" y1="28" x2="34" y2="36" strokeLinecap="round"/>
      <line x1="38" y1="28" x2="44" y2="36" strokeLinecap="round"/>
      <line x1="30" y1="50" x2="30" y2="56"/>
    </g>
  ),
  motor: (
    <g strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <line x1="30" y1="4" x2="30" y2="14"/>
      <circle cx="30" cy="30" r="16"/>
      <text x="30" y="35" textAnchor="middle" fontSize="15" fontFamily="Space Grotesk" fontWeight="700" stroke="none" fill="currentColor">M</text>
      <line x1="30" y1="46" x2="30" y2="56"/>
    </g>
  ),
  iluminacao: (
    <g strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <line x1="30" y1="4" x2="30" y2="14"/>
      <circle cx="30" cy="28" r="12"/>
      <line x1="23" y1="21" x2="37" y2="35"/>
      <line x1="37" y1="21" x2="23" y2="35"/>
      <line x1="30" y1="40" x2="30" y2="56"/>
      <text x="30" y="54" textAnchor="middle" fontSize="7" fontFamily="JetBrains Mono" stroke="none" fill="currentColor">LUM</text>
    </g>
  ),
  tomada: (
    <g strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <line x1="30" y1="4" x2="30" y2="14"/>
      <circle cx="30" cy="28" r="12"/>
      <circle cx="25" cy="27" r="1.8" fill="currentColor" stroke="none"/>
      <circle cx="35" cy="27" r="1.8" fill="currentColor" stroke="none"/>
      <path d="M27 32 Q30 35 33 32" fill="none"/>
      <line x1="30" y1="40" x2="30" y2="56"/>
      <text x="30" y="54" textAnchor="middle" fontSize="6.5" fontFamily="JetBrains Mono" stroke="none" fill="currentColor">TUG/E</text>
    </g>
  ),
  ar_cond: (
    <g strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <line x1="30" y1="4" x2="30" y2="12"/>
      <rect x="10" y="12" width="40" height="22" rx="3"/>
      <line x1="14" y1="19" x2="46" y2="19"/>
      <line x1="14" y1="23" x2="46" y2="23"/>
      <line x1="14" y1="27" x2="46" y2="27"/>
      <text x="30" y="46" textAnchor="middle" fontSize="7" fontFamily="JetBrains Mono" stroke="none" fill="currentColor">AR-COND</text>
      <line x1="30" y1="34" x2="30" y2="56"/>
    </g>
  ),
  carga: (
    <g strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <line x1="30" y1="4" x2="30" y2="16"/>
      <polygon points="16,30 30,16 44,30 30,44"/>
      <text x="30" y="34" textAnchor="middle" fontSize="10" fontFamily="Space Grotesk" fontWeight="600" stroke="none" fill="currentColor">Z</text>
      <line x1="30" y1="44" x2="30" y2="56"/>
    </g>
  ),
  banco_cap: (
    <g strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <line x1="30" y1="4" x2="30" y2="18"/>
      <line x1="12" y1="18" x2="48" y2="18"/>
      <line x1="12" y1="24" x2="48" y2="24"/>
      <line x1="30" y1="24" x2="30" y2="38"/>
      <line x1="12" y1="38" x2="48" y2="38"/>
      <line x1="12" y1="44" x2="48" y2="44"/>
      <line x1="30" y1="44" x2="30" y2="56"/>
    </g>
  ),
};

// ─── Paleta ──────────────────────────────────────────────────────────────────
const PALETTE = [
  { group: "Entrada", items: [
    { type: "concessionaria", label: "Concessionária", tone: "warn", defaults: { tensao: 13800, demanda: 100 } },
    { type: "medidor",        label: "Medidor",        tone: "warn", defaults: { descricao: "Medição de energia" } },
    { type: "transformador",  label: "Transformador",  tone: "accent", defaults: { primario: 13800, secundario: 380, potencia: 75 } },
  ]},
  { group: "Proteção", items: [
    { type: "disjuntor", label: "Disjuntor", tone: "warn", defaults: { corrente: 100, tipo: "Caixa Moldada", curva: "C" } },
    { type: "dr",        label: "DR / IDR",  tone: "warn", defaults: { corrente: 40, sensibilidade: 30 } },
    { type: "dps",       label: "DPS",       tone: "warn", defaults: { classe: "II", in: 20 } },
  ]},
  { group: "Distribuição", items: [
    { type: "barramento", label: "Barramento", tone: "accent", defaults: { tensao: 380, corrente: 200 } },
    { type: "quadro",     label: "Quadro QD",  tone: "accent", defaults: { circuitos: 12, padrao: "QD-01" } },
  ]},
  { group: "Cargas", items: [
    { type: "motor",      label: "Motor",          tone: "ok", defaults: { potencia: 5,   tensao: 380, fp: 0.85, descricao: "Motor 3~" } },
    { type: "iluminacao", label: "Iluminação",     tone: "ok", defaults: { potencia: 1.5, tensao: 220, fp: 0.95 } },
    { type: "tomada",     label: "TUG / TUE",      tone: "ok", defaults: { potencia: 2.5, tensao: 220, fp: 0.95 } },
    { type: "ar_cond",    label: "Ar-Cond.",       tone: "ok", defaults: { potencia: 3.5, tensao: 220, fp: 0.90 } },
    { type: "carga",      label: "Carga genérica", tone: "ok", defaults: { potencia: 2.0, tensao: 380, fp: 0.90 } },
    { type: "banco_cap",  label: "Banco Capacitor",tone: "ok", defaults: { potencia: 25,  descricao: "Correção FP" } },
  ]},
];

const TYPE_INFO = {};
PALETTE.forEach(g => g.items.forEach(it => { TYPE_INFO[it.type] = it; }));

// ─── Demanda ──────────────────────────────────────────────────────────────────
function nodePower(n) {
  const p = parseFloat(n.props?.potencia || 0);
  if (n.type === "motor") return p * 0.736;
  if (["iluminacao","tomada","ar_cond","carga"].includes(n.type)) return p;
  return 0;
}
function subtreeDemand(node, nodes) {
  let total = nodePower(node);
  nodes.filter(n => n.parent === node.id).forEach(c => { total += subtreeDemand(c, nodes); });
  return total;
}

// ─── Layout ───────────────────────────────────────────────────────────────────
function layoutTree(nodes) {
  const HSP = 140, VSP = 130;
  const byId = Object.fromEntries(nodes.map(n => [n.id, n]));
  const childrenOf = id => nodes.filter(n => n.parent === id);
  const roots = nodes.filter(n => !n.parent || !byId[n.parent]);
  const wCache = {};
  function calcW(node) {
    if (wCache[node.id]) return wCache[node.id];
    const ch = childrenOf(node.id);
    const w = ch.length === 0 ? 1 : ch.reduce((s, c) => s + calcW(c), 0);
    return (wCache[node.id] = w);
  }
  roots.forEach(r => calcW(r));
  function place(node, x, y) {
    const w = wCache[node.id];
    node.x = x + (w * HSP) / 2 - HSP / 2;
    node.y = y;
    let cx = x;
    childrenOf(node.id).forEach(c => { place(c, cx, y + VSP); cx += wCache[c.id] * HSP; });
  }
  let cursor = 0;
  roots.forEach(r => { place(r, cursor, 40); cursor += wCache[r.id] * HSP; });
  return [...nodes];
}

// ─── Auto-label ───────────────────────────────────────────────────────────────
function autoLabel(type, nodes) {
  const n = nodes.filter(x => x.type === type).length + 1;
  const map = {
    concessionaria: "CONCESSIONÁRIA",
    medidor: `MED-${String(n).padStart(2,"0")}`,
    transformador: `TR-${String(n).padStart(2,"0")}`,
    disjuntor: `DJ-${String(n).padStart(2,"0")}`,
    dr: `IDR-${String(n).padStart(2,"0")}`,
    dps: `DPS-${String(n).padStart(2,"0")}`,
    barramento: `BAR-${String(n).padStart(2,"0")}`,
    quadro: `QD-${String(n).padStart(2,"0")}`,
    motor: `M-${String(n).padStart(2,"0")}`,
    iluminacao: `IL-${String(n).padStart(2,"0")}`,
    tomada: `TUG-${String(n).padStart(2,"0")}`,
    ar_cond: `AC-${String(n).padStart(2,"0")}`,
    carga: `CG-${String(n).padStart(2,"0")}`,
    banco_cap: `BC-${String(n).padStart(2,"0")}`,
  };
  return map[type] || type.toUpperCase();
}

// ─── Diagrama de exemplo ──────────────────────────────────────────────────────
function buildSample() {
  const id = () => "n" + Math.random().toString(36).slice(2,8);
  const c   = { id:id(), type:"concessionaria", label:"CONCESSIONÁRIA", parent:null,  props:{tensao:13800,demanda:100} };
  const m   = { id:id(), type:"medidor",        label:"MED-01",         parent:c.id,  props:{} };
  const t   = { id:id(), type:"transformador",  label:"TR-01",          parent:m.id,  props:{primario:13800,secundario:380,potencia:75} };
  const dj  = { id:id(), type:"disjuntor",      label:"DJ-GERAL",       parent:t.id,  props:{corrente:125,tipo:"Caixa Moldada",curva:"C"} };
  const dps = { id:id(), type:"dps",            label:"DPS-01",         parent:dj.id, props:{classe:"II",in:20} };
  const bar = { id:id(), type:"barramento",     label:"BAR-PRINCIPAL",  parent:dps.id,props:{tensao:380,corrente:200} };
  const q1  = { id:id(), type:"quadro",         label:"QDLF-01",        parent:bar.id,props:{padrao:"Iluminação",circuitos:12} };
  const q2  = { id:id(), type:"quadro",         label:"QDF-01",         parent:bar.id,props:{padrao:"Força",circuitos:8} };
  const d1  = { id:id(), type:"disjuntor",      label:"DJ-01",          parent:q1.id, props:{corrente:20,tipo:"Din",curva:"B"} };
  const d2  = { id:id(), type:"disjuntor",      label:"DJ-02",          parent:q1.id, props:{corrente:16,tipo:"Din",curva:"B"} };
  const d3  = { id:id(), type:"disjuntor",      label:"DJ-03",          parent:q2.id, props:{corrente:32,tipo:"Din",curva:"C"} };
  const d4  = { id:id(), type:"disjuntor",      label:"DJ-04",          parent:q2.id, props:{corrente:16,tipo:"Din",curva:"B"} };
  const il  = { id:id(), type:"iluminacao",     label:"IL-01",          parent:d1.id, props:{potencia:2.5,tensao:220,fp:0.95} };
  const tu  = { id:id(), type:"tomada",         label:"TUG-01",         parent:d2.id, props:{potencia:3.0,tensao:220,fp:0.95} };
  const mo  = { id:id(), type:"motor",          label:"M-01",           parent:d3.id, props:{potencia:10,tensao:380,fp:0.85} };
  const ac  = { id:id(), type:"ar_cond",        label:"AC-01",          parent:d4.id, props:{potencia:3.5,tensao:220,fp:0.90} };
  return [c,m,t,dj,dps,bar,q1,q2,d1,d2,d3,d4,il,tu,mo,ac];
}

// ─── Ícones ───────────────────────────────────────────────────────────────────
const SvgIcon = ({ name, size=16 }) => {
  const p = { width:size, height:size, viewBox:"0 0 24 24", fill:"none",
              stroke:"currentColor", strokeWidth:1.6, strokeLinecap:"round", strokeLinejoin:"round" };
  const M = {
    undo:    <><polyline points="9 14 4 9 9 4"/><path d="M20 20v-7a4 4 0 00-4-4H4"/></>,
    redo:    <><polyline points="15 14 20 9 15 4"/><path d="M4 20v-7a4 4 0 014-4h12"/></>,
    fit:     <><polyline points="4 9 4 4 9 4"/><polyline points="20 9 20 4 15 4"/><polyline points="20 15 20 20 15 20"/><polyline points="4 15 4 20 9 20"/></>,
    download:<><path d="M12 3v12"/><polyline points="7 10 12 15 17 10"/><line x1="4" y1="21" x2="20" y2="21"/></>,
    trash:   <><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6"/><path d="M10 11v6M14 11v6"/></>,
    reload:  <><path d="M21 12a9 9 0 11-3-6.7L21 8"/><path d="M21 3v5h-5"/></>,
    info:    <><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><circle cx="12" cy="8" r=".5" fill="currentColor"/></>,
    link:    <><path d="M10 13a5 5 0 007.5.7l2-2a5 5 0 00-7-7l-1.5 1.5"/><path d="M14 11a5 5 0 00-7.5-.7l-2 2a5 5 0 007 7L13 18"/></>,
  };
  return <svg {...p}>{M[name]||null}</svg>;
};

// ─── Nó SVG ───────────────────────────────────────────────────────────────────
const W = 96, H = 96;

function footText(n, demand) {
  switch (n.type) {
    case "concessionaria": return `${n.props?.tensao ?? "—"} V`;
    case "medidor":        return "medição";
    case "transformador":  return `${n.props?.potencia ?? "—"} kVA`;
    case "disjuntor":      return `${n.props?.corrente ?? "—"} A · Cv ${n.props?.curva ?? "—"}`;
    case "dr":             return `${n.props?.corrente ?? "—"} A · ${n.props?.sensibilidade ?? "—"} mA`;
    case "dps":            return `Cl ${n.props?.classe ?? "—"} · ${n.props?.in ?? "—"} kA`;
    case "barramento":     return `${demand.toFixed(1)} kW`;
    case "quadro":         return `${demand.toFixed(1)} kW · ${n.props?.circuitos ?? "—"} circ`;
    case "motor":          return `${n.props?.potencia ?? "—"} cv`;
    case "banco_cap":      return `${n.props?.potencia ?? "—"} kVAr`;
    default:               return `${n.props?.potencia ?? "—"} kW`;
  }
}

const NodeShape = ({ node, selected, demand, onClick }) => {
  const info = TYPE_INFO[node.type];
  const tone = info?.tone || "accent";
  const glyph = GLYPHS[node.type];
  const label = node.label || info?.label || node.type;
  return (
    <g transform={`translate(${node.x - W/2},${node.y - H/2})`}
       className={`uni-node tone-${tone}${selected ? " is-sel" : ""}`}
       onClick={e => { e.stopPropagation(); onClick(node.id); }}
       style={{ cursor: "pointer" }}>
      <rect x="0" y="0" width={W} height={H} rx="8" className="uni-node-card"/>
      {/* label tab */}
      <rect x="8" y="-9" width={W-16} height="16" rx="3"
            fill="var(--bg-1,#0f1520)" stroke="var(--border,rgba(100,160,255,0.12))" strokeWidth="1"/>
      <text x={W/2} y="4" textAnchor="middle" className="uni-node-label">{label}</text>
      {/* glyph */}
      <g transform={`translate(${W/2-24},${H/2-32})`} className="uni-glyph">
        <svg viewBox="0 0 60 60" width="48" height="48"
             stroke="currentColor" strokeWidth="1.4" fill="none"
             strokeLinecap="round" strokeLinejoin="round">
          {glyph}
        </svg>
      </g>
      {/* footer */}
      <text x={W/2} y={H-7} textAnchor="middle" className="uni-node-foot">
        {footText(node, demand)}
      </text>
    </g>
  );
};

// ─── Componente principal ─────────────────────────────────────────────────────
const Unifilar = () => {
  useEffect(() => { injectCSS(); }, []);

  const [nodes, setNodes] = usePersist("vl_unifilar_v2", []);
  const [selId, setSelId] = useState(null);
  const [autoLayout, setAutoLayout] = useState(true);
  const [history, setHistory] = useState([[]]);
  const [hIdx, setHIdx] = useState(0);
  const [zoom, setZoom] = useState(0.85);
  const [pan, setPan] = useState({ x: 120, y: 80 });
  const dragRef = useRef(null);
  const stageRef = useRef(null);
  const [openGroup, setOpenGroup] = useState("Entrada");

  const selected = nodes.find(n => n.id === selId) || null;
  const demands = useMemo(() => {
    const m = {};
    nodes.forEach(n => { m[n.id] = subtreeDemand(n, nodes); });
    return m;
  }, [nodes]);
  const totalDemand = useMemo(() =>
    nodes.filter(n => !n.parent).reduce((s, r) => s + demands[r.id], 0),
    [nodes, demands]);

  const commit = useCallback((next) => {
    const out = autoLayout ? layoutTree(next.map(n => ({...n}))) : next;
    setNodes(out);
    setHistory(h => { const nh = h.slice(0, hIdx+1); nh.push(out); return nh; });
    setHIdx(i => i + 1);
  }, [autoLayout, hIdx]);

  const doUndo = () => { if (hIdx <= 0) return; const i = hIdx-1; setHIdx(i); setNodes(history[i]); };
  const doRedo = () => { if (hIdx >= history.length-1) return; const i = hIdx+1; setHIdx(i); setNodes(history[i]); };

  // Zoom & pan
  const onWheel = e => {
    e.preventDefault();
    const rect = stageRef.current.getBoundingClientRect();
    const mx = e.clientX - rect.left, my = e.clientY - rect.top;
    const factor = e.deltaY > 0 ? 0.92 : 1.09;
    const nz = Math.max(0.2, Math.min(3, zoom * factor));
    const wx = (mx - pan.x) / zoom, wy = (my - pan.y) / zoom;
    setPan({ x: mx - wx*nz, y: my - wy*nz });
    setZoom(nz);
  };
  const onMDown = e => {
    if (e.target.closest(".uni-node")) return;
    dragRef.current = { sx: e.clientX, sy: e.clientY, pan: {...pan} };
    setSelId(null);
  };
  const onMMove = e => {
    if (!dragRef.current) return;
    const dx = e.clientX - dragRef.current.sx, dy = e.clientY - dragRef.current.sy;
    setPan({ x: dragRef.current.pan.x + dx, y: dragRef.current.pan.y + dy });
  };
  const onMUp = () => { dragRef.current = null; };

  const fitToScreen = useCallback(() => {
    if (!nodes.length || !stageRef.current) return;
    const rect = stageRef.current.getBoundingClientRect();
    const xs = nodes.map(n=>n.x), ys = nodes.map(n=>n.y);
    const minX = Math.min(...xs)-70, maxX = Math.max(...xs)+70;
    const minY = Math.min(...ys)-70, maxY = Math.max(...ys)+70;
    const z = Math.min((rect.width-40)/(maxX-minX), (rect.height-80)/(maxY-minY), 1.4);
    setZoom(z);
    setPan({ x: rect.width/2 - (minX+maxX)/2*z, y: 50 - minY*z });
  }, [nodes]);

  useEffect(() => { if (nodes.length) setTimeout(fitToScreen, 80); }, []);

  // Adicionar nó
  const addNode = type => {
    const info = TYPE_INFO[type];
    const id = "n" + Math.random().toString(36).slice(2,8);
    // Escolher pai: se selecionado, usa ele; senão busca o último barramento/quadro/raiz
    let parent = selId;
    if (!parent && nodes.length) {
      const pref = [...nodes].reverse().find(n => ["barramento","quadro"].includes(n.type));
      parent = pref?.id || nodes[nodes.length-1].id;
    }
    const newNode = { id, type, label: autoLabel(type, nodes), parent: parent||null, x:0, y:0, props:{...info.defaults} };
    commit([...nodes, newNode]);
    setSelId(id);
  };

  // Deletar nó e seus filhos
  const deleteNode = id => {
    const toDelete = new Set([id]);
    let changed = true;
    while (changed) {
      changed = false;
      nodes.forEach(n => { if (n.parent && toDelete.has(n.parent) && !toDelete.has(n.id)) { toDelete.add(n.id); changed = true; } });
    }
    commit(nodes.filter(n => !toDelete.has(n.id)));
    setSelId(null);
  };

  // Atualizar nó selecionado
  const updateNode = patch => {
    if (!selId) return;
    commit(nodes.map(n => n.id === selId ? { ...n, ...patch, props: { ...n.props, ...(patch.props||{}) } } : n));
  };

  // Reparent
  const reparent = newParent => {
    if (!selId) return;
    // Evitar ciclos
    if (newParent === selId) return;
    commit(nodes.map(n => n.id === selId ? { ...n, parent: newParent||null } : n));
  };

  const clearAll = () => { if (confirm("Limpar todo o diagrama?")) { commit([]); setSelId(null); } };
  const loadSample = () => { const s = layoutTree(buildSample()); commit(s); setSelId(null); setTimeout(fitToScreen, 60); };

  const exportSVG = () => {
    const el = stageRef.current?.querySelector("svg");
    if (!el) return;
    const xml = new XMLSerializer().serializeToString(el);
    const blob = new Blob([xml], { type:"image/svg+xml" });
    const a = document.createElement("a"); a.href = URL.createObjectURL(blob); a.download = "voltlab-unifilar.svg"; a.click();
    URL.revokeObjectURL(a.href);
  };

  // Keyboard
  useEffect(() => {
    const onKey = e => {
      if (e.target.tagName === "INPUT" || e.target.tagName === "SELECT") return;
      if ((e.key === "Delete" || e.key === "Backspace") && selId) deleteNode(selId);
      if (e.key === "0") fitToScreen();
      if (e.ctrlKey && e.key === "z") { e.preventDefault(); doUndo(); }
      if (e.ctrlKey && e.key === "y") { e.preventDefault(); doRedo(); }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [selId, nodes, hIdx]);

  const connections = nodes.filter(n=>n.parent).map(n=>({ n, p: nodes.find(x=>x.id===n.parent) })).filter(c=>c.p);

  const stats = useMemo(() => {
    const m = {};
    nodes.forEach(n => { m[n.type] = (m[n.type]||0)+1; });
    return m;
  }, [nodes]);

  return (
    <div className="uni-shell">

      {/* ── PALETTE ── */}
      <aside className="uni-palette">
        <div className="uni-palette-head">
          <div className="uni-palette-eyebrow">BLOCOS</div>
          <div className="uni-palette-sub">{nodes.length} no diagrama</div>
        </div>
        <div className="uni-palette-scroll">
          {PALETTE.map(g => (
            <div key={g.group}>
              <div className="uni-pgroup-title">{g.group}</div>
              {g.items.map(it => (
                <button key={it.type}
                        className={`uni-pitem tone-${it.tone}`}
                        onClick={() => addNode(it.type)}>
                  <span className="uni-pitem-icon">
                    <svg viewBox="0 0 60 60" width="28" height="28"
                         stroke="currentColor" strokeWidth="1.4" fill="none"
                         strokeLinecap="round" strokeLinejoin="round">
                      {GLYPHS[it.type]}
                    </svg>
                  </span>
                  <span className="uni-pitem-meta">
                    <b>{it.label}</b>
                    <em>{it.tone === "ok" ? "carga" : it.tone === "warn" ? "proteção" : "infra"}</em>
                  </span>
                </button>
              ))}
            </div>
          ))}
        </div>
      </aside>

      {/* ── CANVAS ── */}
      <div className="uni-stage" ref={stageRef}
           onWheel={onWheel}
           onMouseDown={onMDown}
           onMouseMove={onMMove}
           onMouseUp={onMUp}
           onMouseLeave={onMUp}
           onContextMenu={e => e.preventDefault()}>

        {/* Top bar */}
        <div className="uni-topbar">
          <div className="uni-topbar-l">
            <span className="uni-pill">
              <span className="status-dot status-ok"/>
              {nodes.length ? `${nodes.length} blocos · ${connections.length} conexões` : "Diagrama vazio"}
            </span>
            <button className={`uni-toggle${autoLayout?" is-on":""}`}
                    onClick={() => { const next = !autoLayout; setAutoLayout(next); if (next) commit(nodes); }}>
              AUTO-LAYOUT
            </button>
          </div>
          <div className="uni-topbar-r">
            <span className="uni-coord">ZOOM <b>{(zoom*100).toFixed(0)}%</b></span>
            <button className="uni-iconbtn" title="Desfazer (Ctrl+Z)" onClick={doUndo}><SvgIcon name="undo" size={13}/></button>
            <button className="uni-iconbtn" title="Refazer (Ctrl+Y)" onClick={doRedo}><SvgIcon name="redo" size={13}/></button>
            <button className="uni-iconbtn" title="Ajustar à tela (0)" onClick={fitToScreen}><SvgIcon name="fit" size={13}/></button>
            <button className="uni-iconbtn" title="Carregar exemplo" onClick={loadSample}><SvgIcon name="reload" size={13}/></button>
            <button className="uni-btn-ghost" onClick={exportSVG}>
              <SvgIcon name="download" size={13}/> SVG
            </button>
          </div>
        </div>

        {/* SVG */}
        <svg className="uni-svg">
          <defs>
            <pattern id="uniGrid" x={pan.x%( 40*zoom)} y={pan.y%(40*zoom)} width={40*zoom} height={40*zoom} patternUnits="userSpaceOnUse">
              <path d={`M ${40*zoom} 0 L 0 0 0 ${40*zoom}`} fill="none" stroke="rgba(100,160,255,0.04)" strokeWidth="0.5"/>
            </pattern>
            <marker id="uniDot" viewBox="0 0 8 8" refX="4" refY="4" markerWidth="5" markerHeight="5">
              <circle cx="4" cy="4" r="2.5" fill="var(--accent,#3d8bff)" fillOpacity="0.6"/>
            </marker>
          </defs>
          <rect width="100%" height="100%" fill="url(#uniGrid)"/>

          <g transform={`translate(${pan.x},${pan.y}) scale(${zoom})`}>
            {/* Connections */}
            {connections.map(({n, p}, i) => {
              const dy = (n.y - p.y) / 2;
              const d = `M ${p.x} ${p.y+H/2} C ${p.x} ${p.y+H/2+dy}, ${n.x} ${n.y-H/2-dy}, ${n.x} ${n.y-H/2}`;
              const isSel = n.id === selId || p.id === selId;
              return (
                <path key={i} d={d}
                      fill="none"
                      stroke={isSel ? "var(--accent,#3d8bff)" : "rgba(100,160,255,0.2)"}
                      strokeWidth={isSel ? 1.8 : 1.2}
                      markerEnd="url(#uniDot)"
                      strokeDasharray={isSel ? "none" : "none"}/>
              );
            })}

            {/* Nodes */}
            {nodes.map(n => (
              <NodeShape key={n.id} node={n}
                         selected={selId === n.id}
                         demand={demands[n.id]||0}
                         onClick={setSelId}/>
            ))}
          </g>

          {/* Empty state */}
          {!nodes.length && (
            <g className="uni-empty-hint" transform={`translate(${(stageRef.current?.clientWidth||700)/2-140},120)`}>
              <rect width="280" height="100" rx="8"
                    fill="rgba(15,21,32,0.9)"
                    stroke="rgba(61,139,255,0.15)" strokeWidth="1" strokeDasharray="5 4"/>
              <text x="140" y="40" textAnchor="middle" fill="rgba(100,160,255,0.7)" fontSize="14">
                Adicione um bloco da paleta
              </text>
              <text x="140" y="62" textAnchor="middle" fill="rgba(61,139,255,0.4)" fontSize="11" fontFamily="JetBrains Mono">
                Comece pela CONCESSIONÁRIA
              </text>
              <text x="140" y="82" textAnchor="middle" fill="rgba(61,139,255,0.3)" fontSize="10" fontFamily="JetBrains Mono">
                ou clique em "Carregar exemplo" →
              </text>
            </g>
          )}
        </svg>

        {/* Bottom bar */}
        <div className="uni-bottombar">
          <div>BLOCOS · <b>{nodes.length}</b></div>
          <div>QUADROS · <b>{stats.quadro||0}</b></div>
          <div>CARGAS · <b>{(stats.motor||0)+(stats.iluminacao||0)+(stats.tomada||0)+(stats.ar_cond||0)+(stats.carga||0)}</b></div>
          <div>DEMANDA · <b className="readout">{totalDemand.toFixed(2)} kW</b></div>
          <div className="uni-help">DEL=remover · 0=ajustar · Ctrl+Z=desfazer · Scroll=zoom</div>
        </div>
      </div>

      {/* ── INSPECTOR ── */}
      <aside className="uni-insp">
        {selected
          ? <Inspector node={selected} nodes={nodes} demands={demands}
                       onChange={updateNode} onDelete={() => deleteNode(selected.id)}
                       onReparent={reparent}/>
          : <Overview totalDemand={totalDemand} stats={stats} onClear={clearAll}/>
        }
      </aside>
    </div>
  );
};

// ─── Inspector ────────────────────────────────────────────────────────────────
const Inspector = ({ node, nodes, demands, onChange, onDelete, onReparent }) => {
  const info = TYPE_INFO[node.type];
  const up = (key, val) => onChange({ props: { [key]: val } });
  const demand = demands[node.id] || 0;

  // Nós que podem ser pais (exceto ele mesmo e seus filhos)
  const forbidden = new Set([node.id]);
  let changed = true;
  while (changed) {
    changed = false;
    nodes.forEach(n => { if (n.parent && forbidden.has(n.parent) && !forbidden.has(n.id)) { forbidden.add(n.id); changed = true; } });
  }
  const possibleParents = nodes.filter(n => !forbidden.has(n.id));

  return (
    <div style={{display:"flex",flexDirection:"column",gap:0}}>
      <div className="uni-insp-eyebrow">SELECIONADO</div>
      <h3>{node.label}</h3>
      <div className="uni-insp-sub">{info?.label} · {node.id}</div>

      <div className="uni-section">
        <div className="uni-section-title">IDENTIFICAÇÃO</div>
        <div className="uni-field">
          <label>Tag / Identificador</label>
          <input type="text" value={node.label||""} onChange={e => onChange({label:e.target.value})}/>
        </div>
        <div className="uni-field">
          <label>Descrição</label>
          <input type="text" value={node.props?.descricao||""} onChange={e => up("descricao",e.target.value)}/>
        </div>
      </div>

      <div className="uni-section">
        <div className="uni-section-title">CONEXÃO</div>
        <div className="uni-field">
          <label>Conectado a (pai)</label>
          <select className="uni-parent-select"
                  value={node.parent||""}
                  onChange={e => onReparent(e.target.value||null)}>
            <option value="">— Sem pai (raiz) —</option>
            {possibleParents.map(n => (
              <option key={n.id} value={n.id}>{n.label} ({TYPE_INFO[n.type]?.label||n.type})</option>
            ))}
          </select>
        </div>
      </div>

      <div className="uni-section">
        <div className="uni-section-title">PARÂMETROS TÉCNICOS</div>
        {/* Concessionária */}
        {node.type === "concessionaria" && <>
          <NF label="Tensão da rede" unit="V"   val={node.props?.tensao}  onChange={v=>up("tensao",v)}/>
          <NF label="Demanda contratada" unit="kW" val={node.props?.demanda} onChange={v=>up("demanda",v)}/>
        </>}
        {/* Transformador */}
        {node.type === "transformador" && <>
          <NF label="Primário"  unit="V"   val={node.props?.primario}   onChange={v=>up("primario",v)}/>
          <NF label="Secundário" unit="V"  val={node.props?.secundario} onChange={v=>up("secundario",v)}/>
          <NF label="Potência"  unit="kVA" val={node.props?.potencia}   onChange={v=>up("potencia",v)}/>
          <NF label="Impedância" unit="%" val={node.props?.zcc}        onChange={v=>up("zcc",v)}/>
        </>}
        {/* Disjuntor */}
        {node.type === "disjuntor" && <>
          <NF label="Corrente nominal" unit="A" val={node.props?.corrente} onChange={v=>up("corrente",v)}/>
          <TF label="Tipo construtivo"         val={node.props?.tipo}     onChange={v=>up("tipo",v)}/>
          <TF label="Curva (B / C / D)"        val={node.props?.curva}    onChange={v=>up("curva",v)}/>
          <NF label="Poder de corte" unit="kA" val={node.props?.pdc}     onChange={v=>up("pdc",v)}/>
        </>}
        {/* DR */}
        {node.type === "dr" && <>
          <NF label="Corrente nominal"  unit="A"  val={node.props?.corrente}    onChange={v=>up("corrente",v)}/>
          <NF label="Sensibilidade"     unit="mA" val={node.props?.sensibilidade} onChange={v=>up("sensibilidade",v)}/>
        </>}
        {/* DPS */}
        {node.type === "dps" && <>
          <TF label="Classe (I / II / III)" val={node.props?.classe} onChange={v=>up("classe",v)}/>
          <NF label="Corrente de impulso In" unit="kA" val={node.props?.in} onChange={v=>up("in",v)}/>
          <NF label="Nível de proteção Up"  unit="kV" val={node.props?.up} onChange={v=>up("up",v)}/>
        </>}
        {/* Barramento */}
        {node.type === "barramento" && <>
          <NF label="Tensão" unit="V" val={node.props?.tensao}   onChange={v=>up("tensao",v)}/>
          <NF label="Corrente nominal" unit="A" val={node.props?.corrente} onChange={v=>up("corrente",v)}/>
        </>}
        {/* Quadro */}
        {node.type === "quadro" && <>
          <TF label="Padrão / Nome" val={node.props?.padrao}    onChange={v=>up("padrao",v)}/>
          <NF label="Nº de circuitos" unit="" val={node.props?.circuitos} onChange={v=>up("circuitos",v)}/>
        </>}
        {/* Motor */}
        {node.type === "motor" && <>
          <NF label="Potência" unit="cv"  val={node.props?.potencia} onChange={v=>up("potencia",v)}/>
          <NF label="Tensão"   unit="V"   val={node.props?.tensao}   onChange={v=>up("tensao",v)}/>
          <NF label="FP nominal" unit=""  val={node.props?.fp}       onChange={v=>up("fp",v)}/>
          <NF label="Rendimento" unit="%" val={node.props?.rend}     onChange={v=>up("rend",v)}/>
        </>}
        {/* Banco Capacitor */}
        {node.type === "banco_cap" && <>
          <NF label="Potência reativa" unit="kVAr" val={node.props?.potencia} onChange={v=>up("potencia",v)}/>
        </>}
        {/* Cargas genéricas */}
        {["iluminacao","tomada","ar_cond","carga"].includes(node.type) && <>
          <NF label="Potência ativa" unit="kW" val={node.props?.potencia} onChange={v=>up("potencia",v)}/>
          <NF label="Tensão"         unit="V"  val={node.props?.tensao}   onChange={v=>up("tensao",v)}/>
          <NF label="FP"             unit=""   val={node.props?.fp}       onChange={v=>up("fp",v)}/>
        </>}
        {/* Medidor — sem campos extras */}
        {node.type === "medidor" && <div style={{fontSize:11,color:"var(--fg-mute,#3a5070)",fontFamily:"JetBrains Mono"}}>Sem parâmetros editáveis.</div>}
        {/* Concessionária já tratada */}
      </div>

      {/* Demanda da subárvore */}
      {["barramento","quadro","disjuntor"].includes(node.type) && (
        <div className="uni-section">
          <div className="uni-section-title">DEMANDA DA SUBÁRVORE</div>
          <div className="uni-stat-grid">
            <div className="uni-stat-card">
              <span>POTÊNCIA</span>
              <b>{demand.toFixed(2)}</b> <em>kW</em>
            </div>
            <div className="uni-stat-card">
              <span>CORRENTE 3F·380V</span>
              <b>{(demand*1000/(Math.sqrt(3)*380*0.92)).toFixed(1)}</b> <em>A</em>
            </div>
          </div>
        </div>
      )}

      <button className="uni-del-btn" onClick={onDelete}>
        <SvgIcon name="trash" size={13}/> Remover e descendentes
      </button>
    </div>
  );
};

// ─── Overview (sem seleção) ───────────────────────────────────────────────────
const Overview = ({ totalDemand, stats, onClear }) => (
  <div>
    <div className="uni-insp-eyebrow">DIAGRAMA</div>
    <h3>Visão geral</h3>

    <div className="uni-section">
      <div className="uni-stat-grid">
        <div className="uni-stat-card">
          <span>DEMANDA TOTAL</span>
          <b>{totalDemand.toFixed(2)}</b> <em>kW</em>
        </div>
        <div className="uni-stat-card">
          <span>POTÊNCIA APARENTE</span>
          <b>{(totalDemand/0.92).toFixed(2)}</b> <em>kVA</em>
        </div>
        <div className="uni-stat-card" style={{gridColumn:"1/-1"}}>
          <span>CORRENTE NOMINAL (380V · 3Φ · FP 0,92)</span>
          <b>{(totalDemand*1000/(Math.sqrt(3)*380*0.92)).toFixed(1)}</b> <em>A</em>
        </div>
      </div>
    </div>

    <div className="uni-section">
      <div className="uni-section-title">CONTAGEM POR TIPO</div>
      <div className="uni-type-list">
        {Object.entries(stats).map(([t, c]) => {
          const info = TYPE_INFO[t];
          return (
            <div key={t} className={`uni-type-row tone-${info?.tone||"accent"}`}>
              <svg viewBox="0 0 60 60" width="20" height="20"
                   stroke="currentColor" strokeWidth="1.5" fill="none"
                   strokeLinecap="round" strokeLinejoin="round">
                {GLYPHS[t]}
              </svg>
              <span>{info?.label||t}</span>
              <span className="uni-type-count">{String(c).padStart(2,"0")}</span>
            </div>
          );
        })}
        {Object.keys(stats).length === 0 && (
          <div style={{fontSize:11,color:"var(--fg-mute,#3a5070)",fontFamily:"JetBrains Mono",padding:"6px 0"}}>
            Nenhum bloco adicionado.
          </div>
        )}
      </div>
    </div>

    <div className="uni-tip">
      <SvgIcon name="info" size={13}/>
      <span>Selecione um bloco para editar. Ao adicionar da paleta, o novo bloco conecta-se ao selecionado.</span>
    </div>

    {Object.keys(stats).length > 0 && (
      <button className="uni-clear-btn" onClick={onClear}>
        <SvgIcon name="trash" size={13}/> Limpar diagrama
      </button>
    )}
  </div>
);

// ─── Campos de formulário ─────────────────────────────────────────────────────
const NF = ({ label, unit, val, onChange }) => (
  <div className="uni-field-row">
    <label>{label}</label>
    <div style={{display:"flex",alignItems:"center",gap:5}}>
      <input type="number" value={val??""} step="0.01"
             onChange={e=>onChange(e.target.value)}/>
      {unit && <span className="uni-field-unit">{unit}</span>}
    </div>
  </div>
);
const TF = ({ label, val, onChange }) => (
  <div className="uni-field">
    <label>{label}</label>
    <input type="text" value={val??""} onChange={e=>onChange(e.target.value)}/>
  </div>
);

// ─── Exportar ─────────────────────────────────────────────────────────────────
window.VL_Unifilar = Unifilar;
