/* utilities-extension.css — Extensiones del framework EBCGG v3
   Justificación: completa familias existentes (z, max-h, bg) + agrega
   positioning utilities (left/top) faltantes. Cada clase tiene >2 usos
   en código productivo y completa un pattern existente.
   Carga DESPUÉS de ebcgg.min.css. */

/* z-index — completa eb-z-{1,50} */
.eb-z-0    { z-index: 0; }
.eb-z-10   { z-index: 10; }

/* positioning — pattern absolute overlay top:0; left:0 */
.eb-left-0   { left: 0; }
.eb-top-0    { top: 0; }
.eb-top-full { top: 100%; }   /* dropdown alignment */
.eb-top-1-2  { top: 50%; }    /* vertical center reference */

/* max-height — completa eb-max-h-{180,280} */
.eb-max-h-240 { max-height: 240px; }
.eb-max-h-360 { max-height: 360px; }

/* background — completa eb-bg-{surface,surface-2,bg} */
.eb-bg-border      { background: var(--eb-border); }
.eb-bg-transparent { background: transparent; }

/* Pase 2 (2026-05-02 sprint inline cleanup):
   eb-dropdown-panel — patrón típico de menu desplegable bajo trigger
   (8+ usos en buyers/NewRequest, RequestDetail, exportbrazil dropdowns).
   No componible con utilities existentes (faltaba eb-right-0). */
.eb-dropdown-panel {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 50;
  max-height: 240px;
  overflow-y: auto;
  background: var(--eb-surface);
  border: 1px solid var(--eb-border);
  border-radius: var(--eb-radius);
  box-shadow: var(--eb-shadow-md);
  margin-top: 4px;
}

/* positioning utilities — completan eb-left-0, eb-top-0 existentes */
.eb-right-0  { right: 0; }
.eb-bottom-0 { bottom: 0; }

/* inset shorthand (top:0; right:0; bottom:0; left:0) — patrón overlay */
.eb-inset-0 {
  top: 0; right: 0; bottom: 0; left: 0;
}

/* Pase 3 inline cleanup (2026-05-02):
   eb-min-h-row — altura estándar de input/button row (38px ≈ form-input height).
   Justificación: 8+ usos en buyers/NewRequest, RequestDetail, suppliers/NewProduct
   para alinear toggles y dropdown triggers con form-input. No componible. */
.eb-min-h-row { min-height: 38px; }

/* Square icon containers — patrón container fixed-size para emoji/icon centrado.
   8+ usos en buyers/NewRequest (commodity picker), exportbrazil (commodity grid). */
.eb-square-36 { width: 36px; height: 36px; flex-shrink: 0; }
.eb-square-48 { width: 48px; height: 48px; flex-shrink: 0; }

/* Icon column en option lists (16px width + center align) — checkmarks en dropdowns.
   6+ usos en NewRequest. No componible (16px arbitrario). */
.eb-icon-col { width: 16px; text-align: center; flex-shrink: 0; }

/* Dropdown panels con max-height variables. Extiende eb-dropdown-panel.
   Para dropdowns con muchos items necesitan más altura que el default 240. */
.eb-dropdown-panel-lg { max-height: 360px; }
.eb-dropdown-panel-xl { max-height: 480px; }

/* eb-rounded-none — borderRadius: 0 explícito (botones segmentados, etc.) */
.eb-rounded-none { border-radius: 0; }

/* Pase 3 (2026-05-27 port-watch page):
   eb-w-44 — width fijo 180px para inputs numéricos cortos (cargo MT en
   PortsPage finder). Patrón reusable de "input para un número de hasta
   6 dígitos". Justificación reuse-before-create: NO existe ningún
   eb-w-{N} en el framework excepto eb-w-12 (48px) y eb-w-full.
   Sin esta clase, queda style={{maxWidth:180}} inline. */
.eb-w-44 { width: 180px; }

/* Pase 4 (2026-05-27 PortsPage filters/grids):
   Completar la responsividad inconsistente de eb-grid-N — el framework base
   define eb-grid-{2,5} para colapsar a 1fr en mobile pero NO eb-grid-{3,4,6}.
   Esta extensión cierra el gap. Sin esta regla, grids de 3/4/6 columnas
   quedan apretados en celular en vez de apilarse. */
@media (max-width: 768px) {
  .eb-grid-3, .eb-grid-4, .eb-grid-6 { grid-template-columns: 1fr; }
}

