/* =========================================================================
   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;
    /* SUBIDO DE 8A8580 A 767068. El anterior daba 3.65:1 sobre blanco, por
       debajo del mínimo de 4.5, y es el gris de TODO el texto secundario:
       categorías de producto, títulos de filtro, notas del checkout. Ahora
       4.65:1 y sigue leyéndose como secundario, que es su trabajo. */
    --tinta-tenue: #767068;

    /* El acento de marca PARA LETRA PEQUEÑA. Vive aquí y no en web.css
       porque la tienda no carga aquella hoja y tiene el mismo problema. */
    --marca-texto: color-mix(in srgb, var(--marca-acento) 88%, #000);

    /* --- 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;
    /* Tinta para cuando --peligro se usa como FONDO (la insignia "Agotado").
       No puede ser blanco siempre: en modo oscuro --peligro es un rojo CLARO,
       pensado para texto sobre fondo oscuro, y el blanco encima se quedaba en
       2.77:1. Aqui, sobre el rojo oscuro, el blanco da 6.47:1. */
    --peligro-texto: #FFFFFF;

    --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 --------------------------------------------------------- */
    /* LA ESCALA SUBIÓ EN SEP 2026, y no por gusto: seis píxeles en un botón
       y diez en una tarjeta era el redondeo de un formulario de intranet de
       hace diez años. Con esta escala el sistema entero —panel, tienda y web—
       se lee como software de ahora.

       Se cambia la VARIABLE y hereda todo: tarjetas, diálogos, botones,
       campos, tablas, avisos. No hay que ir a buscar las cien reglas que
       usan var(--radio). */
    --radio-xs: 6px;
    --radio-sm: 10px;
    --radio: 16px;
    --radio-lg: 22px;
    --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;
        /* De 83807C a 95918C: el anterior daba 4.21:1 sobre la superficie
           oscura. Ahora 4.85:1. */
        --tinta-tenue: #95918C;
        --marca-texto: color-mix(in srgb, var(--marca-acento) 80%, #fff);

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

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

        --peligro: #F87171;
        --peligro-fondo: #2B1616;
        --peligro-borde: #7F2C2C;
        /* Rojo claro de fondo: la tinta encima tiene que ser OSCURA (6.32:1). */
        --peligro-texto: #1C1917;

        --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: #95918C;
    --marca-texto: color-mix(in srgb, var(--marca-acento) 80%, #fff);

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

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

    --peligro: #F87171;
    --peligro-fondo: #2B1616;
    --peligro-borde: #7F2C2C;
    /* Rojo claro de fondo: la tinta encima tiene que ser OSCURA (6.32:1). */
    --peligro-texto: #1C1917;

    --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%;

    /* RED DE SEGURIDAD MÓVIL: nada puede empujar el ancho del documento y sacar
       barra horizontal. Se usa `clip` y no `hidden` a propósito: `hidden` crea
       un contenedor de desplazamiento que ANULA los `position: sticky` (la
       cabecera de la tienda, el riel del taller); `clip` recorta el desborde
       sin romper el pegado. */
    overflow-x: clip;
}

body {
    margin: 0;
    max-width: 100%;
    overflow-x: clip;
    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;
}

/* Ningún medio se pasa del ancho de su columna en móvil. */
img,
video,
svg,
canvas {
    max-width: 100%;
}

/* =========================================================================
   LOGO SEGÚN EL TEMA (claro / oscuro)
   Se pintan los dos logos y se muestra el que corresponde al tema activo. El
   tema lo marca `data-tema` en <html> (elección del usuario) o, si no eligió,
   la preferencia del sistema. Si no hay logo de modo oscuro, el PHP repite el
   claro en ambos, así siempre se ve algo.
   ========================================================================= */
.logo-modo-oscuro {
    display: none;
}

.logo-modo-claro {
    display: block;
}

@media (prefers-color-scheme: dark) {

    :root:not([data-tema="claro"]) .logo-modo-claro {
        display: none;
    }

    :root:not([data-tema="claro"]) .logo-modo-oscuro {
        display: block;
    }
}

:root[data-tema="oscuro"] .logo-modo-claro {
    display: none;
}

:root[data-tema="oscuro"] .logo-modo-oscuro {
    display: block;
}

:root[data-tema="claro"] .logo-modo-claro {
    display: block;
}

:root[data-tema="claro"] .logo-modo-oscuro {
    display: none;
}

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;
}

/* Apagado POR FALTA DE SERVIDOR, que no es lo mismo que apagado por una regla
   de la pantalla. Se distingue a propósito: en gris y más atenuado, para que
   se lea "esto no es que no puedas, es que no hay conexión". El motivo va en
   el title, al pasar el ratón.

   Vive aquí y no en pos.css porque lo usan los módulos que se abren dentro del
   marco del POS —el taller apaga así sus escrituras sin red— y esas pantallas
   no cargan la hoja del punto de venta. */
.btn.es-sin-red {
    opacity: .38;
    cursor: not-allowed;
    filter: grayscale(1);
}

/* --- 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;
    gap: 7px;
    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);
}

/* La × de una ficha. Sin borde ni fondo: es parte de la ficha, no un botón
   aparte. Área de 24 px para el dedo aunque el glifo sea chico. */
.ficha-talla__quitar {
    margin: 0 -6px 0 6px;
    width: 24px;
    height: 24px;
    border: 0;
    border-radius: var(--radio-completo);
    background: transparent;
    color: var(--tinta-tenue);
    font: inherit;
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
}

.ficha-talla__quitar:hover {
    background: var(--superficie-hundida);
    color: var(--peligro);
}

.ficha-talla--suelta {
    border-style: dashed;
}


/* =========================================================================
   LA MUESTRA DE COLOR

   El circulito con el tono de la variante. Sale donde se elige un color: el
   armador del producto, el selector de tallas de la caja y la ficha de la
   tienda en línea.

   POR QUÉ LLEVA DOS BORDES. Uno por fuera, oscuro y translúcido, para que un
   blanco no desaparezca sobre el fondo blanco del panel; otro por dentro,
   claro, para que un negro no se funda con el fondo oscuro del POS. Con un
   solo borde siempre hay un extremo de la paleta que se pierde, y justo el
   blanco y el negro son los dos colores que más se venden.
   ========================================================================= */
.muestra-color {
    display: inline-block;
    flex: none;
    width: 16px;
    height: 16px;
    border-radius: var(--radio-completo);
    background: var(--tono, #CCCCCC);
    border: 1px solid rgba(0, 0, 0, .28);
    box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .30);
    vertical-align: -3px;
}

/* En el armador del producto el círculo es EDITABLE: tocarlo abre el selector
   de color del sistema para corregir el tono que dedujo el diccionario. El
   input de verdad va encima, transparente y del tamaño del círculo, que es la
   única forma de que el círculo entero sea el botón sin escribir un selector
   de color a mano. */
.muestra-color--editable {
    position: relative;
    overflow: hidden;
    cursor: pointer;
}

.muestra-color--editable input[type="color"] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    padding: 0;
    border: 0;
    opacity: 0;
    cursor: pointer;
}

