/* ZMR-ERP. Hoja única, sin build ni web fonts. Rediseño de julio 2026 con
   densidad de ERP (Odoo, SAP B1): borde de 1px en vez de sombras, un solo
   acento (#0f3d63, sacado de img/icon.svg) y 13px de sistema. */

:root {
    --fondo:        #f4f6f8;
    --superficie:   #ffffff;
    --borde:        #dde2e8;   /* superficies y controles */
    --borde-suave:  #e8ecf0;   /* separadores de filas */
    --borde-fuerte: #c6cdd6;   /* punteados e inputs, tiene que notarse */

    --acento:       #0f3d63;
    --acento-hover: #15507f;
    --acento-tenue: #e9f0f6;   /* fondos de ítem activo / hover de acento */
    --acento-claro: #5fb0e6;   /* detalle de marca y anillo de foco */

    --tinta:        #1f2733;
    --tinta-suave:  #5a6472;
    --tinta-tenue:  #8b95a3;

    /* el tenue es fondo de chip, el sólido va en el punto y el texto */
    --ok:            #1a7f4b;  --ok-tenue:      #e6f3ec;  --ok-borde:      #c8e4d4;
    --alerta:        #b45309;  --alerta-tenue:  #faf0e1;  --alerta-borde:  #eed9b8;
    --peligro:       #b42318;  --peligro-tenue: #faeae8;  --peligro-borde: #f0ccc8;
    --info:          #175cd3;  --info-tenue:    #e9f0fb;  --info-borde:    #cbdaf3;

    --radio:          6px;     /* el máximo del sistema */
    --radio-chico:    4px;     /* inputs, miniaturas */
    --esp-1: 4px;  --esp-2: 8px;  --esp-3: 12px;  --esp-4: 16px;
    --alto-control:   32px;
    --alto-topbar:    48px;
    --ancho-sidebar:      232px;
    --ancho-sidebar-mini: 56px;
    --ancho-vista:    1200px;

    font-family: system-ui, "Segoe UI", Roboto, sans-serif;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
body { background: var(--fondo); color: var(--tinta); font-size: 13px; line-height: 1.45; }
a { color: var(--acento); text-decoration: none; }
a:hover { color: var(--acento-hover); }

/* sobre el azul del topbar el anillo normal casi no se ve, ahí va uno más claro */
:focus-visible { outline: 2px solid var(--acento-claro); outline-offset: 1px; }
.topbar :focus-visible { outline-color: #9cc9ec; }

@media (prefers-reduced-motion: reduce) {
    * { transition: none !important; animation: none !important; }
}

/* barra fina de acento en vez de spinner */
.cargando { text-align: center; color: var(--tinta-tenue); font-size: 12.5px; padding: 48px 0; }
.cargando::before {
    content: ''; display: block; width: 48px; height: 2px; margin: 0 auto 10px;
    background: var(--acento); animation: pulso-carga .8s ease-in-out infinite alternate;
}
@keyframes pulso-carga { from { opacity: .25; } to { opacity: 1; } }
#app > .cargando { min-height: 100vh; display: grid; place-items: center; padding: 0; }
#app > .cargando::before { margin: 0 auto 10px; }

/* topbar */
.topbar {
    background: var(--acento); color: #fff; position: sticky; top: 0; z-index: 70;
    display: flex; align-items: center; gap: var(--esp-2);
    height: var(--alto-topbar); padding: 0 var(--esp-3);
}
.topbar .marca { display: flex; align-items: center; gap: 9px; font-weight: 700; letter-spacing: .3px; font-size: 15px; cursor: pointer; white-space: nowrap; padding: 4px 6px; border-radius: var(--radio-chico); }
.topbar .marca img { display: block; height: 20px; width: auto; }
.topbar .marca span span { color: var(--acento-claro); }
.topbar-titulo {
    font-size: 12.5px; color: rgba(255,255,255,.8); white-space: nowrap;
    overflow: hidden; text-overflow: ellipsis;
    border-left: 1px solid rgba(255,255,255,.25); padding-left: var(--esp-3); margin-left: var(--esp-1);
}
.topbar-flex { flex: 1; }

.btn-menu { flex: 0 0 auto; }
.btn-icono {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    width: auto; min-width: var(--alto-control); height: var(--alto-control);
    padding: 0 6px; border: 0; border-radius: var(--radio);
    background: transparent; color: inherit; cursor: pointer;
    font: inherit; font-size: 12.5px; white-space: nowrap;
    transition: background .12s;
}
.topbar .btn-icono { color: #e8f0f7; }
.topbar .btn-icono:hover { background: rgba(255,255,255,.12); color: #fff; }
.icono { display: inline-grid; place-items: center; line-height: 0; }
.icono svg { display: block; }

.topbar-campana { position: relative; }
.topbar-campana .pastilla {
    position: absolute; top: 1px; right: -2px;
    min-width: 15px; height: 15px; line-height: 15px; font-size: 9.5px; padding: 0 4px;
    box-shadow: 0 0 0 2px var(--acento);
}

/* la campana y su panel: mismo lenguaje que el menú de usuario, más ancho
   porque cada renglón lleva título, folio y antigüedad */
.campana { position: relative; }
.campana-panel {
    position: absolute; right: 0; top: calc(100% + 6px); z-index: 80;
    width: 340px; max-width: calc(100vw - 24px);
    background: var(--superficie); color: var(--tinta);
    border: 1px solid var(--borde); border-radius: var(--radio);
    box-shadow: 0 4px 12px rgba(16, 32, 55, .14); overflow: hidden;
}
.campana-panel[hidden] { display: none; }
.campana-cab {
    display: flex; align-items: center; justify-content: space-between; gap: var(--esp-2);
    padding: 9px 14px; border-bottom: 1px solid var(--borde-suave);
    font-size: 12px; font-weight: 600; text-transform: uppercase;
    letter-spacing: .3px; color: var(--tinta-suave);
}
.campana-marcar {
    border: 0; background: none; cursor: pointer; font: inherit; font-size: 11.5px;
    font-weight: 600; text-transform: none; letter-spacing: 0; color: var(--acento); padding: 0;
}
.campana-marcar:hover { text-decoration: underline; }
/* tope de alto: con 30 avisos el panel se saldría de la pantalla */
.campana-lista { max-height: min(60vh, 420px); overflow-y: auto; }
.campana-item {
    display: flex; align-items: flex-start; gap: 8px; width: 100%;
    padding: 10px 14px; border: 0; border-bottom: 1px solid var(--borde-suave);
    background: none; cursor: pointer; font: inherit; text-align: left; color: var(--tinta);
}
.campana-item:last-child { border-bottom: 0; }
.campana-item:hover { background: var(--fondo); }
/* el punto ocupa su lugar siempre, así los títulos quedan alineados */
.campana-punto {
    flex: 0 0 auto; width: 7px; height: 7px; margin-top: 5px; border-radius: 50%; background: none;
}
.campana-item.sin-leer .campana-punto { background: var(--acento); }
.campana-item.sin-leer .campana-titulo { font-weight: 600; }
.campana-texto { min-width: 0; }
.campana-titulo { font-size: 13px; line-height: 1.35; }
.campana-titulo .badge.mini { margin-left: 6px; font-size: 9.5px; padding: 1px 5px; vertical-align: 1px; }
.campana-meta { font-size: 11.5px; color: var(--tinta-tenue); margin-top: 2px; }
.campana-detalle {
    font-size: 12px; color: var(--tinta-suave); margin-top: 3px;
    overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.campana-vacio { padding: 22px 14px; text-align: center; font-size: 12.5px; color: var(--tinta-tenue); }

.usuario-menu { position: relative; }
.usuario-boton .usuario-nombre { max-width: 160px; overflow: hidden; text-overflow: ellipsis; }
.menu-usuario-panel {
    position: absolute; right: 0; top: calc(100% + 6px); z-index: 80;
    min-width: 230px; background: var(--superficie); color: var(--tinta);
    border: 1px solid var(--borde); border-radius: var(--radio);
    box-shadow: 0 4px 12px rgba(16, 32, 55, .14); overflow: hidden;
}
.menu-usuario-panel[hidden] { display: none; }
.menu-usuario-cab { padding: 10px 14px; border-bottom: 1px solid var(--borde-suave); }
.menu-usuario-cab .nombre { font-weight: 600; font-size: 13px; }
.menu-usuario-cab .correo { color: var(--tinta-suave); font-size: 12px; margin-top: 1px; }
.menu-usuario-cab .rol { color: var(--tinta-tenue); font-size: 11.5px; margin-top: 3px; text-transform: uppercase; letter-spacing: .3px; }
.menu-usuario-item {
    display: flex; align-items: center; gap: 8px; width: 100%;
    padding: 9px 14px; border: 0; background: none; cursor: pointer;
    font: inherit; font-size: 13px; color: var(--tinta); text-align: left;
}
.menu-usuario-item:hover { background: var(--fondo); }
.menu-usuario-item .icono { color: var(--tinta-tenue); }

/* sidebar y contenido */
.shell { display: flex; align-items: stretch; }
.sidebar {
    width: var(--ancho-sidebar); flex: 0 0 auto;
    background: var(--superficie); border-right: 1px solid var(--borde);
    position: sticky; top: var(--alto-topbar); height: calc(100vh - var(--alto-topbar));
    overflow-y: auto; overflow-x: hidden;
    display: flex; flex-direction: column; padding: var(--esp-2) 0;
    transition: width .15s ease;
}
.sidebar nav { flex: 1; display: flex; flex-direction: column; gap: 1px; padding: 0 var(--esp-2); }

.nav-grupo {
    margin: var(--esp-4) var(--esp-2) var(--esp-1); padding-top: 0;
    font-size: 10.5px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase;
    color: var(--tinta-tenue); white-space: nowrap;
}
.nav-item {
    position: relative; display: flex; align-items: center; gap: 10px;
    height: var(--alto-control); padding: 0 10px; border-radius: var(--radio);
    color: var(--tinta-suave); font-size: 13px; font-weight: 500; white-space: nowrap;
    transition: background .12s, color .12s;
}
.nav-item .icono { flex: 0 0 auto; width: 20px; color: var(--tinta-tenue); }
.nav-item .nav-texto { flex: 1; overflow: hidden; text-overflow: ellipsis; }
.nav-item:hover { background: var(--fondo); color: var(--tinta); }
.nav-item.activo { background: var(--acento-tenue); color: var(--acento); font-weight: 600; }
.nav-item.activo .icono { color: var(--acento); }
.nav-item.activo::before {
    content: ''; position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px;
    border-radius: 0 2px 2px 0; background: var(--acento);
}
.nav-item .pastilla { flex: 0 0 auto; }

.sidebar-pie { border-top: 1px solid var(--borde-suave); padding: var(--esp-2) var(--esp-2) 0; }
.nav-colapsar { width: 100%; border: 0; background: none; cursor: pointer; font: inherit; text-align: left; }

/* el colapso a iconos es solo de escritorio, en móvil la sidebar es off-canvas */
@media (min-width: 769px) {
    body.sidebar-mini .sidebar { width: var(--ancho-sidebar-mini); }
    body.sidebar-mini .nav-texto,
    body.sidebar-mini .nav-item .pastilla,
    body.sidebar-mini .nav-grupo span { display: none; }
    body.sidebar-mini .nav-item { justify-content: center; padding: 0; }
    body.sidebar-mini .nav-grupo { margin: var(--esp-2) 10px; border-top: 1px solid var(--borde-suave); height: 0; overflow: hidden; }
    body.sidebar-mini .nav-colapsar .icono svg { transform: rotate(180deg); }
}

/* el velo solo aparece en móvil con la sidebar abierta */
.sidebar-velo { display: none; }

/* la sidebar solo existe dentro de un módulo, el inicio no lleva nav lateral */
body.sin-modulo .sidebar,
body.sin-modulo .sidebar-velo,
body.sin-modulo .btn-menu { display: none; }

.contenido { flex: 1; min-width: 0; padding: var(--esp-4) 24px 60px; }
#vista { max-width: var(--ancho-vista); margin: 0 auto; }

/* en planta la abren desde el teléfono, así que aquí la sidebar es off-canvas */
@media (max-width: 768px) {
    .sidebar {
        position: fixed; left: 0; top: var(--alto-topbar); bottom: 0; height: auto;
        width: 248px; z-index: 60; transform: translateX(-100%);
        transition: transform .15s ease; border-right: 1px solid var(--borde);
    }
    body.sidebar-abierta .sidebar { transform: none; }
    .sidebar-velo { display: none; position: fixed; inset: 0; top: var(--alto-topbar); z-index: 55; background: rgba(15, 25, 40, .4); }
    body.sidebar-abierta .sidebar-velo { display: block; }
    .sidebar-pie { display: none; }   /* el colapso a iconos no aplica en móvil */
    .contenido { padding: var(--esp-3) var(--esp-3) 60px; }
}
@media (max-width: 640px) {
    .topbar-titulo, .usuario-boton .usuario-nombre { display: none; }
}

/* encabezado de página, lo arma encabezadoPagina() en ui.js */
.encabezado-pagina {
    display: flex; align-items: flex-end; justify-content: space-between;
    margin-bottom: var(--esp-4); gap: var(--esp-3); flex-wrap: wrap;
}
.encabezado-info { min-width: 0; }
.encabezado-pagina h1 { font-size: 17px; font-weight: 650; line-height: 1.25; }
.encabezado-pagina .sub { color: var(--tinta-suave); font-size: 12.5px; margin-top: 2px; }
.migas { font-size: 12px; color: var(--tinta-tenue); margin-bottom: 3px; }
.migas a { color: var(--tinta-suave); }
.migas a:hover { color: var(--acento); text-decoration: underline; }
.migas-sep { margin: 0 6px; color: var(--borde-fuerte); }
.encabezado-pagina .acciones { margin-left: auto; }

.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    height: var(--alto-control); padding: 0 12px;
    border: 1px solid var(--borde-fuerte); border-radius: var(--radio);
    background: var(--superficie); color: var(--tinta);
    font-size: 13px; font-weight: 600; font-family: inherit; cursor: pointer;
    white-space: nowrap; transition: background .12s, border-color .12s;
}
.btn:hover { background: var(--fondo); }
/* trabajando: el clic ya se ignora en ui.js (clicUnaVez), esto es lo que se ve.
   El spinner va como ::after para no borrar el texto ni el icono del botón. */
[aria-busy="true"] { pointer-events: none; }
.btn[aria-busy="true"] { opacity: .7; }
.btn[aria-busy="true"]::after {
    content: ''; width: 12px; height: 12px; flex: 0 0 auto;
    border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%;
    animation: gira .6s linear infinite;
}
@keyframes gira { to { transform: rotate(360deg); } }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn-primario { background: var(--acento); border-color: var(--acento); color: #fff; }
.btn-primario:hover { background: var(--acento-hover); border-color: var(--acento-hover); }
.btn-ok      { background: var(--ok);      border-color: var(--ok);      color: #fff; }
.btn-ok:hover      { background: #156b3f; border-color: #156b3f; }
.btn-alerta  { background: var(--alerta);  border-color: var(--alerta);  color: #fff; }
.btn-alerta:hover  { background: #9a4708; border-color: #9a4708; }
.btn-peligro { background: var(--peligro); border-color: var(--peligro); color: #fff; }
.btn-peligro:hover { background: #9c1f15; border-color: #9c1f15; }
.btn-fantasma { background: transparent; border-color: var(--borde); color: var(--tinta-suave); }
.btn-fantasma:hover { background: var(--fondo); color: var(--tinta); }
.btn-sm { height: 26px; padding: 0 9px; font-size: 12px; }
/* Control compacto para usar dentro de un renglón de tabla. */
.select-sm { height: 26px; padding: 0 6px; font-size: 12px; width: auto; }
.btn-bloque { width: 100%; }

/* scroll-margin-top: sin él, al hacer scrollIntoView la cabecera de la tarjeta
   quedaba debajo del topbar fijo */
.card {
    background: var(--superficie); border: 1px solid var(--borde); border-radius: var(--radio);
    scroll-margin-top: calc(var(--alto-topbar) + var(--esp-3));
}
.card + .card { margin-top: var(--esp-4); }
.card-cab {
    padding: 10px 14px; border-bottom: 1px solid var(--borde-suave);
    display: flex; align-items: center; justify-content: space-between; gap: var(--esp-2);
}
.card-cab h2 { font-size: 13px; font-weight: 650; }
.card-cuerpo { padding: 14px; }

.tabla { width: 100%; border-collapse: collapse; font-size: 12.5px; font-variant-numeric: tabular-nums; }
.tabla th, .tabla td { text-align: left; padding: 7px 12px; border-bottom: 1px solid var(--borde-suave); }
.tabla th {
    color: var(--tinta-suave); font-weight: 600; font-size: 11px;
    text-transform: uppercase; letter-spacing: .4px; background: #f7f9fa;
    border-bottom: 1px solid var(--borde);
}
.tabla tbody tr { cursor: pointer; }
.tabla tbody tr:hover { background: #f4f7fa; }
.tabla td.num, .tabla th.num { text-align: right; }
.tabla .folio { font-weight: 600; color: var(--acento); }
/* Las tasas de la partida en la OC: letra chica, gris y con tope de ancho para
   que envuelvan en dos renglones. La descripción es lo que hay que poder leer;
   el desglose que vale son los totales del pie. */
.tabla td.col-impuestos { font-size: 11px; color: var(--tinta-tenue); line-height: 1.35; max-width: 11em; }
/* El pie de totales no es un renglón más de la tabla: raya que cierra las
   partidas y negritas, que es lo que se busca con la vista de reojo. */
.tabla tfoot.totales tr:first-child td { border-top: 2px solid var(--borde-fuerte); }
.tabla tfoot.totales td { font-weight: 600; }
.tabla-plana tbody tr { cursor: default; }
.tabla-plana tbody tr:hover { background: transparent; }

.vacio { text-align: center; color: var(--tinta-tenue); padding: 40px 20px; font-size: 13px; }
.vacio .vacio-icono { display: block; color: var(--borde-fuerte); margin-bottom: var(--esp-2); }
.vacio .vacio-icono svg { display: inline-block; }

/* en pantallas angostas los listados se deslizan a lo horizontal en vez de
   encimarse; el min-width es para que las columnas respiren */
.tabla-scroll { overflow-x: auto; border-radius: var(--radio); }
.tabla-scroll .tabla { min-width: 720px; }
.tabla-scroll th, .tabla-scroll td.folio { white-space: nowrap; }

/* Listados paginados: con 50 renglones el encabezado se pierde al bajar. Para
   que el sticky se pegue, la caja necesita scroll vertical propio (con
   overflow-x el eje Y ya computa a auto, pero sin alto tope nunca desborda).
   Solo en escritorio: en el teléfono dos scrolls anidados estorban más de lo
   que ayudan, y ahí la tabla ya se desliza a lo ancho. */
@media (min-width: 900px) {
    .tabla-scroll.tabla-larga { max-height: calc(100vh - 260px); max-height: calc(100dvh - 260px); }
    /* el borde va de sombra interior: con border-collapse los bordes son de la
       tabla y se quedan en su renglón, así que el th pegado dejaba asomar la
       fila de abajo por donde debería ir su línea */
    .tabla-scroll.tabla-larga thead th {
        position: sticky; top: 0; z-index: 1;
        border-bottom-color: transparent; box-shadow: inset 0 -1px 0 var(--borde);
    }
}
/* la fila que se acaba de abrir, al regresar de su detalle */
.tabla tbody tr.fila-vista { background: var(--acento-tenue); box-shadow: inset 3px 0 0 var(--acento); }

/* estatus en chip tenue con punto de color, no en fondo saturado */
.badge {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 2px 9px; border-radius: 999px; border: 1px solid transparent;
    font-size: 11.5px; font-weight: 600; line-height: 1.5;
    white-space: nowrap; color: var(--tinta);
}
.badge::before { content: ''; width: 6px; height: 6px; border-radius: 50%; flex: 0 0 auto; }
.badge.gris   { background: #eef1f4;             border-color: var(--borde); }
.badge.gris::before   { background: var(--tinta-tenue); }
.badge.info   { background: var(--info-tenue);    border-color: var(--info-borde); }
.badge.info::before   { background: var(--info); }
.badge.alerta { background: var(--alerta-tenue);  border-color: var(--alerta-borde); }
.badge.alerta::before { background: var(--alerta); }
.badge.ok     { background: var(--ok-tenue);      border-color: var(--ok-borde); }
.badge.ok::before     { background: var(--ok); }
.badge.error  { background: var(--peligro-tenue); border-color: var(--peligro-borde); }
.badge.error::before  { background: var(--peligro); }
.punto-urgente { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--peligro); margin-left: var(--esp-2); vertical-align: middle; }

.pastilla {
    display: inline-block; min-width: 18px; height: 18px; line-height: 18px; padding: 0 5px;
    border-radius: 999px; background: var(--peligro); color: #fff; font-size: 11px; font-weight: 700;
    text-align: center; vertical-align: middle;
}
.modulo-pastilla {
    position: absolute; top: -6px; right: -6px; min-width: 20px; height: 20px; line-height: 20px;
    padding: 0 6px; border-radius: 999px; background: var(--peligro); color: #fff; font-size: 11.5px;
    font-weight: 700; text-align: center; box-shadow: 0 0 0 2px var(--superficie);
}

.campo { margin-bottom: var(--esp-4); }
.campo label { display: block; font-size: 12px; font-weight: 600; color: var(--tinta-suave); margin-bottom: var(--esp-1); }
/* partidas y buscadores de admin no van dentro de .campo, de ahí la lista larga */
.campo input, .campo select, .campo textarea,
.partida-linea input, .partida-linea select, input.buscador {
    width: 100%; height: var(--alto-control); padding: 0 10px;
    border: 1px solid var(--borde-fuerte); border-radius: var(--radio-chico);
    font-size: 13px; font-family: inherit; background: var(--superficie); color: var(--tinta);
}
.campo textarea { height: auto; min-height: 64px; padding: 6px 10px; resize: vertical; }
.campo input:focus, .campo select:focus, .campo textarea:focus,
.partida-linea input:focus, .partida-linea select:focus, input.buscador:focus {
    outline: none; border-color: var(--acento); box-shadow: 0 0 0 2px rgba(95, 176, 230, .25);
}
/* La regla de arriba es para cajas de texto; una casilla dentro de .campo se la
   comía y salía de 32px de alto y del ancho de la celda. Pasó en el modal de
   entregas: una palomita del tamaño de un botón, cualquier cosa menos un ERP. */
.campo input[type="checkbox"], .campo input[type="radio"] {
    width: auto; height: auto; padding: 0; accent-color: var(--acento);
}
.error-campo { color: var(--peligro); font-size: 12px; margin-top: var(--esp-1); }
.campo input.invalido, .campo select.invalido { border-color: var(--peligro); }
.fila { display: grid; grid-template-columns: 1fr 1fr; gap: var(--esp-3); }
.fila-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: var(--esp-3); }
.fila-5 { display: grid; grid-template-columns: repeat(5, 1fr); gap: var(--esp-3); }
/* la de 5 baja a 3 antes que las otras: a 900 px cada columna se queda en ~160 px
   y "TPZ · Tepetzingo" ya no cabe. Va ANTES del corte de 640 o gana esta */
@media (max-width: 900px) { .fila-5 { grid-template-columns: 1fr 1fr 1fr; } }
@media (max-width: 640px) { .fila, .fila-3, .fila-5 { grid-template-columns: 1fr; } }
.solo-lectura, .campo input.solo-lectura { background: var(--fondo); color: var(--tinta-suave); cursor: not-allowed; }

/* alta rápida de proveedor dentro del modal */
.caja-punteada { border: 1px dashed var(--borde-fuerte); border-radius: var(--radio); padding: var(--esp-3) var(--esp-3) var(--esp-1); }
/* align-items:start y no center: en columna de 240px la descripción se va a dos o
   tres líneas, y con center la casilla se hunde a la mitad y los renglones dejan de
   alinearse entre sí. La casilla siempre arriba, a la altura de la primera línea. */
.partida-chk { display: flex; gap: var(--esp-2); align-items: start; margin: 0 0 var(--esp-2); font-size: 13px; font-weight: 400; line-height: 1.35; }
.partida-chk input { width: auto; height: auto; margin: 2px 0 0; }
/* Barra de la caja de partidas: marcar todas/ninguna y la cuenta a la vista. Con una
   SC de 20 renglones, cotizar 3 significaba desmarcar 17 a mano y sin saber cuántas
   llevabas. El label va aquí dentro, de ahí el margin:0 que le quita el de .campo. */
.partidas-cab { display: flex; align-items: center; gap: var(--esp-2); flex-wrap: wrap; margin-bottom: var(--esp-2); }
.partidas-cab > label { margin: 0; flex: 1 1 auto; }
.partidas-acciones { display: flex; align-items: center; gap: var(--esp-2); flex-shrink: 0; }
/* auto-fill y no un número fijo de columnas: 3 en escritorio, 2 en tablet y 1 en el
   teléfono, sin una sola media query. El tope de alto es para la SC excepcional de 40
   partidas — la caja scrollea por dentro y lo que va debajo sigue alcanzable. */
.rejilla-partidas {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 0 var(--esp-3); max-height: 40vh; overflow-y: auto;
}

/* Lista de recibo del modal de entregas (¿qué llegó de la OC?). Una orden puede
   traer 25 renglones y el modal no crece con ellos: encabezado pegado, alto tope
   y scroll propio, igual que la rejilla de arriba. Aquí NO va .tabla-scroll: su
   min-width de 720px sacaba una barra horizontal dentro del modal. Con
   table-layout fijo la única columna elástica es la descripción, que se corta
   con puntos y queda entera en el title. */
.lista-recibo { border: 1px solid var(--borde); border-radius: var(--radio); overflow-y: auto; max-height: 40vh; }
.lista-recibo .tabla { min-width: 0; table-layout: fixed; }
.lista-recibo th, .lista-recibo td { padding: 4px 10px; }
/* mismo truco que .tabla-larga: con border-collapse la raya del th pegado se va
   con la tabla, así que la línea se pinta de sombra interior */
.lista-recibo thead th {
    position: sticky; top: 0; z-index: 1;
    border-bottom-color: transparent; box-shadow: inset 0 -1px 0 var(--borde);
}
.lista-recibo tbody tr:last-child td { border-bottom: 0; }
/* el tbody de más es para ganarle al :hover transparente de .tabla-plana: sin él,
   pasar el ratón por un renglón marcado le apagaba el resaltado */
.lista-recibo tbody tr.marcada { background: var(--acento-tenue); }
.lista-recibo .col-chk { width: 32px; }
.lista-recibo .col-part { width: 36px; color: var(--tinta-tenue); }
.lista-recibo .col-falta { width: 7.5rem; white-space: nowrap; }
.lista-recibo .col-recibido { width: 7.5rem; }
.lista-recibo td.desc { overflow: hidden; }
/* label y no texto suelto: el clic en la descripción tilda el renglón */
.lista-recibo td.desc label {
    /* el reset es contra .campo label, que lo pondría gris, en negritas y con margen */
    display: block; cursor: pointer; margin: 0;
    font-size: inherit; font-weight: 400; color: inherit; text-transform: none;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lista-recibo input.num { height: 26px; padding: 0 6px; text-align: right; }
@media (max-width: 640px) {
    .lista-recibo .col-falta, .lista-recibo .col-recibido { width: 5.5rem; }
    .lista-recibo th, .lista-recibo td { padding: 4px 6px; }
}

/* autocomplete de artículos y proveedores.
   FIJA, no absoluta: .partidas-scroll (overflow-x) y .modal-cuerpo (overflow-y)
   la recortaban y las sugerencias quedaban escondidas bajo el borde de la caja.
   Las coordenadas las pone montarSugerencias() en util/sugerencias.js; si aquí
   cambia el max-height, allá cambia ALTO_MAX. El 95 la deja sobre el modal (90)
   y bajo los avisos (100). */
.autocomplete { position: relative; }
.autocomplete-lista {
    position: fixed; z-index: 95;
    background: var(--superficie); border: 1px solid var(--borde); border-radius: var(--radio);
    box-shadow: 0 4px 12px rgba(16, 32, 55, .14);
    max-height: 240px; overflow-y: auto;
}
.autocomplete-lista div { padding: 7px 10px; cursor: pointer; font-size: 13px; display: flex; justify-content: space-between; gap: 10px; }
.autocomplete-lista div:hover, .autocomplete-lista div.sel { background: var(--acento-tenue); }
.autocomplete-lista .veces { color: var(--tinta-tenue); font-size: 11.5px; }

.partidas-scroll { overflow-x: auto; }
.partidas-encabezado, .partida-linea {
    display: grid;
    /* item, cantidad, unidad, descripción, # parte, equipo, quitar */
    grid-template-columns: 34px 90px 110px minmax(240px, 2.6fr) minmax(120px, 1fr) minmax(120px, 1fr) 34px;
    gap: var(--esp-2); align-items: center; min-width: 820px;
}
.partidas-encabezado { padding: 0 2px 6px; }
.partidas-encabezado span { font-size: 10.5px; text-transform: uppercase; letter-spacing: .4px; color: var(--tinta-suave); font-weight: 600; }
.partida-linea { margin-bottom: var(--esp-2); align-items: start; }
.partida-linea .num-item { font-weight: 700; color: var(--tinta-tenue); padding-top: 8px; text-align: center; font-size: 12px; }
.partida-linea input, .partida-linea select { width: 100%; margin: 0; }
.partida-linea .btn-quitar { margin-top: 3px; }
.btn-quitar { color: var(--tinta-tenue); }
.btn-quitar:hover { color: var(--peligro); border-color: var(--peligro-borde); background: var(--peligro-tenue); }

.fotos-cab { display: flex; align-items: center; gap: 10px; }
.galeria-fotos { display: flex; flex-wrap: wrap; gap: 10px; }
.miniatura { position: relative; width: 84px; height: 84px; flex: 0 0 auto; cursor: zoom-in; }
.miniatura img { width: 84px; height: 84px; object-fit: cover; border-radius: var(--radio-chico); border: 1px solid var(--borde); background: var(--fondo); display: block; }
.miniatura .quitar-foto {
    position: absolute; top: -7px; right: -7px; width: 20px; height: 20px; padding: 0;
    border: 0; border-radius: 50%; background: var(--peligro); color: #fff; font-size: 12px;
    line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
}
/* documentación de la SC: lista, no galería. Del PDF lo que importa es el NOMBRE
   (Ficha_tecnica_bomba.pdf), no una miniatura de la primera hoja */
.lista-docs { display: flex; flex-direction: column; gap: 6px; }
.doc-fila {
    display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
    padding: 8px 10px; border: 1px solid var(--borde); border-radius: var(--radio-chico);
    background: var(--superficie); color: inherit; font-family: inherit; font-size: 13px;
}
/* directo, no descendiente: el icono de la ✕ vive dentro de su botón y ese ya
   se pinta solo (btn-quitar se pone rojo al pasar encima) */
.doc-fila > .icono { color: var(--tinta-tenue); flex: 0 0 auto; }
.doc-nombre { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.doc-peso { flex: 0 0 auto; font-size: 12px; }
.doc-abrible { cursor: pointer; }
.doc-abrible:hover { border-color: var(--borde-fuerte); background: var(--fondo); }

.lightbox { display: flex; align-items: center; justify-content: center; padding: 20px; cursor: zoom-out; }
.lightbox .foto-grande { max-width: 92vw; max-height: 92vh; border-radius: var(--radio); }

.urgente { display: inline-flex; border: 1px solid var(--borde-fuerte); border-radius: var(--radio-chico); overflow: hidden; }
.urgente button {
    border: 0; background: var(--superficie); height: 30px; padding: 0 18px; cursor: pointer;
    font-size: 13px; font-weight: 600; font-family: inherit; color: var(--tinta-suave);
}
.urgente button.si.on { background: var(--peligro); color: #fff; }
.urgente button.no.on { background: var(--tinta-suave); color: #fff; }

/* firmas del formato */
.firmas { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: var(--esp-3); }
@media (max-width: 640px) { .firmas { grid-template-columns: 1fr; } }
.firma { border: 1px dashed var(--borde-fuerte); border-radius: var(--radio); padding: var(--esp-3); text-align: center; }
.firma .nombre { font-weight: 600; font-size: 13px; }
.firma .fecha  { font-size: 11.5px; color: var(--tinta-suave); margin-top: 2px; }
.firma .accion { font-size: 10.5px; text-transform: uppercase; letter-spacing: .4px; color: var(--tinta-suave); font-weight: 700; margin-top: var(--esp-2); }
.firma .puesto { font-size: 10.5px; color: var(--tinta-tenue); margin-top: 1px; }
.firma.pendiente .nombre { color: var(--tinta-tenue); font-style: italic; font-weight: 400; }
/* firmó un suplente: bajo el nombre, a quién cubría (43_bitacora_suplencia.sql) */
.suplencia { font-size: 11px; color: var(--tinta-tenue); font-style: italic; margin-top: 1px; }

/* pasos del procedimiento (PASOS_REQ): verde cumplido, acento en curso, gris pendiente */
.pasos { display: flex; flex-wrap: wrap; gap: 6px 10px; margin: 6px 0 4px; }
.paso { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--tinta-tenue); }
.paso .punto { width: 8px; height: 8px; border-radius: 50%; background: var(--borde-fuerte); flex: 0 0 auto; }
.paso.hecho .punto { background: var(--ok); }
.paso.hecho { color: var(--ok); }
.paso.actual .punto { background: var(--acento); box-shadow: 0 0 0 3px var(--acento-tenue); }
.paso.actual { color: var(--acento); font-weight: 600; }

.login-wrap { min-height: 100vh; display: grid; place-items: center; background: var(--fondo); padding: 20px; }
.login-card {
    background: var(--superficie); border: 1px solid var(--borde); border-top: 3px solid var(--acento);
    border-radius: var(--radio); width: 100%; max-width: 360px; padding: 30px 28px;
}
.login-card .marca { display: block; width: 64px; height: 64px; margin: 0 auto 10px; }
.login-card .lema { text-align: center; color: var(--tinta-suave); font-size: 12.5px; margin-bottom: 24px; }

.filtros { display: flex; gap: var(--esp-2); flex-wrap: wrap; margin-bottom: var(--esp-4); }
/* en móvil las bandejas van en tira deslizable, no en cuatro renglones */
@media (max-width: 640px) {
    .filtros { flex-wrap: nowrap; overflow-x: auto; padding-bottom: var(--esp-1); scrollbar-width: none; }
    .filtros .chip { flex: 0 0 auto; white-space: nowrap; }
}
.chip {
    display: inline-flex; align-items: center; border: 1px solid var(--borde);
    background: var(--superficie); color: var(--tinta-suave);
    padding: 4px 12px; border-radius: 999px; font-size: 12.5px; font-weight: 500;
    font-family: inherit;
}
button.chip { cursor: pointer; transition: background .12s, border-color .12s; }
button.chip:hover { border-color: var(--borde-fuerte); color: var(--tinta); }
.chip.activo { background: var(--acento); color: #fff; border-color: var(--acento); }
/* cuántas hay en cada bandeja; sin el número el chip no dice si vale la pena entrar */
.chip .chip-n { margin-left: 6px; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--tinta-tenue); }
.chip.activo .chip-n { color: rgba(255, 255, 255, .8); }
/* resumen del import CSV */
.chip.ok    { background: var(--ok-tenue);      color: var(--ok);          border-color: var(--ok-borde);      font-weight: 600; }
.chip.gris  { background: #eef1f4;              color: var(--tinta-suave); border-color: var(--borde);         font-weight: 600; }
.chip.error { background: var(--peligro-tenue); color: var(--peligro);     border-color: var(--peligro-borde); font-weight: 600; }
.import-barra { display: inline-flex; gap: var(--esp-2); margin-left: auto; }
.resumen-import { display: flex; gap: 10px; flex-wrap: wrap; }

.toasts { position: fixed; bottom: 20px; right: 20px; z-index: 100; display: flex; flex-direction: column; gap: 10px; }
.toast {
    background: var(--tinta); color: #fff; padding: 10px 14px; border-radius: var(--radio);
    font-size: 13px; max-width: 360px; border-left: 3px solid var(--tinta-tenue);
    box-shadow: 0 4px 12px rgba(16, 32, 55, .18); animation: entra .15s ease;
}
.toast.ok { border-left-color: #3fbf7f; } .toast.error { border-left-color: #f08a80; } .toast.alerta { border-left-color: #f2b25c; }
@keyframes entra { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

.modal-fondo { position: fixed; inset: 0; background: rgba(16, 32, 55, .5); display: grid; place-items: center; z-index: 90; padding: 20px; }
/* cabecera y pie fijos, scroll en el cuerpo: la cotización de una SC con
   muchas partidas se salía de la pantalla */
.modal {
    background: var(--superficie); border: 1px solid var(--borde); border-radius: var(--radio);
    box-shadow: 0 6px 20px rgba(16, 32, 55, .2);
    width: 100%; max-width: 480px; overflow: hidden;
    display: flex; flex-direction: column;
    max-height: calc(100vh - 40px);   /* 40px = padding del fondo */
    max-height: calc(100dvh - 40px);  /* dvh: descuenta la barra del navegador móvil */
}
.modal-cab { padding: 12px 16px; border-bottom: 1px solid var(--borde-suave); font-weight: 650; font-size: 14px; flex-shrink: 0; }
.modal-cuerpo { padding: 16px; overflow-y: auto; }
.modal-pie { padding: 12px 16px; border-top: 1px solid var(--borde-suave); display: flex; justify-content: flex-end; gap: var(--esp-2); background: var(--fondo); flex-shrink: 0; }

/* Formulario ancho. NO es .modal-ancho: aquel se lleva la pantalla completa y deja
   el scroll a los paneles de adentro; este es el modal de siempre —cabecera fija,
   cuerpo con scroll, pie fijo— nada más que le cabe más. Nace de la captura de
   cotización: con 20 partidas en una columna, la caja se volvía un scroll eterno.
   En el teléfono no cambia nada: .modal ya es width:100% y el max-width no aplica. */
.modal.modal-medio { max-width: 860px; }

/* --- Modal ancho: pantallas que se decide dentro, no un formulario ---------
   Nace de la adjudicación de cotizaciones: el gerente compara hasta 5 PDF y
   reparte 20 partidas, y eso no cabe en una tarjeta de la vista de detalle. */
.modal-fondo.fondo-ancho { padding: 12px; }
.modal.modal-ancho { max-width: 1180px; height: calc(100vh - 24px); height: calc(100dvh - 24px); }
.modal-ancho .modal-cuerpo { display: flex; flex-direction: column; gap: var(--esp-3); overflow: hidden; flex: 1; min-height: 0; }
/* Un FORMULARIO dentro del modal ancho (la verificación de "Generar orden de
   compra"): como el cuerpo entrega el scroll a los paneles de adentro, el
   formulario tiene que traer el suyo o se corta por abajo en cuanto hay dos
   proveedores. */
.modal-ancho .form-ancho { overflow-y: auto; flex: 1; min-height: 0; }

/* tira de cotizaciones: se envuelve sola, así 5 proveedores no se encaraman */
.adj-cotizaciones { display: flex; flex-wrap: wrap; gap: var(--esp-2); flex-shrink: 0; }
/* la tarjeta completa abre esa cotización en el visor (ver requisicion-detalle.js) */
.adj-cot {
    flex: 1 1 190px; min-width: 0;
    background: var(--superficie); border: 1px solid var(--borde); border-radius: var(--radio);
    padding: var(--esp-2) var(--esp-3);
    cursor: pointer; transition: border-color .15s, background .15s;
}
.adj-cot:hover { border-color: var(--acento); }
/* la que se está leyendo en el visor */
.adj-cot.activa { border-color: var(--acento); background: var(--acento-tenue); }
.adj-cot .adj-prov { font-weight: 650; font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.adj-cot .adj-meta { font-size: 11.5px; color: var(--tinta-tenue); }
.adj-cot .adj-acciones { display: flex; gap: var(--esp-1); margin-top: var(--esp-1); }

.adj-paneles { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--esp-3); flex: 1; min-height: 0; }
.adj-partidas { overflow-y: auto; border: 1px solid var(--borde); border-radius: var(--radio); }
/* el th ya trae fondo opaco; el borde va de sombra interior o con border-collapse
   se queda en su renglón y asoma la fila de abajo (misma trampa que los listados) */
.adj-partidas thead th { position: sticky; top: 0; z-index: 1; box-shadow: inset 0 -1px 0 var(--borde); border-bottom-color: transparent; }
.adj-partidas select { width: 100%; min-width: 120px; }
/* cantidad y unidad son dos datos, no uno: cada quien en su columna y sin
   envolver, que "Metro cuadrado" partido en dos renglones descuadra la fila */
.adj-partidas td.num, .adj-partidas th.num { white-space: nowrap; width: 1%; }
.adj-partidas td:nth-child(4), .adj-partidas th:nth-child(4) { white-space: nowrap; width: 1%; color: var(--tinta-tenue); }
/* la partida que cotiza el proveedor que se está viendo */
.adj-partidas tr.adj-cubre td:first-child { box-shadow: inset 3px 0 0 var(--acento); }

.adj-visor { display: flex; flex-direction: column; border: 1px solid var(--borde); border-radius: var(--radio); overflow: hidden; min-height: 0; }
.adj-visor-cab { padding: 6px 10px; border-bottom: 1px solid var(--borde-suave); font-size: 12px; color: var(--tinta-tenue); flex-shrink: 0; }
.adj-visor embed { flex: 1; width: 100%; border: 0; background: var(--fondo); }
.adj-visor .vacio { margin: auto; }
.adj-resumen { flex-shrink: 0; font-size: 12.5px; }

/* En el teléfono el visor no va: Chrome de Android no dibuja un PDF incrustado
   y Safari solo pinta la primera hoja. Ahí "Ver PDF" abre la pestaña, que es lo
   que ya hacía. Sin visor, las partidas se llevan el alto completo. */
@media (max-width: 900px) {
    .adj-paneles { grid-template-columns: 1fr; }
    .adj-visor { display: none; }
    /* apiladas, 5 cotizaciones se comen la pantalla y no queda alto para las
       partidas: en angosto la tira se desliza a lo horizontal */
    .adj-cotizaciones { flex-wrap: nowrap; overflow-x: auto; }
    .adj-cot { flex: 0 0 200px; }
}
@media (max-width: 700px) {
    /* nada de dos scrolls anidados en el teléfono: la caja crece a lo que necesite y
       quien scrollea es el cuerpo del modal, como en cualquier otro formulario */
    .rejilla-partidas { max-height: none; overflow-y: visible; }
    .modal-fondo.fondo-ancho { padding: 0; }
    .modal.modal-ancho { height: 100vh; height: 100dvh; max-height: none; border: 0; border-radius: 0; }
}

/* El lanzador es la portada del ERP y era la única pantalla sin marca: un <h1>
   'Inicio' y nada más. Aquí sí cabe el mosaico completo, a 52px se lee entero. */
.inicio-marca { display: flex; align-items: center; gap: 14px; margin-bottom: var(--esp-4); }
.inicio-marca img { width: 52px; height: 52px; display: block; flex-shrink: 0; }
.inicio-marca h1 { font-size: 20px; font-weight: 700; color: var(--acento); line-height: 1.15; letter-spacing: .2px; }
.inicio-marca h1 span { color: var(--acento-claro); }
.inicio-marca .sub { color: var(--tinta-suave); font-size: 12.5px; margin-top: 2px; }

.modulos { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: var(--esp-3); }
.modulo {
    display: flex; align-items: center; gap: var(--esp-3);
    background: var(--superficie); border: 1px solid var(--borde); border-radius: var(--radio);
    padding: var(--esp-4); transition: border-color .15s, background .15s;
}
.modulo.entrable { cursor: pointer; }
.modulo.entrable:hover { border-color: var(--acento); background: #fbfcfe; }
.modulo:not(.entrable) { opacity: .65; }
.modulo-icono {
    position: relative; width: 48px; height: 48px; color: var(--acento);
    display: grid; place-items: center; background: var(--fondo);
    border: 1px solid var(--borde-suave); border-radius: var(--radio); flex-shrink: 0;
}
.modulo:not(.entrable) .modulo-icono { color: var(--tinta-tenue); }
.modulo-cuerpo { flex: 1; min-width: 0; }
.modulo-nombre { font-weight: 650; font-size: 13.5px; }
.modulo-desc { color: var(--tinta-suave); font-size: 12px; }
.modulo-nota { color: var(--tinta-tenue); font-size: 11px; margin-top: 2px; }
/* renglón propio debajo del texto: al lado del nombre, un rol largo se encimaba
   con la descripción (la pastilla no encoge y la tarjeta mide 280px) */
.modulo-estado { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 999px; border: 1px solid transparent; margin-top: 6px; max-width: 100%; }
.modulo-estado.ok  { background: var(--ok-tenue);      color: var(--ok);          border-color: var(--ok-borde); }
.modulo-estado.dev { background: #eef1f4;              color: var(--tinta-suave); border-color: var(--borde); }
.modulo-estado.sin { background: var(--peligro-tenue); color: var(--peligro);     border-color: var(--peligro-borde); }
.modulo-estado.ext { background: var(--info-tenue);    color: var(--info);        border-color: var(--info-borde); }
a.modulo { color: inherit; }   /* módulos externos: la tarjeta es un <a> */

/* utilidades */
.grid-2 { display: grid; grid-template-columns: 2fr 1fr; gap: var(--esp-4); align-items: start; }
@media (max-width: 860px) { .grid-2 { grid-template-columns: 1fr; } }
.dato { margin-bottom: var(--esp-3); }
.dato .k { font-size: 11px; color: var(--tinta-suave); text-transform: uppercase; letter-spacing: .4px; }
.dato .v { font-size: 13.5px; font-weight: 500; }
.acciones { display: flex; gap: var(--esp-2); flex-wrap: wrap; }
.mt { margin-top: var(--esp-4); } .mb { margin-bottom: var(--esp-4); } .text-der { text-align: right; }
.total-grande { font-size: 20px; font-weight: 700; color: var(--acento); font-variant-numeric: tabular-nums; }
.muted { color: var(--tinta-suave); font-size: 12.5px; }
/* qué va en un campo, en un renglón. También se usa suelta dentro de una tarjeta,
   así que el tamaño va en la clase y el margen solo cuando cuelga de un .campo */
.ayuda { font-size: 11.5px; line-height: 1.4; color: var(--tinta-suave); }
.campo .ayuda { margin-top: 4px; }

/* mi suplencia: quién firma mientras el gerente no está */
.suplencia-fila { display: flex; align-items: center; justify-content: space-between; gap: var(--esp-3); flex-wrap: wrap; }
.suplencia-fila + .suplencia-fila { margin-top: var(--esp-3); padding-top: var(--esp-3); border-top: 1px solid var(--borde-suave); }
.suplencia-nombre { font-weight: 650; }
.suplencia-acciones { display: flex; align-items: center; gap: var(--esp-2); }

/* admin */
.migaja { display: inline-block; margin-bottom: var(--esp-1); font-size: 12px; color: var(--tinta-suave); }
.migaja:hover { color: var(--acento); text-decoration: underline; }
.barra-filtros { display: flex; gap: 10px; margin-bottom: var(--esp-4); flex-wrap: wrap; align-items: center; }
/* ancho fijo, no "lo que sobre": estirado de lado a lado se lee como un campo
   de captura, no como una caja de búsqueda, y el texto tecleado queda perdido
   en medio del renglón. Encoge en móvil, nunca crece */
.barra-filtros .buscador { flex: 0 1 320px; min-width: 180px; }
.separador {
    margin: var(--esp-3) 0 var(--esp-1); padding-top: var(--esp-3); border-top: 1px solid var(--borde);
    font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .4px; color: var(--tinta-suave);
}

/* filtros de listados (SC/OC): un renglón en escritorio, dos columnas en móvil */
/* Se acomoda solo según quepa: los campos cambian de una lista a otra (unidad
   solo con más de una planta) y una rejilla fija dejaba huecos. */
.panel-filtros { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--esp-3);
    align-items: end; padding: var(--esp-3) 14px; margin-bottom: var(--esp-4); }
.panel-filtros .campo { margin-bottom: 0; min-width: 0; }
.panel-filtros .campo-buscar { grid-column: span 2; }
.panel-filtros .filtros-pie { grid-column: 1 / -1; text-align: right; }
@media (max-width: 860px) {
    .panel-filtros { grid-template-columns: 1fr 1fr; }
    .panel-filtros .campo-buscar { grid-column: 1 / -1; }
}

/* Rango a la izquierda, controles al centro y tamaño de página a la derecha.
   "Página 2 de 50" a secas no dice cuántos renglones son ni deja llegar al
   final: por eso el rango, el salto directo y los extremos. */
.paginador { display: flex; gap: var(--esp-3); align-items: center; justify-content: center; flex-wrap: wrap; margin-top: var(--esp-4); }
/* los márgenes automáticos de .rango y .tamano son los que reparten; el centrado
   es el respaldo para cuando alguno de los dos no se pinta */
.paginador .rango  { margin-right: auto; color: var(--tinta-suave); font-size: 12.5px; font-variant-numeric: tabular-nums; }
.paginador .controles { display: flex; gap: var(--esp-1); align-items: center; }
.paginador .tamano { margin-left: auto; display: flex; gap: var(--esp-2); align-items: center; color: var(--tinta-suave); font-size: 12.5px; }
.paginador .salto {
    width: 56px; height: 28px; text-align: center; padding: 0 4px;
    border: 1px solid var(--borde-fuerte); border-radius: var(--radio-chico);
    font-family: inherit; font-size: 12.5px; background: var(--superficie); color: var(--tinta);
}
/* en el teléfono los extremos estorban y el salto basta */
@media (max-width: 640px) {
    .paginador .btn-extremo { display: none; }
    .paginador .rango, .paginador .tamano { margin: 0; }
}

/* firma electrónica: touch-action none o el dedo arrastra la página en vez de
   trazar la rúbrica */
.firma-marco {
    border: 1px dashed var(--borde-fuerte); border-radius: var(--radio-chico);
    background: #fff; padding: var(--esp-2); margin: var(--esp-3) 0;
}
.firma-marco-chico { max-width: 320px; }
.firma-lienzo { display: block; width: 100%; height: auto; aspect-ratio: 10 / 3; touch-action: none; cursor: crosshair; }
.firma-vista  { display: block; width: 100%; height: auto; max-height: 180px; object-fit: contain; }
.firma-botones { display: flex; gap: var(--esp-2); flex-wrap: wrap; }
.firma-vias { display: flex; gap: var(--esp-2); flex-wrap: wrap; margin-bottom: var(--esp-3); }
.firma-ayuda { color: var(--tinta-suave); font-size: 12.5px; line-height: 1.55; margin: var(--esp-2) 0; }
.firma-nota  { color: var(--tinta-tenue); font-size: 11.5px; margin-top: var(--esp-3); }

.firma-card { padding: 14px; }
.firma-card h2 { font-size: 13px; font-weight: 650; margin-bottom: var(--esp-2); }
.firma-card-cab { display: flex; gap: var(--esp-3); align-items: center; flex-wrap: wrap; }
.firma-fecha { font-size: 12px; color: var(--tinta-suave); }

.firma-enlace { border-top: 1px solid var(--borde-suave); margin-top: var(--esp-3); padding-top: var(--esp-3); }
.firma-url { display: flex; gap: var(--esp-2); align-items: center; flex-wrap: wrap; }
.firma-url code {
    flex: 1; min-width: 220px; overflow-x: auto; white-space: nowrap;
    background: var(--fondo); border: 1px solid var(--borde); border-radius: var(--radio-chico);
    padding: 7px 9px; font-size: 12px;
}
.firma-codigo-grande {
    display: inline-block; font-size: 24px; font-weight: 700; letter-spacing: 4px;
    color: var(--acento); background: var(--acento-tenue); border: 1px solid var(--borde);
    border-radius: var(--radio); padding: 8px 14px; font-variant-numeric: tabular-nums;
}

/* pantalla pública de firma: se abre en el teléfono, sin shell ni sesión */
.firma-pantalla {
    min-height: 100vh; max-width: 560px; margin: 0 auto;
    display: flex; flex-direction: column; justify-content: center;
    padding: 24px 20px; background: var(--fondo);
}
.firma-pantalla h1 { font-size: 20px; font-weight: 650; margin-bottom: var(--esp-1); }
.firma-marca { font-size: 22px; font-weight: 700; color: var(--acento); margin-bottom: var(--esp-4); }
.firma-marca span { color: var(--acento-claro); }
.firma-pantalla .firma-marco { background: var(--superficie); }
.firma-enviar { width: 100%; justify-content: center; margin-top: var(--esp-3); }
.firma-form { display: flex; gap: var(--esp-2); margin-top: var(--esp-3); }
.firma-codigo {
    flex: 1; height: 44px; font-size: 20px; letter-spacing: 3px; text-align: center;
    text-transform: uppercase; font-variant-numeric: tabular-nums;
}
.firma-exito, .firma-error { margin-bottom: var(--esp-3); }
.firma-exito .icono { color: var(--ok); }
.firma-error .icono { color: var(--peligro); }

/* captura a pantalla completa. el iPhone no tiene API de fullscreen: ahí, con
   el teléfono vertical, giro la caja 90° y firma-canvas.js deshace el giro al
   mapear el puntero. z 95 para quedar bajo los toasts */
.firma-fs {
    position: fixed; inset: 0; z-index: 95;
    background: var(--fondo); touch-action: none; overscroll-behavior: contain;
}
.firma-fs-caja {
    position: absolute; inset: 0;
    display: flex; flex-direction: column; gap: var(--esp-2); padding: 10px;
}
.firma-fs-caja.girada {
    inset: auto; top: 0; left: 0;
    width: 100vh; height: 100vw;      /* respaldo para navegadores sin dvh */
    width: 100dvh; height: 100dvw;
    transform: rotate(90deg) translateY(-100%);
    transform-origin: top left;
}
.firma-fs-marco {
    flex: 1; min-height: 0; overflow: hidden;
    border: 1px dashed var(--borde-fuerte); border-radius: var(--radio-chico);
    background: #fff;
}
.firma-fs-lienzo { width: 100%; height: 100%; aspect-ratio: auto; }
.firma-fs-barra { display: flex; gap: var(--esp-2); align-items: center; }
.firma-fs-barra .btn { height: 40px; }
.firma-fs-aviso { flex: 1; min-width: 0; text-align: center; font-size: 12.5px; color: var(--peligro); }
