// Árbol de Proyectos — interactive tree with detail panel

const ProjectNode = ({ project, expanded, expandedEpics, selectedId, onToggle, onToggleEpic,
  onSelect, onCycleStatus, onAddEpic, onAddUs, onDelete, onRenameUs, onRenameEpic, onRenameProject }) => {
  const pct = window.computeProjectPct(project);
  return (
    <div className={"tree-node-project" + (selectedId === project.id ? " selected" : "")} style={{ "--proj-color": project.color }}>
      <div className={"tn-row" + (expanded ? " expanded" : "")} onClick={() => onToggle(project.id)}>
        <span className="chev"><Icon name="chevronRight" size={11} /></span>
        <span className="csq" />
        <span
          className="name"
          contentEditable
          suppressContentEditableWarning
          onClick={(e) => e.stopPropagation()}
          onBlur={(e) => onRenameProject(project.id, e.target.innerText.trim())}
          onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); e.target.blur(); } }}
        >{project.name}</span>
        <span className="area-meta">{project.area}</span>
        <TipoTag tipo={project.tipo} />
        <span onClick={(e) => { e.stopPropagation(); onCycleStatus("project", project.id); }}>
          <StatusBadge status={project.status} />
        </span>
        <span className="pct">{pct}%</span>
        <span className="tn-actions" onClick={(e) => e.stopPropagation()}>
          <button className="icon-btn" title="Añadir epic" onClick={() => onAddEpic(project.id)}><Icon name="plus" size={13} /></button>
          <button className="icon-btn" title="Detalles" onClick={() => onSelect({ kind: "project", id: project.id, projectId: project.id })}><Icon name="target" size={13} /></button>
        </span>
      </div>
      {expanded && (
        <div className="tn-children">
          {(project.epics || []).map((epic) => (
            <EpicNode
              key={epic.id}
              epic={epic}
              project={project}
              expanded={!!expandedEpics[epic.id]}
              selectedId={selectedId}
              onToggleEpic={onToggleEpic}
              onSelect={onSelect}
              onCycleStatus={onCycleStatus}
              onAddUs={onAddUs}
              onDelete={onDelete}
              onRenameUs={onRenameUs}
              onRenameEpic={onRenameEpic}
            />
          ))}
          <button className="add-child" onClick={() => onAddEpic(project.id)}>
            <Icon name="plus" size={11} /> Añadir epic
          </button>
        </div>
      )}
    </div>
  );
};

