/* Google Font for Premium Typography */
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap');

:root {
    /* Color Palette */
    --odoo-primary: #875A7B;
    --odoo-primary-dark: #6d4862;
    --odoo-primary-light: #a17496;
    --odoo-success: #28a745;
    --odoo-warning: #ffc107;
    --odoo-danger: #dc3545;
    --odoo-info: #17a2b8;
    --odoo-secondary: #e9ecef;
    --odoo-bg: #f8f9fa;
    --odoo-card-bg: #ffffff;
    --odoo-text-primary: #212529;
    --odoo-text-muted: #6c757d;
    --odoo-border: #dee2e6;
}

body {
    font-family: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    font-size: 14px;
    background-color: var(--odoo-bg);
    color: var(--odoo-text-primary);
    margin: 0;
    padding: 0;
    -webkit-font-smoothing: antialiased;
}

/* Typography Helpers */
.odoo-page-title {
    font-size: 20px;
    font-weight: 600;
    color: var(--odoo-text-primary);
    margin: 0;
}

/* Custom Buttons */
.btn-odoo-primary {
    background-color: var(--odoo-primary);
    border-color: var(--odoo-primary);
    color: #ffffff;
    font-weight: 500;
    border-radius: 6px;
    padding: 0.375rem 1rem;
    transition: all 0.2s ease-in-out;
}

.btn-odoo-primary:hover, 
.btn-odoo-primary:focus, 
.btn-odoo-primary:active {
    background-color: var(--odoo-primary-dark);
    border-color: var(--odoo-primary-dark);
    color: #ffffff;
    box-shadow: 0 4px 6px rgba(135, 90, 123, 0.2);
}

.btn-odoo-secondary {
    background-color: #ffffff;
    border: 1px solid var(--odoo-border);
    color: #495057;
    font-weight: 500;
    border-radius: 6px;
    padding: 0.375rem 1rem;
    transition: all 0.2s ease-in-out;
}

.btn-odoo-secondary:hover {
    background-color: #f1f3f5;
    color: #212529;
    border-color: #ced4da;
}

/* Navigation & Layout */
.odoo-navbar {
    background-color: var(--odoo-primary);
    padding: 0.5rem 1.5rem;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
}

.odoo-navbar .navbar-brand {
    color: #ffffff;
    font-weight: 700;
    font-size: 18px;
    display: flex;
    align-items: center;
    gap: 8px;
}

.odoo-navbar .nav-link {
    color: rgba(255, 255, 255, 0.85);
    font-weight: 500;
}

.odoo-navbar .nav-link:hover,
.odoo-navbar .nav-link.active {
    color: #ffffff;
}

.odoo-breadcrumb {
    background-color: #f1f3f5;
    padding: 0.5rem 1.5rem;
    border-bottom: 1px solid var(--odoo-border);
    font-size: 13px;
}

.odoo-breadcrumb a {
    color: var(--odoo-primary);
    text-decoration: none;
    font-weight: 500;
}

.odoo-breadcrumb a:hover {
    text-decoration: underline;
}

.odoo-breadcrumb span {
    color: var(--odoo-text-muted);
}

.odoo-page-header {
    background-color: #ffffff;
    border-bottom: 1px solid var(--odoo-border);
    padding: 1rem 1.5rem;
    margin-bottom: 1.5rem;
}

/* Filter Bar */
.odoo-filter-bar {
    display: flex;
    align-items: center;
    background-color: #ffffff;
    border: 1px solid var(--odoo-border);
    border-radius: 6px;
    padding: 0.25rem 0.5rem;
}

/* Avatars */
.avatars-container {
    display: flex;
    align-items: center;
    padding-left: 8px;
}

.odoo-avatar {
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    color: #ffffff;
    border: 2px solid #ffffff;
    box-shadow: 0 1px 3px rgba(0,0,0,0.1);
    user-select: none;
}

.odoo-avatar-xs {
    width: 24px;
    height: 24px;
    font-size: 9px;
    margin-left: -8px;
    z-index: 1;
}

.odoo-avatar-sm {
    width: 32px;
    height: 32px;
    font-size: 12px;
    margin-left: -8px;
    z-index: 1;
}

.odoo-avatar:hover {
    z-index: 10;
    transform: scale(1.1);
    transition: transform 0.15s ease;
}

/* User Management Inline Editing */
.user-row {
    transition: background-color 0.15s ease-in-out;
}

.user-row:hover {
    background-color: #f8f9fa !important;
}

.edit-field {
    max-width: 180px;
    transition: all 0.15s ease-in-out;
    border: 1px solid transparent !important;
    background-color: transparent !important;
    font-size: 14px;
    padding: 0.25rem 0.5rem;
}

.user-row:hover .edit-field {
    border: 1px solid var(--odoo-border) !important;
    background-color: #ffffff !important;
}

.edit-field:focus {
    border-color: var(--odoo-primary-light) !important;
    outline: 0;
    box-shadow: 0 0 0 0.25rem rgba(161, 116, 150, 0.25) !important;
    background-color: #ffffff !important;
}

.password-input {
    max-width: 130px;
    font-size: 0.85rem;
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

.btn-action {
    padding: .2rem .5rem;
    font-size: .8rem;
}

/* Premium Dashboard Card Design */
.app-card {
    background-color: #ffffff;
    border: 1px solid var(--odoo-border);
    border-radius: 8px;
    padding: 1.5rem;
    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
    position: relative;
    overflow: hidden;
    height: 100%;
}

.app-card:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 16px rgba(0,0,0,0.06), 0 2px 4px rgba(0,0,0,0.02);
    border-color: var(--odoo-primary-light);
}

.app-card .app-icon-wrapper {
    width: 48px;
    height: 48px;
    background-color: rgba(135, 90, 123, 0.1);
    color: var(--odoo-primary);
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 24px;
    margin-bottom: 1rem;
}

.app-card.locked {
    background-color: #fdfdfd;
    opacity: 0.75;
}

.app-card.locked:hover {
    transform: none;
    box-shadow: none;
    border-color: var(--odoo-border);
}

.app-card.locked .app-icon-wrapper {
    background-color: #e9ecef;
    color: var(--odoo-text-muted);
}

.app-card .lock-badge {
    position: absolute;
    top: 1rem;
    right: 1rem;
    font-size: 16px;
    color: var(--odoo-text-muted);
}

.app-card .app-title {
    font-size: 18px;
    font-weight: 600;
    margin-bottom: 0.5rem;
    color: var(--odoo-text-primary);
}

.app-card .app-desc {
    color: var(--odoo-text-muted);
    font-size: 13px;
    line-height: 1.5;
    margin-bottom: 1.5rem;
}

/* Custom CSS Switch for Toggles */
.form-switch .form-check-input {
    width: 2.5em;
    cursor: pointer;
}

.form-switch .form-check-input:checked {
    background-color: var(--odoo-primary);
    border-color: var(--odoo-primary);
}

/* Toast styling overrides */
.toast-container {
    z-index: 1100;
}

/* ==========================================================================
   [UI/UX · B1] Sistema de layout compartido: switch de vistas, barra de
   filtros, paginación y cabecera de pantalla (spec §5.2 y §5.4).
   ========================================================================== */

/* --- Switch de vistas (D21/D30) -------------------------------------------
   Control segmentado: activo en morado, inactivos en blanco. Va DEBAJO del
   título y subtítulo, alineado a la izquierda. Soporta N segmentos. */
.odoo-switch {
    display: inline-flex;
    align-items: stretch;
    background-color: #ffffff;
    border: 1px solid var(--odoo-border);
    border-radius: 8px;
    padding: 3px;
    gap: 3px;
}

.odoo-switch-opt {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0.3rem 0.9rem;
    border-radius: 6px;
    font-size: 13px;
    font-weight: 600;
    color: var(--odoo-text-muted);
    text-decoration: none;
    white-space: nowrap;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.odoo-switch-opt:hover {
    background-color: #f1f3f5;
    color: var(--odoo-text-primary);
}

.odoo-switch-opt.active,
.odoo-switch-opt.active:hover {
    background-color: var(--odoo-primary);
    color: #ffffff;
    box-shadow: 0 1px 2px rgba(135, 90, 123, 0.35);
}

.odoo-switch-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 18px;
    padding: 0 6px;
    border-radius: 9px;
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
    background-color: var(--odoo-secondary);
    color: #495057;
}

.odoo-switch-opt.active .odoo-switch-badge {
    background-color: rgba(255, 255, 255, 0.9);
    color: var(--odoo-primary);
}

/* Estado "cargando" del bloque mientras llega el fragmento de la otra vista. */
.odoo-switch.cargando {
    opacity: 0.65;
    pointer-events: none;
}

[data-nexus-fragmento].cargando {
    opacity: 0.45;
    transition: opacity 0.15s ease;
}

/* --- Cabecera de pantalla -------------------------------------------------- */
.odoo-page-header--std {
    margin-bottom: 1.5rem;
}

