/* =========================================================================
   app.css — Sistema de diseño del panel
   Sistema Integral de Gestión Comercial · Jabc SoftWorks

   FORMATO: Expandido absoluto (una declaración por línea)

   POV DE DISEÑO — "el dato es la interfaz"
   Esto es software de operación: alguien lo usa ocho horas al día, de pie,
   con prisa y a veces con un cliente enfrente. Así que el cromo se retira y
   el dato manda. Tres decisiones sostienen todo lo demás:

   1. LIENZO CÁLIDO, NO GRIS AZULADO. Un panel administrativo pasa el día
      entero enfrente de los ojos; el gris cálido cansa menos que el
      slate/zinc azulado de todas las plantillas y hace que el blanco de las
      tarjetas se lea como papel y no como un hueco.

   2. NUMERALES TABULARES EN TODA CIFRA. Precios, existencias y folios usan
      font-variant-numeric: tabular-nums. Los dígitos ocupan lo mismo, así
      que las columnas de dinero se alinean solas y el ojo compara de un
      vistazo. Es EL detalle que separa un inventario serio de una tabla.

   3. EL ACENTO SOLO SIGNIFICA ACCIÓN O ESTADO. Nunca decora. Si algo está
      en color, es porque se puede pulsar o porque está avisando de algo.
      El color de acento lo define la empresa en la configuración y entra
      como variable CSS desde PHP.

   MOTION: curvas propias, salidas más rápidas que entradas, nada que se
   dispare con el teclado se anima, y todo respeta prefers-reduced-motion.
   ========================================================================= */

/* =========================================================================
   0. TIPOGRAFÍA PROPIA (autoalojada, variable)
   Se abandona Inter (la fuente "por defecto" que delata plantillas): Geist
   para el cuerpo —limpia y premium— y Outfit para los titulares grandes de la
   web, que le dan carácter sin gritar. Variables (un solo archivo por familia,
   todos los pesos) y con font-display:swap para no bloquear el pintado.
   ========================================================================= */
@font-face {
    font-family: "Outfit";
    src: url("../fonts/outfit-var.woff2") format("woff2");
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Geist";
    src: url("../fonts/geist-var.woff2") format("woff2");
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

/* =========================================================================
   1. TOKENS
   ========================================================================= */
:root {
    /* --- Color de marca (lo sobreescribe PHP con los datos de la empresa) */
    --marca-tinta: #0F172A;
    --marca-acento: #2563EB;

    /* Tinta que va ENCIMA de cada color de marca. PHP la recalcula por
       luminancia con el color real de la empresa; estos son el respaldo
       para los dos colores por omisión, que son oscuros. */
    --marca-tinta-encima: #FFFFFF;
    --marca-acento-encima: #FFFFFF;

    /* --- Neutros cálidos ------------------------------------------------ */
    --lienzo: #FBFAF9;
    --superficie: #FFFFFF;
    --superficie-hundida: #F5F4F2;
    --superficie-alterna: #FAF9F7;

    --borde: #E7E5E4;
    --borde-fuerte: #D6D3D1;

    --tinta: #1C1917;
    --tinta-suave: #57534E;
    --tinta-tenue: #8A8580;

    /* --- Estados -------------------------------------------------------- */
    --exito: #15803D;
    --exito-fondo: #F0FDF4;
    --exito-borde: #BBF7D0;

    --aviso: #B45309;
    --aviso-fondo: #FFFBEB;
    --aviso-borde: #FDE68A;

    --peligro: #B91C1C;
    --peligro-fondo: #FEF2F2;
    --peligro-borde: #FECACA;

    --info: #1D4ED8;
    --info-fondo: #EFF6FF;
    --info-borde: #BFDBFE;

    /* --- Tipografía ----------------------------------------------------- */
    --fuente: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --fuente-display: "Outfit", "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    --fuente-mono: "SFMono-Regular", ui-monospace, "Cascadia Mono", Consolas, "Liberation Mono", monospace;

    /* --- Radios --------------------------------------------------------- */
    --radio-xs: 4px;
    --radio-sm: 6px;
    --radio: 10px;
    --radio-lg: 14px;
    --radio-completo: 999px;

    /* --- Sombras --------------------------------------------------------
       Muy contenidas: en un panel denso, las sombras marcadas ensucian.
       La jerarquía la da el borde de un píxel, no el desenfoque.          */
    --sombra-sutil: 0 1px 2px rgba(28, 25, 23, .05);
    --sombra: 0 1px 3px rgba(28, 25, 23, .07), 0 1px 2px rgba(28, 25, 23, .04);
    --sombra-elevada: 0 10px 30px -12px rgba(28, 25, 23, .22), 0 2px 6px rgba(28, 25, 23, .06);
    --sombra-flotante: 0 24px 60px -20px rgba(28, 25, 23, .35);

    /* --- Movimiento -----------------------------------------------------
       Las curvas nativas de CSS son demasiado tímidas: no tienen el golpe
       que hace que una animación se sienta intencionada.                  */
    --salida: cubic-bezier(0.23, 1, 0.32, 1);
    --entrada-salida: cubic-bezier(0.77, 0, 0.175, 1);
    --cajon: cubic-bezier(0.32, 0.72, 0, 1);

    --anillo: 0 0 0 3px color-mix(in srgb, var(--marca-acento) 22%, transparent);

    /* --- Medidas -------------------------------------------------------- */
    --barra-lateral: 250px;
    --barra-superior: 56px;
}

/* =========================================================================
   TEMA OSCURO
   Solo cambian las variables: ni un componente sabe en qué tema está.
   Se activa por preferencia del sistema y se puede fijar a mano con el
   atributo data-tema, que siempre gana sobre la preferencia.
   ========================================================================= */
@media (prefers-color-scheme: dark) {

    :root:not([data-tema="claro"]) {
        --lienzo: #17161A;
        --superficie: #1F1E23;
        --superficie-hundida: #26252B;
        --superficie-alterna: #232228;

        --borde: #34323A;
        --borde-fuerte: #45434D;

        --tinta: #F5F4F2;
        --tinta-suave: #B5B1AE;
        --tinta-tenue: #83807C;

        --exito: #4ADE80;
        --exito-fondo: #14261A;
        --exito-borde: #235C34;

        --aviso: #FBBF24;
        --aviso-fondo: #2A2010;
        --aviso-borde: #6B4E14;

        --peligro: #F87171;
        --peligro-fondo: #2B1616;
        --peligro-borde: #7F2C2C;

        --info: #93C5FD;
        --info-fondo: #14203A;
        --info-borde: #2C4A80;

        --sombra-sutil: 0 1px 2px rgba(0, 0, 0, .4);
        --sombra: 0 1px 3px rgba(0, 0, 0, .5);
        --sombra-elevada: 0 10px 30px -12px rgba(0, 0, 0, .7);
        --sombra-flotante: 0 24px 60px -20px rgba(0, 0, 0, .8);
    }
}

:root[data-tema="oscuro"] {
    --lienzo: #17161A;
    --superficie: #1F1E23;
    --superficie-hundida: #26252B;
    --superficie-alterna: #232228;

    --borde: #34323A;
    --borde-fuerte: #45434D;

    --tinta: #F5F4F2;
    --tinta-suave: #B5B1AE;
    --tinta-tenue: #83807C;

    --exito: #4ADE80;
    --exito-fondo: #14261A;
    --exito-borde: #235C34;

    --aviso: #FBBF24;
    --aviso-fondo: #2A2010;
    --aviso-borde: #6B4E14;

    --peligro: #F87171;
    --peligro-fondo: #2B1616;
    --peligro-borde: #7F2C2C;

    --info: #93C5FD;
    --info-fondo: #14203A;
    --info-borde: #2C4A80;

    --sombra-sutil: 0 1px 2px rgba(0, 0, 0, .4);
    --sombra: 0 1px 3px rgba(0, 0, 0, .5);
    --sombra-elevada: 0 10px 30px -12px rgba(0, 0, 0, .7);
    --sombra-flotante: 0 24px 60px -20px rgba(0, 0, 0, .8);
}


/* =========================================================================
   2. BASE
   ========================================================================= */
*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    background: var(--lienzo);
    color: var(--tinta);
    font-family: var(--fuente);
    font-size: 14px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4 {
    margin: 0;
    font-weight: 600;
    letter-spacing: -0.015em;
    color: var(--tinta);
}

p {
    margin: 0;
}

a {
    color: var(--marca-acento);
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

/* TODA cifra del sistema. Sin esto, una columna de precios baila. */
.cifra,
td.cifra,
.tabla td.num,
input[type="number"] {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
}

.mono {
    font-family: var(--fuente-mono);
    font-size: .8125rem;
    letter-spacing: -0.02em;
}

/* Foco visible SIEMPRE. Quitar el outline sin reemplazarlo deja el panel
   inutilizable con teclado, que es como lo usa quien captura rápido. */
:focus-visible {
    outline: 2px solid var(--marca-acento);
    outline-offset: 2px;
    border-radius: var(--radio-xs);
}

::selection {
    background: color-mix(in srgb, var(--marca-acento) 22%, transparent);
}

/* Barras de desplazamiento discretas */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--borde-fuerte) transparent;
}