/* Una combinación ("Negro / Rojo") se parte en diagonal: es la forma más
   corta de decir que la pieza trae los dos y no una mezcla de los dos. */
.muestra-color--doble {
    background: linear-gradient(135deg, var(--tono) 0 50%, var(--tono2) 50% 100%);
}

/* Cuando el círculo va PEGADO a un texto sin que un `gap` los separe —la
   tabla de variantes del producto, el buscador de refacciones del taller—,
   el hueco lo pone él. En los sitios que ya son flex con gap (las fichas del
   armador, los chips de la caja, los botones de la tienda) no se toca, o el
   hueco saldría doble. */
.tabla__principal > .muestra-color,
.tal-resultado .muestra-color {
    margin-right: 7px;
}

.muestra-color--grande {
    width: 22px;
    height: 22px;
    vertical-align: -5px;
}

/* Para el selector táctil de la caja, que se opera de pie y a un brazo de
   distancia. */
.muestra-color--xl {
    width: 30px;
    height: 30px;
    border-width: 1.5px;
}


/* =========================================================================
   EL ARMADOR DE TALLAS Y COLORES (formulario de producto)

   Sustituye al diálogo de "corrida" y a la tabla vacía con dos botones. Vive
   dentro de la tarjeta: pastillas para decir en qué se distingue el producto,
   juegos listos de un clic, una caja de fichas para escribir los valores y la
   vista previa de lo que se creará. Sin palabras de base de datos.
   ========================================================================= */
.armador {
    display: grid;
    gap: 16px;
}

.armador__dimension {
    display: grid;
    gap: 10px;
    padding: 16px;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--superficie-hundida);
}

.armador__paso {
    font-size: 13px;
    font-weight: 600;
    color: var(--tinta-suave);
}