/* Pase 5 (2026-05-28 HeaderPublic en /welcome pre-auth):
   eb-fixed — position: fixed. Necesario para headers que viven sobre
   contenido centrado (.public-page) sin afectar el flex layout. */
.eb-fixed { position: fixed; }

/* Pase 6 (2026-05-28 LoiInbox · revisar/editar/confirmar quote):
   eb-field-modified — resalta visualmente un form-field cuyo valor
   difiere del original (texto accent + border-left dorado).
   modal-body — contenedor scroll dentro del modal para evitar que
   el footer del form quede oculto detrás de la barra del SO. */
.eb-field-modified > .form-label,
.eb-field-modified .form-label,
.eb-field-modified > span:first-child { color: var(--eb-accent-hover); font-weight: 600; }
.eb-field-modified input,
.eb-field-modified select,
.eb-field-modified textarea,
.eb-field-modified .form-input,
.eb-field-modified .form-select { border-color: var(--eb-accent); box-shadow: 0 0 0 1px var(--eb-accent-hover); }

/* DocDetailDrawer body — scroll interno + altura controlada para que
   el footer del modal nunca quede oculto. modal ya define max-height:88vh;
   acá lo bajamos a 82vh y movemos el footer fuera del scroll. */
.eb-doc-detail { max-height: 82vh; display: flex; flex-direction: column; padding-bottom: 0; }
.eb-doc-detail > .modal-header { flex-shrink: 0; }
.eb-doc-detail-body { overflow-y: auto; flex: 1; padding-right: 4px; }
.eb-doc-detail-body > .modal-footer { background: var(--eb-surface); position: sticky; bottom: 0; margin-top: var(--eb-space-3); padding-top: var(--eb-space-3); border-top: 1px solid var(--eb-border-light); }

/* form-row-3 ya existe; agrego form-row-2 como alias semántico para 2 cols
   (form-row solo era el default). Sirve para clarity en los wrappers. */
.form-row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--eb-space-3); }

/* Pase 7 (2026-05-28 LoiQuoteEditor · página dedicada full-screen):
   eb-loi-editor — wrapper de la página con padding inferior generoso
   para que el sticky footer no tape contenido al hacer scroll.
   eb-loi-footer — barra de acciones sticky al pie del viewport, igual
   patrón que usa SCDEditor (acciones siempre visibles aunque scrolleés). */
.eb-loi-editor { padding: var(--eb-space-4); padding-bottom: 100px; max-width: 1400px; margin: 0 auto; }
.eb-loi-footer {
  position: sticky; bottom: 0; left: 0; right: 0;
  background: var(--eb-surface);
  border-top: 1px solid var(--eb-border-light);
  padding: var(--eb-space-3) var(--eb-space-4);
  margin: var(--eb-space-4) calc(-1 * var(--eb-space-4)) 0;
  display: flex; justify-content: flex-end; gap: var(--eb-space-2);
  z-index: 10;
  box-shadow: 0 -4px 12px rgba(0,0,0,0.04);
}

/* Footer fijo DESACTIVADO (2026-05-29): el footer fijo de 50px (Pase 8) tapaba
   el último elemento de cada página (ej. el botón "Crear RFQ y continuar" del
   RFQBuilder) y no aportaba valor — era un placeholder vacío sin contenido.
   Revertido al layout anterior SIN footer: se oculta el elemento y se elimina
   la reserva de padding-bottom. El <footer class="eb-footer"> sigue en el DOM
   (lo renderiza el componente Footer compartido) pero queda oculto/sin efecto. */
.eb-footer { display: none; }
.eb-loi-footer { bottom: 0; }

/* Fix scroll del app-shell (2026-05-29): .eb-main tenía `min-height:100vh`
   (con overflow-y:auto), lo que NO acota la altura → el contenedor crece con el
   contenido y el área queda "calculada más alta que el viewport", dejando el
   final de las páginas largas (ej. botón "Crear RFQ") fuera del área visible /
   sin scroll fiable. Con altura ACOTADA (100dvh) + el overflow-y:auto que ya
   tiene, .eb-main es un scroll-container correcto: el sidebar queda fijo y el
   contenido scrollea internamente hasta el final. 100dvh maneja bien la barra
   de URL en mobile; 100vh de fallback. Sólo seteamos `height` (no toca el
   min-height ni el overflow del bundle). */
.eb-main { height: 100vh; height: 100dvh; }

