/* Lo minimo: MudBlazor pone el resto. Mismo fichero que
   frontend-blazor/Tentalo.POS.ServerStatus/wwwroot/css/app.css mas la espera del guardia.

   LAS CLASES `.arranque` Y `.loading-*` LAS COMPARTEN DOS PANTALLAS
   =================================================================
   wwwroot/index.html (la pantalla de arranque del WASM, que pinta el navegador antes de que haya
   aplicacion) y Components/Guardia.razor (la espera de GET /api/auth/me, que ya pinta Blazor).
   Estan aqui y no en el <head> de index.html precisamente para eso: la parte 1 de
   docs/central/esperas.md pedia que el salto de una a otra no se notara, y la unica forma de que
   no se note es que sean el MISMO lienzo. Tocar un color o un tamano de aqui cambia las dos. */
html, body {
    margin: 0;
    padding: 0;
    /* La familia sale de plano.css (--plano-familia): Archivo variable, que es
       la que se autoaloja en wwwroot\fonts. La pila del sistema sigue detras,
       dentro de la propia ficha, para el rato de `font-display: swap`. */
    font-family: var(--plano-familia);
}

/*
  SIN «DESLIZAR PARA RECARGAR» EN EL TELEFONO (2026-10-06,
  docs/tpv/sin-recarga-al-deslizar-2026-10-06.md). Esta pagina SI se desplaza entera, y se sigue
  desplazando: lo unico que se quita es que un dedo que baja con la pagina arriba del todo recargue
  la aplicacion -y con ella el formulario a medias- en Chrome de Android y Safari de iOS. Va en
  <html> y solo en el eje vertical: la ventana toma el valor del elemento raiz, no del <body>, y el
  rebote lateral no recarga nada. Recargar a proposito sigue en el menu del navegador.
*/
html {
    overscroll-behavior-y: none;
}

/* Pantalla de arranque, mientras baja el runtime de WebAssembly. */
.arranque {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100vh;
    color: var(--plano-tinta-2);
    background: var(--plano-papel);
    text-align: center;
}

.arranque img {
    width: 240px;
    max-width: 60vw;
    margin-bottom: 1.5rem;
    /* En oscuro, el lila de hoja-limpia.css (sobre --plano-papel 7,93:1; antes 2,01:1). */
    filter: var(--plano-logo-filtro, none);
}

.loading-progress {
    position: relative;
    display: block;
    width: 5rem;
    height: 5rem;
    margin: 1rem auto;
}

.loading-progress circle {
    fill: none;
    stroke: #eae6f0;
    stroke-width: 0.5rem;
    transform-origin: 50% 50%;
    transform: rotate(-90deg);
}

.loading-progress circle:last-child {
    stroke: #672990;
    stroke-dasharray: calc(3.141592653589793 * var(--blazor-load-percentage, 0%) * 0.8) 500%;
    transition: stroke-dasharray 0.05s ease-in-out;
}

.loading-progress-text {
    font-weight: 600;
    color: #672990;
}

.loading-progress-text:after {
    content: var(--blazor-load-percentage-text, "Cargando");
}

/* El anillo del guardia: el mismo dibujo, pero girando en vez de contando. Con la aplicacion ya
   arrancada no hay porcentaje que ensenar -el WASM esta bajado- y lo que hay que decir es «sigue
   pasando algo». */
.loading-progress-indeterminado circle:last-child {
    stroke-dasharray: 70% 500%;
    transition: none;
    animation: arranque-giro 1.1s linear infinite;
}

@keyframes arranque-giro {
    from { transform: rotate(-90deg); }
    to { transform: rotate(270deg); }
}

.arranque-texto {
    margin: 0;
}

/* Regla 7 de docs/central/esperas.md: nada late para siempre, y quien haya pedido menos
   movimiento no ve ninguno (WCAG 2.3.3). El anillo se queda quieto y sigue diciendo lo mismo. */
@media (prefers-reduced-motion: reduce) {
    .loading-progress-indeterminado circle:last-child {
        animation: none;
    }
}

/* --- La barra de actividad ---------------------------------------------- */
/* Regla 1 de docs/central/esperas.md: toda peticion en vuelo se ve. DOS pixeles pegados al borde
   de arriba del contenido, encendida mientras haya cualquier llamada al bus o al API en curso.

   DONDE SE VE, DESDE LA TANDA 2 DE LA AUDITORIA DE UX (2026-09-15)
   ================================================================
   Era `position: fixed` con `left: 0; right: 0`: una raya que cruzaba la VENTANA entera por
   debajo de la barra superior, encima del menu lateral incluido. Ahora la pinta el
   `MudMainContent` de los dos marcos y es `sticky`, asi que mide lo que mide el CONTENIDO y no la
   pantalla: con el menu fijo en escritorio queda claro que lo que carga es la pagina y no la
   navegacion, que es lo que confundia. Al scrollear se queda pegada arriba en vez de irse.

   Los 48 px del `top` son la altura de `MudAppBar Dense="true"`, que es la que usan los DOS
   marcos (AdminLayout y MainLayout): es donde la raya se para al scrollear, justo debajo de la
   barra superior. No se usa `var(--mud-appbar-height)` porque MudBlazor deja esa variable en los
   64 px del tema aunque la barra sea densa, y la raya quedaria flotando.

   `height: 0` en el envoltorio para que encender la raya NO empuje el contenido dos pixeles: la
   raya se pinta encima del hueco que MudMainContent ya reserva bajo la barra superior. Y
   `pointer-events: none` porque no debe robar ni un clic.

   El cartel flotante que colgaba de aqui (`.admin-actividad-aviso`) SE HA IDO: la espera larga la
   explica la tarjeta que espera (`.admin-espera-larga`, abajo). El porque, medido, en §6.1 de
   docs/central/diagnostico-lentitud-2026-09-15.md. */
.admin-actividad {
    position: sticky;
    top: 48px;
    z-index: 1305;
    height: 0;
    overflow: visible;
    pointer-events: none;
}

.admin-actividad-barra {
    height: 2px;
}

/* La linea de la regla 4, y desde la tanda 2 la UNICA: debajo del esqueleto que esta esperando
   (PanelWidget), con el titulo de ese panel y los segundos que lleva. */
.admin-espera-larga {
    color: var(--tentalo-tinta-suave);
    font-size: 0.78rem;
    margin-top: 0.5rem;
}

/* PASADOS 20 s EL ESQUELETO DEJA DE ONDEAR.
   Un esqueleto que sigue animandose medio minuto se lee como una pantalla rota (§6.2 del
   diagnostico de lentitud). El texto sigue contando -eso es lo que dice que la cosa sigue viva-,
   pero la animacion se para. Alcanza tanto al esqueleto propio de la pantalla como a las tres
   barritas por omision de PanelWidget. */
.admin-esqueleto--quieto .mud-skeleton::after,
.admin-esqueleto--quieto .mud-skeleton {
    animation: none;
}

/* Mientras se descarga el ensamblado de un modulo diferido (App.razor, plantilla Navigating).
   Aparece a los 400 ms: en red local la descarga dura decimas y un cartel que aparece y
   desaparece molesta mas que la propia espera. */
.admin-descarga {
    color: #5f5f5f;
    font-size: 0.85rem;
    margin-top: 0.75rem;
}

#blazor-error-ui {
    color: #2b2b2b;
    background: #ffe9c4;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1500;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

/* ==========================================================================
   PANTALLAS PUBLICAS DE PANTALLA PARTIDA  (docs\central\diseno-web.md)
   --------------------------------------------------------------------------
   El patron de la pagina de entrada: panel de marca de tinta a la izquierda,
   con el plano del local en negativo, y formulario a la derecha. Lo montan
   Layout\AccesoLayout.razor, Components\PanelMarca.razor y Pages\Acceso.razor.

   Va aqui, en el CSS global, y no en un fichero .razor.css con aislamiento:
   el aislamiento obliga a enlazar Tentalo.Central.Web.styles.css desde
   index.html, y ese enlace lo escribe el mecanismo de marcadores del SDK que
   en el modelo hosted esta apagado a proposito (ver el .csproj). Los nombres
   llevan prefijo (acceso-, panel-marca-) para que hagan de ambito por si
   solos.

   Cortes responsivos, y son los tres que se prueban con el navegador:
     >= 1024 px   dos columnas 50/50
     768-1023 px  dos columnas 40/60
     <  768 px    una columna: el panel pasa a cabecera compacta arriba
   ========================================================================== */

:root {
    /* ======================================================================
       LOS NOMBRES SE QUEDAN; EL VALOR SALE DEL PLANO (2026-09-17)
       ======================================================================
       Hasta el rediseno «El plano de sala» estos nombres llevaban dentro la
       paleta morada de marca, y los usan 319 reglas de esta hoja. Ni una de
       esas 319 se toca: lo que cambia es DE DONDE sale el valor, que ahora es
       css\plano.css -la unica verdad del color, cargado antes que esta hoja-.

       Se quedan como ALIAS y no se borran porque borrarlos seria reescribir
       trescientas reglas para no ganar nada; y estan AQUI, donde vivian, y no
       en plano.css, porque esta hoja se carga DESPUES y ganaria de todos modos.
       Dos verdades es lo que habia que evitar, y asi solo hay una.

       En la tanda 2 se van tres: `--tentalo-oscuro`, `--tentalo-oscuro-medio` y
       `--tentalo-marca-hondo` eran las paradas del degradado del panel de
       marca, y el panel pasa a ser tinta plana. Ninguna otra regla los leia.

       El reparto (ver §2 de docs\central\rediseno-plano-de-sala-2026-09-17.md):
       la marca es el MORADO del logotipo (accion, seleccion, foco) y las tintas
       oscuras son LA TINTA BERENJENA del plano. */
    /* LA MARCA ES EL MORADO DEL LOGOTIPO otra vez (decisión del usuario, 2026-09-17
       por la tarde). Estas 319 reglas no se tocan: sólo cambia de dónde sale el valor. */
    --tentalo-marca: var(--plano-morado);
    /* Acento claro: la palabra resaltada del titular y los checks del acceso.
       Sobre la berenjena honda del panel de marca, la mostaza da 9,35:1. */
    --tentalo-acento: var(--plano-mostaza);
    --tentalo-tinta: var(--plano-tinta);
    /* LOS DOS QUE VAN COPIADOS Y NO CON var(), y hay un motivo concreto:
       AuditoriaUxTanda1Tests los LEE DE ESTA HOJA con una expresion regular que
       espera un valor literal (mide el contraste de la tinta suave y comprueba
       que el anillo de foco sigue siendo de 2 px). Un `var()` le daria la
       cadena «var(--plano-tinta-2)» y no un color que medir.

       Copiar un valor es arriesgarse a que las dos copias se separen, asi que
       no se deja a la buena voluntad: MarcoDelPlanoTests comprueba que estos
       dos son EXACTAMENTE lo que declara plano.css, y falla si alguien cambia
       uno de los dos lados. El valor sigue decidiendose alli. */
    --tentalo-tinta-suave: #5b4a73;
    --tentalo-borde: var(--plano-linea);
    /* Alto minimo de campos y botones: el pulgar en un movil (WCAG 2.5.5). */
    --tentalo-toque: var(--plano-toque-movil);
    /* El anillo de foco del teclado. Ver el bloque de abajo. */
    --tentalo-foco: 2px;
    /* EL ALTO DE UNA FILA DE `.admin-tabla`, MEDIDO en el banco de esqueletos
       (central\Tentalo.Central.Web.Tests\BancoDeEsqueletos.cs) a 1.000 px de
       contenido, no calculado a mano: quien manda en la altura es la pieza mas
       alta de la fila, y son dos distintas segun la entidad.

         - SIN seleccion multiple manda el boton de icono de la celda de
           acciones, y la fila mide 60 px.
         - CON seleccion multiple manda la CASILLA, que es un boton con su area
           de toque de 48 px, y la fila sube a 76.

       Con ocho filas la diferencia son 128 px, o sea, el salto entero. Estan
       aqui, en variables, para que el esqueleto de tabla y la tabla no se
       puedan separar. */
    --tentalo-fila-tabla: 60px;
    --tentalo-fila-tabla-seleccion: 76px;
}

/* ==========================================================================
   EL FOCO DEL TECLADO, EN TODA LA WEB
   (T1 de docs\central\auditoria-ux-2026-09-15.md, WCAG 2.4.7)
   ==========================================================================
   MudBlazor 9 APAGA el anillo del navegador y no pone nada equivalente: en
   MudBlazor.min.css hay «outline:none» / «outline:0» en los enlaces, en
   `button`, en `.mud-button-root`, en `.mud-chip`, en `.mud-table-row` y en
   media docena de piezas mas. Lo unico que da a cambio es el MISMO tinte de
   fondo que el `:hover`, que no distingue «tengo el foco» de «tengo el raton
   encima». Sin esto, ninguna de las 145 pantallas dice donde esta el
   tabulador.

   Es una regla sola y transversal a proposito: reponerla pieza a pieza es lo
   que llevaba hecho `app.css` -cuatro sitios de 5.400 renglones- y por eso
   faltaba en todo lo demas.

   POR QUE SIN `:where()` Y SIN `!important`. `:where(a, button, …)` no vale:
   pesa 0,1,0 y pierde contra el `a:focus-visible{outline:none}` de MudBlazor,
   que pesa 0,1,1. Escritos uno a uno, los selectores pesan lo mismo que los
   suyos y `app.css` se carga DESPUES (wwwroot\index.html), asi que ganan sin
   necesidad de `!important`.

   `:focus-visible` y no `:focus`: el anillo aparece con el teclado y no al
   pulsar con el raton, que es justo lo que hace que se pueda poner en TODO
   sin que la pantalla se llene de recuadros.

   Desde el rediseno «El plano de sala» (2026-09-17) el anillo es la SALVIA
   sobre el papel del plano: 5,19:1 sobre #f2f5f3 y 5,49:1 sobre el blanco,
   muy por encima del 3:1 que WCAG pide a un indicador de foco. Desde el
   rediseno D1 (2026-10-04) la central SI tiene variante oscura: la pone
   hoja-limpia.css bajo `prefers-color-scheme` (y App.razor, la PaletteDark y
   `data-tema`), y alli --plano-salvia pasa a la salvia clara, asi que el
   anillo sigue siendo esta misma regla con la ficha de cada modo. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible,
[role="button"]:focus-visible,
.mud-button-root:focus-visible,
.mud-icon-button:focus-visible,
.mud-nav-link:focus-visible,
.mud-chip:focus-visible,
.mud-table-row:focus-visible,
.mud-table-sort-label:focus-visible,
.mud-list-item:focus-visible,
.mud-menu-item:focus-visible,
.mud-expand-panel-header:focus-visible,
.mud-tab:focus-visible,
.mud-checkbox .mud-button-root:focus-visible,
.mud-radio .mud-button-root:focus-visible,
.mud-switch .mud-button-root:focus-visible {
    outline: var(--tentalo-foco) solid var(--tentalo-marca);
    outline-offset: 2px;
}

/* LA EXCEPCION: los campos de MudBlazor. La variante Outlined -la unica que usa
   el administrador- ya pone su propio canto morado de 2 px al recibir el foco,
   asi que el anillo iria DOBLE y ademas por dentro, pegado al texto y cruzando
   la etiqueta flotante. Se le quita al `input` que vive dentro de un campo de
   MudBlazor, y solo a ese: un `<input>` nativo suelto -el de un `InputFile`,
   por ejemplo- sigue cogiendo el anillo de la regla de arriba, que es donde de
   verdad hacia falta. */
.mud-input-control:focus-visible,
.mud-input-control input:focus-visible,
.mud-input-control textarea:focus-visible,
.mud-input-control select:focus-visible {
    outline: none;
}

/* --- El marco: AccesoLayout, sin barra superior ------------------------- */

.marco-publico {
    min-height: 100vh;
    /* dvh donde exista: en un movil la barra del navegador se come los vh. */
    min-height: 100dvh;
}

/* --- La rejilla de la pantalla partida ---------------------------------- */

.acceso {
    display: grid;
    grid-template-columns: 1fr 1fr;
    min-height: 100vh;
    min-height: 100dvh;
    background: var(--plano-papel);
    /* Ni una barra horizontal en ningun ancho: el plano se recorta. */
    overflow-x: hidden;
}

/* --- Panel de marca ----------------------------------------------------- */

/* EL PLANO EN NEGATIVO (tanda 2). Antes era un degradado de cuatro paradas con
   un brillo radial encima; ahora es BERENJENA HONDA PLANA. El degradado no
   aportaba nada que el dibujo no diga mejor, movia el color del texto de arriba
   abajo del panel -lo que obliga a medir el contraste en dos sitios- y era la
   mitad del cliche que este redisenio rechaza (la otra mitad, la constelacion).

   Plano quiere decir plano: UN color, un punto mas hondo que la tinta del resto
   del sistema, para que el blanco de encima de aqui de 17,68:1 en cualquier
   punto del panel y no haga falta comprobarlo dos veces. */
.panel-marca {
    position: relative;
    display: flex;
    overflow: hidden;
    color: #fff;
    background: var(--plano-berenjena-honda);
}

.panel-marca-contenido {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    width: 100%;
    padding: clamp(2rem, 3.4vw, 3.75rem);
    gap: 2rem;
}

.panel-marca-cabecera {
    display: flex;
    align-items: center;
    gap: 0.9rem;
}

.panel-marca-logo {
    /* El logo original es 360x112; aqui va pequeno y con la altura mandando. */
    height: 34px;
    width: auto;
    /* El logo es trazo MORADO sobre transparente (docs\branding.md): sobre el
       panel oscuro no se ve. brightness(0) lo pasa a negro conservando el
       alfa y invert(1) lo deja en blanco, asi que sale la misma silueta en
       blanco sin necesidad de un segundo fichero de marca. */
    filter: brightness(0) invert(1);
}

.panel-marca-identidad {
    display: flex;
    flex-direction: column;
    line-height: 1.25;
}

.panel-marca-nombre {
    font-size: 1.05rem;
    font-weight: 600;
    letter-spacing: 0.01em;
}

.panel-marca-subtitulo {
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.68);
}

/* El cuerpo se centra verticalmente y empuja el pie abajo. */
.panel-marca-cuerpo {
    display: flex;
    flex-direction: column;
    gap: 1.75rem;
    margin-block: auto;
    max-width: 30rem;
}

.panel-marca-titular {
    margin: 0;
    font-size: clamp(1.85rem, 2.4vw + 0.55rem, 2.85rem);
    font-weight: 700;
    line-height: 1.14;
    letter-spacing: -0.015em;
}

.panel-marca-titular-linea,
.panel-marca-titular-resalte {
    display: block;
}

.panel-marca-titular-resalte {
    color: var(--tentalo-acento);
}

.panel-marca-parrafo {
    margin: 0;
    max-width: 26rem;
    font-size: 0.98rem;
    line-height: 1.6;
    color: rgba(255, 255, 255, 0.78);
}

.panel-marca-puntos {
    display: flex;
    flex-direction: column;
    gap: 1.15rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.panel-marca-punto {
    display: flex;
    align-items: flex-start;
    gap: 0.8rem;
}

.panel-marca-check {
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    margin-top: 0.15rem;
}

.panel-marca-check circle {
    fill: rgba(255, 255, 255, 0.12);
    stroke: var(--tentalo-acento);
    stroke-width: 1.4;
}

.panel-marca-check path {
    fill: none;
    stroke: var(--tentalo-acento);
    stroke-width: 2.2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.panel-marca-punto-texto {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.panel-marca-punto-titulo {
    font-size: 0.95rem;
    font-weight: 600;
}

.panel-marca-punto-detalle {
    font-size: 0.87rem;
    line-height: 1.45;
    color: rgba(255, 255, 255, 0.7);
}

/* Al 62 % y no al 50 %: sobre la tinta plana, el blanco a la mitad da 4,28:1 y
   esto es texto de 12 px, o sea que le tocan 4,5:1. Con 0,62 son 5,77:1. */
.panel-marca-pie {
    margin: 0;
    font-size: 0.75rem;
    color: rgba(255, 255, 255, 0.62);
}

/* --- El plano en negativo ------------------------------------------------ */

/* El local dibujado en linea clara sobre la tinta, ocupando el panel entero.

   `cover` y no `contain`: aqui el dibujo es TEXTURA y no ilustracion, asi que
   recortarse por los bordes es lo correcto -lo que tiene que llenarse es el
   panel- al reves que el plano de la columna del formulario, que se ve entero.
   El SVG esta dibujado en vertical y con la barra y las mesas lejos del borde
   justo para que el recorte no se lleve nada que importe.

   EL DIBUJO SE APARTA DEL TEXTO (tanda 3, retoque 2). En las capturas de la
   tanda 2 las lineas del plano cruzaban por detras del titular y de los tres
   argumentos: no rompia el contraste -la linea lila no cubre un glifo- pero
   restaba LEGIBILIDAD, que es otra cosa, porque el ojo separa el renglon de un
   trazo que lo atraviesa antes de leerlo. Bajar mas la opacidad habria borrado
   el dibujo entero para arreglar la mitad de arriba a la izquierda, asi que en
   vez de eso se ENMASCARA: un degradado a 100° deja el TERCIO SUPERIOR IZQUIERDO
   -la columna de texto, que va centrada verticalmente y mide 30 rem- limpio del
   todo, y el plano vive en el tercio derecho e inferior del panel, que es
   justamente donde no hay nada escrito.

   Al quitarle el texto de encima, el dibujo puede subir de 28 a 34 %: ahi donde
   se ve NO compite con nada, y el plano vuelve a leerse como un plano. Sigue
   dentro de la banda que pide el disenio (25-35 %). El blanco del texto da
   17,68:1 sobre la berenjena honda, y ahora en todo su recorrido, porque bajo la
   columna de texto la mascara deja el panel liso.

   `mask-image` con su copia `-webkit-`: Safari pide el prefijo para las
   mascaras de degradado. Donde no haya mascaras, el plano sale entero al 34 %,
   que es lo que habia antes con dos puntos mas: no se rompe nada.

   Decorativo: no captura un clic (`pointer-events`) y quien lo pinta le pone
   `aria-hidden`. */
.panel-marca-plano {
    position: absolute;
    inset: 0;
    background-image: url("../img/plano/plano-negativo.svg");
    background-repeat: no-repeat;
    background-position: center;
    background-size: cover;
    opacity: 0.34;
    pointer-events: none;
    -webkit-mask-image: linear-gradient(100deg,
        transparent 0%, transparent 34%,
        rgba(0, 0, 0, 0.35) 54%,
        rgba(0, 0, 0, 0.85) 78%,
        #000 100%);
    mask-image: linear-gradient(100deg,
        transparent 0%, transparent 34%,
        rgba(0, 0, 0, 0.35) 54%,
        rgba(0, 0, 0, 0.85) 78%,
        #000 100%);
}

/* --- Columna del formulario -------------------------------------------- */

/* EL PLANO DE FONDO (rediseno «El plano de sala»): el local dibujado en linea
   fina detras del formulario. Es lo primero que se ve del producto y dice de
   que va sin escribir una palabra.

   `background-attachment: local` y `contain` para que el plano se vea ENTERO a
   cualquier alto: recortado por la mitad parece un error de maquetacion y no un
   dibujo. Va anclado abajo a la derecha, que es donde no esta el formulario. */
.acceso-panel {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: clamp(1.75rem, 3.4vw, 4rem);
    background-color: var(--plano-papel);
    background-image: url("../img/plano/fondo-sala.svg");
    background-repeat: no-repeat;
    background-position: right -6rem bottom -4rem;
    background-size: 46rem auto;
}

/* EL FORMULARIO EN UNA ZONA, NO EN UNA TARJETA (§4). Una zona es papel con su
   esquina de muro y dos lados de linea gruesa; una tarjeta seria un rectangulo
   blanco con canto y sombra flotando sobre otro fondo, que es justo lo que este
   sistema no hace. */
.acceso-formulario {
    width: 100%;
    max-width: 25rem;
    position: relative;
    background: var(--plano-hoja);
    border-radius: var(--plano-esquina-muro);
    border-left: 2px solid var(--plano-muro);
    border-bottom: 2px solid var(--plano-muro);
    padding: clamp(1.5rem, 2.2vw, 2.25rem);
}

.acceso-bienvenido {
    margin: 0 0 0.4rem;
    font-size: 1.75rem;
    font-weight: 650;
    font-stretch: 96%;
    letter-spacing: -0.015em;
    color: var(--plano-tinta);
}

.acceso-subtitulo {
    margin: 0 0 2rem;
    font-size: 0.9375rem;
    line-height: 1.5;
    color: var(--plano-tinta-2);
}

.acceso-campo {
    margin-bottom: 1.15rem;
}

/* LOS CAMPOS DEL ACCESO SE VISTEN COMO LOS DEMAS (tanda 4). Aquí quedaban tres
   reglas de antes del rediseño —relleno casi blanco, radio de 12 px y un canto
   contorneado de `--tentalo-borde`— que le ganaban a la piel del plano por peso
   de selector: la primera pantalla de la aplicación enseñaba una variante de
   campo que no existe en ninguna otra. Ahora sólo se pide lo que esta pantalla
   necesita de verdad y que la piel no da —el ALTO DE TOQUE, porque aquí se
   escribe con una mano y a veces en un móvil—, y el relleno, el radio y el
   subrayado de foco los pone §7.2 de `plano.css` como en las otras 134.

   Se llega a las clases de MudBlazor desde fuera porque el CSS es global (ver la
   nota de arriba): con aislamiento haría falta ::deep. */
.acceso-campo .mud-input.mud-input-outlined,
.acceso-campo .mud-input.mud-input-filled {
    min-height: var(--tentalo-toque);
}

/* El botón principal del acceso: el alto de toque y nada más. La forma —píldora,
   morado relleno, y la trama legible cuando está deshabilitado, que es su estado
   por omisión— la pone §7.1 de `plano.css`. El radio de 12 px que había aquí era
   del mismo lote que el de los campos. */
.acceso-boton {
    min-height: var(--tentalo-toque);
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    text-transform: none;
}

.acceso-error {
    margin-top: 1rem;
}

/* El gris es el token y no un #8a8a8a suelto: medido, aquel daba 3,45:1 sobre
   blanco a 12,2 px y el minimo de la regla 1 es 4,5:1. --tentalo-tinta-suave
   (#5f5f5f) da 6,39:1. T4 de docs\central\auditoria-ux-2026-09-15.md. */
.acceso-nota {
    margin: 1.5rem 0 0;
    font-size: 0.76rem;
    line-height: 1.45;
    color: var(--tentalo-tinta-suave);
}

/* Solo se ve cuando el panel de marca es la cabecera compacta del movil. */
.acceso-pie-movil {
    display: none;
    margin: 2rem 0 0;
    font-size: 0.72rem;
    /* Era #9a9a9a: 2,81:1 sobre blanco, el peor texto de la web. Ver T4. */
    color: var(--tentalo-tinta-suave);
    text-align: center;
}

/* --- Corte 768-1023 px: dos columnas 40/60 ------------------------------ */

@media (min-width: 768px) and (max-width: 1023.98px) {
    .acceso {
        grid-template-columns: 40% 60%;
    }

    .panel-marca-contenido {
        gap: 1.5rem;
    }

    .panel-marca-cuerpo {
        gap: 1.35rem;
    }

    .panel-marca-parrafo {
        font-size: 0.92rem;
    }
}

/* --- Corte < 768 px: una columna y cabecera compacta -------------------- */

@media (max-width: 767.98px) {
    .acceso {
        grid-template-columns: 1fr;
        /* La cabecera se ajusta a su contenido; el formulario se queda el resto. */
        grid-template-rows: auto 1fr;
    }

    /* La cabecera compacta: logo, nombre y titular. Ni plano, ni subtitulo, ni
       parrafo, ni puntos, ni pie (el pie lo pone el formulario).

       El PLANO se va con los demas y no se encoge: en una franja de 100 px de
       alto, un `cover` de un dibujo vertical de 700x1000 ensenia una tira de
       dos mesas y media que no se lee como un plano de nada. Mejor tinta
       limpia, que es lo que hace la barra del administrador. */
    .panel-marca-plano,
    .panel-marca-subtitulo,
    .panel-marca-parrafo,
    .panel-marca-puntos,
    .panel-marca-pie {
        display: none;
    }

    .panel-marca-contenido {
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
        gap: 0.5rem 1rem;
        padding: 1rem 1rem 1.15rem;
    }

    .panel-marca-cabecera {
        flex: 0 0 auto;
        gap: 0.7rem;
    }

    .panel-marca-logo {
        height: 28px;
    }

    .panel-marca-nombre {
        font-size: 0.98rem;
    }

    /* El titular cabe al lado del logo cuando hay sitio y baja a su propia
       linea cuando no (en 375 px no cabe, y eso es lo correcto). */
    .panel-marca-cuerpo {
        flex: 1 1 14rem;
        margin-block: 0;
        max-width: none;
    }

    .panel-marca-titular {
        font-size: 1.02rem;
        font-weight: 600;
        line-height: 1.35;
        letter-spacing: 0;
    }

    .panel-marca-titular-linea,
    .panel-marca-titular-resalte {
        display: inline;
    }

    /* Los dos trozos del titular pasan a ir en linea, y entre ellos hace falta
       el espacio que el compilador de Razor se come del salto de linea del
       marcado. white-space: pre para que no lo colapse el navegador; sigue
       habiendo sitio para partir la linea ahi si no cabe. */
    .panel-marca-titular-resalte::before {
        content: " ";
        white-space: pre;
    }

    .acceso-panel {
        /* Margenes de 16 px a los lados, que es lo que pide el diseno. */
        padding: 2.25rem 16px 2rem;
        justify-content: flex-start;
    }

    .acceso-subtitulo {
        margin-bottom: 1.75rem;
    }

    .acceso-pie-movil {
        display: block;
    }
}

/* ==========================================================================
   BARRA DEL ADMINISTRADOR EN PANTALLAS ESTRECHAS
   --------------------------------------------------------------------------
   No es un rediseno de Layout\AdminLayout.razor: es la correccion del unico
   desborde que tenia en 375 px. El nombre de la instalacion se partia en dos
   lineas y empujaba el boton de cambiar de instalacion y el menu de usuario
   -con "Salir" dentro- fuera de la pantalla, donde no habia forma de
   alcanzarlos porque la barra recorta lo que le sobra.

   La regla del sistema de diseno esta en docs\central\diseno-web.md: toda
   pantalla se prueba en 375, 768 y 1280 px antes de darse por hecha.
   ========================================================================== */

.admin-barra-nombre {
    /* min-width: 0 es la pieza que falta en un hijo de flex: sin ella el
       texto no se deja recortar y el contenedor crece. */
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.admin-barra-cambiar {
    flex: 0 0 auto;
    /* 48 px tambien por encima de 600 px: la regla 3 del sistema de diseno no
       depende del ancho, y este boton se quedaba en 37 px en escritorio
       (medido en 768 px al cerrar el modulo 1 de la fase C3). */
    min-height: var(--tentalo-toque);
}

/* Con el texto oculto queda un boton con solo el icono: sin el relleno de un
   boton con etiqueta y con el alto minimo de toque. */
@media (max-width: 599.98px) {
    .admin-barra-cambiar {
        min-width: var(--tentalo-toque);
        min-height: var(--tentalo-toque);
        padding-left: 0.5rem;
        padding-right: 0.5rem;
    }

    .admin-barra-cambiar .mud-button-icon-start {
        margin-right: 0;
        margin-left: 0;
    }
}

/* ==========================================================================
   EL DASHBOARD Y LAS PIEZAS COMUNES DE LOS MODULOS (fase C3, modulo 1)
   --------------------------------------------------------------------------
   Aqui esta lo que el apartado 7 de docs\central\diseno-web.md dejaba por
   decidir: tarjetas de cifra, cabecera de pagina, paneles con sus cuatro
   estados, tablas densas, insignias y el grafico.

   Sin CSS aislado (.razor.css) a proposito -el aislamiento necesita el
   paquete de estilos del SDK, que en el modelo hosted esta apagado-, asi que
   todo lleva PREFIJO admin-. Es lo que hace de ambito.
   ========================================================================== */

/* --- Cabecera de pagina ------------------------------------------------- */

/* LA CABECERA, CON SU REGLA DEBAJO (rediseno «El plano de sala», §4). Lo que
   separa el titulo del contenido es una regla fina de tinta, no un hueco: en un
   plano, una linea es lo que dice donde acaba una cosa y empieza otra. */
.admin-cabecera {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 0.75rem 1.5rem;
    margin-bottom: 1.5rem;
    padding-bottom: 1rem;
    border-bottom: 1.5px solid var(--plano-linea);
}

.admin-cabecera-texto {
    /* min-width: 0 para que un titulo largo se recorte dentro de su columna
       en vez de empujar las acciones fuera de la pantalla. */
    min-width: 0;
    flex: 1 1 16rem;
}

.admin-cabecera-volver {
    margin-left: -0.5rem;
    margin-bottom: 0.25rem;
    min-height: 2rem;
}

/* EL TITULO EN FRASE y no en Title Case, condensado un punto y con el tracking
   cerrado: es la voz de los titulos del plano. El tamano ya no es un `clamp()`
   -la escala del sistema es fija, 28 px- porque un titulo que crece con el
   ancho de la ventana no casa con una escala de razon 1,2: a 1.920 px se salia
   de ella y dejaba de tener relacion con el resto de la pagina. */
.admin-cabecera-titulo {
    margin: 0;
    font-size: 1.75rem;
    font-weight: 650;
    font-stretch: 96%;
    letter-spacing: -0.015em;
    line-height: 1.15;
    color: var(--plano-tinta);
}

.admin-cabecera-subtitulo {
    margin: 0.35rem 0 0;
    font-size: 0.9375rem;
    color: var(--plano-tinta-2);
    max-width: 62ch;
}

.admin-cabecera-acciones {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    /* flex-wrap y max-width: con DOS acciones -un boton y el indicador de
       refresco, que es lo que trae el modulo 6- en 375 px no caben al lado y
       la caja se salia 39 px de la pantalla, dejando el boton de recargar
       inalcanzable (regla 2 del apartado 6 del sistema de diseno). Con el
       modulo 1 no se veia porque sus ocho pantallas solo llevaban el
       indicador. */
    flex: 0 1 auto;
    flex-wrap: wrap;
    max-width: 100%;
}

/* --- Indicador de tiempo real ------------------------------------------- */

.admin-refresco {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.8rem;
    color: var(--tentalo-tinta-suave);
}

.admin-refresco-punto {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: #2e9e5b;
}

/* El latido dice "se esta actualizando" sin gastar una palabra, y SOLO mientras se actualiza:
   es la regla 7 de docs/central/esperas.md (nada late para siempre) y la fea 11 del informe de
   C:\tmp\spinners, donde el punto de «Actualizado a las 18:07» seguia latiendo indefinidamente
   diciendo que pasaba algo cuando no pasaba nada. Quieto, dice lo que de verdad hay: los datos
   son de esa hora. Y se respeta a quien haya pedido menos movimiento (WCAG 2.3.3). */
.admin-refresco-punto-vivo {
    animation: admin-latido 2s ease-in-out infinite;
}

@keyframes admin-latido {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}

@media (prefers-reduced-motion: reduce) {
    .admin-refresco-punto-vivo {
        animation: none;
    }
}

/* --- Tarjetas de cifra --------------------------------------------------- */

.admin-cifras {
    display: grid;
    gap: 1rem;
    margin-bottom: 1.25rem;
    /* auto-fit + minmax es lo que evita una media query por numero de
       tarjetas: cuando no caben cuatro de 11 rem, caben dos, y cuando no
       caben dos, una. Los modificadores de abajo solo ajustan el minimo
       segun cuantas tarjetas trae la pantalla. */
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
}

.admin-cifras-3 {
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}

.admin-cifras-5 {
    grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
}

/* LA CIFRA NO ES UNA TARJETA (tanda 3). Una fila de «cifra grande + etiqueta»
   dentro de cajas blancas es el patron que el §0 del redisenio rechaza por su
   nombre. La cifra se queda -el dato es el dato- y pierde la caja: lo que la
   separa de la de al lado es una regla fina, como en un plano. */
.admin-cifra {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.85rem 1.1rem 0.95rem;
    background-color: transparent;
    border-radius: 0;
    border-left: 1px solid var(--plano-linea-fina);
    box-shadow: none;
}

/* La primera de la fila no lleva regla: el borde de la pagina ya la separa.
   Sin `:first-child` seguro (el contenedor puede traer un titulo delante), se
   apaga la regla cuando la cifra abre su rejilla. */
.admin-cifras > .admin-cifra:first-child { border-left: none; padding-left: 0; }

.admin-cifra-etiqueta {
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--tentalo-tinta-suave);
}

.admin-cifra-valor {
    font-size: clamp(1.35rem, 1vw + 1.1rem, 1.75rem);
    font-weight: 600;
    line-height: 1.25;
    color: var(--tentalo-tinta);
    /* Tabular para que una cifra que cambia cada 60 s no mueva la tarjeta. */
    font-variant-numeric: tabular-nums;
}

.admin-cifra-destacada .admin-cifra-valor {
    color: var(--tentalo-marca);
    font-weight: 700;
}

.admin-cifra-detalle {
    font-size: 0.78rem;
    color: var(--tentalo-tinta-suave);
}

.admin-cifra-extra {
    margin-top: 0.6rem;
}

/* --- Paneles: DE TARJETA A ZONA (tanda 3 del rediseno «El plano de sala») -- */

/* `.admin-panel` es el contenedor mas repetido de la web -219 sitios en 92
   pantallas- y hasta la tanda 3 era una TARJETA: fondo blanco, canto de 10 px,
   sombra de elevacion 1 y una cabecera separada por una linea. Es, palabra por
   palabra, «la tarjeta blanca con borde y sombra como contenedor universal» que
   el §0 del redisenio rechaza.

   Ahora es una ZONA: sin fondo, sin canto y sin sombra; lo que separa una zona
   de la siguiente son 28 px de aire y una regla fina, y eso lo pone
   `.plano-region` en plano.css. Aqui solo quedan el ROTULO y el relleno del
   cuerpo, que son de la pieza y no del plano.

   LA CLASE NO SE VA. Sigue en el marcado de PanelWidget, de CrudSeccion y de
   los paneles escritos a mano, porque es lo que miran las pruebas del esqueleto
   y las de las pantallas, y porque un `MudPaper` que todavia la lleve deja de
   ser papel por estas tres lineas sin tocar su marcado. */
/* EL CANTO NO SE APAGA AQUI, y lo enseno la primera captura de la tanda 3. Esta
   hoja se carga DESPUES de plano.css, asi que un `border: none` escrito aqui se
   llevaba por delante la REGLA FINA con la que `.plano-region` separa una zona
   de la siguiente: las zonas de una ficha salian flotando, sin nada entre ellas.
   Y no hacia falta para nada: lo que pinta `.admin-panel` es un `<section>`, que
   no trae canto de serie. */
.admin-panel {
    background-color: transparent;
    background-image: none;
    border-radius: 0;
    box-shadow: none;
    /* El aire entre zonas lo pone `.plano-region`; aqui solo el de los paneles
       que no son zona (los sueltos de una pantalla que aun no ha barrido). */
    margin-bottom: 0;
}

/* ARRIBA Y A LA IZQUIERDA, y las dos cosas hacen falta. Esta regla se carga
   DESPUES de plano.css y comparte especificidad con `.plano-region-rotulo`, que
   es la otra clase del MISMO elemento: con `align-items: center` aqui, aquella
   perdia y -al estar el bloque en columna- el `center` dejaba de centrar
   verticalmente y centraba el rotulo HORIZONTALMENTE. En la primera captura de
   la tanda 3 se veia: el rotulo en medio de su columna y la frase de ayuda
   debajo, a la izquierda. Lo enseno la captura, no la lectura del CSS. */
.admin-panel-cabecera {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 0.5rem;
    /* Sin relleno y sin linea: el rotulo de una zona no es la cabecera de una
       tarjeta, es una etiqueta de plano puesta al lado de lo que nombra. */
    padding: 0;
    border-bottom: none;
}

/* EL ROTULO DE LA ZONA, en versales condensadas (§1 del redisenio). Va escrito
   aqui y no solo en `.plano-rotulo` porque app.css se carga DESPUES de
   plano.css y, con la misma especificidad, ganaria esta regla: un titulo que
   lleva las dos clases tiene que salir igual por las dos. Los paneles escritos a
   mano que solo llevan `admin-panel-titulo` salen igual por el mismo motivo. */
.admin-panel-titulo {
    margin: 0;
    font-family: var(--plano-familia);
    font-size: var(--plano-t-12);
    font-weight: 600;
    font-stretch: 75%;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    line-height: 1.3;
    color: var(--plano-tinta-2);
}

.admin-panel-cuerpo {
    padding: 0;
}

.admin-panel-error {
    margin: 0;
}

.admin-panel-vacio {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
    padding: 2.25rem 1rem;
    text-align: center;
    color: var(--tentalo-tinta-suave);
}

/* Una tabla ancha hace scroll DENTRO de su panel, nunca en la pagina: es la
   regla de docs\central\diseno-web.md. Por debajo de Breakpoint.Sm, MudTable
   apila cada fila en una tarjeta con sus DataLabel y ya no hace falta. */
.admin-tabla {
    overflow-x: auto;
}

.admin-tabla .mud-table-cell {
    font-variant-numeric: tabular-nums;
}

/* --- Rejilla de tarjetas (locales, centros de venta, almacenes) ---------- */

.admin-rejilla-tarjetas {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.admin-tarjeta-enlace {
    text-decoration: none;
    color: inherit;
    display: block;
    border-radius: 10px;
}

/* El anillo de foco de esta tarjeta ya no se escribe aqui: lo pone la regla
   global de `:focus-visible` de arriba, que la alcanza por ser un <a>. */

/* DE TARJETA A HABITACION (tanda 3). La rejilla de locales, centros de venta y
   almacenes se leia como una cuadricula de tarjetas blancas con sombra; ahora
   cada pieza es una habitacion del plano, con el mismo lenguaje que las salas de
   la portada: MURO de 2 px en dos lados, linea fina en los otros dos y la
   esquina de muro. Al pasar por encima se tine de aguada morada en vez de
   levantarse: en un plano nada flota. */
.admin-tarjeta {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    height: 100%;
    padding: 1rem 1.1rem 1.1rem;
    background-color: var(--plano-hoja);
    border-radius: var(--plano-esquina-muro);
    border: 1px solid var(--plano-linea-fina);
    border-left: 2px solid var(--plano-muro);
    border-bottom: 2px solid var(--plano-muro);
    box-shadow: none;
    transition: background-color var(--plano-tiempo) var(--plano-curva);
}

.admin-tarjeta-enlace:hover .admin-tarjeta {
    background-color: var(--plano-morado-aguada);
    box-shadow: none;
}

.admin-tarjeta-titulo {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--tentalo-tinta);
}

.admin-tarjeta-cifra {
    font-size: 1.7rem;
    font-weight: 700;
    line-height: 1.15;
    color: var(--tentalo-marca);
    font-variant-numeric: tabular-nums;
}

.admin-tarjeta-etiqueta {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--tentalo-tinta-suave);
}

.admin-tarjeta-datos {
    margin-top: 0.4rem;
}

.admin-tarjeta-mas {
    margin-top: auto;
    padding-top: 0.6rem;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--tentalo-marca);
}

/* --- Dos columnas que se apilan ----------------------------------------- */

.admin-dos-columnas {
    display: grid;
    gap: 1.25rem;
    grid-template-columns: 1fr;
}

@media (min-width: 1024px) {
    .admin-dos-columnas {
        grid-template-columns: 1fr 1fr;
    }
}

/* --- Barra de ocupacion -------------------------------------------------- */

.admin-ocupacion {
    height: 6px;
    border-radius: 3px;
    background: #e7ecea;
    overflow: hidden;
}

.admin-ocupacion-relleno {
    height: 100%;
    border-radius: 3px;
    transition: width 0.3s ease-in-out;
}

/* Los tres tramos del administrador React: lleno es BUENO en ocupacion. */
.admin-ocupacion-alta { background: #2e9e5b; }
.admin-ocupacion-media { background: #d99423; }
.admin-ocupacion-baja { background: #c1443c; }

@media (prefers-reduced-motion: reduce) {
    .admin-ocupacion-relleno {
        transition: none;
    }
}

/* --- Insignias de las tablas de almacen --------------------------------- */

.admin-insignia {
    display: inline-block;
    min-width: 3rem;
    padding: 0.2rem 0.45rem;
    border-radius: 6px;
    font-size: 0.8rem;
    font-weight: 700;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.admin-insignia-roja { background: #fbe6e4; color: #8e2b25; }
.admin-insignia-ambar { background: #fdf1dc; color: #7a5410; }
.admin-insignia-verde { background: #e4f4ea; color: #1d6b3c; }
.admin-insignia-neutra { background: #e7ecea; color: var(--tentalo-tinta-suave); }

.admin-lista-principal {
    font-weight: 600;
    font-size: 0.88rem;
}

.admin-lista-secundario {
    font-size: 0.78rem;
    color: var(--tentalo-tinta-suave);
}

/* --- Fichas de usuario activo ------------------------------------------- */

.admin-usuarios {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.admin-usuario {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.35rem;
    padding: 1rem;
    border: 1px solid var(--tentalo-borde);
    border-radius: 10px;
    text-align: center;
}

.admin-usuario-avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 3.25rem;
    height: 3.25rem;
    border-radius: 50%;
    color: #fff;
    font-size: 1.35rem;
    font-weight: 700;
}

.admin-usuario-datos {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}

.admin-usuario-nombre {
    font-weight: 600;
    font-size: 0.95rem;
}

.admin-usuario-perfil {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--tentalo-tinta-suave);
}

.admin-usuario-actividad {
    font-size: 0.75rem;
    color: var(--tentalo-tinta-suave);
}

.admin-usuario-cifras {
    width: 100%;
    margin-top: 0.5rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--tentalo-borde);
}

/* --- El grafico de ventas por horas ------------------------------------- */

.admin-grafico-svg {
    display: block;
    width: 100%;
    height: auto;
}

/* La rejilla y el eje, en la línea del plano; la serie principal en MORADO y la
   comparación en TINTA REBAJADA, que es el mismo reparto que `Graficos.PALETA`
   le da a los gráficos de la analítica. Dos gráficos de la misma web no pueden
   usar el primer color para cosas distintas. */
.admin-grafico-rejilla {
    stroke: var(--plano-linea-fina);
    stroke-width: 1;
}

.admin-grafico-eje {
    stroke: var(--plano-linea);
    stroke-width: 1;
}

/* Rótulo condensado de 11 px: las cotas de un plano. */
.admin-grafico-escala,
.admin-grafico-hora {
    font-size: 11px;
    font-stretch: 75%;
    font-weight: 600;
    fill: var(--plano-tinta-2);
}

.admin-grafico-barra {
    fill: var(--plano-morado);
}

.admin-grafico-linea {
    fill: none;
    stroke: var(--plano-tinta-2);
    stroke-width: 2;
    stroke-dasharray: 4 3;
    stroke-linejoin: round;
}

.admin-grafico-leyenda {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem 1rem;
    margin-top: 0.75rem;
    font-size: 0.8rem;
    color: var(--tentalo-tinta-suave);
}

.admin-grafico-clave {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.admin-grafico-muestra-barra,
.admin-grafico-muestra-linea {
    display: inline-block;
    width: 0.85rem;
}

.admin-grafico-muestra-barra {
    height: 0.7rem;
    border-radius: 2px;
    background: var(--plano-morado);
}

.admin-grafico-muestra-linea {
    height: 0;
    border-top: 2px dashed var(--plano-tinta-2);
}

.admin-grafico-total {
    margin-left: auto;
    font-weight: 600;
}

/* --- El menu lateral: secciones y estrellas ----------------------------- */

.admin-menu-seccion {
    display: block;
    margin-top: 0.25rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-size: 0.7rem;
}

/* La estrella va AL LADO del enlace, no dentro: dentro seria un boton dentro
   de un enlace (marcado invalido) y pulsarla navegaria. */
.admin-menu-fila {
    display: flex;
    align-items: center;
}

.admin-menu-fila > .mud-nav-item {
    flex: 1 1 auto;
    min-width: 0;
}

.admin-menu-estrella {
    flex: 0 0 auto;
    margin-right: 0.35rem;
}

/* Regla 2 de docs/central/esperas.md: la respuesta a una pulsacion es inmediata. El destino de
   una navegacion tarda entre 0,26 s y 3 s en pintarse (fea 6 del informe) y lo unico que el
   navegador da gratis es el `:hover`; sin esto, pulsar un enlace del menu no se ve, y lo que hace
   la gente entonces es volver a pulsar. Hundir el enlace cuesta cero milisegundos porque lo pinta
   el compositor, no Blazor.

   Quien marca el destino DESPUES es el propio `NavLink`, que se suscribe a
   `NavigationManager.LocationChanged` y se repinta con `active` en cuanto la URL cambia -antes de
   que la pantalla llegue, que es justo lo que hace falta-. Lo comprueba
   `EsperasTests.El_enlace_del_menu_se_marca_al_cambiar_la_ruta`. */
.mud-navmenu a.mud-nav-link:active {
    transform: scale(0.98);
    background-color: rgba(103, 41, 144, 0.12);
}

@media (prefers-reduced-motion: reduce) {
    .mud-navmenu a.mud-nav-link:active {
        transform: none;
    }
}

/* El esqueleto de la seccion FAVORITOS. Reserva el alto de las N filas que se esperan (N = el
   ultimo recuento, guardado en localStorage) para que el menu no salte cuando lleguen del bus:
   era la fea 7 del informe, 330 px de empujon a un menu que ya se estaba leyendo. */
.admin-menu-esqueleto {
    padding: 0 1rem;
}

.admin-menu-esqueleto .mud-skeleton {
    height: var(--tentalo-toque);
    margin: 0;
}

/* --- Altura minima de toque en el marco del administrador --------------- */
/* La regla 3 de docs\central\diseno-web.md pide 48 px de alto minimo en
   campos y botones, y se escribio para la pantalla de acceso. En el
   administrador hay tres controles que por omision de MudBlazor se quedan
   cortos y que son de los que MAS se pulsan: los enlaces del menu lateral
   (41 px), los botones de icono pequenos -actualizar y la estrella de
   favoritos- (26 px) y el boton pequeno de «Volver» (37 px). Medido con el
   navegador en 768 px antes de esta regla.

   No se sube el tamano del icono, solo la caja: el area de toque crece y el
   dibujo se queda igual, que es lo que pide WCAG 2.5.5. */
.mud-navmenu .mud-nav-link,
.mud-navmenu .mud-nav-link-disabled {
    min-height: var(--tentalo-toque);
}

.admin-menu-estrella,
.admin-refresco .mud-icon-button {
    min-width: var(--tentalo-toque);
    min-height: var(--tentalo-toque);
}

.admin-cabecera-volver {
    min-height: var(--tentalo-toque);
}

/* El chip «próximamente» de un modulo sin pantalla se salia del cajon de 240 px
   con las etiquetas largas («Comunicaciones»): se recortaba a media palabra.
   Con envoltura, la etiqueta y el chip caen en dos lineas, que es lo correcto
   en un cajon estrecho. Medido en 1280 px al cerrar el modulo 1 de la C3. */
.mud-navmenu .mud-nav-link .d-inline-flex {
    flex-wrap: wrap;
    row-gap: 0.15rem;
}

/* --- Comunicaciones (modulo 6 de la fase C3) ---------------------------- */
/* El semaforo de un local: punto de color MAS su palabra. El color solo no
   vale -WCAG 1.4.1, y esta pantalla se recorre buscando el rojo-, asi que
   nunca se pinta el punto sin el texto al lado. */

.admin-comms-semaforo {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-weight: 600;
    font-size: 0.85rem;
    white-space: nowrap;
}

.admin-comms-punto {
    display: inline-block;
    width: 0.6rem;
    height: 0.6rem;
    border-radius: 50%;
    background: currentColor;
    flex: 0 0 auto;
}

/* Los mismos tres colores que la barra de ocupacion del modulo 1, para que
   verde signifique lo mismo en todo el administrador. */
.admin-comms-ok { color: #1d6b3c; }
.admin-comms-aviso { color: #7a5410; }
.admin-comms-error { color: #8e2b25; }

/* El motivo va debajo del estado y en dos lineas como maximo de ancho: los
   mensajes del nucleo son frases enteras («El local lleva mas de una hora sin
   conectarse a la central.») y en una celda de tabla sin acotar empujan las
   demas columnas fuera. */
.admin-comms-motivo {
    display: block;
    font-size: 0.76rem;
    line-height: 1.35;
    color: var(--tentalo-tinta-suave);
    /* min() y no 22rem a secas: en 375 px la celda mide menos que eso y un
       max-width mayor que el hueco empuja la tabla apilada fuera de su
       contenedor. */
    max-width: min(22rem, 100%);
    margin-top: 0.15rem;
    overflow-wrap: anywhere;
}

.admin-comms-nombre {
    display: block;
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--tentalo-marca);
    text-decoration: none;
}

.admin-comms-nombre:hover,
.admin-comms-nombre:focus-visible {
    text-decoration: underline;
}

/* Los dos botones de la ultima columna caen en dos lineas cuando no caben, en
   vez de recortarse: son los unicos controles de accion de la pantalla. */
.admin-comms-acciones {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    justify-content: flex-end;
}

/* «Publicar datos» partido en dos lineas dentro de la celda hacia que la fila
   creciera al doble de alto y que la columna del nombre se partiera en tres.
   Con nowrap la tabla mide 20 px mas y las siete columnas caben en 1280 px;
   por debajo del corte, MudTable apila la fila y esto deja de aplicar. */
.admin-comms-acciones .mud-button-root {
    white-space: nowrap;
}

/* El envoltorio de una tarjeta de cifra que necesita un gancho de prueba.
   Cifra.razor no captura atributos sueltos (no tiene CaptureUnmatchedValues) y
   no se le anade por esto: la rejilla .admin-cifras usa `display: grid`, asi
   que un div intermedio tiene que estirarse para que la tarjeta siga midiendo
   lo mismo que sus hermanas. */
.admin-comms-cifra {
    display: flex;
}

.admin-comms-cifra > .admin-cifra {
    flex: 1 1 auto;
}

/* «Informacion adicional»: el motivo del estado, debajo de las cifras de su
   seccion en el detalle. */
.admin-comms-adicional {
    margin-top: 1rem;
}

.admin-comms-adicional p {
    margin: 0.2rem 0 0;
    font-size: 0.88rem;
    font-weight: 600;
}

/* Altura de toque de los botones de accion (regla 3 del sistema de diseno, 48
   px). MudBlazor da 36 px a un boton normal, 31 a uno pequeno y 24 a un chip
   pulsable, y los tres aparecen en las pantallas de comunicaciones: los dos
   botones de la cabecera, los dos de cada fila de la tabla y los cuatro chips
   del filtro por estado. Medido con el navegador en 1280 px.

   Crece la caja y no el texto, igual que hizo el modulo 1 con los enlaces del
   menu y los botones de icono. La cabecera se toca por su clase compartida a
   proposito: es el sitio de las acciones de TODAS las pantallas del
   administrador, y el «Cambiar limites» de la ficha de la instalacion tenia el
   mismo problema desde la fase C1. */
.admin-cabecera-acciones .mud-button-root,
.admin-comms-acciones .mud-button-root,
.admin-comms-filtro .mud-chip {
    min-height: var(--tentalo-toque);
}

/* La tabla no puede pasarse de su contenedor. Con Breakpoint.Sm, MudBlazor
   apila cada fila en una tarjeta y la tabla deja de tener columnas que la
   acoten: en 375 px la de «Órdenes de configuración» salia 47 px por la
   derecha de su panel -sin hacer scrollear la pagina, porque .admin-tabla la
   recorta, pero recortando texto-. Medido en el detalle del local 1. */
/* Con Breakpoint.Sm, MudBlazor apila cada fila en una tarjeta poniendo la
   celda en `display: flex` con la etiqueta en un ::before. Un elemento flex no
   baja de su min-content, asi que el ancho de la tabla lo fija la celda con el
   texto mas largo: en 375 px la de «Órdenes de configuración» pedia 345 px
   dentro de un contenedor de 298 y se salia 47 px por la derecha (la pagina no
   scrollea -.mud-table-container recorta- pero recorta texto). Con
   table-layout: fixed el min-content deja de mandar, y con min-width: 0 en los
   hijos de la celda el texto envuelve en vez de empujar.
   Solo en modo apilado: en escritorio las columnas siguen midiendose por su
   contenido. Medido en el detalle del local 1 a 375 px. */
.admin-tabla .mud-sm-table .mud-table-root {
    width: 100%;
    max-width: 100%;
    table-layout: fixed;
}

.admin-tabla .mud-sm-table .mud-table-cell > * {
    min-width: 0;
}

/* ======================================================================== */
/*  MODULO 2 DE LA FASE C3: EL MARCO CRUD DEL CATALOGO                      */
/*  docs\central\fase-c3.md, «Módulo 2, parte 1».                           */
/*                                                                          */
/*  Dos prefijos: «crud-» para el marco (lista, ficha, secciones, edicion   */
/*  multiple) y «campo-» para los controles compartidos de                  */
/*  Components\Campos\. Van aqui y no en un .razor.css por el apartado 1    */
/*  del sistema de diseno (el aislamiento de CSS esta apagado en el modelo  */
/*  hosted).                                                                */
/* ======================================================================== */

/* --- La barra de la lista: buscador, contador y acciones de grupo -------- */
.crud-barra {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}

/* EL BUSCADOR VIVE DENTRO DE `.crud-buscador-caja` desde el 2026-09-18 (§14 del rediseno): es la
   caja la que reparte el sitio en la barra -y la que le pone el tope de 480 px- y el campo crece
   dentro de ella. Las dos medidas de aqui se quedan para los buscadores escritos a mano que
   siguen llevando la clase suelta (el arbol de permisos, el selector de instalacion). */
.crud-buscador {
    flex: 1 1 16rem;
    max-width: 26rem;
}

.crud-contador {
    color: var(--tentalo-tinta-suave);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* La barra de acciones de grupo solo existe con algo seleccionado, asi que se
   distingue con el fondo de marca al 6 %: aparece y desaparece, y sin un
   cambio de fondo el usuario no ve que la tabla le esta ofreciendo algo. */
.crud-seleccion {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
    padding: 0.5rem 0.75rem;
    border-radius: 8px;
    background: var(--plano-morado-aguada);
}

.crud-principal {
    font-weight: 600;
}

/* Las celdas numericas a la derecha y con cifras de ancho fijo, como pide el
   apartado 7.4 del sistema de diseno. */
.crud-celda-numero {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.crud-celda-centro {
    text-align: center;
}

/* Los botones de accion de una fila, juntos y sin envolver. */
.crud-celda-acciones {
    text-align: center;
    white-space: nowrap;
}

/* --- La ficha ------------------------------------------------------------ */
/* Las secciones de un formulario largo, separadas siempre por lo mismo.

   DESDE LA TANDA 3 las que son ZONA (`.plano-region`) se separan solas -28 px de
   aire y una regla fina, §4- y aqui se les quita el margen para que las dos
   medidas no se sumen: con las dos, entre dos grupos de campos habia 44 px y la
   regla quedaba descentrada. Lo que no es zona -una tabla suelta, un aviso- sigue
   con su centimetro de siempre. */
.crud-secciones > * {
    margin-bottom: 1rem;
}

.crud-secciones > .plano-region {
    margin-bottom: 0;
}

/* Dos columnas cuando caben, una cuando no. Sin media query: el minmax decide.
   22 rem es el ancho por debajo del cual un campo con etiqueta larga
   («Pregunta antes de avisar de un cambio de cantidad») deja de leerse. */
.crud-secciones-dos {
    display: grid;
    /* min(22rem, 100%) y no 22rem a secas: con 22rem el minimo de la pista (352 px)
       es mayor que el ancho disponible en 375 px (343 px con los margenes del
       contenedor), y la columna se sale del contenedor. La pagina no scrollea
       -algo mas arriba tiene overflow hidden- pero los campos de la derecha
       quedan RECORTADOS, que por la regla 2 del sistema de diseno es peor: un
       campo recortado es un campo inalcanzable. Medido en la ficha de producto,
       donde salian 69 elementos fuera de pantalla. */
    grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr));
    gap: 1rem;
    align-items: start;
}

.crud-secciones-dos > * {
    min-width: 0;
}

/* Guardar y Cancelar: al final del formulario en escritorio y PEGADOS al borde
   inferior por debajo de 900 px. El formulario de un producto mide cuatro
   pantallas de movil y con los botones al final hay que recorrerlo entero para
   guardar un campo. */
.crud-ficha-acciones {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 1rem;
    padding: 0.75rem 0;
}

.crud-ficha-estado {
    white-space: nowrap;
}

@media (max-width: 900px) {
    .crud-ficha-acciones {
        position: sticky;
        bottom: 0;
        z-index: 3;
        margin-top: 0.5rem;
        padding: 0.75rem;
        border-top: 1px solid var(--tentalo-borde);
        border-radius: 8px 8px 0 0;
        background: #fff;
        box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.06);
    }
}

/* El esqueleto de la ficha (Components\Crud\EsqueletoDeFicha.razor): un campo
   fantasma mide como uno de verdad, o sea, etiqueta encima del control y el
   mismo hueco debajo que .campo. La caja y las dos columnas no se definen aqui:
   son .admin-panel y .crud-secciones-dos, las mismas del formulario, que es
   justo lo que hace que no haya salto de altura cuando llegan los datos. */
.crud-campo-esqueleto {
    margin-bottom: 0.75rem;
}

/* ==========================================================================
   LOS ESQUELETOS QUE MIDEN LO QUE VA A LLEGAR
   (T2 de docs\central\auditoria-ux-2026-09-15.md, tanda 3; regla 3 de
   docs\central\esperas.md)
   ==========================================================================
   Hasta el 2026-09-15 el esqueleto por omision de PanelWidget eran TRES
   BARRITAS de 1,4 rem -170 px en total-, y 33 paneles de 26 pantallas caian en
   el: lo que llegaba despues era una tabla de nueve columnas, una rejilla de
   tarjetas o un formulario de dos pantallas. Estas reglas son la parte de CSS
   de los esqueletos nuevos; la parte de marcado esta en
   Comun\Components\Crud\EsqueletoDeTabla.razor y EsqueletoDeCampos.razor.

   La regla que las gobierna: NINGUNA MEDIDA SE ESCRIBE DOS VECES. El alto de
   la fila sale de --tentalo-fila-tabla (ver :root), el ancho de cada columna
   lo pone el componente en el `style` con los pesos de las columnas de verdad,
   y la tarjeta y su relleno son .admin-panel, la misma del contenido. */

.admin-esqueleto-tabla {
    display: grid;
    /* grid-template-columns lo pone el componente: son los pesos de ESTA
       tabla y no los hay dos iguales. */
    align-items: center;
    column-gap: 1rem;
}

.admin-esqueleto-tabla-fila {
    display: contents;
}

/* El alto lo llevan las CELDAS y no la fila, porque `display: contents` saca a
   la fila de la caja: son las celdas las que ocupan la rejilla. Y el
   rectangulo va dentro de la celda, no ES la celda: si el alto se le pusiera
   al propio esqueleto, la barra mediria 43 px en vez de 1 rem y no se
   parceria a una linea de texto. */
.admin-esqueleto-tabla-celda {
    height: var(--tentalo-fila-tabla);
    display: flex;
    align-items: center;
    border-bottom: 1px solid var(--tentalo-borde);
}

/* La cabecera mide como una fila: lleva los botones de ordenar, que son de la
   misma talla que los de la celda de acciones. */
.admin-esqueleto-tabla--seleccion .admin-esqueleto-tabla-celda {
    height: var(--tentalo-fila-tabla-seleccion);
}

/* La rejilla de tarjetas: las mismas columnas que .admin-rejilla-tarjetas, que
   es lo que va a llegar. */
.admin-esqueleto-tarjetas {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

/* Un grafico reserva su lienzo entero: media pantalla de barritas donde va a
   ir un grafico es el salto de siempre. El alto lo pone el propio rectangulo
   (PanelWidget.ALTO_DE_GRAFICO, o el `Alto` que pase la pantalla). */
.admin-esqueleto-grafico {
    display: flex;
}

.admin-esqueleto-lista {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

/* Una seccion PLEGADA de la ficha: la barra de rotulo de `crud-seccion`, sin
   nada dentro. Mide lo mismo que el MudExpansionPanel cerrado -56 px- porque
   es lo que va a llegar; ver EsqueletoDeFormulario.razor. */
/* Desde la tanda 3 la seccion de verdad ya no es una tarjeta, asi que el
   esqueleto tampoco: la barra de rotulo con su regla fina debajo, que es lo que
   va a llegar. El alto baja de 56 a 44 px por lo mismo (el tirador de la zona
   mide el toque y no el panel de Mud con su relleno). */
.crud-seccion-esqueleto {
    height: 44px;
    display: flex;
    align-items: center;
    padding: 0;
    margin-bottom: 1rem;
    background: transparent;
    border-radius: 0;
    border-bottom: 1px solid var(--plano-linea-fina);
    box-shadow: none;
}

.crud-errores {
    margin: 0.4rem 0 0;
    padding-left: 1.2rem;
}

.crud-errores li {
    font-size: 0.9rem;
}

/* --- Secciones plegables de una ficha ----------------------------------- */
.crud-seccion {
    margin-bottom: 1rem;
}

.crud-seccion-titulo {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/* --- Precios por tarifa ------------------------------------------------- */
/* Una fila por tarifa: nombre a la izquierda y los tres precios y el IVA
   propio al lado. Por debajo de 700 px se apila, que es lo que hace que la
   fila se lea en un movil sin scroll horizontal. */
.crud-precios-fila {
    display: grid;
    grid-template-columns: minmax(8rem, 1fr) repeat(3, minmax(7rem, 8rem)) minmax(9rem, 12rem);
    gap: 0.5rem;
    align-items: start;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--tentalo-borde);
}

.crud-precios-tarifa {
    display: flex;
    flex-direction: column;
    padding-top: 0.6rem;
}

.crud-precios-nombre {
    font-weight: 600;
}

.crud-precios-iva {
    font-size: 0.76rem;
    color: var(--tentalo-tinta-suave);
}

@media (max-width: 700px) {
    .crud-precios-fila {
        grid-template-columns: 1fr;
    }

    .crud-precios-tarifa {
        padding-top: 0;
    }
}

/* --- Horarios de una categoria ----------------------------------------- */
.crud-horario {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--tentalo-borde);
}

.crud-horario-horas {
    display: flex;
    gap: 0.5rem;
    flex: 1 1 16rem;
}

.crud-horario-dias {
    display: flex;
    flex-wrap: wrap;
    gap: 0.1rem;
}

/* --- Edicion multiple --------------------------------------------------- */
.crud-multiple {
    display: flex;
    flex-direction: column;
}

/* Una fila por modificacion: la casilla «aplicar» arriba y su campo debajo,
   sangrado. El campo se queda VISIBLE y apagado cuando la casilla no esta
   marcada (opacidad y sin puntero): en una lista de veinticuatro
   modificaciones hay que poder ver de que va cada una antes de marcarla. */
.crud-modificacion {
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--tentalo-borde);
}

.crud-modificacion-activa {
    background: rgba(103, 41, 144, 0.04);
}

.crud-modificacion-texto {
    display: flex;
    flex-direction: column;
}

.crud-modificacion-categoria {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--tentalo-tinta-suave);
}

.crud-modificacion-descripcion {
    font-size: 0.92rem;
}

.crud-modificacion-campo {
    margin-left: 2.5rem;
}

.crud-modificacion-campo-apagado {
    opacity: 0.45;
    pointer-events: none;
}

/* El filtro por etiqueta de la lista de categorias, encima de la tabla. */
.crud-filtro-etiquetas {
    margin-bottom: 1rem;
}

/* El filtro por MARCADOR DE CATEGORIA (decision 3 del usuario del 2026-09-15). Ya no es un panel
   aparte con su propia caja de texto -eso eran dos buscadores que no se conocian, apartado 4 de
   la auditoria UX-: es una linea suelta encima de la tabla con un desplegable, los chips de lo
   elegido y el recuento honrado. Sin MudPaper a proposito: un segundo panel por encima del de la
   lista es lo que hacia que pareciera otra pantalla. */
.crud-filtro-marcadores {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}

.crud-filtro-marcadores-campo {
    flex: 0 1 20rem;
    margin-bottom: 0;
}

.crud-filtro-marcadores-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
}

/* --- Los campos compartidos -------------------------------------------- */
.campo {
    margin-bottom: 0.75rem;
}

.campo-precio {
    max-width: 12rem;
}

.campo-nota {
    margin: 0 0 0.75rem;
    font-size: 0.87rem;
}

.campo-error {
    display: block;
    margin: -0.4rem 0 0.6rem;
}

.campo-casilla {
    margin-bottom: 0.2rem;
}

/* Las casillas anidadas del nucleo (control de lotes, lote en venta, lote
   automatico, dias de caducidad) se sangran de verdad: sin sangria, cuatro
   casillas seguidas no dicen que una depende de la anterior. */
/* LA DEPENDENCIA SE DIBUJA CON AGUADA, NO CON UNA BANDA (tanda 4). La línea de
   2 px a la izquierda decía «estas casillas cuelgan de la de arriba», pero en un
   sistema donde 2 px de tinta en dos lados son UN MURO, una banda suelta de un
   lado es ruido: el ojo la lee como el canto de una habitación que no está.
   La sangría se queda —es la que dice que hay jerarquía— y el bloque toma una
   aguada de tinta que lo separa del resto sin dibujar ninguna línea. */
.campo-casilla-hijos {
    margin-left: 1.75rem;
    padding: 0.25rem 0.5rem;
    border-radius: var(--plano-radio-control);
    background-color: rgba(42, 26, 62, 0.04);
}

.campo-multiple {
    margin-bottom: 1rem;
}

.campo-multiple-etiqueta {
    display: block;
    margin-bottom: 0.3rem;
    font-weight: 600;
}

.campo-multiple-vacio {
    margin-bottom: 0.4rem;
    color: var(--tentalo-tinta-suave);
}

.campo-multiple-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    margin-bottom: 0.4rem;
}

.campo-multiple-anadir {
    max-width: 26rem;
}

/* ==========================================================================
   LOS CAMPOS DE RELACION
   (T11 de docs\central\auditoria-ux-2026-09-15.md; la regla de cual usar esta
   en docs\central\campos-de-relacion.md)
   ==========================================================================
   Tres piezas que sustituyeron a la pared de chips del campo de seleccion
   multiple que hubo hasta el 2026-09-15: CampoCasillas (conjunto pequeno y
   cerrado), CampoLista (conjunto grande, con o sin orden) y
   SelectorDeElementos (el dialogo que abre el boton «Elegir…»).

   Las reglas .campo-multiple-* de arriba NO son suyas y siguen en uso:
   las comparten CampoEtiquetas, CampoImagen, CampoListaDeTextos y las
   cabeceras de estos tres.

   TRES COSAS MANDAN EN TODO ESTE BLOQUE:

     1. 44 px de alto minimo por fila y por casilla (WCAG 2.5.5). No son los 48
        de --tentalo-toque a proposito: estas son filas de una LISTA, no botones
        sueltos, y a 48 una lista de ocho ocupa 384 px, media pantalla de movil.
        Los botones que van dentro de la fila si conservan sus 44 de area.
     2. Ni una consulta de medios para la rejilla ni para las filas:
        `repeat(auto-fill, minmax(220px, 1fr))` y `flex-wrap` resuelven 1280,
        768 y 375 solos. La unica consulta de medios del bloque es la que hace
        que el selector ocupe la pantalla entera por debajo de 600 px.
     3. Colores, los que ya hay: --tentalo-tinta-suave para el detalle en gris
        (6,39:1 sobre blanco), --tentalo-borde para las separaciones y el ambar
        #B06000 del T4 para el aviso. Sin emojis; los iconos son los de Material
        que ya trae MudBlazor. */

/* --- Lo que comparten los tres ----------------------------------------- */
.campo-relacion {
    margin-bottom: 1rem;
}

/* El detalle en gris de una fila o de una casilla: el local del grupo de
   cajas, el codigo del producto. Va debajo y mas pequeno, nunca al lado. */
.campo-casillas__secundario,
.campo-lista__secundario,
.selector-elementos__secundario {
    display: block;
    color: var(--tentalo-tinta-suave);
    font-size: 0.78rem;
    line-height: 1.2;
}

/* --- CampoCasillas ----------------------------------------------------- */
.campo-casillas {
    margin-bottom: 1rem;
}

.campo-casillas__cabecera {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.5rem;
    margin-bottom: 0.3rem;
}

.campo-casillas__cabecera .campo-multiple-etiqueta {
    margin-bottom: 0;
}

/* El recuento «3 de 8». Es la respuesta a «no se ve cuantos hay» y por eso va
   pegado a la etiqueta y no al final de la rejilla. */
.campo-casillas__contador,
.campo-lista__contador,
.campo-etiquetas__contador {
    color: var(--tentalo-tinta-suave);
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
}

.campo-casillas__atajos {
    display: inline-flex;
    gap: 0.15rem;
    margin-left: auto;
}

/* «Todas» y «Ninguna» son botones de texto, no enlaces: se ven como enlaces
   pero cogen el tabulador y heredan el anillo de foco del T1. Se compactan a
   proposito -no llevan los 48 px de --tentalo-toque- porque son un atajo al
   lado de la etiqueta, no una accion de la ficha. */
.campo-casillas__atajo {
    min-width: 0;
    padding: 0.1rem 0.4rem;
    text-transform: none;
}

.campo-casillas__ayuda,
.campo-lista__ayuda {
    display: block;
    margin-bottom: 0.35rem;
    color: var(--tentalo-tinta-suave);
}

/* LA REJILLA. auto-fill con un minimo de 220 px: el navegador decide cuantas
   columnas caben, asi que a 1280 px dentro de una ficha salen tres o cuatro, a
   768 dos y a 375 -donde 220 + los margenes ya no dejan sitio a dos- una sola.
   Sin una linea de media query. */
.campo-casillas__rejilla {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 0.1rem 0.75rem;
}

.campo-casillas__casilla {
    display: flex;
    align-items: center;
    min-height: 44px;
}

/* La etiqueta ocupa la fila entera para que el area clicable sea toda la
   celda y no solo las cuatro palabras del texto. */
.campo-casillas__casilla .mud-checkbox {
    width: 100%;
}

.campo-casillas__casilla .mud-checkbox > label,
.campo-casillas__casilla .mud-checkbox .mud-typography {
    flex: 1 1 auto;
}

.campo-casillas__texto {
    display: block;
    line-height: 1.25;
}

/* --- CampoLista -------------------------------------------------------- */
.campo-lista__cabecera {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.4rem;
}

.campo-lista__cabecera .campo-multiple-etiqueta {
    margin-bottom: 0;
}

/* El autocompletado de anadir por nombre se encoge antes que el boton: a 375
   px la cabecera acaba en dos lineas -etiqueta y recuento arriba, campo y
   boton abajo- y el boton nunca se parte. */
.campo-lista__anadir {
    flex: 1 1 12rem;
    max-width: 22rem;
    margin-bottom: 0;
    margin-left: auto;
}

.campo-lista__elegir {
    flex: 0 0 auto;
    min-height: var(--tentalo-toque);
    white-space: nowrap;
}

.campo-lista__filtro {
    max-width: 22rem;
    margin-bottom: 0.4rem;
}

/* El aviso de «quita el filtro para reordenar», en el ambar del T4 (#B06000,
   4,65:1 sobre blanco). No es un error -no hay nada que corregir- pero tampoco
   es una nota al pie: explica por que dos botones estan apagados. */
.campo-lista__aviso {
    display: block;
    margin: -0.2rem 0 0.4rem;
    color: #B06000;
}

/* SIN CAJA (rediseño «El plano de sala», tanda 5, punto 2c). Tenia un canto de
   1 px y un radio de 6: dentro de una zona, un rectangulo con canto se lee como
   una tarjeta metida en otra. Lo que le da principio y fin son ahora sus reglas
   finas, y las escribe `plano.css`, que es donde vive la gramatica de listado. */
.campo-lista__filas {
    margin: 0;
    padding: 0;
    list-style: none;
}

/* ALTO FIJO DE OCHO FILAS con desplazamiento propio. 8 x 48 px es lo que cabe
   de un vistazo; por encima, una lista de cuarenta productos empujaba el resto
   del formulario fuera de la pantalla. El filtro de arriba es lo que hace que
   seguir siendo util con la lista recortada. */
.campo-lista__filas--alta {
    max-height: calc(8 * 48px);
    overflow-y: auto;
}

.campo-lista__fila {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-height: 44px;
    padding: 0.2rem 0.4rem;
}

.campo-lista__fila--vacia {
    justify-content: center;
}

/* El numero de orden, solo con Ordenable. Cifras de ancho fijo para que la
   columna no baile entre el 9 y el 10. */
.campo-lista__numero {
    flex: 0 0 1.8rem;
    color: var(--tentalo-tinta-suave);
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.campo-lista__texto {
    flex: 1 1 auto;
    min-width: 0;
}

.campo-lista__principal {
    display: block;
    line-height: 1.25;
    overflow-wrap: anywhere;
}

/* Los botones de la fila conservan su area de toque de 44 px sin estirar la
   fila: crece la caja del boton, no el icono. */
.campo-lista__fila .mud-icon-button,
.campo-lista__fila .mud-menu > .mud-icon-button {
    min-width: 44px;
    min-height: 44px;
}

/* --- CampoLista, LA FILA ESTRECHA (tanda de las pantallas densas) ---------- */
/*
   EL DEFECTO QUE CIERRA, medido. En la columna de 320 px del constructor del
   explorador la fila de una medida llevaba el número (29 px), el texto, y
   CUATRO objetivos de 44: subir, bajar, «⋮» y el aspa. Son 176 px de botones
   más 29 de número, más los huecos y el relleno: al nombre le quedaban 22 px.
   Y `.campo-lista__principal` lleva `overflow-wrap: anywhere` —que está bien
   para que un código de barras de treinta cifras no desborde—, así que con 22 px
   «Ventas netas» no se recortaba: se escribía EN VERTICAL, una letra por línea,
   dentro de una fila de 200 px de alto. Es literalmente la captura del usuario.

   Con `Compacto` las cuatro acciones son UNA («⋮») y el nombre se recorta con
   puntos suspensivos, que es lo que hace toda fila del plano que no cabe. El
   `anywhere` se apaga aquí y sólo aquí: fuera de la fila estrecha sigue siendo
   lo correcto.
*/
.campo-lista--compacto .campo-lista__principal {
    overflow: hidden;
    overflow-wrap: normal;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.campo-lista--compacto .campo-lista__secundario {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* El «⋮» es el único objetivo de la derecha y no se encoge nunca: es lo que
   pasaba con los cuatro, que se repartían el ancho con el texto. */
.campo-lista--compacto .campo-lista__menu {
    flex: 0 0 auto;
    margin-left: auto;
}

.campo-lista--compacto .campo-lista__menu .mud-icon-button {
    min-width: 44px;
    min-height: 44px;
}

/* El añadidor de una columna estrecha ocupa la línea entera y «Elegir…» va
   debajo: en 320 px, un autocompletado de 12rem y un botón de «Elegir…» en la
   misma línea dejan al campo en 90 px. */
.campo-lista--compacto .campo-lista__anadir {
    flex: 1 1 100%;
    max-width: none;
    margin-left: 0;
}

/* --- SelectorDeElementos ----------------------------------------------- */
.selector-elementos__buscador {
    margin-bottom: 0.5rem;
}

/* 70 vh de alto maximo: el dialogo no puede crecer mas que la ventana, y la
   banda de «N elegidos / Cancelar / Aceptar» tiene que quedar siempre a la
   vista sin desplazar el dialogo entero. */
.selector-elementos__lista {
    max-height: 70vh;
    overflow-y: auto;
    border: 1px solid var(--tentalo-borde);
    border-radius: 6px;
}

.selector-elementos__fila {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 0 0.5rem;
    border-bottom: 1px solid var(--tentalo-borde);
}

.selector-elementos__fila:last-child {
    border-bottom: none;
}

.selector-elementos__fila .mud-checkbox {
    width: 100%;
}

.selector-elementos__texto {
    display: block;
    line-height: 1.25;
}

/* El recuento se va a la izquierda del todo y empuja los dos botones a la
   derecha: es informacion, no una accion, y no puede parecer un tercer boton. */
.selector-elementos__cuenta {
    margin-right: auto;
    padding-left: 0.5rem;
    color: var(--tentalo-tinta-suave);
    font-size: 0.85rem;
}

/* A PANTALLA COMPLETA POR DEBAJO DE 600 px (el corte Xs de MudBlazor).
   Se hace aqui y no con DialogOptions.FullScreen porque FullScreen es un
   booleano que hay que decidir ANTES de abrir el dialogo: obligaria a
   preguntar el ancho por JS (IBrowserViewportService), a inyectar un servicio
   mas en CampoLista y a vivir con un dialogo del tamano equivocado si la
   ventana cambia de tamano con el abierto. La consulta de medios no falla. */
@media (max-width: 599.98px) {
    .mud-dialog.selector-elementos {
        width: 100vw;
        max-width: 100vw;
        height: 100vh;
        max-height: 100vh;
        margin: 0;
        border-radius: 0;
    }

    .selector-elementos__lista {
        /* Lo que queda de la ventana quitando el titulo, el buscador y la
           banda de botones. */
        max-height: calc(100vh - 15rem);
    }
}

/* --- CampoEtiquetas: las sugerencias ------------------------------------ */
.campo-etiquetas__cabecera {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
}

.campo-etiquetas__cabecera .campo-multiple-etiqueta {
    margin-bottom: 0.3rem;
}

/* Las que ya existen en la instalacion y no estan puestas. Van en variante
   Text y en gris para que NO se confundan con los chips de arriba, que son los
   que de verdad estan elegidos: dos filas de chips iguales serian ilegibles. */
.campo-etiquetas__sugerencias {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem;
    margin-top: -0.35rem;
}

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

.campo-etiquetas__sugerencia {
    border: 1px dashed var(--tentalo-borde);
}

/* --- CampoGruposDeTpv --------------------------------------------------- */
/* La rejilla NO desaparece con «vale en todos los grupos de cajas» marcada: se
   atenua y se apaga. Asi se ve cuales hay -y cuales habia elegidas- sin tener
   que desmarcar para mirar. 0,55 de opacidad sobre texto que ya cumple 6,39:1
   deja el detalle en ~3,5:1, que es el minimo de WCAG para contenido
   DESACTIVADO (1.4.3 exempta los controles inactivos) y a la vez se distingue
   de lo activo de un vistazo. */
.campo-grupos__lista {
    margin-top: 0.25rem;
}

.campo-grupos__lista--apagada {
    opacity: 0.55;
}

/* --- SelectorDeGruposDeCajas / SelectorDeGrupoDeCajas ------------------- */
/* Primero el local y luego sus grupos (docs\central\grupos-de-cajas-por-local-
   2026-10-04.md). El local y el buscador van en una fila que se parte sola:
   a 1280 px caben los dos, a 375 uno debajo del otro, sin consulta de medios. */
.selector-grupos__filtros,
.selector-grupo--con-local {
    display: flex;
    flex-wrap: wrap;
    gap: 0 1rem;
    align-items: flex-start;
}

.selector-grupos__filtros > *,
.selector-grupo--con-local > * {
    flex: 1 1 220px;
    min-width: 0;
}

.selector-grupos__resumen {
    margin: 0.25rem 0 0;
    font-size: 0.8125rem;
    color: var(--tentalo-tinta-suave);
}

/* --- Color -------------------------------------------------------------- */
.campo-color-pie {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: -0.4rem 0 0.75rem;
}

.campo-color-muestra {
    width: 20px;
    height: 20px;
    border: 1px solid var(--tentalo-borde);
    border-radius: 4px;
}

/* --- Imagen ------------------------------------------------------------- */
.campo-imagen {
    margin-bottom: 1rem;
}

.campo-imagen-cuerpo {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 1rem;
}

.campo-imagen-vista {
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    border: 1px dashed var(--tentalo-borde);
    border-radius: 8px;
    background: #fafafa;
}

.campo-imagen-vista img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.campo-imagen-acciones {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

/* El InputFile de Blazor no se puede estilar: se esconde y lo activa la
   etiqueta que lo envuelve, que ES el boton. Con 48 px de alto, como pide la
   regla 3 del sistema de diseno. */
.campo-imagen-boton {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    min-height: var(--tentalo-toque);
    padding: 0 0.9rem;
    border: 1px solid var(--tentalo-marca);
    border-radius: 4px;
    color: var(--tentalo-marca);
    font-size: 0.875rem;
    font-weight: 500;
    cursor: pointer;
}

.campo-imagen-boton:hover {
    background: rgba(103, 41, 144, 0.06);
}

.campo-imagen-boton:focus-within {
    outline: 2px solid var(--tentalo-marca);
    outline-offset: 2px;
}

.campo-imagen-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
}

/* --- Texto traducible y listas de texto -------------------------------- */
.campo-traducible-idiomas {
    margin: -0.4rem 0 0.75rem;
}

.campo-lista {
    margin-bottom: 1rem;
}

.campo-lista-fila {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.campo-lista-fila .campo {
    flex: 1 1 auto;
    margin-bottom: 0.35rem;
}

.campo-grupos {
    margin-bottom: 1rem;
}

/* --- Crear y recargar al lado de un desplegable (2026-10-09, AtajosDelCampo) ---
   El campo ocupa lo que queda y los dos botones de icono van a su derecha, a la
   altura del campo (48 px de toque, como campo-lista-fila); en un teléfono de
   390 px caben igual: el campo encoge, los botones no. */
.campo-con-atajos {
    min-width: 0;
}

.campo-con-atajos__fila {
    display: flex;
    align-items: flex-start;
    gap: 0.25rem;
}

.campo-con-atajos__campo {
    flex: 1 1 auto;
    min-width: 0;
}

.campo-con-atajos__botones {
    display: flex;
    flex: 0 0 auto;
    gap: 0;
    padding-top: 0.15rem;
}

/* En las fichas la etiqueta va ENCIMA del campo (hoja-limpia.css): los botones bajan lo que
   ocupa la etiqueta, para quedar a la altura de la caja del campo. */
.ficha .campo-con-atajos__botones {
    padding-top: calc(var(--plano-t-12, 0.75rem) * 1.3 + 4px);
}

.campo-con-atajos .campo-con-atajos__boton {
    min-height: var(--tentalo-toque);
    min-width: var(--tentalo-toque);
}

.campo-con-atajos__resultado {
    margin: -0.5rem 0 0.75rem;
    font-size: 0.8rem;
    color: var(--limpia-neutro-tinta, var(--tentalo-tinta-suave));
}

/* «Restablecer impresoras» al pie de «Impresión (avanzado)» de la zona. */
.zona-impresion-restablecer {
    margin-top: 0.25rem;
}

/* --- La pista al lado del nombre de una fila (2026-10-09, CrudColumna.Pista) ---
   Pequeña, en gris y sin romper la línea del nombre: «imprime distinto» en la lista
   de zonas de venta. No es una etiqueta de estado (no tiene color de aviso): dice
   que en la ficha hay algo que mirar. */
.crud-pista {
    display: inline-block;
    margin-inline-start: 0.4rem;
    padding: 0 0.4rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 500;
    line-height: 1.35rem;
    white-space: nowrap;
    vertical-align: baseline;
    background-color: var(--limpia-neutro-fondo, #e7ecea);
    color: var(--limpia-neutro-tinta, var(--tentalo-tinta-suave));
}

/* --- Altura de toque en el marco CRUD (regla 3, 48 px) ----------------- */
/* MudBlazor da 36 px a un boton normal, 31 a uno pequeno y 30 a un boton de
   icono pequeno; en estas pantallas aparecen los tres: «Nuevo», los de la
   barra de seleccion, los de cada fila de la tabla y los de anadir y quitar de
   las listas. Crece la caja, no el icono. */
.crud-boton,
.crud-accion,
.crud-seleccion .mud-button-root,
.crud-horario .mud-icon-button,
.campo-lista-fila .mud-icon-button {
    min-height: var(--tentalo-toque);
    min-width: var(--tentalo-toque);
}

/* El submenu del catalogo: sus entradas tienen la misma altura de toque que
   las de primer nivel. */
.admin-menu-grupo .mud-nav-link {
    min-height: var(--tentalo-toque);
}

/* --- Los controles que MudBlazor deja por debajo de 48 px -------------- */
/* Medido con el navegador en 375 px sobre la lista de productos: la regla 3
   del sistema de diseno pide 48 px de alto minimo en CAMPOS y BOTONES, y
   MudBlazor deja cuatro cosas por debajo en estas pantallas.

   Se corrige aqui y no quitando Margin.Dense de los campos: sin denso, un
   MudTextField mide 56 px y la ficha de un producto (sesenta campos) crecería
   un 40 % de alto por un margen que nadie necesita. Con esto crece la CAJA
   hasta 48 y el texto se queda como esta, que es lo que pide WCAG 2.5.5 y lo
   mismo que hizo el modulo 1 con los enlaces del menu.

   Los cuatro casos, con su medida original:
     - los campos densos del marco (40 px);
     - la casilla de seleccion de cada fila de MudTable (24 la celda, 32 el
       input): es el control que mas se pulsa de la lista;
     - el desplegable de «ordenar por» que MudTable ensena en modo tarjeta
       por debajo de 600 px (32 px);
     - el desplegable de «filas por pagina» del paginador (20 px). */
.campo .mud-input-control,
.campo .mud-input-root,
.campo input.mud-input-slot,
.crud-buscador,
.crud-buscador .mud-input-root,
.crud-buscador input.mud-input-slot {
    min-height: var(--tentalo-toque);
}

.admin-tabla .mud-table-cell-checkbox,
.admin-tabla .mud-table-cell-checkbox .mud-checkbox-input,
.admin-tabla .mud-table-cell-checkbox .mud-button-root {
    min-height: var(--tentalo-toque);
    min-width: var(--tentalo-toque);
}

.admin-tabla .mud-table-smalldevices-sortselect,
.admin-tabla .mud-table-smalldevices-sortselect .mud-input-control,
.admin-tabla .mud-table-smalldevices-sortselect input,
.admin-tabla .mud-table-pagination-select,
.admin-tabla .mud-table-pagination-select input {
    min-height: var(--tentalo-toque);
}

/* Y EL ANCHO, que faltaba (auditoría responsiva, 2026-09-18). El selector de
   «filas por página» dice «100» y MudBlazor lo deja en 37 px de ancho por 48 de
   alto: alto de sobra y ancho por debajo de los 44 que pide el §6 del diseño. Se
   mide el hueco donde de verdad se pulsa, que es el `.mud-input-root` de dentro. */
.admin-tabla .mud-table-pagination-select,
.admin-tabla .mud-table-pagination-select .mud-input-root {
    min-width: var(--tentalo-toque);
}

/* Las casillas de verificacion y los botones de radio: la casilla de «aplicar»
   de la edicion multiple, las de CampoCasilla (nueve en la ficha de producto),
   las de una fila de tabla (formatos adicionales, tallas y colores) y los dos
   radios de «vale en todos / solo en algunos» de CampoGruposDeTpv y de los
   centros de venta. Lo que se pulsa es el boton con el icono, que MudBlazor
   deja en 32 px con Dense. */
.crud-modificacion-casilla .mud-button-root,
.mud-radio .mud-button-root,
.mud-radio input,
.campo-casilla-control,
.campo-casilla-control .mud-button-root,
.campo-casilla-control input,
.admin-tabla .mud-table-cell .mud-input-control-boolean-input .mud-button-root {
    min-height: var(--tentalo-toque);
    min-width: var(--tentalo-toque);
}

/* Los botones de adorno de un campo (la flecha y la X de un autocompletado, el
   selector de color) y los botones de texto pequenos de los campos. */
.campo .mud-input-adornment .mud-icon-button,
.mud-input-clear-button,
.campo-color-pie .mud-button-root,
.campo-imagen-acciones .mud-button-root,
.campo-traducible-idiomas .mud-expand-panel-header {
    min-height: var(--tentalo-toque);
}

/* --- Lo pulsable que se quedaba fuera de la regla de 48 px -------------- */
/* O1 de docs\central\auditoria-ux-2026-09-15.md: `--tentalo-toque` estaba en
   sesenta reglas de esta hoja, pero todas nombraban una pieza del marco CRUD,
   asi que lo de FUERA del marco se quedaba en los 30-40 px de MudBlazor.

   La regla es «lo PULSABLE, no las celdas de datos»: aqui solo hay botones,
   chips, entradas de menu, campos de dialogo y cabeceras ordenables. Las
   celdas normales de `.admin-tabla` NO se tocan -una tabla densa de nueve
   columnas con filas de 48 px deja de caber en pantalla- y por eso no aparece
   `.mud-table-cell` a secas en ningun selector de este bloque.

   Los sitios, con su medida original: las catorce casillas de dia de la
   semana en fila (32 px), los selectores de fecha y hora de una oferta (sin
   altura), las cabeceras ordenables de un informe (31), sus exportaciones
   (31), la barra de una ficha de documento (36), el selector de columnas (32)
   y los campos y botones de los siete dialogos de documentos (36-40). */
.crud-horario-dias .mud-button-root,
.crud-horario-dias .mud-checkbox .mud-button-root,
.crud-horario-dias input,
.crud-fechas .mud-input-control,
.crud-fechas .mud-input-root,
.crud-fechas input.mud-input-slot,
.informe-orden,
.informe-resultado-acciones .mud-button-root,
.documento-ficha-acciones .mud-button-root,
.documento-ficha-navegacion .mud-button-root,
.documento-ficha-acciones-barra .mud-button-root,
.documentos-columnas-menu .mud-button-root,
.documentos-columnas-menu .mud-checkbox .mud-button-root,
.mud-dialog-content .campo .mud-input-control,
.mud-dialog-content .campo .mud-input-root,
.mud-dialog-content .campo input.mud-input-slot,
.mud-dialog-actions .mud-button-root {
    min-height: var(--tentalo-toque);
}

/* Las entradas de un menu desplegable y de una lista elegible: el «Nuevo» de
   los disenos de pantalla son tres opciones de 32 px, y no existia un solo
   selector `.mud-menu-item` en toda la hoja. Los enlaces del menu lateral ya
   estaban a 48 px desde el modulo 1 (`.mud-navmenu .mud-nav-link`, arriba). */
.mud-menu-item,
.mud-list-item {
    min-height: var(--tentalo-toque);
}

/* Los campos que van DENTRO de una celda de tabla (stock minimo y maximo por
   almacen, proporcion de un formato, cantidad de un ingrediente): no llevan la
   clase «campo» porque en una celda no quieren margen inferior. */
.admin-tabla .mud-input-control,
.admin-tabla .mud-input-root,
.admin-tabla input.mud-input-slot {
    min-height: var(--tentalo-toque);
}

/* --- Las tablas del marco CRUD: 37 columnas caben scrollando ----------- */
/* La lista de productos tiene ONCE columnas fijas mas TRES por tarifa, y la
   instalacion de prueba tiene ocho tarifas: 37 columnas. Con la tabla al 100 %
   del panel, MudTable reparte 947 px entre 37 columnas (25 px cada una) y las
   cabeceras se solapan: no se lee nada. Medido en 1280 px.

   La solucion es la del sistema de diseno -una tabla ancha hace scroll DENTRO
   de su contenedor- y son TRES cosas, ninguna opcional:

     1. HorizontalScrollbar en el MudTable (CrudLista.razor), que es lo que pone
        el contenedor con overflow-x: auto.
     2. min-width: max-content en la tabla. Sin esto la tabla sigue midiendo el
        100 % del contenedor y no hay nada que scrollear: es el paso que falta en
        casi todas las recetas que se encuentran de esto.
     3. white-space: nowrap en las celdas, para que cada columna pida el ancho de
        su contenido en vez de partir «Conversion Bebida N/Incl» en cinco lineas.

   Solo en las tablas del marco (.crud-tabla): las del dashboard tienen cinco
   columnas, caben de sobra y ahi envolver esta bien. */
/* El selector va con la MISMA forma (y una clase mas) que la regla del modulo 6
   de unas lineas arriba -«.admin-tabla .mud-sm-table .mud-table-root»-, porque
   si no gana ella: esa regla pone width: 100 % y table-layout: fixed para que
   en modo tarjeta el texto envuelva, y con fixed + min-width: max-content el
   navegador reparte los 7.752 px A PARTES IGUALES (210 px por columna), con lo
   que un nombre largo se pinta ENCIMA de la familia. Con auto, «Id» mide lo que
   mide un numero y «Nombre» lo que mida el nombre mas largo.

   La regla del modulo 6 sigue aplicandose a sus tablas y, por debajo de 600 px,
   tambien a estas: ver la media query del final del bloque. */
.admin-tabla.crud-tabla .mud-sm-table .mud-table-root {
    width: auto;
    max-width: none;
    table-layout: auto;
    min-width: max-content;
}

.crud-tabla .mud-table-cell {
    white-space: nowrap;
}

/* NO se recorta el nombre con puntos suspensivos. Se probo con
   max-width + text-overflow: ellipsis y en una tabla dimensionada por
   max-content el recorte se pinta ENCIMA de la columna siguiente («Louis
   Latour Romanee St Vivant GRAND CRU» se metia dentro de la familia): el ancho
   de la columna lo calcula el navegador con el contenido completo y el max-width
   del enlace no entra en esa cuenta. La columna mide lo que mida el nombre mas
   largo y la tabla scrollea, que es justo para lo que esta el scroll. */

/* En modo tarjeta (por debajo de 600 px) manda lo contrario: la celda ocupa una
   fila entera, no hay a donde scrollear y el texto SI tiene que envolver. */
@media (max-width: 599px) {
    .admin-tabla.crud-tabla .mud-sm-table .mud-table-root {
        width: 100%;
        max-width: 100%;
        table-layout: fixed;
        min-width: 0;
    }

    .crud-tabla .mud-table-cell {
        white-space: normal;
    }

    .crud-tabla .mud-table-cell .crud-principal {
        max-width: none;
        white-space: normal;
    }
}

/* ============================================================================
   MODULO 3 DE LA FASE C3: LOCALES Y TPVs (parte 1)
   ============================================================================
   Cinco piezas, todas con prefijo `locales-`, `tpv-`, `config-` o
   `impuestos-`. El resto de las quince pantallas se pinta con lo que ya hay:
   cabecera, paneles con sus cuatro estados, el marco CRUD del modulo 2 y los
   campos compartidos. */

/* Los atajos de la lista de locales: una tarjeta por local con los enlaces a
   sus dos pantallas propias (configuracion y comunicaciones). Rejilla y no
   tabla porque cada tarjeta es un DESTINO y no algo que se compare columna a
   columna, que es el criterio del §7.4 del sistema de diseno.

   minmax(min(16rem, 100%), 1fr) y no minmax(16rem, 1fr): con la pista fija, en
   375 px la columna pide 256 px dentro de un contenedor de 343 y se sale. Es el
   mismo fallo que el modulo 2 midio en .crud-secciones-dos. */
.locales-atajos {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(16rem, 100%), 1fr));
    gap: .75rem;
}

/* Un atajo de la ficha de local: la misma habitación que las demás rejillas
   (tanda 3). Antes era un `MudPaper Outlined` con su canto gris por los cuatro
   lados; ahora, muro de 2 px en dos y línea fina en los otros dos. */
.locales-atajo {
    min-width: 0;
    padding: 0.75rem;
    background-color: var(--plano-hoja);
    border: 1px solid var(--plano-linea-fina);
    border-left: 2px solid var(--plano-muro);
    border-bottom: 2px solid var(--plano-muro);
    border-radius: var(--plano-esquina-muro);
}

/* Los datos de la central en la ficha de un local: dos columnas de
   etiqueta/valor en escritorio, una en movil. */
.locales-central {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
    gap: 0 1.5rem;
}

.locales-central-acciones {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-top: .5rem;
}

/* --- La carta digital de un establecimiento ----------------------------- */
/* El interruptor «Publicada». MudBlazor deja el suyo en 38 px de alto y aqui se
   pulsa con el pulgar en una tableta detras de la barra: 44 px es el minimo de
   area de toque de la auditoria (O1). Se estira la CAJA del control, no el
   dibujo del interruptor. */
.carta-digital__interruptor .mud-switch {
    min-height: 44px;
    margin: 0;
}

/* ENLACE A LA IZQUIERDA, QR A LA DERECHA, y en 375 px una sola columna con el
   QR ARRIBA.

   El DOM lleva el QR primero a proposito -es lo que se viene a buscar-, asi que
   la columna unica del movil sale sola con el orden del documento y sin una
   media query que reordene nada. En escritorio son `grid-column` los que
   devuelven el enlace a la izquierda.

   minmax(min(18rem, 100%), 1fr) y no minmax(18rem, 1fr): con la pista fija, en
   375 px la columna pide 288 px dentro de un contenedor de 343 y se sale. Es el
   mismo fallo que midio el modulo 2 en .crud-secciones-dos. */
.carta-digital__rejilla {
    display: grid;
    grid-template-columns: minmax(min(18rem, 100%), 1fr) auto;
    gap: 1rem 1.5rem;
    align-items: start;
    margin-top: .5rem;
}

.carta-digital__enlace {
    grid-column: 1;
    grid-row: 1;
    min-width: 0;
}

.carta-digital__qr {
    grid-column: 2;
    grid-row: 1;
}

/* El QR, cuadrado y de 240 px: es el tamano con el que se lee en la pantalla sin
   ampliar y sigue cabiendo al lado del enlace en 1280 px. `height: auto` para
   que un SVG sin viewBox no se deforme. */
.carta-digital__qr-imagen {
    display: block;
    width: 240px;
    max-width: 100%;
    height: auto;
    border: 1px solid var(--tentalo-borde);
    border-radius: 6px;
    background: #FFFFFF;
}

.carta-digital__qr-botones,
.carta-digital__acciones {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin: .5rem 0;
}

/* El logo de la carta (comensal v2): el campo de imagen compacto y, al lado, el que usa ahora la carta (el de la sociedad). */
.carta-digital__logo {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem 1.25rem;
    align-items: flex-start;
    margin-top: .75rem;
    padding-top: .75rem;
    border-top: 1px solid var(--tentalo-borde);
}

.carta-digital__logo-ayuda {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex: 1 1 14rem;
    min-width: 0;
    padding-top: 1.75rem;
}

.carta-digital__logo-actual {
    flex: none;
    width: 40px;
    height: 40px;
    object-fit: contain;
    border: 1px solid var(--tentalo-borde);
    border-radius: 8px;
    background: #FFFFFF;
}

/* «Regenerar enlace» va separado del resto por una linea: no es una accion mas
   de la carta, es la unica que rompe algo que ya esta impreso. */
.carta-digital__peligro {
    margin-top: .75rem;
    padding-top: .75rem;
    border-top: 1px solid var(--tentalo-borde);
}

/* UNA COLUMNA EN EL MOVIL. Las dos pistas se deshacen y las dos celdas vuelven a
   colocarse solas en el orden del DOM, que es QR y despues enlace. */
@media (max-width: 599.98px) {
    .carta-digital__rejilla {
        grid-template-columns: 1fr;
    }

    .carta-digital__enlace,
    .carta-digital__qr {
        grid-column: auto;
        grid-row: auto;
    }
}

/* --- Los QR de las mesas de un establecimiento (2026-09-27) ------------- */
/* docs/central/qr-de-mesa-2026-09-27.md §4. Las fichas de zona, la barra con
   «Todas» y las dos descargas, y una rejilla de tarjetas de mesa. */
.qr-mesas__zonas,
.qr-mesas__descargas,
.qr-mesas__botones {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
}

/* PNG y SVG en UNA linea debajo del QR. Con el hueco de .5rem los dos botones
   (94 + 93 px medidos) no caben en los 192 px de una tarjeta de 12rem y el
   segundo baja a otra linea: medido en el volcado del panel a 1280 px. */
.qr-mesas__botones {
    gap: .25rem;
    justify-content: center;
}

.qr-mesas__barra {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .25rem 1rem;
    margin: .75rem 0 .25rem;
}

.qr-mesas__descargas {
    margin-left: auto;
}

/* Tarjetas de 12rem: en 1280 px caben cinco o seis por fila, y en 375 px
   `min(12rem, 100%)` evita que la pista pida mas de lo que hay (el mismo fallo
   que la rejilla de la carta). */
.qr-mesas__rejilla {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(12rem, 100%), 1fr));
    gap: .75rem;
}

.qr-mesas__mesa {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .25rem;
    padding: .5rem;
    border: 1px solid var(--tentalo-borde);
    border-radius: 8px;
    text-align: center;
}

.qr-mesas__cabecera {
    display: flex;
    align-items: center;
    align-self: stretch;
    gap: .25rem;
    min-height: 44px;
}

.qr-mesas__rotulo {
    font-weight: 600;
    text-align: left;
    overflow-wrap: anywhere;
}

.qr-mesas__imagen {
    display: block;
    width: 160px;
    max-width: 100%;
    height: auto;
    border-radius: 4px;
    background: #FFFFFF;
}

/* En el movil las descargas dejan de irse a la derecha: debajo de «Todas». */
@media (max-width: 599.98px) {
    .qr-mesas__descargas {
        margin-left: 0;
    }
}

/* --- Los cobros de un establecimiento (Viva.com) ------------------------ */
/* El semaforo, los datos y los bloques del panel «Cobros». Reutiliza
   `.admin-comms-semaforo` y `.admin-insignia`, que ya significan lo mismo en
   comunicaciones y en almacen: aqui solo esta lo que anade. */

.cobros-estado {
    margin-bottom: .5rem;
}

/* Los datos de la cuenta: dos columnas de etiqueta/valor en escritorio y una en
   movil, igual que `.locales-central` de esta misma ficha. */
.cobros-datos {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
    gap: 0 1.5rem;
}

/* Cada tramo del panel -conectar, credenciales, terminales, cobros- separado por
   una linea. Son cuatro cosas distintas dentro de una tarjeta y sin la linea se
   leen como una lista larga de campos sueltos. */
.cobros-bloque {
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid var(--tentalo-borde);
}

/* EL FORMULARIO DE CREDENCIALES, EN DOS COLUMNAS. Son nueve campos cortos
   (identificadores y claves) y en una sola columna la tarjeta mide dos pantallas.

   minmax(min(20rem, 100%), 1fr) y no minmax(20rem, 1fr): con la pista fija, en
   375 px la columna pide 320 px dentro de un contenedor de 343 y el campo se
   sale. Es el mismo fallo que midio el modulo 2 en `.crud-secciones-dos` y el
   que arreglo la rejilla de la carta digital. */
.cobros-formulario {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
    gap: 0 1.5rem;
}

.cobros-campo {
    min-width: 0;
}

.cobros-acciones {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin: .5rem 0;
}

/* Los pasos del alta en Viva.com. Numerada porque el orden importa: sin la
   fuente de pago creada, las credenciales no cobran nada. */
.cobros-pasos {
    margin: .25rem 0 0;
    padding-left: 1.25rem;
    line-height: 1.6;
    font-size: .875rem;
}

.cobros-pasos > li {
    margin-bottom: .35rem;
}

/* El importe de un cobro, alineado a la derecha y con cifras de la misma anchura:
   una columna de dinero que no cuadra al ojo se repasa tres veces. */
.cobros-tabla .cobros-cifra {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* La devolucion se pide en una caja aparte y con fondo: es un formulario que sale
   DEBAJO de una tabla, y sin el fondo no se ve a que fila pertenece lo que se
   esta escribiendo. */
.cobros-devolucion {
    margin-top: .75rem;
    padding: .75rem;
    border: 1px solid var(--tentalo-borde);
    border-radius: 6px;
    background: #f2f5f3;
}

/* «Desconectar» va separado del resto por una linea, como «Regenerar enlace» de
   la carta: no es una accion mas, es la que deja al establecimiento sin cobrar. */
.cobros-peligro {
    margin-top: .75rem;
    padding-top: .75rem;
    border-top: 1px solid var(--tentalo-borde);
}

/* EN EL MOVIL, UNA COLUMNA. Las dos rejillas se deshacen: un campo de credencial
   a media anchura de 375 px no deja leer lo que se pega desde el portapapeles. */
@media (max-width: 599.98px) {
    .cobros-datos,
    .cobros-formulario {
        grid-template-columns: 1fr;
    }
}

/* Los tres pasos del alta de un local. Numerada porque el orden importa: sin el
   segundo paso el local existe y no sincroniza. */
.locales-alta-pasos {
    margin: 0 0 1rem;
    padding-left: 1.25rem;
    line-height: 1.6;
    font-size: .875rem;
}

.locales-alta-pasos > li {
    margin-bottom: .35rem;
}

/* Los cuatro campos de impresion de un documento en la ficha de un TPV, en una
   caja con su titulo: son cuatro bloques iguales y sin separarlos no se sabe
   donde acaba uno. */
.tpv-impresion {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 6px;
    padding: .75rem;
    margin-bottom: .75rem;
    min-width: 0;
}

/* Tanda T3 de «todo a Diseño»: cada HUECO (termico y de pagina) es su selector
   con sus botones debajo, pegados a la derecha, para que «Vista previa» y
   «Probar» se lean como del hueco de encima y no del documento entero. */
.tpv-impresion-hueco {
    min-width: 0;
}

.tpv-impresion-botones {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: .25rem;
    margin: -.25rem 0 .25rem;
}

/* «Cuándo» y las copias en una fila (las copias son un número de una cifra: no
   necesitan más que su rótulo), y el idioma debajo a todo el ancho. Tres en fila
   dejaban «Siempre» y «Español» cortados a una letra en la columna de la ficha. */
.tpv-impresion-fila {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 6.5rem;
    gap: 0 .75rem;
    min-width: 0;
}

/* --- Ajustes técnicos de un local (y Módulos y Reservas de su ficha) ------- */

/* AJUSTES COMPACTOS (2026-10-12, docs/central/ajustes-tecnicos-del-local-2026-10-10.md
   §3 ter). Antes cada campo medía 76 px de alto (el `min-height: 48px` de `.campo`
   sobre un <input> en content-box con el relleno de la etiqueta flotante, sin
   etiqueta) y ocupaba un tercio de la pantalla, fuera una hora o una URL.

   Ahora es el patrón de los grupos de platos del menú (`.menu-grupos`): campos de
   40 px con ratón y los 44 de --plano-toque con el dedo, el rótulo encima en una
   línea y el ancho DEL DATO (BloqueDeAjuste pone la clase): `-corta` (un número o
   una hora, 9rem), `-media` (un texto o un desplegable, su columna), `-ancha` (una
   dirección, un secreto o una lista, dos columnas si caben) y `-casilla` (la
   casilla con el rótulo como texto, en la misma línea).

   La rejilla es de columnas de 16rem como mínimo: cuatro a 1.440 px, una en un
   teléfono. Lo ancho pide dos columnas solo si la rejilla tiene dos (consulta de
   contenedor: lo que manda es el ancho de la sección, no el de la ventana). */
.config-claves {
    --ajuste-control: var(--plano-toque);
    container-type: inline-size;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(16rem, 100%), 1fr));
    gap: .5rem 1.5rem;
    align-items: start;
}

@media (pointer: fine) {
    .config-claves { --ajuste-control: 40px; }
}

@container (min-width: 34rem) {
    .config-claves > .config-clave-ancha { grid-column: span 2; }
}

/* Una nota suelta dentro de la rejilla (el reinicio de los módulos) va a todo el ancho. */
.config-claves > .campo-nota { grid-column: 1 / -1; margin: .25rem 0 0; }

.config-clave {
    display: flex;
    flex-direction: column;
    gap: .25rem;
    min-width: 0;
    padding: .5rem .75rem;
    border-radius: var(--plano-radio-control);
}

/* El control: sin los márgenes de `.campo` ni de MudBlazor, a la altura de la rejilla. */
.config-clave-control { min-width: 0; max-inline-size: 100%; }
.config-clave-corta .config-clave-control { inline-size: 9rem; }

.config-clave .campo,
.config-clave .mud-input-control { margin: 0; }

.config-clave .campo.mud-input-control,
.config-clave .campo .mud-input-root,
.config-clave .campo input.mud-input-slot { min-block-size: 0; }

.config-claves .config-clave .mud-input.mud-input-filled { min-block-size: var(--ajuste-control); }

/* Cinco clases y detrás de nada: gana al `padding-block: 8px` de `.ficha` (hoja-limpia.css, cuatro) en la ficha. */
.config-claves .config-clave .mud-input.mud-input-filled > input.mud-input-slot {
    box-sizing: border-box;
    block-size: var(--ajuste-control);
    padding-block: 0;
    padding-inline: 12px;
    text-overflow: ellipsis;
}

.config-claves .config-clave .campo .mud-input-adornment .mud-icon-button {
    min-block-size: 0;
    padding: 4px;
}

/* El secreto: el campo y «Poner una» / «Cambiar» en la misma línea. */
.config-clave .campo-secreto {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: .25rem .5rem;
}

.config-clave .campo-secreto > .mud-input-control { flex: 1 1 12rem; }

.config-claves .config-clave .campo-secreto .crud-boton.mud-button-root {
    min-block-size: var(--ajuste-control);
    block-size: var(--ajuste-control);
    min-inline-size: 0;
}

/* La casilla: el cuadro pegado al canto izquierdo del bloque, alineado con los rótulos
   de al lado, y su texto con el mismo peso que ellos. El objetivo sigue siendo de
   --ajuste-control (40/44 px): crece hacia fuera, no el dibujo. */
/* La fila de la casilla mide lo que su objetivo (40/44 px) pero se sube 8 px arriba y
   abajo: así su texto cae en la línea de los rótulos de al lado («Puerto de las
   cajas» | «☐ HTTPS en las cajas») sin encoger lo que se pulsa. */
.config-clave-casilla .config-clave-cabecera { flex-wrap: nowrap; margin-block: -8px; }

.config-clave-casilla .campo-casilla { margin: 0; min-width: 0; }

.config-clave-casilla .campo-casilla-control,
.config-clave-casilla .campo-casilla-control .mud-button-root {
    min-block-size: var(--ajuste-control);
    min-inline-size: 0;
}

/* Se corre con `left` y no con un margen negativo: el margen restaba 6 px al ancho que
   pide la casilla y el rótulo partía en dos líneas («API / HTTP»). */
.config-clave-casilla .campo-casilla-control { position: relative; inset-inline-start: -6px; }

.config-clave-casilla .campo-casilla-control .mud-typography {
    font-size: var(--plano-t-13);
    font-weight: 600;
    line-height: 1.3;
}

/* UNA CLAVE CAMBIADA SE MARCA CON AGUADA, NO CON UNA BANDA LATERAL (tanda 4).
   Llevaba 3 px de morado en el borde izquierdo, y eso es exactamente la «raya de
   acento» que este rediseño quita de todas partes: en este sistema una línea de
   2 px en dos lados es un MURO, y una banda de color de un solo lado deja de
   querer decir nada en cuanto hay las dos cosas en la misma pantalla.

   La aguada morada dice lo mismo —marca la región entera, que es como manda el
   color aquí— y sigue ACOMPANADA del chip «cambiada», porque el color solo no
   vale (WCAG 1.4.1). */
.config-clave-cambiada {
    background-color: var(--plano-morado-aguada);
}

.config-clave-cabecera {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .4rem;
    min-block-size: 1.5rem;
}

.config-clave-chip { block-size: 20px; font-size: var(--plano-t-12); }

/* El título de un grupo del avanzado y su ayuda, separado del grupo de arriba por una regla fina. */
.config-grupo-cabecera {
    margin: 1rem 0 .25rem;
    padding: .75rem .75rem 0;
    border-block-start: 1px solid var(--limpia-borde-fino);
}

.config-grupo-cabecera:first-child { margin-block-start: 0; padding-block-start: 0; border-block-start: none; }

.config-grupo-titulo { font-weight: 650; }

.config-grupo-ayuda { display: block; overflow-wrap: anywhere; }

/* EL ROTULO de un ajuste. Ya no es el nombre de la variable en monoespaciada
   -«EnableHttpKitchenDisplaySSL»- sino su nombre en castellano, asi que se
   escribe como texto del cuerpo y solo se le da peso: la monoespaciada decia
   «esto es codigo», y lo que se lee aqui es una frase. El nombre tecnico vive
   en el title, para el que lo necesite.

   Partible igualmente: «Fecha y hora al principio del nombre de los ficheros»
   no cabe en una columna de 20rem sin partir. */
.config-clave-nombre {
    font-size: var(--plano-t-13);
    font-weight: 600;
    line-height: 1.3;
    overflow-wrap: anywhere;
    min-width: 0;
}

/* El icono ↻ de un ajuste que no surte efecto hasta reiniciar. Sustituye al
   chip «requiere reinicio», que salia en 53 de las claves y llenaba la pantalla
   de ruido: el dato es el mismo, pero un icono con title cabe al lado del
   rotulo. El color lo pone MudBlazor (Color.Warning). */
.config-clave-reinicio {
    flex: 0 0 auto;
}

/* El pie: cuando se modifico el valor y quien lo puso, y «antes: X» si esta
   cambiado. Es lo ultimo del bloque y lo mas pequeno: se lee cuando hace falta
   saber de donde sale un valor raro. */
.config-clave-pie {
    display: block;
    color: var(--limpia-tinta-3);
    font-size: var(--plano-t-12);
    line-height: 1.35;
    overflow-wrap: anywhere;
}

/* La ayuda de una clave. Va DEBAJO del control y encima del pie: lo que hay que
   leer antes de escribir un numero, no un dato de la fila. Sin cursiva desde el
   2026-10-12 (en tres renglones de 12 px se leía mal): se distingue del pie por
   el color (tinta-2 la ayuda, tinta-3 el pie) y por ir antes. */
.config-clave-ayuda {
    display: block;
    color: var(--limpia-tinta-2);
    font-size: var(--plano-t-12);
    line-height: 1.35;
    overflow-wrap: anywhere;
}

/* --- Impuestos ------------------------------------------------------------- */

/* La tabla de los diez IVA lleva campos DENTRO de las celdas, y un campo denso
   de MudBlazor mide 40 px de alto: por debajo de los 48 px de la regla 3 del
   sistema de diseno. Se corrige creciendo la caja y no el dibujo, igual que hizo
   el modulo 2 con sus nueve controles. */
.impuestos-tabla .mud-input-control {
    min-height: 48px;
}

.impuestos-tabla .mud-table-cell {
    padding-top: .25rem;
    padding-bottom: .25rem;
}

/* La columna del nombre no puede quedarse en su min-content: con
   table-layout: auto y cinco campos, el navegador le daba 90 px y el nombre
   «Reducido 10%» no cabia. */
.impuestos-tabla .mud-table-cell:nth-child(2) {
    min-width: 12rem;
}

/* --- Modulo 2, parte 2: ofertas y menus ------------------------------------ */

/* Dos campos que van JUNTOS en una linea y se apilan en un movil: el «desde /
   hasta» de una oferta y sus dos cantidades («se lleva 3, paga 2»). No se usa
   .crud-precios-fila porque esa lleva el nombre de la tarifa delante y reparte
   el ancho de otra manera. */
.crud-fechas {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.crud-fechas > * {
    flex: 1 1 12rem;
    min-width: 0;
}

.crud-modificacion-fechas {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-bottom: 0.5rem;
}

.crud-modificacion-fechas > * {
    flex: 1 1 10rem;
    min-width: 0;
}

/* La programacion de una oferta reusa .crud-horario (los horarios de una
   categoria), pero es UNA sola y no una lista: sin la raya de separacion de
   abajo, que ahi separaba una fila de la siguiente y aqui no separa nada. */
.crud-horario-oferta {
    border-bottom: none;
    padding-bottom: 0;
}

/* LOS GRUPOS DE PLATOS DE UN MENU (EditorGruposDeMenu; rediseño compacto del 2026-10-10).
   Una <table> propia: una fila de 52 px por grupo con todo en la misma línea, sin etiquetas dentro
   de las celdas (la cabecera nombra la columna y cada campo lleva su aria-label). Anchos con
   sentido: el orden y el paso de platos estrechos y fijos, el nombre al 17 %, la categoría (la que
   trae los nombres más largos) al 36 % y el pase con el resto. Por debajo de 640 px cada grupo es una tarjeta.
   Solo fichas --limpia-* y --plano-*: el oscuro sale solo.

   La altura de los campos: 40 px con ratón (la fila de la lista común es de 40 y WCAG 2.5.8 pide
   24); con el dedo, los 44 de --plano-toque. */
.menu-grupos { --mg-control: var(--plano-toque); }

@media (pointer: fine) {
    .menu-grupos { --mg-control: 40px; }
}

.menu-grupos-oculto {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.menu-grupos-caja {
    overflow-x: auto;
    border: 1px solid var(--limpia-borde);
    border-radius: var(--limpia-radio);
    background-color: var(--limpia-hoja);
}

.menu-grupos-tabla {
    inline-size: 100%;
    min-inline-size: 720px;
    table-layout: fixed;
    border-collapse: separate;
    border-spacing: 0;
    font-size: var(--plano-t-13);
    color: var(--limpia-tinta);
}

.menu-grupos-tabla thead th {
    padding: 8px;
    background-color: var(--limpia-cabecera);
    border-block-end: 1px solid var(--limpia-borde);
    color: var(--limpia-tinta-3);
    font-size: var(--plano-t-11);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    text-align: start;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.menu-grupos-tabla thead th:first-child { padding-inline-start: 12px; }

.menu-grupos-tabla th.menu-grupos-col-orden { inline-size: 76px; }
.menu-grupos-tabla th.menu-grupos-col-nombre { inline-size: 17%; }
.menu-grupos-tabla th.menu-grupos-col-categoria { inline-size: 36%; }
.menu-grupos-tabla th.menu-grupos-col-platos { inline-size: 128px; }
.menu-grupos-tabla th.menu-grupos-col-quitar { inline-size: 52px; }

.menu-grupos-tabla tbody td {
    padding: 6px 8px;
    vertical-align: middle;
    border-block-end: 1px solid var(--limpia-borde-fino);
    min-inline-size: 0;
}

.menu-grupos-tabla tbody tr:last-child td { border-block-end: none; }
.menu-grupos-tabla tbody tr:hover td { background-color: var(--limpia-hover); }
.menu-grupos-tabla tbody td.menu-grupos-col-orden { padding-inline-start: 12px; }

/* Los campos: sin el hueco de debajo de .campo ni el margen de MudBlazor, a la altura de la fila. */
.menu-grupos-tabla .campo,
.menu-grupos-tabla .mud-input-control { margin: 0; }

.menu-grupos-tabla .campo .mud-input-control,
.menu-grupos-tabla .campo .mud-input-root,
.menu-grupos-tabla .campo input.mud-input-slot {
    min-block-size: var(--mg-control);
}

.menu-grupos-tabla .mud-input.mud-input-filled > input.mud-input-slot {
    box-sizing: border-box;
    block-size: var(--mg-control);
    padding-block: 0;
    text-overflow: ellipsis;
}

.menu-grupos-tabla .campo .mud-input-adornment .mud-icon-button {
    min-block-size: 0;
    padding: 4px;
}

/* El orden: el número en una pastilla y ↑ ↓ apiladas a su lado. */
.menu-grupos-col-orden { white-space: nowrap; }

.menu-grupos-numero {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 26px;
    block-size: 26px;
    border-radius: 6px;
    background-color: var(--limpia-morado-aguada);
    color: var(--limpia-morado);
    font-size: var(--plano-t-13);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    vertical-align: middle;
}

.menu-grupos-flechas {
    display: inline-flex;
    flex-direction: column;
    margin-inline-start: 4px;
    vertical-align: middle;
}

.menu-grupos-flecha,
.menu-grupos-flecha-hueco {
    inline-size: 28px;
    block-size: 20px;
}

.menu-grupos-flecha,
.menu-grupos-quitar,
.menu-grupos-paso-boton {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: none;
    color: var(--limpia-tinta-2);
    cursor: pointer;
    transition: background-color 150ms ease, color 150ms ease;
}

.menu-grupos-flecha:hover,
.menu-grupos-paso-boton:hover:not([aria-disabled="true"]) {
    background-color: var(--limpia-morado-aguada);
    color: var(--limpia-morado);
}

:is(.menu-grupos-flecha, .menu-grupos-quitar, .menu-grupos-paso-boton):focus-visible {
    outline: 2px solid var(--limpia-morado);
    outline-offset: 1px;
}

/* El número de platos: − 2 + en una sola caja del alto de los campos. */
.menu-grupos-paso {
    display: inline-flex;
    align-items: stretch;
    block-size: var(--mg-control);
    border-radius: var(--limpia-radio-control);
    box-shadow: inset 0 0 0 1px var(--limpia-borde-control);
    background-color: var(--limpia-hoja);
}

.menu-grupos-paso:focus-within { box-shadow: inset 0 0 0 2px var(--limpia-morado); }

.menu-grupos-paso-boton { inline-size: 32px; }
.menu-grupos-paso-boton[aria-disabled="true"] { color: var(--limpia-borde-control); cursor: default; }

.menu-grupos-paso-valor {
    inline-size: 3ch;
    min-inline-size: 36px;
    padding: 0;
    border: none;
    background: none;
    color: var(--limpia-tinta);
    font: inherit;
    font-size: 0.875rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    text-align: center;
    appearance: textfield;
    -moz-appearance: textfield;
}

.menu-grupos-paso-valor::-webkit-inner-spin-button,
.menu-grupos-paso-valor::-webkit-outer-spin-button { appearance: none; margin: 0; }
.menu-grupos-paso-valor:focus { outline: none; }

/* La papelera: discreta, roja solo al pasar o al enfocar. */
.menu-grupos-col-quitar { text-align: end; }

.menu-grupos-quitar {
    inline-size: 36px;
    block-size: 36px;
    color: var(--limpia-tinta-3);
}

.menu-grupos-quitar:hover,
.menu-grupos-quitar:focus-visible {
    background-color: var(--limpia-error-fondo);
    color: var(--limpia-error-tinta);
}

.menu-grupos-anadir { margin-block-start: 12px; }

/* EL SISTEMA DE MENÚS, FASE 1 (2026-10-14; boceto 1 de reports/central/bocetos-menus-2026-10-14/, aprobado). Los grupos de
   platos como TARJETAS (EditorGruposDeMenu), «Cuándo y dónde» (CuandoYDondeDelMenu) y la columna de «Así se vende» y «Así se
   reparte» (ResumenDelMenu). Densidad de la central: filas de 40 px con ratón y 44 con el dedo (--mg-control, de .menu-grupos),
   textos de 13 px, sin sombras; solo fichas --limpia-* y --plano-*: el oscuro sale solo. A 640 px o menos, las tarjetas se
   pliegan (se toca el número) y la columna de la derecha baja debajo. */
.mg-con-lado {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(16rem, 21rem);
    gap: 16px;
    align-items: start;
}

@media (max-width: 1100px) {
    .mg-con-lado { grid-template-columns: minmax(0, 1fr); }
}

.mg-principal { min-inline-size: 0; display: flex; flex-direction: column; gap: 8px; }

.mg-lista {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 26rem), 1fr));
    gap: 12px;
}

.mg-tarjeta {
    min-inline-size: 0;
    border: 1px solid var(--limpia-borde);
    border-radius: var(--limpia-radio);
    background-color: var(--limpia-hoja);
    color: var(--limpia-tinta);
    font-size: var(--plano-t-13);
}

.mg-cabecera {
    display: flex;
    align-items: center;
    gap: 8px;
    min-block-size: calc(var(--mg-control) + 12px);
    padding: 6px 8px 6px 10px;
    border-block-end: 1px solid var(--limpia-borde-fino);
}

.mg-pliegue {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: none;
    background: none;
    cursor: default;
}

.mg-numero {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 26px;
    block-size: 26px;
    border-radius: 6px;
    background-color: var(--limpia-morado-aguada);
    color: var(--limpia-morado);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.mg-nombre {
    flex: 1 1 8rem;
    min-inline-size: 0;
    block-size: var(--mg-control);
    padding: 0 8px;
    border: 1px solid transparent;
    border-radius: var(--limpia-radio-control);
    background: none;
    color: var(--limpia-tinta);
    font: inherit;
    font-size: 0.9375rem;
    font-weight: 700;
    text-overflow: ellipsis;
}

.mg-nombre:hover { border-color: var(--limpia-borde-control); }
.mg-nombre:focus { outline: none; border-color: var(--limpia-morado); box-shadow: inset 0 0 0 1px var(--limpia-morado); }

.mg-regla,
.mg-pastilla {
    display: inline-flex;
    align-items: center;
    block-size: 24px;
    padding: 0 8px;
    border-radius: 12px;
    font-size: var(--plano-t-11);
    font-weight: 700;
    white-space: nowrap;
}

.mg-regla { background-color: var(--limpia-morado-aguada); color: var(--limpia-morado); }
.mg-pastilla { background-color: var(--limpia-neutro-fondo); color: var(--limpia-neutro-tinta); }
.mg-pastilla-info { background-color: var(--limpia-aviso-fondo); color: var(--limpia-aviso-tinta); }
.mg-pastilla-bien { background-color: var(--limpia-bien-fondo); color: var(--limpia-bien-tinta); margin-inline-start: 6px; }

.mg-hueco { flex: 1 1 0; }

.mg-flechas { display: inline-flex; }

.mg-icono {
    inline-size: 32px;
    block-size: 32px;
}

.mg-cuerpo { padding: 8px 10px 10px; display: flex; flex-direction: column; gap: 8px; }

.mg-reglas {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
}

.mg-regla-campo { display: inline-flex; align-items: center; gap: 6px; }

/* LOS PASES DE LOS GRUPOS (2026-10-17). El pase va en su línea bajo el nombre y FUERA del pliegue (en el teléfono se ve también con
   la tarjeta plegada): el rótulo pequeño, el desplegable de 40 px («2.º EMPIEZA») y, si toca, «Propuesto» y la frase del aviso. Los
   avisos de todo el menú, encima de las tarjetas, en el tono de aviso de la hoja (mostaza; el oscuro sale de las fichas). */
.mg-pase-linea {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    padding: 6px 10px;
    border-block-end: 1px solid var(--limpia-borde-fino);
}
.mg-pase-campo { flex: 0 1 15rem; min-inline-size: 9rem; }
.mg-pase-campo .campo { margin: 0; }
.mg-pastilla-propuesto { background-color: var(--limpia-morado-aguada); color: var(--limpia-morado); }
.mg-pase-aviso { flex: 1 1 100%; color: var(--limpia-aviso-tinta); font-size: var(--plano-t-12); font-weight: 600; }
.mg-pase-le-toca { font-weight: 700; }
.mg-con-aviso { box-shadow: inset 3px 0 0 var(--limpia-aviso-tinta); }

.mg-avisos {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin-block-end: 12px;
    padding: 8px 10px;
    border-radius: var(--limpia-radio);
    background-color: var(--limpia-aviso-fondo);
    color: var(--limpia-aviso-tinta);
    font-size: var(--plano-t-13);
}
.mg-avisos-icono { flex: none; margin-block-start: 1px; }
.mg-avisos-cuerpo { display: flex; flex-direction: column; gap: 6px; min-inline-size: 0; }
.mg-avisos-lista { margin: 0; padding-inline-start: 16px; }
.mg-avisos-lista li + li { margin-block-start: 2px; }
.mg-avisos-enlace { margin-inline-start: 4px; color: inherit; font-weight: 700; }
.mg-avisos-boton { align-self: flex-start; }

.mg-rotulo {
    color: var(--limpia-tinta-3);
    font-size: var(--plano-t-11);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
}

.mg-interruptor {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-block-size: var(--mg-control);
    cursor: pointer;
    font-weight: 600;
}

.mg-interruptor input { inline-size: 18px; block-size: 18px; accent-color: var(--limpia-morado); }

.mg-cifra {
    inline-size: 5.5rem;
    block-size: var(--mg-control);
    padding: 0 8px;
    border: none;
    border-radius: var(--limpia-radio-control);
    box-shadow: inset 0 0 0 1px var(--limpia-borde-control);
    background-color: var(--limpia-hoja);
    color: var(--limpia-tinta);
    font: inherit;
    font-variant-numeric: tabular-nums;
    text-align: end;
}

.mg-cifra:focus { outline: none; box-shadow: inset 0 0 0 2px var(--limpia-morado); }
.mg-cifra::placeholder { color: var(--limpia-tinta-3); }

.mg-platos {
    inline-size: 100%;
    border-collapse: collapse;
    table-layout: fixed;
}

.mg-platos thead th {
    padding: 4px 4px 6px;
    color: var(--limpia-tinta-3);
    font-size: var(--plano-t-11);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-align: start;
    text-transform: uppercase;
}

.mg-platos td {
    padding: 3px 4px;
    border-block-start: 1px solid var(--limpia-borde-fino);
    vertical-align: middle;
}

.mg-platos .mg-col-suplemento { inline-size: 6.5rem; text-align: end; }
.mg-platos .mg-col-omision,
.mg-platos .mg-col-quitar { inline-size: 40px; text-align: center; }

.mg-plato { display: flex; align-items: center; min-inline-size: 0; }
.mg-plato-nombre { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.mg-omision {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 36px;
    block-size: 36px;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: none;
    color: var(--limpia-tinta-3);
    cursor: pointer;
}

.mg-omision[aria-pressed="true"] { color: var(--limpia-morado); }
.mg-omision:hover,
.mg-omision:focus-visible { background-color: var(--limpia-morado-aguada); outline: none; }

.mg-anadir,
.mg-categoria {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.mg-anadir-campo,
.mg-categoria-campo { flex: 1 1 12rem; min-inline-size: 0; }
.mg-anadir-campo .campo,
.mg-categoria-campo .campo { margin: 0; }

.mg-boton {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--mg-control);
    padding: 0 12px;
    border: 1px solid var(--limpia-borde-control);
    border-radius: var(--limpia-radio-control);
    background-color: var(--limpia-hoja);
    color: var(--limpia-morado);
    font: inherit;
    font-weight: 700;
    cursor: pointer;
    white-space: nowrap;
}

.mg-boton:hover { background-color: var(--limpia-morado-aguada); }
.mg-boton:focus-visible { outline: 2px solid var(--limpia-morado); outline-offset: 1px; }

/* A 640 px o menos: la tarjeta se pliega por el número (44 px de toque) y la cabecera parte línea si hace falta. */
@media (max-width: 640px) {
    .mg-pliegue { inline-size: 44px; block-size: 44px; cursor: pointer; }
    .mg-cabecera { flex-wrap: wrap; }
    .mg-plegada .mg-cuerpo { display: none; }
    .mg-platos .mg-col-suplemento { inline-size: 5.5rem; }
    .mg-cifra { inline-size: 4.75rem; }
}

/* «Cuándo y dónde»: franjas con los días como botones de 44 px y las horas al lado; los canales como botones que se marcan. */
.mg-cuando { display: flex; flex-direction: column; gap: 16px; }
.mg-cuando-zona { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }

.mg-subtitulo {
    margin: 0;
    color: var(--limpia-tinta-2);
    font-size: var(--plano-t-13);
    font-weight: 700;
}

.mg-nota { margin: 0; color: var(--limpia-tinta-3); font-size: var(--plano-t-13); max-inline-size: 70ch; }

.mg-franja { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.mg-dias,
.mg-canales { display: inline-flex; flex-wrap: wrap; gap: 4px; }

.mg-dia,
.mg-canal {
    min-inline-size: 44px;
    min-block-size: 44px;
    padding: 0 10px;
    border: 1px solid var(--limpia-borde-control);
    border-radius: var(--limpia-radio-control);
    background-color: var(--limpia-hoja);
    color: var(--limpia-tinta-2);
    font: inherit;
    font-weight: 700;
    cursor: pointer;
}

.mg-dia[aria-pressed="true"],
.mg-canal[aria-pressed="true"] {
    border-color: var(--limpia-morado);
    background-color: var(--limpia-morado);
    color: var(--limpia-sobre-morado);
}

.mg-dia:focus-visible,
.mg-canal:focus-visible { outline: 2px solid var(--limpia-morado); outline-offset: 1px; }

.mg-horas { display: inline-flex; align-items: center; gap: 6px; }

.mg-hora {
    block-size: 44px;
    padding: 0 8px;
    border: none;
    border-radius: var(--limpia-radio-control);
    box-shadow: inset 0 0 0 1px var(--limpia-borde-control);
    background-color: var(--limpia-hoja);
    color: var(--limpia-tinta);
    font: inherit;
    font-variant-numeric: tabular-nums;
}

/* La columna de la derecha: «Así se vende» y «Así se reparte». */
.mg-aparte { min-inline-size: 0; }
.mg-resumen { display: flex; flex-direction: column; gap: 12px; }

.mg-lado {
    padding: 12px 14px;
    border: 1px solid var(--limpia-borde);
    border-radius: var(--limpia-radio);
    background-color: var(--limpia-hoja);
    color: var(--limpia-tinta);
    font-size: var(--plano-t-13);
}

.mg-lado-titulo {
    margin: 0 0 6px;
    color: var(--limpia-tinta-2);
    font-size: var(--plano-t-11);
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

.mg-lado-sub { font-weight: 500; letter-spacing: 0; text-transform: none; }
.mg-lado-frase { margin: 0 0 4px; font-weight: 700; }
.mg-lado-texto { margin: 0 0 6px; }
.mg-lado-reglas { margin: 0; padding-inline-start: 18px; color: var(--limpia-tinta-2); }
.mg-lado-nota { margin: 6px 0 0; color: var(--limpia-tinta-3); font-size: var(--plano-t-11); }
.mg-lado-aviso { margin: 8px 0 0; padding: 6px 8px; border-radius: 6px; background: var(--limpia-error-fondo); color: var(--limpia-error-tinta); font-size: var(--plano-t-12, .75rem); }

.mg-reparto { inline-size: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.mg-reparto th { padding: 2px; color: var(--limpia-tinta-3); font-size: var(--plano-t-11); font-weight: 600; text-align: start; }
.mg-reparto td { padding: 4px 2px; border-block-start: 1px solid var(--limpia-borde-fino); }
.mg-reparto .mg-num { text-align: end; white-space: nowrap; }
.mg-reparto-total td { font-weight: 700; }

/* «Precio y reparto»: el método, dos opciones de radio con su explicación. */
.mg-metodo { display: flex; flex-direction: column; gap: 6px; }
.mg-opcion { display: flex; align-items: flex-start; gap: 8px; min-block-size: 32px; cursor: pointer; }
.mg-opcion input { margin-block-start: 3px; inline-size: 18px; block-size: 18px; accent-color: var(--limpia-morado); }

/* La lista de un desplegable en celda (CampoDesplegable EnCelda): tan ancha como el campo como
   poco y, si el nombre es más largo, más ancha hasta un tope; el nombre entero, a dos líneas si
   hace falta, y los «EMPIEZA--------» del sistema anterior parten donde haga falta en vez de ensanchar. */
.campo-en-celda-lista { max-inline-size: min(28rem, calc(100vw - 32px)); }

.campo-en-celda-opcion {
    white-space: normal;
    overflow-wrap: anywhere;
}

/* EL SISTEMA DE MENÚS, FASE 3 (2026-10-16). «Cómo se vende» en la ficha del menú (grupo o evento, degustación, «Hazlo menú», la
   comanda y el enlace al planificador). */
.mg-como { display: flex; flex-direction: column; gap: 4px; padding: 8px 10px; border: 1px dashed var(--limpia-borde); border-radius: var(--limpia-radio); }
.mg-como-comensales { padding-inline-start: 34px; }
.mg-planificar { align-self: flex-start; text-decoration: none; margin-block-start: 4px; }

/* EL PLANIFICADOR DE MENÚS (AdminPlanificadorDeMenus): la rejilla de la semana en escritorio (grupos en filas, días en columnas) y,
   a 900 px o menos, los días como pestañas de 44 px y los grupos uno debajo de otro. Densidad de la central (40 px con ratón, 44 con
   el dedo), textos de 13 px, sin sombras; solo fichas --limpia-* y --plano-*. El cartel solo se ve al imprimir. */
.pm { --mg-control: var(--plano-toque); display: flex; flex-direction: column; gap: 12px; min-inline-size: 0; font-size: var(--plano-t-13); }

@media (pointer: fine) {
    .pm { --mg-control: 40px; }
}

.pm-barra, .pm-acciones, .pm-plantillas, .pm-semana { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.pm-barra { justify-content: space-between; }
.pm-campo-menu { flex: 1 1 16rem; max-inline-size: 28rem; min-inline-size: 0; }
.pm-campo-menu .campo, .pm-plantilla-campo .campo { margin: 0; }
.pm-plantilla-campo { min-inline-size: 10rem; }
.pm-semana-texto { min-inline-size: 13rem; text-align: center; font-weight: 700; color: var(--limpia-tinta); }

.pm-icono {
    display: inline-flex; align-items: center; justify-content: center;
    inline-size: var(--mg-control); block-size: var(--mg-control);
    padding: 0; border: 1px solid var(--limpia-borde-control); border-radius: var(--limpia-radio-control);
    background-color: var(--limpia-hoja); color: var(--limpia-morado); cursor: pointer;
}

.pm-icono:hover { background-color: var(--limpia-morado-aguada); }
.pm-icono:focus-visible { outline: 2px solid var(--limpia-morado); outline-offset: 1px; }
.pm-acciones .mg-boton[disabled] { opacity: .5; cursor: default; }

.pm-texto, .pm-buscar {
    block-size: var(--mg-control); min-inline-size: 0; padding: 0 8px; border: none; border-radius: var(--limpia-radio-control);
    box-shadow: inset 0 0 0 1px var(--limpia-borde-control); background-color: var(--limpia-hoja); color: var(--limpia-tinta); font: inherit;
}

.pm-texto { inline-size: 13rem; }
.pm-texto:focus, .pm-buscar:focus { outline: none; box-shadow: inset 0 0 0 2px var(--limpia-morado); }

.pm-rejilla { overflow-x: auto; border: 1px solid var(--limpia-borde); border-radius: var(--limpia-radio); background-color: var(--limpia-hoja); }
.pm-tabla { inline-size: 100%; min-inline-size: 960px; border-collapse: collapse; table-layout: fixed; }
.pm-tabla th, .pm-tabla td { padding: 6px; border-block-end: 1px solid var(--limpia-borde-fino); border-inline-end: 1px solid var(--limpia-borde-fino); vertical-align: top; text-align: start; }
.pm-tabla thead th { color: var(--limpia-tinta-3); font-size: var(--plano-t-11); font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
.pm-tabla .pm-col-grupo { inline-size: 9.5rem; }
.pm-tabla th.pm-col-grupo { display: table-cell; }
.pm-tabla tbody th { color: var(--limpia-tinta); }
.pm-tabla .pm-hoy { background-color: var(--limpia-morado-aguada); }
.pm-grupo-nombre { display: block; margin-block-end: 4px; font-weight: 700; overflow-wrap: anywhere; }
.pm-no-vende { display: block; color: var(--limpia-tinta-3); font-weight: 500; text-transform: none; letter-spacing: 0; }

.pm-celda { display: flex; flex-direction: column; align-items: stretch; gap: 4px; min-inline-size: 0; }
.pm-celda--sin-venta { opacity: .55; }

.pm-plato {
    display: flex; flex-wrap: wrap; align-items: center; gap: 2px; min-inline-size: 0;
    border: 1px solid var(--limpia-borde-control); border-radius: var(--limpia-radio-control); background-color: var(--limpia-hoja);
}

.pm-plato--fijo { padding: 4px 8px; border-style: dashed; color: var(--limpia-tinta-3); }

.pm-plato-nombre {
    flex: 1 1 auto; min-inline-size: 0; min-block-size: var(--mg-control); padding: 2px 8px; border: none; background: none;
    color: var(--limpia-tinta); font: inherit; text-align: start; overflow-wrap: anywhere; cursor: pointer;
}

.pm-plato-nombre:focus-visible, .pm-quitar:focus-visible, .pm-anadir:focus-visible, .pm-opcion:focus-visible,
.pm-dia:focus-visible { outline: 2px solid var(--limpia-morado); outline-offset: 1px; }

.pm-sup { margin-inline-start: 4px; color: var(--limpia-morado); font-variant-numeric: tabular-nums; white-space: nowrap; }

.pm-quitar {
    display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
    inline-size: var(--mg-control); block-size: var(--mg-control); padding: 0; border: none; border-radius: 6px;
    background: none; color: var(--limpia-tinta-3); cursor: pointer;
}

.pm-quitar:hover { background-color: var(--limpia-error-fondo); color: var(--limpia-error-tinta); }
.pm-sup-campo { inline-size: 100%; }

.pm-anadir {
    min-block-size: var(--mg-control); padding: 0 8px; border: 1px dashed var(--limpia-borde-control); border-radius: var(--limpia-radio-control);
    background: none; color: var(--limpia-morado); font: inherit; font-weight: 700; text-align: start; cursor: pointer;
}

.pm-anadir:hover { background-color: var(--limpia-morado-aguada); }

.pm-falta {
    align-self: flex-start; padding: 2px 8px; border-radius: 12px; background-color: var(--limpia-error-fondo); color: var(--limpia-error-tinta);
    font-size: var(--plano-t-11); font-weight: 700;
}

.pm-elegir { display: flex; flex-direction: column; gap: 4px; padding: 6px; border: 1px solid var(--limpia-morado); border-radius: var(--limpia-radio-control); background-color: var(--limpia-hoja); }
.pm-opciones { display: flex; flex-direction: column; gap: 2px; max-block-size: 16rem; overflow-y: auto; }

.pm-opcion {
    min-block-size: var(--mg-control); padding: 4px 8px; border: none; border-radius: 6px; background: none;
    color: var(--limpia-tinta); font: inherit; text-align: start; overflow-wrap: anywhere; cursor: pointer;
}

.pm-opcion:hover { background-color: var(--limpia-morado-aguada); }
.pm-cerrar { align-self: flex-end; }

/* Los días como pestañas y la vista del día: solo a 900 px o menos. */
.pm-dias, .pm-movil { display: none; }

.pm-dia {
    display: inline-flex; flex-direction: column; align-items: center; justify-content: center; flex: 1 1 0;
    min-inline-size: 44px; min-block-size: 52px; padding: 2px; border: 1px solid var(--limpia-borde-control);
    border-radius: var(--limpia-radio-control); background-color: var(--limpia-hoja); color: var(--limpia-tinta-2); font: inherit; cursor: pointer;
}

.pm-dia[aria-selected="true"] { border-color: var(--limpia-morado); background-color: var(--limpia-morado); color: var(--limpia-sobre-morado); }
.pm-dia--hoy .pm-dia-numero { text-decoration: underline; }
.pm-dia--sin-venta { opacity: .55; }
.pm-dia-nombre { font-size: var(--plano-t-11); text-transform: uppercase; }
.pm-dia-numero { font-size: 1rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.pm-dia-titulo { margin: 0; font-size: 1rem; font-weight: 700; color: var(--limpia-tinta); }
.pm-grupo { display: flex; flex-direction: column; gap: 6px; padding: 10px; border: 1px solid var(--limpia-borde); border-radius: var(--limpia-radio); background-color: var(--limpia-hoja); }
.pm-grupo .pm-grupo-nombre { display: flex; align-items: center; gap: 8px; margin: 0; font-size: var(--plano-t-13); }

@media (max-width: 900px) {
    .pm-rejilla { display: none; }
    .pm-dias { display: flex; gap: 4px; }
    .pm-movil { display: flex; flex-direction: column; gap: 10px; }
    .pm-semana-texto { min-inline-size: 0; flex: 1 1 10rem; }
    .pm-texto { inline-size: 100%; flex: 1 1 10rem; }
    .pm-acciones > .mg-boton, .pm-guardar { flex: 1 1 auto; }
}

@media (max-width: 640px) {
    .pm { --mg-control: 44px; }
    .pm-plantillas { inline-size: 100%; }
}

/* EL CARTEL: no se ve en la pantalla; al imprimir, es lo único que sale. */
.pm-cartel { display: none; }

@media print {
    body * { visibility: hidden; }
    .pm-cartel, .pm-cartel * { visibility: visible; }
    .pm-cartel { display: block; position: absolute; inset: 0 auto auto 0; inline-size: 100%; padding: 24px; color: #000; background: #fff; text-align: center; }
    .pm-cartel-titulo { margin: 0 0 4px; font-size: 32px; }
    .pm-cartel-dia { margin: 0 0 8px; font-size: 18px; text-transform: capitalize; }
    .pm-cartel-precio { margin: 0 0 16px; font-size: 28px; font-weight: 700; }
    .pm-cartel-grupo { margin: 16px 0 4px; font-size: 18px; text-transform: uppercase; letter-spacing: .06em; }
    .pm-cartel-platos { margin: 0; padding: 0; list-style: none; font-size: 18px; line-height: 1.5; }
    .pm-cartel-sup { margin-inline-start: 6px; font-size: 14px; }
}

/* La X de vaciar un desplegable en celda solo al pasar o con el foco: fija, se comía 40 px del
   texto en cada fila. */
.campo-en-celda:not(:hover):not(:focus-within) .mud-input-clear-button { display: none; }

/* LAS TABLAS QUE SE ESCRIBEN DE ALMACÉN, COMO «GRUPOS DE PLATOS» (2026-10-11, rama central/etiquetas-en-celdas).
   Las líneas de un pedido y de una entrega y las unidades adicionales repetían la etiqueta de cada campo dentro
   de la celda («Cantidad», «Precio», «Dto. %», «Dto. €», «Nombre», «Factor») bajo la cabecera que ya la decía:
   la fila medía 98-113 px, los campos quedaban 9-10 px por debajo del texto de la fila y en el pedido ocho
   números salían cortados. Con CampoNumero/CampoTexto en celda (EnCelda) ya no hay etiqueta; aquí se dejan los
   campos a la altura de la fila (40 px con ratón, 44 con el dedo) y las cifras a la derecha, como su cabecera.
   El ámbito es «.admin-tabla con un campo en celda»: ninguna otra tabla cambia. */
.admin-tabla:has(tbody .campo-en-celda) { --ec-control: var(--plano-toque); }

@media (pointer: fine) {
    .admin-tabla:has(tbody .campo-en-celda) { --ec-control: 40px; }
}

/* Sin el margen de .campo ni sus 48 px de alto mínimo (la regla 3 de diseno-web.md es para un campo con su
   etiqueta encima): el control mide lo que su campo, y la fila, campo + 12 px. */
.admin-tabla .mud-table-cell .campo-en-celda,
.admin-tabla .mud-table-cell .campo-en-celda.mud-input-control { margin: 0; min-block-size: 0; }

.admin-tabla .campo-en-celda .mud-input-root,
.admin-tabla .campo-en-celda input.mud-input-slot { min-block-size: var(--ec-control); }

.admin-tabla .campo-en-celda .mud-input.mud-input-filled > input.mud-input-slot {
    box-sizing: border-box;
    block-size: var(--ec-control);
    padding-block: 0;
    text-overflow: ellipsis;
}

@media (min-width: 720px) {
    .admin-tabla:has(tbody .campo-en-celda) .mud-table-body .mud-table-cell {
        padding-block: 6px;
        vertical-align: middle;
    }

    /* La cifra, a la derecha y en una columna estrecha y fija (7,5rem caben «1000000,000»), y el sitio que deja,
       para el nombre del producto: con 8,5rem por cifra el pedido partía «Aceite de oliva virgen extra (garrafa
       de 5 l)» en cinco renglones. */
    .admin-tabla .crud-celda-numero:has(.campo-en-celda) { inline-size: 7.5rem; min-inline-size: 7.5rem; }
    .admin-tabla:has(tbody .campo-en-celda) .mud-table-body .mud-table-cell:first-child:not(:has(input)) { min-inline-size: 16rem; }
    /* Reparto por contenido y no a partes iguales (table-layout: fixed daba 135 px a cada una de las ocho columnas
       del pedido, también al producto y a la papelera). */
    .admin-tabla:has(tbody .campo-en-celda) .mud-table-root { table-layout: auto; }

    /* La unidad, el importe y el resto del texto corto de la fila, en un renglón («Garrafa 5 l» partía la «l»). */
    .admin-tabla:has(tbody .campo-en-celda) .mud-table-body .mud-table-cell:not(:first-child):not(:has(input)) { white-space: nowrap; }
    .admin-tabla .crud-celda-numero .campo-en-celda input.mud-input-slot { text-align: end; }
}

/* EN EL TELÉFONO, UNA TARJETA POR FILA (como los grupos de platos). plano.css ya apila la fila y pinta el rótulo
   de la columna (data-label) encima de cada campo —ahora el único nombre visible, porque el campo no trae el
   suyo—; aquí la fila pasa a ser una tarjeta con los campos de dos en dos y la papelera arriba a la derecha, en
   vez de un renglón para ella sola al pie. Los selectores llevan los dos :has —el de plano.css y el del campo en
   celda— para ganarle a la regla que apila (más específica que un :has solo). «screen and» no cambia nada en
   pantalla y deja este bloque fuera de las pruebas que leen EL bloque «@media (max-width: 719.98px)» de esta hoja. */
@media screen and (max-width: 719.98px) {
    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)):has(tbody .campo-en-celda) .mud-table-body .mud-table-row {
        position: relative;
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 10px 12px;
        margin-block-end: 12px;
        padding: 12px;
        border: 1px solid var(--limpia-borde);
        border-radius: var(--limpia-radio);
        background-color: var(--limpia-hoja);
    }

    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)):has(tbody .campo-en-celda) .mud-table-body .mud-table-cell { padding: 0; min-inline-size: 0; }

    /* La primera celda (el producto, o el nombre de la unidad) a lo ancho, sin rótulo si es solo texto, y con hueco
       a la derecha para la papelera. */
    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)):has(tbody .campo-en-celda) .mud-table-body .mud-table-cell:first-child {
        grid-column: 1 / -1;
        padding-inline-end: calc(var(--ec-control) + 8px);
    }

    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)):has(tbody .campo-en-celda) .mud-table-body .mud-table-cell:first-child:not(:has(input))::before { content: none; }

    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)):has(tbody .campo-en-celda) .mud-table-body .mud-table-cell.crud-celda-acciones {
        position: absolute;
        inset-block-start: 8px;
        inset-inline-end: 8px;
    }
}

/* EN EL TELÉFONO, UNA TARJETA POR GRUPO: orden, nombre y papelera arriba; la categoría debajo; el
   número de platos y el pase al pie. Cada campo de abajo con su rótulo (el de la columna, que en
   la tabla ya no se ve). */
@media (max-width: 639.98px) {
    .menu-grupos-caja {
        overflow: visible;
        border: none;
        background: none;
    }

    .menu-grupos-tabla,
    .menu-grupos-tabla tbody { display: block; min-inline-size: 0; }

    .menu-grupos-tabla thead {
        position: absolute;
        inline-size: 1px;
        block-size: 1px;
        overflow: hidden;
        clip-path: inset(50%);
    }

    .menu-grupos-tabla tbody tr {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr) auto;
        grid-template-areas:
            "orden nombre quitar"
            "categoria categoria categoria"
            "platos pase pase";
        gap: 10px 8px;
        align-items: end;
        margin-block-end: 12px;
        padding: 12px;
        border: 1px solid var(--limpia-borde);
        border-radius: var(--limpia-radio);
        background-color: var(--limpia-hoja);
    }

    .menu-grupos-tabla tbody tr:hover td { background: none; }

    .menu-grupos-tabla tbody td,
    .menu-grupos-tabla tbody td.menu-grupos-col-orden {
        display: block;
        padding: 0;
        border: none;
    }

    .menu-grupos-tabla td.menu-grupos-col-orden { grid-area: orden; align-self: center; display: flex; align-items: center; }
    .menu-grupos-tabla td.menu-grupos-col-nombre { grid-area: nombre; }
    .menu-grupos-tabla td.menu-grupos-col-categoria { grid-area: categoria; }
    .menu-grupos-tabla td.menu-grupos-col-platos { grid-area: platos; }
    .menu-grupos-tabla td.menu-grupos-col-pase { grid-area: pase; min-inline-size: 0; }
    .menu-grupos-tabla td.menu-grupos-col-quitar { grid-area: quitar; align-self: center; }

    .menu-grupos-tabla :is(.menu-grupos-col-categoria, .menu-grupos-col-platos, .menu-grupos-col-pase)::before {
        content: attr(data-label);
        display: block;
        margin-block-end: 4px;
        color: var(--limpia-tinta-2);
        font-size: var(--plano-t-12);
        font-weight: 600;
    }

    /* Con el dedo, ↑ y ↓ una al lado de la otra y del tamaño de un toque. */
    .menu-grupos-flechas { flex-direction: row; margin-inline-start: 6px; }

    .menu-grupos-flecha,
    .menu-grupos-flecha-hueco {
        inline-size: var(--mg-control);
        block-size: var(--mg-control);
    }

    .menu-grupos-quitar {
        inline-size: var(--mg-control);
        block-size: var(--mg-control);
    }

    .menu-grupos-paso-boton { inline-size: var(--mg-control); }
}

/* Una seccion que ocupa las DOS columnas de .crud-secciones-dos. Es un div que
   envuelve al panel y no una clase del propio panel porque PanelWidget no admite
   una clase: envolverlo hace del div el elemento de la rejilla, que es donde
   tiene que ir el grid-column.

   Lo necesita la tabla de grupos de platos de un menu (cinco columnas, cuatro de
   ellas con un campo dentro: en media pagina el navegador le da 60 px a cada una
   y no cabe ni «Postres») y la de precios por tarifa. */
.crud-seccion-ancha {
    grid-column: 1 / -1;
    min-width: 0;
}

/* ============================================================================
   MODULO 7 DE LA FASE C3: ALMACEN Y COMPRAS (parte 1)
   ============================================================================
   Cuatro piezas que el marco no tenia: el PIE DE TOTALES de un documento de
   compra, la fila de descuentos que va encima, la cabecera de la consulta de
   stock y el resumen de existencias por almacen de la ficha de un lote.

   Todo con las variables del sistema de diseno (docs\central\diseno-web.md): ni
   un color ni un espaciado escrito a mano. */

/* El pie de totales. Es una lista de pares etiqueta/cifra alineada a la derecha
   y no una tabla: son de dos a seis filas sin cabecera, y una tabla ahi
   ensenaria bordes que separan lo que se lee junto. */
.almacen-totales {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    margin-left: auto;
    max-width: 26rem;
}

/* Mientras el nucleo recalcula se ensena el ultimo total en gris en vez de
   vaciar la caja: al cambiar la cantidad de una linea el total se pide otra vez
   y una caja que parpadea a vacio en cada pulsacion es peor que un numero medio
   segundo desactualizado. */
.almacen-totales-esperando {
    opacity: 0.55;
    transition: opacity 120ms ease-in-out;
}

.almacen-totales-linea {
    display: flex;
    justify-content: space-between;
    gap: 1.5rem;
    align-items: baseline;
}

/* El desglose por tipo de IVA cuelga de la base imponible: mas pequeno, gris y
   sangrado, para que se lea como detalle y no como otro total. */
.almacen-totales-detalle {
    font-size: 0.8125rem;
    color: var(--mud-palette-text-secondary);
    padding-left: 1rem;
}

/* Las cifras en tabular para que la coma decimal caiga en la misma columna:
   sin esto, 1.234,50 y 98,00 no se pueden comparar de un vistazo. */
.almacen-totales-cifra {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.almacen-totales-total {
    font-weight: 600;
    font-size: 1.0625rem;
}

/* Los dos descuentos del documento, uno al lado del otro cuando caben. El
   minimo de 14rem es el ancho al que la etiqueta «Descuento por pronto pago
   (€)» deja de partirse en tres lineas. */
.almacen-descuentos {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 0.75rem;
    margin-bottom: 1rem;
}

/* La cabecera de la consulta de stock: almacen, producto y las dos fechas. El
   producto necesita mas sitio que las fechas porque su buscador ensena el
   nombre entero, asi que no es un auto-fit de columnas iguales. */
.almacen-consulta {
    display: grid;
    grid-template-columns: minmax(12rem, 1fr) minmax(16rem, 2fr) minmax(9rem, 0.8fr) minmax(9rem, 0.8fr);
    gap: 0.75rem;
    align-items: start;
}

/* Por debajo de 900 px las cuatro columnas no caben sin que el buscador de
   producto quede en 120 px: se apilan en dos y luego en una. Es el mismo corte
   que usa .crud-secciones-dos. */
@media (max-width: 900px) {
    .almacen-consulta {
        grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    }
}

/* Las cifras grandes del resumen (stock actual de un producto, total de un
   lote): la misma forma que los widgets del panel, en pequeno. */
.almacen-resumen {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    align-items: baseline;
}

.almacen-resumen-cifra {
    font-size: 1.5rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
}

.almacen-resumen-etiqueta {
    font-size: 0.8125rem;
    color: var(--mud-palette-text-secondary);
}

/* Un movimiento que RESTA existencias se pinta en rojo y uno que las suma en
   verde. Es color ADEMAS del signo, no en lugar de el: el numero ya lleva su
   menos delante, asi que quien no distingue los dos colores lee lo mismo
   (regla 6 del sistema de diseno). */
.almacen-salida {
    color: var(--mud-palette-error);
}

.almacen-entrada {
    color: var(--mud-palette-success);
}

/* ======================================================================== */
/* MODULO 5 — INFORMES                                                      */
/* ======================================================================== */

/* El estado «no hay nada» de un panel que NO es un PanelWidget: la rejilla de
   resultados y la pantalla de un informe que no existe. Es el mismo aspecto
   que .admin-panel-vacio, y esta aparte porque aquel vive DENTRO del panel del
   dashboard, con su padding ya puesto. */
.admin-vacio {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
    padding: 2.25rem 1rem;
    text-align: center;
    color: var(--tentalo-tinta-suave);
}

/* --- La vista generica de parametros ------------------------------------ */

/* Los parametros van en una rejilla que se adapta, no en columnas fijas: hay
   informes con tres parametros y otros con ocho, y una rejilla de dos columnas
   deja el de tres con un hueco enorme. El minimo de 16rem es lo que necesita un
   desplegable con «Grupos de cajas: todos (12)» dentro sin partir el texto. */
.informe-parametros {
    display: grid;
    gap: 0 1rem;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}

.informe-parametro {
    min-width: 0;
}

/* Un parametro de lista (las familias, las categorias) ocupa la fila entera:
   su casilla «todas» y su selector de varios elementos no caben en 16rem. */
.informe-parametro-ancho {
    grid-column: 1 / -1;
}

.informe-parametros-acciones {
    display: flex;
    align-items: center;
    margin-top: 0.5rem;
}

/* --- LA BARRA DE FILTROS DE UN DIARIO (tanda de las pantallas densas) ------ */
/*
   NO ES UN PANEL. Los cuatro diarios pintaban dos campos de fecha y un botón
   dentro de una ZONA: papel, rótulo, 28 px de aire arriba y abajo y una regla
   fina, para tres controles. Un panel de filtros encima de un panel de tabla es
   exactamente la «caja dentro de una caja» que DESIGN.md rechaza, y además
   empujaba la primera fila de documentos 180 px hacia abajo.

   Ahora es una FILA ENVOLVIBLE de campos rellenos, pegada a su tabla y cerrada
   por debajo con una regla fina, igual que la fila del periodo de la analítica.
   Las dos pantallas hacen lo mismo —acotar lo que se va a mirar— y ahora se leen
   igual.
*/
.admin-filtros {
    margin-bottom: 12px;
    padding: 0 0 0.75rem;
    border-bottom: 1px solid var(--plano-linea-fina);
}

.informe-parametros--barra {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.5rem 0.75rem;
    /* La rejilla de `auto-fit, minmax(16rem, 1fr)` del informe repartía el ancho
       entre tres columnas iguales: dos fechas de 10rem ocupaban media pantalla
       de 2.000 px. Una fila envolvible da a cada campo lo que necesita. */
    grid-template-columns: none;
}

.informe-parametros--barra > .informe-parametro,
.informe-parametros--barra > .informe-parametro-ancho {
    flex: 0 1 auto;
    grid-column: auto;
    min-width: 11rem;
    max-width: 22rem;
}

.informe-parametros--barra .campo,
.informe-parametros--barra .mud-input-control {
    margin-bottom: 0;
}

.informe-parametros-acciones--barra {
    margin-top: 0;
}

/* EL TIRADOR «FILTRAR» y su recuento: solo por debajo de 720 px (ver el corte
   al final del bloque). Arriba, la fila está siempre puesta y un botón para
   abrirla no significaría nada. */
.admin-filtros-abrir {
    display: none;
    align-items: center;
    gap: 0.5rem;
    min-height: var(--tentalo-toque);
    padding: 0.35rem 1rem;
    border: 1.5px solid var(--plano-linea);
    border-radius: var(--plano-radio-control);
    background: transparent;
    color: var(--plano-tinta);
    font: inherit;
    font-weight: 560;
    cursor: pointer;
}

/* El recuento va en la aguada informativa del sistema (morado al 18 %) y con la
   cifra en tinta: es un dato, no un estado. */
.admin-filtros-cuenta {
    display: inline-grid;
    place-items: center;
    min-width: 1.5rem;
    height: 1.5rem;
    padding-inline: 0.35rem;
    border-radius: var(--plano-pildora);
    background-color: var(--plano-morado-aguada-honda);
    color: var(--plano-tinta);
    font-size: var(--plano-t-12);
    font-weight: 620;
    font-variant-numeric: tabular-nums;
}

.admin-filtros-velo {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 1350;
    background-color: rgba(42, 26, 62, 0.35);
}

.admin-filtros-cerrar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    flex: 1 1 100%;
}

.admin-filtros-titulo {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 640;
    letter-spacing: -0.01em;
}

@media (max-width: 719.98px) {
    .admin-filtros-abrir {
        display: flex;
    }

    /* La fila se esconde y solo vuelve dentro de la hoja: dos calendarios y un
       desplegable en 390 px son 260 px de alto antes del primer documento. */
    .informe-parametros--barra {
        display: none;
    }

    .admin-filtros-velo {
        display: block;
    }

    /* LA HOJA INFERIOR, la del sistema: hasta 88dvh, papel de hoja, esquinas de
       zona por arriba y el giro sobre la bisagra. Reserva por abajo el alto de
       la barra inferior fija y la muesca, como las otras cuatro piezas que viven
       fuera del cuerpo. */
    .informe-parametros--abierta {
        display: flex;
        position: fixed;
        inset-inline: 0;
        inset-block-end: 0;
        z-index: 1360;
        max-height: 88dvh;
        overflow-y: auto;
        padding: 0.75rem 1rem calc(1rem + var(--tentalo-toque) + env(safe-area-inset-bottom, 0px));
        background: var(--plano-hoja);
        border-start-start-radius: var(--plano-radio-zona);
        border-start-end-radius: var(--plano-radio-zona);
        box-shadow: var(--plano-sombra-hoja);
        animation: plano-hoja-entra var(--plano-tiempo-largo) var(--plano-curva);
        transform-origin: bottom center;
        touch-action: pan-y;
    }

    .informe-parametros--abierta > .informe-parametro,
    .informe-parametros--abierta > .informe-parametro-ancho,
    .informe-parametros--abierta > .informe-parametros-acciones--barra {
        flex: 1 1 100%;
        max-width: none;
    }
}

/* --- La rejilla de resultados ------------------------------------------- */

.informe-resultado-cabecera {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

/* Los botones de exportacion se envuelven en vez de recortarse: en 375 px, un
   «CSV» y un «PDF» al lado de «1.284 filas» no caben en una linea, y un boton
   recortado es un boton inalcanzable (es la regla de CabeceraPagina). */
.informe-resultado-acciones {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

/* La tabla de un informe hace scroll DENTRO de su panel y nunca en la pagina:
   es la regla de docs\central\diseno-web.md, y aqui es obligatoria de verdad
   porque un informe de productos tiene nueve columnas y en 375 px ninguna
   combinacion cabe. Va en el contenedor y no en la tabla para que el
   FixedHeader de MudTable siga funcionando. */
.informe-rejilla {
    overflow-x: auto;
}

/* Breakpoint.None en la tabla: NO se apila en tarjetas por fila en el movil,
   al reves que las listas del catalogo. Una fila de informe son nueve numeros
   que se comparan con los de la fila de al lado; apilada en una tarjeta con
   nueve etiquetas deja de poderse comparar y ocupa una pantalla entera. Lo que
   se hace es desplazar la tabla, que es lo que hace una hoja de calculo. */
.informe-tabla .mud-table-cell {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.informe-celda-numero {
    text-align: right;
}

.informe-celda-texto {
    text-align: left;
}

/* La cabecera es un boton para poder ordenar con el teclado y para que el
   lector de pantalla diga «botón, Ordenar por Total». Se le quita el aspecto de
   boton -mayusculas, relleno- para que siga leyendose como una cabecera. */
.informe-orden {
    padding: 0 0.25rem;
    min-width: 0;
    font-weight: 600;
    text-transform: none;
    letter-spacing: normal;
}

.informe-celda-numero .informe-orden {
    margin-left: auto;
}

.informe-total {
    font-weight: 700;
    border-top: 2px solid var(--tentalo-borde);
}

/* --- El indice de informes ---------------------------------------------- */

.informe-indice-grupo {
    display: grid;
    gap: 0.4rem;
    grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
}

.informe-indice-fila {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    min-width: 0;
}

.informe-indice-tarjeta {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    flex: 1 1 auto;
    min-width: 0;
    /* 48 px de alto minimo: la regla de la zona de toque del sistema de diseno. */
    min-height: var(--tentalo-toque);
    padding: 0.5rem 0.6rem;
    border-radius: 8px;
    text-decoration: none;
    color: inherit;
}

.informe-indice-tarjeta:hover {
    background-color: rgba(103, 41, 144, 0.06);
}

/* Sin anillo propio: lo pone la regla global de `:focus-visible`, igual que en
   .admin-tarjeta-enlace. */

.informe-indice-titulo {
    display: block;
    font-weight: 600;
    line-height: 1.3;
}

.informe-indice-nota {
    display: block;
    font-size: 0.8rem;
    color: var(--tentalo-tinta-suave);
    line-height: 1.35;
}

/* --- Los tres paneles del negocio --------------------------------------- */

.informe-paneles {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
}

.informe-panel-barras {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.informe-panel-barra-texto {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    font-size: 0.85rem;
    margin-bottom: 0.2rem;
}

/* La pista es relativa y las dos barras van encima una de otra: la de base
   marca el total y la de margen, la parte que queda. Con dos barras apiladas en
   vertical ocuparia el doble y habria que leer dos numeros para compararlas. */
.informe-panel-barra-pista {
    position: relative;
    height: 10px;
    border-radius: 5px;
    background-color: rgba(42, 26, 62, 0.08);
    overflow: hidden;
}

.informe-panel-barra-relleno,
.informe-panel-barra-margen {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    border-radius: 5px;
}

.informe-panel-barra-relleno {
    background-color: rgba(103, 41, 144, 0.35);
}

.informe-panel-barra-margen {
    background-color: var(--tentalo-marca);
}

.informe-panel-leyenda {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.9rem;
    font-size: 0.78rem;
    color: var(--tentalo-tinta-suave);
}

.informe-punto {
    display: inline-block;
    width: 0.7rem;
    height: 0.7rem;
    border-radius: 2px;
    border: 1px solid var(--tentalo-borde);
    vertical-align: -1px;
}

.informe-punto-base {
    background-color: rgba(42, 26, 62, 0.35);
}

.informe-punto-margen {
    background-color: var(--tentalo-marca);
}

.informe-panel-total {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    margin-top: 0.9rem;
    padding-top: 0.6rem;
    border-top: 1px solid var(--tentalo-borde);
}

/* --- El mapa de calor ---------------------------------------------------- */

.informe-mapa {
    overflow-x: auto;
}

.informe-mapa-tabla {
    border-collapse: separate;
    border-spacing: 2px;
    font-size: 0.72rem;
}

.informe-mapa-tabla th {
    font-weight: 600;
    color: var(--tentalo-tinta-suave);
    padding: 0 0.2rem;
    text-align: center;
}

.informe-mapa-tabla th[scope="row"] {
    text-align: right;
    padding-right: 0.4rem;
    position: sticky;
    left: 0;
    /* Sin fondo, las celdas de colores se ven pasar por debajo del dia al
       desplazar la tabla en el movil. */
    background-color: #fff;
}

/* Cuadradas y pequenas: siete por veinticuatro son 168 celdas y lo que se lee
   es la FORMA de la mancha, no cada celda. Se les da un borde muy claro para
   que una fila con dos horas vacias en medio siga leyendose como una rejilla. */
.informe-mapa-celda {
    width: 18px;
    min-width: 18px;
    height: 18px;
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0.04);
    padding: 0;
}

/* El valor de la celda esta en el DOM para el lector de pantalla, pero no se
   pinta: no cabe. No se usa display:none porque eso lo esconde tambien del
   lector, que es justo lo contrario de lo que se quiere. */
.informe-mapa-oculto {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

.informe-mapa-medida {
    min-width: 12rem;
}

/* ==========================================================================
   FORMATOS DE IMPRESION (modulo 3, parte 2)
   Anadido por la parte 2 del modulo 3, al final del fichero: es el UNICO
   fichero compartido que toca ese trabajo y asi no se cruza con nada de
   arriba. Prefijos: «impresion-», «escpos-», «plantilla-» y «cupon-».
   ========================================================================== */

/* --- La vista previa de un ticket ESC/POS -------------------------------- */
/* Un ticket ESC/POS llega del nucleo YA MONTADO: los espacios de dentro son
   los que alinean la columna de precios. Con una tipografia proporcional o con
   un ancho que no sea el del papel esa alineacion se rompe, y la vista previa
   deja de servir para lo unico para lo que existe. De ahi: monoespaciada,
   white-space: pre y un ancho por numero de columnas.

   EL ANCHO SON SUS COLUMNAS, Y NO UN NUMERO DE PIXELES (arreglo del
   2026-09-17). Hasta hoy cada ancho de papel era un `min(100 %, 355px)` heredado
   del administrador React, medido alli con otra tipografia y otro cuerpo. Con
   «Roboto Mono» a 11 px, 48 columnas miden 316,8 px de texto mas 24 de relleno y
   2 de canto: 343. La caja media 355, o sea de sobra… salvo que el panel fuera
   mas estrecho, y entonces `min(100 %, …)` la encogia SIN encoger la letra: el
   ticket seguia midiendo 48 columnas, la caja no, y la columna de la derecha
   -«Importe», «5,00 €»- se quedaba fuera. Habia barra horizontal, pero dentro de
   una caja de 343 px de alto no se ve: en la practica es contenido inalcanzable,
   que es justo lo que prohibe la regla 2 del sistema de diseno.

   AHORA LA CAJA MIDE SUS COLUMNAS (`Nch`) Y LA LETRA SE ENCOGE SOLA. `1ch` es el
   avance de un caracter, asi que `48ch` son exactamente 48 columnas de la
   tipografia que se acabe usando. Y el cuerpo sale de un `clamp()` contra el
   ancho del PANEL (`100cqw`, la caja de contencion que pone `.escpos-papel`):
   mientras quepa, el de siempre; cuando no, el que hace que quepa. Asi una linea
   de N columnas se ve ENTERA y sin barra en un panel de 420 px, y en un movil de
   375 px la letra baja en vez de recortarse el papel.

   El 0,6 de `--escpos-avance` es el avance de «Roboto Mono»: 600 unidades de
   1000 de em, medido en el navegador (48 caracteres a 11 px = 316,8 px). Solo
   sirve para elegir el cuerpo; el ancho de la caja lo pone `ch`, que mide la
   tipografia de verdad, asi que una suplente mas estrecha no descuadra nada.

   El suelo de 6 px del `clamp()` es el limite de lo legible: por debajo de eso
   no se encoge mas y vuelve a haber barra, que es preferible a un ticket que no
   se puede leer. */
.escpos-papel {
    /* La caja de contencion del cuerpo de letra. Envuelve SOLO al <pre>: la
       contencion hace de bloque contenedor de lo posicionado, y colgandola de un
       panel con barras de herramientas se llevaria por delante sus menus. */
    container-type: inline-size;
}

.escpos-vista-previa {
    --escpos-columnas: 42;
    --escpos-cuerpo: 12px;
    /* El relleno (0,75rem a cada lado) mas los dos cantos de 1 px. */
    --escpos-marco: calc(1.5rem + 2px);
    --escpos-avance: 0.6;
    /* El alto de linea del papel, en un sitio: el doble alto reserva exactamente
       una linea mas (lo mismo que el escpos.css del TPV). */
    --escpos-interlineado: 1.35;
    box-sizing: border-box;
    font-family: "Roboto Mono", ui-monospace, "Cascadia Mono", Consolas, "Courier New", monospace;
    font-size: clamp(
        6px,
        calc((100cqw - var(--escpos-marco)) / (var(--escpos-columnas) * var(--escpos-avance))),
        var(--escpos-cuerpo)
    );
    line-height: var(--escpos-interlineado);
    white-space: pre;
    /* NO DEBERIA DESPLAZARSE (tanda T3, 2026-09-28): quien pinta el papel escribe
       en el `style` del <pre> `--escpos-columnas` con las del papel O las de su
       linea mas ancha, la que sea mayor (VistaPreviaEscPos.EstiloDeColumnas, lo
       mismo que el TPV), y la letra se ajusta a esas columnas. Esto queda de
       ultimo recurso por debajo del suelo de 6 px: scrollea DENTRO de su caja y
       no en la pagina, que es la regla del sistema de diseno. */
    overflow-x: auto;
    width: calc(var(--escpos-columnas) * 1ch + var(--escpos-marco));
    max-width: 100%;
    margin: 0;
    padding: 0.75rem;
    border: 1px solid var(--tentalo-borde);
    border-radius: 6px;
    background-color: #fff;
    color: var(--tentalo-tinta);
    min-height: 8rem;
}

.escpos-vista-previa-32 {
    --escpos-columnas: 32;
}

.escpos-vista-previa-42 {
    --escpos-columnas: 42;
}

.escpos-vista-previa-48 {
    --escpos-columnas: 48;
    --escpos-cuerpo: 11px;
}

.escpos-vista-previa-56 {
    --escpos-columnas: 56;
    --escpos-cuerpo: 9.5px;
}

.escpos-vista-previa-64 {
    --escpos-columnas: 64;
    --escpos-cuerpo: 8.75px;
}

/* LAS MARCAS DE LA IMPRESORA (tanda T3, 2026-09-28). La central pinta con EL
   MISMO analizador que el TPV (Services\VistaPreviaEscPos.cs delega en
   frontend-blazor\Tentalo.POS.Tactil\Runtime\VistaPreviaEscPos.cs, compilado
   aqui por enlace), y estas reglas copian el criterio de su escpos.css. El
   analizador ya no sustituye etiqueta por etiqueta: recorre el marcado con el
   estado de la impresora y saca el texto en TRAMOS, uno por combinacion de
   bits, cada uno en UN <span> con sus clases:

     escpos-b     negrita.
     escpos-u     subrayado.
     escpos-neg   negativo (GS B): tinta clara sobre fondo oscuro. El nucleo
                  rellena con espacios la linea entera, asi que la banda del
                  titulo y la del TOTAL salen de lado a lado, como en el papel.
     escpos-red   la segunda tinta de las impresoras de dos colores (ESC r).
     escpos-cpp12 la fuente B: 9 puntos de ancho en vez de 12, o sea 0,75.
     escpos-dw    doble ancho: CADA LETRA OCUPA DOS COLUMNAS. Se estira el tramo
                  al doble desde su izquierda con un transform, que no ocupa
                  sitio, y el sitio de las otras N columnas lo reserva el margen:
                  `--n` son los caracteres del tramo, lo escribe el analizador.
                  Antes se separaban las letras 8 px, que no son columnas.
     escpos-dh    doble alto: cada letra ocupa DOS LINEAS. Se estira hacia arriba
                  desde el pie y la linea de encima la reserva el margen superior
                  del bloque en linea. Antes no se pintaba distinto.
     dw + dh      las dos cosas: el cuerpo al doble, que en una letra
                  monoespaciada es exactamente dos columnas y dos lineas.

   `<cpp10>`, `<prop>`, `<comp>` e `<i>` no dejan clase (bits de ESC ! que las
   termicas corrientes no pintan), ni los cortes, la estacion, el avance de
   pagina, la pagina de codigos o los bytes en crudo: no dejan nada en el papel. */
.escpos-vista-previa .escpos-b {
    font-weight: 700;
}

.escpos-vista-previa .escpos-u {
    text-decoration: underline;
}

.escpos-vista-previa .escpos-neg {
    background-color: var(--tentalo-tinta);
    color: #fff;
}

.escpos-vista-previa .escpos-red {
    color: #b3261e;
}

.escpos-vista-previa .escpos-neg.escpos-red {
    background-color: #b3261e;
    color: #fff;
}

.escpos-vista-previa .escpos-cpp12 {
    font-size: 0.75em;
}

.escpos-vista-previa .escpos-dw {
    display: inline-block;
    transform: scaleX(2);
    transform-origin: 0 50%;
    margin-inline-end: calc(var(--n, 0) * 1ch);
}

.escpos-vista-previa .escpos-dh {
    display: inline-block;
    transform: scaleY(2);
    transform-origin: 50% 100%;
    margin-block-start: calc(var(--escpos-interlineado) * 1em);
}

.escpos-vista-previa .escpos-dw.escpos-dh {
    display: inline;
    transform: none;
    margin: 0;
    font-size: 2em;
}

.escpos-vista-previa .escpos-dw.escpos-dh.escpos-cpp12 {
    font-size: 1.5em;
}

/* LAS IMAGENES. El analizador pone las clases en el propio <img> (ya no hay
   envoltorio) y su ancho DEL PAPEL en columnas, en `ch` (doce puntos de la
   impresora por columna: una raya de 576 puntos ocupa las 48), asi que escalan
   con la letra igual que el texto. El tope es el papel. `pixelated` porque son
   mapas de bits de un punto por pixel: suavizados, las rayas salen grises. Sin
   `align` es centrada, que es lo que hace el motor ESC/POS (§17). */
.escpos-vista-previa img {
    display: block;
    width: auto;
    max-width: 100%;
    height: auto;
    margin: 0 auto;
    image-rendering: pixelated;
}

.escpos-vista-previa img.escpos-img-left {
    margin: 0 auto 0 0;
}

.escpos-vista-previa img.escpos-img-right {
    margin: 0 0 0 auto;
}

/* EL HUECO ROTULADO DEL DISENADOR (§21, 2026-09-18). Donde el motor no ha
   podido pintar una imagen -el bloque va dentro de un grupo cuya condicion no
   se cumple, la empresa no tiene logotipo, el base64 no vale- la vista previa
   del DISENADOR deja esta marca en su sitio. Antes no dejaba nada: el papel
   empezaba por la linea siguiente y no habia forma de saber que faltaba algo.

   PUNTEADO Y EN MOSTAZA, que es lo que el sistema de diseno reserva para
   «atencion, esto esta pendiente» (DESIGN.md): no es un error -el diseno se
   guarda y se imprime igual- sino algo que hay que mirar. El punteado dice
   ademas que el recuadro NO SALE POR EL PAPEL, que es justo lo que se quiere
   dar a entender.

   SE SALE DE LA REJILLA DE CARACTERES A PROPOSITO. El papel va en un <pre> con
   `white-space: pre` y la letra apretada a las columnas del rollo; el rotulo es
   una frase larga que tiene que leerse, asi que aqui se vuelve a `normal` para
   que parta por palabras, y el cuerpo sube a 0,95em porque no cuenta columnas.
   Ocupa el ancho del papel, que es lo que ocuparia la imagen que falta. */
.escpos-vista-previa .escpos-hueco {
    display: block;
    box-sizing: border-box;
    width: 100%;
    margin: 0.4rem 0;
    padding: 0.5rem 0.6rem;
    white-space: normal;
    font-size: 0.95em;
    line-height: 1.4;
    text-align: center;
    border: 1px dashed var(--plano-mostaza-honda);
    border-radius: 4px;
    background-color: var(--plano-mostaza-aguada);
    color: var(--plano-tinta);
}

/* El hueco de un codigo de barras o de un QR. El nucleo manda la MARCA con su
   valor, no el dibujo; el React pone en su sitio dos PNG genericos que trae
   dentro (ocho kilobytes de base64 entre los dos) y aqui se dibujan con CSS,
   que dice lo mismo y no pesa nada. */
.escpos-simbolo {
    display: block;
    margin: 0.4rem auto;
    border: 1px solid var(--tentalo-borde);
}

.escpos-simbolo-barras {
    width: 60%;
    height: 2.6rem;
    background-image: repeating-linear-gradient(
        90deg,
        var(--tentalo-tinta) 0 2px,
        #fff 2px 4px,
        var(--tentalo-tinta) 4px 5px,
        #fff 5px 9px
    );
}

.escpos-simbolo-qr {
    width: 5.5rem;
    height: 5.5rem;
    background-image:
        repeating-linear-gradient(90deg, var(--tentalo-tinta) 0 6px, #fff 6px 12px),
        repeating-linear-gradient(0deg, var(--tentalo-tinta) 0 6px, #fff 6px 12px);
    background-blend-mode: difference;
}

/* EL QR DE VERDAD (2026-09-18). js\qr.js mete dentro del <span> el SVG del
   codigo, dibujado con el valor que el traductor dejo en `data-valor`, y le
   pone esta clase: el recuadro de relleno de arriba se apaga -ya no hace falta
   decir «aqui va un QR» cuando esta el QR- y el hueco pasa a medir lo que mide
   el simbolo en el papel, que es el ancho que el propio SVG trae en tanto por
   ciento. El borde tambien se quita: el simbolo lleva su zona de silencio
   dibujada y un canto pegado a ella confunde al lector. */
.escpos-simbolo-qr-pintado {
    width: auto;
    height: auto;
    background-image: none;
    border: 0;
    line-height: 0;
}

/* EL SVG SE CENTRA SOLO, y hace falta decirlo: el <span> pasa a `width: auto`
   —o sea, todo el ancho del papel— y el `margin: auto` de `.escpos-simbolo` ya
   no lo mueve, porque lo que hay que centrar es el dibujo de dentro, que mide
   lo que mide en el papel. Sin esto el código sale pegado a la izquierda y la
   impresora lo saca centrado (ESC a 1), o sea que la previa mentiría. */
.escpos-simbolo-qr-pintado svg {
    display: block;
    height: auto;
    margin: 0 auto;
}

.escpos-simbolo-qr-pintado.escpos-simbolo-left svg {
    margin-left: 0;
}

.escpos-simbolo-qr-pintado.escpos-simbolo-right svg {
    margin-right: 0;
}

/* La alineacion del simbolo dentro del papel. Sin clase queda el `margin: auto`
   de `.escpos-simbolo`, que centra, y centrado es lo que hace la impresora con
   un <qr/>; estas dos son para el dia que el nucleo mande un `align`. */
.escpos-simbolo-left {
    margin-left: 0;
    margin-right: auto;
}

.escpos-simbolo-right {
    margin-left: auto;
    margin-right: 0;
}

/* EL QR DE MUESTRA: el que se pinta cuando el bloque todavia no tiene campo
   elegido. Se rotula con `::after` y no con texto dentro del <span> porque el
   papel va en un <pre> con `white-space: pre` y un texto de mas correria una
   linea. Atenuado, para que nadie confunda la muestra con el QR del documento. */
.escpos-simbolo-qr-muestra {
    opacity: 0.55;
}

.escpos-simbolo-qr-muestra::after {
    content: attr(data-muestra);
    display: block;
    font-family: var(--plano-familia);
    font-size: 0.75em;
    line-height: 1.4;
    text-align: center;
    color: var(--tentalo-tinta-suave);
}

/* --- La vista previa de una pagina RDL ----------------------------------- */
/* Son PNG ya renderizados por el nucleo, una imagen por pagina. A ancho
   completo del panel y con su borde, para que se vea donde acaba la hoja. */
.impresion-vista-previa-paginas img {
    display: block;
    width: 100%;
    height: auto;
    margin-bottom: 0.5rem;
    border: 1px solid var(--tentalo-borde);
    border-radius: 4px;
    background-color: #fff;
}

.impresion-vista-previa-acciones {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.75rem;
}

/* --- El editor de elementos de cabecera, pie y cupon ---------------------- */
/* Una fila es: los dos botones de orden a la izquierda, el cuerpo (un campo de
   texto con sus cuatro conmutadores, o una imagen) en medio y el de quitar a la
   derecha. Con grid y no con flex porque las tres piezas tienen que quedar
   alineadas entre filas aunque una lleve imagen y la de al lado texto. */
.plantilla-elemento {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: 0.5rem;
    align-items: start;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--tentalo-borde);
}

.plantilla-elemento:last-of-type {
    border-bottom: none;
}

/* min-width: 0 en el hijo de una rejilla: sin el, un campo de texto no baja de
   su min-content y la fila se sale del panel en 375 px. Es lo mismo que hace
   .crud-secciones-dos con sus columnas. */
.plantilla-elemento-cuerpo {
    min-width: 0;
}

.plantilla-elemento-orden,
.plantilla-elemento-quitar {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    /* Los botones a la altura del campo y no del borde de la fila: el campo
       lleva su etiqueta flotante encima. */
    padding-top: 0.25rem;
}

.plantilla-elemento-atributos {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    margin-top: -0.25rem;
    margin-bottom: 0.5rem;
}

.plantilla-elementos-acciones {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.75rem;
}

/* Altura de toque (regla 3 del sistema de diseno): los botones de orden, el de
   quitar y los cuatro conmutadores de estilo son botones de icono pequenos, que
   MudBlazor deja en 30 px. Crece la caja, no el dibujo. */
.plantilla-elemento-boton {
    min-height: var(--tentalo-toque);
    min-width: var(--tentalo-toque);
}

/* --- La ayuda de marcadores de un cupon ---------------------------------- */
.cupon-marcadores code {
    white-space: nowrap;
}

.cupon-marcadores td:first-child {
    width: 1%;
    white-space: nowrap;
    vertical-align: top;
}

.cupon-marcadores-ejemplo {
    text-align: center;
    margin: 0.5rem 0;
}

/* --- El diario y la ficha de documentos de venta (fase D1) --------------- *
 *
 * docs\central\diario-de-documentos.md. Tres pantallas de tabla y tres fichas
 * que reutilizan casi todo lo del informe (.informe-rejilla, .informe-tabla,
 * .informe-celda-numero, .admin-insignia): aqui solo esta lo que anaden.      */

/* La columna de la casilla de seleccion, lo mas estrecha posible: en una tabla
   de treinta columnas cada pixel de la primera es un pixel que le falta a la
   serie y el numero. */
.documentos-celda-marca {
    width: 1%;
    padding-right: 0 !important;
}

/* La fila entera lleva a la ficha (OnRowClick), asi que tiene que parecerlo.
   El cursor es la unica pista que queda cuando la celda del enlace se ha
   apagado en el selector de columnas. */
.documentos-tabla .mud-table-row:hover {
    cursor: pointer;
}

/* El filtro por columna vive DENTRO de la cabecera, debajo del boton de
   ordenar. Sin el ancho minimo, MudBlazor le da el de su contenido y en una
   columna estrecha («CP») el campo se queda en dos caracteres. */
.documentos-filtro {
    min-width: 6rem;
    margin-top: 0.25rem;
}

/* El menu de columnas visibles: una columna de casillas con altura maxima, que
   con treinta columnas no cabe en pantalla. */
.documentos-columnas-menu {
    display: flex;
    flex-direction: column;
    max-height: 60vh;
    overflow-y: auto;
    padding: 0.5rem 0.75rem;
    min-width: 14rem;
}

/* La barra de acciones de la ficha: navegacion a la izquierda, acciones a la
   derecha, y las dos se envuelven en vez de recortarse (la misma regla que
   .informe-resultado-acciones: un boton recortado es un boton inalcanzable). */
.documento-ficha-barra {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.documento-ficha-navegacion,
.documento-ficha-acciones {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

/* EL CUERPO DE LA FICHA, UNA PILA DE ZONAS A ANCHO COMPLETO (tanda 5 del
   redisenio «El plano de sala»).

   Hasta la tanda 4 esto eran DOS COLUMNAS, la vista previa a la izquierda y los
   datos a la derecha, y la revision de acabado lo midio: un ticket ESC/POS de 42
   columnas no pasa de unos 330 px de ancho y se corta a 70vh de alto, mientras
   que la columna de datos de una factura -documento, importes, cliente y lineas-
   pasa de los mil cuatrocientos. Debajo del papel quedaban unos OCHOCIENTOS
   pixeles de columna en blanco.

   Ahora el papel es una zona mas, la primera, y las demas van debajo una tras
   otra. La rejilla de doce del §4 -rotulo condensado a la izquierda, contenido a
   la derecha- la enciende la clase `.crud-secciones` que el marcado lleva al
   lado, que es la misma que usan las 48 fichas del marco CRUD; aqui no hace
   falta ni una regla nueva. Es un `<div>` sin nada que decir, y eso es lo que
   dice esta regla. */
.documento-ficha-cuerpo {
    display: block;
}

/* La vista previa hace scroll dentro de su zona: un ticket de sesenta lineas
   no puede alargar la ficha entera.

   Y NO SE ESTIRA A LO ANCHO. En una zona de nueve doceavos de la pagina hay unos
   970 px a 1.440: una pagina A4 estirada ahi se lee como un cartel, y un ticket
   de 42 columnas -que mide lo que mide- dejaria el resto en blanco de todas
   formas. 40 rem es lo que median las dos columnas de antes, asi que el papel se
   ve del mismo tamano que siempre. */
.documentos-previa {
    max-height: 70vh;
    max-inline-size: 40rem;
    overflow: auto;
}

.documento-ficha-insignias {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}

/* --------------------------------------------------------------------------
   EL PAPEL AL LADO Y LOS DATOS EN TARJETAS (2026-09-30,
   docs\central\ficha-de-factura-2026-09-30.md §2)
   --------------------------------------------------------------------------
   La queja, con fotos al 80 % en una pantalla de 1.920: «la parte de abajo es
   un churro». Medido en el banco (documentos-factura-simplificada): etiqueta y
   valor a 1.994 px uno del otro, nueve «-» en un cliente que no existe y ese
   bloque vacío con 373 px de alto. Los datos cortos de un documento no llenan
   una zona a ancho completo, así que dejan de ser zonas:

     * LA FICHA PARA EN 90 REM (1.440 px): el papel (22) más su hueco (2) más
       tres tarjetas en fila (66). La barra de acciones acaba donde acaban los
       datos y no en el borde de 2.400 px CSS que da una pantalla de 1.920 al
       80 %.
     * EL RESUMEN: el papel a la izquierda y las tarjetas a la derecha desde
       1.024 px; por debajo, el papel encima y las tarjetas debajo.
     * LAS TARJETAS miden de 18 rem a lo que toque (`auto-fill`, como las de
       diseños de impresión: una sola no se estira a todo el ancho) y el
       conjunto no pasa de 66 rem: tres por fila a 1.600 y a 1.920, dos a 1.280
       y a 768, una a 375.
     * UN PAR ES UNA FILA DE LA REJILLA de su tarjeta (`subgrid`): la columna de
       etiquetas mide la más larga y el valor va JUSTO al lado. Los importes, a
       la derecha y con cifras de ancho fijo para que las comas caigan en
       columna. */
.documento-ficha {
    max-inline-size: 90rem;
}

.documento-ficha-resumen {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.5rem;
    align-items: start;
    padding-block: 1.25rem 1.75rem;
    border-block-end: 1px solid var(--plano-linea-fina);
}

@media (min-width: 1024px) {
    .documento-ficha-resumen {
        grid-template-columns: minmax(18rem, 22rem) minmax(0, 1fr);
        gap: 2rem;
    }

    /* Un documento de PÁGINA (A4 en imágenes o en PDF) necesita algo más de
       papel que un ticket de 42 columnas para leerse. */
    .documento-ficha-resumen:has(.impresion-vista-previa-paginas) {
        grid-template-columns: minmax(20rem, 28rem) minmax(0, 1fr);
    }
}

.documento-ficha-papel {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    min-inline-size: 0;
}

.documento-ficha-papel .documentos-previa {
    max-inline-size: 100%;
    margin-block-start: 0.4rem;
}

.documento-ficha-tarjetas {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(18rem, 100%), 1fr));
    gap: 1rem;
    align-items: start;
    min-inline-size: 0;
    max-inline-size: 66rem;
}

/* Lo ancho sigue en zonas bajo el resumen; la primera se separa de su regla. */
.documento-ficha-cuerpo {
    padding-block-start: 1.25rem;
}

/* Las líneas de un ticket son cuatro columnas: a 60 rem se leen enteras sin
   que la cantidad y el importe queden a un metro del producto. */
.documento-ficha-cuerpo .plano-region-campos {
    max-inline-size: 60rem;
}

/* LA TARJETA: la habitación del plano (hoja, línea fina en dos lados y muro de
   2 px en los otros dos), la misma de `.admin-tarjeta` y de los diseños de
   impresión. Ni sombra ni papel. */
.documento-tarjeta {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    min-inline-size: 0;
    padding: 1rem 1.1rem 1.1rem;
    background-color: var(--plano-hoja);
    border: 1px solid var(--plano-linea-fina);
    border-left: 2px solid var(--plano-muro);
    border-bottom: 2px solid var(--plano-muro);
    border-radius: var(--plano-esquina-muro);
}

.documento-tarjeta-cabecera {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.documento-tarjeta-titulo {
    margin: 0;
}

/* LA AYUDA, entera: a todo el ancho de su tarjeta y partiéndose en líneas.
   Antes vivía en la columna del rótulo de la zona, a 34ch, y en la foto de la
   queja salía cortada por la izquierda. */
.documento-ficha-ayuda {
    margin: 0;
    font-size: var(--plano-t-13);
    line-height: 1.4;
    color: var(--plano-tinta-2);
    overflow-wrap: anywhere;
}

.documento-datos {
    display: grid;
    grid-template-columns: minmax(6.5rem, max-content) minmax(0, 1fr);
    column-gap: 1rem;
    row-gap: 0.45rem;
    margin: 0;
    font-size: 0.875rem;
    line-height: 1.4;
}

.documento-dato {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
    align-items: baseline;
}

.documento-dato-etiqueta {
    color: var(--plano-tinta-2);
}

.documento-dato-valor {
    margin: 0;
    min-inline-size: 0;
    font-weight: 600;
    color: var(--plano-tinta);
    overflow-wrap: anywhere;
}

.documento-dato-cifra .documento-dato-valor {
    text-align: end;
    font-variant-numeric: tabular-nums;
}

/* EL TOTAL: con su regla encima y el peso de un total. */
.documento-dato-destacado {
    border-block-start: 1px solid var(--plano-linea);
    padding-block-start: 0.45rem;
}

.documento-dato-destacado .documento-dato-etiqueta,
.documento-dato-destacado .documento-dato-valor {
    font-size: var(--plano-t-15);
    font-weight: 700;
    color: var(--plano-tinta);
}

/* LO QUE FALTA, ATENUADO Y DICHO: «Sin dato», «Sin cliente», en la tinta
   secundaria (8:1 sobre la hoja) y sin peso. Nunca un guion suelto. */
.documento-dato-vacio .documento-dato-valor {
    font-weight: 400;
    color: var(--plano-tinta-2);
}

/* Un documento relacionado dentro de un par es un enlace: objetivo de 44 px. */
.documento-dato-enlace {
    display: inline-flex;
    align-items: center;
    min-block-size: 2.75rem;
    min-inline-size: 2.75rem;
}

/* El buscador por serie y numero: los dos campos y el boton en una linea, y en
   el movil apilados. El boton no encoge, para que no se recorte su texto. */
.documento-buscador {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
}

.documento-buscador .campo {
    max-width: 12rem;
    flex: 1 1 8rem;
}

.documento-buscador .mud-button-root {
    flex: 0 0 auto;
    min-height: var(--tentalo-toque);
}

/* --------------------------------------------------------------------------
   LAS ACCIONES DE LA FICHA Y DEL DIARIO (fases D2 y D3 de
   docs\central\diario-de-documentos.md)
   -------------------------------------------------------------------------- */

/* La barra de acciones de la ficha envuelve igual que su contenedor: en una
   factura son once acciones y a 1024 px no caben en una fila. */
.documento-ficha-acciones-barra {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

/* El motivo por el que una accion del menu esta apagada, debajo de su nombre.
   Se acota en ancho: algunos MSG_* del nucleo son un parrafo entero y el menu
   no puede crecer hasta el pie de la pantalla. */
.documento-accion-motivo {
    max-width: 22rem;
    white-space: normal;
    line-height: 1.25;
}

/* Los campos del dialogo de emision: caja, jornada y forma de pago en una
   rejilla que se apila en el movil. */
.documento-emision-campos {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    gap: 0.75rem;
    align-items: start;
}

.documento-emision-importe {
    display: flex;
    align-items: center;
}

/* Una tabla dentro de un dialogo (los clientes del buscador, los resultados de
   una accion en masa) hace scroll DENTRO de su caja: sin esto, un nombre fiscal
   largo saca la barra de scroll de la pagina entera. */
.documento-tabla-envoltorio {
    overflow-x: auto;
    max-height: 24rem;
    overflow-y: auto;
}

/* La fila elegida en el buscador de clientes. Con fondo y no solo con borde,
   porque en una tabla rayada un borde de 1 px no se distingue del rayado. */
.documento-fila-elegida > td {
    background: var(--tentalo-lila-suave, #e7ecea);
    font-weight: 600;
}

/* La barra de acciones EN MASA del diario, encima de la tabla: sale solo cuando
   hay filas marcadas y dice cuantas hay. */
.documento-masa {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

.documento-masa-cuantas {
    margin-right: 0.5rem;
    font-weight: 600;
}

/* El estado de la orden de «Imprimir en la tienda» dentro de la ficha. */
.documento-orden-estado {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

/* --------------------------------------------------------------------------
   LA SOLICITUD A LA TIENDA: «Abonar» y «Facturar» desde la central
   (docs\central\abonar-y-facturar-desde-la-central-2026-09-18.md, tanda T2)
   --------------------------------------------------------------------------
   La banda de `EstadoDeLaOperacion.razor`, debajo de la barra de acciones de la
   ficha de una factura. Es hermana de `.documento-orden-estado` de aqui arriba
   -misma fila flexible, mismo hueco- y se separa en una cosa: esta tiene ESTADO
   y por eso el color la posee entera, con una AGUADA de fondo.

   NO ES UNA TARJETA NI LLEVA BANDA LATERAL DE COLOR. Ni canto por los cuatro
   lados, ni sombra, ni `border-left` de acento: el color POSEE la region con su
   aguada, que es como manda aqui (DESIGN.md, «Zonas en vez de tarjetas», y el
   punto 6 de la revision de acabado que fija `AcabadoDelPlanoTests`). Una banda
   lateral de color no es muro -un muro va en tinta, nunca en mostaza- y se
   quito de las tres piezas que la tenian; no vuelve por esta.

   LOS TRES COLORES SON LOS TRES DE ESTADO, y ninguno es la accion: mostaza =
   atencion (la solicitud espera), salvia = al dia (emitido), arcilla = error
   (rechazado o caducado). El morado no entra aqui; el morado es lo que se
   pulsa. El cuarto caso -cancelada- se queda en la tinta neutra: no espera nada
   y tampoco fue un fallo.

   EL COLOR NO ES LA UNICA SENAL (WCAG 1.4.1): el titular DICE el estado con
   todas sus letras -«Emitido», «Rechazado», «Caducado»- y el punto de la
   izquierda solo lo acompana. Quien no distinga la mostaza de la salvia lee lo
   mismo. */
.documento-operacion-estado {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.5rem;
    padding: 0.5rem 0.75rem;
    border-radius: 6px;
    background: var(--plano-papel-hondo, #eae6f0);
}

.documento-operacion-punto {
    flex: 0 0 auto;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: currentColor;
}

/* El texto envuelve en una linea propia cuando no cabe: el motivo de un rechazo
   es el MSG_* del nucleo y alguno es un parrafo entero. */
.documento-operacion-texto {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.35rem;
    min-width: 0;
    flex: 1 1 14rem;
}

.documento-operacion-titular {
    font-weight: 600;
}

.documento-operacion-detalle {
    color: var(--plano-tinta-2, #5b4a73);
    font-size: 0.875rem;
    line-height: 1.3;
}

/* Esperando a la tienda: MOSTAZA, que en este sistema es atencion y no error.
   La tinta es la honda (#9c6c12) y no la mostaza clara: esa no llega a 4,5:1
   sobre papel y aqui hay texto, no solo un canto (DESIGN.md, «Colors»). */
.documento-operacion-espera {
    background: var(--plano-mostaza-aguada, rgba(233, 180, 76, 0.18));
    color: var(--plano-mostaza-honda, #9c6c12);
}

/* Emitido: SALVIA, que es «al dia». */
.documento-operacion-hecha {
    background: var(--plano-salvia-aguada, rgba(47, 143, 131, 0.12));
    color: var(--plano-salvia, #23726a);
}

/* Rechazado o caducado: ARCILLA. */
.documento-operacion-fallo {
    background: var(--plano-arcilla-aguada, rgba(217, 96, 74, 0.14));
    color: var(--plano-arcilla-honda, #b03826);
}

/* Cancelado: ni espera ni fallo. Tinta normal sobre papel hondo. */
.documento-operacion-neutra {
    color: var(--plano-tinta-2, #5b4a73);
}

/* El titular y el detalle heredan el color de estado de la banda; el enlace al
   documento emitido NO, porque un enlace se pinta como enlace en todas las
   pantallas y cambiarle el color aqui lo haria irreconocible. */
.documento-operacion-estado .mud-typography {
    color: inherit;
}

.documento-operacion-estado a.mud-link {
    color: var(--plano-morado, #672990);
    font-weight: 600;
}

/* El aviso de «la tienda lleva N min sin conectar» dentro del dialogo de
   emision. Misma mostaza, misma aguada y misma gramatica que la banda de
   arriba, en una sola linea: es un aviso, no un estado, y no corta nada. El
   icono de nube tachada es la senal que no es color. */
.documento-emision-sin-conectar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
    padding: 0.5rem 0.75rem;
    border-radius: 6px;
    background: var(--plano-mostaza-aguada, rgba(233, 180, 76, 0.18));
    color: var(--plano-mostaza-honda, #9c6c12);
    font-size: 0.875rem;
    line-height: 1.3;
}

/* ==========================================================================
   EL DISEÑADOR DE SALAS (prefijo `salas-`)
   ==========================================================================
   Fase M2 de docs\tpv\diseno-de-salas.md, rediseñado el 2026-09-11 (§9.8 de ese
   documento). Tres columnas —paleta, lienzo y propiedades— que en pantalla
   estrecha pasan a cajones, y un SVG que se dibuja en CENTÍMETROS: todo lo que
   aquí se mide en píxeles es del marco, no del plano.

   LA DIRECCIÓN ES «SALA CLARA, TINTA MORADA» (docs\tpv\diseno-sala-clara.md) y
   el listón lo ponen los editores de planos de Toast, Lightspeed, Square for
   Restaurants y SevenRooms: fondo cálido casi blanco, mesa con relleno suave y
   canto de 1,5 px, sombra corta, nombre en negrita y datos secundarios
   pequeños y grises, adornos con colores neutros que no compiten, y rejilla de
   puntos casi invisible.

   EL CANTO DE 1,5 px NO ESCALA CON EL ZOOM, y por eso todas las figuras llevan
   `vector-effect: non-scaling-stroke`. Sin él, el grosor va en centímetros del
   plano: al 30 % una mesa no tiene borde y al 300 % lo tiene de un dedo. El
   COLOR del canto sí es un atributo de cada figura (sale de su relleno, ver
   DibujoDeSala.CantoDeMesa) y estas reglas lo pisan solo cuando toca —estado,
   selección, error—, que es justo lo que se quiere.

   LOS COLORES DE ESTADO SON LOS DE «SALA CLARA» (§4): morado de marca #672990,
   verde #2f8f5b, ámbar #c98a12, azul #2f6fb5 y rojo #c8382f. El ámbar NO se usa
   para texto —no llega a 4,5:1 sobre blanco—, solo para canto y relleno, que es
   la salvedad que ese documento deja escrita.

   Y ESOS CINCO SIGUEN SIENDO MORADO, VERDE, ÁMBAR, AZUL Y ROJO después del
   rediseño «El plano de sala» (2026-09-17), a propósito: salen de `sala.css`,
   que es una COPIA del original del TPV y que una prueba compara por hash
   (PaletaDeSalaTests). Los siete estados de una mesa tienen que pintarse IGUAL
   en la nube y en la caja, así que el plano de sala del TPV manda aquí y la
   tinta del plano de la central no entra. Lo que sí cambia alrededor —el
   lienzo, los muebles preajustados, las tarjetas— está en esta hoja y ya usa
   las fichas del plano.

   Y DESDE EL 2026-09-12 NO SE ESCRIBEN AQUÍ: son los tokens --sala-* de
   wwwroot\css\sala.css, que es EL MISMO FICHERO que carga el TPV desde la
   biblioteca Táctil (una copia que refresca el objetivo MSBuild
   TentaloCopiarPaletaDeSala y vigila la prueba PaletaDeSalaTests). Los dos
   frentes pintan el mismo FloorPlanDTO y hasta ese encargo lo hacían con dos
   paletas distintas: arriba las mesas libres con relleno suave y «4 plazas» en
   gris, abajo en blanco y con un «4» pelado. La cabecera de sala.css cuenta la
   historia entera y lleva la tabla de tokens.

   Y NINGÚN ESTADO SE DISTINGUE SOLO POR EL COLOR: cocina lista, cuenta pedida,
   reservada y bloqueada llevan además un glifo, y la inactiva un rayado. Es la
   misma regla del sistema de diseño que hace que las insignias lleven texto. */

/* Los tokens del diseñador. Viven aquí y no en :root porque son de esta
   pantalla: el resto del administrador no pinta planos. */
.salas-editor,
.salas-tres-columnas,
.salas-tarjeta,
.salas-vacio {
    --salas-papel: var(--sala-suelo);
    --salas-lienzo: var(--sala-lienzo);
    --salas-canto: var(--sala-suelo-canto);
    --salas-tinta: var(--sala-tinta);
    --salas-tinta-2: #6b6373;
    --salas-marca: var(--tentalo-marca);
    --salas-sombra-1: 0 1px 2px rgba(42, 26, 62, 0.06), 0 1px 3px rgba(42, 26, 62, 0.07);
    --salas-sombra-3: 0 2px 4px rgba(42, 26, 62, 0.08), 0 6px 16px rgba(42, 26, 62, 0.12);
}

/* --- EL EDITOR A PANTALLA (§15 de docs\tpv\diseno-de-salas.md, 2026-09-27) ----
   «Se desaprovecha mucha pantalla, si haces zoom, lo haces dentro del
   rectángulo en el que está». El lienzo vivía en un recuadro de unos 340 px de
   alto en mitad de una página que seguía hacia abajo con el panel de
   propiedades. Ahora, con el editor abierto, EL MARCO MIDE LA VENTANA y no se
   desplaza: la barra, los taburetes y la línea de la central se quedan donde
   están y todo lo que sobra es del editor, que lo reparte en una columna —su
   cabeza, la barra de herramientas y las tres columnas— con el lienzo
   llevándose el alto entero. Las columnas se desplazan por dentro.

   Va con `:has()` y no con una clase puesta desde C# en el <html>: el marco no
   sabe qué pantalla lleva dentro y así no hay nada que quitar al salir. */
.plano-marco:has(.salas-editor) {
    block-size: 100vh;
    block-size: 100dvh;
    min-block-size: 0;
    overflow: hidden;
}

/* EL CUERPO DEL MARCO, ATADO AL ALTO QUE QUEDA (2026-10-06, «el plano no se
   ajusta» en la sala «Barra» de T000010). La barra lateral del rediseño D2
   (hoja-limpia.css) metió entre el marco y el cuerpo una REJILLA,
   `.plano-marco-cuerpo`, con `align-items: start` y la fila a lo que mida su
   contenido. Con eso el cuerpo dejó de medir el alto que sobra y pasó a medir
   lo que mide el editor: la columna más alta —las propiedades, unos 1.370 px—
   estiraba el lienzo, salas.js medía ESE hueco (no el que se ve), la vista
   centraba la sala en él y el marco, con `overflow: hidden`, cortaba lo de
   abajo: hueco gris arriba, sala a media altura y cortada. Y como la hoja del
   <svg> nunca es menor que el hueco, al plegar las columnas el hueco ya no
   encogía: el lienzo sostenía su propio alto.

   Aquí la rejilla tiene UNA fila que mide lo que sobra de la ventana
   (`minmax(0, 1fr)`, y `min-block-size: 0` para que como hijo flexible del
   marco pueda quedarse por debajo de su contenido), y el cuerpo se estira a
   ella. Así cada caja entre el marco y el lienzo tiene el alto atado y el
   hueco mide lo que se ve. Lo vigila
   EditorDeSalasAPantallaTests.Cada_caja_entre_el_marco_y_el_editor_tiene_el_alto_atado. */
.plano-marco:has(.salas-editor) .plano-marco-cuerpo {
    min-block-size: 0;
    grid-template-rows: minmax(0, 1fr);
}

.plano-marco:has(.salas-editor) .plano-cuerpo {
    display: flex;
    flex-direction: column;
    align-self: stretch;
    min-block-size: 0;
    padding-block: 0.75rem;
}

.plano-marco:has(.salas-editor) .plano-contenido {
    flex: 1 1 auto;
    min-block-size: 0;
    inline-size: 100%;
    display: flex;
    flex-direction: column;
}

/* `position: relative` aquí y en el cuerpo de cada columna NO es decorativo: lo
   que va con `position: absolute` dentro (el <input> de la imagen de fondo, los
   textos solo para el lector de pantalla) tomaba de bloque contenedor la
   VENTANA, escapaba del recorte del marco y volvía a hacer la página más alta
   que la ventana. */
.salas-editor {
    position: relative;
    flex: 1 1 auto;
    min-block-size: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

/* La cabeza, la barra y los avisos miden lo que su contenido: si se partieran en
   dos líneas, encogerlos haría que la barra se pintara encima. Solo las columnas
   ceden alto. */
.salas-editor > * {
    flex-shrink: 0;
}

.salas-editor > .salas-tres-columnas {
    flex-shrink: 1;
}

/* LA PANTALLA COMPLETA: el editor sale a toda la ventana, por encima del marco
   (y de la barra del navegador si el navegador la concede; ver salas.js). Por
   debajo de los menús de MudBlazor (1200) y de los cajones del editor (1290+). */
.salas-editor--completa {
    position: fixed;
    inset: 0;
    z-index: 1190;
    padding: 0.5rem 0.75rem 0.75rem;
    background: var(--plano-papel, #f5f3f8);
}

/* Y lo del marco que se pega encima (la barra va a 1200, lo mismo que los menús
   de MudBlazor) se aparta mientras dura: subir el editor por encima de 1200
   dejaría los desplegables de las propiedades debajo de él. */
.plano-marco:has(.salas-editor--completa) .plano-barra-marco {
    visibility: hidden;
}

/* El título de la pantalla existe para el lector de pantalla: lo que se ve es
   el nombre, que se edita en línea. */
.salas-oculto {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.salas-tres-columnas {
    display: grid;
    grid-template-columns: 17rem minmax(0, 1fr) 21rem;
    grid-template-rows: minmax(0, 1fr);
    gap: 0.75rem;
    align-items: stretch;
    flex: 1 1 auto;
    min-block-size: 0;
}

/* LAS COLUMNAS, a toda altura y con su propio desplazamiento. */
.salas-columna {
    display: flex;
    flex-direction: column;
    min-block-size: 0;
    min-inline-size: 0;
}

.salas-columna-cuerpo {
    position: relative;
    flex: 1 1 auto;
    min-block-size: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
}

/* EL RIEL de una columna plegada: un botón de arriba abajo con su icono y su
   nombre, que la vuelve a abrir. Solo existe en escritorio. */
.salas-riel {
    display: none;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
    inline-size: 100%;
    block-size: 100%;
    padding: 0.75rem 0;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.6rem;
    background: var(--plano-hoja, #ffffff);
    color: var(--plano-tinta-2, #5b4a73);
    font: inherit;
    font-size: 0.8125rem;
    font-weight: 560;
    cursor: pointer;
}

.salas-riel:hover {
    color: var(--plano-morado, #672990);
    background: rgba(103, 41, 144, 0.08);
}

.salas-riel:focus-visible {
    outline: 2px solid var(--plano-morado, #672990);
    outline-offset: 2px;
}

.salas-riel-rotulo {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    letter-spacing: 0.02em;
}

@media (min-width: 1201px) {
    .salas-tres-columnas--sin-paleta {
        grid-template-columns: 2.75rem minmax(0, 1fr) 21rem;
    }

    .salas-tres-columnas--sin-propiedades {
        grid-template-columns: 17rem minmax(0, 1fr) 2.75rem;
    }

    .salas-tres-columnas--sin-paleta.salas-tres-columnas--sin-propiedades {
        grid-template-columns: 2.75rem minmax(0, 1fr) 2.75rem;
    }

    .salas-columna-plegada .salas-riel {
        display: flex;
    }

    .salas-columna-plegada .salas-columna-cabecera,
    .salas-columna-plegada .salas-columna-cuerpo {
        display: none;
    }
}

/* Por debajo de 1200 px el lienzo se queda sin sitio util: la paleta y las
   propiedades pasan a ser CAJONES sobre el plano y el lienzo ocupa el ancho.
   No son dos instancias distintas de los componentes -eso duplicaria el estado
   local de la paleta, que se acuerda de la zona y del nombre de la mesa nueva-
   sino las MISMAS columnas sacadas del flujo. */
@media (max-width: 1200px) {
    .salas-tres-columnas {
        grid-template-columns: minmax(0, 1fr);
    }

    .salas-columna {
        position: fixed;
        top: 0;
        bottom: 0;
        z-index: 1300;
        width: min(21rem, 88vw);
        overflow-y: auto;
        padding: 0.75rem;
        background: #ffffff;
        box-shadow: var(--salas-sombra-3);
        transition: transform 180ms ease;
    }

    .salas-columna-izquierda {
        left: 0;
        transform: translateX(-102%);
    }

    .salas-columna-derecha {
        right: 0;
        transform: translateX(102%);
    }

    .salas-columna-abierta {
        transform: translateX(0);
    }

    .salas-columna-cuerpo {
        overflow-y: visible;
    }
}

/* El velo del cajon: tocar fuera lo cierra. */
.salas-velo {
    position: fixed;
    inset: 0;
    z-index: 1290;
    background: rgba(42, 26, 62, 0.32);
}

/* La cabecera de una columna: su nombre como rótulo de plano (nombra una
   COLUMNA) y el botón de plegar, o el de cerrar cuando es un cajón. */
.salas-columna-cabecera {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-block-size: 2.25rem;
    padding-inline: 0.25rem 0;
    font-family: var(--plano-familia, inherit);
    font-size: 0.75rem;
    font-weight: 600;
    font-stretch: 75%;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--plano-tinta-2, #5b4a73);
}

/* Los dos botones que abren los cajones solo existen donde hay cajones. */
.salas-solo-estrecho {
    display: none !important;
}

@media (max-width: 1200px) {
    .salas-solo-estrecho {
        display: inline-flex !important;
    }

    .salas-solo-ancho {
        display: none !important;
    }
}

/* --- La CABEZA del editor: de dónde se viene, qué sala es y si está guardada.
   Una línea de 48 px que sustituye a la cabecera de página y a la antigua
   «barra de la sala» (unos 200 px entre las dos). */
.salas-cabeza {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem 1rem;
    min-block-size: 3rem;
}

.salas-cabeza-volver {
    flex: none;
}

.salas-cabeza-estados {
    margin-inline-start: auto;
}

.salas-barra-identidad {
    display: flex;
    flex-direction: column;
    min-width: 10rem;
    max-width: 26rem;
    flex: 1 1 16rem;
}

/* El nombre en linea: se ve como el titulo de la pantalla hasta que se toca. */
.salas-barra-nombre .mud-input-root {
    font-size: 1.25rem;
    font-weight: 640;
    letter-spacing: -0.01em;
    color: var(--salas-tinta);
}

.salas-barra-nombre {
    margin: 0;
}

.salas-barra-zonas {
    font-size: 0.78rem;
    color: var(--salas-tinta-2);
}

.salas-barra-vista {
    display: flex;
    align-items: center;
    gap: 0.15rem;
    margin-inline-start: auto;
    padding: 0.1rem 0.25rem;
    border: 1px solid var(--tentalo-borde);
    border-radius: var(--plano-radio-control);
}

/* LOS MANDOS DE LA VISTA, sobre el lienzo abajo a la derecha (§15): zoom, su
   tanto por ciento, «Ajustar», el 100 % y la pantalla completa. Flotan sobre el
   plano, así que llevan sombra, como el mapa de situación que va encima. */
.salas-vista {
    position: absolute;
    inset-inline-end: 1rem;
    inset-block-end: 1rem;
    display: flex;
    align-items: center;
    gap: 0.1rem;
    padding: 0.15rem 0.3rem;
    background: var(--plano-hoja, #ffffff);
    border: 1px solid var(--tentalo-borde);
    border-radius: var(--plano-radio-control);
    box-shadow: var(--salas-sombra-3);
}

.salas-lienzo-hueco--ampliado ~ .salas-vista {
    inset-inline-end: 1.5rem;
    inset-block-end: 1.5rem;
}

.salas-vista .mud-icon-button {
    min-width: 40px;
    min-height: 40px;
}

.salas-vista .salas-vista-boton {
    min-height: 40px;
    border-radius: var(--plano-radio-control);
    padding-inline: 0.7rem;
}

.salas-vista-regla {
    align-self: stretch;
    width: 1px;
    margin: 0.4rem 0.2rem;
    background: var(--tentalo-borde);
}

/* «Ajustar» encendido mientras la vista sigue a la ventana. */
.salas-vista .salas-vista-activa {
    color: var(--plano-morado, #672990);
    background: rgba(103, 41, 144, 0.10);
}

.salas-barra-zoom {
    min-width: 3.2rem;
    text-align: center;
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
    color: var(--salas-tinta-2);
}

.salas-barra-guardado {
    display: flex;
    align-items: center;
    gap: 0.35rem;
}

.salas-estado {
    font-size: 0.78rem;
    color: var(--salas-tinta-2);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* «Cambios sin guardar» lleva un punto ambar: el color solo no basta (el ambar
   no llega a 4,5:1 para texto), asi que el texto sigue en gris y el punto es lo
   que salta a la vista. */
.salas-estado-sucio::before {
    content: "";
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    margin-right: 0.35rem;
    border-radius: 50%;
    background: #c98a12;
    vertical-align: baseline;
}

/* --- La barra de herramientas -------------------------------------------- */
.salas-barra {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.15rem;
    padding: 0.2rem 0.4rem;
    background: #ffffff;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.6rem;
}

/* La regla 3 del §6 de docs\central\diseno-web.md: 48 px de caja, sin tocar el
   dibujo del icono. */
.salas-barra .mud-icon-button,
.salas-lienzo-barra .mud-icon-button,
.salas-barra-vista .mud-icon-button,
.salas-barra-guardado .mud-icon-button,
.salas-alinear .mud-icon-button {
    min-width: var(--tentalo-toque);
    min-height: var(--tentalo-toque);
}

.salas-barra-importar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--tentalo-toque);
    min-height: var(--tentalo-toque);
    cursor: pointer;
    border-radius: 50%;
    color: var(--tentalo-tinta-suave);
}

.salas-barra-importar:hover {
    background: rgba(103, 41, 144, 0.08);
}

/* El texto del boton de importar existe para el lector de pantalla y no se ve:
   `display: none` lo quitaria tambien del lector. */
.salas-barra-oculto {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* --- El lienzo ----------------------------------------------------------- */
.salas-lienzo-marco {
    position: relative;
    display: flex;
    flex-direction: column;
    min-block-size: 0;
    min-inline-size: 0;
    background: #ffffff;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.6rem;
    overflow: hidden;
    box-shadow: var(--salas-sombra-1);
}

/* EL HUECO: la caja que se desplaza cuando la sala está ampliada. Las barras se
   pintan siempre que haga falta —también en un Mac con las barras «al
   desplazar»—, porque son lo que dice que hay más plano fuera de la vista. */
.salas-lienzo-hueco {
    flex: 1 1 auto;
    min-block-size: 0;
    overflow: auto;
    overscroll-behavior: contain;
    background: var(--sala-lienzo);
    outline: none;
}

.salas-lienzo-hueco::-webkit-scrollbar {
    width: 12px;
    height: 12px;
}

.salas-lienzo-hueco::-webkit-scrollbar-track,
.salas-lienzo-hueco::-webkit-scrollbar-corner {
    background: var(--sala-lienzo);
}

.salas-lienzo-hueco::-webkit-scrollbar-thumb {
    background: rgba(42, 26, 62, 0.30);
    border: 3px solid var(--sala-lienzo);
    border-radius: 999px;
}

.salas-lienzo-hueco::-webkit-scrollbar-thumb:hover {
    background: rgba(103, 41, 144, 0.60);
}

@supports not selector(::-webkit-scrollbar) {
    .salas-lienzo-hueco {
        scrollbar-color: rgba(42, 26, 62, 0.35) transparent;
    }
}

/* LA MANO: con la barra espaciadora pulsada, arrastrar mueve el lienzo. */
.salas-lienzo-hueco--mano .salas-lienzo,
.salas-lienzo-hueco--mano .salas-figura {
    cursor: grab;
}

.salas-lienzo-hueco--arrastrando .salas-lienzo,
.salas-lienzo-hueco--arrastrando .salas-figura {
    cursor: grabbing;
}

/* EL MAPA DE SITUACIÓN: solo con la sala ampliada. Flota —es de lo poco que
   flota en el editor— y por eso lleva sombra. */
.salas-situacion {
    position: absolute;
    inset-inline-end: 1.5rem;
    inset-block-end: calc(1.5rem + 3.5rem);
    inline-size: 12rem;
    block-size: auto;
    max-block-size: 9rem;
    padding: 0.35rem;
    background: var(--plano-hoja, #ffffff);
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.5rem;
    box-shadow: var(--salas-sombra-3);
    cursor: pointer;
    touch-action: none;
}

.salas-situacion-suelo {
    fill: var(--sala-suelo);
    stroke: var(--sala-suelo-canto);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
}

.salas-situacion-mesa {
    fill: var(--sala-libre-borde);
    opacity: 0.55;
}

.salas-situacion-adorno {
    fill: var(--sala-tinta);
    opacity: 0.35;
}

.salas-situacion-vista {
    fill: rgba(103, 41, 144, 0.12);
    stroke: var(--plano-morado, #672990);
    stroke-width: 2;
    vector-effect: non-scaling-stroke;
}

.salas-lienzo-barra {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.15rem 0.5rem;
    border-bottom: 1px solid var(--tentalo-borde);
}

.salas-lienzo-zoom {
    font-variant-numeric: tabular-nums;
    font-size: 0.8rem;
    color: var(--tentalo-tinta-suave);
    min-width: 3.5rem;
}

.salas-lienzo-medida {
    margin-left: auto;
    font-size: 0.8rem;
    color: var(--tentalo-tinta-suave);
}

/* `touch-action: none` es lo que permite arrastrar con el dedo sin que el
   navegador se lleve el gesto para desplazar la pagina; sin esto, en tableta el
   plano no se puede editar. El pellizco y el arrastre con dos dedos los
   resuelve salas.js.

   EL TAMAÑO DE AQUÍ ES UN RESPALDO (§15). Quien manda es el `style` en línea que
   pone LienzoDeSala con la vista (VistaDelLienzo): el <svg> es la HOJA, que mide
   lo que la sala a la escala de ahora con su margen y nunca menos que el hueco.
   Mientras no hay medida -el primer pintado, y bUnit- se estira al hueco y el
   `viewBox` con `meet` encaja la sala sola, que es lo mismo que «Ajustar». */
.salas-lienzo {
    display: block;
    width: 100%;
    height: 100%;
    touch-action: none;
    background: var(--sala-lienzo);
    cursor: default;
}

.salas-lienzo:focus-visible {
    outline: 2px solid var(--tentalo-marca);
    outline-offset: -2px;
}

/* El «papel» de la sala: blanco calido con una sombra de 1 px, para que se vea
   donde acaba la sala y donde empieza el lienzo. */
.salas-suelo {
    stroke: var(--sala-suelo-canto);
    stroke-width: var(--sala-canto);
    vector-effect: non-scaling-stroke;
    filter: drop-shadow(0 1px 2px rgba(42, 26, 62, 0.10));
}

/* La rejilla, en PUNTOS y no en lineas: una trama que se ve al mirarla y
   desaparece al mirar el plano.

   SE SELECCIONA POR EL ID DEL <pattern> Y NO POR LA CLASE DEL <rect>. Los puntos
   viven DENTRO del patron, que esta en <defs>; el rectangulo que lleva la clase
   `salas-rejilla` solo lo referencia con fill="url(#salas-rejilla)" y no tiene
   hijos. Con `.salas-rejilla circle` la regla no casaba con nada y la rejilla no
   se veia -que es lo que le pasaba a la version de lineas de M2-. */
#salas-rejilla circle {
    fill: var(--sala-rejilla);
}

#salas-rayado line {
    stroke: var(--sala-inactiva-rayado);
    stroke-width: 3;
}

/* --- Las figuras --------------------------------------------------------- */
.salas-figura {
    cursor: move;
}

/* La miniatura y la vista sin manos no invitan a arrastrar nada. */
.salas-figura-quieta {
    cursor: inherit;
}

.salas-figura:focus-visible {
    outline: none;
}

.salas-figura:focus-visible .salas-figura-cuerpo,
.salas-figura:focus-visible .salas-adorno-cuerpo {
    stroke: var(--sala-elegida-borde);
    stroke-width: 3;
}

/* El CUERPO de una mesa: canto de 1,5 px que no escala y sombra corta. El color
   del canto lo pone la figura (atributo `stroke`). */
.salas-figura-cuerpo {
    stroke-width: var(--sala-canto);
    vector-effect: non-scaling-stroke;
}

.salas-figura-mesa .salas-figura-cuerpo {
    filter: var(--sala-sombra);
}

/* Al pasar el raton, canto morado suave: la mesa dice que se puede coger antes
   de que nadie la coja. */
.salas-figura-mesa:hover .salas-figura-cuerpo {
    stroke: rgba(103, 41, 144, 0.55);
}

/* Al arrastrar, la mesa se despega del plano. La capa de arriba del lienzo es
   la de lo seleccionado, que es justo lo que se esta moviendo. */
.salas-figura-elegida .salas-figura-cuerpo {
    filter: drop-shadow(0 3px 6px rgba(42, 26, 62, 0.22));
}

.salas-figura-detalle {
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
    opacity: 0.55;
}

/* --- El mobiliario (§14 de docs\tpv\diseno-de-salas.md, «Dibujo») -----------
   UNA MESA ES SU HUELLA: tablero y sillas dentro del recuadro del DTO, como en
   el plano antiguo. La huella es invisible y solo sirve para cogerla entre dos sillas.
   Las sillas, los taburetes y los bancos de la cabina salen de los tokens
   --sala-silla-* de sala.css, los mismos que pinta el TPV. */
.salas-figura-huella {
    fill: transparent;
    stroke: none;
}

.salas-silla-asiento {
    fill: var(--sala-silla);
    stroke: var(--sala-silla-canto);
    stroke-width: 0.75;
    vector-effect: non-scaling-stroke;
}

.salas-silla-respaldo {
    fill: var(--sala-silla-respaldo);
}

.salas-taburete,
.salas-banco {
    fill: var(--sala-silla);
    stroke: var(--sala-silla-respaldo);
    stroke-width: 1.25;
    vector-effect: non-scaling-stroke;
}

/* La planta: sombra de la maceta, roseta clara, roseta honda y centro. Un color
   propio del adorno llega en `style` y gana a estas reglas. */
.salas-planta-sombra {
    fill: var(--sala-planta-sombra);
    stroke: none;
}

.salas-planta-hoja {
    fill: var(--sala-adorno-planta);
}

.salas-planta-hoja-honda {
    fill: var(--sala-planta-honda);
}

.salas-planta-centro {
    fill: var(--sala-planta-centro);
}

/* El mueble importado del plano antiguo sin clasificar: un bulto neutro con canto. En el EDITOR
   su canto es de puntos, que dice «esto está por decidir» —se coge y se le
   cambia la clase en las propiedades—; en la miniatura, no. */
.salas-mueble {
    fill: var(--sala-adorno-mueble);
    stroke: var(--sala-adorno-mueble-canto);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
}

.salas-lienzo .salas-adorno-de-origen .salas-mueble {
    stroke: var(--sala-adorno-tinta);
    stroke-dasharray: 2 3;
}

/* Lo macizo —pared y pilar— sin canto visible: el topo oscuro ya es el borde. */
.salas-adorno-macizo {
    stroke-width: 0.5;
}

/* La hoja de una puerta abierta: el único trazo firme de la puerta. */
.salas-adorno-hoja {
    stroke-width: 2.5;
    vector-effect: non-scaling-stroke;
    stroke-linecap: round;
}

.salas-figura-rotulo {
    text-anchor: middle;
    dominant-baseline: middle;
    fill: var(--sala-tinta);
    font-weight: var(--sala-nombre-peso);
    pointer-events: none;
}

/* El aforo: el 60 % del nombre y en gris. Nunca compite con el. */
.salas-figura-aforo {
    text-anchor: middle;
    dominant-baseline: middle;
    fill: var(--sala-tinta-2);
    font-weight: 400;
    pointer-events: none;
}

.salas-figura-icono {
    text-anchor: end;
    pointer-events: none;
}

/* SELECCION: anillo morado de 2 px. Las asas cuadradas blancas con borde morado
   estan mas abajo (.salas-asa). */
.salas-figura.salas-figura-elegida .salas-figura-cuerpo,
.salas-figura.salas-figura-elegida .salas-adorno-cuerpo,
.salas-figura.salas-figura-elegida .salas-adorno-zona {
    stroke: var(--sala-elegida-borde);
    stroke-width: var(--sala-canto-acento);
}

.salas-figura.salas-figura-error .salas-figura-cuerpo,
.salas-figura.salas-figura-error .salas-adorno-cuerpo {
    stroke: var(--sala-bloqueada-borde);
    stroke-width: 2.5;
    stroke-dasharray: 7 5;
}

/* --- Los adornos: neutros, finos y sin competir con las mesas ------------- */
.salas-adorno-cuerpo {
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
}

.salas-adorno-detalle {
    pointer-events: none;
}

/* El arco de la puerta y las dos lineas de la ventana: trazo fino de plano. */
.salas-adorno-arco,
.salas-adorno-vidrio {
    stroke-width: 1.5;
    vector-effect: non-scaling-stroke;
    fill: none;
}

.salas-adorno-filo,
.salas-adorno-peldano {
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
    opacity: 0.7;
}

.salas-adorno-linea {
    fill: none;
    stroke-linecap: round;
}

.salas-adorno-zona {
    stroke-width: var(--sala-canto);
    vector-effect: non-scaling-stroke;
    stroke-dasharray: 10 7;
}

.salas-adorno-rotulo {
    text-anchor: start;
    dominant-baseline: hanging;
    fill: var(--sala-adorno-tinta);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    pointer-events: none;
}

/* La caja de un texto libre solo existe para poder cogerlo con el raton. */
.salas-adorno-caja {
    fill: transparent;
    stroke: rgba(74, 100, 120, 0.35);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
    stroke-dasharray: 6 6;
}

/* --- Las guias de alineacion --------------------------------------------- */
.salas-guia {
    stroke: var(--tentalo-marca);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
    stroke-dasharray: 6 5;
    opacity: 0.75;
    pointer-events: none;
}

/* --- Las asas de la seleccion -------------------------------------------- */
.salas-envolvente {
    fill: none;
    stroke: var(--tentalo-marca);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
    stroke-dasharray: 6 5;
    opacity: 0.7;
    pointer-events: none;
}

.salas-asa {
    fill: #ffffff;
    stroke: var(--tentalo-marca);
    stroke-width: 1.5;
    vector-effect: non-scaling-stroke;
    cursor: nwse-resize;
}

.salas-asa-girar {
    cursor: grab;
}

.salas-asa-girar:active {
    cursor: grabbing;
}

.salas-asa-brazo {
    stroke: var(--tentalo-marca);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
    pointer-events: none;
}

.salas-marco {
    fill: rgba(103, 41, 144, 0.08);
    stroke: var(--tentalo-marca);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
    stroke-dasharray: 6 4;
    pointer-events: none;
}

/* --- Los siete estados del TPV (vista de muestra) -------------------------
   Los mismos siete tokens que consume el bloque `plano-de-sala` de la caja
   (frontend-blazor\Tentalo.POS.Terminal\wwwroot\css\terminal.css). El
   `!important` del relleno es lo que hace que EL ESTADO GANE AL COLOR de la
   mesa —que viaja en el atributo `fill`—: una mesa ocupada es morada venga de
   la zona que venga, porque lo que hay que leer es «tiene gente» y no «es de la
   terraza». La LIBRE es la única que no lo lleva, justo para que ahí sí se vea
   el tinte de su zona.
   -------------------------------------------------------------------------- */
.salas-figura.salas-mesa-libre .salas-figura-cuerpo {
    fill: var(--sala-libre-fondo);
    stroke: var(--sala-libre-borde);
}

.salas-figura.salas-mesa-ocupada .salas-figura-cuerpo {
    fill: var(--sala-ocupada-fondo) !important;
    stroke: var(--sala-ocupada-borde);
    stroke-width: var(--sala-canto-acento);
}

.salas-figura.salas-mesa-cocina .salas-figura-cuerpo {
    fill: var(--sala-cocina-fondo) !important;
    stroke: var(--sala-cocina-borde);
    stroke-width: var(--sala-canto-fuerte);
}

.salas-figura.salas-mesa-cuenta .salas-figura-cuerpo {
    fill: var(--sala-cuenta-fondo) !important;
    stroke: var(--sala-cuenta-borde);
    stroke-width: var(--sala-canto-fuerte);
}

.salas-figura.salas-mesa-inactiva .salas-figura-cuerpo {
    fill: url(#salas-rayado) !important;
    stroke: var(--sala-inactiva-borde);
}

.salas-figura.salas-mesa-reservada .salas-figura-cuerpo {
    stroke: var(--sala-reservada-borde);
    stroke-width: var(--sala-canto-acento);
    stroke-dasharray: var(--sala-reservada-guion);
}

.salas-figura.salas-mesa-bloqueada .salas-figura-cuerpo {
    fill: var(--sala-bloqueada-fondo) !important;
    stroke: var(--sala-bloqueada-borde);
}

/* La leyenda de la vista de estados, sobre el lienzo abajo a la izquierda: ya
   no roba una fila de alto debajo del plano. */
.salas-leyenda {
    position: absolute;
    inset-inline-start: 0.75rem;
    inset-block-end: 0.75rem;
    max-inline-size: calc(100% - 25rem);
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 0.75rem;
    padding: 0.35rem 0.6rem;
    background: rgba(252, 251, 253, 0.94);
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.5rem;
    font-size: 0.8rem;
    color: var(--tentalo-tinta-suave);
    pointer-events: none;
}

.salas-leyenda-item {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.salas-leyenda-muestra {
    width: 1rem;
    height: 1rem;
    border-radius: 0.15rem;
    border: 2px solid var(--sala-libre-borde);
    background: var(--sala-libre-fondo);
}

.salas-mesa-ocupada .salas-leyenda-muestra {
    background: var(--sala-ocupada-fondo);
    border-color: var(--sala-ocupada-borde);
}

.salas-mesa-cocina .salas-leyenda-muestra {
    background: var(--sala-cocina-fondo);
    border-color: var(--sala-cocina-borde);
}

.salas-mesa-cuenta .salas-leyenda-muestra {
    background: var(--sala-cuenta-fondo);
    border-color: var(--sala-cuenta-borde);
}

.salas-mesa-inactiva .salas-leyenda-muestra {
    background: repeating-linear-gradient(45deg, var(--sala-inactiva-fondo) 0 3px, #d6d2da 3px 6px);
    border-color: var(--sala-inactiva-borde);
}

.salas-mesa-reservada .salas-leyenda-muestra {
    background: var(--sala-reservada-fondo);
    border-color: var(--sala-reservada-borde);
    border-style: dashed;
}

.salas-mesa-bloqueada .salas-leyenda-muestra {
    background: var(--sala-bloqueada-fondo);
    border-color: var(--sala-bloqueada-borde);
}

/* --- La paleta ----------------------------------------------------------- */
.salas-paleta {
    background: #ffffff;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.6rem;
    overflow: hidden;
    box-shadow: var(--salas-sombra-1);
}

/* El titulo de una seccion de la paleta: el icono a la izquierda del texto, y la
   flecha de plegado de MudBlazor donde estaba. Con el parametro `Icon` del panel
   el icono SUSTITUYE a esa flecha, y una seccion plegable que no ensena que se
   pliega es peor que una sin icono. */
.salas-paleta-titulo {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    font-weight: 600;
    color: var(--tentalo-tinta);
}

.salas-paleta-titulo .mud-icon-root {
    color: var(--tentalo-marca);
}

.salas-paleta-buscador {
    margin-bottom: 0.5rem;
}

.salas-paleta-lista {
    list-style: none;
    margin: 0;
    padding: 0;
    max-height: 18rem;
    overflow-y: auto;
}

.salas-paleta-item {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    min-height: var(--tentalo-toque);
    padding: 0 0.25rem;
    border-bottom: 1px solid var(--tentalo-borde);
    border-radius: 0.3rem;
    cursor: grab;
}

.salas-paleta-item:hover {
    background: rgba(103, 41, 144, 0.05);
}

.salas-paleta-item:active {
    cursor: grabbing;
}

.salas-paleta-nombre {
    font-weight: 600;
    font-size: 0.85rem;
}

.salas-paleta-zona {
    margin-left: auto;
    font-size: 0.75rem;
    color: var(--tentalo-tinta-suave);
}

.salas-paleta-nada {
    padding: 0.5rem 0.25rem;
    font-size: 0.8rem;
    color: var(--tentalo-tinta-suave);
}

.salas-paleta-rejilla {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
    gap: 0.4rem;
}

.salas-preset {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0.1rem;
    min-height: var(--tentalo-toque);
    padding: 0.4rem 0.35rem 0.3rem;
    text-align: left;
    background: #ffffff;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.45rem;
    cursor: grab;
    font: inherit;
    color: inherit;
    transition: border-color 150ms ease, background 150ms ease, box-shadow 150ms ease;
}

.salas-preset:hover {
    border-color: var(--tentalo-marca);
    box-shadow: var(--salas-sombra-1);
}

.salas-preset:active {
    cursor: grabbing;
}

.salas-preset:focus-visible {
    outline: 2px solid var(--tentalo-marca);
    outline-offset: 1px;
}

.salas-preset-elegido {
    border-color: var(--tentalo-marca);
    background: rgba(103, 41, 144, 0.06);
}

.salas-preset-nombre {
    font-size: 0.78rem;
    font-weight: 600;
    line-height: 1.15;
}

.salas-preset-medida {
    font-size: 0.68rem;
    color: var(--tentalo-tinta-suave);
    font-variant-numeric: tabular-nums;
}

/* La silueta del preset: el dibujo manda y el texto lo acompaña. */
.salas-muestra {
    display: block;
    width: 100%;
    height: 2.4rem;
    margin-bottom: 0.15rem;
}

.salas-muestra rect,
.salas-muestra circle,
.salas-muestra ellipse,
.salas-muestra path {
    fill: #e7ecea;
    stroke: #5b4a73;
    stroke-width: 1;
}

.salas-muestra-silla {
    fill: #cfc8da !important;
    stroke: none !important;
}

.salas-muestra-linea {
    fill: none !important;
    stroke: #5b4a73 !important;
    stroke-width: 1.2 !important;
    stroke-linecap: round;
}

.salas-muestra-filo {
    stroke: #5b4a73;
    stroke-width: 1;
}

.salas-muestra-punteado {
    fill: rgba(42, 26, 62, 0.06) !important;
    stroke-dasharray: 3 2.5;
}

/* --- El panel de propiedades --------------------------------------------- */
.salas-propiedades {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

/* El rotulo de un grupo de campos: la separacion que evita que veinte campos
   seguidos parezcan un formulario de alta de proveedor. */
.salas-propiedades-rotulo {
    margin: 0.6rem 0 0.15rem;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--tentalo-tinta-suave);
}

.salas-propiedades-pareja {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.5rem;
}

/* «Quién la ve» (§15): un bloque por local cuando la sala vale en todos, y
   aparte, en mostaza —atención, no error—, los grupos de otros locales que
   estaban marcados. */
.salas-quien .campo-casillas__rejilla {
    grid-template-columns: minmax(0, 1fr);
}

.salas-quien-bloque + .salas-quien-bloque {
    margin-block-start: 0.75rem;
    padding-block-start: 0.75rem;
    border-block-start: 1px solid var(--plano-linea-fina, rgba(42, 26, 62, 0.12));
}

.salas-quien-ajenos {
    margin-block-start: 0.75rem;
    padding: 0.6rem 0.75rem;
    border-radius: 0.5rem;
    background: var(--plano-mostaza-aguada, rgba(233, 180, 76, 0.18));
    color: var(--plano-tinta, #2a1a3e);
    font-size: 0.8125rem;
}

.salas-quien-ajenos-texto {
    margin: 0 0 0.25rem;
}

/* «REHACER DESDE UN PLANO DEL SISTEMA ANTERIOR…» (§16): cada plano del salón es una fila
   que se elige entera —vista previa a la izquierda, datos a la derecha—, y la
   elegida se TIÑE y lleva el canto morado, como una fila elegida. */
.salas-origen-lista {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    --salas-tinta-2: var(--plano-tinta-2, #5b4a73);
    --salas-lienzo: var(--sala-lienzo);
    --salas-canto: var(--sala-suelo-canto);
}

.salas-origen-opcion {
    display: grid;
    grid-template-columns: 9.5rem minmax(0, 1fr);
    align-items: center;
    gap: 0.9rem;
    padding: 0.5rem;
    border: 1px solid var(--plano-linea-fina, rgba(42, 26, 62, 0.12));
    border-radius: 0.6rem;
    background: var(--plano-hoja, #ffffff);
    color: var(--plano-tinta, #2a1a3e);
    font: inherit;
    text-align: start;
    cursor: pointer;
}

.salas-origen-opcion:hover {
    background: var(--plano-morado-aguada, rgba(103, 41, 144, 0.10));
}

.salas-origen-opcion--elegida,
.salas-origen-opcion--elegida:hover {
    background: var(--plano-morado-aguada, rgba(103, 41, 144, 0.10));
    border-color: var(--plano-morado, #672990);
    box-shadow: inset 0 0 0 1px var(--plano-morado, #672990);
}

.salas-origen-opcion:focus-visible {
    outline: 2px solid var(--plano-morado, #672990);
    outline-offset: 2px;
}

.salas-origen-previa {
    display: block;
    aspect-ratio: 16 / 10;
    border: 1px solid var(--sala-suelo-canto);
    border-radius: 0.4rem;
    overflow: hidden;
    background: var(--sala-lienzo);
}

.salas-origen-texto {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    min-width: 0;
}

.salas-origen-nombre {
    font-weight: 600;
}

.salas-origen-datos {
    font-size: 0.8125rem;
    color: var(--plano-tinta-2, #5b4a73);
    font-variant-numeric: tabular-nums;
}

.salas-origen-marcas {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
}

.salas-chip-principal {
    background: var(--plano-morado, #672990);
    color: var(--plano-papel, #f5f3f8);
}

.salas-origen-ayuda,
.salas-origen-vacio {
    margin: 0 0 0.75rem;
    color: var(--plano-tinta-2, #5b4a73);
    max-width: 62ch;
}

.salas-origen-pregunta {
    margin: 0 0 0.5rem;
    font-weight: 600;
}

.salas-origen-que-pasa {
    margin: 0;
    padding-inline-start: 1.1rem;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    max-width: 62ch;
}

.salas-alinear {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 0.15rem;
}

.salas-color {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin: 0.35rem 0;
}

.salas-color-etiqueta {
    font-size: 0.85rem;
    color: var(--tentalo-tinta-suave);
}

.salas-color-caja {
    width: 3rem;
    height: var(--tentalo-toque);
    padding: 0;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.35rem;
    background: none;
}

/* Las ocho muestras: cuadrados de 2 rem con 44 px de caja de toque. */
.salas-color-muestras {
    display: grid;
    grid-template-columns: repeat(8, 1fr);
    gap: 0.25rem;
    margin: 0.2rem 0;
}

.salas-color-muestra {
    height: 1.9rem;
    padding: 0;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.3rem;
    cursor: pointer;
    transition: transform 150ms ease, box-shadow 150ms ease;
}

.salas-color-muestra:hover {
    transform: translateY(-1px);
    box-shadow: var(--salas-sombra-1);
}

.salas-color-muestra:focus-visible {
    outline: 2px solid var(--tentalo-marca);
    outline-offset: 1px;
}

.salas-color-elegido {
    border: 2px solid var(--tentalo-marca);
    box-shadow: 0 0 0 2px rgba(103, 41, 144, 0.16);
}

.salas-fondo {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    margin-top: 0.35rem;
}

.salas-fondo-boton {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    min-height: var(--tentalo-toque);
    cursor: pointer;
    color: var(--tentalo-marca);
    font-size: 0.85rem;
}

/* El <InputFile> de verdad, tapado por su etiqueta: un input de fichero no se
   puede dar estilo y su boton nativo no dice nada en castellano. */
.salas-fondo-input {
    position: absolute;
    width: 0.1px;
    height: 0.1px;
    opacity: 0;
    overflow: hidden;
}

.salas-errores {
    margin: 0;
    padding-left: 1.1rem;
}

/* --- La lista de salas ---------------------------------------------------- */
/* UNA SALA SE DIBUJA COMO UNA SALA (tanda 3). Esta lista es, literalmente, el
   plano del local: no tiene sentido que sus piezas sean tarjetas blancas cuando
   la portada ya dibuja cada establecimiento como una habitacion. Mismo lenguaje
   que `.plano-local` y que `.admin-tarjeta`: muro de 2 px en dos lados, linea
   fina en los otros dos, esquina de muro y NADA de sombra. */
.salas-tarjeta {
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: 0.6rem;
    border-radius: var(--plano-esquina-muro);
    background: var(--plano-hoja);
    border: 1px solid var(--plano-linea-fina);
    border-left: 2px solid var(--plano-muro);
    border-bottom: 2px solid var(--plano-muro);
    transition: background-color var(--plano-tiempo) var(--plano-curva);
}

/* La tarjeta ACTIVA del buscador (§15): la que abre Intro. Tinta y un canto de
   morado, sin sombra: se lee como «elegida», igual que una fila elegida. */
.salas-tarjeta--activa {
    background-color: var(--plano-morado-aguada);
    outline: 2px solid var(--plano-morado);
    outline-offset: 2px;
}

/* EL BUSCADOR DE LA LISTA (§15): el campo, el filtro de establecimiento y la
   cuenta, en una fila que se parte en el teléfono. */
.salas-buscador {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 1rem;
    margin-block-end: 1rem;
}

.salas-buscador-campo {
    flex: 0 1 26rem;
    min-inline-size: 14rem;
    margin: 0;
}

.salas-buscador-locales {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.salas-buscador-local {
    min-block-size: 2.25rem;
    padding: 0 0.85rem;
    border: none;
    border-radius: var(--plano-radio-control);
    background: rgba(42, 26, 62, 0.07);
    color: var(--plano-tinta);
    font: inherit;
    font-size: var(--plano-t-13, 0.8125rem);
    cursor: pointer;
}

.salas-buscador-local:hover {
    background: var(--plano-morado-aguada);
}

.salas-buscador-local--elegido,
.salas-buscador-local--elegido:hover {
    background: var(--plano-morado);
    color: var(--plano-papel);
}

.salas-buscador-local:focus-visible {
    outline: 2px solid var(--plano-morado);
    outline-offset: 2px;
}

.salas-buscador-cuenta {
    margin-inline-start: auto;
    font-size: var(--plano-t-13, 0.8125rem);
    color: var(--plano-tinta-2);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.salas-sin-resultados {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    margin-block-end: 1rem;
    color: var(--plano-tinta-2);
}

.salas-sin-resultados p {
    margin: 0;
}

/* Al pasar por encima se TINE, no se levanta: en un plano nada flota. */
.salas-tarjeta:hover {
    background-color: var(--plano-morado-aguada);
    box-shadow: none;
    transform: none;
}

.salas-tarjeta:focus-within {
    background-color: var(--plano-morado-aguada);
    box-shadow: none;
}

.salas-tarjeta-enlace {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    flex: 1 1 auto;
    text-decoration: none;
    color: inherit;
    border-radius: 0.5rem;
}

.salas-tarjeta-enlace:focus-visible {
    outline: 2px solid var(--tentalo-marca);
    outline-offset: 2px;
}

/* EL MARCO 16:10. La miniatura se escala DENTRO de el (preserveAspectRatio), asi
   que todas las tarjetas miden lo mismo y ninguna se estira. */
.salas-tarjeta-marco {
    display: block;
    aspect-ratio: 16 / 10;
    width: 100%;
    overflow: hidden;
    border: 1px solid var(--salas-canto);
    border-radius: 0.5rem;
    background: var(--salas-lienzo);
}

.salas-miniatura {
    display: block;
    width: 100%;
    height: 100%;
}

.salas-miniatura-suelo {
    stroke: #e3ddda;
    stroke-width: 1.5;
    vector-effect: non-scaling-stroke;
}

.salas-tarjeta-texto {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    padding: 0 0.15rem;
}

.salas-tarjeta-nombre {
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.25;
    color: var(--salas-tinta);
}

.salas-tarjeta-linea {
    font-size: 0.8rem;
    color: var(--salas-tinta-2);
}

/* El establecimiento de cada sala: era #8a8394 (3,65:1 sobre blanco a 12 px).
   Pasa al gris morado de la propia pantalla, --salas-tinta-2 (#6b6373), que da
   5,74:1. T4 de docs\central\auditoria-ux-2026-09-15.md. */
.salas-tarjeta-local {
    font-size: 0.75rem;
    color: var(--salas-tinta-2);
}

.salas-tarjeta-pie {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.5rem;
    padding-top: 0.4rem;
    border-top: 1px solid var(--tentalo-borde);
}

.salas-tarjeta-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem;
    min-width: 0;
}

.salas-tarjeta-menu {
    display: inline-flex;
    margin-left: auto;
}

.salas-tarjeta-pie .mud-icon-button {
    min-width: var(--tentalo-toque);
    min-height: var(--tentalo-toque);
}

/* Los chips de la tarjeta: discretos, en gris, y solo cuando hay algo que
   decir. Un chip que aparece siempre no informa de nada. */
.salas-chip {
    display: inline-block;
    padding: 0.12rem 0.4rem;
    border-radius: 999px;
    background: #e7ecea;
    color: var(--salas-tinta-2);
    font-size: 0.7rem;
    font-weight: 600;
    white-space: nowrap;
}

.salas-chip-aviso {
    background: #fdf1dc;
    color: #7a5410;
}

.salas-chip-medida {
    background: none;
    /* Era #8a8394, 3,65:1. Ver .salas-tarjeta-local. */
    color: var(--salas-tinta-2);
    font-weight: 400;
    font-variant-numeric: tabular-nums;
}

/* LA MINIATURA QUE ESTÁ LLEGANDO (2026-10-01, docs/tpv/miniaturas-de-salas-
   2026-10-01.md): el contorno de la sala con un brillo que pasa, para que no se
   confunda con una sala vacía. La que NO ha llegado sale apagada y la tarjeta
   ofrece reintentar en su pie. */
.salas-miniatura--cargando .salas-miniatura-suelo {
    animation: salas-miniatura-brillo 1.4s ease-in-out infinite;
}

.salas-miniatura--fallida .salas-miniatura-suelo {
    fill: #f3f1f4;
    stroke-dasharray: 6 4;
}

@keyframes salas-miniatura-brillo {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.55; }
}

/* Donde irán «· N plazas · Zona …» mientras llega el detalle. */
.salas-tarjeta-linea-cargando {
    display: inline-block;
    inline-size: 7.5rem;
    block-size: 0.7em;
    margin-inline-start: 0.4rem;
    border-radius: 999px;
    background: rgba(42, 26, 62, 0.08);
    vertical-align: baseline;
    animation: salas-miniatura-brillo 1.4s ease-in-out infinite;
}

.salas-chip-reintentar {
    border: none;
    font: inherit;
    font-size: 0.7rem;
    font-weight: 600;
    min-block-size: var(--tentalo-toque);
    cursor: pointer;
}

.salas-chip-reintentar:focus-visible {
    outline: 2px solid var(--plano-morado);
    outline-offset: 2px;
}

/* LAS MESAS SIN COLOCAR, UNA VEZ PARA TODA LA INSTALACIÓN y no en cada tarjeta:
   no son de ninguna sala. */
.salas-sin-colocar {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.25rem 0.5rem;
    margin: -0.25rem 0 1rem;
    font-size: 0.8rem;
    color: var(--salas-tinta-2);
}

.salas-sin-colocar .salas-chip {
    font-size: 0.75rem;
}

/* El esqueleto tiene la MISMA silueta que la tarjeta, para que la pagina no de
   un salto cuando llegan las salas. */
.salas-tarjeta-fantasma .salas-tarjeta-marco {
    border: none;
}

.salas-tarjeta-fantasma .mud-skeleton {
    border-radius: 0.4rem;
}

/* --- El estado vacio ------------------------------------------------------ */
.salas-vacio {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    padding: 2.5rem 1.5rem;
    text-align: center;
    background: #ffffff;
    border: 1px dashed var(--tentalo-borde);
    border-radius: 0.9rem;
}

.salas-vacio-dibujo {
    width: min(18rem, 70vw);
    height: auto;
}

.salas-vacio-suelo {
    fill: var(--salas-papel);
    stroke: var(--salas-canto);
    stroke-width: 1.5;
}

.salas-vacio-rejilla {
    stroke: none;
}

/* Igual que la rejilla del lienzo: por el id del <pattern>, no por la clase del
   rectangulo que lo usa. */
#salas-vacio-puntos circle {
    fill: rgba(42, 26, 62, 0.18);
}

.salas-vacio-pared {
    fill: #ded7cf;
}

.salas-vacio-mesa {
    fill: #e7ecea;
    stroke: #5b4a73;
    stroke-width: 1.5;
}

.salas-vacio-barra {
    fill: #f0e3cf;
    stroke: #c4b39a;
    stroke-width: 1.5;
}

.salas-vacio-texto {
    max-width: 30rem;
}

.salas-vacio-titulo {
    margin: 0 0 0.25rem;
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--salas-tinta);
}

.salas-vacio-detalle {
    margin: 0;
    font-size: 0.88rem;
    color: var(--salas-tinta-2);
}

.salas-vacio-acciones {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem;
}

/* --- Las mesas en la ficha de una zona de venta --------------------------- */
.salas-mesas-enlace {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    min-height: var(--tentalo-toque);
    padding: 0 0.35rem;
    font-size: 0.8rem;
    white-space: nowrap;
    color: var(--tentalo-marca);
    text-decoration: none;
}

.salas-mesas-enlace:hover {
    text-decoration: underline;
}

.salas-mesas-suelta {
    font-size: 0.8rem;
    white-space: nowrap;
    color: var(--tentalo-tinta-suave);
}

/* Quien pide menos movimiento no ve ninguno: la regla de accesibilidad del
   sistema de diseño, aplicada a las transiciones de esta pantalla. */
@media (prefers-reduced-motion: reduce) {
    .salas-tarjeta,
    .salas-preset,
    .salas-color-muestra,
    .salas-columna {
        transition: none;
    }

    .salas-tarjeta:hover {
        transform: none;
    }

    .salas-miniatura--cargando .salas-miniatura-suelo,
    .salas-tarjeta-linea-cargando {
        animation: none;
    }
}

/* ==========================================================================
   EL DISEÑADOR DE IMPRESIÓN (prefijo `impresion-diseno-`)
   ==========================================================================
   Fase P2 de docs\tpv\diseno-de-impresion.md. Tres columnas —paleta, lienzo
   y propiedades— que por debajo de 1200 px se apilan, con el mismo corte que
   `.salas-tres-columnas`: es el ancho por debajo del cual el lienzo se queda
   sin sitio útil.

   «SALA CLARA, TINTA MORADA» (docs\tpv\diseno-sala-clara.md): fondo blanco,
   cantos `--tentalo-borde` y el morado de marca solo donde marca algo —el
   bloque elegido, el foco—. Ni un color inventado: todo sale de los tokens
   `--tentalo-*` que ya define el sistema de diseño.

   LA VISTA PREVIA NO SE ESTILA AQUÍ. Reutiliza `.escpos-vista-previa*` del
   bloque de FORMATOS DE IMPRESIÓN de más arriba, que es el mismo `<pre>`
   monoespaciado con el mismo ancho por número de columnas. Duplicarlo sería
   tener dos verdades sobre cuánto mide un papel de 48 columnas.

   Y NINGÚN ESTADO SE DISTINGUE SOLO POR EL COLOR: el bloque elegido lleva
   además una barra a la izquierda y `aria-pressed`, y un bloque de un tipo
   que esta central no conoce lleva su icono de interrogación además del
   canto punteado. Es la misma regla que hace que las insignias lleven texto. */

/* ==========================================================================
   LA DISPOSICIÓN DEL EDITOR (prefijo `impresion-editor-`)
   ==========================================================================
   Reforma del 2026-09-12. Antes eran tres columnas —paleta, lienzo,
   propiedades— con la VISTA PREVIA DEBAJO DEL LIENZO, y la queja fue exacta:
   «es incómodo tener la vista previa abajo». Y lo era de verdad: un ticket de
   fábrica tiene 120 bloques, la columna del lienzo medía cinco mil píxeles y
   para ver el papel había que bajar hasta el final y volver a subir a cambiar
   una línea. La previa estaba, pero no se veía nunca a la vez que lo que se
   estaba tocando, que es lo único para lo que sirve una vista previa.

   AHORA SON CUATRO PANELES A LA MISMA ALTURA —paleta · lienzo · propiedades ·
   previa— dentro de una caja que ocupa el alto de la ventana, cada uno con SU
   PROPIO SCROLL. El documento se recorre en el panel del lienzo sin mover la
   página, y el papel compuesto está siempre delante.

   EL ALTO ES `100dvh` Y NO `100vh`: en un móvil con la barra del navegador
   plegándose, `vh` deja la última fila debajo del borde de la pantalla. Y se
   le resta la cabecera del administrador con una variable propia, porque el
   alto de esa cabecera lo decide el marco y no este fichero.

   LOS ANCHOS SE ARRASTRAN Y SE RECUERDAN. Tres separadores mueven tres
   variables CSS (`--ancho-paleta`, `--ancho-propiedades`, `--ancho-previa`)
   que `js\impresion.js` escribe y guarda en `localStorage`. El `clamp()` de
   este fichero es el que decide cuánto puede encoger y crecer cada panel: el
   JavaScript solo mueve el número, así que un valor guardado absurdo -de otra
   pantalla, de otro monitor- no puede dejar un panel de tres píxeles.

   POR DEBAJO DE 1400 px NO CABEN CUATRO. La previa deja de ser una columna y
   pasa a compartir la de la derecha con las propiedades en dos pestañas, y
   queda además el botón de «previa flotante», que la abre en un cajón lateral
   SUPERPUESTO y NO MODAL: se sigue editando con la previa delante, que es lo
   que hace falta en un portátil de 1366. Por debajo de 1100 px se apila todo y
   la caja deja de medir el alto de la ventana, porque en un móvil el scroll
   que manda es el de la página.

   «SALA CLARA, TINTA MORADA»: fondo blanco cálido, cantos `--tentalo-borde` y
   el morado solo donde marca algo. */

/* EL CORTE SE MIDE SOBRE EL ESPACIO DE LOS PANELES Y NO SOBRE LA VENTANA, y
   por eso esto es una CONSULTA DE CONTENEDOR y no una media query. El
   administrador tiene una barra lateral de unos 240 px, así que una ventana de
   1440 deja 1.152 px de panel -medido-: decidir con el ancho de la ventana
   habría dejado cuatro columnas donde no caben y un lienzo de 130 px. Con
   `@container` la pregunta es la que importa —«¿cabe una cuarta columna
   AQUÍ?»— y el editor se comporta igual si mañana la barra lateral se pliega.

   El contenedor es `.impresion-editor` y no `.impresion-editor-paneles` porque
   una consulta de contenedor NO puede cambiar los estilos del propio
   contenedor, y lo que hay que cambiar es su `grid-template-columns`. */
/* EL EDITOR SE SALE DEL ANCHO MÁXIMO DEL ADMINISTRADOR. Todas las pantallas del
   administrador viven dentro del MudContainer del AdminLayout, que está en
   MaxWidth.Large: 1.280 px. Para una ficha con dos columnas de campos eso es
   justo lo que se quiere -una línea de texto de dos mil píxeles no se lee-, pero
   este editor son CUATRO PANELES y el ancho es la funcionalidad: con el tope
   puesto, un monitor de 1920 le dejaba al lienzo 296 px, menos que en uno de
   1440, y la pantalla no mejoraba al comprar monitor. Aquí el tope se quita, y
   solo aquí: el `:has` acota la excepción al contenedor que lleva DENTRO el
   editor, sin tocar el layout ni añadirle a la página un parámetro que las otras
   cuarenta pantallas tendrían que ignorar. */
.mud-container:has(> .impresion-editor) {
    max-width: none;
}

.impresion-editor {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    container-type: inline-size;
    container-name: editor;
    /* La cabecera del administrador más el aire de la página. Es una variable y
       no un número suelto para poder afinarla en un solo sitio. */
    --impresion-editor-alto-cabecera: 8.5rem;
    height: calc(100dvh - var(--impresion-editor-alto-cabecera));
    min-height: 34rem;
}

.impresion-editor-paneles {
    /* Los anchos por omisión son los MÍNIMOS CÓMODOS y no los holgados: a partir
       de aquí el lienzo se queda todo lo que sobre, que es lo que hay que ver
       ancho en un monitor grande, y quien quiera más paleta la arrastra. */
    --ancho-paleta: 15rem;
    --ancho-propiedades: 19rem;
    --ancho-previa: 23rem;
    --impresion-editor-separador: 0.5rem;
    display: grid;
    grid-template-columns:
        clamp(11rem, var(--ancho-paleta), 26rem)
        var(--impresion-editor-separador)
        minmax(14rem, 1fr)
        var(--impresion-editor-separador)
        clamp(15rem, var(--ancho-propiedades), 34rem)
        var(--impresion-editor-separador)
        clamp(16rem, var(--ancho-previa), 44rem);
    flex: 1 1 auto;
    min-height: 0; /* sin esto un hijo con scroll estira el grid en vez de desplazarse */
}

/* --- Un panel ------------------------------------------------------------- */
.impresion-editor-panel {
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    background: #ffffff;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.5rem;
    overflow: hidden;
}

.impresion-editor-panel-cabecera {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex: 0 0 auto;
    min-height: 2.5rem;
    padding: 0.25rem 0.6rem;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--tentalo-tinta-suave);
    /* Blanco cálido, la mitad de camino entre el blanco del panel y el canto:
       es lo que separa la cabecera del cuerpo sin meter otra línea. */
    background: #f2f5f3;
    border-bottom: 1px solid var(--tentalo-borde);
}

.impresion-editor-panel-cabecera .mud-icon-button {
    min-width: 2rem;
    min-height: 2rem;
}

.impresion-editor-panel-cuerpo {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    /* Nada queda aplastado: un panel con dos campos sigue teniendo cuerpo. */
    padding: 0;
}

.impresion-editor-panel-cuenta {
    margin-left: auto;
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    font-variant-numeric: tabular-nums;
}

/* --- Los separadores ------------------------------------------------------ */
/* Ocho píxeles de zona sensible con una línea de uno en medio: la zona de
   agarre tiene que ser cómoda y la línea tiene que ser fina. */
.impresion-editor-separador {
    position: relative;
    padding: 0;
    cursor: col-resize;
    background: transparent;
    border: 0;
    touch-action: none;
}

.impresion-editor-separador::after {
    content: "";
    position: absolute;
    inset: 0.25rem 50%;
    width: 1px;
    background: var(--tentalo-borde);
    transition: background-color 120ms ease, width 120ms ease;
}

.impresion-editor-separador:hover::after,
.impresion-editor-separador-activo::after {
    width: 3px;
    inset-inline: calc(50% - 1px);
    background: var(--tentalo-marca);
}

.impresion-editor-separador:focus-visible {
    outline: 2px solid var(--tentalo-marca);
    outline-offset: -2px;
    border-radius: 0.25rem;
}

/* --- La cabecera del editor ----------------------------------------------- */
.impresion-editor-barra {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    flex: 0 0 auto;
    padding: 0.5rem 0.75rem;
    background: #ffffff;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.5rem;
}

/* Con qué se compone la vista previa (tanda T2 de «todo a Diseño»): el local que
   emite, la caja y la muestra o su último documento real. Una fila bajo la barra. */
.impresion-editor-contexto {
    flex: 0 0 auto;
    padding: 0.1rem 0.75rem;
}

.impresion-editor-contexto-campos {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
}

.impresion-editor-contexto-campos > div {
    flex: 0 1 16rem;
    min-width: 10rem;
}

/* El NOMBRE se edita EN LÍNEA y en el sitio donde se lee, no en un campo del
   panel de la derecha: es el título de la pantalla. Parece un título hasta que
   se pulsa, y entonces enseña su canto. */
.impresion-editor-nombre {
    flex: 1 1 14rem;
    min-width: 8rem;
    max-width: 26rem;
    padding: 0.2rem 0.4rem;
    font-family: inherit;
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--tentalo-tinta);
    background: transparent;
    border: 1px solid transparent;
    border-radius: 0.3rem;
}

.impresion-editor-nombre:hover {
    border-color: var(--tentalo-borde);
}

.impresion-editor-nombre:focus {
    outline: none;
    background: #ffffff;
    border-color: var(--tentalo-marca);
    box-shadow: 0 0 0 3px rgba(103, 41, 144, 0.14);
}

.impresion-editor-chips {
    display: flex;
    flex: 0 0 auto;
    flex-wrap: wrap;
    gap: 0.35rem;
    align-items: center;
}

/* Los grupos de acciones, separados por un canto fino: deshacer y rehacer
   juntos, las herramientas del documento juntas, y guardar al final y solo. */
.impresion-editor-acciones {
    display: flex;
    align-items: center;
    gap: 0.15rem;
}

.impresion-editor-acciones + .impresion-editor-acciones {
    padding-left: 0.4rem;
    border-left: 1px solid var(--tentalo-borde);
}

.impresion-editor-acciones-final {
    margin-left: auto;
}

/* La regla 3 del §6 de docs\central\diseno-web.md: 48 px de caja de toque, sin
   tocar el dibujo del icono. */
.impresion-editor-acciones .mud-icon-button {
    min-width: var(--tentalo-toque);
    min-height: var(--tentalo-toque);
}

/* --- Las pestañas de la columna estrecha ---------------------------------- */
/* Por debajo de 1400 px las propiedades y la previa comparten columna. Las
   pestañas se pintan SIEMPRE en el árbol -no se crean al estrecharse- para que
   el estado de la pestaña elegida no dependa del ancho de la ventana. */
/* LAS DOS CARAS DEL PANEL DE LA DERECHA. Por omisión -o sea, con la previa en su
   propia columna- este panel es SIEMPRE el de propiedades: se ve su cabecera y las
   pestañas sobran. Por debajo del corte se cambian los papeles. Lo decide el CSS y
   no C#, que es lo que permite que el estado de la pestaña no dependa del ancho. */
.impresion-editor-solo-estrecho {
    display: none;
}

.impresion-editor-pestanas {
    display: none;
    flex: 0 0 auto;
    gap: 0.25rem;
    padding: 0.3rem 0.4rem;
    border-bottom: 1px solid var(--tentalo-borde);
}

.impresion-editor-pestana {
    flex: 1 1 0;
    min-height: 2.25rem;
    padding: 0.25rem 0.5rem;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--tentalo-tinta-suave);
    cursor: pointer;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 0.3rem;
}

.impresion-editor-pestana:hover {
    background: rgba(103, 41, 144, 0.05);
}

.impresion-editor-pestana-activa {
    color: var(--tentalo-marca);
    background: rgba(103, 41, 144, 0.1);
    border-color: rgba(103, 41, 144, 0.3);
}

.impresion-editor-pestana:focus-visible {
    outline: 2px solid var(--tentalo-marca);
    outline-offset: 1px;
}

/* El cajón de la previa flotante. NO ES MODAL a propósito: se sigue editando
   con la previa delante, que es justo para lo que se abre. */
.impresion-editor-cajon .mud-drawer-content {
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* --- Los cortes ----------------------------------------------------------- */
/* 1.180 px DE PANEL: por debajo, la previa deja de ser columna y se va a las
   pestañas de la derecha, con el botón de «previa flotante» como salida. El
   número sale de sumar: paleta 15 rem + propiedades 19 rem + previa 23 rem +
   tres separadores = 57,5 rem ≈ 920 px, más los 16 rem (256 px) que necesita
   una fila del lienzo con su icono, su texto y sus cuatro asas. Con la barra
   lateral del administrador puesta y sin el tope del contenedor, una ventana de
   1440 da 1.152 px de panel (queda con pestañas) y una de 1920, 1.632 (cuatro
   columnas). Medido con Playwright sobre el volcado; ver el §11. */
@container editor (max-width: 1180px) {
    .impresion-editor-paneles {
        grid-template-columns:
            clamp(11rem, var(--ancho-paleta), 26rem)
            var(--impresion-editor-separador)
            minmax(14rem, 1fr)
            var(--impresion-editor-separador)
            clamp(15rem, var(--ancho-propiedades), 34rem);
    }

    .impresion-editor-columna-previa,
    .impresion-editor-separador-previa {
        display: none;
    }

    /* Aquí la previa NO tiene columna: el panel de la derecha pasa a ser de dos
       caras y las pestañas sustituyen a su cabecera. */
    .impresion-editor-pestanas {
        display: flex;
    }

    .impresion-editor-solo-ancho {
        display: none;
    }

    .impresion-editor-solo-estrecho {
        display: block;
    }
}

/* 820 px de panel: ya no caben ni tres columnas y se apila todo. */
@container editor (max-width: 820px) {
    .impresion-editor-paneles {
        grid-template-columns: minmax(0, 1fr);
        gap: 0.75rem;
    }

    .impresion-editor-separador {
        display: none;
    }

    .impresion-editor-panel-cuerpo {
        max-height: 32rem;
    }
}

/* Y LA ALTURA SÍ ES COSA DE LA VENTANA, no del panel: lo que se decide aquí es
   si el desplazamiento que manda es el de cada panel o el de la página, y en un
   móvil manda el de la página. (Va en una media query también porque una
   consulta de contenedor no puede cambiar los estilos de su propio contenedor.)
   Es el mismo criterio que el editor de salas. */
@media (max-width: 1100px) {
    .impresion-editor {
        height: auto;
        min-height: 0;
    }
}

/* --- La paleta ------------------------------------------------------------ */
.impresion-diseno-paleta {
    background: #ffffff;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.5rem;
    overflow: hidden;
}

.impresion-diseno-paleta-rejilla {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr));
    gap: 0.35rem;
}

/* EL BUSCADOR DE CAMPOS. El catálogo de un ticket son más de doscientos campos
   repartidos en once grupos plegados: encontrar «Verifactu» abriéndolos de uno
   en uno es exactamente lo que un buscador ahorra. Va pegado arriba del panel y
   no dentro de un grupo, porque busca en todos. */
.impresion-diseno-paleta-buscador {
    position: sticky;
    top: 0;
    z-index: 1;
    padding: 0.4rem 0.5rem;
    background: #ffffff;
    border-bottom: 1px solid var(--tentalo-borde);
}

.impresion-diseno-paleta-buscador .campo {
    margin: 0;
}

/* Los resultados de la búsqueda salen PLANOS y con su grupo delante: buscando
   se ha dejado de pensar en grupos, y saber de cuál sale cada campo es lo que
   evita insertar «Total» del documento creyendo que es el de una línea. */
.impresion-diseno-paleta-resultados {
    padding: 0.35rem 0.5rem 0.6rem;
}

.impresion-diseno-campo-grupo {
    display: block;
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--tentalo-tinta-suave);
}

.impresion-diseno-paleta-sin-resultados {
    padding: 0.75rem 0.25rem;
    font-size: 0.82rem;
    color: var(--tentalo-tinta-suave);
}

.impresion-diseno-pieza {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    min-height: var(--tentalo-toque);
    padding: 0.35rem 0.5rem;
    font: inherit;
    text-align: left;
    cursor: pointer;
    color: var(--tentalo-tinta);
    background: #ffffff;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.4rem;
}

.impresion-diseno-pieza:hover {
    border-color: var(--tentalo-marca);
    background: rgba(103, 41, 144, 0.06);
}

.impresion-diseno-pieza-nombre {
    font-size: 0.8rem;
    line-height: 1.15;
}

.impresion-diseno-campos {
    list-style: none;
    margin: 0;
    padding: 0;
}

.impresion-diseno-campo {
    margin: 0;
    padding: 0;
}

.impresion-diseno-campo-boton {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    width: 100%;
    min-height: 2rem;
    padding: 0.2rem 0.35rem;
    font: inherit;
    text-align: left;
    cursor: pointer;
    color: var(--tentalo-tinta);
    background: transparent;
    border: 0;
    border-radius: 0.3rem;
}

.impresion-diseno-campo-boton:hover {
    background: rgba(103, 41, 144, 0.08);
}

.impresion-diseno-campo-nombre {
    font-size: 0.8rem;
}

/* El valor de muestra, en gris y sin robarle sitio al nombre del campo. */
.impresion-diseno-campo-muestra {
    margin-left: auto;
    max-width: 55%;
    overflow: hidden;
    font-size: 0.72rem;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: var(--tentalo-tinta-suave);
}

/* --- El desplegable que elige QUÉ CAMPO se imprime (2026-09-18) ----------- */
/* Una fila de la lista es la GRAMÁTICA DE FILA del plano de sala: lo principal
   —el nombre legible— a la izquierda, y las secundarias —la ruta técnica y el
   valor de ejemplo— en tinta suave. La ruta NO se esconde nunca: es lo que se
   guarda en el diseño. Encima de la primera fila de cada grupo va el rótulo del
   grupo, que aquí se pinta a mano porque MudAutocomplete no agrupa (ver
   Components\Impresion\SelectorDeCampo.razor). */
.impresion-campo-opcion {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
    width: 100%;
}

.impresion-campo-opcion-grupo {
    margin-bottom: 0.15rem;
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--tentalo-tinta-suave);
}

.impresion-campo-opcion-cuerpo {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    min-width: 0;
}

.impresion-campo-opcion-nombre {
    overflow: hidden;
    font-size: 0.85rem;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* La ruta técnica, a la derecha y en monoespaciada: es un identificador y se
   lee mejor con la misma letra con la que sale en el JSON del diseño. */
.impresion-campo-opcion-ruta {
    margin-left: auto;
    overflow: hidden;
    flex-shrink: 0;
    max-width: 55%;
    font-family: "Roboto Mono", ui-monospace, "Cascadia Mono", Consolas, "Courier New", monospace;
    font-size: 0.7rem;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: var(--tentalo-tinta-suave);
}

.impresion-campo-opcion-ejemplo {
    overflow: hidden;
    font-size: 0.72rem;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: var(--tentalo-tinta-suave);
}

/* El campo y su aviso de «no está en el catálogo» forman un bloque: el aviso
   tiene que quedar pegado al campo y no al de abajo. */
.impresion-diseno-campo-selector {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.impresion-diseno-campo-coleccion {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.2rem 0.35rem;
}

.impresion-diseno-campo-hijos {
    margin: 0 0 0.35rem 1.1rem;
    padding: 0;
    list-style: none;
    font-size: 0.72rem;
    color: var(--tentalo-tinta-suave);
}

/* --- El lienzo ------------------------------------------------------------ */
.impresion-diseno-lienzo-marco {
    background: #ffffff;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.5rem;
    overflow: hidden;
}

.impresion-diseno-lienzo-barra {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.35rem 0.75rem;
    font-size: 0.8rem;
    color: var(--tentalo-tinta-suave);
    border-bottom: 1px solid var(--tentalo-borde);
}

.impresion-diseno-lienzo-cuenta {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
}

/* El PAPEL. El ancho se mide en caracteres monoespaciados («ch»), que es lo que
   hace que un diseño de 48 columnas se vea más ancho que uno de 42 sin tener
   que calcular milímetros. El `min()` es la regla 2 del sistema de diseño: en
   375 px una caja fija se saldría del panel. */
/* EL PAPEL PARECE PAPEL: sombra baja, canto continuo y un poco de aire por
   fuera para que se vea que hay un borde y dónde se acaba el rollo. El canto
   punteado de antes lo hacía parecer un contenedor vacío de un maquetador. */
.impresion-diseno-papel {
    padding: 0.6rem 0.5rem;
    margin: 0.9rem auto;
    background: #ffffff;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.25rem;
    box-shadow: 0 1px 2px rgba(42, 26, 62, 0.06), 0 6px 18px rgba(42, 26, 62, 0.07);
    overflow-x: auto;
}

.impresion-diseno-papel:focus-visible {
    outline: 2px solid var(--tentalo-marca);
    outline-offset: 2px;
}

.impresion-diseno-papel-42 { width: min(100%, 44ch); }

.impresion-diseno-papel-48 { width: min(100%, 50ch); }

/* EL ESTADO VACÍO no es una frase gris en medio de la nada: dice qué hay que
   hacer y con qué, y deja sitio para el icono. Es el mismo patrón que el estado
   vacío de las salas. */
.impresion-diseno-vacio {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    margin: 2.5rem 0.75rem;
    font-size: 0.85rem;
    line-height: 1.5;
    text-align: center;
    color: var(--tentalo-tinta-suave);
}

.impresion-diseno-vacio-icono {
    color: rgba(42, 26, 62, 0.35);
}

.impresion-diseno-vacio-titulo {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--tentalo-tinta);
}

.impresion-diseno-filas {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

/* Una fila por bloque. La sangría sale del NIVEL del recorrido plano, que el
   componente pasa en una variable CSS: así un grupo condicional y sus hijos se
   leen como lo que son sin un árbol de verdad. */
.impresion-diseno-fila {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-height: 2.25rem;
    padding: 0.15rem 0.35rem;
    padding-left: calc(0.35rem + (var(--impresion-diseno-nivel, 0) * 1.25rem));
    font-family: "Roboto Mono", ui-monospace, "Cascadia Mono", Consolas, "Courier New", monospace;
    font-size: 0.78rem;
    cursor: pointer;
    background: var(--plano-hoja);
    border: 1px solid transparent;
    border-radius: 0.25rem;
}

.impresion-diseno-fila:hover {
    background: rgba(103, 41, 144, 0.05);
}

/* EL BLOQUE ELEGIDO: ANILLO MORADO Y AGUADA, y su `aria-pressed`; ningún estado
   se distingue solo por el color. El anillo va con `box-shadow` y no con
   `border` a propósito -un canto de dos píxeles movería la fila un píxel al
   elegirla y la lista entera daría un salto-.

   LA BARRA DE LA IZQUIERDA SE CAE (tanda 4): eran 3 px de morado en un solo
   lado, o sea la «raya de acento» que este rediseño quita de todas partes, y
   además competía con el anillo, que ya rodea la fila entera. La aguada dice lo
   mismo poseyendo la región, que es como manda el color aquí. */
.impresion-diseno-fila-elegida {
    border-color: transparent;
    background: rgba(103, 41, 144, 0.09);
    box-shadow: 0 0 0 2px var(--tentalo-marca);
}

.impresion-diseno-fila:focus-visible {
    outline: 2px solid var(--tentalo-marca);
    outline-offset: 1px;
}

/* Un bloque de un tipo que esta central no conoce: se conserva verbatim y no se
   puede editar. El canto punteado lo dice sin necesidad de leer el panel. */
.impresion-diseno-fila-desconocida {
    border-style: dashed;
    border-color: var(--tentalo-borde);
}

.impresion-diseno-fila-icono {
    flex: 0 0 auto;
    color: var(--tentalo-marca);
}

.impresion-diseno-fila-texto {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* Las asas de la fila: se ven siempre en pantalla táctil y al pasar por encima
   en escritorio. Nunca desaparecen del árbol -son la vía accesible-, solo
   pierden opacidad. */
.impresion-diseno-fila-asas {
    display: flex;
    flex: 0 0 auto;
    gap: 0;
    opacity: 0.35;
}

.impresion-diseno-fila:hover .impresion-diseno-fila-asas,
.impresion-diseno-fila-elegida .impresion-diseno-fila-asas,
.impresion-diseno-fila-asas:focus-within {
    opacity: 1;
}

@media (hover: none) {
    .impresion-diseno-fila-asas {
        opacity: 1;
    }
}

/* --- El lienzo ABSOLUTO: etiqueta y página (fase P4) ---------------------- */

/* El papel se mide en MILÍMETROS DE CSS, que son 96/25.4 px por definición del
   estándar. Así una etiqueta de 57 × 32 mm mide en pantalla lo que mide en el
   rollo y no hay ningún factor de escala que mantener a mano entre este fichero
   y el C#; LienzoAbsoluto.PX_POR_MM es esa misma constante y es todo lo que
   hace falta para pasar el arrastre de píxeles a milímetros.

   Un A4 son 210 mm ≈ 794 px, que no caben en la columna central por debajo de
   1200 px: el papel va dentro de un contenedor que se desplaza en horizontal,
   que es la regla 2 del sistema de diseño (nada se sale de su panel). */
.impresion-diseno-lienzo-desplazable {
    padding: 0.75rem;
    overflow: auto;
}

.impresion-diseno-lienzo-mm {
    position: relative;
    margin: 0 auto;
    background-color: #ffffff;
    /* La rejilla: una línea fina cada milímetro y una marcada cada centímetro.
       Cuatro gradientes repetidos y ni un <svg>: el navegador la redibuja al
       hacer zoom sin recalcular nada. */
    background-image:
        repeating-linear-gradient(to right, rgba(42, 26, 62, 0.16) 0 1px, transparent 1px 10mm),
        repeating-linear-gradient(to bottom, rgba(42, 26, 62, 0.16) 0 1px, transparent 1px 10mm),
        repeating-linear-gradient(to right, rgba(42, 26, 62, 0.06) 0 1px, transparent 1px 1mm),
        repeating-linear-gradient(to bottom, rgba(42, 26, 62, 0.06) 0 1px, transparent 1px 1mm);
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.15rem;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
    touch-action: none; /* el arrastre con el dedo mueve el bloque, no la página */
}

.impresion-diseno-lienzo-mm:focus-visible {
    outline: 2px solid var(--tentalo-marca);
    outline-offset: 2px;
}

/* El recuadro de los márgenes de la página, por dentro del papel. Es una guía y
   no un bloque: no se puede elegir ni recibe el ratón. */
.impresion-diseno-lienzo-margenes {
    position: absolute;
    pointer-events: none;
    border: 1px dashed rgba(42, 26, 62, 0.45);
}

/* Una caja por bloque. El canto es continuo -no punteado- para distinguirla del
   recuadro de márgenes, y la elegida lleva ADEMÁS del color un canto más grueso
   y su aria-pressed: ningún estado se distingue solo por el color. */
.impresion-diseno-caja {
    position: absolute;
    display: flex;
    align-items: center;
    gap: 0.2rem;
    box-sizing: border-box;
    min-width: 6mm;
    min-height: 4mm;
    padding: 0 0.15rem;
    overflow: hidden;
    font-family: "Roboto Mono", ui-monospace, "Cascadia Mono", Consolas, "Courier New", monospace;
    font-size: 0.7rem;
    line-height: 1.1;
    white-space: nowrap;
    cursor: grab;
    color: var(--tentalo-tinta);
    background: rgba(255, 255, 255, 0.85);
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.15rem;
}

.impresion-diseno-caja:active {
    cursor: grabbing;
}

.impresion-diseno-caja:hover {
    border-color: var(--tentalo-marca);
    background: rgba(103, 41, 144, 0.06);
}

.impresion-diseno-caja-elegida {
    border: 2px solid var(--tentalo-marca);
    background: rgba(103, 41, 144, 0.12);
}

.impresion-diseno-caja:focus-visible {
    outline: 2px solid var(--tentalo-marca);
    outline-offset: 1px;
}

/* El rectángulo del lienzo absoluto se pinta como lo que es: una caja sin fondo,
   o maciza si lleva relleno. */
.impresion-diseno-caja-rect {
    background: transparent;
    border-color: var(--tentalo-tinta);
}

.impresion-diseno-caja-rect-relleno {
    color: #ffffff;
    background: var(--tentalo-tinta);
}

/* Un bloque de un tipo que esta central no conoce, igual que en el térmico. */
.impresion-diseno-caja-desconocida {
    border-style: dashed;
}

.impresion-diseno-caja-icono {
    flex: 0 0 auto;
    color: var(--tentalo-marca);
}

.impresion-diseno-caja-texto {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* La rejilla de milímetros en el panel de propiedades: X, Y, ancho y alto son
   cuatro números cortos y en una sola columna ocuparían cuatro filas de nada. */
.impresion-diseno-geometria {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 0.5rem;
}

/* --- El panel de propiedades --------------------------------------------- */
.impresion-diseno-propiedades {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.impresion-diseno-etiqueta {
    display: block;
    margin-bottom: 0.2rem;
    font-size: 0.75rem;
    color: var(--tentalo-tinta-suave);
}

/* El área de texto del bloque de texto: monoespaciada, porque lo que se escribe
   ahí sale en un papel monoespaciado y las llaves de los campos se cuentan. */
.impresion-diseno-texto {
    box-sizing: border-box;
    width: 100%;
    padding: 0.5rem;
    font-family: "Roboto Mono", ui-monospace, "Cascadia Mono", Consolas, "Courier New", monospace;
    font-size: 0.8rem;
    line-height: 1.4;
    color: var(--tentalo-tinta);
    background: #ffffff;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.25rem;
    resize: vertical;
}

.impresion-diseno-texto:focus-visible {
    outline: 2px solid var(--tentalo-marca);
    outline-offset: 0;
}

.impresion-diseno-texto-alto {
    min-height: 18rem;
}

.impresion-diseno-texto-caja {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.impresion-diseno-subtitulo {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.75rem;
    padding-top: 0.5rem;
    font-size: 0.8rem;
    font-weight: 600;
    border-top: 1px solid var(--tentalo-borde);
}

.impresion-diseno-subtitulo .mud-icon-button {
    margin-left: auto;
}

/* La vista previa de la imagen incrustada de un bloque de imagen. NO es el
   cuadrado de lado fijo de .campo-imagen-vista: un logotipo de ticket es
   apaisado (576 x 96 puntos) y el panel de propiedades es estrecho, asi que la
   caja se adapta a lo que hay y la imagen nunca se sale (max-width: 100%).
   Fondo BLANCO y no gris: es el papel, y ahi es donde se juzga si un trazo
   claro se va a ver. */
.impresion-imagen-vista {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.25rem;
    min-height: 72px;
    max-width: 100%;
    padding: 0.5rem;
    margin-bottom: 0.35rem;
    overflow: hidden;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.35rem;
    background: #ffffff;
}

.impresion-imagen-vista img {
    max-width: 100%;
    height: auto;
}

/* Una columna de tabla o una celda de fila: su propia cajita, para que quince
   campos seguidos no se lean como una lista sin principio ni fin. */
.impresion-diseno-subficha {
    padding: 0.5rem;
    margin-bottom: 0.5rem;
    background: #f2f5f3;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.35rem;
}

.impresion-diseno-subficha-barra {
    display: flex;
    align-items: center;
    gap: 0.15rem;
    margin-bottom: 0.35rem;
    font-size: 0.78rem;
    color: var(--tentalo-tinta-suave);
}

.impresion-diseno-subficha-barra .mud-icon-button:first-of-type {
    margin-left: auto;
}

.impresion-diseno-formato {
    display: flex;
    align-items: flex-start;
    gap: 0.35rem;
}

.impresion-diseno-formato .campo {
    flex: 1 1 auto;
}

/* --- La vista previa ------------------------------------------------------ */
/* La vista previa DENTRO DE UN PANEL no lleva su propio cuadro: el panel ya se
   lo pone. La variante suelta —el diálogo de importación no la usa, pero sí el
   cajón flotante— conserva el suyo con `.impresion-diseno-previa-suelta`. */
.impresion-diseno-previa {
    padding: 0.75rem;
}

.impresion-diseno-previa-suelta {
    background: #ffffff;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.5rem;
}

.impresion-diseno-previa-barra {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.impresion-diseno-previa-titulo {
    font-weight: 600;
}

.impresion-diseno-previa-columnas {
    margin-left: auto;
    font-size: 0.78rem;
    color: var(--tentalo-tinta-suave);
}

/* EL BLOQUE ELEGIDO, MARCADO EN EL PAPEL COMPUESTO. Son las líneas que ha
   impreso ese bloque, que el núcleo devuelve en `BlockLines` y que la pantalla
   envuelve aquí. Fondo tenue y una barra morada a la izquierda: sobre un <pre>
   monoespaciado un fondo sólido taparía el texto y una caja movería las
   columnas, y en una vista previa las columnas son el dato. */
.impresion-diseno-previa-bloque {
    display: block;
    background: rgba(42, 26, 62, 0.1);
    box-shadow: inset 3px 0 0 var(--tentalo-marca);
    border-radius: 0 0.15rem 0.15rem 0;
}

/* La vista previa de una ETIQUETA: el SVG que compone el núcleo, dentro de un
   <img> con el papel de fondo. Se le pone un cuadro para que se vea el borde de
   la etiqueta aunque el SVG sea casi todo blanco. */
.impresion-diseno-previa-etiqueta {
    display: block;
    max-width: 100%;
    margin: 0 auto;
    background: #ffffff;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.15rem;
}

/* La vista previa de una PÁGINA: el visor de PDF del navegador. El alto es fijo
   porque un <object> sin alto colapsa a cero; 28rem es lo que deja ver una hoja
   entera sin comerse la pantalla. */
.impresion-diseno-previa-pdf {
    display: block;
    width: 100%;
    height: 28rem;
    background: #ffffff;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.25rem;
}

/* El contenido de reserva del <object>: lo ve quien no tenga visor de PDF. */
.impresion-diseno-previa-reserva {
    margin: 0;
    padding: 1rem;
    font-size: 0.85rem;
    text-align: center;
    color: var(--tentalo-tinta-suave);
}

/* Los avisos del render y las pegas de validación, como lista y no como
   párrafo: son varios y cada uno nombra un campo distinto. */
.impresion-diseno-avisos {
    margin: 0;
    padding-left: 1.1rem;
}

/* LOS AVISOS DE UNA VISTA PREVIA, DISCRETOS (AvisosDeLaPrevia.razor, 2026-10-07). Una etiqueta pequeña
   («1 aviso», la .etiqueta-aviso de la hoja limpia) que despliega la lista; en la cabecera de un papel la
   lista flota bajo la etiqueta para no empujar el papel. Antes, un recuadro ámbar grande por papel. */
.previa-avisos {
    min-width: 0;
}

.previa-avisos-etiqueta {
    display: inline-flex;
    align-items: center;
    min-height: 28px;
    list-style: none;
    cursor: pointer;
    border-radius: 6px;
}

.previa-avisos-etiqueta::-webkit-details-marker {
    display: none;
}

.previa-avisos-etiqueta:focus-visible {
    outline: 2px solid var(--limpia-morado, currentColor);
    outline-offset: 2px;
}

.previa-avisos-etiqueta .etiqueta {
    gap: 4px;
}

.previa-avisos-icono.mud-icon-root {
    font-size: 1rem;
}

.previa-avisos-lista {
    margin: 6px 0 0;
    padding: 8px 12px 8px 1.6rem;
    border: 1px solid var(--tentalo-borde);
    border-radius: 6px;
    background-color: var(--limpia-aviso-fondo, #fdf4e2);
    color: var(--limpia-aviso-tinta, #8a5f0f);
    font-size: 0.8125rem;
    line-height: 1.4;
    overflow-wrap: anywhere;
}

.previa-avisos-flotante {
    position: static;
}

.previa-avisos-flotante .previa-avisos-lista {
    position: absolute;
    z-index: 5;
    top: 100%;
    left: 0;
    right: 0;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
}

/* --- La lista de diseños -------------------------------------------------- */

/* Las cinco familias de la fase P3. Son <details>/<summary> del navegador: con
   treinta tipos de documento la pantalla entera desplegada no se lee, y el
   plegado nativo no cuesta ni JavaScript ni estado, y ya viene con el teclado y
   con el papel de «grupo desplegable» para un lector de pantalla. */
.impresion-diseno-familia {
    margin-bottom: 1rem;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.5rem;
    background: #fff;
}

.impresion-diseno-familia-cabecera {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.6rem;
    padding: 0.6rem 0.75rem;
    cursor: pointer;
    user-select: none;
    border-radius: 0.5rem;
}

.impresion-diseno-familia[open] > .impresion-diseno-familia-cabecera {
    border-bottom: 1px solid var(--tentalo-borde);
    border-radius: 0.5rem 0.5rem 0 0;
}

.impresion-diseno-familia-cabecera:hover {
    background: #e7ecea;
}

.impresion-diseno-familia-cabecera:focus-visible {
    outline: 2px solid var(--tentalo-marca);
    outline-offset: -2px;
}

.impresion-diseno-familia-titulo {
    font-size: 1rem;
    font-weight: 600;
    color: var(--tentalo-tinta);
}

.impresion-diseno-familia-cuenta {
    margin-left: auto;
    font-size: 0.78rem;
    color: var(--tentalo-tinta-suave);
}

/* Dentro de una familia, el grupo de un tipo de documento. Va con menos aire que
   cuando eran cuatro en toda la pantalla: aquí son hasta ocho seguidos. */
.impresion-diseno-grupo {
    padding: 0.6rem 0.75rem;
}

.impresion-diseno-grupo + .impresion-diseno-grupo {
    border-top: 1px dashed var(--tentalo-borde);
}

.impresion-diseno-grupo-cabecera {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    min-height: 2rem;
}

.impresion-diseno-grupo-titulo {
    margin: 0;
    font-size: 0.92rem;
    font-weight: 600;
    color: var(--tentalo-tinta);
}

/* «sin diseños», «3 diseños», «en la fase P4». Es lo que hace legible un grupo
   vacío sin gastar en él una línea de texto entera. */
.impresion-diseno-grupo-cuenta {
    font-size: 0.75rem;
    color: var(--tentalo-tinta-suave);
}

/* El botón de crear se va a la derecha, para que los nombres de los documentos
   queden alineados en una columna que se puede recorrer con la vista. */
.impresion-diseno-grupo-cabecera .mud-button-root {
    margin-left: auto;
}

.impresion-diseno-grupo .impresion-diseno-tarjetas {
    margin-top: 0.6rem;
}

/* LA REJILLA DE TARJETAS DE DISEÑOS (rehecha el 2026-09-29,
   docs\central\tarjetas-de-disenos-2026-09-29.md).

   Era `.admin-rejilla-tarjetas` (auto-fit, 15rem) con `align-items: start`: cada
   tarjeta medía lo que su contenido, así que el nombre en una o dos líneas, las
   insignias en una o dos y el «en uso» o el «sin usar» dejaban la fecha y los
   botones a una altura distinta en cada una. Y la fila de seis iconos de 48 px
   (308 px) no cabía en los 218 px útiles: se salía por la derecha, encima de la
   vecina.

   Ahora:
     · AUTO-FILL Y NO AUTO-FIT, con `min(15rem, 100%)`: un grupo con UN diseño no
       estira su tarjeta a todo el ancho (con la miniatura de proporción fija
       saldría de medio metro de alto) y en 375 px la columna no desborda.
     · SEIS RANURAS POR TARJETA ALINEADAS CON `subgrid`: miniatura, nombre,
       insignias, «en uso», fecha y acciones caen a la misma altura en toda la
       fila de tarjetas. Donde no haya subgrid, las tarjetas se estiran igual
       (`stretch`) y las acciones se van al pie con `margin-top: auto`.
     · TRES ACCIONES (editar, por omisión y «⋯»): 3 × 48 px caben siempre. */
.impresion-diseno-tarjetas {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr));
    column-gap: 1rem;
    row-gap: 0.4rem;
    align-items: stretch;
}

/* La pieza de un diseño de impresión: la misma habitación que las salas y los
   locales, para que las tres rejillas de la web se lean como una sola (tanda 3).
   OJO: la tarjeta NO puede ser contenedor de consulta (`container-type`): eso le
   pone contención de maquetación, la convierte en un contexto independiente y
   el navegador deja `grid-template-rows: subgrid` en `none` —se midió: las
   ranuras de las tarjetas de una fila bailaban 6-15 px—. El contenedor es la
   propia miniatura, que es a quien le hace falta. */
.impresion-diseno-tarjeta {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    min-width: 0;
    margin-bottom: 0.6rem;
    padding: 0.6rem;
    background-color: var(--plano-hoja);
    border: 1px solid var(--plano-linea-fina);
    border-left: 2px solid var(--plano-muro);
    border-bottom: 2px solid var(--plano-muro);
    border-radius: var(--plano-esquina-muro);
    transition: background-color var(--plano-tiempo) var(--plano-curva);
}

@supports (grid-template-rows: subgrid) {
    .impresion-diseno-tarjeta {
        display: grid;
        grid-row: span 6;
        grid-template-rows: subgrid;
        row-gap: 0.4rem;
    }

    .impresion-diseno-tarjeta-enlace {
        display: grid;
        grid-row: span 2;
        grid-template-rows: subgrid;
        row-gap: 0.4rem;
    }
}

/* El enlace a editar envuelve la miniatura y el nombre: la zona de toque es esa
   mitad de la tarjeta y no una palabra. NINGÚN título se subraya: al pasar se
   tiñe la tarjeta entera, como las demás habitaciones del plano, y así todos
   los nombres tienen siempre el mismo aspecto. */
.impresion-diseno-tarjeta-enlace {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    min-width: 0;
    color: inherit;
    text-decoration: none;
    border-radius: 0.25rem;
}

.impresion-diseno-tarjeta-enlace:hover,
.impresion-diseno-tarjeta-enlace:focus-visible {
    text-decoration: none;
}

.impresion-diseno-tarjeta:has(.impresion-diseno-tarjeta-enlace:hover) {
    background-color: var(--plano-morado-aguada);
}

.impresion-diseno-tarjeta-enlace:focus-visible {
    outline: 2px solid var(--tentalo-marca);
    outline-offset: 2px;
}

/* La miniatura: las doce primeras líneas de la vista previa, en pequeño y sin
   scroll, con PROPORCIÓN FIJA (16:9) para que todas midan lo mismo. La letra de
   sus renglones se ata a su ancho (48 columnas × 0,6 em caben en 100cqi) con
   topes de 6 y 10 px. Lo que no cabe se desvanece con una máscara en vez de
   cortarse a navaja, que es lo que hace que se lea como «sigue» y no como «roto». */
.impresion-diseno-miniatura {
    aspect-ratio: 16 / 9;
    min-width: 0;
    margin: 0;
    padding: 0.4rem;
    overflow: hidden;
    container-type: inline-size;
    font-family: "Roboto Mono", ui-monospace, "Cascadia Mono", Consolas, "Courier New", monospace;
    line-height: 1.25;
    color: var(--tentalo-tinta);
    background: #f2f5f3;
    border: 1px solid var(--tentalo-borde);
    border-radius: 0.25rem;
    mask-image: linear-gradient(to bottom, #000 70%, transparent 100%);
}

.impresion-diseno-miniatura > * {
    font-size: clamp(6px, calc(100cqi / 29.5), 10px);
}

.impresion-diseno-miniatura-linea {
    display: block;
    min-height: 1.25em;
    white-space: pre;
    overflow: hidden;
}

/* El hueco de una imagen («[imagen]» o «[logotipo]» en la vista previa de
   texto): un recuadro del ancho de un logotipo centrado, con su icono. */
.impresion-diseno-miniatura-imagen {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36%;
    height: 3.75em;
    margin: 0.1em auto 0.25em;
    color: var(--plano-tinta-2);
    background: rgba(103, 41, 144, 0.06);
    border: 1px dashed var(--plano-linea);
    border-radius: 2px;
}

/* El icono va a la letra de la miniatura: MudBlazor le pone 1,5rem propio, y un
   `em` medido sobre ese 1,5rem daba un icono de 62 px encima del texto. */
.impresion-diseno-miniatura-imagen .mud-icon-root {
    font-size: inherit;
    width: 2.6em;
    height: 2.6em;
}

/* Sin líneas (una etiqueta, una página A4 o un diseño que no se pudo
   componer): el recuadro se queda y lo dice, en vez de un rectángulo mudo. */
.impresion-diseno-miniatura[data-vacia]::after {
    content: "Sin vista previa";
    display: grid;
    place-items: center;
    height: 100%;
    font-family: var(--plano-letra, inherit);
    font-size: 0.75rem;
    color: var(--tentalo-tinta-suave);
}

/* EL NOMBRE, COMO MUCHO EN DOS LÍNEAS, con puntos suspensivos; el entero va en
   el `title`. Reserva siempre las dos líneas para que una tarjeta de nombre
   corto no suba su fila (sin subgrid es lo único que las alinea). */
.impresion-diseno-tarjeta-nombre {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    overflow-wrap: anywhere;
    min-height: calc(2 * 1.3em);
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.3;
    color: var(--tentalo-tinta);
}

.impresion-diseno-tarjeta-cifras {
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
    align-items: center;
    gap: 0.3rem;
    min-width: 0;
    font-size: 0.75rem;
}

.impresion-diseno-tarjeta-medida {
    font-variant-numeric: tabular-nums;
}

.impresion-diseno-tarjeta-fecha {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: 0.72rem;
    color: var(--tentalo-tinta-suave);
    font-variant-numeric: tabular-nums;
}

/* LAS ACCIONES AL PIE: editar y «por omisión» a la izquierda, el «⋯» a la
   derecha. Nunca se parten ni se salen: son tres objetivos de 48 px. */
.impresion-diseno-tarjeta-acciones {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: 0.25rem;
    min-width: 0;
    margin-top: auto;
    padding-top: 0.25rem;
    border-top: 1px solid var(--tentalo-borde);
}

.impresion-diseno-tarjeta-acciones .mud-icon-button,
.impresion-diseno-tarjeta-acciones .mud-button-root {
    min-width: var(--tentalo-toque);
    min-height: var(--tentalo-toque);
}

.impresion-diseno-tarjeta-menu {
    display: inline-flex;
    margin-left: auto;
}

/* Borrar, en el menú: separado por una regla y en rojo, texto e icono. */
.impresion-diseno-menu-borrar,
.impresion-diseno-menu-borrar .mud-menu-item-text {
    color: var(--mud-palette-error);
}

/* Las opciones del menú ya miden 48 px por la regla global de `.mud-menu-item`. */

/* --- Tanda T4 de «todo a Diseño»: filtros, «en uso» y asignar a cajas ------ */

/* Los filtros: el buscador a lo ancho y los desplegables en una rejilla que se
   apila sola en un teléfono (375 px: uno por fila). */
.impresion-disenos-filtros {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: 0.5rem 0.75rem;
    align-items: start;
    margin-bottom: 1rem;
}

.impresion-disenos-buscador,
.impresion-disenos-filtros-pie {
    grid-column: 1 / -1;
}

.impresion-disenos-filtros-pie {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 1rem;
}

.impresion-disenos-cuenta {
    font-size: 0.8rem;
    color: var(--tentalo-tinta-suave);
    font-variant-numeric: tabular-nums;
}

/* «En uso» de una tarjeta o de una fila: una línea que se despliega con las
   cajas y su enlace. */
.impresion-diseno-uso {
    font-size: 0.75rem;
}

.impresion-diseno-uso summary {
    cursor: pointer;
    color: var(--tentalo-marca);
}

.impresion-diseno-uso summary:focus-visible {
    outline: 2px solid var(--tentalo-marca);
    outline-offset: 2px;
}

.impresion-diseno-uso-libre {
    color: var(--tentalo-tinta-suave);
}

.impresion-diseno-uso-lista {
    max-height: 12rem;
    overflow-y: auto;
    margin: 0.35rem 0 0;
    padding-left: 1rem;
}

.impresion-diseno-uso-lista li {
    overflow-wrap: anywhere;
}

.impresion-diseno-uso-donde {
    display: block;
    color: var(--tentalo-tinta-suave);
}

/* En la tabla, las mismas tres acciones sin la regla de encima y sin partirse:
   caben en 152 px, y la celda no tiene por qué hacer sitio a seis. */
.impresion-disenos-tabla .impresion-diseno-tarjeta-acciones {
    border-top: 0;
    padding-top: 0;
    margin-top: 0;
}

/* EN UN TELÉFONO LAS ACCIONES VAN EN SU PROPIA LÍNEA, al pie de la fila. La
   gramática común (plano.css, «LA FILA») ancla la celda de acciones arriba a la
   derecha con un carril de UN botón, que es el «⋯» de las listas del marco;
   aquí son tres (editar, por omisión y «⋯»), y en ese carril tapaban el nombre.
   Los selectores igualan la especificidad de la regla común (0,4,3) y ganan por
   ir después. El «en uso» se levanta por encima del enlace que cubre la fila,
   para que su desplegable se pueda tocar. */
@media (max-width: 719.98px) {
    .admin-tabla.impresion-disenos-tabla .mud-table-root tbody > tr:has(> td[data-papel="acciones"]) {
        --plano-carril-acciones: 0px;
    }

    .admin-tabla.impresion-disenos-tabla .mud-table-root tbody > tr > td[data-papel="acciones"] {
        position: static;
        order: 3;
        flex: 1 0 100%;
        margin-top: 0.25rem;
    }

    .admin-tabla.impresion-disenos-tabla .mud-table-root tbody > tr > td:has(> .impresion-diseno-uso) {
        flex: 1 0 100%;
    }

    .impresion-disenos-tabla .impresion-diseno-uso {
        position: relative;
        z-index: 1;
    }
}

/* «Asignar a cajas…»: un bloque por local con sus cajas en columnas. */
.impresion-asignar-local {
    padding: 0.5rem 0;
    border-top: 1px solid var(--tentalo-borde);
}

.impresion-asignar-cajas {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
    padding-left: 1.5rem;
}

/* ==========================================================================
   TANDA 4 DE LA AUDITORIA DE UX (docs\central\auditoria-ux-2026-09-15.md)
   El buscador de pantallas, el menu en seis secciones, las migas y la
   separacion de las acciones destructivas.
   ========================================================================== */

/* --- El buscador de pantallas (T5) -------------------------------------- */
/* Una paleta propia y no un MudDialog: el porque, en
   Components\BuscadorDePantallas.razor. El z-index va por encima de la barra
   superior de MudBlazor (1300) porque la paleta tapa la ventana entera. */
.paleta-fondo {
    position: fixed;
    inset: 0;
    z-index: 1400;
    background: rgba(42, 26, 62, 0.45);
}

.paleta {
    position: fixed;
    z-index: 1401;
    /* Anclada arriba y no centrada: la lista CRECE hacia abajo segun lo que se
       escribe, y con la caja centrada el campo de texto se movia bajo el dedo
       a cada tecla. */
    top: 12vh;
    left: 50%;
    transform: translateX(-50%);
    width: min(38rem, calc(100vw - 2rem));
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border-radius: 12px;
    background: #fff;
    box-shadow: 0 18px 48px rgba(42, 26, 62, 0.28);
}

.paleta-campo {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0 0.75rem;
    border-bottom: 1px solid var(--tentalo-borde);
}

.paleta-texto {
    flex: 1 1 auto;
    min-width: 0;
    /* Regla 3 del sistema de diseno: 48 px de alto minimo. */
    min-height: var(--tentalo-toque);
    border: 0;
    outline: none;
    background: transparent;
    font: inherit;
    font-size: 1.05rem;
    color: var(--tentalo-tinta);
}

.paleta-lista {
    margin: 0;
    padding: 0.25rem 0;
    list-style: none;
    /* Tope de alto para que la paleta no se salga de una pantalla de portatil;
       con doce resultados como maximo casi nunca hace falta scroll. */
    max-height: min(26rem, 55vh);
    overflow-y: auto;
}

.paleta-fila {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    min-height: var(--tentalo-toque);
    padding: 0 0.9rem;
    cursor: pointer;
}

.paleta-fila-elegida {
    background: rgba(103, 41, 144, 0.1);
    box-shadow: inset 3px 0 0 var(--tentalo-marca);
}

.paleta-icono {
    flex: 0 0 auto;
    color: var(--tentalo-tinta-suave);
}

.paleta-nombre {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Lo que casa con lo escrito. `mark` trae un amarillo de navegador que en esta
   paleta se lee como un error: aqui es la tinta de marca en negrita. */
.paleta-casa {
    background: transparent;
    color: var(--tentalo-marca);
    font-weight: 700;
}

.paleta-camino {
    flex: 0 0 auto;
    font-size: 0.78rem;
    color: var(--tentalo-tinta-suave);
}

.paleta-rotulo,
.paleta-vacio {
    margin: 0;
    padding: 0.6rem 0.9rem 0.2rem;
    font-size: 0.78rem;
    color: var(--tentalo-tinta-suave);
}

.paleta-vacio {
    padding: 1.2rem 0.9rem;
}

.paleta-pie {
    margin: 0;
    padding: 0.5rem 0.9rem;
    border-top: 1px solid var(--tentalo-borde);
    font-size: 0.72rem;
    color: var(--tentalo-tinta-suave);
}

.paleta-tecla {
    display: inline-block;
    padding: 0 0.3rem;
    border: 1px solid var(--tentalo-borde);
    border-radius: 4px;
    background: #e7ecea;
    font-family: inherit;
    font-size: 0.7rem;
    line-height: 1.5;
}

/* En un movil la paleta ocupa casi toda la pantalla: con 375 px de ancho, una
   caja flotante con margenes deja la lista en 300 px y los caminos se cortan. */
@media (max-width: 599px) {
    .paleta {
        top: 0;
        left: 0;
        transform: none;
        width: 100vw;
        height: 100vh;
        border-radius: 0;
    }

    .paleta-lista {
        max-height: none;
        flex: 1 1 auto;
    }

    /* El camino baja de linea en vez de recortar el nombre. */
    .paleta-fila {
        flex-wrap: wrap;
        padding: 0.4rem 0.9rem;
    }

    .paleta-camino {
        flex-basis: 100%;
        padding-left: 1.6rem;
    }
}

/* --- El menu en seis secciones ------------------------------------------ */
/* La SECCION que contiene la pantalla actual, marcada aunque este plegada:
   con seis cajones cerrados, el `active` del enlace de dentro no se ve. Es una
   banda de marca en el borde izquierdo y el rotulo en negrita; no se usa el
   fondo porque el `:hover` del propio cajon ya lo usa. */
.admin-menu-seccion-actual > .mud-nav-link {
    box-shadow: inset 3px 0 0 var(--tentalo-marca);
    font-weight: 600;
}

/* El submenu de SEGUNDO nivel sangra un poco mas para que se lea como hijo. */
.admin-menu-subgrupo > .mud-nav-link {
    padding-left: 2.2rem;
}

/* --- Las migas (O11) ---------------------------------------------------- */
.admin-cabecera-migas {
    margin-bottom: 0.15rem;
}

.admin-cabecera-migas .mud-breadcrumbs {
    padding: 0;
}

.admin-cabecera-migas li,
.admin-cabecera-migas a,
.admin-cabecera-migas .mud-breadcrumb-separator {
    font-size: 0.78rem;
}

/* --- Las acciones destructivas, separadas (O6) -------------------------- */
/* En la CELDA de acciones de una fila: la papelera no puede estar a 4 px del
   lapiz. No se ensancha la celda (una columna mas costaria 158 px y la tabla
   se sale del panel en 1280 px): se mete un divisor de un pixel y medio hueco
   a cada lado, que son 9 px de separacion por 1 px de ancho. */
.crud-accion-divisor {
    display: inline-block;
    width: 1px;
    height: 1.4rem;
    margin: 0 0.25rem;
    vertical-align: middle;
    background: var(--tentalo-borde);
}

.crud-accion-peligro {
    margin-left: 0.25rem;
}

/* En la BARRA de seleccion y en la de la ficha: el grupo destructivo va al
   final, detras de su divisor, y no se mezcla con el resto al envolver. */
.crud-seleccion-peligro,
.crud-ficha-peligro {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.crud-ficha-peligro .mud-button-root {
    min-height: var(--tentalo-toque);
}

/* --- LAS NOTAS DE UNA VERSION (tanda de las pantallas densas) ------------- */
/*
   LO CAZO EL DETECTOR DE TEXTO EN VERTICAL, y es el mismo defecto que el de la
   medida del Explorador con otro origen. La celda llevaba
   `overflow-wrap: anywhere` en un estilo en línea: con la tabla apretada a 768 y
   a 1.024 px la columna se encogía a 33 px y «Rediseño de la central "El plano
   de sala"» se pintaba en diez renglones de tres letras.

   `anywhere` entra en el cálculo del ancho MINIMO del contenido —le dice al
   navegador «puedo quedarme en una letra»—; `break-word` no: parte sólo las
   palabras que no caben, y la columna conserva su mínimo. Es la diferencia
   entera entre las dos, y es la que hace falta aquí. Con un mínimo de 14rem la
   nota se lee y la tabla se desplaza dentro de su carril, que ya trae su señal
   de continuidad.
*/
.versiones-notas {
    display: block;
    min-width: 14rem;
    overflow-wrap: break-word;
}

/* ========================================================================== */
/*  LA ANALITICA (BI)                                                         */
/*  docs\central\analitica-bi-2026-09-16.md, apartado 4 («Diseño visual»).     */
/* ========================================================================== */
/*
   LAS TRES REGLAS QUE GOBIERNAN TODO ESTE BLOQUE, y que una prueba comprueba
   leyendo este mismo fichero (AnaliticaTests):

     1. NI UNA SOMBRA. Los indicadores, los paneles de gráfico y las tablas se
        separan del fondo con LINEA y con AIRE, nunca con relieve: una pantalla
        con catorce piezas y catorce sombras se lee como un montón de cajas
        flotando, no como un panel.
     2. NI UN FILO. Todo lo que es una caja lleva `border-radius`; no queda ni
        una esquina viva. Un panel de datos con esquinas de 0 px se lee como
        una tabla de un sistema de los noventa, que es justo lo que esta
        reingeniería viene a quitar de en medio.
     3. TRES CORTES Y NO MÁS: 375 (una columna), 768 (dos) y 1280 (cuatro
        tarjetas por fila y los gráficos en rejilla de dos). Se escriben como
        `min-width`, así que el teléfono es el caso BASE y no la excepción.

   Y una cuarta que no es de estilo sino de tacto, la del 2026-09-15: toda
   región que desplace lleva `min-height: 0` y `touch-action` compatible en
   toda la cadena, porque las pantallas táctiles de caja y cocina entregan
   eventos de RATÓN y un contenedor sin eso se queda sin poder arrastrarse.

   LO QUE CAMBIA EN LA TANDA 2 DEL PLANO DE SALA (2026-09-17). La regla 1 decía
   «canto de 1 px y nada más», y eso, aplicado a ocho indicadores en fila, son
   ocho rectángulos blancos con borde: exactamente la «fila de indicadores
   genéricos» y la «tarjeta blanca con borde» que el rediseño rechaza por su
   nombre. Se mantiene el fondo de la regla —separar sin relieve— y cambia el
   medio: los indicadores pasan a ser UNA ZONA con reglas finas entre ellos, la
   barra de periodo deja de ser una tarjeta y se convierte en una fila de
   pastillas sobre el papel, y las tablas toman la piel de tabla del plano
   (cabecera en rótulo condensado, filas separadas por regla fina, sin cebra).
   Los colores salen de las fichas `--plano-*`; los `--tentalo-*` de aquí ya son
   alias suyos. Ni un `data-testid` ni una clase cambian de nombre: es piel.
*/

/* --- La barra de periodo, comparación y establecimientos ----------------- */

/* NO ES UNA TARJETA: es la fila de mandos de la pantalla, sobre el papel y
   cerrada por debajo con una regla fina, igual que la tira del área cierra la
   barra del marco. Un recuadro blanco con borde alrededor de cinco pastillas
   sólo añade una caja que no contiene nada. */
/* EL AIRE DE LA FILA DEL PERIODO (tanda de las pantallas densas, 2026-09-18).
   Eran 20 px hasta lo siguiente, y lo siguiente eran los cuatro botones de la
   pregunta: a 2.000 px quedaba un pasillo vacío entre las pastillas y sus
   acciones que no agrupaba nada. El encargo lo fija: 12 px entre la fila del
   periodo y la barra de acciones, y 20 px entre la barra y la tabla. */
.admin-barra-periodo {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 12px;
    padding: 0 0 0.75rem;
    border: none;
    border-bottom: 1px solid var(--plano-linea-fina);
    border-radius: var(--plano-radio-control);
    background: transparent;
}

/* La tira del periodo: cinco pastillas que se leen como un control. */
.admin-barra-periodo-grupo {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* LAS PASTILLAS DEL PERIODO, LAS MISMAS QUE LA TIRA DEL AREA. Son `MudButton`
   por dentro —el marcado no cambia, y con él `aria-pressed` y los
   `data-testid`— pero se pintan como `.plano-pastilla`: píldora, aguada de
   tinta al 5 %, y tinta rellena la elegida. Así el periodo y la navegación
   hablan el mismo idioma, que es lo que pide §4 («controles familiares»).

   EL ALTO NO BAJA DE `--tentalo-toque` (48 px) y la píldora de la tira del área
   mide 34: aquí manda el toque, y no es una incoherencia. Un periodo se elige
   desde la tablet de la barra con el dedo mojado, y esta fila es el control
   principal de la pantalla; la tira del área se recorre con el pulgar pero es
   navegación, que además tiene el pase y la barra inferior como alternativas.
   Lo que se iguala con la tira es la FORMA —píldora, aguada, tinta rellena la
   elegida—, que es lo que hace que se lean como el mismo sistema. */
/* Y DESDE EL 2026-09-18 SON TECLAS, como la tira del área: rectángulo de 8 px en
   vez de píldora, con su canto y su hundido (plano.css §8.5 bis). Lo que se
   iguala sigue siendo la FORMA; el alto sigue siendo el del toque. */
.admin-boton-periodo {
    min-height: var(--tentalo-toque);
    border-radius: var(--plano-r-tecla);
}

.admin-boton-periodo.mud-button-root {
    padding-inline: 1.05rem;
    border: none;
    border-radius: var(--plano-r-tecla);
    font-size: var(--plano-t-13);
    font-weight: 540;
    background-color: rgba(42, 26, 62, 0.05);
    color: var(--plano-tinta);
}

.admin-boton-periodo.mud-button-root:hover:not(:disabled) {
    background-color: var(--plano-morado-aguada);
    color: var(--plano-morado);
}

/* La elegida va «ocupada», como la pastilla de la pantalla en la que se está. (Su
   relieve de tecla ENCLAVADA lo pone plano.css §8.5 bis y no esta hoja: aquí
   dentro no entra ni una `box-shadow` que no sea la del tooltip, y lo comprueba
   `AnaliticaTests.El_bloque_de_la_analitica_solo_eleva_el_tooltip...`.) */
.admin-boton-periodo.mud-button-root[aria-pressed="true"] {
    background-color: var(--plano-tinta);
    color: var(--plano-papel);
    font-weight: 620;
}

.admin-boton-periodo.mud-button-root[aria-pressed="true"]:hover:not(:disabled) {
    background-color: var(--plano-tinta);
    color: var(--plano-papel);
}

.admin-barra-periodo-fechas {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.admin-campo-fecha {
    min-width: 10rem;
}

/* «COMPARAR CON»: rótulo de plano y pastilla desplegable (tanda de las pantallas
   densas). Era un `CampoDesplegable` de ancho fijo -14rem- y «Mismo periodo del
   año pasado» son 27 caracteres: la caja recortaba en «Mismo periodo del año
   p…». Una pastilla mide lo que mide su texto y se envuelve cuando no cabe; lo
   que NO hace nunca es cortar el valor que dice qué se está mirando. */
.admin-barra-periodo-comparacion {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
}

.admin-barra-periodo-rotulo {
    font-size: var(--plano-t-12);
    font-weight: 600;
    font-stretch: 75%;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--plano-tinta-2);
    white-space: nowrap;
}

/* La pastilla desplegable: el mismo botón contorneado del sistema (radio de control
   desde el repaso del 2026-10-06: lo que se pulsa no es un óvalo), con su
   flecha, el alto de toque y el texto ENTERO (`white-space: nowrap`, sin
   `max-width`). Es la variante secundaria de DESIGN.md, no un campo. */
.admin-pastilla-desplegable.mud-button-root {
    min-height: var(--tentalo-toque);
    padding-inline: 1.05rem;
    border: 1.5px solid var(--plano-linea);
    border-radius: var(--plano-radio-control);
    font-size: var(--plano-t-13);
    font-weight: 540;
    color: var(--plano-tinta);
    background: transparent;
    white-space: nowrap;
}

.admin-pastilla-desplegable.mud-button-root:hover:not(:disabled) {
    border-color: var(--plano-morado);
    background-color: var(--plano-morado-aguada);
    color: var(--plano-morado);
}

/* El activador de un MudMenu envuelve al botón en un `<div>` en línea; sin esto
   el div hereda `display: block` y la pastilla rompe la fila. */
.admin-pastilla-menu {
    display: inline-flex;
    min-width: 0;
}

/* Los chips de establecimiento, con el mismo alto y hueco que las pastillas del
   periodo: son la misma clase de control (elegir con qué se mira) y por tanto
   se tienen que ver iguales. Desde el repaso del 2026-10-06 tampoco son óvalos:
   llevan el radio de tecla de las pastillas del periodo que tienen al lado
   (`.mud-chip.` delante para ganar a la regla del chip pulsable de plano.css). */
.admin-barra-periodo-locales {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
}

.mud-chip.admin-chip-local {
    min-height: var(--tentalo-toque);
    border-radius: var(--plano-r-tecla);
}

/* Las acciones («Excel», «PNG»…) empujan a la derecha cuando cabe, y caen a
   su propia línea cuando no. `margin-left: auto` y no `justify-content`
   porque la barra es un `flex` con varias piezas y solo esta va al final.

   SE QUEDA PARA LOS LISTADOS, que llevan un solo botón («Excel de todo») y ahí
   sí es una acción del periodo. El explorador, que llevaba cuatro, los saca a su
   propia banda: ver `.admin-acciones-de-pagina`. */
.admin-barra-periodo-acciones {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    margin-left: auto;
}

/* --- LA BARRA DE ACCIONES DE PAGINA (tanda de las pantallas densas) -------- */
/*
   UNA PRINCIPAL Y EL RESTO TERCIARIAS, alineadas a la IZQUIERDA y no flotando a
   la derecha. A 2.000 px, cuatro botones pegados al canto derecho no pertenecen
   a nada: no están cerca de lo que modifican ni de lo que producen. Aquí forman
   una banda propia entre la fila del periodo (12 px arriba) y el resultado
   (20 px abajo), que es el aire que el encargo fija.
*/
.admin-acciones-de-pagina {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 20px;
}

/* El motivo de un botón apagado, escrito. No es un aviso ni un error: es la
   nota que explica por qué «PNG» está tramado, y va en tinta rebajada al final
   de la banda. `aria-describedby` la ata al botón. */
.admin-acciones-motivo {
    font-size: var(--plano-t-13);
    color: var(--plano-tinta-2);
}

/* --- Los gráficos -------------------------------------------------------- */
/*
   EL ALTO LO MANDA EL CSS Y NO APEXCHARTS (ver la cabecera de Grafico.razor):
   `aspect-ratio` para que el gráfico crezca con su columna y `min-height` para
   que en una columna estrecha no se quede en una raya.
*/
.admin-grafico-caja {
    width: 100%;
}

.admin-grafico-lienzo {
    width: 100%;
    aspect-ratio: 16 / 9;
    min-height: 260px;
    /* Una región que puede desplazarse dentro de un `flex`/`grid` necesita
       esto o no se encoge nunca (lección del 2026-09-15). */
    min-width: 0;
}

/*
   LA TABLA DE DATOS QUE VA DEBAJO DE CADA GRÁFICO.

   Está SIEMPRE en el DOM y escondida solo para la vista: es lo único que lee
   un lector de pantalla (un <canvas> no tiene nada que leer), lo que se ve si
   ApexCharts no carga y lo que comprueban las pruebas de bUnit, donde no hay
   navegador. No se usa `display: none` por eso mismo: eso la quitaría también
   del árbol de accesibilidad.

   AL IMPRIMIR SÍ SE VE, y el lienzo no: un <canvas> sale en blanco en la
   mayoría de los navegadores al imprimir, así que lo que queda en el papel es
   la tabla, que además es lo que se puede leer.
*/
.admin-grafico-datos {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
    /* UNA TABLA NO SE ENCOGE A 1 px SOLO PORQUE SE LO DIGAS (auditoría responsiva,
       2026-09-18). Con el algoritmo automático, `width: 1px` sobre un `<table>` es
       una sugerencia: la tabla se queda en el ancho de su contenido —536 px con
       trece horas de venta— y, al estar POSICIONADA, esos 536 px cuentan para el
       desplazamiento del documento aunque `clip-path` no deje verlos. El Panel de
       la analítica pedía 543 px de ancho en un teléfono de 390 y la página se iba
       de lado: seis tablas que nadie ve empujando la pantalla entera.
       `table-layout: fixed` es lo que hace que el 1 px se cumpla. */
    table-layout: fixed;
    max-width: 1px;
}

@media print {
    .admin-grafico-datos {
        position: static;
        width: auto;
        max-width: none;
        table-layout: auto;
        height: auto;
        margin: 0;
        overflow: visible;
        clip-path: none;
        white-space: normal;
        border-collapse: collapse;
    }

    .admin-grafico-lienzo {
        display: none;
    }
}

/* --- LA PIEL DE APEXCHARTS (tanda 2 del plano de sala) ------------------- */
/*
   Lo que NO se puede decir desde `Graficos.Json`. ApexCharts escribe en cada
   `<text>` del SVG el `font-family`, el `font-size`, el `font-weight` y el
   `color` que le pasen sus opciones, pero NO `font-stretch`, que es el eje con
   el que Archivo se condensa; y el rótulo condensado de 12 px es la mitad del
   sistema tipográfico del plano. Así que la familia y la anchura de los ejes,
   de la leyenda y de los valores visibles se ponen aquí, sobre el SVG ya
   pintado, que es donde sí se puede.

   EL TOOLTIP lleva la sombra teñida del plano y NINGUN canto. ApexCharts inyecta
   su hoja desde JavaScript, así que su `<style>` va DESPUÉS de éste en el
   documento y a igual peso ganaría: por eso estos selectores llevan tres clases
   (`.apexcharts-canvas` + la suya + su tema) y no dos. Ni un `!important`.
*/
.admin-grafico-lienzo .apexcharts-text,
.admin-grafico-lienzo .apexcharts-legend-text,
.admin-grafico-lienzo .apexcharts-datalabel {
    font-family: var(--plano-familia);
    font-stretch: 75%;
    letter-spacing: 0.01em;
}

/* Las etiquetas de los ejes: rótulo condensado de 12 px, como una cota. */
.admin-grafico-lienzo .apexcharts-xaxis-label,
.admin-grafico-lienzo .apexcharts-yaxis-label {
    font-size: 12px;
    font-weight: 600;
}

.admin-grafico-lienzo .apexcharts-legend-text {
    color: var(--plano-tinta-2);
    font-size: 12px;
}

/* El eje y sus marcas, en la línea del plano y no en el gris de ApexCharts. */
.admin-grafico-lienzo .apexcharts-xaxis line,
.admin-grafico-lienzo .apexcharts-yaxis line,
.admin-grafico-lienzo .apexcharts-gridline {
    stroke: var(--plano-linea-fina);
}

.apexcharts-canvas .apexcharts-tooltip.apexcharts-theme-light,
.apexcharts-canvas .apexcharts-tooltip.apexcharts-theme-dark {
    border: none;
    border-radius: var(--plano-radio-control);
    box-shadow: var(--plano-sombra-alzada);
    background: var(--plano-hoja);
    color: var(--plano-tinta);
    font-family: var(--plano-familia);
    font-size: var(--plano-t-13);
}

.apexcharts-canvas .apexcharts-tooltip.apexcharts-theme-light .apexcharts-tooltip-title,
.apexcharts-canvas .apexcharts-tooltip.apexcharts-theme-dark .apexcharts-tooltip-title {
    background: transparent;
    border-bottom: 1px solid var(--plano-linea-fina);
    font-family: var(--plano-familia);
    font-size: var(--plano-t-12);
    font-stretch: 75%;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--plano-tinta-2);
}

.apexcharts-canvas .apexcharts-tooltip .apexcharts-tooltip-text-y-value {
    font-variant-numeric: tabular-nums;
}

/* --- Las tablas de la analítica ----------------------------------------- */
/*
   Son <table> DE VERDAD y no MudTable, y es deliberado: lo que se pinta aquí
   son cifras -una tabla pivotante de dos pisos de cabecera, un ranking, un
   listado de cien filas- y MudTable añade su propia capa de estado, su
   paginación en el cliente y su ordenación en el cliente, que es justo lo que
   estas tres pantallas NO hacen (todo va al servidor). `.admin-tabla` del marco
   es el envoltorio de un MudTable y no sirve aquí; de ahí el nombre propio.
*/
.admin-analitica-tabla {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}

/* LA PIEL DE TABLA DEL PLANO (tanda 2), la misma que `plano.css` le pone a las
   de MudBlazor: cabecera en rótulo condensado con su regla de 1,5 px, filas
   separadas por regla fina de tinta al 12 %, sin cebra y sin canto alrededor.
   Son dos familias de tablas distintas —éstas son `<table>` a pelo— y tenían
   que verse iguales; ahora se ven iguales. */
.admin-analitica-tabla th,
.admin-analitica-tabla td {
    padding: 0.55rem 0.6rem;
    border-bottom: 1px solid var(--plano-linea-fina);
    text-align: left;
    vertical-align: middle;
}

.admin-analitica-tabla thead th {
    font-size: var(--plano-t-12);
    font-weight: 600;
    font-stretch: 75%;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--plano-tinta-2);
    border-bottom: 1.5px solid var(--plano-linea);
    white-space: nowrap;
}

.admin-analitica-tabla tbody tr:hover {
    background-color: var(--plano-morado-aguada);
}

.admin-analitica-tabla tbody th {
    font-weight: 400;
    color: var(--plano-tinta);
}

.admin-analitica-tabla--compacta th,
.admin-analitica-tabla--compacta td {
    padding: 0.25rem 0.5rem;
    font-size: 0.8125rem;
}

/* LOS NÚMEROS A LA DERECHA (§4). Es lo que permite leer una columna de
   importes en vertical, que es para lo que está. Y sin partirse: «1,40 €» es
   una sola palabra (ver `.plano-cifra` en plano.css). */
.admin-celda-numero {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.admin-celda-total {
    font-weight: 600;
}

/* La cabecera ordenable es un <button> y no un <th> con `onclick`: tiene que
   poder alcanzarse con el tabulador y activarse con Intro, y un `th` no es
   foco. Se despinta del todo para que parezca la cabecera que es. */
.admin-tabla-orden {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    cursor: pointer;
    min-height: var(--tentalo-toque);
}

.admin-tabla-pie {
    margin: 0.5rem 0 0;
    font-size: 0.8125rem;
    color: var(--tentalo-tinta-suave);
}

/* La tabla pivotante puede ser MUY ancha (doce meses × dos medidas), así que
   se desplaza en horizontal dentro de su caja en vez de romper el panel. */
.admin-tabla-pivote-caja {
    overflow-x: auto;
    min-width: 0;
    /* Táctil: el arrastre horizontal es del contenedor, el vertical de la
       página. Sin esto, en una tablet el gesto se lo queda la página. */
    touch-action: pan-x pan-y;
    overscroll-behavior-inline: contain;
    /* LA SEÑAL DE CONTINUIDAD (§14): dos tapas que se van con el contenido y dos
       sombras quietas en los cantos. Es la misma técnica y los mismos valores que
       `plano.css` le pone a `.admin-tabla` y a la tira del área; se repite aquí
       porque esta caja es de la analítica y no pasa por ninguna de las dos. Sin
       ella, una tabla pivotante de doce meses se corta en el canto y nada dice
       que siga. */
    background-repeat: no-repeat;
    background-position: left center, right center, left center, right center;
    background-size: 2rem 100%, 2rem 100%, 1.25rem 100%, 1.25rem 100%;
    background-attachment: local, local, scroll, scroll;
    background-image:
        linear-gradient(to right, var(--plano-papel) 55%, transparent),
        linear-gradient(to left, var(--plano-papel) 55%, transparent),
        linear-gradient(to right, rgba(42, 26, 62, 0.20), rgba(42, 26, 62, 0)),
        linear-gradient(to left, rgba(42, 26, 62, 0.20), rgba(42, 26, 62, 0));
}

.admin-tabla-pivote-esquina {
    position: sticky;
    left: 0;
    background: var(--plano-hoja);
}

/* LA FILA DE TOTALES SE QUEDA AL PIE, con el muro fino encima. En una pregunta
   de cien filas, el total estaba a cien renglones de distancia: o sea, en la
   práctica, no estaba. `position: sticky` sobre las CELDAS y no sobre el
   `<tfoot>` porque un elemento de tabla que no es celda no se pega en todos los
   navegadores; el fondo es el papel de la página, que es lo que hay debajo. */
.admin-analitica-tabla--pivote tfoot :is(th, td) {
    position: sticky;
    bottom: 0;
    z-index: 1;
    background: var(--plano-papel);
    border-top: 1.5px solid var(--plano-linea);
    border-bottom: 0;
}

/* --- LA COMPARACION, EN LA MISMA FILA (tanda de las pantallas densas) ------ */
/*
   AQUI HABIA UNA SUBFILA. Cada resultado arrastraba una segunda `<tr>` con el
   rótulo de la comparación y sus cifras en 12 px: el alto de la tabla se
   doblaba, el dato quedaba lejos de aquello con lo que se compara y la
   DIFERENCIA —que es lo único que se busca al comparar— no se decía en ninguna
   parte. Ahora cada medida lleva dos columnas más a su derecha.

   LA COMPARACION EN TINTA REBAJADA Y UN PELDAÑO MENOR: es el dato de apoyo, no
   el dato. La DIFERENCIA va en salvia o arcilla, que son los dos tonos que el
   sistema reserva para «correcto» y «error» y que aquí dicen «sube» y «baja»;
   el signo va escrito delante, así que el color no es la única señal (la regla
   de la palabra de DESIGN.md).
*/
.admin-celda-comparacion {
    font-size: var(--plano-t-13);
    color: var(--plano-tinta-2);
}

.admin-celda-diferencia {
    font-size: var(--plano-t-13);
    font-weight: 560;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.admin-celda-diferencia--bien {
    color: var(--plano-salvia);
}

.admin-celda-diferencia--mal {
    color: var(--plano-arcilla-honda);
}

.admin-celda-diferencia--neutro {
    color: var(--plano-tinta-2);
}

/* Las dos columnas de apoyo se separan de la SIGUIENTE medida con una regla
   fina vertical, que es lo que agrupa «valor · comparación · diferencia» como
   un solo bloque cuando hay tres medidas seguidas. */
.admin-analitica-tabla--pivote .admin-celda-diferencia {
    border-inline-end: 1px solid var(--plano-linea-fina);
}

.admin-analitica-tabla--pivote tr > .admin-celda-diferencia:last-child {
    border-inline-end: 0;
}

/* --- El explorador ------------------------------------------------------- */

/* `minmax(0, 1fr)` Y NO `1fr` (tanda de las pantallas densas). `1fr` es
   `minmax(auto, 1fr)`, o sea «no bajes del ancho mínimo de tu contenido», y el
   contenido de esta columna son OCHO pestañas: a 390 px la rejilla pedía 424 y
   el documento se desbordaba 34 px por la derecha. Es el mismo arreglo que ya
   llevaba la rejilla del panel viejo (retirado en T4), y no estaba aquí porque
   el Explorador no tenía escena en el banco: la auditoría no puede cazar lo que no mide. */
.admin-explorador {
    display: grid;
    gap: 1rem;
    /* 375: la barra es una HOJA y no una columna. Los cortes, al final. */
    grid-template-columns: minmax(0, 1fr);
}

.admin-explorador > * {
    min-width: 0;
}

/* Y las pestañas se desplazan dentro de su caja en vez de estirarla. MudBlazor
   ya sabe hacerlo; lo que le faltaba era poder encogerse. */
.admin-explorador-pestanas .mud-tabs-tabbar-inner,
.admin-explorador-pestanas .mud-tabs-tabbar {
    min-width: 0;
    max-width: 100%;
}

/* EL TIRADOR DE LA HOJA «PREGUNTA» (tanda de las pantallas densas). Solo existe
   por debajo de 768: en escritorio el constructor está siempre puesto y un botón
   para abrirlo no significaría nada.

   Es una fila de 48 px con el rótulo de plano a la izquierda, la pregunta en
   pastillas en medio y el icono al final, no un botón con la palabra «Medidas y
   filtros»: en un teléfono el constructor está cerrado siempre, así que ese
   botón era el único sitio donde podía decirse qué se está preguntando y no lo
   decía. Las pastillas se desplazan en horizontal cuando son muchas, con su
   señal de continuidad (la máscara), que es lo que pide el §14. */
.admin-explorador-abrir {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    min-height: var(--tentalo-toque);
    padding: 0.35rem 0.75rem;
    border: 1.5px solid var(--plano-linea);
    border-radius: var(--plano-radio-control);
    background: transparent;
    color: var(--plano-tinta);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.admin-explorador-abrir-rotulo {
    flex: 0 0 auto;
    font-size: var(--plano-t-12);
    font-weight: 600;
    font-stretch: 75%;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--plano-tinta-2);
}

.admin-explorador-abrir-pastillas {
    display: flex;
    flex: 1 1 auto;
    gap: 0.35rem;
    min-width: 0;
    overflow-x: auto;
    overscroll-behavior-inline: contain;
    scrollbar-width: none;
    /* LA SEÑAL DE CONTINUIDAD DEL §14, con las dos capas: las TAPAS que se van
       con el contenido (`background-attachment: local`) y las SOMBRAS quietas en
       los cantos, más la máscara que desvanece la pastilla cortada. Las tres
       hacen falta: la sombra se ve por detrás de las pastillas y apenas se nota,
       y la máscara sola no dice de qué lado queda recorrido. */
    background-repeat: no-repeat;
    background-position: left center, right center, left center, right center;
    background-size: 1.25rem 100%, 1.25rem 100%, 0.75rem 100%, 0.75rem 100%;
    background-attachment: local, local, scroll, scroll;
    background-image:
        linear-gradient(to right, var(--plano-papel) 55%, transparent),
        linear-gradient(to left, var(--plano-papel) 55%, transparent),
        linear-gradient(to right, rgba(42, 26, 62, 0.20), rgba(42, 26, 62, 0)),
        linear-gradient(to left, rgba(42, 26, 62, 0.20), rgba(42, 26, 62, 0));
    mask-image: linear-gradient(to right, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%);
}

.admin-explorador-resumen {
    flex: 0 0 auto;
    white-space: nowrap;
}

.admin-explorador-lateral {
    display: none;
}

/* EL VELO de la hoja inferior, el mismo de todo el sistema. */
.admin-explorador-velo {
    position: fixed;
    inset: 0;
    z-index: 1350;
    background-color: rgba(42, 26, 62, 0.35);
}

/* LA HOJA INFERIOR del teléfono. Era una capa `inset: 0` de `#fff` —un blanco
   puro que no está en la paleta— que tapaba la pantalla entera: no se veía nada
   de lo que se estaba cambiando y no había forma de cerrarla sin buscar el aspa.
   Ahora es la hoja inferior del sistema: hasta 88dvh, papel de hoja, esquinas de
   zona por arriba, sombra de hoja y el mismo giro sobre la bisagra. */
.admin-explorador-lateral--abierta {
    display: block;
    position: fixed;
    inset-inline: 0;
    inset-block-end: 0;
    z-index: 1360;
    max-height: 88dvh;
    padding: 0.75rem 1rem calc(1rem + var(--tentalo-toque) + env(safe-area-inset-bottom, 0px));
    overflow-y: auto;
    min-height: 0;
    background: var(--plano-hoja);
    border-start-start-radius: var(--plano-radio-zona);
    border-start-end-radius: var(--plano-radio-zona);
    box-shadow: var(--plano-sombra-hoja);
    animation: plano-hoja-entra var(--plano-tiempo-largo) var(--plano-curva);
    transform-origin: bottom center;
    touch-action: pan-y;
}

.admin-explorador-cerrar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.25rem;
}

.admin-explorador-hoja-titulo {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 640;
    letter-spacing: -0.01em;
}

.admin-explorador-barra {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    min-width: 0;
}

.admin-explorador-principal {
    min-width: 0;
}

.admin-explorador-rotulo {
    margin: 0 0 0.35rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--tentalo-tinta-suave);
    text-transform: none;
}

/* SIN CAJA (tanda de las pantallas densas). Eran dos rectángulos con canto de
   1 px y radio de 12 dentro de la columna del constructor: una tarjeta metida en
   otra, que es justo lo que DESIGN.md prohíbe por su nombre. Lo que les da
   principio y fin es ahora una regla fina por arriba y el aire de la columna. */
.admin-explorador-filtros,
.admin-explorador-periodo {
    padding: 0.75rem 0 0;
    border: none;
    border-top: 1px solid var(--plano-linea-fina);
    border-radius: 0;
}

/* LA FILA DE UN FILTRO, con la gramática de fila del plano: 44 px, el nombre a
   la izquierda sin romperse y el aspa como único objetivo de la derecha. */
.admin-explorador-filtro {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-height: 44px;
    min-width: 0;
    padding: 0.2rem 0;
}

.admin-explorador-filtro-nombre {
    flex: 0 1 auto;
    min-width: 0;
    font-weight: 600;
    font-size: 0.8125rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.admin-explorador-filtro .mud-icon-button {
    min-width: 44px;
    min-height: 44px;
}

.admin-explorador-filtro-valores {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.8125rem;
    color: var(--tentalo-tinta-suave);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.admin-explorador-sin-filtros,
.admin-explorador-ayuda,
.admin-explorador-periodo-comparacion {
    margin: 0.2rem 0 0;
    font-size: 0.8125rem;
    color: var(--tentalo-tinta-suave);
}

.admin-explorador-periodo-texto {
    margin: 0;
    font-weight: 600;
}

.admin-explorador-pestanas {
    margin-bottom: 0;
}

/* LA LINEA DEL RESULTADO, bajo las pestañas (tanda de las pantallas densas).
   Una sola frase en tinta rebajada —«4 ms · 24 filas · detalle»— en vez de los
   dos rótulos sueltos que colgaban del panel («TABLA» a la izquierda, «4 ms» y
   «detalle» a la derecha) y que además repetían el nombre de la pestaña que se
   acababa de pulsar. Aquí viven también «Cancelar» y la pastilla de densidad,
   porque las tres cosas hablan del resultado que hay debajo. */
.admin-explorador-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin: 0.35rem 0 0.75rem;
    min-height: 1.5rem;
}

.admin-explorador-tiempo {
    font-size: var(--plano-t-13);
    color: var(--plano-tinta-2);
    font-variant-numeric: tabular-nums;
}

/* La densidad empuja al final de la línea: es un mando, no un dato. Y NO SE
   ESTIRA: `MudToggleGroup` es `display: flex` a todo el ancho por omisión, y en
   la línea del resultado eso daba una barra de dos metros con «Normal» y
   «Compacta» dentro, más ancha que la tabla que gobierna. */
.admin-explorador-densidad.mud-toggle-group {
    margin-left: auto;
    width: auto;
    /* `flex: 0 0 auto` es lo que la saca del reparto: MudBlazor escribe
       `grid-template-columns: repeat(2, minmax(0, 1fr))` EN LINEA —y un estilo
       en línea no se pisa sin `!important`—, pero esos `1fr` se reparten el
       ancho que tenga la caja, y la caja ya no crece. */
    flex: 0 0 auto;
}

.admin-explorador-densidad .mud-toggle-item {
    flex: 0 0 auto;
    padding-inline: 0.9rem;
    font-size: var(--plano-t-13);
}

/* «Elegir…» en la columna estrecha va CONTORNEADO. La acción principal de esta
   pantalla es «Excel»; un segundo botón relleno de morado a media pantalla dice
   que hay dos acciones principales, que es lo que DESIGN.md prohíbe con todas
   las letras. En una ficha, donde el relleno es lo correcto, no cambia nada. */
.campo-lista--compacto .campo-lista__elegir.mud-button-root {
    background-color: transparent;
    border: 1.5px solid var(--plano-linea);
    color: var(--plano-tinta);
    box-shadow: none;
}

.campo-lista--compacto .campo-lista__elegir.mud-button-root:hover:not(:disabled) {
    border-color: var(--plano-morado);
    background-color: var(--plano-morado-aguada);
    color: var(--plano-morado);
}

/* Las doce vistas de fábrica, que solo se ven cuando no hay resultado: son la
   respuesta a «y ahora qué pregunto». Región, no caja: regla fina arriba y aire,
   como las demás zonas de la pantalla. */
.admin-explorador-vistas {
    margin-top: 1.25rem;
    padding: 1rem 0 0;
    border: none;
    border-top: 1px solid var(--plano-linea-fina);
    border-radius: 0;
}

.admin-explorador-vistas-lista {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.admin-explorador-vista {
    min-height: var(--tentalo-toque);
    border-radius: 10px;
}

/* --- LA TABLA PIVOTANTE EN UN MOVIL (tanda de las pantallas densas) -------- */
/*
   LA REGLA DE LA ETIQUETA, llevada a la tabla del explorador. Por debajo de
   720 px, una tabla de cuatro columnas numéricas —valor, comparación, diferencia
   y la dimensión— no cabe: o se desplaza (y entonces sólo se ve la mitad de cada
   fila) o se apila. Aquí se apila con el patrón del sistema: la dimensión en 600
   a la izquierda, la cifra a su derecha, y debajo la comparación y la diferencia
   en 13 px y tinta rebajada.

   SOLO CON UNA MEDIDA, y se pregunta con `data-medidas`: con dos o más, «valor ·
   comparación · diferencia» por medida son seis o nueve cifras sin rótulo, que
   apiladas no dicen cuál es cuál. En ese caso manda el carril, que ya lleva su
   señal de continuidad.
*/
@media (max-width: 719.98px) {
    .admin-analitica-tabla--pivote[data-medidas="1"] thead {
        /* Sin cabecera: el nombre de cada dato se deduce de su sitio, que es lo
           que hace la regla de la etiqueta en las otras cuarenta y siete listas. */
        display: none;
    }

    .admin-analitica-tabla--pivote[data-medidas="1"] :is(tbody, tfoot) > tr {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        column-gap: 0.5rem;
        row-gap: 0.1rem;
        align-items: baseline;
        padding: 0.5rem 0;
        border-bottom: 1px solid var(--plano-linea-fina);
    }

    .admin-analitica-tabla--pivote[data-medidas="1"] :is(tbody, tfoot) > tr > :is(th, td) {
        padding: 0;
        border: 0;
    }

    .admin-analitica-tabla--pivote[data-medidas="1"] :is(tbody, tfoot) > tr > th[scope="row"] {
        grid-column: 1;
        grid-row: 1;
        font-weight: 600;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .admin-analitica-tabla--pivote[data-medidas="1"] :is(tbody, tfoot) > tr > td:first-of-type {
        grid-column: 2;
        grid-row: 1;
        font-weight: 560;
    }

    .admin-analitica-tabla--pivote[data-medidas="1"] .admin-celda-comparacion {
        grid-column: 1;
        grid-row: 2;
        text-align: left;
    }

    .admin-analitica-tabla--pivote[data-medidas="1"] .admin-celda-diferencia {
        grid-column: 2;
        grid-row: 2;
        border-inline-end: 0;
    }

    /* La cifra del pie sigue siendo el total, y se rotula: sin cabecera, «Total»
       ya está en la primera columna de su propia fila. */
    .admin-analitica-tabla--pivote[data-medidas="1"] tfoot > tr {
        border-top: 1.5px solid var(--plano-linea);
        border-bottom: 0;
    }
}

/* --- Los listados -------------------------------------------------------- */

.admin-listado-barra {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

.admin-listado-buscador {
    flex: 1 1 14rem;
    min-width: 0;
}

.admin-listado-densidad {
    border-radius: 10px;
}

.admin-listado-tabla-caja {
    overflow-x: auto;
    min-width: 0;
    touch-action: pan-x pan-y;
}

/* La fila de filtros por columna (un <input> pelado por celda) se fue el 2026-10-06: «son una chapuza», dijo el
   usuario. Los filtros por columna son ahora los embudos tipo Excel de hoja-limpia.css (FILTROS TIPO EXCEL). */

/* --- LOS DOS OBJETIVOS PEQUEÑOS DE UN LISTADO DEL BI ---------------------- */
/*
   Los cazó la auditoría en cuanto los listados del BI entraron en el banco
   (tanda de las pantallas densas): el botón de «Columnas» medía 36 px de ancho
   y los filtros por columna, 28 de alto. Los dos se tocan en una tableta y los
   dos estaban por debajo de los 44 px del sistema. Se suben por FAMILIA —el
   botón de icono de la barra del listado y el campo de filtro— y no pantalla a
   pantalla, que es la regla del §6 de la auditoría de la mañana.
*/
@media (max-width: 768px) {
    .admin-listado-barra .mud-icon-button,
    .admin-listado-barra .mud-menu > .mud-button-root {
        min-width: var(--tentalo-toque);
        min-height: var(--tentalo-toque);
    }

}

/* EL ENLACE DE UNA CELDA se toca con el dedo en una TABLETA: «A/1204» son
   49 × 16 px, o sea la mitad del objetivo. Crece en ALTO y no en ancho —el ancho
   ya llega— y como `inline-flex`, que es lo que le deja centrar su texto.

   DE 720 PARA ARRIBA Y NO DE 390: por debajo de 720 la fila del listado ya está
   apilada con la gramática de etiqueta y el enlace es la primera línea, así que
   ahí el objetivo lo da la fila. Con la regla suelta hasta 390, cada fila crecía
   de 79 a 104 px —de diez resultados por pantalla a ocho— por un objetivo que ya
   estaba bien. */
@media (min-width: 720px) and (max-width: 768px) {
    .admin-analitica-tabla tbody a {
        display: inline-flex;
        align-items: center;
        min-height: var(--tentalo-toque);
    }
}

.admin-listado-paginacion {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.75rem;
}

.admin-listado-cuenta {
    margin-right: auto;
    font-size: 0.8125rem;
    color: var(--tentalo-tinta-suave);
    font-variant-numeric: tabular-nums;
}

/* --- La redirección de los informes viejos ------------------------------- */

.admin-redireccion {
    padding: 2rem 1rem;
    text-align: center;
    color: var(--tentalo-tinta-suave);
}

/* ========================================================================== */
/*  LOS TRES CORTES (§4)                                                      */
/*  375 una columna · 768 el Explorador con su barra en columna               */
/* ========================================================================== */
/*
   Se escriben como `min-width` y en orden creciente, así que lo de arriba es
   el TELÉFONO y estas reglas solo añaden. Es la forma que hace que una
   pantalla nueva funcione en 375 px aunque nadie se acuerde de probarla.
*/

@media (min-width: 768px) {
    /* La barra del explorador deja de ser una hoja y pasa a ser una COLUMNA de
       320 px, que es la medida del §3.2. El botón de abrirla desaparece. */
    .admin-explorador {
        grid-template-columns: 320px minmax(0, 1fr);
    }

    .admin-explorador-abrir {
        display: none;
    }

    .admin-explorador-lateral,
    .admin-explorador-lateral--abierta {
        display: block;
        position: static;
        max-height: none;
        padding: 0;
        overflow: visible;
        background: none;
        border-radius: 0;
        box-shadow: none;
        animation: none;
    }

    .admin-explorador-cerrar,
    .admin-explorador-velo {
        display: none;
    }
}

/* ========================================================================== */
/*  LA VARIANTE OSCURA: POR QUE AQUI NO, Y DONDE SI                           */
/* ========================================================================== */
/*
   DESDE EL REDISEÑO D1 (2026-10-04) LA CENTRAL SÍ TIENE VARIANTE OSCURA: la
   ponen hoja-limpia.css (las fichas --limpia-* y las --plano-* bajo
   prefers-color-scheme) y la PaletteDark de App.razor, que además pone
   data-tema="oscuro" para los gráficos. Lo que sigue es por qué no la hubo.

   Aquí hubo un bloque `@media (prefers-color-scheme: dark)` que repintaba el
   fondo de las cajas de la analítica. Se fue el mismo día que entró, y el
   detector de UI lo cazó con veintidós avisos de contraste: repintaba los
   FONDOS y no las TINTAS, así que en un navegador puesto en oscuro salían
   tarjetas de fondo #1c1720 con texto #2b2b2b encima. 1,2:1.

   Y aunque estuvieran bien las tintas, entonces seguía estando mal: la web de
   la central no tenía variante oscura, y un bloque oscuro que sólo alcanzara
   a la analítica dejaba seis tarjetas negras en medio de una página blanca.
   Por eso la de D1 no vive aquí sino en hoja-limpia.css, que oscurece las
   fichas que lee toda la web (el menú, la barra y las demás pantallas cambian
   con ella).

   El parámetro `Oscuro` de `Grafico.razor` y el `oscuro` de `Graficos.Json`
   cambian los tres neutros de un gráfico (tinta de ejes, rejilla y tooltip)
   sin tocar la paleta de series. Desde D1 les llega de verdad: App.razor pone
   en cascada `TemaOscuro` según el modo del sistema.
*/

/* ========================================================================== */
/*  MENOS MOVIMIENTO                                                          */
/* ========================================================================== */
/*
   La animación de ENTRADA de los gráficos ya está apagada siempre en
   Graficos.cs; lo que se apaga aquí es lo que ApexCharts mete por su cuenta en
   el DOM al redibujar, que no pasa por las opciones.
*/
@media (prefers-reduced-motion: reduce) {
    .admin-grafico-lienzo * {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* ========================================================================== */
/*  LOS GRAFICOS SVG DE LA ANALITICA (rediseño del 2026-09-29, tanda T2)      */
/* ========================================================================== */
/*
   docs\central\analitica-rediseno-2026-09-29.md §6. Los componentes de
   Web.Analitica\Components\Graficos\: LineasConComparacion, ColumnasConLinea,
   BarrasHorizontales y MapaDeCalor (Minigrafico y CifraGrande, del panel viejo,
   se retiraron en D6). Todo lleva el prefijo `grafico-` y nada de aquí toca a
   nadie más.

   COMO SE PINTAN, en tres reglas:

     1. EL DIBUJO SE ESTIRA Y EL TEXTO NO. El SVG tiene un `viewBox` fijo y
        `preserveAspectRatio="none"`: ocupa el ancho de su caja y el ALTO LO
        PONE ESTA HOJA (`--grafico-alto`), así que el gráfico no salta al
        cargar y mide lo mismo en 375 que en 1600 px. Los textos de los ejes
        son HTML colocados en tanto por ciento y miden sus 12 px en cualquier
        ancho; los trazos llevan `non-scaling-stroke`, y los puntos son trazos
        de longitud cero con remate redondo, que con eso son círculos.
     2. LOS COLORES SON FICHAS. Cada gráfico lee NUEVE fichas propias
        (`--grafico-*`) que salen de las del plano: la serie en morado, la
        comparación en lila clara discontinua, subir en salvia y bajar en
        arcilla honda (§6). El marcado no lleva ni un color (lo comprueba
        GraficosSvgTests).
     3. SIN ANIMACIONES Y SIN JAVASCRIPT. El hover es CSS (`:hover` enciende el
        punto, la guía y la banda del día) más el `<title>` de cada elemento,
        que el navegador enseña como aviso.

   EL TEMA OSCURO SALE DE LAS FICHAS, y sólo de ellas: basta con que un
   antepasado lleve `data-tema="oscuro"` para que las nueve cambien. Desde el
   rediseño D1 (2026-10-04) lo pone App.razor en el envoltorio de toda la web
   según el modo del sistema (antes sólo lo usaba el banco de capturas). NO se
   cuelga de `prefers-color-scheme` directamente para que el gráfico siga al
   mismo `oscuro` que MudBlazor y el resto de la página (ver «LA VARIANTE
   OSCURA: POR QUE AQUI NO, Y DONDE SI», arriba). Los tonos
   oscuros son los del tema oscuro del TPV (tactil.css: texto #f3eff7 y
   #c4bccf, correcto #5fd38d, error #ff6b6b) con el morado aclarado hasta dar
   6,4:1 sobre el panel #1c1920.
*/
.grafico {
    --grafico-serie: var(--plano-morado);
    --grafico-comparacion: #8a7a9e; /* 3,56:1 sobre el papel: un trazo necesario pide 3:1 (WCAG 1.4.11); la lila-clara daba 1,57:1 */
    --grafico-sube: var(--plano-salvia);
    --grafico-baja: var(--plano-arcilla-honda);
    --grafico-texto: var(--plano-tinta);
    --grafico-texto-2: var(--plano-tinta-2);
    --grafico-rejilla: var(--plano-linea-fina);
    --grafico-eje: var(--plano-linea);
    --grafico-vacia: var(--plano-papel-hondo);
    --grafico-resalte: var(--plano-morado-aguada);
}

[data-tema="oscuro"] .grafico {
    --grafico-serie: #b98ae0;
    --grafico-comparacion: #8a7fa0;
    --grafico-sube: #5fd38d;
    --grafico-baja: #ff6b6b;
    --grafico-texto: #f3eff7;
    --grafico-texto-2: #c4bccf;
    --grafico-rejilla: rgba(243, 239, 247, 0.10);
    --grafico-eje: rgba(243, 239, 247, 0.28);
    --grafico-vacia: #2b2631;
    --grafico-resalte: rgba(185, 138, 224, 0.14);
}

.grafico {
    /* El alto del trazo de líneas y columnas. Fijo, y por eso aquí: no depende
       del ancho, así que la pantalla no salta al cargar ni al girar el móvil. */
    --grafico-alto: 15rem;
    margin: 0;
    min-width: 0;
    color: var(--grafico-texto);
    font-variant-numeric: tabular-nums;
    /* LA TABLA OCULTA NO EMPUJA LA PAGINA (tanda T3, medido en una central local a 375 px). Una
       <table> no encoge por debajo de su contenido aunque lleve `width: 1px`, así que la de los
       datos de un gráfico medía 385-593 px y la página se desplazaba de lado 17-225 px. El gráfico
       es su caja (`position: relative`) y la recorta en horizontal (`clip`, que no crea barra de
       desplazamiento ni corta nada en vertical). */
    position: relative;
    overflow-x: clip;
}

/* --- Líneas y columnas: la caja, los ejes y el trazo ------------------------ */

.grafico-lienzo {
    display: grid;
    /* La columna del eje Y tiene ancho FIJO: sus etiquetas van en posición
       absoluta y no la ensancharían. 3,5rem caben «200 k €» y «-500 €». */
    grid-template-columns: 3.5rem minmax(0, 1fr);
    grid-template-rows: var(--grafico-alto) auto;
    column-gap: 0.5rem;
    /* Media etiqueta de aire arriba: la del tope se centra en la línea de
       arriba y, sin esto, asomaría por encima de la caja. */
    padding-block-start: 0.5rem;
}

.grafico-eje-y {
    position: relative;
    grid-column: 1;
    grid-row: 1;
}

.grafico-eje-y span,
.grafico-eje-x span {
    position: absolute;
    font-size: var(--plano-t-12);
    line-height: 1;
    font-weight: 500;
    color: var(--grafico-texto-2);
    white-space: nowrap;
}

.grafico-eje-y span {
    right: 0;
    transform: translateY(-50%);
}

.grafico-trazo {
    position: relative;
    grid-column: 2;
    grid-row: 1;
    min-width: 0;
}

.grafico-svg {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
    overflow: visible;
}

.grafico-eje-x {
    position: relative;
    grid-column: 2;
    grid-row: 2;
    block-size: 1.6rem;
}

.grafico-eje-x span {
    top: 0.5rem;
    transform: translateX(-50%);
}

/* Al ras por dentro en los extremos: la última etiqueta no se sale de la caja
   ni empuja la página de lado en un teléfono. */
.grafico-eje-x span.grafico-eje-x-marca--inicio {
    transform: none;
}

.grafico-eje-x span.grafico-eje-x-marca--fin {
    transform: translateX(-100%);
}

.grafico :is(line, polyline, path) {
    vector-effect: non-scaling-stroke;
}

.grafico-rejilla {
    stroke: var(--grafico-rejilla);
    stroke-width: 1px;
}

.grafico-cero {
    stroke: var(--grafico-eje);
    stroke-width: 1px;
}

.grafico-serie {
    fill: none;
    stroke: var(--grafico-serie);
    stroke-width: 2px;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.grafico-comparacion,
.grafico-linea {
    fill: none;
    stroke: var(--grafico-comparacion);
    stroke-width: 2px;
    stroke-dasharray: 5 4;
    stroke-linejoin: round;
}

.grafico-columna {
    fill: var(--grafico-serie);
}

/* Una hora con más abonos que ventas: cuelga del cero en el tono de bajar. */
.grafico-columna--negativa {
    fill: var(--grafico-baja);
}

/* LO QUE NO RECOGE EL PUNTERO: las líneas y los puntos van por encima de las
   bandas, y si lo recogieran taparían el aviso del día que está debajo. */
.grafico :is(.grafico-rejilla, .grafico-cero, .grafico-serie, .grafico-comparacion,
             .grafico-linea, .grafico-guia, .grafico-punto, .grafico-columna) {
    pointer-events: none;
}

/* La banda de cada día u hora: transparente, a toda altura, y es la que recoge
   el puntero. Al pasar se tiñe con la aguada de morado. */
.grafico-zona {
    fill: transparent;
}

.grafico-dato:hover .grafico-zona {
    fill: var(--grafico-resalte);
}

.grafico-guia {
    stroke: var(--grafico-eje);
    stroke-width: 1px;
    opacity: 0;
}

/* El punto: un trazo de longitud cero con remate redondo (ver la regla 1). */
.grafico-punto {
    fill: none;
    stroke-linecap: round;
    stroke-width: 8px;
    opacity: 0;
}

.grafico-punto--serie {
    stroke: var(--grafico-serie);
}

.grafico-punto--comparacion {
    stroke: var(--grafico-comparacion);
    stroke-width: 7px;
}

.grafico-punto--fijo,
.grafico-dato:hover :is(.grafico-guia, .grafico-punto) {
    opacity: 1;
}

/* --- La leyenda ----------------------------------------------------------- */

.grafico-leyenda {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem 1rem;
    margin-block-start: 0.35rem;
    font-size: var(--plano-t-12);
    color: var(--grafico-texto-2);
}

.grafico-clave {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

.grafico-clave::before {
    content: "";
    inline-size: 1.1rem;
    block-size: 0;
    border-block-start: 2px solid var(--grafico-serie);
}

.grafico-clave--comparacion::before {
    border-block-start: 2px dashed var(--grafico-comparacion);
}

.grafico-clave--columna::before {
    inline-size: 0.75rem;
    block-size: 0.75rem;
    border: 0;
    border-radius: 2px;
    background: var(--grafico-serie);
}

/* --- Sin datos ------------------------------------------------------------ */
/* El MISMO alto que el gráfico, con una frase: nunca un hueco en blanco (el
   fallo del panel viejo, §1). */
.grafico-vacio {
    display: grid;
    place-items: center;
    min-block-size: var(--grafico-alto);
    margin: 0;
    border: 1.5px dashed var(--grafico-eje);
    border-radius: var(--plano-radio-control);
    font-size: var(--plano-t-13);
    color: var(--grafico-texto-2);
}

.grafico-barras .grafico-vacio,
.grafico-calor .grafico-vacio {
    min-block-size: 8rem;
}

/* --- La tabla oculta ------------------------------------------------------ */
/* Lo que lee un lector de pantalla y lo que sale al imprimir. Es el patrón de
   `.admin-grafico-datos`, con su `table-layout: fixed`: sin él, una tabla
   posicionada de 1 px sigue midiendo lo que su contenido y empuja la página
   de lado en un teléfono (auditoría responsiva, 2026-09-18). */
.grafico-datos {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
    table-layout: fixed;
    max-width: 1px;
}

@media print {
    .grafico {
        overflow-x: visible;
    }

    .grafico-datos {
        position: static;
        width: auto;
        max-width: none;
        table-layout: auto;
        height: auto;
        margin: 0;
        overflow: visible;
        clip-path: none;
        white-space: normal;
        border-collapse: collapse;
    }

    .grafico-lienzo,
    .grafico-barras-lista,
    .grafico-calor-rejilla,
    .grafico .grafico-leyenda {
        display: none;
    }
}

/* --- Barras horizontales -------------------------------------------------- */
/*
   Las filas son una `subgrid` de la lista: etiqueta, barra, valor y, si alguna
   fila los tiene, detalle y variación, alineados en columna aunque las
   etiquetas midan distinto. La etiqueta mide lo que la más larga hasta 12rem y
   luego se corta con puntos suspensivos (el nombre entero va en su `title`).
*/
.grafico-barras {
    container: grafico-barras / inline-size;
}

.grafico-barras-lista {
    display: grid;
    grid-template-columns: fit-content(12rem) minmax(3rem, 1fr) max-content;
    column-gap: 0.75rem;
}

.grafico-barras-lista--con-detalle,
.grafico-barras-lista--con-variacion {
    grid-template-columns: fit-content(12rem) minmax(3rem, 1fr) max-content max-content;
}

.grafico-barras-lista--con-detalle.grafico-barras-lista--con-variacion {
    grid-template-columns: fit-content(12rem) minmax(3rem, 1fr) max-content max-content max-content;
}

.grafico-barra-fila {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
    align-items: center;
    row-gap: 0.3rem;
    min-block-size: 2.25rem;
    padding-block: 0.3rem;
    border-block-end: 1px solid var(--grafico-rejilla);
    font-size: var(--plano-t-13);
}

.grafico-barra-fila:hover {
    background-color: var(--grafico-resalte);
}

.grafico-barra-etiqueta {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.grafico-barra-trazo {
    display: block;
    inline-size: 100%;
    block-size: 0.875rem;
    overflow: visible;
}

.grafico-barra {
    fill: var(--grafico-serie);
}

.grafico-barra--negativa {
    fill: var(--grafico-baja);
}

.grafico-barra-valor,
.grafico-barra-detalle,
.grafico-barra-fila .grafico-variacion {
    text-align: end;
    white-space: nowrap;
}

.grafico-barra-valor {
    font-weight: 600;
}

.grafico-barra-detalle {
    color: var(--grafico-texto-2);
}

.grafico-variacion--bien {
    color: var(--grafico-sube);
}

.grafico-variacion--mal {
    color: var(--grafico-baja);
}

.grafico-variacion--neutro {
    color: var(--grafico-texto-2);
}

/* EN UNA CAJA ESTRECHA la barra baja a su propia línea, a todo el ancho, y la
   etiqueta y las cifras se quedan arriba. Es una consulta de CONTENEDOR y no de
   ventana: el mismo bloque va a todo el ancho en el Resumen y en media columna
   en Cobros, y lo que importa es cuánto mide él. */
@container grafico-barras (max-width: 30rem) {
    .grafico-barras-lista {
        grid-template-columns: minmax(0, 1fr) max-content;
    }

    .grafico-barras-lista--con-detalle,
    .grafico-barras-lista--con-variacion {
        grid-template-columns: minmax(0, 1fr) max-content max-content;
    }

    .grafico-barras-lista--con-detalle.grafico-barras-lista--con-variacion {
        grid-template-columns: minmax(0, 1fr) max-content max-content max-content;
    }

    .grafico-barra-trazo {
        grid-row: 2;
        grid-column: 1 / -1;
    }
}

/* --- Mapa de calor -------------------------------------------------------- */

.grafico-calor-rejilla {
    display: grid;
    grid-template-columns: 2.5rem minmax(0, 1fr);
    grid-template-rows: auto calc(var(--grafico-filas) * 1.75rem);
    column-gap: 0.5rem;
    row-gap: 0.3rem;
    /* Una celda no pasa de 3,5rem de ancho: con doce horas a 1600 px saldrían
       rectángulos de 120 × 28 px, que se leen como franjas y no como celdas. */
    max-inline-size: calc(3rem + (var(--grafico-columnas) * 3.5rem));
}

.grafico-calor-columnas {
    grid-column: 2;
    grid-row: 1;
    display: grid;
    grid-template-columns: repeat(var(--grafico-columnas), minmax(0, 1fr));
}

.grafico-calor-filas {
    grid-column: 1;
    grid-row: 2;
    display: grid;
    grid-template-rows: repeat(var(--grafico-filas), minmax(0, 1fr));
    align-items: center;
}

.grafico-calor-columnas span,
.grafico-calor-filas span {
    font-size: var(--plano-t-12);
    line-height: 1;
    font-weight: 500;
    color: var(--grafico-texto-2);
    white-space: nowrap;
}

.grafico-calor-columnas span {
    text-align: center;
    /* Con 24 horas a 375 px la columna mide 13 px y «14 h», 26: el rótulo se
       desborda a la columna de al lado, que es la que va sin rotular. */
    overflow: visible;
    justify-self: center;
}

/* EN UNA CAJA ESTRECHA, uno de cada dos rótulos de hora (el componente marca
   cuáles): con dieciséis horas a 375 px la columna mide 18 px y «14 h», 24. */
.grafico-calor {
    container: grafico-calor / inline-size;
}

@container grafico-calor (max-width: 36rem) {
    .grafico-calor-columnas .grafico-calor-rotulo--secundario {
        visibility: hidden;
    }
}

.grafico-calor-svg {
    grid-column: 2;
    grid-row: 2;
    display: block;
    inline-size: 100%;
    block-size: 100%;
}

.grafico-celda,
.grafico-calor-muestra {
    fill: var(--grafico-serie);
}

.grafico-celda--vacia {
    fill: var(--grafico-vacia);
}

.grafico-celda:hover {
    stroke: var(--grafico-texto);
    stroke-width: 2px;
    vector-effect: non-scaling-stroke;
}

.grafico-calor-rampa {
    display: inline-flex;
    gap: 2px;
}

.grafico-calor-rampa svg {
    display: block;
    inline-size: 0.875rem;
    block-size: 0.875rem;
}

/* ========================================================================== */
/*  EL PANEL «COMO VA EL NEGOCIO» (rediseño del 2026-09-29, tanda T3)          */
/* ========================================================================== */
/*
   docs\central\analitica-rediseno-2026-09-29.md §3 y §4: la barra común, las
   cinco pestañas y sus bloques. Todo lleva el prefijo `analitica-`; los
   gráficos son los del bloque de arriba y aquí no se tocan.

   Las reglas de siempre de la analítica: ni una sombra (la barra fija se separa
   con una regla fina, no con relieve), ni un filo, el teléfono como caso base
   (`min-width`) y lo que se toca mide el toque.
*/

/* --- La barra común ------------------------------------------------------ */

/* FIJA ARRIBA DESDE 768 PX (§3). En un teléfono la barra son cuatro o cinco
   renglones de teclas: fija, taparía un tercio de la pantalla, así que ahí se
   queda en su sitio y sube con la página. El papel de fondo tapa lo que pasa
   por debajo; la regla fina de abajo la separa sin sombra. */
.analitica-barra {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
    padding: 0.5rem 0 0.75rem;
    border-bottom: 1px solid var(--plano-linea-fina);
    border-radius: 0;
    background: var(--plano-papel);
}

.analitica-barra-fila {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    min-width: 0;
}

.analitica-barra-comparar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* «Explorar ↗» y «Listados ↗»: a la derecha cuando cabe, a su renglón si no. */
.analitica-barra-enlaces {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1rem;
    margin-left: auto;
}

.analitica-enlace-herramienta,
.analitica-enlace {
    display: inline-flex;
    align-items: center;
    min-height: var(--tentalo-toque);
    padding: 0 0.25rem;
    border: 0;
    border-radius: var(--plano-r-tecla);
    background: none;
    font: inherit;
    font-size: var(--plano-t-13);
    font-weight: 600;
    color: var(--plano-morado);
    text-decoration: none;
    cursor: pointer;
}

.analitica-enlace-herramienta:hover,
.analitica-enlace:hover {
    text-decoration: underline;
}

/* «Calculando datos: 43 % (hasta el 12/09)». Se lee, no alarma: tinta sobre la
   aguada morada, como el resto de avisos de estado de la analítica. */
.analitica-franja {
    padding: 0.5rem 0.75rem;
    border-radius: var(--plano-r-tecla);
    background: var(--plano-morado-aguada);
    color: var(--plano-tinta);
    font-size: var(--plano-t-13);
}

/* --- Las pestañas -------------------------------------------------------- */

/* Una tira de enlaces (cada pestaña es una URL: se puede abrir en otra
   ventana o compartir), con la abierta subrayada en morado. Si no caben, la
   tira se desplaza de lado y la página no. */
.analitica-pestanas {
    display: flex;
    gap: 0.25rem;
    margin-bottom: 1rem;
    overflow-x: auto;
    min-width: 0;
    touch-action: pan-x pan-y;
    border-bottom: 1px solid var(--plano-linea-fina);
    border-radius: 0;
    scrollbar-width: none;
}

.analitica-pestana {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    min-height: var(--tentalo-toque);
    padding: 0 0.85rem;
    border-bottom: 3px solid transparent;
    border-radius: 0;
    font-size: var(--plano-t-15);
    font-weight: 540;
    color: var(--plano-tinta-2);
    text-decoration: none;
    white-space: nowrap;
}

.analitica-pestana:hover {
    color: var(--plano-morado);
}

.analitica-pestana[aria-current="page"] {
    border-bottom-color: var(--plano-morado);
    color: var(--plano-tinta);
    font-weight: 650;
}

/* --- Los bloques ----------------------------------------------------------- */

.analitica-contenido {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    min-width: 0;
}

.analitica-contenido > * {
    min-width: 0;
}

/* LA FRASE DE CONCLUSION (§5): lo primero que se lee del bloque, en tinta y a
   15 px, por encima del gráfico al que resume. Sin margen: el aire lo pone el
   hueco de 12 px del cuerpo del panel (una columna flex), igual que al esqueleto. */
.analitica-conclusion {
    margin: 0;
    font-size: var(--plano-t-15);
    line-height: 1.4;
    color: var(--plano-tinta);
}

/* Las cuatro cifras grandes: una, dos o cuatro por fila. */
.analitica-cifras {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.25rem 1.5rem;
}

.analitica-rejilla {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
}

/* Las dos zonas de una fila empiezan a la misma altura: la segunda no es la
   primera de su contenedor y `.plano-region` le ponía 28 px encima. */
.analitica-rejilla > * {
    min-width: 0;
    margin-block-start: 0;
}

.analitica-bloque-pie {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1rem;
}

/* --- Las tablas del panel ------------------------------------------------ */

/* Se desplazan DENTRO de su caja: la tabla de locales tiene diez columnas y a
   375 px no caben, pero la página no se mueve de lado. */
.analitica-tabla-caja {
    overflow-x: auto;
    min-width: 0;
    touch-action: pan-x pan-y;
    overscroll-behavior-inline: contain;
}

.analitica-tabla-caja .admin-analitica-tabla th,
.analitica-tabla-caja .admin-analitica-tabla td {
    white-space: nowrap;
}

/* LOS NUMEROS A LA DERECHA, también dentro de estas tablas. `.admin-celda-numero`
   sola (0,1,0) perdía contra `.admin-analitica-tabla td` (0,1,1), que alinea a la
   izquierda: en la primera captura las columnas de importes salían a la izquierda. */
.analitica-contenido .admin-analitica-tabla :is(th, td).admin-celda-numero {
    text-align: right;
}

.analitica-contenido .admin-analitica-tabla th.admin-celda-numero .analitica-orden {
    justify-content: flex-end;
}

/* LA VARIACION EN UNA CELDA usa las fichas de los gráficos, que sólo se definen
   dentro de `.grafico`: fuera de él salía en tinta, sin el
   verde ni el rojo (primera captura de Productos y Cobros). */
.analitica-variacion {
    --grafico-sube: var(--plano-salvia);
    --grafico-baja: var(--plano-arcilla-honda);
    --grafico-texto-2: var(--plano-tinta-2);
    white-space: nowrap;
}

.analitica-orden {
    font-weight: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
}

.analitica-fila-total th,
.analitica-fila-total td {
    font-weight: 700;
    border-bottom: 1.5px solid var(--plano-linea);
}

.analitica-fila-sin-local th,
.analitica-fila-sin-local td {
    color: var(--plano-tinta-2);
}

.analitica-fila-sin-local th {
    font-style: italic;
}

/* El nombre de un local es un botón que filtra el panel por él (§4.1.3). */
.analitica-enlace-local {
    min-height: var(--tentalo-toque);
    padding: 0;
    border: 0;
    border-radius: var(--plano-r-tecla);
    background: none;
    font: inherit;
    color: var(--plano-morado);
    text-align: left;
    cursor: pointer;
}

.analitica-enlace-local:hover {
    text-decoration: underline;
}

.analitica-enlace-cajas {
    margin-left: 0.75rem;
    font-size: var(--plano-t-13);
    font-style: normal;
    color: var(--plano-morado);
}

.analitica-celda-barra {
    width: 6rem;
    min-width: 4rem;
}

/* La barra proporcional de la tabla de locales: morado, sin texto (el número va
   en la celda de al lado). */
.analitica-barra-proporcional {
    display: block;
    height: 0.625rem;
    border-radius: 0 3px 3px 0;
    background: var(--plano-morado);
}

.analitica-celda-mini {
    width: 7.5rem;
}

.analitica-rojo {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-weight: 700;
    color: var(--plano-arcilla-honda);
}

/* El «?» de la regla del rojo: 24 px, el mínimo de WCAG 2.2 para un objetivo
   pequeño dentro de una línea de texto. */
.analitica-ayuda {
    display: inline-grid;
    place-items: center;
    width: 24px;
    height: 24px;
    padding: 0;
    border: 1.5px solid currentColor;
    border-radius: 50%;
    background: none;
    font: inherit;
    font-size: var(--plano-t-12);
    line-height: 1;
    color: inherit;
    cursor: pointer;
}

.analitica-nota {
    margin: 0.75rem 0 0;
    font-size: var(--plano-t-13);
    color: var(--plano-tinta-2);
}

.analitica-oculto {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* --- Los esqueletos (regla 3 de esperas.md: miden lo que va a llegar) ------ */
/*
   Los de los gráficos, las barras y las tablas usan las MISMAS clases que lo que
   imitan (ver EsqueletoDeBloque.razor): aquí sólo va lo que no tiene pareja.
*/
.analitica-esqueleto-cifra {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

/* La columna del esqueleto, con el hueco del cuerpo del panel. */
.analitica-esqueleto {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* El renglón de la frase: 15 px × 1,4, como `.analitica-conclusion`. En el
   teléfono son dos renglones (medido a 375 px: 21 px de salto por bloque con uno). */
.analitica-esqueleto-frase {
    display: flex;
    align-items: center;
    min-height: 2.625rem;
}

/* La etiqueta de una barra mide su renglón de 13 px: a 375 px la fila de verdad
   baja la barra a otro renglón y lo que manda es el texto (medido: 5 px por fila). */
.analitica-esqueleto .grafico-barra-etiqueta {
    display: flex;
    align-items: center;
    min-height: 1.125rem;
}

/* Las celdas miden un renglón de su texto (medido: 22 px el de las filas y 17 px
   el de la cabecera, que va a 12 px). */
.analitica-esqueleto-celda {
    display: flex;
    align-items: center;
    min-height: 1.375rem;
}

.analitica-esqueleto-cabecera {
    display: flex;
    align-items: center;
    min-height: 1.0625rem;
}

/* La fila del Total: el minigráfico (1,75rem) es lo más alto que lleva. */
.analitica-esqueleto-celda--mini {
    min-height: 1.75rem;
}

/* Las filas de locales y sus cabeceras: botones del alto del toque. */
.analitica-esqueleto-celda--toque {
    min-height: var(--tentalo-toque);
}

.analitica-esqueleto-pie {
    align-items: center;
    min-height: var(--tentalo-toque);
}

/* Las siete filas del mapa (1,75rem cada una) con la fila de horas y la rampa. */
.analitica-esqueleto-rejilla {
    height: calc(7 * 1.75rem + 3.5rem);
}

@media (min-width: 768px) {
    .analitica-barra {
        position: sticky;
        top: 48px;
        z-index: 3;
    }

    /* Desde 768 px la frase cabe en un renglón; en el teléfono (el caso base) son dos. */
    .analitica-esqueleto-frase {
        min-height: 1.3125rem;
    }

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

@media (min-width: 1280px) {
    .analitica-cifras {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }

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

/* ========================================================================== */
/*  MIGRAR DESDE LA CENTRAL DEL SISTEMA ANTERIOR (tanda MC1, 2026-09-18)                        */
/* ========================================================================== */
/*
   docs\central\migrador-de-origen-central-2026-09-18.md, decisión M8. Es la
   pantalla `/admin/migrar-desde-origen`: cuatro pasos apilados, el informe y
   dos tablas de sólo lectura.

   TODO LLEVA EL PREFIJO `migrorigen-` y nada de aquí toca a nadie más. Las
   piezas del sistema que ya existen se usan tal cual —`.admin-panel`,
   `.plano-region`, `.admin-tabla`, `.plano-papeles`, `.admin-celda-numero`— y
   lo que hay debajo es sólo lo que esta pantalla añade: la rejilla de los dos
   interruptores, la caja de las direcciones de salida, las insignias de
   estado y la piel de sus dos tablas.

   LOS COLORES SON LAS FICHAS DEL PLANO, sin un solo hexadecimal suelto y sin
   grises nuevos: mostaza es atención, arcilla es error y salvia es al día
   (DESIGN.md). Un cupo que no cabe es arcilla; uno que cabe justo, mostaza.
*/

.migrorigen-interruptores {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1.5rem;
    margin-bottom: 0.25rem;
}

/* La caja de las direcciones que hay que autorizar. Es una región dentro de
   otra: se distingue con la aguada del morado —lo informativo— y no con un
   canto, que dentro de una zona se leería como una tarjeta. */
.migrorigen-ips {
    background-color: var(--plano-morado-aguada);
    padding: 0.75rem 0.9rem;
    margin-bottom: 1rem;
}

.migrorigen-lista-ips {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 0.75rem;
}

.migrorigen-ip {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    background-color: var(--plano-papel-hondo);
    border-radius: var(--plano-radio-zona-corto);
    padding: 0.15rem 0.4rem;
}

/* EL MODO AGENTE (tanda MC4, 2026-09-19). Misma aguada morada que las
   direcciones de salida porque es lo mismo: informativo, y dentro del paso de
   la conexión. Las dos cajas nunca se ven a la vez —o se autoriza el
   cortafuegos o se usa el agente—, así que no compiten. */
.migrorigen-agente {
    background-color: var(--plano-morado-aguada);
    padding: 0.75rem 0.9rem;
    margin-bottom: 1rem;
}

/* La línea de órdenes que hay que ejecutar en la sede. Se puede seleccionar y
   copiar entera, y NO se corta a la derecha: una orden partida por la mitad se
   pega mal. En pantalla estrecha se desplaza ella sola, que es lo que hay que
   hacer con algo que no se puede reflow-ear sin romperlo. */
.migrorigen-orden {
    background-color: var(--plano-papel-hondo);
    border-radius: var(--plano-radio-zona-corto);
    padding: 0.6rem 0.75rem;
    margin: 0 0 0.5rem 0;
    overflow-x: auto;
    font-family: var(--plano-fuente-mono, ui-monospace, Consolas, monospace);
    font-size: var(--plano-t-12);
    line-height: 1.5;
    white-space: pre;
    -webkit-overflow-scrolling: touch;
    /* Toque: una región que se desplaza necesita decirlo, o en una tableta el
       gesto se lo come el contenedor de arriba. */
    touch-action: pan-x pan-y;
    min-height: 0;
}

/* La caja de «Reanudar»: mostaza, porque es atención —hay un trabajo parado
   esperando a que alguien teclee la clave—, no un error. */
.migrorigen-reanudar {
    background-color: var(--plano-mostaza-aguada);
    padding: 0.75rem 0.9rem;
}

.migrorigen-acciones {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
}

.migrorigen-campo-corto {
    max-width: 10rem;
}

/* «OLVIDAR LA CLAVE» (2026-09-20). Va al objetivo ANCHO de 48 px en cualquier
   tamaño y no sólo en móvil, por lo mismo que el activador de las plantillas:
   se toca una vez, no compite con nada por el sitio, y fallar el toque aquí es
   pulsar el campo de al lado y creer que la clave sigue puesta. Sin ancho fijo:
   se estira con la sección y hace salto de línea si hace falta. */
.migrorigen-olvidar .mud-button-root {
    min-height: 48px;
}

/* LA CARPETA `templates` DEL SISTEMA ANTERIOR (2026-09-19). El activador del MudFileUpload es
   un botón y se toca una sola vez en toda la migración, así que va al objetivo
   ANCHO de 48 px en cualquier tamaño y no solo en móvil: aquí no compite con
   nada por el sitio y el precio de fallar el toque es volver a buscar el ZIP. Sin
   ancho fijo: se estira con la sección y hace salto de línea si hace falta. */
.migrorigen-plantillas .mud-button-root {
    min-height: 48px;
}

.migrorigen-plantilla-puesta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    align-items: center;
    margin-top: 0.4rem;
}

.migrorigen-datos {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0 1.5rem;
}

.migrorigen-avisos {
    margin: 0;
    padding-left: 1.2rem;
}

.migrorigen-avisos li {
    margin-bottom: 0.25rem;
}

.migrorigen-insignias {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

/* Las insignias de estado. Mismo trato que `.admin-insignia` del marco —una
   píldora pequeña con su aguada— pero con las fichas del plano en vez de los
   hexadecimales que aquélla arrastra de antes del rediseño. */
.migrorigen-insignia {
    display: inline-block;
    border-radius: var(--plano-pildora);
    padding: 0.1rem 0.55rem;
    font-size: var(--plano-t-12);
    font-weight: 600;
    white-space: nowrap;
}

.migrorigen-insignia-salvia {
    background-color: var(--plano-salvia-aguada-honda);
    color: var(--plano-salvia);
}

.migrorigen-insignia-mostaza {
    background-color: var(--plano-mostaza-aguada);
    color: var(--plano-mostaza-honda);
}

.migrorigen-insignia-arcilla {
    background-color: var(--plano-arcilla-aguada);
    color: var(--plano-arcilla-honda);
}

.migrorigen-insignia-neutra {
    background-color: var(--plano-papel-hondo);
    color: var(--plano-tinta-2);
}

/* Los nulos que el esquema 873 no admite (§14.8 del migrador de la central del sistema anterior): una lista corta
   —diez columnas como mucho— dentro de la alerta que bloquea el botón de empezar. */
.migrorigen-lista-de-nulos {
    margin: 0;
    padding-left: 1.25rem;
    line-height: 1.6;
}

.migrorigen-nulo-destino {
    color: var(--plano-tinta-2);
    font-size: 0.85em;
}

.migrorigen-nombre {
    font-weight: 600;
    color: var(--plano-tinta);
    margin-right: 0.4rem;
}

/* LAS DOS TABLAS son `<table>` de verdad y no `MudTable`, por lo mismo que las
   de la analítica: aquí no hay ni paginación ni ordenación: son dos listas
   cortas de sólo lectura. La piel es la misma que la suya para que se lean
   igual; el envoltorio (`.admin-tabla .plano-papeles`) es el del marco, y es
   lo que las apila en un teléfono leyendo el `data-papel` de cada celda. */
.migrorigen-tabla-caja {
    margin-top: 0.25rem;
}

.migrorigen-tabla {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}

.migrorigen-tabla th,
.migrorigen-tabla td {
    padding: 0.55rem 0.6rem;
    border-bottom: 1px solid var(--plano-linea-fina);
    text-align: left;
    vertical-align: middle;
}

.migrorigen-tabla thead th {
    font-size: var(--plano-t-12);
    font-weight: 600;
    font-stretch: 75%;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--plano-tinta-2);
    border-bottom: 1.5px solid var(--plano-linea);
    white-space: nowrap;
}

.migrorigen-tabla tbody tr:hover {
    background-color: var(--plano-morado-aguada);
}

/* LA CELDA DE «Actualizar desde la central del sistema anterior» (tanda MC2). Es la única celda
   de estas tablas que se PULSA, y por eso NO lleva `data-papel="acciones"`: ese
   papel ancla la celda al carril de 44 px del canto derecho, que está hecho
   para el «⋯» de un listado y no para un botón con seis palabras dentro. Aquí
   la celda es un dato secundario más y en un teléfono baja a su propia línea,
   donde el botón llega al alto de toque y ocupa el ancho entero: una fila alta
   de más se lee; un botón recortado contra el nombre, no. */
.migrorigen-celda-accion {
    white-space: nowrap;
}

/* De 900 px para arriba los datos de una ficha caben en dos columnas, que es
   lo que hace que el análisis y el informe se lean de una ojeada en vez de en
   una tira de veinte renglones. */
@media (min-width: 900px) {
    .migrorigen-datos {
        grid-template-columns: 1fr 1fr;
    }
}

/* EN UN TELÉFONO SE TOCA (docs\central\auditoria-responsiva-2026-09-18.md §6):
   los objetivos se miden hasta 768 px, así que los botones de los cuatro pasos
   llegan al alto de toque y las acciones ocupan la línea entera en vez de
   quedarse en botones estrechos pegados unos a otros. */
@media (max-width: 768px) {
    .migrorigen-acciones .mud-button-root {
        min-height: var(--plano-toque);
    }

    .migrorigen-acciones {
        gap: 0.6rem;
    }

    .migrorigen-campo-corto {
        max-width: none;
    }

    /* La celda de «Actualizar desde la central del sistema anterior», en su propia línea y con el
       objetivo entero. `flex: 1 0 100%` porque a este ancho la fila de la tabla
       es una caja flexible que envuelve (plano.css, la gramática de la etiqueta)
       y una celda que no pide la línea entera se queda apretada al lado de las
       fechas. */
    .migrorigen-celda-accion {
        flex: 1 0 100%;
        margin-block-start: 0.4rem;
        white-space: normal;
    }

    .migrorigen-celda-accion .mud-button-root {
        min-height: var(--plano-toque);
        width: 100%;
    }

    /* LOS DOS BOTONCITOS DE «Hilos de carga», TAMBIÉN A 44 px. Los cazó la
       auditoría responsiva de esta pantalla (desviación 4 del §6.3 del diseño):
       MudBlazor los APILA a 20 × 24 px cada uno, o sea dos objetivos imposibles
       pegados el uno al otro, y eran el único hallazgo de las dos escenas.

       Es el mismo defecto que la tanda 5 cazó en la tabla que se escribe y se
       cura igual (plano.css, «LOS DOS BOTONCITOS DEL CAMPO NUMERICO»): uno AL
       LADO del otro, con el objetivo entero y el hueco de 8 px entre ellos. Aquí
       sobra sitio, porque a este ancho el campo ocupa la línea entera.

       LAS DOS CLASES DE MUDBLAZOR VAN DELANTE Y NO SOBRAN: su propia hoja apila
       los botones y les pone `min-width: unset` con tres clases y un elemento, y
       un selector de dos clases nuestro pierde por especificidad aunque la hoja
       vaya después. Se midió: sin ellas los botones seguían saliendo de 20 px. */
    .mud-input-control.mud-input-number-control.migrorigen-campo-corto .mud-input-numeric-spin {
        flex-direction: row;
        align-items: center;
        gap: 0.5rem;
    }

    .mud-input-control.mud-input-number-control.migrorigen-campo-corto .mud-input-numeric-spin .mud-button-root {
        min-inline-size: var(--plano-toque);
        min-block-size: var(--plano-toque);
    }

    /* Y el campo crece hasta el alto de toque, que es lo que evita que los dos
       botones -44 px dentro de una caja de 40- asomen por arriba y por abajo del
       campo y se coman el renglón de ayuda que va debajo. */
    .migrorigen-campo-corto .mud-input {
        min-block-size: var(--plano-toque);
    }
}

/* ==========================================================================
   «IMPRESIÓN»: EL EDITOR GUIADO DE LOS DOCUMENTOS DE VENTA (tanda T4 del diseño
   único de impresión, docs/tpv/diseno-unico-de-impresion-2026-09-29.md §6.1).

   Arriba el ámbito (general o un local) y la barra (papel, texto/gráfico y las
   acciones); debajo, los AJUSTES a la izquierda y la VISTA PREVIA MÚLTIPLE a la
   derecha. Por debajo de 1100 px los ajustes van encima y los papeles debajo; por
   debajo de 720 px los papeles pasan a pestañas y se ve uno cada vez.

   Los papeles son LIENZO (regla «Lienzos» de DESIGN.md): el ticket va en blanco y
   negro como sale, no en berenjena. Todo lo demás lleva el cromo del plano.
   ========================================================================== */
.impresion-venta {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-width: 0;
}

.impresion-venta-ambito {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px 24px;
    min-width: 0;
}

.impresion-venta-ambito-campo {
    flex: 0 1 22rem;
    min-width: min(100%, 14rem);
}

.impresion-venta-ambito-estado {
    display: flex;
    flex: 1 1 20rem;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 10px;
    min-width: 0;
    font-size: 0.875rem;
    color: var(--tentalo-tinta);
    overflow-wrap: anywhere;
}

.impresion-venta-barra {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    padding-bottom: 2px;
    min-width: 0;
}

.impresion-venta-barra .mud-button-group-root {
    flex-wrap: wrap;
}

.impresion-venta-acciones {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-left: auto;
}

.impresion-venta-sin-guardar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 0;
    font-size: 0.8125rem;
    color: var(--tentalo-tinta-suave);
}

.impresion-venta-cuerpo {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 28px;
    align-items: start;
    min-width: 0;
}

@media (min-width: 1100px) {
    .impresion-venta-cuerpo {
        grid-template-columns: minmax(18rem, 23rem) minmax(0, 1fr);
    }
}

/* ---------------------------------------------------------------- ajustes */
.impresion-venta-ajustes {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.impresion-venta-que {
    margin: 0 0 8px;
    font-size: 0.8125rem;
    color: var(--tentalo-tinta-suave);
    overflow-wrap: anywhere;
}

.impresion-venta-seccion {
    border-top: 1px solid var(--plano-linea-fina);
}

.impresion-venta-seccion:last-child {
    border-bottom: 1px solid var(--plano-linea-fina);
}

.impresion-venta-seccion > summary {
    display: flex;
    align-items: center;
    min-height: 44px;
    cursor: pointer;
    font-weight: 600;
    font-stretch: 75%;
    font-size: 0.75rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--tentalo-tinta-suave);
    list-style: none;
}

.impresion-venta-seccion > summary::-webkit-details-marker {
    display: none;
}

.impresion-venta-seccion > summary::after {
    content: "";
    margin-left: auto;
    width: 0.5rem;
    height: 0.5rem;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(45deg);
    transition: transform var(--plano-tiempo) var(--plano-curva);
}

.impresion-venta-seccion[open] > summary::after {
    transform: rotate(225deg);
}

.impresion-venta-campos,
.impresion-venta-textos {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 4px 0 20px;
    min-width: 0;
}

.impresion-venta-casillas {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.impresion-venta-subrotulo {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--tentalo-tinta);
}

.impresion-venta-ayuda {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--tentalo-tinta-suave);
    max-width: 34ch;
}

.impresion-venta-texto {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--plano-linea-fina);
}

.impresion-venta-legales ul {
    margin: 6px 0 0;
    padding-left: 1.1rem;
    font-size: 0.8125rem;
    color: var(--tentalo-tinta-suave);
}

.impresion-venta-margenes {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* ---------------------------------------------------------- vista previa */
.impresion-venta-previa {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-width: 0;
}

.impresion-venta-papeles {
    display: grid;
    gap: 20px;
    min-width: 0;
}

.impresion-venta-papeles-termico {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr));
}

.impresion-venta-papeles-a4 {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 24rem), 1fr));
}

.impresion-venta-hueco {
    min-width: 0;
}

.impresion-venta-papel {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
}

.impresion-venta-papel-cabecera {
    position: relative;
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 28px;
}

.impresion-venta-papel-nombre {
    font-weight: 600;
    font-size: 0.9375rem;
}

.impresion-venta-papel-espera {
    margin-left: auto;
}

.impresion-venta-papel-grafico {
    box-sizing: border-box;
    padding: 0.75rem;
    border: 1px solid var(--tentalo-borde);
    border-radius: 6px;
    background-color: #fff;
}

.impresion-venta-papel-grafico img {
    display: block;
    width: 100%;
    height: auto;
}

.impresion-venta-papel-pdf {
    display: block;
    width: 100%;
    height: 34rem;
    border: 1px solid var(--tentalo-borde);
    border-radius: 6px;
    background-color: #fff;
}

.impresion-venta-papel-origen {
    margin: 0;
    font-size: 0.75rem;
    color: var(--tentalo-tinta-suave);
    overflow-wrap: anywhere;
}

/* Las pestañas de la previa: solo en un teléfono. */
.impresion-venta-pestanas {
    display: none;
}

@media (max-width: 719.98px) {
    .impresion-venta-acciones {
        margin-left: 0;
    }

    .impresion-venta-pestanas {
        display: flex;
        gap: 6px;
        overflow-x: auto;
        scroll-snap-type: x proximity;
        padding-bottom: 2px;
    }

    .impresion-venta-pestana {
        flex: 0 0 auto;
        min-height: 44px;
        padding: 0 0.9rem;
        border: 1px solid var(--plano-linea);
        border-radius: 8px;
        background: transparent;
        color: var(--tentalo-tinta);
        font: inherit;
        font-size: 0.875rem;
        scroll-snap-align: start;
        cursor: pointer;
    }

    .impresion-venta-pestana-activa {
        background-color: var(--plano-tinta);
        border-color: var(--plano-tinta);
        color: var(--plano-papel);
        font-weight: 640;
    }

    .impresion-venta-hueco {
        display: none;
    }

    .impresion-venta-hueco-activo {
        display: block;
    }

    .impresion-venta-papel-pdf {
        height: 26rem;
    }
}

/* EL CANDADO DE LOS BLOQUES FIJOS del diseño de venta en el avanzado (tanda T4 del
   diseño único, §6.2): delante del resumen de la fila, en tinta rebajada, con el
   nombre del papel. Se mueven y se estilan; el botón de borrar va apagado. */
.impresion-diseno-fila-candado {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 2px;
    padding: 0 6px;
    border-radius: 999px;
    background-color: var(--plano-morado-aguada);
    color: var(--plano-morado);
    font-size: 0.75rem;
    font-weight: 560;
    white-space: nowrap;
}

.impresion-diseno-fila-candado .mud-icon-root {
    font-size: 0.95rem;
}

/* El papel y el modo ELEGIDOS van enclavados (regla «del estado que no depende del relieve»):
   relleno de tinta, texto de papel y peso, además de aria-pressed. */
.impresion-venta-barra .mud-button-group-root .mud-button-root[aria-pressed="true"] {
    background-color: var(--plano-tinta);
    border-color: var(--plano-tinta);
    color: var(--plano-papel);
    font-weight: 640;
}

/* ========================================================================== */
/*  LOS VISTOS BUENOS DEL DIRECTOR (pieza 2 del soporte, 1.0.87)              */
/* ========================================================================== */
/* La franja encima del contenido (FranjaDeVistosBuenos) y la página «Vistos buenos». Lo que no vuelve va en
   aguada de arcilla y con su rótulo, no solo con el color (WCAG 1.4.1). Sin sombras ni bandas laterales de color. */
.franja-vistos-buenos {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    margin: 0 0 16px;
    padding: 10px 14px;
    border-radius: 10px;
    background-color: var(--plano-mostaza-aguada, rgba(233, 180, 76, 0.18));
    color: var(--plano-tinta);
}

.franja-vistos-buenos-icono {
    flex: 0 0 auto;
}

.franja-vistos-buenos-texto {
    flex: 1 1 240px;
    min-width: 0;
    overflow-wrap: anywhere;
}

.franja-vistos-buenos-ver {
    flex: 0 0 auto;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    padding: 0 14px;
    border-radius: var(--plano-radio-control);
    background-color: var(--plano-tinta);
    color: var(--plano-papel);
    font-weight: 600;
    text-decoration: none;
}

.vistos-buenos-seccion {
    margin: 0 0 24px;
}

.vistos-buenos-titulo {
    margin: 0 0 12px;
    font-size: 1.1rem;
    font-weight: 640;
}

.vistos-buenos-vacio {
    color: var(--tentalo-tinta-suave);
}

.visto-bueno {
    margin: 0 0 16px;
    padding: 16px;
    border: 1px solid var(--plano-linea);
    border-radius: 12px;
    background-color: var(--plano-hoja);
    overflow-wrap: anywhere;
}

.visto-bueno-titulo {
    margin: 0 0 6px;
    font-size: 1rem;
    font-weight: 640;
}

.visto-bueno-quien,
.visto-bueno-caduca {
    margin: 0 0 8px;
    color: var(--tentalo-tinta-suave);
    font-size: 0.9rem;
}

.visto-bueno-que-hace,
.visto-bueno-porque {
    margin: 0 0 8px;
}

.visto-bueno-cambios {
    width: 100%;
    margin: 4px 0 12px;
    border-collapse: collapse;
    font-size: 0.9rem;
}

.visto-bueno-cambios th,
.visto-bueno-cambios td {
    padding: 6px 8px;
    border-bottom: 1px solid var(--plano-linea-fina);
    text-align: left;
    vertical-align: top;
}

.visto-bueno-no-vuelve {
    display: flex;
    gap: 8px;
    align-items: flex-start;
    margin: 0 0 12px;
    padding: 10px 12px;
    border-radius: 10px;
    background-color: var(--plano-arcilla-aguada, rgba(217, 96, 74, 0.14));
    color: var(--plano-tinta);
}

.visto-bueno-decidir {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.visto-bueno-entiendo {
    display: flex;
    gap: 8px;
    align-items: flex-start;
    min-height: 44px;
    cursor: pointer;
}

.visto-bueno-entiendo input {
    width: 20px;
    height: 20px;
    margin-top: 2px;
    flex: 0 0 auto;
}

.visto-bueno-botones {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
}

.visto-bueno-motivo {
    flex: 1 1 200px;
    min-width: 0;
    min-height: 44px;
    padding: 0 10px;
    border: 1px solid var(--plano-linea);
    border-radius: 8px;
    background-color: var(--plano-papel);
    color: var(--plano-tinta);
    font: inherit;
}

.visto-bueno-solo-administrador {
    margin: 0;
    color: var(--tentalo-tinta-suave);
    font-style: italic;
}

.vistos-buenos-hechos {
    margin: 0;
    padding: 0;
    list-style: none;
}

.visto-bueno-hecho {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 10px;
    align-items: center;
    padding: 10px 0;
    border-bottom: 1px solid var(--plano-linea-fina);
}

.visto-bueno-hecho-titulo {
    font-weight: 600;
}

.visto-bueno-hecho-detalle {
    flex: 1 1 100%;
    color: var(--tentalo-tinta-suave);
    font-size: 0.9rem;
}

/* ¿SE VERÁ EN LA CAJA? (menús y pases a la tienda, 2026-10-17): el aviso junto a la familia y las categorías de la ficha del
   menú, del producto y del alta (AvisoEnLaCaja.razor). Compacto, como el resto de la central: una franja mostaza con el motivo y
   el botón que lleva a elegir categoría; si se ve en todos, una línea discreta. */
.en-la-caja { margin: 4px 0 8px; font-size: var(--plano-t-13); }
.en-la-caja--aviso {
    display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px;
    padding: 8px 10px; border-radius: var(--plano-esquina-muro, 6px);
    background-color: var(--plano-mostaza-aguada); color: var(--plano-tinta);
}
.en-la-caja__texto { flex: 1 1 16rem; min-inline-size: 0; overflow-wrap: anywhere; }
.en-la-caja__boton { min-block-size: 36px; }
.en-la-caja--bien { color: var(--limpia-tinta-3); overflow-wrap: anywhere; }

/* LOS PERIODOS DE SERVICIO DEL PANEL DE RESERVAS DE LA CAJA (2026-11-06): una fila compacta por periodo en «Reservas en línea» de la
   ficha del local (PeriodosDeServicioDelLocal.razor). Nombre, las dos horas, los siete días como botones de 32 px con una letra y
   quitar; en una pantalla estrecha, dos líneas. Los campos, a la altura de los de los ajustes (40 px con ratón, 44 con el dedo). */
.periodos-servicio { display: flex; flex-direction: column; gap: .35rem; margin-top: .75rem; padding: .5rem .75rem; min-width: 0; }
.periodos-servicio__lista { display: flex; flex-direction: column; gap: .5rem; min-width: 0; }
.periodos-servicio__fila {
    display: grid;
    grid-template-columns: minmax(8rem, 1.4fr) minmax(7rem, 1fr) minmax(7rem, 1fr) auto auto;
    gap: .5rem .75rem;
    align-items: center;
    min-width: 0;
}
.periodos-servicio__fila .campo,
.periodos-servicio__fila .mud-input-control { margin: 0; }
.periodos-servicio__dias { display: flex; gap: 4px; flex-wrap: wrap; }
.periodos-servicio__dia {
    inline-size: 32px;
    block-size: 32px;
    min-inline-size: 32px;
    border-radius: 50%;
    border: 1px solid var(--mud-palette-lines-inputs);
    background: transparent;
    color: var(--mud-palette-text-secondary);
    font: inherit;
    font-size: .8125rem;
    font-weight: 600;
    cursor: pointer;
}
.periodos-servicio__dia--puesto { background: var(--mud-palette-primary); border-color: var(--mud-palette-primary); color: var(--mud-palette-primary-text); }
.periodos-servicio__error { grid-column: 1 / -1; }
.periodos-servicio__acciones { display: flex; gap: .5rem; flex-wrap: wrap; }
.periodos-servicio__minutos { margin-top: .25rem; }

@media (pointer: coarse) {
    .periodos-servicio__dia { inline-size: 44px; block-size: 44px; min-inline-size: 44px; }
}

@media (max-width: 720px) {
    .periodos-servicio__fila { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; }
    .periodos-servicio__nombre { grid-column: 1 / -1; }
    .periodos-servicio__dias { grid-column: 1 / -1; }
    .periodos-servicio__quitar { grid-column: 3; grid-row: 2; }
}

/* LAS CORRECCIONES DE TRADUCCIÓN DEL MASTER (pieza 6 de idiomas, Pages/TraduccionesMaster.razor): los filtros en una fila que se parte en el
   teléfono, la clave en monoespaciada que corta donde haga falta y el editor encima de la tabla. */
.traducciones-filtros { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: flex-start; margin-bottom: 8px; }
.traducciones-filtros .traducciones-idioma { flex: 0 0 110px; }
.traducciones-filtros .traducciones-buscar { flex: 1 1 260px; min-width: 0; }
.traducciones-filtros .traducciones-filtro { flex: 0 1 220px; min-width: 0; }
.traducciones-cuenta, .traducciones-ayuda { font-size: 0.8125rem; color: var(--mud-palette-text-secondary); margin: 4px 0 8px; }
.traducciones-clave, .traducciones-editor-clave code { font-size: 0.75rem; overflow-wrap: anywhere; }
.traducciones-editor-es { margin: 6px 0 10px; white-space: pre-wrap; overflow-wrap: anywhere; }
.traducciones-acciones { display: flex; flex-wrap: wrap; gap: 8px; }
.traducciones-acciones .mud-button-root { min-height: 40px; }
.traducciones-falta { color: var(--mud-palette-text-secondary); }
@media (max-width: 599.98px) {
    .traducciones-filtros .traducciones-idioma, .traducciones-filtros .traducciones-filtro { flex: 1 1 140px; }
}
.traducciones-editor { border: 1px solid var(--mud-palette-lines-default); border-radius: 8px; padding: 12px; margin-bottom: 12px; }