const EpicNode = ({ epic, project, expanded, selectedId, onToggleEpic, onSelect, onCycleStatus, onAddUs, onDelete, onRenameUs, onRenameEpic }) => {
  const pct = window.computeEpicPct(epic);
  return (
    <div className="tn-epic">
      <div className={"epic-row" + (expanded ? " expanded" : "")} onClick={() => onToggleEpic(epic.id)}>
        <span className="chev"><Icon name="chevronRight" size={11} /></span>
        <span
          className="name"
          contentEditable
          suppressContentEditableWarning
          onClick={(e) => e.stopPropagation()}
          onBlur={(e) => onRenameEpic(project.id, epic.id, e.target.innerText.trim())}
          onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); e.target.blur(); } }}
        >{epic.name}</span>
        <span onClick={(e) => { e.stopPropagation(); onCycleStatus("epic", epic.id, project.id); }}>
          <StatusBadge status={epic.status} />
        </span>
        <span className="pct">{pct}%</span>
        <span className="tn-actions" onClick={(e) => e.stopPropagation()}>
          <button className="icon-btn" title="Añadir actividad" onClick={() => onAddUs(project.id, epic.id)}><Icon name="plus" size={12} /></button>
          <button className="icon-btn" title="Detalles" onClick={() => onSelect({ kind: "epic", id: epic.id, projectId: project.id })}><Icon name="target" size={12} /></button>
          <button className="icon-btn" title="Eliminar" onClick={() => onDelete("epic", project.id, epic.id)}><Icon name="close" size={12} /></button>
        </span>
      </div>
      {expanded && (
        <div className="us-children">
          {(epic.userStories || []).map((u) => {
            const dot = window.STATUS_DOT_COLOR[u.status] || "#94A3B8";
            const sel = selectedId === u.id;
            return (
              <div
                key={u.id}
                className={"tn-us" + (u.status === "completado" ? " done" : "")}
                style={sel ? { background: "rgba(96,165,250,.10)" } : null}
                onClick={() => onSelect({ kind: "us", id: u.id, epicId: epic.id, projectId: project.id })}
              >
                <span className="udot" style={{ background: dot, boxShadow: `0 0 6px ${dot}` }} />
                <span
                  className="name"
                  contentEditable
                  suppressContentEditableWarning
                  onClick={(e) => e.stopPropagation()}
                  onBlur={(e) => onRenameUs(project.id, epic.id, u.id, e.target.innerText.trim())}
                  onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); e.target.blur(); } }}
                >{u.name}</span>
                {u.deadline && u.status !== "completado" && (
                  <span className="deadline">⚡ {window.fmtShortDate(u.deadline)}</span>
                )}
                <span onClick={(e) => { e.stopPropagation(); onCycleStatus("us", u.id, project.id, epic.id); }}>
                  <StatusBadge status={u.status} />
                </span>
                <span className="tn-actions" onClick={(e) => e.stopPropagation()}>
                  <button className="icon-btn" title="Detalles" onClick={() => onSelect({ kind: "us", id: u.id, epicId: epic.id, projectId: project.id })}><Icon name="target" size={11} /></button>
                  <button className="icon-btn" title="Eliminar" onClick={() => onDelete("us", project.id, epic.id, u.id)}><Icon name="close" size={11} /></button>
                </span>
              </div>
            );
          })}
          {(epic.userStories || []).length === 0 && (
            <div style={{ fontSize: 10, color: "var(--text-2)", padding: "6px 8px", fontStyle: "italic" }}>
              Sin actividades — clic + para añadir
            </div>
          )}
          <button className="add-child" onClick={() => onAddUs(project.id, epic.id)} style={{ marginTop: 4 }}>
            <Icon name="plus" size={11} /> Añadir actividad
          </button>
        </div>
      )}
    </div>
  );
};