/* eb-page-actions (2026-05-29): barra de acción al pie de un formulario de
   página (.eb-page), con el botón de submit (ej. "Crear RFQ y continuar").
   EN FLUJO NORMAL (no fixed): antes era position:fixed bottom:0, lo que pegaba
   el botón al borde inferior del viewport — justo la franja que la barra de
   tareas del SO tapa cuando la ventana es alta → el botón quedaba cortado y el
   scroll no lo movía (los fixed no scrollean). Ahora es un bloque normal al
   final del contenido, y .eb-page reserva 120px DEBAJO (el "row" inferior), de
   modo que al scrollear hasta el fondo el botón queda ~120px por encima del
   borde inferior, dentro del área visible y nunca tapado. */
.eb-page-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--eb-space-2);
  margin-top: var(--eb-space-4);
  padding-top: var(--eb-space-3);
  border-top: 1px solid var(--eb-border-light);
}
.eb-page:has(.eb-page-actions) { padding-bottom: 120px; }

/* Pase 9 (2026-05-28 LoiQuoteEditor · validación required SCO):
   eb-field-required-missing — resalta visualmente un form-field requerido
   que está vacío. Border + label rojos suaves. Convive con
   eb-field-modified (los obligatorios vacíos ganan por specificity de
   orden: la clase missing va después del fldCls de modified). */
.eb-field-required-missing > .form-label,
.eb-field-required-missing .form-label,
.eb-field-required-missing > span:first-child { color: var(--eb-danger-text); font-weight: 600; }
.eb-field-required-missing input,
.eb-field-required-missing select,
.eb-field-required-missing textarea,
.eb-field-required-missing .form-input,
.eb-field-required-missing .form-select { border-color: var(--eb-danger-text); box-shadow: 0 0 0 1px var(--eb-danger-bg); }

/* Pase 10 (2026-05-28 audit coherencia pipeline):
   utilities faltantes detectadas en la auditoría de framework. */
.eb-whitespace-pre-wrap { white-space: pre-wrap; }
.eb-list-disc { list-style: disc; }

/* Pase 11 (2026-05-29 ficha técnica · TechSpecSheet):
   eb-tip — tooltip de hover CSS-only para celdas con texto de atribución.
   Justificación reuse-before-create: range-tooltip es para sliders (posición
   fija, sin trigger de hover); acá se necesita un tooltip activado por :hover
   sobre celda de tabla con texto multilinea ("Modificado por X · fecha"). No
   componible con lo existente. Uso: <span class="eb-tip" data-tip="...">v</span> */
.eb-tip { position: relative; cursor: help; }
.eb-tip::after {
  content: attr(data-tip);
  position: absolute; bottom: calc(100% + 6px); left: 50%;
  transform: translateX(-50%);
  background: var(--eb-text-1); color: #fff;
  padding: 6px 9px; border-radius: var(--eb-radius-sm);
  font-size: 11px; font-weight: 500; line-height: 1.35;
  white-space: pre; text-align: left;
  max-width: 320px; width: max-content;
  box-shadow: 0 4px 14px rgba(0,0,0,0.22);
  opacity: 0; visibility: hidden; transition: opacity 0.12s;
  z-index: var(--eb-z-tooltip); pointer-events: none;
}
.eb-tip::before {
  content: ''; position: absolute; bottom: calc(100% + 2px); left: 50%;
  transform: translateX(-50%);
  border: 4px solid transparent; border-top-color: var(--eb-text-1);
  opacity: 0; visibility: hidden; transition: opacity 0.12s;
  z-index: var(--eb-z-tooltip); pointer-events: none;
}
.eb-tip:hover::after, .eb-tip:hover::before { opacity: 1; visibility: visible; }

/* eb-spec-modified — celda de ficha técnica con override (resalta el valor). */
.eb-spec-modified {
  background: var(--eb-warning-bg);
  border-bottom: 1px dashed var(--eb-accent);
  font-weight: 700;
}
.eb-spec-modified-mark { color: var(--eb-accent); font-size: 0.85em; margin-left: 2px; }

/* min-width:0 — para items de grid/flex que contienen un hijo con scroll
   horizontal (carrusel de certs/docs); sin esto el item usa min-width:auto y se
   expande rompiendo el grid. */
.eb-min-w-0 { min-width: 0; }

/* badge-success — estado cerrado/firmado/pagado (verde). Reusa tokens de éxito
   del framework; no existía un badge verde y es semánticamente necesario para
   timelines de operaciones (SPA firmado, comisión pagada). Agregado 2026-05-30. */
.badge-success { background: var(--eb-success-bg); color: var(--eb-success-text); }