.odoo-page-sello {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 1px 8px;
    border-radius: 10px;
    background-color: #f1f3f5;
    border: 1px solid var(--odoo-border);
    font-size: 11px;
    font-weight: 600;
    color: var(--odoo-text-muted);
    white-space: nowrap;
}

/* --- Barra de filtros (fix D18) -------------------------------------------
   El grupo "Filtrar + ↻" no se encoge nunca: era la causa del botón de reset
   desbordado en el catálogo y en el catálogo BLANK. */
.odoo-filters .odoo-filters-acciones {
    flex-shrink: 0;
    white-space: nowrap;
}

.odoo-filters .odoo-filters-acciones .btn {
    flex-shrink: 0;
}

.odoo-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 0.2rem 0.7rem;
    border: 1px solid var(--odoo-border);
    border-radius: 14px;
    background-color: #ffffff;
    color: #495057;
    font-size: 12px;
    font-weight: 600;
    text-decoration: none;
    transition: all 0.15s ease;
}

.odoo-chip:hover {
    border-color: var(--odoo-primary-light);
    color: var(--odoo-primary);
}

.odoo-chip.active {
    background-color: var(--odoo-primary);
    border-color: var(--odoo-primary);
    color: #ffffff;
}

.odoo-chip-quitar {
    color: var(--odoo-text-muted);
    font-weight: 700;
}

/* --- Paginación por columna (D16) ------------------------------------------ */
.odoo-col-pagination {
    border-top: 1px solid var(--odoo-border);
    background-color: #fbfbfc;
}

.odoo-col-page-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 6px;
    color: var(--odoo-primary);
    text-decoration: none;
    font-size: 12px;
}

.odoo-col-page-btn:hover {
    background-color: #eef0f2;
}

.odoo-col-page-btn.disabled {
    color: #ced4da;
    pointer-events: none;
}

/* ═══════════════════════════════════════════════════════════════════════════
 * [B4 · D26 · T2] Cabeceras ordenables y filtros por columna
 * Base de la rejilla de B11: el mismo enlace de orden que se pinta hoy en la
 * barra de cabecera se reutilizará dentro de la rejilla tipo SSMS.
 * ═══════════════════════════════════════════════════════════════════════════ */
.odoo-th-orden {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: inherit;
    text-decoration: none;
    white-space: nowrap;
}

.odoo-th-orden:hover {
    color: var(--odoo-primary);
}

.odoo-th-orden.activo {
    color: var(--odoo-primary);
    font-weight: 700;
}

/* La flecha "sin orden" solo se insinúa: con 14 columnas, 14 iconos a pleno
   contraste convierten la cabecera en ruido. */
.odoo-th-orden-icono {
    font-size: 9px;
    opacity: 0.35;
}

.odoo-th-orden:hover .odoo-th-orden-icono,
.odoo-th-orden.activo .odoo-th-orden-icono {
    opacity: 1;
}

/* "Bajo mínimo primero": el modo de orden por déficit (stock − mínimo efectivo). */
.odoo-th-deficit {
    margin-left: 6px;
    color: #ced4da;
    text-decoration: none;
    font-size: 11px;
}