*::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

*::-webkit-scrollbar-thumb {
    background: var(--borde-fuerte);
    border: 3px solid transparent;
    border-radius: var(--radio-completo);
    background-clip: content-box;
}


/* =========================================================================
   3. ESTRUCTURA — barra lateral + contenido
   ========================================================================= */
.app {
    display: grid;
    grid-template-columns: var(--barra-lateral) 1fr;
    min-height: 100vh;
}

.lateral {
    position: sticky;
    top: 0;
    height: 100vh;
    display: flex;
    flex-direction: column;
    background: var(--superficie-hundida);
    border-right: 1px solid var(--borde);
    overflow: hidden;
}

.lateral__marca {
    display: flex;
    align-items: center;
    gap: 10px;
    height: var(--barra-superior);
    padding: 0 16px;
    border-bottom: 1px solid var(--borde);
    flex-shrink: 0;
}

.lateral__logo {
    width: 28px;
    height: 28px;
    border-radius: 8px;
    background: var(--marca-tinta);
    color: #fff;
    display: grid;
    place-items: center;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: -0.03em;
    flex-shrink: 0;
    overflow: hidden;
}

.lateral__logo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.lateral__nombre {
    font-weight: 600;
    font-size: 13.5px;
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.lateral__nav {
    flex: 1;
    overflow-y: auto;
    padding: 12px 10px 20px;
}

.lateral__grupo {
    margin-top: 14px;
}

.lateral__grupo:first-child {
    margin-top: 0;
}

.lateral__titulo {
    padding: 0 8px 6px;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--tinta-tenue);
}

.nav__enlace {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 8px;
    margin-bottom: 1px;
    border-radius: var(--radio-sm);
    color: var(--tinta-suave);
    font-size: 13.5px;
    font-weight: 500;
    text-decoration: none;
    position: relative;
    transition: background-color 120ms ease, color 120ms ease;
}

.nav__enlace svg {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    opacity: .75;
}

@media (hover: hover) and (pointer: fine) {

    .nav__enlace:hover {
        background: color-mix(in srgb, var(--tinta) 5%, transparent);
        color: var(--tinta);
        text-decoration: none;
    }
}

/* El activo es una pastilla blanca elevada: se lee como "estás aquí" sin
   necesitar color, y funciona igual en tema claro y oscuro. */
.nav__enlace[aria-current="page"] {
    background: var(--superficie);
    color: var(--tinta);
    box-shadow: var(--sombra-sutil);
    font-weight: 600;
}

.nav__enlace[aria-current="page"] svg {
    opacity: 1;
    color: var(--marca-acento);
}

.nav__contador {
    margin-left: auto;
    font-size: 11px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--peligro);
    background: var(--peligro-fondo);
    border: 1px solid var(--peligro-borde);
    padding: 1px 6px;
    border-radius: var(--radio-completo);
}

.lateral__pie {
    border-top: 1px solid var(--borde);
    padding: 10px;
    flex-shrink: 0;
}