/* ── Validación de formularios (onboard Fase C) ───────────────────────────
   Justificación reuse-before-create: estado visual "campo requerido pendiente"
   no componible con utilities de color existentes (necesita border+shadow+focus
   coordinados sobre input/select/textarea). Aplicado por React al intentar avanzar. */
.eb-input-error,
.eb-input-error:focus {
  border-color: var(--eb-danger-text) !important;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--eb-danger-text) 22%, transparent) !important;
}
/* eb-pl-4: completa la escala eb-pl-N (faltaba el step 4=16px) para listas de la card */
.eb-pl-4 { padding-left: var(--eb-space-4); }
/* checkbox/radio rows requeridos sin completar: borde visible alrededor del row */
.form-check.eb-input-error {
  border: 1px solid var(--eb-danger-text);
  border-radius: var(--eb-radius-md);
  padding: var(--eb-space-2);
}

/* ── Monitor de ramas SCO (gestion /sco-multibranch) ──
   reuse-before-create: pt-* ausente del set (existen py-*/px-*/p-* pero no pt-*);
   detail-list = grid clave/valor reutilizable para paneles de detalle;
   timeline = reset de lista para feeds de eventos. */
.eb-pt-2 { padding-top: var(--eb-space-2); }
.eb-pt-3 { padding-top: var(--eb-space-3); }
.eb-detail-list { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; margin: 0; align-items: baseline; }
.eb-detail-list dt { color: var(--eb-muted); white-space: nowrap; display: flex; align-items: center; gap: 4px; }
.eb-detail-list dd { margin: 0; }
.eb-timeline { list-style: none; margin: 0; padding: 0; }
/* texto clickeable que semánticamente es <button> (no <a>): reset + look de link.
   reuse-before-create: no existe primitiva de button-as-link en el master. */
.eb-linkbtn { background: none; border: none; padding: 0; font: inherit; color: var(--eb-primary); cursor: pointer; text-align: left; }
.eb-linkbtn:hover { text-decoration: underline; }
/* Banner de impersonación superadmin: fijo abajo, siempre visible, no tapa el nav superior. */
.eb-imp-banner { position: fixed; left: 0; right: 0; bottom: 0; z-index: 9999; margin: 0; border-radius: 0; box-shadow: 0 -2px 12px rgba(0,0,0,.18); }

/* Nodos fantasma (deal-chain): gris claro en reposo, se pintan al hover.
   reuse-before-create: estado "placeholder accionable que revela su acento al hover"
   no componible (transición coordinada de border+texto+fondo). */
.eb-ghost { display: block; width: 100%; font-family: inherit; background: var(--eb-surface-2); color: var(--eb-text-3); border: 1px dashed var(--eb-border); border-radius: var(--eb-radius-lg); transition: border-color .15s ease, color .15s ease, background .15s ease; }
.eb-ghost:hover { background: var(--eb-surface); }
.eb-ghost-green:hover { border-color: var(--eb-primary); color: var(--eb-primary); }
.eb-ghost-gold:hover  { border-color: var(--eb-accent);  color: var(--eb-accent); }

/* Conectores del deal-chain: línea Bézier dashed (raya intermedia); verde al conectar a un buyer. */
.eb-conn path { stroke: var(--eb-border); }
.eb-conn-green path { stroke: var(--eb-primary); }

