// ============================================================
// app.jsx · Navigator shell · routing · toggles
// ============================================================

// ---- faux backdrop behind modal showcases ----
function FauxBehind() {
  return (
    <div style={{ position: "absolute", inset: 0, padding: 36, opacity: 0.5, filter: "saturate(0.6)" }}>
      <div className="xk-card" style={{ padding: 26, maxWidth: 760, margin: "40px auto" }}>
        <Sk w={220} h={20} style={{ marginBottom: 16 }} />
        <Sk w="100%" h={11} style={{ marginBottom: 8 }} /><Sk w="80%" h={11} style={{ marginBottom: 20 }} />
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }}>
          <Sk h={48} /><Sk h={48} /><Sk h={48} /><Sk h={48} />
        </div>
      </div>
    </div>
  );
}
function ModalArtifact({ render }) {
  return (
    <div style={{ height: "100%", position: "relative", overflow: "hidden", background: "var(--xk-bg)" }}>
      <FauxBehind />
      {render(() => {})}
    </div>
  );
}

// ---- States showcase wrappers ----
function StateShowcase({ title, children }) {
  return (
    <div className="no-scrollbar" style={{ height: "100%", overflowY: "auto", background: "var(--xk-bg)" }}>
      <div style={{ maxWidth: 880, margin: "0 auto", padding: 36 }}>
        <WizardHead title={title} subtitle="Patrón reusable · se aplica en cualquier pantalla con este estado." />
        {children}
      </div>
    </div>
  );
}
function SLoadingArtifact() {
  return (
    <StateShowcase title="S-Loading · skeleton">
      <div style={{ display: "flex", flexDirection: "column", gap: 28 }}>
        <div><Eyebrow>KPIs</Eyebrow><SLoading variant="kpis" /></div>
        <div><Eyebrow>Cards</Eyebrow><SLoading variant="cards" rows={3} cols={3} /></div>
        <div><Eyebrow>Tabla</Eyebrow><SLoading variant="table" rows={4} /></div>
        <div><Eyebrow>Spinner · acción puntual</Eyebrow><div style={{ display: "flex", alignItems: "center", gap: 12 }}><Spinner /><span style={{ fontSize: 13, color: "var(--xk-text-secondary)" }}>Creando tenant…</span></div></div>
      </div>
    </StateShowcase>
  );
}
function SEmptyArtifact() {
  return (
    <StateShowcase title="S-Empty · empty state">
      <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
        <SEmpty illustration="school" title="Aún no has creado escuelas" body="Empieza con la primera · el alta toma unos 5 minutos en 3 pasos." cta="Crear primera escuela" ctaIcon="plus" />
        <SEmpty illustration="filter" title="Ninguna fila pasó la validación" body="Revisa el mapeo del paso anterior · puede que falten columnas requeridas." cta="Volver a mapear" ctaIcon="arrow-left" />
      </div>
    </StateShowcase>
  );
}
function SErrorArtifact() {
  return (
    <StateShowcase title="S-Error · error con retry">
      <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
        <SError title="No pudimos cargar las escuelas" body="Hubo un problema al conectar con el servidor. Revisa tu conexión e intenta de nuevo." technical="ERR_NETWORK · /api/v1/schools" />
        <Banner tone="danger" icon="alert-circle">Validación inline · cuando el error es de un campo, se muestra debajo del input — no en pantalla completa.</Banner>
      </div>
    </StateShowcase>
  );
}
Object.assign(window, { ModalArtifact, SLoadingArtifact, SEmptyArtifact, SErrorArtifact });