.principal {
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.superior {
    position: sticky;
    top: 0;
    z-index: 30;
    height: var(--barra-superior);
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 0 20px;
    background: color-mix(in srgb, var(--superficie) 85%, transparent);
    backdrop-filter: saturate(180%) blur(12px);
    -webkit-backdrop-filter: saturate(180%) blur(12px);
    border-bottom: 1px solid var(--borde);
}

.superior__titulo {
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -0.015em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.superior__acciones {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 8px;
}

.contenido {
    padding: 22px 20px 64px;
    max-width: 1440px;
    width: 100%;
}

.encabezado-pagina {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 18px;
}

.encabezado-pagina h1 {
    font-size: 22px;
    letter-spacing: -0.025em;
}

.encabezado-pagina p {
    color: var(--tinta-suave);
    font-size: 13.5px;
    margin-top: 3px;
}

.encabezado-pagina__acciones {
    margin-left: auto;
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}


/* =========================================================================
   4. BOTONES
   El :active con scale(0.97) no es decoración: es el acuse de recibo. Sin
   él, en una tablet el usuario no sabe si el toque entró y vuelve a picar.
   ========================================================================= */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    height: 36px;
    padding: 0 14px;
    border: 1px solid transparent;
    border-radius: var(--radio-sm);
    background: var(--superficie);
    color: var(--tinta);
    font-family: inherit;
    font-size: 13.5px;
    font-weight: 550;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    transition: transform 160ms var(--salida), background-color 140ms ease, border-color 140ms ease, box-shadow 140ms ease, opacity 140ms ease;
}

.btn svg {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
}

.btn:active {
    transform: scale(.97);
}

/* Un botón con el atributo hidden debe desaparecer: el display de la clase
   le ganaba a [hidden] y el botón se quedaba pintado. */
.btn[hidden] {
    display: none;
}

.btn:disabled,
.btn[aria-disabled="true"] {
    opacity: .5;
    cursor: not-allowed;
    transform: none;
}

/* --- Primario --------------------------------------------------------- */
.btn--primario {
    background: var(--marca-acento);

    /* No es blanco fijo: lo decide el servidor por luminancia. Con un
       acento claro (amarillo, lima, cian) el blanco desaparecería. */
    color: var(--marca-acento-encima);
    box-shadow: var(--sombra-sutil);
}

@media (hover: hover) and (pointer: fine) {

    .btn--primario:hover:not(:disabled) {
        background: color-mix(in srgb, var(--marca-acento) 88%, #000);
    }
}

/* --- Secundario ------------------------------------------------------- */
.btn--secundario {
    border-color: var(--borde);
    box-shadow: var(--sombra-sutil);
}

@media (hover: hover) and (pointer: fine) {

    .btn--secundario:hover:not(:disabled) {
        background: var(--superficie-hundida);
        border-color: var(--borde-fuerte);
    }
}

/* --- Fantasma --------------------------------------------------------- */
.btn--fantasma {
    background: transparent;
    color: var(--tinta-suave);
}

@media (hover: hover) and (pointer: fine) {

    .btn--fantasma:hover:not(:disabled) {
        background: color-mix(in srgb, var(--tinta) 6%, transparent);
        color: var(--tinta);
    }
}

/* --- Peligro ---------------------------------------------------------- */
.btn--peligro {
    background: var(--peligro);
    color: #fff;
}

@media (hover: hover) and (pointer: fine) {

    .btn--peligro:hover:not(:disabled) {
        background: color-mix(in srgb, var(--peligro) 85%, #000);
    }
}

.btn--sm {
    height: 30px;
    padding: 0 10px;
    font-size: 12.5px;
    border-radius: var(--radio-xs);
}

.btn--lg {
    height: 44px;
    padding: 0 20px;
    font-size: 15px;
}

.btn--bloque {
    width: 100%;
}

.btn--icono {
    width: 36px;
    padding: 0;
}

.btn--icono.btn--sm {
    width: 30px;
}

/* Estado de carga: el texto se difumina en vez de desaparecer. El desenfoque
   tapa el salto entre los dos estados y se lee como una sola transformación
   en lugar de dos objetos intercambiándose. */
.btn[data-cargando="true"] {
    pointer-events: none;
    position: relative;
    color: transparent;
}

.btn[data-cargando="true"] > * {
    filter: blur(3px);
    opacity: .35;
    transition: filter 180ms ease, opacity 180ms ease;
}

.btn[data-cargando="true"]::after {
    content: "";
    position: absolute;
    width: 15px;
    height: 15px;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    color: inherit;
    animation: girar 620ms linear infinite;
}

.btn--primario[data-cargando="true"]::after,
.btn--peligro[data-cargando="true"]::after {
    border-color: rgba(255, 255, 255, .85);
    border-top-color: transparent;
}

.btn--secundario[data-cargando="true"]::after,
.btn--fantasma[data-cargando="true"]::after {
    border-color: var(--tinta-suave);
    border-top-color: transparent;
}

/* Girar rápido: un spinner ágil hace que la espera se sienta más corta,
   aunque el servidor tarde exactamente lo mismo. */
@keyframes girar {

    to {
        transform: rotate(360deg);
    }
}


/* =========================================================================
   5. FORMULARIOS
   ========================================================================= */
.campo {
    display: block;
    margin-bottom: 14px;
}

.campo__etiqueta {
    display: block;
    margin-bottom: 5px;
    font-size: 12.5px;
    font-weight: 550;
    color: var(--tinta-suave);
}

.campo__obligatorio {
    color: var(--peligro);
    margin-left: 2px;
}

.entrada,
.selector,
.area {
    width: 100%;
    min-height: 36px;
    padding: 8px 11px;
    border: 1px solid var(--borde);
    border-radius: var(--radio-sm);
    background: var(--superficie);
    color: var(--tinta);
    font-family: inherit;
    font-size: 13.5px;
    line-height: 1.35;
    transition: border-color 140ms ease, box-shadow 140ms ease;
    appearance: none;
}

.area {
    min-height: 88px;
    resize: vertical;
}

.selector {
    padding-right: 32px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238A8580' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 11px center;
}

.entrada::placeholder,
.area::placeholder {
    color: var(--tinta-tenue);
}

.entrada:focus,
.selector:focus,
.area:focus {
    outline: none;
    border-color: var(--marca-acento);
    box-shadow: var(--anillo);
}

.entrada[aria-invalid="true"],
.selector[aria-invalid="true"],
.area[aria-invalid="true"] {
    border-color: var(--peligro);
}

.entrada[aria-invalid="true"]:focus {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--peligro) 20%, transparent);
}

.entrada:disabled,
.selector:disabled,
.area:disabled {
    background: var(--superficie-hundida);
    color: var(--tinta-tenue);
    cursor: not-allowed;
}

.campo__error {
    display: block;
    margin-top: 5px;
    font-size: 12px;
    color: var(--peligro);
}

.campo__ayuda {
    display: block;
    margin-top: 5px;
    font-size: 12px;
    color: var(--tinta-tenue);
}

/* Entrada con prefijo de moneda */
.entrada-grupo {
    display: flex;
    align-items: stretch;
}

.entrada-grupo__prefijo {
    display: grid;
    place-items: center;
    padding: 0 10px;
    border: 1px solid var(--borde);
    border-right: 0;
    border-radius: var(--radio-sm) 0 0 var(--radio-sm);
    background: var(--superficie-hundida);
    color: var(--tinta-tenue);
    font-size: 13px;
    font-weight: 550;
}

.entrada-grupo .entrada {
    border-radius: 0 var(--radio-sm) var(--radio-sm) 0;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* Interruptor */
.interruptor {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    user-select: none;
}

.interruptor input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.interruptor__pista {
    position: relative;
    width: 36px;
    height: 21px;
    border-radius: var(--radio-completo);
    background: var(--borde-fuerte);
    flex-shrink: 0;
    transition: background-color 180ms var(--salida);
}

.interruptor__pista::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 17px;
    height: 17px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .25);
    transition: transform 180ms var(--salida);
}

