diff --git a/docs/UI-UX-WINDOWS.md b/docs/UI-UX-WINDOWS.md
index dde6d0b..e0b77ea 100644
--- a/docs/UI-UX-WINDOWS.md
+++ b/docs/UI-UX-WINDOWS.md
@@ -118,10 +118,41 @@ openDialog({
**selección múltiple** (checkbox), fila con **hover** y **estado seleccionado** (`accent/.14`), y
**clic derecho** que abre el menú contextual de esa fila (ver §6). Alternativa por fila sin mouse
derecho: botón `⋯` que abre el mismo menú.
-- **Master-Detail (Split View)** — patrón **nativo de Windows** (Correo, Configuración, Explorador):
- lista angosta a la izquierda + panel de detalle a la derecha que se actualiza **en el sitio** al
- seleccionar un ítem, sin modal. Preferir sobre "detalle en modal" cuando la pantalla es
- principalmente de exploración/lectura de una lista larga.
+- **DetailPopup** — patrón **por defecto** para ver/crear/editar el detalle de un ítem de un listado
+ de gestión (proyectos, actividades, usuarios, catálogos, etc.). Overlay que cubre la ventana y deja
+ **inactivo el listado detrás** (dim + sin interacción) mientras se usa el popup — a diferencia de un
+ panel lateral o de un panel apilado debajo del listado, el detalle NUNCA reduce ni empuja el
+ listado, y siempre aparece completo y en el mismo lugar sin importar el largo de la lista ni la
+ fila elegida. Reglas duras:
+ - **Nunca se cierra con clic afuera** (a diferencia de `Flyout`) — solo con el botón "Cerrar" de su
+ cabecera o una acción explícita del formulario (`Guardar`/`Cancelar`).
+ - **Alto FIJO por instancia**, no se ajusta al contenido: si el popup tiene pestañas o secciones
+ internas (p. ej. Info/Comentarios/Documentos), cambiar entre ellas **nunca** cambia el tamaño del
+ popup — solo el contenido interno hace scroll. El ancho/alto se elige según cuánto contenido
+ espera esa pantalla (un formulario simple de 2 campos no necesita el mismo alto que un detalle
+ con subtareas y dependencias), pero una vez abierto queda fijo.
+ - Header propio: título a la izquierda, botón "Cerrar" (ícono `X`) a la derecha.
+ - Contrato (React; adaptar al framework del proyecto):
+ `{contenido}` — portal a
+ `document.body` (igual que `Flyout`/`ContentDialog`), **nunca** anidado dentro del árbol de la
+ página, para no quedar atrapado en el stacking context de un ancestro y terminar tapado por otro
+ overlay (bug real: sin portal, un `ContentDialog` abierto DESDE un `DetailPopup` quedaba oculto
+ detrás de este). Jerarquía de `z-index` entre overlays: `Flyout` (100) < `DetailPopup` (200) <
+ `ContentDialog` (250) < `Toast` (300) — así una confirmación abierta desde dentro de un
+ `DetailPopup` siempre queda por encima.
+ - Secciones internas relacionadas con el ítem (ej. una actividad con Info + Subtareas +
+ Dependencias + Comentarios + Documentos) van cada una en **su propia pestaña** dentro del popup,
+ nunca todas apiladas dentro de la pestaña "Info" — mismo criterio que pestañas reales a nivel de
+ pantalla completa (ver identidad web `UI-UX-LINKEDCORP.md`), aplicado ahora dentro del popup.
+- **Master-Detail (Split View)** — patrón **nativo de Windows** (Correo, Explorador): lista angosta a
+ la izquierda + panel de detalle a la derecha que se actualiza **en el sitio** al seleccionar un
+ ítem, sin modal. Uso **restringido**: solo para pantallas cuya función principal es explorar/leer
+ una lista larga como actividad central de esa vista (no para listados de gestión con acciones
+ crear/editar — ahí va `DetailPopup`). Evitar cualquier variante que ubique el detalle "a un costado"
+ o "debajo" de un listado de gestión (panel lateral fijo, panel acoplado al borde, panel apilado
+ bajo la tabla): en la práctica el detalle se siente secundario y el listado pierde protagonismo o
+ queda "lejos" del detalle cuando la lista crece. Ante la duda entre Master-Detail y `DetailPopup`
+ para un listado de gestión, usar `DetailPopup`.
- **Menú contextual (clic derecho)** — el patrón de interacción **más característico de Windows**:
ítems con ícono + label + acelerador de teclado a la derecha (`Ctrl+E`, `Del`…), separadores,
submenú con flecha `▸` que se expande al pasar el mouse, ítem destructivo en `danger`. Debe estar
@@ -226,11 +257,14 @@ Alt+Tab); si es una decisión puntual ligada al contexto actual, es un `ContentD
1. **CommandBar** (`Nuevo`, `Actualizar`, acciones contextuales + overflow `···`).
2. **Elegir el patrón de datos** según el caso:
+ - **Listado + `DetailPopup`** (default para listados de gestión: proyectos, actividades, usuarios,
+ catálogos…): al hacer clic en una fila u optar "Nuevo", se abre un `DetailPopup` (overlay de
+ tamaño fijo, listado inactivo detrás, nunca se cierra con clic afuera) con el detalle/formulario
+ y sus acciones (`Guardar`, `Editar`, `Eliminar`). El listado se ve completo e intacto en cuanto
+ se cierra el popup.
- **Listado + Master-Detail**: lista con selección simple a la izquierda/arriba, detalle **en el
- sitio** a la derecha/abajo. Preferido cuando el usuario navega/lee mucho (correo, catálogos).
- - **Listado + ContentDialog de detalle**: al hacer clic en una fila se abre un `ContentDialog`
- (o una ventana secundaria si el contenido es largo) con el detalle y acciones (`Editar`,
- `Eliminar`). Preferido cuando el detalle es ocasional y la lista debe verse completa mientras se usa.
+ sitio** a la derecha/abajo, sin modal. Reservado para pantallas cuya función principal es
+ explorar/leer una lista larga (correo) — no para listados de gestión con crear/editar.
3. **Selección múltiple + acciones por lote**: casillas en la columna izquierda de la tabla; la barra
de estado muestra "`N` de `M` seleccionados"; las acciones de lote aparecen en la `CommandBar`
solo cuando hay selección.
@@ -261,11 +295,16 @@ Alt+Tab); si es una decisión puntual ligada al contexto actual, es un `ContentD
con el resto de Windows.
- ✅ Radios de esquina consistentes: `4px` controles, `8px` superficies elevadas y la ventana misma.
- ✅ Un solo set de íconos en toda la app (Lucide o Segoe Fluent Icons), heredando color del contexto.
-- ✅ Master-Detail para listas de exploración; `ContentDialog`/ventana secundaria para detalle ocasional.
+- ✅ `DetailPopup` (tamaño fijo, nunca se cierra con clic afuera) para ver/crear/editar el detalle de
+ un ítem de un listado de gestión; Master-Detail solo para pantallas de exploración/lectura pura.
- ✅ Foco visible solo con teclado (`:focus-visible`); hover visible siempre (mouse-first).
- ❌ `MessageBox`/`alert`/`confirm` del sistema. ❌ combos/selects/calendarios nativos sin estilar.
❌ mezclar sets de íconos. ❌ apilar listado + formulario + detalle en una sola pantalla sin
- separación clara. ❌ usar `Toast` para pedir una decisión al usuario.
+ separación clara. ❌ usar `Toast` para pedir una decisión al usuario. ❌ panel de detalle lateral o
+ debajo del listado en pantallas de gestión (usar `DetailPopup`). ❌ que un `DetailPopup` cambie de
+ tamaño al moverse entre sus pestañas/secciones internas. ❌ montar `ContentDialog`/`DetailPopup` sin
+ portal a `document.body` (queda atrapado en el stacking context de un ancestro y puede terminar
+ tapado por otro overlay).
> Para que una app "se sienta Windows moderna": misma barra de título, mismo panel de navegación,
> mismos cuatro mecanismos de aviso (`ContentDialog`/`InfoBar`/`Toast`/`Flyout`) bien diferenciados,
diff --git a/frontend/src/components/ContentDialog.jsx b/frontend/src/components/ContentDialog.jsx
index 4795452..4e53f26 100644
--- a/frontend/src/components/ContentDialog.jsx
+++ b/frontend/src/components/ContentDialog.jsx
@@ -1,3 +1,4 @@
+import { createPortal } from 'react-dom';
import { useUi } from '../context/ui-context.jsx';
import { Button } from './Button.jsx';
@@ -17,8 +18,11 @@ export function ContentDialogHost() {
if (!action.keepOpen) closeDialog();
}
- return (
-
{ if (e.target === e.currentTarget) closeDialog(); }}>
+ // Regla dura: NUNCA se cierra con clic afuera (a diferencia de Flyout) — solo con un boton.
+ // Portal a document.body (igual que Flyout/DetailPopup): garantiza que quede SIEMPRE por
+ // encima de cualquier DetailPopup abierto, sin depender del punto del arbol donde se monta.
+ return createPortal(
+
@@ -33,6 +37,7 @@ export function ContentDialogHost() {
))}
-
+
,
+ document.body
);
}
diff --git a/frontend/src/components/DetailPopup.jsx b/frontend/src/components/DetailPopup.jsx
new file mode 100644
index 0000000..28a0f0c
--- /dev/null
+++ b/frontend/src/components/DetailPopup.jsx
@@ -0,0 +1,25 @@
+import { createPortal } from 'react-dom';
+import { X } from 'lucide-react';
+
+// Popup grande para ver/editar el detalle de un elemento de un listado (reemplaza el patron
+// "panel debajo del listado"). Reglas duras:
+// 1. NUNCA se cierra con clic afuera del popup — solo con el boton "Cerrar" de su header o una
+// accion explicita del formulario (ej. Guardar/Cancelar).
+// 2. Alto FIJO (no se ajusta al contenido): moverse entre pestañas/secciones internas del popup
+// (ej. Info/Comentarios/Documentos) nunca debe cambiar su tamaño — solo el contenido interno
+// hace scroll. `height` es fijo por instancia; ajustar via prop segun cuanto contenido espera.
+export function DetailPopup({ open, title, onClose, children, width = 720, height = 640 }) {
+ if (!open) return null;
+ return createPortal(
+
+
+
+
{title}
+
+
+
{children}
+
+
,
+ document.body
+ );
+}
diff --git a/frontend/src/pages/Configuracion/CatalogEditor.jsx b/frontend/src/pages/Configuracion/CatalogEditor.jsx
index 816e9fd..839c44e 100644
--- a/frontend/src/pages/Configuracion/CatalogEditor.jsx
+++ b/frontend/src/pages/Configuracion/CatalogEditor.jsx
@@ -8,6 +8,7 @@ import { Button } from '../../components/Button.jsx';
import { Field, FieldRow } from '../../components/Field.jsx';
import { ComboBox } from '../../components/ComboBox.jsx';
import { Badge } from '../../components/Badge.jsx';
+import { DetailPopup } from '../../components/DetailPopup.jsx';
const COLOR_OPTIONS = ['accent', 'success', 'warning', 'danger', 'muted'].map((c) => ({ value: c, label: c }));
@@ -93,35 +94,33 @@ export function CatalogEditor({ catalogKey, fields, title }) {
]}
/>
- {editing && (
-