// ============================================================
// REGISTRY
// ============================================================
const REG = [
  { group: "Sysadmin · alta de escuela", role: "sysadmin", items: [
    { id: "A1", label: "Dashboard sysadmin", comp: "A1", states: ["happy", "loading", "empty", "error"] },
    { id: "A2", label: "Crear escuela · datos fiscales", comp: "A2", states: ["happy", "validation"] },
    { id: "A3", label: "Crear escuela · billing", comp: "A3", states: ["happy"] },
    { id: "A4", label: "Crear escuela · invitar director", comp: "A4", states: ["happy", "error"] },
    { id: "A5", label: "Tenant creado · celebration", comp: "A5", states: ["happy"] },
  ]},
  { group: "Director · onboarding", role: "director", items: [
    { id: "B0", label: "Welcome del director", comp: "B0", states: ["happy"] },
    { id: "B1", label: "Perfil de la escuela", comp: "B1", states: ["happy", "validation"] },
    { id: "B2", label: "Branding white-label", comp: "B2", states: ["happy", "error"] },
    { id: "B3", label: "Estructura académica", comp: "B3", states: ["happy", "empty", "error"] },
    { id: "B4", label: "Ciclo escolar", comp: "B4", states: ["happy", "empty", "validation"] },
    { id: "B5", label: "Pickup semáforo", comp: "B5", states: ["happy", "empty", "error"] },
    { id: "B6", label: "Revisión · qué incluye", comp: "B6", states: ["happy"] },
    { id: "B7", label: "Onboarding completo · celebration", comp: "B7", states: ["happy"] },
  ]},
  { group: "Sistema · modales", role: "director", items: [
    { id: "M1", label: "Confirmar · cancelar wizard", modal: c => <MConfirmCancel onClose={c} onConfirm={c} /> },
    { id: "M2", label: "Confirmar · destructivo", modal: c => <MConfirmDestructive description="Esta acción crea 26 cuentas activas y no se puede deshacer." actionLabel="Sí, importar" confirmWord="IMPORTAR" affected={614} onClose={c} onConfirm={c} /> },
    { id: "M3", label: "Import · progreso", modal: c => <MImportProgress /> },
    { id: "M4", label: "Preview · email branded", modal: c => <MPreviewEmail branded={true} onClose={c} /> },
  ]},
  { group: "Sistema · estados universales", role: "director", items: [
    { id: "S1", label: "S-Loading · skeleton", comp: "SLoadingArtifact", states: ["happy"] },
    { id: "S2", label: "S-Empty · empty state", comp: "SEmptyArtifact", states: ["happy"] },
    { id: "S3", label: "S-Error · error + retry", comp: "SErrorArtifact", states: ["happy"] },
  ]},
];
const FLAT = REG.flatMap(g => g.items);
const FLOW = ["A1","A2","A3","A4","A5","B0","B1","B2","B3","B4","B5","B6","B7"];
const STATE_LABELS = { happy: "Happy", loading: "Loading", empty: "Empty", error: "Error", validation: "Validación", sent: "Enviado" };