.interruptor input:checked + .interruptor__pista {
    background: var(--marca-acento);
}

.interruptor input:checked + .interruptor__pista::after {
    transform: translateX(15px);
}

.interruptor input:focus-visible + .interruptor__pista {
    box-shadow: var(--anillo);
}

.interruptor__texto {
    font-size: 13.5px;
    color: var(--tinta);
}

/* Casilla */
.casilla {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    font-size: 13.5px;
}

.casilla input[type="checkbox"] {
    width: 16px;
    height: 16px;
    accent-color: var(--marca-acento);
    cursor: pointer;
    flex-shrink: 0;
}

/* Rejilla de formulario */
.rejilla {
    display: grid;
    gap: 0 16px;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.rejilla--2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.col-completa {
    grid-column: 1 / -1;
}

@media (max-width: 640px) {

    .rejilla--2 {
        grid-template-columns: 1fr;
    }
}


/* =========================================================================
   6. TARJETAS Y PANELES
   ========================================================================= */
.tarjeta {
    background: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    box-shadow: var(--sombra-sutil);
}

.tarjeta__cabeza {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 13px 16px;
    border-bottom: 1px solid var(--borde);
}

.tarjeta__titulo {
    font-size: 14px;
    font-weight: 600;
}

.tarjeta__subtitulo {
    font-size: 12.5px;
    color: var(--tinta-tenue);
    margin-top: 1px;
}

.tarjeta__cuerpo {
    padding: 16px;
}

/* Lista de datos clave→valor (p. ej. la ficha del certificado de impresión). */
.lista-datos {
    margin: 0;
    display: grid;
    gap: 10px;
}

.lista-datos > div {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 16px;
}

.lista-datos dt {
    color: var(--tinta-tenue);
    font-size: 12.5px;
}

.lista-datos dd {
    margin: 0;
    text-align: right;
    font-weight: 600;
}

/* Filas de configuración de impresora por caja. */
.lista-cajas {
    display: grid;
    gap: 10px;
}

.caja-fila {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px;
    padding: 12px;
    border: 1px solid var(--borde);
    border-radius: var(--radio-sm);
    background: var(--superficie-hundida);
}

.caja-fila__nombre {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 120px;
    padding-bottom: 6px;
}

.caja-fila__impresora {
    flex: 1 1 220px;
}

.caja-fila__ancho {
    width: 110px;
    flex: 0 0 auto;
}

.caja-fila__acciones {
    display: flex;
    gap: 6px;
    padding-bottom: 1px;
}

/* Pasos numerados de una guía (instalación de QZ Tray). */
.lista-pasos {
    margin: 0;
    padding-left: 20px;
    display: grid;
    gap: 9px;
    font-size: 13.5px;
    line-height: 1.5;
}

.lista-pasos code {
    font-family: var(--fuente-mono);
    font-size: 12px;
    background: var(--superficie-hundida);
    padding: 1px 5px;
    border-radius: 5px;
}

.tarjeta__pie {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 16px;
    border-top: 1px solid var(--borde);
    background: var(--superficie-alterna);
    border-radius: 0 0 var(--radio) var(--radio);
}

/* --- Métricas del tablero -------------------------------------------- */
.metricas {
    display: grid;
    gap: 12px;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    margin-bottom: 20px;
}

.metrica {
    background: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    padding: 14px 16px;
    box-shadow: var(--sombra-sutil);
    position: relative;
    overflow: hidden;
}

.metrica__etiqueta {
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--tinta-tenue);
}

.metrica__valor {
    margin-top: 7px;
    font-size: 26px;
    font-weight: 640;
    letter-spacing: -0.035em;
    line-height: 1.05;
    font-variant-numeric: tabular-nums;
}

.metrica__pie {
    margin-top: 5px;
    font-size: 12px;
    color: var(--tinta-tenue);
}

.metrica--alerta .metrica__valor {
    color: var(--peligro);
}

.metrica--alerta {
    border-color: var(--peligro-borde);
    background: linear-gradient(180deg, var(--peligro-fondo), var(--superficie) 60%);
}


/* =========================================================================
   7. TABLAS
   La tabla es la pantalla que más se mira en todo el sistema; se optimiza
   para escaneo vertical: cabecera pegajosa, filas altas y cifras a la
   derecha con numerales tabulares.
   ========================================================================= */
.tabla-envoltura {
    width: 100%;
    overflow-x: auto;
    border-radius: var(--radio);
}

.tabla {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 13.5px;
}

.tabla thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--superficie-alterna);
    padding: 9px 14px;
    text-align: left;
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--tinta-tenue);
    border-bottom: 1px solid var(--borde);
    white-space: nowrap;
}

.tabla tbody td {
    padding: 11px 14px;
    border-bottom: 1px solid var(--borde);
    vertical-align: middle;
}

.tabla tbody tr:last-child td {
    border-bottom: 0;
}

@media (hover: hover) and (pointer: fine) {

    .tabla tbody tr:hover td {
        background: var(--superficie-alterna);
    }
}

.tabla .num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.tabla .acciones {
    text-align: right;
    white-space: nowrap;
}

.tabla__principal {
    font-weight: 550;
    color: var(--tinta);
}

.tabla__secundario {
    display: block;
    font-size: 12px;
    color: var(--tinta-tenue);
    margin-top: 1px;
}

/* Miniatura de producto */
.miniatura {
    width: 34px;
    height: 34px;
    border-radius: var(--radio-xs);
    object-fit: cover;
    background: var(--superficie-hundida);
    border: 1px solid var(--borde);
    flex-shrink: 0;
}

.miniatura--vacia {
    display: grid;
    place-items: center;
    color: var(--tinta-tenue);
}

.celda-producto {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}


/* =========================================================================
   8. INSIGNIAS Y ESTADOS
   ========================================================================= */
.insignia {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px;
    border-radius: var(--radio-completo);
    border: 1px solid transparent;
    font-size: 11.5px;
    font-weight: 600;
    line-height: 1.5;
    white-space: nowrap;
}

.insignia--neutral {
    background: var(--superficie-hundida);
    border-color: var(--borde);
    color: var(--tinta-suave);
}

.insignia--exito {
    background: var(--exito-fondo);
    border-color: var(--exito-borde);
    color: var(--exito);
}

.insignia--aviso {
    background: var(--aviso-fondo);
    border-color: var(--aviso-borde);
    color: var(--aviso);
}