/* Abanico de conectores del deal-chain: líneas SVG con un único origen (el nodo del viewer). */
.eb-fanout-gap { gap: 5.5rem; }
.eb-conn-line { stroke: var(--eb-border); fill: none; stroke-width: 2; stroke-dasharray: 5 4; }
.eb-conn-line-green { stroke: var(--eb-primary); }
.eb-conn-label { fill: var(--eb-text, #1a1a1a); font-size: 10px; font-weight: 600; paint-order: stroke; stroke: #fff; stroke-width: 3px; stroke-linejoin: round; }

/* ============================================================================
   Grafo "deal-chain n8n" — primitivos visuales COMPARTIDOS (todos los vhosts).
   Justificación reuse-before-create: la estética del grafo (banda de
   intermediación, nodo-tarjeta con borde de estado, conectores Bézier SVG con
   etiqueta de comisión) NO se compone con utilidades atómicas existentes —
   requiere apariencia propia. Se extrae del lenguaje visual de TradingDeskChain
   (gestion /deal-flow) para reusarlo en la vista multirama confidencial del
   portal. Todo con tokens (sin hex). El posicionamiento x/y dinámico va inline
   en el componente (coords runtime); acá SOLO apariencia.
   ========================================================================== */

/* Nodo-tarjeta del grafo. Se combina con .card. El color del borde-izquierdo
   (estado/dataset) se pasa por --dc-accent desde el componente (token, no hex). */
.dc-node { border-left: 4px solid var(--dc-accent, var(--eb-border)); transition: box-shadow .15s ease, transform .15s ease; }
.dc-node.dc-clickable { cursor: pointer; }
.dc-node.dc-clickable:hover { box-shadow: 0 4px 14px rgba(20, 30, 25, .12); transform: translateY(-1px); }
.dc-node-self { box-shadow: 0 0 0 2px var(--eb-primary-ring, var(--eb-primary)); }

/* Banda EBCGG: hace explícita la intermediación / el origen confiable masked. */
.dc-band { background: color-mix(in srgb, var(--eb-accent) 12%, transparent); border: 1.5px solid var(--eb-accent); border-radius: var(--eb-radius-lg, 12px); }
.dc-band-title { color: var(--eb-accent); font-weight: 700; }

/* Hub de fase (chip sobre la banda, marca el paso que cruza por EBCGG). */
.dc-hub { border: 1px solid var(--eb-accent); border-radius: var(--eb-radius-md, 6px); background: var(--eb-bg-soft, color-mix(in srgb, var(--eb-accent) 6%, transparent)); }
.dc-hub-label { color: var(--eb-accent); font-weight: 700; }

/* Conectores Bézier (SVG <path>). Defecto = borde; verde = terminal (buyer);
   accent punteado = bifurcación que rutea por EBCGG. */
.dc-conn { fill: none; stroke: var(--eb-border); stroke-width: 2; }
.dc-conn-green { stroke: var(--eb-primary); }
.dc-conn-accent { stroke: var(--eb-accent); stroke-width: 2.5; stroke-dasharray: 6 5; }
.dc-conn-label { fill: var(--eb-muted, currentColor); font-size: 10px; font-weight: 600; }

/* Lienzo con drag-pan (mismo gesto que TradingDeskChain). */
.dc-canvas { position: relative; }
.dc-canvas.dc-grabbing { cursor: grabbing; }

/* Mini-nodo de comisión sobre la arista (se combina con .card para bg/borde).
   Posicionado en el midpoint de la conexión por el componente (left/top runtime). */
.dc-node-comm { position: absolute; z-index: 2; padding: 2px 7px; line-height: 1.25; white-space: nowrap; text-align: center; }
.dc-node-comm-green { border-color: var(--eb-primary) !important; }

/* Sidebar badge — dot pulsante para notif inline en items del sidebar.
   Justificación reuse: no hay clase "notification dot pulsante inline en link
   de sidebar" en EBCGG core. Se combina con .sidebar-link para posicionamiento. */
.sidebar-badge {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--eb-danger, #dc2626);
  box-shadow: 0 0 0 rgba(220, 38, 38, 0.6);
  animation: sidebar-badge-pulse 1.6s ease-out infinite;
  flex-shrink: 0;
}
@keyframes sidebar-badge-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.6); }
  70%  { box-shadow: 0 0 0 8px rgba(220, 38, 38, 0);  }
  100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0);    }
}

/* Form validation en inputs React controlados — Justificación reuse: existe
   .form-input.is-invalid pero form-input está PROHIBIDO en controlled inputs
   (ebcgg.js intercepta eventos); la familia .eb-input no tenía el modifier.
   Mismo naming is-invalid que el core. */
.eb-input.is-invalid, .form-select.is-invalid, select.is-invalid { border-color: var(--eb-danger-text) !important; }

/* Texto justificado como utility — Justificación reuse: .doc-paragraph/.doc-clause
   justifican pero traen font-size/margins de documento; no había utility pura. */
.eb-text-justify { text-align: justify; }

/* Renglón anulado (tachado) — Justificación reuse: no existe utility de
   line-through en EBCGG core; se compone con .eb-opacity-50 / .eb-text-muted. */
.eb-strike { text-decoration: line-through; }

/* Visibilidad por tema — para assets con variante clara/oscura (ej. logo wordmark).
   Justificación reuse-before-create: no existe utilidad show/hide por [data-theme]
   en el framework; general, reusable y token-free (solo toggling de display). */
.eb-theme-dark { display: none; }
[data-theme="dark"] .eb-theme-dark { display: revert; }
[data-theme="dark"] .eb-theme-light { display: none; }