.armador__paso--con-boton {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

/* Pastillas: una fila que se envuelve. La elegida se pinta con el color de
   marca; el resto queda en superficie con borde, para que se lea como
   "opciones" y no como etiquetas. */
.pastillas {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.pastilla {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 34px;
    padding: 0 14px;
    border-radius: var(--radio-completo);
    border: 1px solid var(--borde-fuerte);
    background: var(--superficie);
    color: var(--tinta);
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease, color .15s ease;
}

.pastilla:hover {
    border-color: var(--marca-acento);
}

.pastilla[aria-pressed="true"] {
    border-color: var(--marca-acento);
    background: var(--marca-acento);
    color: var(--marca-acento-encima);
}

/* Los juegos listos: más suaves que los tipos (borde punteado, sin negrita)
   porque son atajos, no una decisión. El ejemplo va en gris al lado. */
.pastilla--suave {
    border-style: dashed;
    font-weight: 500;
}

.pastilla__ejemplo {
    color: var(--tinta-tenue);
    font-weight: 400;
}

/* La caja de fichas: parece una entrada de texto (lo es) y las fichas van
   dentro, antes del cursor. */
.fichas-entrada {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    min-height: 46px;
    padding: 7px 10px;
    border: 1px solid var(--borde-fuerte);
    border-radius: var(--radio-sm);
    background: var(--superficie);
    cursor: text;
    transition: border-color .15s ease, box-shadow .15s ease;
}

.fichas-entrada:focus-within {
    border-color: var(--marca-acento);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--marca-acento) 22%, transparent);
}

.fichas-entrada input {
    flex: 1 1 160px;
    min-width: 0;
    height: 28px;
    border: 0;
    outline: 0;
    background: transparent;
    font: inherit;
    font-size: 14px;
    color: var(--tinta);
}

.fichas-entrada input::placeholder {
    color: var(--tinta-tenue);
}

/* La vista previa de lo que se creará. */
.armador__vista {
    padding: 14px 16px;
    border: 1px dashed var(--borde-fuerte);
    border-radius: var(--radio);
    font-size: 14px;
    color: var(--tinta-suave);
}

.armador__vista strong {
    color: var(--tinta);
}

.armador__vista-fichas {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 10px;
}


/* =========================================================================
   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;
    }
}


/* =========================================================================
   ARRASTRAR Y SOLTAR ARCHIVOS

   Un recuadro que recibe archivos tiene que DECIR que los recibe. Sin este
   aviso visual, quien arrastra no sabe si va a soltar en el sitio correcto y
   acaba soltando fuera —lo que en un navegador significa abrir el archivo y
   perder el formulario a medio llenar.
   ========================================================================= */

.zona-soltar--encima {
    border-color: var(--marca-acento) !important;
    background: color-mix(in srgb, var(--marca-acento) 8%, transparent) !important;
    outline: 2px dashed var(--marca-acento);
    outline-offset: -4px;
}


/* =========================================================================
   EL MOMENTO DE COBRO

   La pantalla grande con la palomita y el cambio en enorme. Reemplaza al
   aviso de esquina, que se perdía justo cuando quien cobra necesita ver de
   un vistazo cuánto devolver.

   Vive aquí y no en pos.css porque lo usan DOS pantallas: el punto de venta
   y el cobro de una orden de taller. Es el mismo gesto y el mismo dinero,
   así que tiene que verse igual en las dos.
   ========================================================================= */

.pos-exito {
    position: fixed;
    inset: 0;
    z-index: 90;
    display: grid;
    place-items: center;
    padding: 24px;
    background: color-mix(in srgb, var(--lienzo) 82%, transparent);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
}

.pos-exito[hidden] {
    display: none;
}

.pos-exito__tarjeta {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 6px;
    padding: 40px 56px;
    border-radius: 24px;
    background: var(--superficie);
    border: 1px solid var(--borde);
    box-shadow: var(--sombra-flotante);
    animation: pos-exito-entra 420ms var(--salida) both;
}

.pos-exito__check {
    width: 76px;
    height: 76px;
    margin-bottom: 8px;
    color: var(--exito);
}

.pos-exito__check circle {
    fill: none;
    stroke: currentColor;
    stroke-width: 3;
    stroke-dasharray: 151;
    stroke-dashoffset: 151;
    animation: pos-check-circulo 480ms var(--salida) forwards;
}

.pos-exito__check path {
    fill: none;
    stroke: currentColor;
    stroke-width: 4;
    stroke-linecap: round;
    stroke-linejoin: round;
    stroke-dasharray: 42;
    stroke-dashoffset: 42;
    animation: pos-check-palomita 340ms 300ms var(--salida) forwards;
}