// ============================================================
// TourStartPill · pill flotante para iniciar/reiniciar el tour
// ============================================================
function TourStartPill({ flowKey, onStart, onDismiss }) {
  const tour = window.HABITAT_TOURS && window.HABITAT_TOURS[flowKey];
  const title = tour ? tour.title : "Tour guiado";
  const stepCount = tour ? tour.steps.length : 0;
  useEffect(() => { window.lucide && window.lucide.createIcons(); });
  return (
    <div className="animate-slide-up" style={{
      position: "fixed", bottom: 28, right: 28, zIndex: 9990,
      display: "flex", alignItems: "stretch",
      background: "#FFFFFF",
      border: "1px solid color-mix(in oklab, #88B83C 35%, transparent)",
      borderRadius: 14,
      boxShadow: "0 12px 28px rgba(15,14,12,0.18), 0 2px 6px rgba(15,14,12,0.06)",
      overflow: "hidden",
      fontFamily: "var(--xk-font-sans)",
    }}>
      <button onClick={onStart} className="xk-btn-press" style={{
        display: "flex", alignItems: "center", gap: 11,
        padding: "12px 16px 12px 14px",
        border: "none", background: "transparent", cursor: "pointer",
        textAlign: "left", fontFamily: "inherit",
      }}>
        <span style={{
          width: 32, height: 32, borderRadius: 10,
          background: "#88B83C",
          display: "inline-flex", alignItems: "center", justifyContent: "center",
          flexShrink: 0,
        }}>
          <Icon name="play" size={16} color="#FFFFFF" />
        </span>
        <span style={{ lineHeight: 1.25 }}>
          <div style={{ fontSize: 12.5, fontWeight: 600, color: "#04342C" }}>
            Iniciar tour guiado
          </div>
          <div style={{ fontSize: 10.5, color: "var(--xk-text-muted)", marginTop: 1 }}>
            {title} · {stepCount} paso{stepCount === 1 ? "" : "s"}
          </div>
        </span>
      </button>
      <button onClick={onDismiss} title="Cerrar"
        style={{
          width: 32, padding: 0, border: "none", borderLeft: "1px solid var(--xk-border)",
          background: "transparent", cursor: "pointer",
          color: "var(--xk-text-muted)",
          display: "inline-flex", alignItems: "center", justifyContent: "center",
        }}>
        <Icon name="x" size={14} />
      </button>
    </div>
  );
}