// -------- Detail Panel --------
const DetailPanel = ({ selection, projects, onClose, onUpdate, onDelete, onSelect, style }) => {
  if (!selection) return null;
  const entity = React.useMemo(() => {
    const p = projects.find((x) => x.id === selection.projectId || x.id === selection.id);
    if (selection.kind === "project") return { kind: "project", project: p, data: p };
    if (selection.kind === "epic") {
      const e = p?.epics.find((x) => x.id === selection.id);
      return { kind: "epic", project: p, epic: e, data: e };
    }
    if (selection.kind === "us") {
      const e = p?.epics.find((x) => x.id === selection.epicId);
      const u = e?.userStories.find((x) => x.id === selection.id);
      return { kind: "us", project: p, epic: e, us: u, data: u };
    }
    return null;
  }, [selection, projects]);

  const [draft, setDraft] = React.useState({});
  React.useEffect(() => { setDraft({ ...(entity?.data || {}) }); }, [entity?.data?.id]);

  if (!entity || !entity.data) return null;
  const kindColor = entity.kind === "project" ? entity.project.color
    : entity.kind === "epic" ? "#A78BFA" 
    : (window.STATUS_DOT_COLOR[draft.status] || "#94A3B8");
  const kindLabel = entity.kind === "project" ? "Proyecto"
    : entity.kind === "epic" ? "Epic" : "Actividad";

  const save = () => {
    onUpdate(entity.kind, {
      projectId: entity.project.id,
      epicId: entity.epic?.id,
      id: entity.data.id,
    }, draft);
  };

  return (
    <div className="detail-panel" style={{ "--kind-color": kindColor, ...style }}>
      <div className="dp-head">
        <div>
          <div className="dp-kind"><span className="ksq" /> {kindLabel}</div>
          <div style={{ fontSize: 13, fontWeight: 700, marginTop: 6, color: "var(--text-1)" }}>{draft.name || entity.data.name}</div>
          {entity.kind !== "project" && (
            <div style={{ fontSize: 10, color: "var(--text-2)", marginTop: 4 }}>
              <span 
                className="breadcrumb-link" 
                onClick={() => onSelect({ kind: "project", id: entity.project.id, projectId: entity.project.id })}
              >
                {entity.project?.name}
              </span>
              {entity.epic && entity.kind === "us" && (
                <>
                  {" · "}
                  <span 
                    className="breadcrumb-link" 
                    onClick={() => onSelect({ kind: "epic", id: entity.epic.id, projectId: entity.project.id })}
                  >
                    {entity.epic.name}
                  </span>
                </>
              )}
            </div>
          )}
        </div>
        <button className="icon-btn" onClick={onClose}><Icon name="close" /></button>
      </div>
      <div className="dp-body">
        <div className="dp-field">
          <label>Nombre</label>
          <div
            contentEditable
            suppressContentEditableWarning
            onBlur={(e) => setDraft({ ...draft, name: e.target.innerText.trim() })}
          >{draft.name || ""}</div>
        </div>

        <div className="dp-field">
          <label>Status</label>
          <div className="dp-status-row">
            {window.STATUS_OPTIONS.map((s) => (
              <span
                key={s.key}
                className={"badge " + s.className + (draft.status === s.key ? " selected" : "")}
                onClick={() => setDraft({ ...draft, status: s.key })}
                style={{ cursor: "pointer", opacity: draft.status === s.key ? 1 : .55 }}
              >{s.label}</span>
            ))}
          </div>
        </div>

        {entity.kind === "project" && (
          <>
            <div className="dp-field">
              <label>Área</label>
              <select value={draft.area || ""} onChange={(e) => setDraft({ ...draft, area: e.target.value })}>
                {window.AREAS.map((a) => <option key={a} value={a}>{a}</option>)}
              </select>
            </div>
            <div className="dp-field">
              <label>Tipo</label>
              <select value={draft.tipo || ""} onChange={(e) => setDraft({ ...draft, tipo: e.target.value })}>
                {window.TIPO_OPTIONS.map((t) => <option key={t.key} value={t.key}>{t.label}</option>)}
              </select>
            </div>
            <div className="dp-field">
              <label>Color del proyecto</label>
              <input type="text" value={draft.color || ""} onChange={(e) => setDraft({ ...draft, color: e.target.value })} />
            </div>
          </>
        )}

        <div className="field-row">
          <div className="dp-field">
            <label>Inicio</label>
            <input type="date" value={draft.start || ""} onChange={(e) => setDraft({ ...draft, start: e.target.value })} />
          </div>
          <div className="dp-field">
            <label>Fin</label>
            <input type="date" value={draft.end || (entity.kind === "us" ? draft.deadline : "") || ""} onChange={(e) => setDraft({ ...draft, end: e.target.value, deadline: e.target.value })} />
          </div>
        </div>

        <div className="dp-field">
          <label>Notas</label>
          <textarea value={draft.notas || ""} onChange={(e) => setDraft({ ...draft, notas: e.target.value })} placeholder="Añade contexto, criterios de aceptación, links…" />
        </div>

        {entity.kind === "us" && (
          <div className="dp-field">
            <label>Criterios de aceptación</label>
            <textarea value={draft.criterios || ""} onChange={(e) => setDraft({ ...draft, criterios: e.target.value })} placeholder="• Criterio 1&#10;• Criterio 2" />
          </div>
        )}

        {entity.kind !== "project" && (
          <div className="dp-field">
            <label>Archivos / Links</label>
            <input type="text" value={draft.links || ""} onChange={(e) => setDraft({ ...draft, links: e.target.value })} placeholder="https://…" />
          </div>
        )}
      </div>
      <div className="dp-foot">
        <button className="btn-primary" onClick={save}>Guardar cambios</button>
        <button className="btn-secondary" onClick={onClose}>Cerrar</button>
        {entity.kind !== "project" && (
          <button className="btn-danger" style={{ marginLeft: "auto" }} onClick={() => {
            onDelete(entity.kind, entity.project.id, entity.epic?.id, entity.data.id);
            onClose();
          }}>Eliminar</button>
        )}
      </div>
    </div>
  );
};