.pos-exito__etiqueta {
    font-size: 15px;
    font-weight: 600;
    color: var(--tinta-suave);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.pos-exito__monto {
    font-size: 64px;
    font-weight: 720;
    letter-spacing: -0.045em;
    line-height: 1;
    color: var(--tinta);
    font-variant-numeric: tabular-nums;
}

.pos-exito__folio {
    margin-top: 10px;
    font-size: 13px;
    font-weight: 600;
    color: var(--tinta-tenue);
    font-variant-numeric: tabular-nums;
}

@keyframes pos-exito-entra {
    from { opacity: 0; transform: scale(0.92); }
    to   { opacity: 1; transform: scale(1); }
}

@keyframes pos-check-circulo {
    to { stroke-dashoffset: 0; }
}

@keyframes pos-check-palomita {
    to { stroke-dashoffset: 0; }
}

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

    .pos-exito__tarjeta {
        animation: none;
    }

    .pos-exito__check circle,
    .pos-exito__check path {
        animation: none;
        stroke-dashoffset: 0;
    }
}


/* =========================================================================
   [hidden] DE VERDAD

   Este archivo lleva ya media docena de reglas ".loquesea[hidden]" puestas
   una por una, cada vez que alguien descubrió que su elemento seguía a la
   vista: el botón, el velo, el panel del desplegable, el momento de cobro…
   Siempre el mismo motivo — `display: flex/grid/block` en la clase le gana al
   `display: none` que el navegador le da a [hidden], porque una clase pesa
   más que un selector de atributo en la cascada.
   Y siempre el mismo síntoma: `elemento.hidden = true` en el JavaScript y
   nada que se mueva en pantalla.
   Con esta regla deja de pasar, y las de arriba se quedan por si acaso.
   ========================================================================= */

[hidden] {
    display: none !important;
}


/* =========================================================================
   LA CAJA REDONDEA MÁS

   El punto de venta, el taller y el acceso del POS marcan su <body> con
   "es-caja" y con eso suben la ESCALA de radios entera. No se redondea
   elemento por elemento: se cambia la variable y hereda todo —tarjetas,
   diálogos, botones, campos, chips— sin ir a buscar una por una las
   cincuenta reglas que usan var(--radio).

   Desde sep 2026 la escala BASE también subió (arriba, en :root), así que
   esto ya no es "redondeado contra cuadrado" sino un escalón más: la caja se
   toca con el dedo, sus botones son más grandes y una esquina proporcional a
   un botón de 48 px es más abierta que la de uno de 34.
   ========================================================================= */

body.es-caja {
    --radio-xs: 10px;
    --radio-sm: 14px;
    --radio: 22px;
    --radio-lg: 28px;
}

/* Los campos y los botones nacieron con su radio escrito a mano en app.css,
   así que la escala no los alcanza. Se redondean aquí. */
body.es-caja .entrada,
body.es-caja .selector,
body.es-caja .area,
body.es-caja .btn,
body.es-caja .entrada-grupo {
    border-radius: var(--radio);
}

body.es-caja .btn--icono {
    border-radius: var(--radio-completo);
}

/* El diálogo, con esquinas de aplicación y no de ventana de sistema. */
body.es-caja .dialogo {
    border-radius: var(--radio-lg);
}

/* Una sombra dura contra una esquina redonda se ve pegada; difusa se ve
   apoyada. Al subir el radio hay que subir también la difusión. */
body.es-caja .dialogo,
body.es-caja .acceso__tarjeta {
    box-shadow: 0 24px 60px -24px rgba(0, 0, 0, .55), 0 2px 10px -4px rgba(0, 0, 0, .3);
}


/* Los vacíos de las ventanas del POS (corte, devolución, taller). Un panel
   de media pantalla en negro con una línea gris al centro no dice "todavía no
   hay nada que enseñar": dice que algo no cargó. */
.ventana-vacio {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 46vh;
    padding: 32px 24px;
    text-align: center;
    color: var(--tinta-tenue);
}

.ventana-vacio svg {
    width: 44px;
    height: 44px;
    opacity: .28;
    margin-bottom: 12px;
}

.ventana-vacio__titulo {
    font-size: 15px;
    font-weight: 640;
    color: var(--tinta-suave);
    margin-bottom: 6px;
}

.ventana-vacio p {
    max-width: 40ch;
    margin: 0;
    line-height: 1.5;
}


/* =========================================================================
   LA CARGA DEL TALLER (Agenda del taller)

   Un número grande y una frase. Es la cifra que decide si la agenda en línea
   sigue abierta, así que se lee de lejos y no como un renglón más de tabla.
   ========================================================================= */
.carga-taller {
    display: flex;
    align-items: center;
    gap: 18px;
    flex-wrap: wrap;
}

.carga-taller__cifra {
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-family: var(--fuente-display);
    font-size: 15px;
}

.carga-taller__cifra strong {
    font-size: 40px;
    line-height: 1;
    letter-spacing: -0.03em;
    color: var(--tinta);
}

.carga-taller__texto {
    flex: 1 1 260px;
    min-width: 0;
    font-size: 14px;
    color: var(--tinta-suave);
}

.carga-taller__texto strong {
    color: var(--tinta);
}