.insignia--peligro {
    background: var(--peligro-fondo);
    border-color: var(--peligro-borde);
    color: var(--peligro);
}

.insignia--info {
    background: var(--info-fondo);
    border-color: var(--info-borde);
    color: var(--info);
}

/* Punto de estado: menos ruidoso que una insignia completa cuando la
   tabla ya tiene mucha información. */
.punto {
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    margin-right: 6px;
    vertical-align: baseline;
}

.punto--activo {
    background: var(--exito);
}

.punto--inactivo {
    background: var(--tinta-tenue);
}


/* =========================================================================
   9. AVISOS
   ========================================================================= */
.aviso {
    display: flex;
    gap: 11px;
    padding: 12px 14px;
    border: 1px solid var(--borde);
    border-radius: var(--radio-sm);
    background: var(--superficie-hundida);
    font-size: 13.5px;
    color: var(--tinta-suave);
    margin-bottom: 16px;
}

.aviso svg {
    width: 17px;
    height: 17px;
    flex-shrink: 0;
    margin-top: 1px;
}

.aviso strong {
    color: var(--tinta);
    font-weight: 600;
}

.aviso--exito {
    background: var(--exito-fondo);
    border-color: var(--exito-borde);
    color: var(--exito);
}

.aviso--aviso {
    background: var(--aviso-fondo);
    border-color: var(--aviso-borde);
    color: var(--aviso);
}

.aviso--peligro {
    background: var(--peligro-fondo);
    border-color: var(--peligro-borde);
    color: var(--peligro);
}

.aviso--info {
    background: var(--info-fondo);
    border-color: var(--info-borde);
    color: var(--info);
}


/* =========================================================================
   10. ESTADO VACÍO
   Nunca una tabla en blanco: siempre explica qué falta y ofrece la salida.
   ========================================================================= */
.vacio {
    padding: 52px 24px;
    text-align: center;
}

.vacio__icono {
    width: 44px;
    height: 44px;
    margin: 0 auto 14px;
    display: grid;
    place-items: center;
    border-radius: var(--radio);
    background: var(--superficie-hundida);
    border: 1px solid var(--borde);
    color: var(--tinta-tenue);
}

.vacio__titulo {
    font-size: 15px;
    font-weight: 600;
    margin-bottom: 5px;
}

.vacio__texto {
    font-size: 13.5px;
    color: var(--tinta-tenue);
    max-width: 380px;
    margin: 0 auto 18px;
    line-height: 1.55;
}


/* =========================================================================
   11. AVISOS FLOTANTES (toasts)
   Transiciones, NO fotogramas: los avisos se disparan en ráfaga y una
   animación por fotogramas reinicia desde cero al interrumpirse. Una
   transición se redirige desde donde iba y no da el brinco.
   ========================================================================= */
.avisos {
    position: fixed;
    right: 16px;
    bottom: 16px;
    z-index: 90;
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: min(370px, calc(100vw - 32px));
    pointer-events: none;
}

.toast {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 14px;
    border-radius: var(--radio);
    background: var(--superficie);
    border: 1px solid var(--borde);
    box-shadow: var(--sombra-elevada);
    font-size: 13.5px;
    color: var(--tinta);

    opacity: 1;
    transform: translateY(0) scale(1);
    transition: opacity 260ms var(--salida), transform 260ms var(--salida);
}

/* translateY con porcentaje: se desplaza su propia altura, mida lo que mida. */
.toast[data-estado="entrando"] {
    opacity: 0;
    transform: translateY(100%) scale(.98);
}

/* La salida es más rápida que la entrada: al usuario ya no le interesa. */
.toast[data-estado="saliendo"] {
    opacity: 0;
    transform: translateY(8px) scale(.98);
    transition-duration: 160ms;
}

.toast__icono {
    width: 17px;
    height: 17px;
    flex-shrink: 0;
    margin-top: 1px;
}

.toast--exito .toast__icono {
    color: var(--exito);
}

.toast--error .toast__icono {
    color: var(--peligro);
}

.toast--info .toast__icono {
    color: var(--info);
}

.toast__cuerpo {
    flex: 1;
    min-width: 0;
    line-height: 1.45;
}

.toast__cerrar {
    background: none;
    border: 0;
    padding: 2px;
    cursor: pointer;
    color: var(--tinta-tenue);
    border-radius: var(--radio-xs);
    flex-shrink: 0;
    transition: color 140ms ease;
}

.toast__cerrar:hover {
    color: var(--tinta);
}


/* =========================================================================
   12. DIÁLOGOS
   El diálogo escala desde el centro (no desde un disparador) porque no está
   anclado a ningún botón: aparece en medio de la pantalla. Y nunca desde
   scale(0): nada en el mundo real aparece de la nada.
   ========================================================================= */
.velo {
    position: fixed;
    inset: 0;
    z-index: 80;
    display: grid;
    place-items: center;
    padding: 20px;
    background: rgba(28, 25, 23, .45);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    opacity: 1;
    transition: opacity 200ms var(--salida);
}

/* SIN ESTA REGLA, NINGÚN DIÁLOGO SE ESCONDE JAMÁS.
   Los diálogos se ocultan con el atributo hidden, pero el display: grid de
   arriba —al ser regla de clase— le gana al display: none que el navegador
   da a [hidden]. El resultado era el diálogo de contraseña plantado encima
   de TODAS las pantallas del panel, y el de reseñas tapando la ficha del
   producto. Cada componente hermano (.cajon, .lightbox, .velo-menu) tiene
   su propia regla [hidden]; este era el único sin ella. */
.velo[hidden] {
    display: none;
}

.velo[data-estado="entrando"],
.velo[data-estado="saliendo"] {
    opacity: 0;
}

.dialogo {
    width: min(540px, 100%);
    max-height: calc(100vh - 40px);
    display: flex;
    flex-direction: column;
    background: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio-lg);
    box-shadow: var(--sombra-flotante);
    overflow: hidden;

    transform: scale(1) translateY(0);
    opacity: 1;
    transition: transform 220ms var(--salida), opacity 220ms var(--salida);
}

.dialogo--ancho {
    width: min(820px, 100%);
}

.velo[data-estado="entrando"] .dialogo {
    transform: scale(.96) translateY(6px);
    opacity: 0;
}

.velo[data-estado="saliendo"] .dialogo {
    transform: scale(.98) translateY(2px);
    opacity: 0;
    transition-duration: 150ms;
}

.dialogo__cabeza {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 16px 18px 13px;
    border-bottom: 1px solid var(--borde);
}

.dialogo__titulo {
    font-size: 15.5px;
    font-weight: 600;
    letter-spacing: -0.015em;
}