// -------- GraphView --------
const GraphView = ({ projects, expanded, expandedEpics, selectedId, onToggle, onToggleEpic, onSelect }) => {
  const PROJ_W = 260, PROJ_H = 72;
  const EPIC_W = 220, EPIC_H = 56;
  const US_W = 200, US_H = 40;
  const COL_GAP = 90;
  const V_GAP = 14;
  const PAD = 28;
  const HEADER_H = 40; // height of the column-label strip at top
  const [hoverSubtree, setHoverSubtree] = React.useState(null);

  const projX = PAD;
  const epicX = PAD + PROJ_W + COL_GAP;
  const usX = epicX + EPIC_W + COL_GAP;

  // Layout pass: compute y positions — start below the header strip
  const positions = {};
  let yCursor = PAD + HEADER_H;
  projects.forEach((p) => {
    const projTop = yCursor;
    let blockH = PROJ_H;
    const isOpen = expanded[p.id];
    if (isOpen && p.epics?.length) {
      let epicCursor = yCursor;
      p.epics.forEach((e) => {
        const epicTop = epicCursor;
        let epicBlock = EPIC_H;
        const epicOpen = expandedEpics[e.id];
        if (epicOpen && e.userStories?.length) {
          let usCursor = epicTop;
          e.userStories.forEach((u) => {
            positions[u.id] = { x: usX, y: usCursor, w: US_W, h: US_H, parentId: e.id, projectId: p.id, kind: "us" };
            usCursor += US_H + V_GAP;
          });
          epicBlock = Math.max(EPIC_H, usCursor - epicTop - V_GAP);
        }
        const epicNodeY = epicTop + Math.max(0, (epicBlock - EPIC_H) / 2);
        positions[e.id] = { x: epicX, y: epicNodeY, w: EPIC_W, h: EPIC_H, parentId: p.id, projectId: p.id, kind: "epic" };
        epicCursor += epicBlock + V_GAP;
      });
      blockH = Math.max(PROJ_H, epicCursor - projTop - V_GAP);
    }
    const projNodeY = projTop + Math.max(0, (blockH - PROJ_H) / 2);
    positions[p.id] = { x: projX, y: projNodeY, w: PROJ_W, h: PROJ_H, projectId: p.id, kind: "project" };
    yCursor += blockH + V_GAP;
  });

  const canvasW = usX + US_W + PAD;
  const canvasH = yCursor + PAD;

  // Column header spec
  const COL_HEADERS = [
    { x: projX, w: PROJ_W, label: "PROYECTOS", accent: "var(--azul-profundo)" },
    { x: epicX, w: EPIC_W, label: "EPICS",      accent: "var(--purpura)" },
    { x: usX,   w: US_W,   label: "ACTIVIDADES",accent: "var(--teal)" },
  ];

  const curve = (a, b) => {
    const x1 = a.x + a.w, y1 = a.y + a.h / 2;
    const x2 = b.x,        y2 = b.y + b.h / 2;
    const dx = Math.max(40, (x2 - x1) * 0.55);
    return `M${x1},${y1} C${x1 + dx},${y1} ${x2 - dx},${y2} ${x2},${y2}`;
  };

  return (
    <div className="graph-canvas-wrap">
      <div className="graph-canvas" style={{ width: canvasW, height: canvasH }}>

        {/* ── Column headers ── */}
        {COL_HEADERS.map(({ x, w, label, accent }) => (
          <div
            key={label}
            style={{
              position: "absolute",
              left: x, top: 0,
              width: w, height: HEADER_H,
              display: "flex", flexDirection: "column",
              alignItems: "center", justifyContent: "center",
              gap: 4,
              pointerEvents: "none",
            }}
          >
            <span style={{
              fontSize: 9, fontWeight: 800, letterSpacing: ".12em",
              textTransform: "uppercase", color: accent,
              padding: "2px 10px", borderRadius: 999,
              background: accent + "18",
              border: `1px solid ${accent}30`,
            }}>
              {label}
            </span>
            <span style={{
              display: "block", width: 1, height: 8,
              background: "var(--border-subtle)",
            }} />
          </div>
        ))}

        <svg className="graph-svg" width={canvasW} height={canvasH}>
          {projects.map((p) => {
            if (!expanded[p.id]) return null;
            const pPos = positions[p.id];
            const highlight = hoverSubtree === p.id;
            const color = p.color;
            return (p.epics || []).map((e) => {
              const ePos = positions[e.id];
              if (!ePos) return null;
              return (
                <path
                  key={"l-" + e.id}
                  d={curve(pPos, ePos)}
                  className={"graph-line" + (highlight ? " hl" : "")}
                  style={highlight ? { stroke: color } : null}
                />
              );
            });
          })}
          {projects.map((p) => {
            if (!expanded[p.id]) return null;
            const highlight = hoverSubtree === p.id;
            const color = p.color;
            return (p.epics || []).map((e) => {
              if (!expandedEpics[e.id]) return null;
              const ePos = positions[e.id];
              return (e.userStories || []).map((u) => {
                const uPos = positions[u.id];
                if (!uPos) return null;
                return (
                  <path
                    key={"l-" + u.id}
                    d={curve(ePos, uPos)}
                    className={"graph-line" + (highlight ? " hl" : "")}
                    style={highlight ? { stroke: color } : null}
                  />
                );
              });
            });
          })}
        </svg>

        {projects.map((p) => {
          const pos = positions[p.id];
          return (
            <div
              key={p.id}
              className={"graph-node graph-proj" + (selectedId === p.id ? " selected" : "") + (expanded[p.id] ? " open" : "")}
              style={{ left: pos.x, top: pos.y, width: pos.w, height: pos.h, "--proj-color": p.color }}
              onClick={() => onToggle(p.id)}
              onMouseEnter={() => setHoverSubtree(p.id)}
              onMouseLeave={() => setHoverSubtree(null)}
            >
              <span className="gn-csq" />
              <div className="gn-content">
                <div className="gn-name">{p.name}</div>
                <div className="gn-meta-row">
                  <span className="gn-meta">{p.area}</span>
                  <StatusBadge status={p.status} />
                </div>
              </div>
              <button className="gn-detail abs" title="Detalles" onClick={(ev) => { ev.stopPropagation(); onSelect({ kind: "project", id: p.id }); }}>
                <Icon name="target" size={11} />
              </button>
            </div>
          );
        })}

        {projects.map((p) => {
          if (!expanded[p.id]) return null;
          return (p.epics || []).map((e) => {
            const pos = positions[e.id];
            if (!pos) return null;
            const pct = window.computeEpicPct(e);
            return (
              <div
                key={e.id}
                className={"graph-node graph-epic" + (selectedId === e.id ? " selected" : "") + (expandedEpics[e.id] ? " open" : "")}
                style={{ left: pos.x, top: pos.y, width: pos.w, height: pos.h, "--proj-color": p.color }}
                onClick={() => onToggleEpic(e.id)}
                onMouseEnter={() => setHoverSubtree(p.id)}
                onMouseLeave={() => setHoverSubtree(null)}
              >
                <div className="gn-content">
                  <div className="gn-name">{e.name}</div>
                  <div className="gn-meta-row">
                    <StatusBadge status={e.status} />
                    <span className="gn-pct">{pct}%</span>
                  </div>
                </div>
                <button className="gn-detail abs" title="Detalles" onClick={(ev) => { ev.stopPropagation(); onSelect({ kind: "epic", id: e.id, projectId: p.id }); }}>
                  <Icon name="target" size={11} />
                </button>
              </div>
            );
          });
        })}

        {projects.map((p) => {
          if (!expanded[p.id]) return null;
          return (p.epics || []).map((e) => {
            if (!expandedEpics[e.id]) return null;
            return (e.userStories || []).map((u) => {
              const pos = positions[u.id];
              if (!pos) return null;
              const dot = window.STATUS_DOT_COLOR[u.status] || "#94A3B8";
              const trimmed = u.name.length > 28 ? u.name.slice(0, 28) + "…" : u.name;
              return (
                <div
                  key={u.id}
                  className={"graph-node graph-us" + (selectedId === u.id ? " selected" : "") + (u.status === "completado" ? " done" : "")}
                  style={{ left: pos.x, top: pos.y, width: pos.w, height: pos.h, "--proj-color": p.color }}
                  onClick={() => onSelect({ kind: "us", id: u.id, epicId: e.id, projectId: p.id })}
                  onMouseEnter={() => setHoverSubtree(p.id)}
                  onMouseLeave={() => setHoverSubtree(null)}
                  title={u.name}
                >
                  <span className="gn-udot" style={{ background: dot, boxShadow: `0 0 6px ${dot}` }} />
                  <div className="gn-name us-name">{trimmed}</div>
                  <StatusBadge status={u.status} />
                </div>
              );
            });
          });
        })}
      </div>
    </div>
  );
};