// ============================================================
// APP
// ============================================================
function App() {
  const [activeId, setActiveId] = useState("A1");
  const [stateMode, setStateMode] = useState("happy");
  const [bindMode, setBindMode] = useState("values");
  const [modal, setModal] = useState(null);
  const [navOpen, setNavOpen] = useState(true);
  const [landing, setLanding] = useState(true);
  const [revealed, setRevealed] = useState(false);
  const [support, setSupport] = useState(null);
  const [role, setRole] = useState("sysadmin");
  const [appView, setAppView] = useState("cover");
  const [pendingSection, setPendingSection] = useState(null);
  const [tourKey, setTourKey] = useState(null);      // tour activo (null = no tour corriendo)
  const [pendingTour, setPendingTour] = useState(null); // flujo que tiene tour disponible para iniciar
  const iframeRef = useRef(null);

  const ROLES = [
    { id: "sysadmin", label: "Sysadmin", sub: "Alta de escuela (Xokai)", icon: "shield", n: 1 },
    { id: "director", label: "Director · alta", sub: "Onboarding + carga", icon: "monitor", n: 2 },
    { id: "director-op", label: "Director · consola", sub: "Operación diaria", icon: "layout-dashboard", n: 3, src: "roles/director-op/index.html" },
    { id: "finanzas", label: "Finanzas", sub: "Colegiaturas · CFDI", icon: "wallet", n: 4, src: "roles/finanzas/index.html" },
    { id: "maestro", label: "Maestro", sub: "App móvil", icon: "smartphone", n: 5, src: "roles/maestro/index.html" },
    { id: "portero", label: "Portero", sub: "Kiosko pickup", icon: "scan-line", n: 6, src: "roles/portero/index.html" },
    { id: "padre", label: "Padre", sub: "App móvil", icon: "smartphone", n: 7, src: "roles/padre/index.html" },
  ];
  const activeRole = ROLES.find(r => r.id === role);
  const isConsole = role === "sysadmin" || role === "director";
  const guide = window.ROLE_GUIDE[role];
  const roleFirstId = { sysadmin: "A1", director: "B0" };
  const [frameReady, setFrameReady] = useState(false);
  function switchRole(id) {
    setRole(id);
    setAppView("cover");
    setPendingSection(null);
    setFrameReady(false);
    if (roleFirstId[id]) setActiveId(roleFirstId[id]);
  }
  // send deep-link section into the iframe
  function postSection(section) {
    if (!section) return;
    const fr = iframeRef.current;
    if (fr && fr.contentWindow) fr.contentWindow.postMessage({ type: "xk-nav", section }, "*");
  }
  // iframe announces ready → post whatever section is pending
  useEffect(() => {
    const onMsg = (e) => {
      if (e.data && e.data.type === "xk-ready") {
        setFrameReady(true);
        if (pendingSection) { postSection(pendingSection); setTimeout(() => postSection(pendingSection), 120); }
      }
    };
    window.addEventListener("message", onMsg);
    return () => window.removeEventListener("message", onMsg);
  }, [pendingSection]);
  // already-live and the section changes → post directly
  useEffect(() => {
    if (appView === "live" && frameReady && pendingSection) postSection(pendingSection);
  }, [pendingSection, frameReady, appView]);
  function enterApp(section) {
    // console roles: jump to an internal screen and go live
    if (isConsole) {
      if (section) setActiveId(section);
      else if (roleFirstId[role]) setActiveId(roleFirstId[role]);
      setAppView("live");
      return;
    }
    // null → go to the prototype's dashboard (deep-link consoles)
    const target = section || (guide && guide.deepLink ? guide.dashId : null);
    setPendingSection(target);
    setAppView("live");
  }
  useEffect(() => { if (appView !== "live") setFrameReady(false); }, [appView]);

  window.__XK_BINDMODE = bindMode;
  window.__XK_GO = setActiveId;
  window.__XK_FLOW = FLOW;
  window.__XK_CUR = activeId;
  window.enterSupport = (name) => { setSupport(name); setRole("director"); setActiveId("B0"); setAppView("live"); };
  window.__XK_SWITCHROLE = switchRole;

  // Reveal lock: after each screen mounts, force entrance animations to
  // their final visible state (robust to frozen animation timelines).
  useEffect(() => {
    setRevealed(false);
    setModal(null);
    const t = setTimeout(() => setRevealed(true), 1300);
    return () => clearTimeout(t);
  }, [activeId, stateMode, bindMode]);

  const active = FLAT.find(x => x.id === activeId);
  const openModal = (node) => setModal(node);
  openModal.close = () => setModal(null);

  // reset state when artifact changes if unsupported
  useEffect(() => {
    if (active && active.states && !active.states.includes(stateMode)) setStateMode(active.states[0]);
  }, [activeId]);

  useEffect(() => { window.lucide && window.lucide.createIcons(); });

  // keyboard nav
  useEffect(() => {
    const onKey = e => {
      if (modal) return;
      if (!isConsole || appView !== "live") return;
      if (e.target.tagName === "INPUT" || e.target.tagName === "SELECT" || e.target.tagName === "TEXTAREA") return;
      const roleItems = REG.filter(g => g.role === role).flatMap(g => g.items);
      const idx = roleItems.findIndex(x => x.id === activeId);
      if (e.key === "ArrowRight" && idx >= 0 && idx < roleItems.length - 1) setActiveId(roleItems[idx + 1].id);
      if (e.key === "ArrowLeft" && idx > 0) setActiveId(roleItems[idx - 1].id);
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [activeId, modal, role, isConsole, appView]);

  let content = null;
  if (active) {
    if (active.modal) content = <ModalArtifact render={active.modal} />;
    else {
      const Comp = window[active.comp];
      content = Comp ? <Comp state={stateMode} openModal={openModal} /> : <div style={{ padding: 40 }}>Sin componente</div>;
    }
  }

  return (
    <div style={{ display: "flex", height: "100vh", overflow: "hidden", background: "#1a1816" }}>
      {landing && <LandingHero roles={ROLES} onEnter={(flowKey) => {
        const FLOW_MAP = {
          comunicados: { role: "director-op", section: "broadcast" },
          pickup:      { role: "padre", section: "m3-pickup" },
          pagos:       { role: "padre", section: "m6-pagos" },
          maestro:     { role: "maestro", section: "m3" },
          setup:       { role: "sysadmin", section: null },
        };
        const target = FLOW_MAP[flowKey];
        if (!target) { setLanding(false); return; }
        switchRole(target.role);
        if (target.section) {
          setPendingSection(target.section);
          setAppView("live");
        } else if (target.role === "sysadmin") {
          setActiveId("A1");
          setAppView("live");
        } else {
          setAppView("live");
        }
        setLanding(false);
        // El tour NO arranca solo · queda armado como pendingTour y Norma lo inicia con el pill
        setTourKey(null);
        setPendingTour(flowKey);
      }} />}
      {pendingTour && !tourKey && (
        <TourStartPill flowKey={pendingTour}
          onStart={() => setTourKey(pendingTour)}
          onDismiss={() => setPendingTour(null)} />
      )}
      {tourKey && window.TourOverlay && (
        <window.TourOverlay
          tourKey={tourKey}
          getIframe={() => iframeRef.current}
          onFinish={() => { setTourKey(null); /* pendingTour se queda → pill vuelve a aparecer si quiere repetir */ }}
        />
      )}
      {/* Navigator rail */}
      <aside style={{ width: navOpen ? 256 : 0, flexShrink: 0, background: "var(--xk-surface)", borderRight: "1px solid var(--xk-border)", display: "flex", flexDirection: "column", transition: "width 200ms ease", overflow: "hidden" }}>
        <div style={{ padding: "14px 16px", borderBottom: "1px solid var(--xk-border)" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 12 }}>
            <button onClick={() => setLanding(true)} title="Volver al inicio" className="xk-btn-press" style={{ display: "flex", alignItems: "center", gap: 9, border: "none", background: "transparent", cursor: "pointer", padding: 0, flex: 1, textAlign: "left" }}>
              <HabitatIso size={24} />
              <div style={{ lineHeight: 1.2 }}>
                <div style={{ fontSize: 12.5, fontWeight: 700, letterSpacing: "-0.01em", color: "var(--tenant-brand-dark, #04342C)" }}>Hábitat</div>
                <div style={{ fontSize: 10, color: "var(--xk-text-muted)" }}>powered by Xokai · demo</div>
              </div>
            </button>
            <button onClick={() => setLanding(true)} title="Volver al inicio" className="xk-btn-press" style={{ flexShrink: 0, width: 28, height: 28, borderRadius: 8, border: "1px solid var(--xk-border)", background: "var(--xk-surface)", cursor: "pointer", display: "inline-flex", alignItems: "center", justifyContent: "center", color: "var(--xk-text-secondary)" }}>
              <Icon name="house" size={15} />
            </button>
          </div>
          <div className="xk-overline" style={{ fontSize: 9, marginBottom: 6, color: "var(--xk-text-muted)" }}>Rol · flujo cronológico</div>
          <div style={{ display: "flex", flexDirection: "column", gap: 3 }}>
            {ROLES.map(r => {
              const on = r.id === role;
              return (
                <button key={r.id} onClick={() => switchRole(r.id)} style={{ display: "flex", alignItems: "center", gap: 9, padding: "7px 9px", borderRadius: 8, cursor: "pointer", textAlign: "left",
                  border: "1px solid " + (on ? "var(--xk-accent)" : "var(--xk-border)"),
                  background: on ? "var(--xk-accent-light)" : "transparent" }}>
                  <span style={{ width: 18, height: 18, borderRadius: 999, flexShrink: 0, display: "inline-flex", alignItems: "center", justifyContent: "center", fontSize: 10, fontWeight: 700, fontFamily: "var(--xk-font-mono)",
                    background: on ? "var(--xk-accent)" : "var(--xk-surface-3)", color: on ? "#fff" : "var(--xk-text-muted)" }}>{r.n}</span>
                  <Icon name={r.icon} size={15} color={on ? "var(--xk-accent)" : "var(--xk-text-muted)"} />
                  <div style={{ lineHeight: 1.25 }}>
                    <div style={{ fontSize: 12, fontWeight: on ? 600 : 500, color: on ? "var(--xk-accent)" : "var(--xk-text)" }}>{r.label}</div>
                    <div style={{ fontSize: 10, color: "var(--xk-text-muted)" }}>{r.sub}</div>
                  </div>
                </button>
              );
            })}
          </div>
        </div>
        <nav className="no-scrollbar" style={{ flex: 1, overflowY: "auto", padding: "8px 10px 20px", display: isConsole ? "block" : "none" }}>
          <button onClick={() => setAppView("cover")} style={{ width: "100%", textAlign: "left", display: "flex", alignItems: "center", gap: 9, padding: "7px 8px", border: "none", borderRadius: 7, marginBottom: 4, cursor: "pointer",
            background: appView === "cover" ? "var(--xk-accent-light)" : "transparent", color: appView === "cover" ? "var(--xk-accent)" : "var(--xk-text-secondary)" }}>
            <Icon name="book-open" size={15} color={appView === "cover" ? "var(--xk-accent)" : "var(--xk-text-muted)"} />
            <span style={{ fontSize: 12.5, fontWeight: appView === "cover" ? 600 : 500 }}>Portada · guía</span>
          </button>
          {REG.filter(g => g.role === role).map((g, gi) => (
            <div key={gi} style={{ marginTop: gi === 0 ? 4 : 14 }}>
              <div className="xk-overline" style={{ fontSize: 9.5, padding: "6px 8px", color: "var(--xk-text-muted)" }}>{g.group}</div>
              {g.items.map(it => {
                const on = appView === "live" && it.id === activeId;
                return (
                  <button key={it.id} onClick={() => { setActiveId(it.id); setAppView("live"); }} style={{ width: "100%", textAlign: "left", display: "flex", alignItems: "center", gap: 9, padding: "6px 8px", border: "none", borderRadius: 7, marginBottom: 1, cursor: "pointer",
                    background: on ? "var(--xk-accent-light)" : "transparent", color: on ? "var(--xk-accent)" : "var(--xk-text-secondary)" }}>
                    <span className="xk-mono" style={{ fontSize: 10, fontWeight: 600, width: 30, flexShrink: 0, color: on ? "var(--xk-accent)" : "var(--xk-text-muted)" }}>{it.id}</span>
                    <span style={{ fontSize: 12.5, fontWeight: on ? 600 : 400, lineHeight: 1.3 }}>{it.label}</span>
                  </button>
                );
              })}
            </div>
          ))}
        </nav>
        {!isConsole && guide && (
          <nav className="no-scrollbar" style={{ flex: 1, overflowY: "auto", padding: "8px 10px 20px" }}>
            <div style={{ marginTop: 4 }}>
              <div className="xk-overline" style={{ fontSize: 9.5, padding: "6px 8px", color: "var(--xk-text-muted)" }}>{guide.title}</div>
              <button onClick={() => setAppView("cover")} style={{ width: "100%", textAlign: "left", display: "flex", alignItems: "center", gap: 9, padding: "7px 8px", border: "none", borderRadius: 7, marginBottom: 2, cursor: "pointer",
                background: appView === "cover" ? "var(--xk-accent-light)" : "transparent", color: appView === "cover" ? "var(--xk-accent)" : "var(--xk-text-secondary)" }}>
                <Icon name="book-open" size={15} color={appView === "cover" ? "var(--xk-accent)" : "var(--xk-text-muted)"} />
                <span style={{ fontSize: 12.5, fontWeight: appView === "cover" ? 600 : 500 }}>Portada · guía</span>
              </button>
              <button onClick={() => enterApp(null)} style={{ width: "100%", textAlign: "left", display: "flex", alignItems: "center", gap: 9, padding: "7px 8px", border: "none", borderRadius: 7, marginBottom: 2, cursor: "pointer",
                background: appView === "live" && !pendingSection ? "var(--xk-accent-light)" : "transparent", color: appView === "live" && !pendingSection ? "var(--xk-accent)" : "var(--xk-text-secondary)" }}>
                <Icon name="play" size={15} color={appView === "live" && !pendingSection ? "var(--xk-accent)" : "var(--xk-text-muted)"} />
                <span style={{ fontSize: 12.5, fontWeight: 500 }}>Entrar al prototipo</span>
              </button>
            </div>
            {guide.deepLink && guide.sections.length > 0 && (
              <div style={{ marginTop: 14 }}>
                <div className="xk-overline" style={{ fontSize: 9.5, padding: "6px 8px", color: "var(--xk-text-muted)" }}>Pantallas</div>
                {guide.sections.map((s, i) => {
                  const on = appView === "live" && pendingSection === s.id;
                  return (
                    <button key={i} onClick={() => enterApp(s.id)} style={{ width: "100%", textAlign: "left", display: "flex", alignItems: "center", gap: 9, padding: "6px 8px", border: "none", borderRadius: 7, marginBottom: 1, cursor: "pointer",
                      background: on ? "var(--xk-accent-light)" : "transparent", color: on ? "var(--xk-accent)" : "var(--xk-text-secondary)" }}>
                      <Icon name={s.icon} size={14} color={on ? "var(--xk-accent)" : "var(--xk-text-muted)"} />
                      <span style={{ fontSize: 12.5, fontWeight: on ? 600 : 400, lineHeight: 1.3 }}>{s.label}</span>
                    </button>
                  );
                })}
              </div>
            )}
            {!guide.deepLink && (
              <div style={{ marginTop: 12, padding: "10px 10px", fontSize: 11, color: "var(--xk-text-muted)", lineHeight: 1.5 }}>
                Este prototipo trae su propia navegación interna · entra y explora desde su menú.
              </div>
            )}
          </nav>
        )}
        <div style={{ padding: "10px 14px", borderTop: "1px solid var(--xk-border)", fontSize: 10.5, color: "var(--xk-text-muted)" }}>
          {isConsole ? "← → para navegar" : (appView === "cover" ? "Portada · guía de venta" : "Prototipo en vivo")}
        </div>
      </aside>

      {/* Main */}
      <div style={{ flex: 1, display: "flex", flexDirection: "column", minWidth: 0 }}>
        {/* Top control bar */}
        <div style={{ height: 48, flexShrink: 0, display: "flex", alignItems: "center", gap: 12, padding: "0 16px", background: "#23201d", color: "#e7e5e0" }}>
          <button onClick={() => setNavOpen(!navOpen)} style={{ border: "none", background: "transparent", cursor: "pointer", color: "#bdb9b2", display: "inline-flex" }}><Icon name="panel-left" size={18} /></button>
          {isConsole ? (
            appView === "cover" ? (
              <span style={{ display: "inline-flex", alignItems: "center", gap: 8, fontSize: 13, fontWeight: 600 }}>
                <Icon name="book-open" size={15} color="#bdb9b2" />Hábitat · {activeRole.label} · portada
              </span>
            ) : (
              <React.Fragment>
                <span className="xk-mono" style={{ fontSize: 11, color: "#8a867e" }}>{active && active.id}</span>
                <span style={{ fontSize: 13, fontWeight: 600 }}>{active && active.label}</span>
              </React.Fragment>
            )
          ) : (
            <span style={{ display: "inline-flex", alignItems: "center", gap: 8, fontSize: 13, fontWeight: 600 }}>
              <Icon key={appView === "cover" ? "book-open" : activeRole.icon} name={appView === "cover" ? "book-open" : activeRole.icon} size={15} color="#bdb9b2" />
              Hábitat · {activeRole.label}{appView === "cover" ? " · portada" : (pendingSection ? " · " + pendingSection : "")}
            </span>
          )}

          <div style={{ flex: 1 }}></div>

          {/* state segmented — web console only */}
          {isConsole && appView === "live" && active && active.states && active.states.length > 1 && (
            <div style={{ display: "inline-flex", background: "#15130f", borderRadius: 8, padding: 3, gap: 2 }}>
              {active.states.map(s => (
                <button key={s} onClick={() => setStateMode(s)} style={{ border: "none", cursor: "pointer", padding: "4px 11px", borderRadius: 6, fontSize: 11.5, fontWeight: 500,
                  background: stateMode === s ? "var(--xk-accent)" : "transparent", color: stateMode === s ? "#fff" : "#bdb9b2" }}>{STATE_LABELS[s]}</button>
              ))}
            </div>
          )}

          {/* bind toggle — web console only */}
          {isConsole && (
            <button onClick={() => setBindMode(bindMode === "values" ? "tokens" : "values")} style={{ display: "inline-flex", alignItems: "center", gap: 7, padding: "5px 11px", borderRadius: 8, cursor: "pointer", fontSize: 11.5, fontWeight: 500,
              border: "1px solid " + (bindMode === "tokens" ? "var(--xk-accent)" : "#3a3631"),
              background: bindMode === "tokens" ? "var(--xk-accent)" : "transparent", color: "#fff", fontFamily: "var(--xk-font-mono)" }}>
              <Icon name="braces" size={14} />{bindMode === "tokens" ? "Variables" : "Valores"}
            </button>
          )}
        </div>

        {/* Canvas */}
        <div style={{ flex: 1, position: "relative", overflow: "hidden", background: "var(--xk-bg)", display: "flex", flexDirection: "column" }}>
          {!isConsole ? (
            <div className={revealed ? "xk-revealed" : ""} style={{ flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }}>
              {appView === "cover"
                ? <RoleCover key={role} guide={guide} roleId={role} onEnter={() => enterApp(null)} onSection={(s) => enterApp(s)} />
                : <iframe ref={iframeRef} key={role} src={activeRole.src} title={activeRole.label}
                    onLoad={() => { if (pendingSection) { postSection(pendingSection); setTimeout(() => postSection(pendingSection), 400); } }}
                    style={{ flex: 1, width: "100%", height: "100%", border: "none", background: "#0E0D11" }}></iframe>}
            </div>
          ) : appView === "cover" ? (
            <div className={revealed ? "xk-revealed" : ""} style={{ flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }}>
              <RoleCover key={role} guide={guide} roleId={role} onEnter={() => enterApp(null)} onSection={(s) => enterApp(s)} />
            </div>
          ) : (
          <React.Fragment>
          {support && /^(I|AD|RE|MC)/.test(activeId) && (
            <div style={{ flexShrink: 0, display: "flex", alignItems: "center", gap: 10, padding: "8px 18px", background: "var(--xk-warning-tint)", borderBottom: "1px solid color-mix(in oklab, var(--xk-warning) 30%, transparent)", color: "var(--xk-warning)", fontSize: 12.5, fontWeight: 600 }}>
              <Icon name="shield-alert" size={15} />
              Modo soporte · {support} · estás viendo el tenant como Xokai
              <span style={{ flex: 1 }}></span>
              <button onClick={() => { setSupport(null); setRole("sysadmin"); setActiveId("A1"); }} style={{ border: "none", background: "transparent", cursor: "pointer", color: "var(--xk-warning)", fontWeight: 600, fontSize: 12.5, display: "inline-flex", alignItems: "center", gap: 4 }}>Salir <Icon name="arrow-right" size={13} /></button>
            </div>
          )}
          <div style={{ flex: 1, position: "relative", overflow: "hidden" }}>
            <div key={activeId + stateMode + bindMode} className={revealed ? "xk-revealed" : ""} style={{ height: "100%" }}>
              {content}
            </div>
            {modal && <div className="xk-revealed" style={{ position: "absolute", inset: 0 }}>{modal}</div>}
          </div>
          </React.Fragment>
          )}
        </div>
      </div>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