.dialogo__descripcion {
    font-size: 13px;
    color: var(--tinta-tenue);
    margin-top: 3px;
    line-height: 1.5;
}

.dialogo__cuerpo {
    padding: 16px 18px;
    overflow-y: auto;
}

.dialogo__pie {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 13px 18px;
    border-top: 1px solid var(--borde);
    background: var(--superficie-alterna);
}


/* =========================================================================
   13. BARRA DE FILTROS
   ========================================================================= */
.filtros {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 11px 14px;
    background: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio) var(--radio) 0 0;
    border-bottom: 0;
}

.buscador {
    position: relative;
    flex: 1;
    min-width: 210px;
}

.buscador svg {
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    width: 15px;
    height: 15px;
    color: var(--tinta-tenue);
    pointer-events: none;
}

.buscador .entrada {
    padding-left: 32px;
}

.filtros .selector {
    width: auto;
    min-width: 150px;
}

.paginacion {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 14px;
    border: 1px solid var(--borde);
    border-top: 0;
    border-radius: 0 0 var(--radio) var(--radio);
    background: var(--superficie);
    font-size: 12.5px;
    color: var(--tinta-tenue);
}

.paginacion__botones {
    margin-left: auto;
    display: flex;
    gap: 6px;
}


/* =========================================================================
   14. PESTAÑAS
   ========================================================================= */
.pestanas {
    display: flex;
    gap: 2px;
    border-bottom: 1px solid var(--borde);
    margin-bottom: 18px;
    overflow-x: auto;
}

.pestana {
    position: relative;
    padding: 9px 13px;
    border: 0;
    background: none;
    color: var(--tinta-tenue);
    font-family: inherit;
    font-size: 13.5px;
    font-weight: 550;
    cursor: pointer;
    white-space: nowrap;
    transition: color 140ms ease;
}

.pestana::after {
    content: "";
    position: absolute;
    left: 8px;
    right: 8px;
    bottom: -1px;
    height: 2px;
    border-radius: 2px 2px 0 0;
    background: var(--marca-acento);
    transform: scaleX(0);
    transform-origin: center;
    transition: transform 200ms var(--salida);
}

.pestana[aria-selected="true"] {
    color: var(--tinta);
}

.pestana[aria-selected="true"]::after {
    transform: scaleX(1);
}


/* =========================================================================
   15. ACCESO (login)
   ========================================================================= */
.acceso {
    min-height: 100vh;
    display: grid;
    grid-template-columns: 1fr;
    place-items: center;
    padding: 24px;
    background:
        radial-gradient(1000px 520px at 15% -10%, color-mix(in srgb, var(--marca-acento) 9%, transparent), transparent 65%),
        var(--lienzo);
}

.acceso__caja {
    width: min(392px, 100%);
}

.acceso__marca {
    display: flex;
    align-items: center;
    gap: 11px;
    margin-bottom: 22px;
}

.acceso__logo {
    width: 38px;
    height: 38px;
    border-radius: 11px;
    background: var(--marca-tinta);
    color: #fff;
    display: grid;
    place-items: center;
    font-weight: 700;
    font-size: 16px;
    letter-spacing: -0.04em;
    overflow: hidden;
}

.acceso__logo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.acceso__titulo {
    font-size: 20px;
    letter-spacing: -0.025em;
}

.acceso__subtitulo {
    color: var(--tinta-suave);
    font-size: 13.5px;
    margin-top: 2px;
}

.acceso__tarjeta {
    background: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio-lg);
    padding: 22px;
    box-shadow: var(--sombra-elevada);
}

.acceso__pie {
    margin-top: 18px;
    text-align: center;
    font-size: 12px;
    color: var(--tinta-tenue);
}

/* Enlaces secundarios de la tarjeta de acceso (olvidé mi contraseña, volver).
   Van discretos a propósito: el camino principal es entrar, no recuperar. */
.acceso__enlaces {
    margin-top: 16px;
    text-align: center;
    font-size: 13.5px;
}

.acceso__enlace {
    color: var(--tinta-suave);
    text-decoration: none;
    border-bottom: 1px solid transparent;
    padding-bottom: 1px;
    transition: color 160ms ease, border-color 160ms ease;
}

.acceso__enlace:hover {
    color: var(--tinta);
    border-bottom-color: var(--borde-fuerte);
}

/* Medidor de fuerza de la contraseña. Tres barras: no puntúa con precisión,
   solo avisa cuando lo escrito es obviamente débil. Se anima el color, no la
   geometría, para que no dé saltos mientras se teclea. */
.fuerza {
    display: flex;
    gap: 4px;
    margin-top: 8px;
}

.fuerza[hidden] {
    display: none;
}

.fuerza__barra {
    height: 3px;
    flex: 1;
    border-radius: 2px;
    background: var(--borde);
    transition: background-color 200ms ease;
}

.fuerza[data-nivel="1"] .fuerza__barra:nth-child(1) {
    background: var(--peligro);
}

.fuerza[data-nivel="2"] .fuerza__barra:nth-child(-n+2) {
    background: var(--aviso);
}

.fuerza[data-nivel="3"] .fuerza__barra {
    background: var(--exito);
}

.fuerza__texto {
    margin-top: 6px;
    font-size: 12.5px;
    color: var(--tinta-tenue);
    min-height: 17px;
}

/* Sacudida al fallar el acceso: comunica el rechazo sin leer nada. Se
   dispara poco (solo en error), así que la animación está justificada. */
@keyframes sacudir {

    0%, 100% {
        transform: translateX(0);
    }

    20% {
        transform: translateX(-6px);
    }

    40% {
        transform: translateX(5px);
    }

    60% {
        transform: translateX(-3px);
    }

    80% {
        transform: translateX(2px);
    }
}

.acceso__tarjeta[data-error="true"] {
    animation: sacudir 380ms var(--entrada-salida);
}


/* =========================================================================
   16. MENÚ DESPLEGABLE
   Escala desde su disparador, no desde el centro: el menú SÍ está anclado.
   ========================================================================= */
.desplegable {
    position: relative;
}

.desplegable__panel {
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    z-index: 50;
    min-width: 208px;
    padding: 5px;
    background: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    box-shadow: var(--sombra-elevada);

    transform-origin: top right;
    transform: scale(1);
    opacity: 1;
    transition: transform 160ms var(--salida), opacity 160ms var(--salida);
}

.desplegable__panel[hidden] {
    display: block;
    pointer-events: none;
    opacity: 0;
    transform: scale(.96);
}

.desplegable__item {
    display: flex;
    align-items: center;
    gap: 9px;
    width: 100%;
    padding: 7px 9px;
    border: 0;
    border-radius: var(--radio-xs);
    background: none;
    color: var(--tinta);
    font-family: inherit;
    font-size: 13.5px;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 120ms ease;
}