// -------- TreeView root --------
const TreeView = ({ projects, setProjects, selection, setSelection, onAddProject, onAddEpic, onAddUs }) => {
  const [expanded, setExpanded] = React.useState(() => Object.fromEntries(projects.map((p) => [p.id, true])));
  const [expandedEpics, setExpandedEpics] = React.useState(() => {
    const e = {};
    for (const p of projects) for (const ep of p.epics || []) e[ep.id] = ep.status === "en-progreso";
    return e;
  });
  const [viewMode, setViewMode] = React.useState("lista");
  const toast = window.useToast();

  const toggle = (id) => setExpanded((s) => ({ ...s, [id]: !s[id] }));
  const toggleEpic = (id) => setExpandedEpics((s) => ({ ...s, [id]: !s[id] }));

  const cycleStatus = (kind, id, pid, eid) => {
    const order = ["backlog", "pendiente", "planeado", "en-progreso", "completado", "on-hold"];
    setProjects((prev) => prev.map((p) => {
      if (kind === "project" && p.id === id) {
        const i = order.indexOf(p.status);
        return { ...p, status: order[(i + 1) % order.length] };
      }
      if (p.id !== pid && kind !== "project") return p;
      return {
        ...p,
        epics: p.epics.map((e) => {
          if (kind === "epic" && e.id === id) {
            const i = order.indexOf(e.status);
            return { ...e, status: order[(i + 1) % order.length] };
          }
          if (kind === "us" && e.id === eid) {
            return {
              ...e,
              userStories: e.userStories.map((u) => {
                if (u.id !== id) return u;
                const i = order.indexOf(u.status);
                return { ...u, status: order[(i + 1) % order.length] };
              }),
            };
          }
          return e;
        }),
      };
    }));
    toast.push("Status actualizado");
  };

  const renameProject = (id, name) => {
    if (!name) return;
    setProjects((prev) => prev.map((p) => p.id === id ? { ...p, name } : p));
  };
  const renameEpic = (pid, eid, name) => {
    if (!name) return;
    setProjects((prev) => prev.map((p) => p.id !== pid ? p : { ...p, epics: p.epics.map((e) => e.id === eid ? { ...e, name } : e) }));
  };
  const renameUs = (pid, eid, uid, name) => {
    if (!name) return;
    setProjects((prev) => prev.map((p) => p.id !== pid ? p : {
      ...p,
      epics: p.epics.map((e) => e.id !== eid ? e : {
        ...e,
        userStories: e.userStories.map((u) => u.id === uid ? { ...u, name } : u),
      }),
    }));
  };

  const onDelete = (kind, pid, eid, uid) => {
    if (kind === "epic") {
      if (!confirm("¿Eliminar epic? Esta acción no se puede deshacer.")) return;
      setProjects((prev) => prev.map((p) => p.id !== pid ? p : { ...p, epics: p.epics.filter((e) => e.id !== eid) }));
      toast.push("Epic eliminado", { color: "var(--rojo-suave)", icon: "close" });
    } else if (kind === "us") {
      setProjects((prev) => prev.map((p) => p.id !== pid ? p : {
        ...p,
        epics: p.epics.map((e) => e.id !== eid ? e : { ...e, userStories: e.userStories.filter((u) => u.id !== uid) }),
      }));
      toast.push("Actividad eliminada", { color: "var(--rojo-suave)", icon: "close" });
    }
  };

  const onUpdate = (kind, refs, draft) => {
    const { projects: next, error } = window.updateHierarchyDates(projects, kind, refs.id, draft, toast);
    
    if (error) {
      toast.push(`⚠️ Error: ${error}`, { color: "#B3393E", icon: "error" });
      return;
    }

    setProjects(next);
    toast.push("Cambios guardados");
  };

  const [panelOffset, setPanelOffset] = React.useState(0);

  const handleSelect = (sel) => {
    setSelection(sel);
    // Align panel to the top of the current viewport
    const treeLayout = document.querySelector(".tree-layout");
    if (treeLayout) {
      const scrollY = window.scrollY || document.documentElement.scrollTop;
      const layoutTop = treeLayout.offsetTop;
      // We want the panel to start at the current scroll, but at least at the top of the layout
      // and taking into account the header/tabs (approx 130px)
      const offset = Math.max(0, scrollY - layoutTop + 20); 
      setPanelOffset(offset);
    }
  };


  const selectedId = selection?.id;

  return (
    <>
      <div className="view-header">
        <div>
          <div className="view-title">Árbol de Proyectos</div>
          <div className="view-sub">Jerarquía Proyecto → Epic → Actividad · clic para expandir · doble clic para renombrar</div>
        </div>
        <div className="row gap-sm">
          <div className="seg-toggle" role="tablist" aria-label="Modo de visualización">
            <button
              role="tab"
              aria-selected={viewMode === "lista"}
              className={"seg-btn" + (viewMode === "lista" ? " active" : "")}
              onClick={() => setViewMode("lista")}
            >
              <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round">
                <line x1="4" y1="7" x2="20" y2="7"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="17" x2="20" y2="17"/>
              </svg>
              Lista
            </button>
            <button
              role="tab"
              aria-selected={viewMode === "grafo"}
              className={"seg-btn" + (viewMode === "grafo" ? " active" : "")}
              onClick={() => setViewMode("grafo")}
            >
              <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                <polygon points="12 3 20 8 20 16 12 21 4 16 4 8 12 3"/>
              </svg>
              Grafo
            </button>
          </div>
          <button className="btn-secondary" onClick={() => {
            const all = Object.fromEntries(projects.map((p) => [p.id, true]));
            setExpanded(all);
            const allE = {};
            for (const p of projects) for (const ep of (p.epics || [])) allE[ep.id] = true;
            setExpandedEpics(allE);
          }}>Expandir todo</button>
          <button className="btn-secondary" onClick={() => {
            setExpanded({});
            setExpandedEpics({});
          }}>Colapsar todo</button>
          <button className="btn-primary" onClick={onAddProject}><Icon name="plus" size={12} /> Nuevo proyecto</button>
        </div>
      </div>

      <div className={"tree-layout" + (selection ? "" : " no-detail")}>
        {viewMode === "lista" ? (
          <div className="tree-container">
            {/* Nivel legend strip */}
            <div style={{
              display: "flex", alignItems: "center", gap: 6,
              padding: "6px 12px 10px",
              fontSize: 9, fontWeight: 700, letterSpacing: ".1em",
              textTransform: "uppercase",
            }}>
              {[
                { label: "Proyecto",    color: "var(--azul-profundo)" },
                { label: "→",           color: "var(--text-3)", fw: 400, ls: 0 },
                { label: "Epic",        color: "var(--purpura)" },
                { label: "→",           color: "var(--text-3)", fw: 400, ls: 0 },
                { label: "Actividad",   color: "var(--teal)" },
              ].map(({ label, color, fw, ls }, i) => (
                <span key={i} style={{
                  color, fontWeight: fw || 700,
                  letterSpacing: ls !== undefined ? ls : ".1em",
                  padding: fw ? "0" : "2px 8px",
                  borderRadius: 999,
                  background: fw ? "transparent" : color + "18",
                  border: fw ? "none" : `1px solid ${color}30`,
                }}>{label}</span>
              ))}
            </div>
            {projects.map((p) => (
              <ProjectNode
                key={p.id}
                project={p}
                expanded={!!expanded[p.id]}
                expandedEpics={expandedEpics}
                selectedId={selectedId}
                onToggle={toggle}
                onToggleEpic={toggleEpic}
                onSelect={handleSelect}
                onCycleStatus={cycleStatus}
                onAddEpic={onAddEpic}
                onAddUs={onAddUs}
                onDelete={onDelete}
                onRenameProject={renameProject}
                onRenameEpic={renameEpic}
                onRenameUs={renameUs}
              />
            ))}
          </div>
        ) : (
          <GraphView
            projects={projects}
            expanded={expanded}
            expandedEpics={expandedEpics}
            selectedId={selectedId}
            onToggle={toggle}
            onToggleEpic={toggleEpic}
            onSelect={handleSelect}
          />
        )}
        {selection && (
          <DetailPanel
            selection={selection}
            projects={projects}
            onClose={() => setSelection(null)}
            onUpdate={onUpdate}
            onDelete={onDelete}
            onSelect={handleSelect}
            style={{ marginTop: panelOffset }}
          />
        )}
      </div>
    </>
  );
};

Object.assign(window, { TreeView, DetailPanel, GraphView });