.odoo-th-deficit:hover {
    color: var(--odoo-danger, #dc3545);
}

.odoo-th-deficit.activo {
    color: var(--odoo-danger, #dc3545);
}

.odoo-filters-toggle {
    color: var(--odoo-primary);
    text-decoration: none;
    font-size: 12px;
    font-weight: 600;
}

.odoo-filters-avanzados {
    border-top: 1px dashed var(--odoo-border);
    padding-top: 12px;
    margin-top: 2px;
}

.odoo-filters-rango .form-control {
    max-width: 90px;
}

/* Mientras se recarga solo el cuerpo (filtro, orden, página), el contenido se
   atenúa: sin señal, un filtro sobre 18.500 filas parece que no hizo nada. */
[data-nexus-fragmento].cargando {
    opacity: 0.55;
    transition: opacity 0.12s ease-in;
    pointer-events: none;
}

/* ==========================================================================
   [UI/UX · B2] Componente de diálogo unificado (D32 · D33)
   Reviste `NexusModal`: cabecera, tipografía, botonera, estado de error,
   campos declarados, teclado numérico y avisos sin interacción.
   ========================================================================== */

.nexus-modal .modal-content {
    border: none;
    border-radius: 10px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.22);
    overflow: hidden;
}

.nexus-modal .modal-header {
    background-color: var(--odoo-primary);
    border-bottom: none;
    padding: 0.6rem 1rem;
}

.nexus-modal .modal-title {
    font-size: 14px;
    font-weight: 700;
    color: #ffffff;
    margin: 0;
}

.nexus-modal .modal-header .btn-close {
    filter: invert(1) grayscale(1) brightness(2);
    opacity: 0.85;
    font-size: 11px;
}

.nexus-modal--peligro .modal-header {
    background-color: var(--odoo-danger);
}

.nexus-modal .modal-body {
    padding: 1rem;
    font-size: 13px;
}

.nexus-modal .modal-footer {
    background-color: #fbfafb;
    border-top: 1px solid var(--odoo-border);
    padding: 0.5rem 1rem;
    gap: 0.4rem;
}

.nexus-modal .modal-footer .btn {
    font-weight: 600;
}

/* El tema no redefine .btn-primary, asi que Bootstrap pintaba el boton de
   confirmar de AZUL debajo de una cabecera morada. La botonera del dialogo usa
   el color del tema; el rojo de `tono:'peligro'` se respeta tal cual. */
.nexus-modal .modal-footer .btn-primary {
    background-color: var(--odoo-primary);
    border-color: var(--odoo-primary);
}

.nexus-modal .modal-footer .btn-primary:hover,
.nexus-modal .modal-footer .btn-primary:focus {
    background-color: var(--odoo-primary-dark);
    border-color: var(--odoo-primary-dark);
}

.nexus-modal .modal-footer .btn-primary:disabled {
    background-color: var(--odoo-primary-light);
    border-color: var(--odoo-primary-light);
}

/* Cancelar es secundario de verdad: no compite con el de confirmar. */
.nexus-modal .modal-footer .btn-secondary {
    background-color: #ffffff;
    border-color: var(--odoo-border);
    color: var(--odoo-text-muted);
}

.nexus-modal .modal-footer .btn-secondary:hover {
    background-color: #f1f3f5;
    color: var(--odoo-text-primary);
}

/* El error del servidor: sale DENTRO del diálogo y se ve (regla dura D31). */
.nexus-modal-error {
    padding: 0.5rem 0.75rem;
    margin-bottom: 0.85rem;
    font-size: 12px;
    font-weight: 600;
    white-space: pre-line;
    border-left: 3px solid var(--odoo-danger);
    border-radius: 6px;
}

/* Confirmación destructiva de DOS PASOS: sustituye al `confirm()` nativo. */
.nexus-modal-confirma {
    background-color: #fef2f2;
    border-top: 1px solid #fecaca;
}

.nexus-modal-confirma-texto {
    font-size: 12px;
    font-weight: 700;
    color: #b91c1c;
}

/* --- Campos declarados ----------------------------------------------------- */
.nexus-modal-label {
    font-size: 12px;
    font-weight: 600;
    margin-bottom: 0.15rem;
    color: #374151;
}

.nexus-modal-check {
    font-size: 12px;
    font-weight: 600;
    color: #374151;
}

.nexus-req {
    color: var(--odoo-danger);
}

.nexus-modal-ayuda {
    font-size: 11px;
    color: var(--odoo-text-muted);
    margin-top: 0.2rem;
}

.nexus-modal-estatico {
    font-size: 13px;
    color: var(--odoo-text-primary);
}

.nexus-campos .form-control-sm,
.nexus-campos .form-select-sm {
    font-size: 13px;
}

/* [UI/UX · B10] `tipo:'color'`, estrenado por el editor de proceso especial. */
.nexus-modal-color {
    width: 100%; height: 31px; padding: 2px;
}

/* --- [UI/UX · B10 · D35] Cuerpo servido por el servidor ---------------------
   Los 7 fragmentos de MEJORAS (`_lanzar_produccion`, `_nueva_of`, `_nueva_oft`,
   `_cancelar_of`, `_cancelar_oft`, `_cancelar_pedido`, `_borrar_pedido`) se
   armonizan POR DENTRO, que es lo que pide D35: **su lógica y sus endpoints no
   se tocan**, solo dejan de llevar la tipografía en atributos `style=` repetidos
   fragmento a fragmento (`font-size:12px;font-weight:600` en cada `<label>`,
   `font-size:11px` en cada nota, `font-size:12px` en cada tabla…). Ahora es el
   tema el que la pone, en un sitio, para los dos modos de cuerpo a la vez. */
.nexus-modal [data-nexus="cuerpo"] {
    font-size: 13px;
    color: var(--odoo-text-primary);
}

.nexus-modal [data-nexus="cuerpo"] .nexus-modal-seccion {
    font-size: 13px;
    font-weight: 600;
    margin-bottom: 0.35rem;
}

.nexus-modal [data-nexus="cuerpo"] .nexus-modal-tabla,
.nexus-modal [data-nexus="cuerpo"] .nexus-modal-tabla th,
.nexus-modal [data-nexus="cuerpo"] .nexus-modal-tabla td {
    font-size: 12px;
}

.nexus-modal [data-nexus="cuerpo"] .nexus-modal-tabla thead th {
    font-weight: 600;
    color: var(--odoo-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

.nexus-modal [data-nexus="cuerpo"] .nexus-modal-alerta {
    font-size: 12px;
    padding: 0.5rem 0.75rem;
    border-radius: 6px;
}

/* --- Teclado numérico (taller: se pulsa con guantes) ------------------------ */
.nexus-numpad-display {
    text-align: center;
    font-size: 46px;
    font-weight: 900;
    line-height: 1.2;
    padding: 0.35rem;
    min-height: 68px;
    color: #111;
    background: #fafafa;
    border: 3px solid #e5e7eb;
    border-radius: 12px;
    margin-bottom: 0.6rem;
}

.nexus-numpad.aviso .nexus-numpad-display {
    border-color: var(--odoo-warning);
    background: #fffbeb;
    color: #92400e;
}

.nexus-numpad-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.4rem;
}

.nexus-numpad-key {
    padding: 14px;
    font-size: 22px;
    font-weight: 800;
    text-align: center;
    color: #111;
    background: #ffffff;
    border: 2px solid #e5e7eb;
    border-radius: 10px;
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    transition: transform 0.1s ease, background-color 0.1s ease;
}

.nexus-numpad-key:active {
    background: #f3f4f6;
    transform: scale(0.95);
}

.nexus-numpad-key.backspace {
    background: #fef3c7;
    border-color: #fde68a;
    color: #92400e;
    font-size: 18px;
}

.nexus-numpad-key.clear {
    background: #fef2f2;
    border-color: #fecaca;
    color: #dc2626;
    font-size: 16px;
}

/* --- Avisos sin interacción (D33) ------------------------------------------ */
.nexus-avisos {
    position: fixed;
    top: 1rem;
    right: 1rem;
    z-index: 1090;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    max-width: 380px;
}

.nexus-aviso {
    position: relative;
    padding: 0.6rem 2rem 0.6rem 0.85rem;
    border-radius: 8px;
    border-left: 4px solid var(--odoo-info);
    background: #ffffff;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.16);
    font-size: 12.5px;
    color: var(--odoo-text-primary);
    animation: nexusAvisoIn 0.18s ease-out;
}

.nexus-aviso.saliendo {
    opacity: 0;
    transition: opacity 0.2s ease;
}

@keyframes nexusAvisoIn {
    from { transform: translateX(12px); opacity: 0; }
    to { transform: translateX(0); opacity: 1; }
}

.nexus-aviso--ok { border-left-color: var(--odoo-success); }
.nexus-aviso--aviso { border-left-color: var(--odoo-warning); }
.nexus-aviso--error { border-left-color: var(--odoo-danger); }

.nexus-aviso-titulo {
    font-weight: 700;
    margin-bottom: 0.1rem;
}

.nexus-aviso-cerrar {
    position: absolute;
    top: 2px;
    right: 6px;
    border: none;
    background: none;
    font-size: 18px;
    line-height: 1;
    color: var(--odoo-text-muted);
    cursor: pointer;
}

/* ═══════════════════════════════════════════════════════════════════════════
   [UI/UX · B3 · spec §6.2 · D7/D8] Barra superior: 3 entradas + menu de usuario
   La estructura la declara `apps/core/navegacion.py`; aqui solo se viste.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Dropdowns del nav: el padre se marca activo cuando lo esta cualquier hija (T6). */
.odoo-navbar .nav-link.dropdown-toggle.active,
.odoo-navbar .nav-link.active {
    color: #ffffff;
    font-weight: 600;
}

.odoo-navbar .dropdown-menu {
    border-radius: 8px;
    padding: 0.35rem 0;
    min-width: 230px;
    font-size: 13px;
}

.odoo-navbar .dropdown-item {
    padding: 0.5rem 1rem;
    color: var(--odoo-text-primary);
}

.odoo-navbar .dropdown-item i {
    color: var(--odoo-text-muted);
    width: 18px;
}

.odoo-navbar .dropdown-item:hover,
.odoo-navbar .dropdown-item:focus {
    background-color: rgba(135, 90, 123, 0.10);
    color: var(--odoo-primary-dark);
}

/* El item de la pantalla en la que estas: Bootstrap lo pintaria de AZUL
   (.dropdown-item.active usa su --bs-primary), y el tema no viste los colores de
   Bootstrap. Se fuerza el morado, como hizo B2 con la botonera del dialogo. */
.odoo-navbar .dropdown-item.active,
.odoo-navbar .dropdown-item:active {
    background-color: var(--odoo-primary);
    color: #ffffff;
}

.odoo-navbar .dropdown-item.active i,
.odoo-navbar .dropdown-item:active i {
    color: rgba(255, 255, 255, 0.85);
}

/* Boton unificado "OFs y OFTs por revisar" (D7): un icono + un badge por tipo.
   Si el contador es 0 el badge no se pinta, pero el ICONO si: la barra no cambia
   de ancho porque una cola se vacie. */
.odoo-navbar .odoo-nav-revisar {
    gap: 0.35rem;
    padding-left: 0.75rem;
    padding-right: 0.75rem;
    border-radius: 6px;
    background-color: rgba(255, 255, 255, 0.10);
}

.odoo-navbar .odoo-nav-revisar:hover,
.odoo-navbar .odoo-nav-revisar.active {
    background-color: rgba(255, 255, 255, 0.20);
}

.odoo-nav-cont {
    position: relative;
    display: inline-flex;
    align-items: center;
    padding-right: 2px;
}

.odoo-nav-cont i {
    font-size: 15px;
}

.odoo-nav-badge {
    position: absolute;
    top: -7px;
    right: -9px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 8px;
    font-size: 10px;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
    color: #ffffff;
    border: 1px solid var(--odoo-primary);
}

.odoo-nav-badge-of { background-color: #dc2626; }
.odoo-nav-badge-oft { background-color: #2563eb; }
/* [FAMILIAS Y PROCESOS · B7 · §8.2] El tercer badge: BLANK pendientes de alta en SAP.
   Ámbar, que es el tono de "esto espera a alguien" en todo el sistema (la chapa del
   origen usa el mismo), y no rojo: no es un error, es trabajo pendiente fuera de aquí. */
.odoo-nav-badge-alta { background-color: #b45309; }

/* ═══════════════════════════════════════════════════════════════════════════
   [UI/UX · B5 · spec §6.7 tarea 4] TALLER — tablero de columnas
   ───────────────────────────────────────────────────────────────────────────
   Vivía DUPLICADO byte a byte en `taller.html` (5 columnas) y en
   `taller_oft.html` (2 columnas, `max-width:900px`). Al fusionar las dos
   pantallas sube aquí una sola vez; la única diferencia real de la vista OFT
   es la rejilla, que queda como modificador `--oft`.
   El CSS del overlay de numpad (`.numpad-*`) NO sube: ese diálogo era el tercer
   sistema de popup del proyecto y se fue entero con la plantilla (B2/D32).
   ═══════════════════════════════════════════════════════════════════════════ */
/* [FAMILIAS Y PROCESOS · B14 · spec §10.1] LAS COLUMNAS YA NO SON CINCO.
   El proceso de moleta tiene 5 pasos, el de punzón 6 y el de rodillo 7, así que la
   rejilla la parametriza la PANTALLA: `--cols` lo escribe `_taller_body.html` con el
   número de columnas de ESE proceso.
   🪤 Y las tres consultas de medios que plegaban el tablero a 3, 2 y 1 columnas se han
   ido: plegar un tablero kanban REORDENA los pasos —la cuarta columna aparece debajo de
   la primera— y con siete pasos eso deja de ser un detalle estético para ser una
   secuencia mal contada. En su lugar, `minmax` + scroll horizontal: las columnas nunca
   bajan de 200px y el orden del proceso se conserva siempre, que es lo que el operario
   lee. */
.taller-grid {
    display: grid; gap: 1rem; overflow-x: auto; padding-bottom: 0.25rem;
    grid-template-columns: repeat(var(--cols, 5), minmax(200px, 1fr));
}
@media (max-width: 640px) {
    .taller-grid { grid-template-columns: repeat(var(--cols, 5), minmax(240px, 1fr)); }
}

/* Procesos de dos pasos (hoy, «Estándar · OFT»): con la rejilla a todo lo ancho las dos
   columnas quedaban desiertas. Se acota, como hacía el modificador `--oft` que sustituye
   — y ahora depende del número de columnas y no de la cara del switch, que es lo correcto:
   una OFT con un proceso de siete pasos necesita el ancho entero. */
.taller-grid--estrecho { max-width: 900px; }
@media (max-width: 640px) { .taller-grid--estrecho { max-width: none; } }

/* [B14 · §10.1] Las sub-pestañas (Moletas · Punzones · Rodillos) y el selector de proceso
   de «Procesos especiales» son el switch segmentado de UI/UX B1 (`.odoo-switch`), así que
   no traen estilo propio: solo su hueco, DENTRO del cuerpo — es el único canal por el que
   pueden depender de la vista activa (bitácora UI/UX B4, decisión 3). */
.taller-pestanas { margin-bottom: 1rem; }

.taller-col { background: #f8f9fa; border-radius: 10px; min-height: 300px; }
.taller-col-header {
    padding: 0.75rem 1rem; border-radius: 10px 10px 0 0; font-weight: 700;
    font-size: 14px; color: white; display: flex; align-items: center; gap: 0.5rem;
}
.taller-card {
    background: white; border-radius: 10px; padding: 1rem; margin: 0.5rem;
    box-shadow: 0 1px 4px rgba(0,0,0,0.06); border-left: 4px solid;
}
.taller-card.urgent { border-color: #ef4444 !important; background: #fef2f2; }
.taller-card .of-code { font-weight: 800; font-size: 16px; }
.taller-card .item-code { font-size: 13px; color: #6b7280; }
.taller-card .qty { font-size: 24px; font-weight: 800; }
.taller-card .qty-label {
    display: block; font-size: 10px; font-weight: 600; color: #9ca3af;
    text-transform: uppercase; letter-spacing: 0.03em; line-height: 1;
}
.taller-btn {
    display: block; width: 100%; padding: 10px; border: none; border-radius: 8px;
    font-weight: 700; font-size: 14px; color: white; cursor: pointer;
    margin-top: 0.5rem; transition: all 0.2s;
}
.taller-btn:hover { opacity: 0.9; transform: scale(1.02); }
.taller-btn:active { transform: scale(0.98); }
.taller-btn:disabled { opacity: 0.5; cursor: not-allowed; }
/* [Repaso del dueno de B5] El "Completar X" secundario de una tarjeta "Listo para X"
   se retiro: lo que no se ha empezado no se termina. Su clase se va con el, para no
   dejar CSS muerto; si algun dia vuelve un boton secundario en la tarjeta, se recupera
   de este mismo commit. */
.taller-btn-print {
    display: block; width: 100%; padding: 6px; border: 1px solid #d1d5db;
    border-radius: 6px; background: white; font-size: 12px; font-weight: 600;
    color: #374151; cursor: pointer; margin-top: 0.4rem; transition: all 0.2s;
    text-align: center; text-decoration: none;
}
.taller-btn-print:hover { background: #f3f4f6; color: #111; }
.taller-btn-cancel {
    display: block; width: 100%; padding: 6px; border: 1px solid #fecaca;
    border-radius: 6px; background: white; font-size: 12px; font-weight: 600;
    color: #dc2626; cursor: pointer; margin-top: 0.4rem; transition: all 0.2s;
    text-align: center;
}
.taller-btn-cancel:hover { background: #fef2f2; }
.taller-edit-qty { display: flex; gap: 0.25rem; margin-top: 0.5rem; }
.taller-edit-qty input { flex: 1; min-width: 0; }
.taller-edit-qty button {
    border: 1px solid #d1d5db; background: white; border-radius: 6px;
    padding: 2px 10px; cursor: pointer; color: #374151;
}
.taller-edit-qty button:hover { background: #f3f4f6; }
.taller-time {
    display: inline-block; font-size: 11px; font-weight: 700; padding: 2px 8px;
    border-radius: 6px; background: #f3f4f6; color: #374151; margin-top: 0.4rem;
}
/* [E8] Franja de último cambio (piezas/arandelas de más) y [E9] badge de reimprimir. */
.taller-cambio {
    display: block; font-size: 11px; font-weight: 700; padding: 2px 8px; margin-top: 0.35rem;
    border-radius: 6px; background: #fef2f2; color: #b91c1c;
}
.taller-cambio .taller-cambio-meta { color: #9ca3af; font-weight: 500; }
.taller-reimprimir {
    display: block; font-size: 11px; font-weight: 700; padding: 2px 8px; margin-top: 0.35rem;
    border-radius: 6px; background: #fffbeb; color: #b45309;
}
/* Sub-estados (E6): subcabecera de cada grupo apilado dentro de la columna. */
.taller-group-label {
    display: flex; align-items: center; gap: 0.35rem; margin: 0.5rem 0.5rem 0;
    font-size: 11px; font-weight: 800; letter-spacing: 0.03em; text-transform: uppercase;
    color: #64748b;
}
.taller-group-label.en_curso { color: #0f766e; }
.taller-group-label span {
    margin-left: auto; background: #e5e7eb; color: #374151;
    border-radius: 999px; padding: 0 7px; font-size: 10px;
}
.taller-group-label.en_curso span { background: #ccfbf1; color: #0f766e; }

/* [FAMILIAS Y PROCESOS · B14 · §9.5] «Cerrar con lo fabricado» en la tarjeta. Solo lo
   pintan las pantallas cuyo `taller_cfg.acciones` lo pide (hoy, «Procesos especiales»):
   en el taller estándar la orden cierra al completar su último paso y ofrecerlo en cada
   tarjeta invitaría a cerrar a medias sin motivo. Verde, que es el color de cerrar en
   todo el sistema. */
.taller-btn-cerrar {
    display: block; width: 100%; padding: 6px; border: 1px solid #bbf7d0;
    border-radius: 6px; background: white; font-size: 12px; font-weight: 600;
    color: #16a34a; cursor: pointer; margin-top: 0.4rem; transition: all 0.2s;
    text-align: center;
}
.taller-btn-cerrar:hover { background: #f0fdf4; }

/* ══════════════════════════════════════════════════════════════════════════
   [FAMILIAS Y PROCESOS · B14 · spec §10.2] EL CARRIL DE «PROCESOS ESPECIALES»
   ──────────────────────────────────────────────────────────────────────────
   Vivía en un `<style>` dentro de `procesos_especiales.html`, y sube aquí por lo
   mismo que subió el del taller en UI/UX B5: desde este bloque esa pantalla tiene
   switch y su cuerpo se sirve **suelto** como fragmento, y un `<style>` que vive
   en el armazón no viaja con él — la vista "Todos" cargada sin recargar la página
   se habría quedado sin estilo.
   Es el formato fila-por-orden, el de la vista "Todos". Elegido un proceso, la
   pantalla usa la rejilla del taller de aquí arriba.
   ══════════════════════════════════════════════════════════════════════════ */
.proc-row-card { background:#fff; border-radius:12px; box-shadow:0 1px 4px rgba(0,0,0,.08); margin-bottom:1.1rem; overflow:hidden; }
.proc-row-card.urgent { box-shadow:0 0 0 2px #ef4444 inset, 0 1px 4px rgba(0,0,0,.08); }
.proc-row-head { display:flex; flex-wrap:wrap; align-items:center; gap:.6rem; padding:.75rem 1rem; border-bottom:1px solid #eef2f7; }
.proc-row-head .of-code { font-weight:800; font-size:16px; }
.proc-row-head .item { color:#64748b; font-size:13px; }
.proc-name-badge { font-size:11px; font-weight:700; padding:2px 10px; border-radius:999px; color:#fff; }
/* Carril horizontal con scroll por fila */
.proc-track { display:flex; gap:.5rem; overflow-x:auto; padding:.85rem 1rem; scroll-behavior:smooth; }
.proc-step { min-width:158px; flex:0 0 auto; border-radius:10px; background:#f8fafc; border:1px solid #eef2f7; }
.proc-step.is-done { opacity:.7; }
.proc-step.is-current { min-width:230px; background:#fff; border:2px solid var(--c); box-shadow:0 3px 12px rgba(0,0,0,.08); }
.proc-step-head { display:flex; align-items:center; gap:.35rem; font-weight:700; font-size:13px; color:#fff;
    background:var(--c); padding:.5rem .7rem; border-radius:8px 8px 0 0; position:sticky; top:0; }
.proc-step-head .rev { margin-left:auto; opacity:.9; }
.proc-step-body { padding:.7rem; }
.proc-step-empty { padding:.9rem .7rem; color:#cbd5e1; font-size:12px; text-align:center; }
.proc-now { font-size:10px; font-weight:800; letter-spacing:.06em; color:var(--c); }
.proc-sub { font-weight:800; color:#0f766e; }
.proc-qtyin { font-size:12px; color:#475569; margin-bottom:.5rem; }
.proc-btn { display:block; width:100%; border:none; border-radius:8px; padding:8px; font-weight:700; font-size:13px; color:#fff; cursor:pointer; margin-top:.4rem; }
.proc-btn:hover { opacity:.92; }
.proc-btn-back { background:#fff; color:#475569; border:1px solid #cbd5e1; }
.proc-btn-fin { background:#16a34a; }
.proc-done-chip { font-size:10px; color:#16a34a; }

/* ── [UI/UX · B10] Filas del editor de proceso especial (`_proc_editor.html`) ──
   B5 subió aquí el overlay propio del editor (`.proc-editor-overlay/-caja`) y dejó
   dicho que portarlo al componente era de B10. Hecho: el editor es ya un diálogo de
   `NexusModal` en modo `campos`, así que esas dos clases **se han borrado** — si las
   buscas, no están —. Lo único que sobrevive es el aspecto de la FILA de paso, que
   el diálogo no puede dar porque las filas se crean en JS (llevan arrastre).
   Las mismas clases valen en "Procesos" y en "Taller Procesos Especiales": desde
   B10 las dos pantallas comparten editor. */
.proc-step-row { background: #f8fafc; border: 1px solid #eef2f7; }
.proc-step-row .proc-drag { cursor: grab; color: #94a3b8; }
.proc-step-row .proc-drag:active { cursor: grabbing; }
.proc-step-row .proc-step-color { width: 40px; padding: 2px; }

/* ══════════════════════════════════════════════════════════════════════════
   [UI/UX · B6 · spec §6.8] "OFs y OFTs por revisar" (pantalla unificada)
   ══════════════════════════════════════════════════════════════════════════
   Estaba duplicado byte a byte en `ordenes_por_revisar.html` y en
   `ofts_por_revisar.html` (esta última, borrada al fusionar). Sube al tema con
   el mismo criterio que el CSS del taller en B5. */
.rev-card {
    background: white; border-radius: 12px; box-shadow: 0 1px 4px rgba(0,0,0,0.07);
    border-left: 5px solid #94a3b8; padding: 1rem 1.25rem; margin-bottom: 1rem;
}
.rev-card.rojo { border-left-color: #ef4444; }
.rev-card.amarillo { border-left-color: #f59e0b; }
.rev-card.verde { border-left-color: #22c55e; }
.rev-code { font-size: 16px; }
.rev-sub { font-size: 13px; }
.rev-qty-input { width: 90px; font-weight: 700; }
.rev-cli { font-size: 12px; color: #475569; }
.rev-oft-fila { background: #f8fafc; }
.cat-badge {
    font-size: 10px; font-weight: 700; padding: 2px 8px; border-radius: 6px;
    text-transform: uppercase;
}
.cat-badge.cat-rojo { background: #fee2e2; color: #b91c1c; }
.cat-badge.cat-amarillo { background: #fef3c7; color: #92400e; }
.cat-badge.cat-verde { background: #dcfce7; color: #166534; }

/* Fila de HERMANAS (D2 · C2): hacer VISIBLE la fusión que hoy es silenciosa.
   El botón solo se pinta donde `services.ofs_hermanas` marca `fusionable`. */
.rev-hermanas { border-top: 1px dashed #e2e8f0; }
.rev-hermanas-titulo {
    font-size: 12px; font-weight: 600; color: #475569; margin-bottom: 0.35rem;
}
.rev-hermana {
    display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem;
    font-size: 12px; padding: 4px 8px; border-radius: 8px; background: #f8fafc;
    margin-bottom: 4px;
}
.rev-hermana-code { font-weight: 700; color: var(--odoo-primary); }
.rev-hermana-fase {
    background: #e0e7ff; color: #3730a3; border-radius: 6px; padding: 1px 8px;
    font-weight: 600;
}
.rev-hermana-qty { color: #475569; }
.rev-hermana-libre { color: #166534; font-weight: 600; }
.rev-hermana-btn { margin-left: auto; }
.rev-hermana-info { margin-left: auto; color: #94a3b8; font-style: italic; }

/* [BLANK/OFT · B10 · §7.6 · D31] La chapa del artículo BLANK en la tarjeta de la OF.
   Los tonos son los mismos que usa el desplegable seccionado de B9 (`ok`, `ambar`,
   `apagado`, `info`), y por la misma razón: el servidor manda un TONO, no un color, y el
   color lo pone aquí. "Pendiente de BLANK" va en ámbar porque frena la aprobación.
   [FAMILIAS Y PROCESOS · B6 · §6] El tono `apagado` se queda sin su inquilino —aquí vivía
   el "sin BLANK · no aplica" que este bloque retira— y entra `info`, que es el de una OF
   que parte de COLADA: no es un aviso ni una laguna, es de dónde sale la pieza. Y "origen
   sin declarar" va en ámbar por lo mismo que lo va "pendiente de BLANK": frena aprobar. */
.rev-blank {
    display: inline-flex; align-items: center; font-size: 12px; font-weight: 600;
    padding: 2px 9px; border-radius: 8px; border: 1px solid transparent;
}
.rev-blank-ok { background: #dcfce7; color: #166534; border-color: #bbf7d0; }
.rev-blank-ambar { background: #fef3c7; color: #92400e; border-color: #fde68a; }
.rev-blank-apagado { background: #f1f5f9; color: #64748b; border-color: #e2e8f0; }
.rev-blank-info { background: #e0f2fe; color: #075985; border-color: #bae6fd; }
.rev-blank-btn { margin-left: 0.4rem; padding: 1px 8px; font-size: 11px; }

/* [FAMILIAS Y PROCESOS · B7 · §8.2] "BLANK pendientes de alta" reutiliza la tarjeta de
   "por revisar" (`.rev-card` y sus chapas) porque es la misma clase de pantalla: una cola
   de cosas que alguien tiene que atender. Lo único suyo es este aviso de cabecera, que es
   lo que hace visible PFP8 sin que nadie tenga que sumar días a mano. Ámbar, no rojo: no
   es un error del sistema, es trabajo pendiente fuera de él. */
.alta-aviso {
    background: #fef3c7; color: #92400e; border: 1px solid #fde68a;
    border-radius: 10px; padding: 0.6rem 0.9rem; font-size: 13px;
}

/* ═══ [UI/UX · B7 · §6.6 · D16] Producción — clasificación de fabricación ═══
   El CSS vivía dentro de `dashboard.html` en un <style> (la plantilla ya no
   existe). Las tarjetas son las de la clasificación rojo/amarillo/verde, ahora
   con fechas (D13/D14) y paginación por columna. */
.prod-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
@media (max-width: 992px) { .prod-grid { grid-template-columns: 1fr; } }
.prod-col { background: #f8f9fa; border-radius: 10px; min-height: 120px; padding-bottom: 0.25rem; }
.prod-col-header {
    padding: 0.6rem 1rem; border-radius: 10px 10px 0 0; font-weight: 700; font-size: 13px;
    color: white; display: flex; align-items: center; gap: 0.5rem;
}
.prod-card {
    background: white; border-radius: 8px; padding: 0.55rem 0.75rem; margin: 0.4rem;
    box-shadow: 0 1px 3px rgba(0,0,0,0.05); border-left: 4px solid; font-size: 12px;
}
.prod-card-code { font-weight: 700; color: var(--odoo-primary); }
.prod-card-qty { font-weight: 700; color: #334155; white-space: nowrap; }
.prod-card-sub { color: #64748b; margin-top: 0.1rem; }
.prod-card-meta { color: #64748b; margin-top: 0.25rem; display: flex; flex-wrap: wrap; gap: 0.35rem; font-size: 11px; }
.prod-card-entrega { color: #b91c1c; font-weight: 600; width: 100%; }
.prod-chip {
    background: #fee2e2; color: #b91c1c; border-radius: 999px; padding: 0 0.4rem;
    margin-left: 0.25rem; font-weight: 600;
}
.prod-card-badges { margin-top: 0.35rem; display: flex; flex-wrap: wrap; gap: 0.3rem; align-items: center; }
.prod-fase {
    background: #eef2ff; color: #4338ca; border-radius: 999px; padding: 0.05rem 0.5rem;
    font-size: 10px; font-weight: 600;
}
.prod-badge-reimprimir {
    background: #fef3c7; color: #92400e; border-radius: 999px; padding: 0.05rem 0.5rem;
    font-size: 10px; font-weight: 600;
}

/* ═══ [UI/UX · B8 · §6.4 · D24] Bandeja — columna "Pedidos generados" ═══
   La caja del desglose scrollea dentro de sí misma: el caso real del dueño es un
   email con 22 pedidos, y sin `max-height` esa fila estira la tabla entera. */
.inbox-cabeza { color: var(--odoo-primary); font-weight: 600; cursor: pointer; white-space: nowrap; }
.inbox-cabeza:hover { text-decoration: underline; }
.inbox-flecha { font-size: 10px; margin-right: 0.15rem; }
.inbox-desglose > td { background: #f8f9fa; border-top: 0; }
.inbox-desglose-caja { max-height: 260px; overflow-y: auto; font-size: 12px; }
.inbox-linea { padding: 0.2rem 0; border-bottom: 1px dashed #e2e8f0; }
.inbox-linea:last-child { border-bottom: 0; }
.inbox-motivos { list-style: none; padding: 0; margin: 0; color: #92400e; font-size: 12px; }

/* ═══ [UI/UX · B9 · §6.5] Tablero de pedidos ═══
   Las ~110 líneas de `<style>` que vivían dentro de `order_board.html` (plantilla
   ya borrada). Suben al tema por el mismo motivo que las del taller en B5: el
   cuerpo se sirve como fragmento y un `<style>` reinsertado se duplica en cada
   cambio de pestaña. */
.board-grid { display: flex; gap: 1rem; align-items: flex-start; overflow-x: auto; padding-bottom: 0.5rem; }
.board-col { flex: 1 1 0; min-width: 290px; background: #f8f9fa; border-radius: 10px; display: flex; flex-direction: column; }
.board-col.col-hidden { display: none; }
.board-col-header {
    padding: 0.6rem 0.85rem; border-radius: 10px 10px 0 0; font-weight: 700;
    font-size: 13px; color: white; display: flex; align-items: center; gap: 0.4rem;
}
.board-cards { padding: 0.5rem; min-height: 80px; flex: 1 1 auto; }
.board-col .empty-hint { display: none; text-align: center; color: #9ca3af; font-size: 12px; padding: 1.5rem 0; }
.board-col.is-empty .empty-hint { display: block; }

/* [D15 · P4] Vista MATRIZ: con una sola columna visible las cards se reparten a
   todo lo ancho en `auto-fill`, y el orden se lee POR FILAS (izq→der, arriba→
   abajo), que es el orden del DOM y por tanto el que persiste el arrastre. */
.board-grid.board-matriz .board-col.col-matriz { min-width: 100%; }
.board-grid.board-matriz .board-col.col-matriz .board-cards {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 0.5rem;
    align-items: start;
}
.board-grid.board-matriz .board-col.col-matriz .board-card { margin-bottom: 0; }
.board-card-orden {
    display: inline-block; min-width: 20px; margin-right: 0.35rem; padding: 0 0.3rem;
    border-radius: 999px; background: #e2e8f0; color: #334155; font-size: 10px;
    font-weight: 700; text-align: center; vertical-align: middle;
}

.board-card {
    background: white; border-radius: 10px; padding: 0; margin-bottom: 0.5rem;
    box-shadow: 0 1px 4px rgba(0,0,0,0.06); border-left: 4px solid #94a3b8; overflow: hidden;
}
.board-card-ghost { opacity: 0.4; }
.board-card-head { padding: 0.6rem 0.7rem; cursor: grab; }
.board-card-head:active { cursor: grabbing; }
.board-card-toprow { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.35rem; }
.board-card-badge { display: flex; flex-wrap: wrap; gap: 0.2rem; justify-content: flex-end; }
.board-card-num { font-weight: 800; font-size: 14px; }
.board-card-num a { color: inherit; text-decoration: none; }
.board-card-num a:hover { text-decoration: underline; }
.board-card-client { font-size: 11px; color: #6b7280; margin-top: 1px; }
.board-card-fechas { font-size: 10px; color: #6b7280; margin-top: 0.3rem; }
.board-chip-atencion { background: #fef3c7; color: #92400e; font-size: 10px; }
.board-card-actions { display: flex; align-items: center; gap: 0.35rem; margin-top: 0.5rem; }
.adv-slot { flex: 1 1 auto; }
.board-adv-btn {
    border: none; border-radius: 6px; padding: 5px 10px; font-size: 11px;
    font-weight: 700; color: #fff; cursor: pointer; width: 100%;
}
.board-adv-btn:hover { opacity: 0.92; }
.board-adv-secondary { background: #fff; color: #6b7280; border: 1px solid #d1d5db; }
.board-adv-secondary:hover { background: #f3f4f6; color: #374151; }
/* Toggle del desplegable: SIEMPRE con texto ("Ver líneas" / "Ocultar") + un
   chevron que apunta hacia abajo cuando está cerrado (invita a abrir) y hacia
   arriba cuando está abierto. Nunca a la derecha (eso se lee como "avanzar"). */
.board-collapse-btn {
    border: 1px solid #d1d5db; background: #fff; border-radius: 6px; padding: 4px 9px;
    cursor: pointer; color: #4b5563; line-height: 1; flex: 0 0 auto;
    display: inline-flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 600;
}
.board-collapse-btn:hover { background: #f3f4f6; color: #111827; }
.board-collapse-btn .bi { transition: transform 0.15s; display: inline-block; transform: rotate(180deg); }
.board-collapse-btn .lbl-ver { display: none; }
.board-collapse-btn.collapsed .bi { transform: rotate(0deg); }
.board-collapse-btn.collapsed .lbl-ver { display: inline; }
.board-collapse-btn.collapsed .lbl-ocultar { display: none; }

.board-lanzar-btn {
    display: block; width: 100%; margin-top: 0.5rem; border: none; border-radius: 6px;
    padding: 7px 10px; background: #6366f1; color: #fff; font-size: 12px; font-weight: 700;
    cursor: pointer;
}
.board-lanzar-btn:hover:not(:disabled) { background: #4f46e5; }
.board-lanzar-btn:disabled { background: #c7d2fe; cursor: not-allowed; }
.board-lanzado-nota {
    margin-top: 0.5rem; padding: 5px 8px; background: #f0fdf4; border-radius: 6px;
    font-size: 10px; color: #15803d; text-align: center;
}
.board-lanzado-nota a { color: #15803d; font-weight: 700; }

.board-card-body { display: none; border-top: 1px solid #f1f3f5; padding: 0.4rem 0.5rem 0.55rem; }
.board-card-body.show { display: block; }
.board-lines-table { width: 100%; font-size: 11px; border-collapse: collapse; }
.board-lines-table th {
    font-size: 9px; text-transform: uppercase; letter-spacing: 0.3px; color: #9ca3af;
    font-weight: 700; padding: 2px 3px; text-align: center; border-bottom: 1px solid #eee;
}
.board-lines-table td { padding: 3px; text-align: center; border-bottom: 1px solid #f3f4f6; vertical-align: middle; }
.board-lines-table tr:last-child td { border-bottom: none; }
.board-lines-table td.code { text-align: left; font-weight: 700; }
.board-lines-table td.code a { color: #2563eb; text-decoration: none; }
.board-completo-more { padding: 0.5rem; text-align: center; }
/* La tabla del colapsable se reutiliza dentro del diálogo de "Iniciar Revisión"
   (D11): misma tabla, redundancia intencional del spec. */
.board-dlg-lineas { max-height: 260px; overflow-y: auto; border: 1px solid #e9ecef; border-radius: 6px; padding: 0.4rem; }

/* Slots RES/PTE/ENV (mismo aspecto que en el detalle del pedido, §6.5.12) */
.slot-cell { display: inline-flex; align-items: center; gap: 2px; }
.slot-input {
    width: 40px; text-align: center; font-size: 11px; font-weight: 700; padding: 1px 2px;
    border: 1px solid #dee2e6; border-radius: 5px; -moz-appearance: textfield;
}
.slot-input::-webkit-outer-spin-button, .slot-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.slot-input:focus { outline: none; border-color: var(--odoo-primary); }
.slot-check { border: none; background: transparent; padding: 0; line-height: 1; cursor: pointer; font-size: 13px; }
.slot-check:disabled { opacity: 0.5; cursor: not-allowed; }

/* Barra de control de columnas */
.board-controls { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.board-toggle-col {
    border: 1px solid #e5e7eb; background: #fff; border-radius: 20px; padding: 3px 11px;
    font-size: 12px; font-weight: 600; color: #6b7280; cursor: pointer; display: inline-flex;
    align-items: center; gap: 0.35rem;
}
.board-toggle-col .dot, .board-cols-dropdown .dot {
    width: 9px; height: 9px; border-radius: 50%; background: var(--c); display: inline-block;
}
.board-toggle-col.active { color: #111827; border-color: var(--c); background: color-mix(in srgb, var(--c) 10%, #fff); }
.board-toggle-col:not(.active) { opacity: 0.55; }
.board-toggle-col:not(.active) .dot { background: #cbd5e1; }
.board-ctrl-count { font-size: 10px; background: #f1f3f5; border-radius: 10px; padding: 0 6px; }
.board-cols-dropdown label { cursor: pointer; font-size: 13px; }
.board-gear {
    border: 1px solid #e5e7eb; background: #fff; border-radius: 8px; width: 30px; height: 30px;
    color: #6b7280; cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
}
.board-gear:hover { background: #f3f4f6; color: var(--odoo-primary); }

/* ═══════════════════════════════════════════════════════════════════════════
   [UI/UX · B11 · P7] Rejilla de datos tipo SSMS + combobox con predictivo
   ═══════════════════════════════════════════════════════════════════════════
   Dos componentes que nacen en el mismo bloque y comparten una idea: el listado
   deja de ser una tabla web paginada y pasa a recorrerse como una rejilla densa.
   El contrato del servidor vive en `apps/core/rejilla.py`; el comportamiento, en
   `core/js/nexus_rejilla.js`.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── La caja con scroll: es quien fija la cabecera ─────────────────────────
   `position: sticky` necesita un ancestro con scroll propio. Con la altura
   calculada contra la ventana, la cabecera se queda arriba y el pie de "cargar
   más" no se va de la pantalla a medida que la tabla crece. */
.nexus-rejilla-scroll {
    max-height: calc(100vh - 300px);
    min-height: 240px;
    overflow: auto;
    position: relative;
}
.nexus-rejilla.cargando { opacity: 0.75; }

.nexus-rejilla-tabla {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 12.5px;
    table-layout: fixed;
}

/* ── Cabecera fija ─────────────────────────────────────────────────────────
   `sticky` es además posición: el agarre de redimensionado se ancla al propio
   <th> sin necesidad de un `position: relative` extra. */
.nexus-rejilla-tabla thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    background: #f7f3f6;
    border-bottom: 2px solid #e5e7eb;
    border-right: 1px solid #ede9ee;
    padding: 6px 8px;
    text-align: left;
    vertical-align: top;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.2px;
    color: #6b7280;
    user-select: none;
    overflow: hidden;
}
.nexus-rejilla-tabla thead th:last-child { border-right: 0; }
.nexus-rejilla-th { display: flex; align-items: center; gap: 4px; min-height: 20px; }
.nexus-rejilla-th-fijo { font-weight: 600; }
.nexus-rejilla-filtro { margin-top: 4px; }

/* La columna del número de fila: estrecha, gris y fuera del copiado. */
.nexus-rejilla-num {
    width: 46px; min-width: 46px; text-align: right !important;
    color: #9ca3af; font-variant-numeric: tabular-nums;
}
.nexus-rejilla-tabla tbody td.nexus-rejilla-num { font-size: 11px; }

/* ── Filas densas ────────────────────────────────────────────────────────── */
.nexus-rejilla-tabla tbody td {
    padding: 3px 8px;
    border-bottom: 1px solid #f1f1f4;
    border-right: 1px solid #f6f6f8;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: middle;
}
.nexus-rejilla-tabla tbody td:last-child { border-right: 0; }
.nexus-rejilla-tabla tbody tr:nth-child(even) { background: #fcfcfd; }
.nexus-rejilla-tabla tbody tr:hover { background: #f3f0f5; }
.nexus-rejilla-tabla tbody tr.sel { background: #ece3f0 !important; }
.nexus-rejilla-tabla tbody tr.activa td {
    border-top: 1px solid var(--odoo-primary);
    border-bottom-color: var(--odoo-primary);
}
.nexus-rejilla-tabla tbody tr.bajo-minimo td { background-color: rgba(220, 53, 69, 0.05); }

/* ── Ocultar una columna ─────────────────────────────────────────────────── */
.nexus-col-oculta { display: none !important; }

/* ── Filas de detalle: la rejilla de dos niveles (BLANK/OFT · B8) ──────────
   El contrato está en `apps/core/rejilla.py`. Aquí solo el aspecto: la fila de
   detalle no es una fila más, así que ni se raya en zebra ni se recorta con
   ellipsis — dentro va una tabla propia que sí puede ocupar lo que necesite.
   ⚠️ En una rejilla con detalle la zebra deja de alternar (todas las filas
   reales caen en posición impar). Es a propósito: quien marca dónde estás es la
   fila desplegada, no el rayado. */
/* Explícito y no confiando en el reboot de Bootstrap: una fila de detalle que se
   pintara desplegada al cargar seria una pantalla rota, no un detalle de estilo. */
.nexus-rejilla-tabla tbody tr.nexus-rejilla-detalle[hidden] { display: none; }
.nexus-rejilla-tabla tbody tr.nexus-rejilla-detalle:hover { background: transparent; }
.nexus-rejilla-tabla tbody tr.nexus-rejilla-detalle > td {
    white-space: normal; overflow: visible; text-overflow: clip;
    padding: 0; background: #fbfafc; border-right: 0;
}
.nexus-rejilla-tabla tbody tr.desplegada > td {
    background: #f6f2f8; border-bottom-color: transparent;
}
.nexus-desplegar {
    border: 0; background: transparent; padding: 0 4px 0 0; line-height: 1;
    color: #9ca3af; cursor: pointer; font-size: 11px;
}
.nexus-desplegar:hover { color: var(--odoo-primary); }
.nexus-desplegar i { transition: transform 0.12s ease; display: inline-block; }
.nexus-desplegar.abierto i { transform: rotate(90deg); }

/* ── Artículos BLANK OFT de un Código BLANK (`_blank_lotes_tabla.html`) ──── */
.blank-lotes { padding: 6px 16px 8px; }
.blank-lotes-vacia { font-size: 12px; }
/* En el catálogo el bloque se sangra hasta debajo del código, que es de donde
   cuelga: el nº de fila más el chevrón. */
.blank-lotes-compacta { padding-left: 52px; }
.blank-lotes-tabla { width: 100%; font-size: 12px; border-collapse: collapse; }
.blank-lotes-tabla thead th {
    font-size: 10px; text-transform: uppercase; letter-spacing: 0.3px;
    color: #9ca3af; font-weight: 700; padding: 2px 8px; border-bottom: 1px solid #e9e7ee;
    white-space: nowrap;
}
.blank-lotes-tabla tbody td {
    padding: 3px 8px; border-bottom: 1px solid #f1f0f4; white-space: nowrap;
    background: transparent;
}
.blank-lotes-tabla tbody tr:last-child td { border-bottom: 0; }
.blank-lotes-tabla tbody tr.lote-negativo td { background: rgba(239, 68, 68, 0.06); }
.blank-lotes-tabla tbody tr.lote-cero td { color: #9ca3af; }
.blank-lote-code { font-family: monospace; font-weight: 700; color: #374151; }
.blank-lote-cajon {
    display: inline-block; margin-right: 6px; padding: 0 5px; border-radius: 4px;
    background: #eef2f7; color: #4b5563; font-size: 11px;
}
.blank-lote-nota { font-size: 10px; color: #9ca3af; font-weight: 400; margin-left: 4px; }
.blank-lotes-tabla .badge { font-size: 10px; font-weight: 600; }
.blank-lotes-compacta .blank-lotes-tabla { font-size: 11.5px; }

/* ── Agarre de redimensionado ─────────────────────────────────────────────
   Es un elemento propio en el borde del <th> y no el borde a secas: si fuera el
   borde, competiría con el click del enlace de ordenar. */
.nexus-rejilla-agarre {
    position: absolute; top: 0; right: 0; width: 6px; height: 100%;
    cursor: col-resize; z-index: 4;
}
.nexus-rejilla-agarre:hover { background: var(--odoo-primary); opacity: 0.35; }
body.nexus-rejilla-redim { cursor: col-resize; user-select: none; }

/* ── Controles de filtro dentro de la cabecera ───────────────────────────── */
.nexus-rejilla-input {
    width: 100%; font-size: 11px; padding: 1px 5px; height: 22px;
    border: 1px solid #ddd6e0; border-radius: 4px; background: #fff;
    color: #374151; text-transform: none; font-weight: 400;
}
.nexus-rejilla-input:focus { outline: none; border-color: var(--odoo-primary); }
.nexus-rejilla-rango { display: flex; gap: 3px; }

/* ── Barra superior y pie ────────────────────────────────────────────────── */
.nexus-rejilla-barra { border-bottom: 1px solid #eef0f2; background: #fff; }
.nexus-rejilla-pie { border-top: 1px solid #eef0f2; background: #fbfbfc; }
.nexus-rejilla-fin { height: 1px; }
.nexus-rejilla-cols { max-height: 320px; overflow: auto; min-width: 210px; }
.nexus-rejilla-col-item { display: flex; align-items: center; font-size: 12.5px; cursor: pointer; }

/* ── Combobox con predictivo (NexusModal tipo:'autocompletar') ─────────────
   [mini-spec desplegable · D1] La lista es `fixed` y la coloca el JS contra la
   VENTANA (`montarAutocompletar::colocar`): `left`, `width`, `max-height` y
   `top`/`bottom` llegan de ahí. Era `absolute` dentro de `.nexus-ac`, y el
   cuerpo del diálogo —que siempre es `modal-dialog-scrollable`, o sea
   `overflow-y:auto`— la recortaba a las dos o tres filas que cupieran por
   debajo del campo. Un elemento fijo tiene el viewport por bloque contenedor y
   ningún `overflow` de un ancestro lo recorta.
   `.nexus-ac` deja de ser el ancla pero sigue existiendo: es lo que mantiene a
   la lista pegada al campo en el DOM, para que se la lleve por delante el
   mismo reemplazo de cuerpo que se lleva al `<input>`.
   El z-index supera al del modal de Bootstrap (1055): si no, la lista se
   pintaría por debajo. */
.nexus-ac { position: relative; }
.nexus-ac-lista {
    position: fixed; z-index: 1090; right: auto;
    max-height: 460px; overflow-y: auto;
    background: #fff; border: 1px solid #e5e7eb; border-radius: 8px;
    box-shadow: 0 8px 24px rgba(17, 24, 39, 0.12);
}
.nexus-ac-item { padding: 5px 10px; cursor: pointer; border-bottom: 1px solid #f5f5f7; }
.nexus-ac-item:last-child { border-bottom: 0; }
.nexus-ac-item:hover, .nexus-ac-item.activo { background: #f3f0f5; }
/* [D4] `nowrap`: las cifras NO bajan de línea ni se desplazan por un código
   largo — antes es el código el que se trunca. Es lo que sostiene la columna. */
.nexus-ac-codigos { display: flex; align-items: baseline; gap: 8px; flex-wrap: nowrap; }
.nexus-ac-codigo {
    font-weight: 700; font-size: 12.5px; color: var(--odoo-primary);
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.nexus-ac-ref { font-size: 11.5px; color: #6b7280; font-family: monospace; white-space: nowrap; }
.nexus-ac-stock { font-size: 10.5px; color: #9ca3af; margin-left: auto; white-space: nowrap; }
.nexus-ac-desc {
    font-size: 11.5px; color: #4b5563; white-space: nowrap;
    overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
.nexus-ac-vacio, .nexus-ac-mas { padding: 8px 10px; font-size: 11.5px; color: #9ca3af; text-align: center; }
/* [FAMILIAS Y PROCESOS · B5 · FP35] Una lista vacía no siempre es una laguna: la de un
   rodillo es LA respuesta, porque los rodillos parten de colada y no llevan BLANK. El
   servidor manda el tono (`motivo_tono`) y aquí se traduce: `info` es una nota, no un
   hueco. `apagado` es el gris de siempre, y sigue siendo el defecto. */
.nexus-ac-vacio.tono-info {
    color: #1e40af; background: #eff6ff; text-align: left;
    border-left: 3px solid #93b4e8;
}
.nexus-ac-vacio.tono-apagado { color: #9ca3af; }
/* Lo que hay que leer antes de mirar la lista: el código propuesto y de dónde sale
   (§5.2, el BLANK base no es la medida exacta), o que todavía no existe en el catálogo. */
.nexus-ac-cabecera {
    padding: 7px 10px; font-size: 11.5px; color: #374151;
    background: #f8f7fa; border-bottom: 1px solid #ececf1;
}

/* ── Desplegable SECCIONADO (BLANK/OFT · B9 · spec §7.2) ───────────────────
   El mismo combobox, agrupado. La cabecera de sección NO es una fila: no se
   elige, no se numera y el teclado la salta (ver `nexus_modal.js::html`).
   El `tono` lo manda el servidor (ok · ambar · rojo · info · apagado) y aquí
   —y solo aquí— se traduce a color: el JS no sabe qué es "libre". La banda
   roja no se esconde ni se recorta a propósito: un artículo a cero es un
   recado para el cliente y uno sobrecomprometido es un descuadre que hay que
   ver (§7.4, §8.3). */
.nexus-ac-seccion {
    display: flex; align-items: baseline; gap: 6px; padding: 5px 10px;
    background: #f8f7fa; border-top: 1px solid #ececf1; border-bottom: 1px solid #ececf1;
    position: sticky; top: 0; z-index: 1;
}
.nexus-ac-seccion:first-child { border-top: 0; }
.nexus-ac-seccion-nombre { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .3px; color: #6b7280; }
.nexus-ac-seccion-n {
    font-size: 10px; font-weight: 700; color: #6b7280; background: #ececf1;
    border-radius: 8px; padding: 0 6px;
}
.nexus-ac-seccion-nota { font-size: 10.5px; color: #9ca3af; margin-left: auto; text-align: right; }
.nexus-ac-seccion.tono-ambar { background: #fff8ec; border-color: #f5e2c0; }
.nexus-ac-seccion.tono-ambar .nexus-ac-seccion-nombre,
.nexus-ac-seccion.tono-ambar .nexus-ac-seccion-nota { color: #a16207; }
.nexus-ac-seccion.tono-rojo { background: #fdf2f2; border-color: #f5cfcf; }
.nexus-ac-seccion.tono-rojo .nexus-ac-seccion-nombre,
.nexus-ac-seccion.tono-rojo .nexus-ac-seccion-nota { color: #b91c1c; }
/* [FAMILIAS Y PROCESOS · B5 · §7] La sección de más — lo que el usuario ha ido a
   buscar, que no sale del artículo de la orden. En azul y no en gris porque no es el
   resto de la lista: es otra pregunta. */
.nexus-ac-seccion.tono-info { background: #eff6ff; border-color: #cfe0f5; }
.nexus-ac-seccion.tono-info .nexus-ac-seccion-nombre,
.nexus-ac-seccion.tono-info .nexus-ac-seccion-nota { color: #1e40af; }
.nexus-ac-item.tono-ambar { background: rgba(245, 158, 11, 0.05); }
.nexus-ac-item.tono-rojo { background: rgba(239, 68, 68, 0.05); }
/* Sin estas dos, la fila de una banda de color perderia el resalte del raton y del
   teclado: `.nexus-ac-item:hover` tiene la misma especificidad y va ANTES en el
   archivo, asi que ganaria el tono y moverse por la lista dejaria de verse. */
.nexus-ac-item.tono-ambar:hover, .nexus-ac-item.tono-ambar.activo { background: rgba(245, 158, 11, 0.16); }
.nexus-ac-item.tono-rojo:hover, .nexus-ac-item.tono-rojo.activo { background: rgba(239, 68, 68, 0.16); }

/* Las DOS cifras de §7.2, siempre juntas: en cajón y libre.
   [mini-spec desplegable · D4] En COLUMNA: ancho fijo, alineadas a la derecha y con
   cifras tabulares, así que "en cajón" y "libre" caen en la misma vertical en todas
   las filas y se comparan bajando el ojo. Con `margin-left:auto` a secas cada fila las
   ponía donde acabara su código, que es lo que hacía ilegible un listado de cuatro o
   más. `flex: 0 0 auto` para que no las encoja un código largo: el que se trunca es él. */
.nexus-ac-cifras { display: flex; gap: 6px; margin-left: auto; flex: 0 0 auto; }
.nexus-ac-cifra {
    font-size: 10.5px; color: #9ca3af; white-space: nowrap;
    min-width: 72px; text-align: right; font-variant-numeric: tabular-nums;
}
.nexus-ac-cifra b { color: #374151; font-size: 11.5px; }
.nexus-ac-cifra.tono-ok b { color: #15803d; }
.nexus-ac-cifra.tono-rojo b { color: #b91c1c; }
.nexus-ac-cifra.tono-apagado b { color: #9ca3af; }

/* [D4] La SEGUNDA línea de la fila, y la única: chapas + descripción + nota en un
   renglón que se trunca. Antes eran tres bloques apilados y la fila medía cuatro
   líneas; el texto completo sigue disponible en el `title` que pone el JS. */
.nexus-ac-detalle {
    display: flex; align-items: center; gap: 5px; margin-top: 2px;
    flex-wrap: nowrap; overflow: hidden; white-space: nowrap;
}
.nexus-ac-chapa {
    font-size: 10px; font-weight: 600; border-radius: 4px; padding: 1px 5px;
    background: #ececf1; color: #4b5563; flex: 0 0 auto;
}
.nexus-ac-chapa.tono-ambar { background: #fef3c7; color: #92400e; }
.nexus-ac-chapa.tono-rojo { background: #fee2e2; color: #991b1b; }
.nexus-ac-chapa.tono-info { background: #dbeafe; color: #1e40af; }

/* [mini-spec blank-sugerido] La chapa del artículo BLANK PROPUESTO en «Por revisar».
   Estrena el tono `rojo` en la tarjeta —un Código BLANK con todos sus artículos sin piezas
   requiere reposición—, con los mismos colores que la banda roja del desplegable. Las
   marcas («BLANK base», la edad de la foto del Kardex) van más pequeñas que la chapa
   porque la acompañan, y el detalle es la línea que dice qué hacer cuando no hay
   propuesta: el porqué lo escribe `blank_propuesto.py`, aquí solo se le da sitio. */
.rev-blank-rojo { background: #fee2e2; color: #991b1b; border-color: #fecaca; }
.rev-blank-marca { margin-left: 0.3rem; font-size: 10.5px; font-weight: 600; padding: 1px 7px; }
.rev-blank-detalle { margin-top: 3px; font-size: 11px; color: #64748b; max-width: 640px; }