.desplegable__item svg {
    width: 15px;
    height: 15px;
    color: var(--tinta-tenue);
    flex-shrink: 0;
}

@media (hover: hover) and (pointer: fine) {

    .desplegable__item:hover {
        background: var(--superficie-hundida);
        text-decoration: none;
    }
}

.desplegable__item--peligro {
    color: var(--peligro);
}

.desplegable__item--peligro svg {
    color: var(--peligro);
}

.desplegable__separador {
    height: 1px;
    margin: 5px 3px;
    background: var(--borde);
}

.desplegable__encabezado {
    padding: 8px 9px 6px;
    font-size: 12px;
}

.desplegable__encabezado strong {
    display: block;
    color: var(--tinta);
    font-weight: 600;
}

.desplegable__encabezado span {
    color: var(--tinta-tenue);
}


/* =========================================================================
   17. UTILIDADES MÍNIMAS
   ========================================================================= */
.fila {
    display: flex;
    align-items: center;
    gap: 8px;
}

.fila--separada {
    justify-content: space-between;
}

.crece {
    flex: 1;
    min-width: 0;
}

.tenue {
    color: var(--tinta-tenue);
}

.suave {
    color: var(--tinta-suave);
}

.pequeno {
    font-size: 12.5px;
}

.oculto {
    display: none !important;
}

.solo-lectores {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.pila > * + * {
    margin-top: 16px;
}

/* Lista de diagnóstico ("si no sale, revisa esto"). Sin viñeta redonda: una
   raya al margen se lee como una lista de causas, no como un menú. */
.lista-ayuda {
    list-style: none;
    padding: 0;
    margin: 0;
    font-size: 13.5px;
    line-height: 1.6;
    color: var(--tinta-suave);
}

.lista-ayuda > li + li {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--borde);
}

.lista-ayuda strong {
    color: var(--tinta);
    font-weight: 600;
}

/* Pares etiqueta/valor de solo lectura (versión de PHP, última migración).
   No es una tabla: son datos sueltos y una tabla de dos filas se lee peor. */
.datos-sueltos {
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--borde);
    display: grid;
    gap: 10px;
}

.datos-sueltos__etiqueta {
    display: block;
    font-size: 12px;
    color: var(--tinta-tenue);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 2px;
}

.datos-sueltos__valor {
    display: block;
    font-size: 13.5px;
    color: var(--tinta);
}

/* Comandos para copiar (tareas programadas). Desborda en horizontal dentro
   de su propia caja: partir una ruta en dos líneas la vuelve incopiable. */
.bloque-codigo {
    margin: 0;
    padding: 10px 12px;
    background: var(--lienzo);
    border: 1px solid var(--borde);
    border-radius: var(--radio-sm);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px;
    line-height: 1.5;
    color: var(--tinta);
    overflow-x: auto;
    white-space: pre;
    user-select: all;
}


/* =========================================================================
   18. ENTRADA ESCALONADA
   Las tarjetas del tablero aparecen en cascada. Retrasos cortos (40 ms): con
   más, la página se siente lenta en lugar de viva. Es decorativo, así que
   nunca bloquea la interacción.
   ========================================================================= */
@keyframes surgir {

    from {
        opacity: 0;
        transform: translateY(6px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.escalonado > * {
    opacity: 0;
    animation: surgir 340ms var(--salida) forwards;
}

.escalonado > *:nth-child(1) { animation-delay: 0ms; }
.escalonado > *:nth-child(2) { animation-delay: 40ms; }
.escalonado > *:nth-child(3) { animation-delay: 80ms; }
.escalonado > *:nth-child(4) { animation-delay: 120ms; }
.escalonado > *:nth-child(5) { animation-delay: 160ms; }
.escalonado > *:nth-child(6) { animation-delay: 200ms; }


/* =========================================================================
   19. RESPONSIVO
   El panel se usa en escritorio y en tablet. Por debajo de 1024 px la barra
   lateral se convierte en cajón deslizante.
   ========================================================================= */
.lateral__cerrar,
.abrir-menu {
    display: none;
}

@media (max-width: 1023px) {

    .app {
        grid-template-columns: 1fr;
    }

    .lateral {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        z-index: 70;
        width: 268px;
        transform: translateX(-100%);
        transition: transform 300ms var(--cajon);
        box-shadow: var(--sombra-flotante);
    }

    .lateral[data-abierto="true"] {
        transform: translateX(0);
    }

    .lateral__cerrar {
        display: inline-flex;
        margin-left: auto;
    }

    .abrir-menu {
        display: inline-flex;
    }

    .velo-menu {
        position: fixed;
        inset: 0;
        z-index: 60;
        background: rgba(28, 25, 23, .4);
        opacity: 1;
        transition: opacity 220ms var(--salida);
    }

    .velo-menu[hidden] {
        display: block;
        opacity: 0;
        pointer-events: none;
    }

    .contenido {
        padding: 18px 14px 56px;
    }
}

@media (max-width: 640px) {

    .encabezado-pagina h1 {
        font-size: 19px;
    }

    .metrica__valor {
        font-size: 22px;
    }

    .filtros {
        flex-direction: column;
        align-items: stretch;
    }

    .filtros .selector {
        width: 100%;
    }
}


/* =========================================================================
   20. MOVIMIENTO REDUCIDO
   "Reducido" no es "cero": se conservan las transiciones de opacidad y color
   porque ayudan a entender qué cambió. Lo que se retira es el desplazamiento,
   que es lo que provoca mareo.
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {

    *,
    *::before,
    *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 120ms !important;
        scroll-behavior: auto !important;
    }

    .btn:active {
        transform: none;
    }

    .escalonado > * {
        opacity: 1;
        animation: none;
    }

    .toast[data-estado="entrando"],
    .toast[data-estado="saliendo"] {
        transform: none;
    }

    .velo[data-estado="entrando"] .dialogo,
    .velo[data-estado="saliendo"] .dialogo {
        transform: none;
    }

    .lateral {
        transition: none;
    }
}


/* =========================================================================
   21. IMPRESIÓN
   ========================================================================= */
@media print {

    .lateral,
    .superior,
    .filtros,
    .paginacion,
    .avisos,
    .encabezado-pagina__acciones,
    .acciones {
        display: none !important;
    }

    .app {
        grid-template-columns: 1fr;
    }

    body {
        background: #fff;
    }

    .tarjeta,
    .metrica {
        border: 1px solid #ddd;
        box-shadow: none;
        break-inside: avoid;
    }
}


/* =========================================================================
   PIE DE LA APLICACIÓN

   Cierra cada pantalla del panel con la marca, la versión y el crédito, como
   en los demás proyectos del ecosistema. La versión con fecha está ahí para
   que un reporte de soporte diga de un vistazo qué versión tiene el usuario.

   Va DENTRO de <main>, después de .contenido: así queda debajo del contenido
   real y no compite con la barra lateral, que es un hermano de <main>.
   ========================================================================= */
.pie-app {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px 20px;
    max-width: 1440px;
    width: 100%;
    margin-top: auto;
    padding: 18px 20px;
    border-top: 1px solid var(--borde);
    font-size: 12.5px;
    color: var(--tinta-suave);
}

.pie-app__marca strong {
    color: var(--tinta);
    font-weight: 600;
}

/* La versión como pastilla: se distingue del texto sin gritar. */
.pie-app__version {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 8px;
    border-radius: 999px;
    background: var(--superficie-hundida);
    border: 1px solid var(--borde);
    font-size: 11.5px;
    color: var(--tinta-suave);
    letter-spacing: 0.02em;
}

.pie-app__corazon {
    color: #e0245e;
}

.pie-app__credito a {
    color: var(--primario);
    font-weight: 600;
    text-decoration: none;
}

@media (hover: hover) {

    .pie-app__credito a:hover {
        text-decoration: underline;
    }
}

/* El pie cae hasta abajo aunque la pantalla tenga poco contenido gracias al
   margin-top:auto de arriba: .principal ya es flex en columna y el grid de
   .app lo estira a 100vh, así que sobra espacio que el auto empuja. */

@media (max-width: 620px) {

    .pie-app {
        justify-content: center;
        text-align: center;
        padding: 16px 14px;
    }
}


/* =========================================================================
   REPARTO DEL REEMBOLSO (devoluciones)
   Muestra, antes de confirmar, a qué método regresa el dinero. Es informativo
   —lo calcula el servidor—, por eso se ve como aviso y no como campo editable.
   ========================================================================= */
.reparto-reembolso {
    margin-top: 14px;
    padding: 12px 14px;
    border: 1px solid var(--borde);
    border-radius: var(--radio-sm);
    background: var(--superficie-hundida);
}

.reparto-reembolso__titulo {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--tinta-suave);
    margin-bottom: 8px;
}

.reparto-reembolso__linea {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 4px 0;
    font-size: 14px;
    color: var(--tinta-suave);
}

.reparto-reembolso__linea strong {
    color: var(--tinta);
    font-variant-numeric: tabular-nums;
}


/* =========================================================================
   VISTA PREVIA DE UNA CORRIDA DE TALLAS (formulario de producto)
   Muestra como fichas las tallas que se van a crear, en su orden.
   ========================================================================= */
.vista-corrida {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 12px;
    padding: 12px;
    border: 1px dashed var(--borde-fuerte);
    border-radius: var(--radio-sm);
    background: var(--superficie-hundida);
}

.ficha-talla {
    display: inline-flex;
    align-items: center;
    height: 28px;
    padding: 0 12px;
    border-radius: var(--radio-completo);
    background: var(--superficie);
    border: 1px solid var(--borde);
    font-size: 13px;
    font-weight: 600;
    color: var(--tinta);
}


/* =========================================================================
   GALERÍA DE FOTOS DEL PRODUCTO (formulario)
   Miniaturas reordenables por arrastre. La que sea portada lleva su sello.
   ========================================================================= */
.galeria-fotos {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
    gap: 8px;
    margin-top: 12px;
}

.foto-mini {
    position: relative;
    aspect-ratio: 1;
    border-radius: var(--radio-sm);
    overflow: hidden;
    border: 1px solid var(--borde);
    background: var(--superficie-hundida);
    cursor: grab;
}

.foto-mini img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    pointer-events: none;
}

.foto-mini--portada {
    border-color: var(--marca-acento);
    box-shadow: 0 0 0 1px var(--marca-acento);
}

.foto-mini--arrastrando {
    opacity: 0.4;
}

.foto-portada__insignia {
    position: absolute;
    top: 4px;
    left: 4px;
    padding: 1px 6px;
    border-radius: var(--radio-completo);
    background: var(--marca-acento);
    color: var(--marca-acento-encima);
    font-size: 10px;
    font-weight: 600;
}

.foto-mini__acciones {
    position: absolute;
    top: 4px;
    right: 4px;
    display: flex;
    gap: 4px;
    opacity: 0;
    transition: opacity 140ms ease;
}

.foto-mini:hover .foto-mini__acciones {
    opacity: 1;
}

.foto-mini__accion {
    width: 22px;
    height: 22px;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: var(--radio-xs);
    background: rgba(0, 0, 0, 0.6);
    color: #fff;
    font-size: 12px;
    cursor: pointer;
    line-height: 1;
}

.foto-mini__accion--borrar:hover {
    background: var(--peligro);
}

/* En pantallas táctiles no hay hover: las acciones se ven siempre. */
@media (hover: none) {

    .foto-mini__acciones {
        opacity: 1;
    }
}


/* =========================================================================
   CONSTRUCTOR WEB — asa de arrastre de secciones
   ========================================================================= */
.asa-arrastre {
    flex-shrink: 0;
    width: 30px;
    align-self: stretch;
    border: 0;
    border-radius: var(--radio-xs);
    background: transparent;
    color: var(--tinta-tenue);
    font-size: 18px;
    line-height: 1;
    cursor: grab;
    transition: background-color 140ms ease, color 140ms ease;
}

@media (hover: hover) {

    .asa-arrastre:hover {
        background: var(--superficie-hundida);
        color: var(--tinta);
    }
}

.asa-arrastre:active {
    cursor: grabbing;
}

.seccion-arrastrable--activa {
    opacity: 0.5;
    outline: 2px dashed var(--marca-acento);
    outline-offset: 2px;
}


/* =========================================================================
   ESQUELETOS DE CARGA
   Un bloque gris con un brillo que lo recorre. Ocupa el lugar del contenido
   mientras llega, así la pantalla no "salta" y se percibe más rápida que un
   spinner en blanco. Reutilizable: cualquier .esqueleto brilla.
   ========================================================================= */
.esqueleto {
    position: relative;
    overflow: hidden;
    background: var(--superficie-hundida);
    border-radius: var(--radio-xs);
}

.esqueleto::after {
    content: "";
    position: absolute;
    inset: 0;
    transform: translateX(-100%);
    background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--superficie) 65%, transparent), transparent);
    animation: esqueleto-brillo 1.3s infinite;
}

@keyframes esqueleto-brillo {
    to { transform: translateX(100%); }
}

@media (prefers-reduced-motion: reduce) {

    .esqueleto::after {
        animation: none;
    }
}
