/* EL PLANO DE SALA — fichas y piel de Mud; el porqué, en
   docs\central\rediseno-plano-de-sala-2026-09-17.md §8. Orden de hojas, y importa:
   MudBlazor.min.css → sala.css → plano.css → app.css; por eso NO hace falta
   `!important` salvo donde Mud escribe el suyo. Los alias `--tentalo-*` no
   viven aquí: los reescribe el `:root` de app.css. */

/* 1. TIPOGRAFIA — Archivo variable, OFL 1.1 © 2020 The Archivo Project
   Authors (licencia en wwwroot\fonts\OFL.txt). Autoalojada, SIN CDN. Ejes
   wght 100-900 y wdth 62%-125%, de rango para que el navegador interpole.
   `font-display: swap`: se lee en la del sistema mientras llega. */

@font-face {
    font-family: "Archivo";
    font-style: normal;
    font-display: swap;
    font-weight: 100 900;
    font-stretch: 62% 125%;
    src: url("../fonts/archivo-latin.woff2") format("woff2-variations");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
        U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191,
        U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: "Archivo";
    font-style: normal;
    font-display: swap;
    font-weight: 100 900;
    font-stretch: 62% 125%;
    src: url("../fonts/archivo-latin-ext.woff2") format("woff2-variations");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
        U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
        U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
        U+A720-A7FF;
}

/* 2. LAS FICHAS — OKLCH con su hex de respaldo delante.

   EL MORADO DEL LOGOTIPO ES EL COLOR DE LA APLICACION (decisión del usuario del
   2026-09-17 por la tarde; PRODUCT.md y §1 del diseño). Cambia EL COLOR y nada
   más: forma, tipografía, marco, portada y patrones son los mismos.

   EL REPARTO: la TINTA berenjena es la única tinta (texto, líneas, muros) y
   sustituye al azul noche; el MORADO es LA ACCION (botón principal, selección,
   foco, taburete ocupado, fila elegida); la SALVIA es SOLO ESTADO —«abierto,
   correcto, al día»— y al dejar de ser la acción recupera su significado, porque
   un verde que está a la vez en «Guardar» y en «Al día» no dice ninguna de las
   dos; MOSTAZA, atención; ARCILLA, error y «sin conexión».

   AA sobre el papel: la tinta da 14,48:1 y el morado 8,30:1 en los dos sentidos.
   Los tonos de referencia no dan como TEXTO —#2f8f83 3,54:1, #d9604a 3,33:1,
   #e9b44c 1,72:1—, así que son línea, canto y aguada, y el texto va en los
   hondos #23726a (5,17:1), #b03826 (5,54:1) y #9c6c12, que tiene que cumplir a
   la vez sobre blanco (4,60:1) y con tinta encima (3,47:1) porque MudBlazor lo
   usa de `Warning`. */

:root {
    /* Papel vegetal con un punto de lila, NUNCA crema: la tinta se lee tinta. */
    --plano-papel: #f5f3f8; --plano-papel: oklch(0.9671 0.0069 304.2);
    --plano-hoja: #fcfbfd; --plano-hoja: oklch(0.9894 0.0028 308.4);
    --plano-papel-hondo: #eae6f0; --plano-papel-hondo: oklch(0.9309 0.0140 304.1);

    /* La UNICA tinta: berenjena. 14,48:1. */
    --plano-tinta: #2a1a3e; --plano-tinta: oklch(0.2579 0.0674 302.5);
    --plano-tinta-2: #5b4a73; --plano-tinta-2: oklch(0.4437 0.0687 302.7);
    /* En canal, para tramas. */
    --plano-linea: rgba(42, 26, 62, 0.18);
    --plano-linea-fina: rgba(42, 26, 62, 0.12);
    --plano-muro: rgba(42, 26, 62, 0.85);

    /* MORADO: la acción, y el color del logotipo. */
    --plano-morado: #672990; --plano-morado: oklch(0.4220 0.1641 308.5);
    /* Para el hover y el pulsado de lo que ya va relleno de morado. */
    --plano-morado-honda: #4f1f70; --plano-morado-honda: oklch(0.3531 0.1353 308.1);
    --plano-morado-aguada: rgba(103, 41, 144, 0.10);
    --plano-morado-aguada-honda: rgba(103, 41, 144, 0.18);

    /* SALVIA: sólo «abierto / correcto / al día». */
    --plano-salvia: #23726a; --plano-salvia: oklch(0.5027 0.0761 185.5);
    --plano-salvia-viva: #2f8f83; --plano-salvia-viva: oklch(0.5915 0.0899 183.4);
    --plano-salvia-aguada: rgba(47, 143, 131, 0.12);
    --plano-salvia-aguada-honda: rgba(47, 143, 131, 0.20);

    --plano-mostaza: #e9b44c; --plano-mostaza: oklch(0.7995 0.1340 81.4);
    --plano-mostaza-honda: #9c6c12; --plano-mostaza-honda: oklch(0.5673 0.1134 76.4);
    --plano-mostaza-aguada: rgba(233, 180, 76, 0.18);

    /* LA MOSTAZA DE UNA SALA, UN PUNTO MAS AMARILLA (tanda 5). La mostaza del
       sistema tiene el matiz en 81, que es ambar: en una aguada floja sobre la
       hoja lila da un MELOCOTON, o sea el mismo tono que daba la arcilla, y una
       sala «cerrando» se leia como una sala con un problema. Esta ficha desplaza
       el matiz a 97 —amarillo de verdad, ya fuera del arco del naranja— y sube un
       punto la claridad, que es lo que hace que la aguada no se apague.
       Se declara APARTE y no se toca `--plano-mostaza` porque esa manda ademas en
       la aguada de zona de Carta, en el `Warning` de MudBlazor y en las insignias
       de atencion, y lo que la revision juzga es el papel de UNA SALA. */
    --plano-mostaza-sala: #f0bd2f; --plano-mostaza-sala: oklch(0.8120 0.1380 97.0);

    --plano-arcilla: #d9604a; --plano-arcilla: oklch(0.6356 0.1569 32.1);
    --plano-arcilla-honda: #b03826; --plano-arcilla-honda: oklch(0.5142 0.1591 31.4);
    --plano-arcilla-aguada: rgba(217, 96, 74, 0.14);

    /* Lavanda azulada: la zona de «Mis tiendas» y la quinta serie de un gráfico. */
    --plano-azul: #6f7fc0; --plano-azul: oklch(0.6109 0.1007 272.6);

    /* La berenjena honda del panel de acceso, y la línea lila que lo dibuja. */
    --plano-berenjena-honda: #1f1230; --plano-berenjena-honda: oklch(0.2169 0.0583 301.7);
    --plano-lila-clara: #cdbfe3; --plano-lila-clara: oklch(0.8276 0.0519 303.0);

    /* (Las ocho aguadas de área, `--plano-zona-*`, y sus «-plana» pintaban la franja
       y la tira del área; sin consumidor desde D2, se retiraron en D6.) */

    --plano-familia: "Archivo", "Segoe UI Variable", "Segoe UI", system-ui,
        -apple-system, "Helvetica Neue", Arial, sans-serif;

    /* Escala fija ~1,2, en rem. Los dos peldaños de arriba —40 y 88— los estrena
       la CIFRA DE CARTEL de la portada (§3): la tanda 1 los había quitado para
       que la hoja cupiera en 40 KB y aquí vuelven, que es su sitio. */
    --plano-t-11: 0.6875rem;
    --plano-t-12: 0.75rem;
    --plano-t-13: 0.8125rem;
    --plano-t-15: 0.9375rem;
    --plano-t-17: 1.0625rem;
    --plano-t-20: 1.25rem;
    --plano-t-28: 1.75rem;
    --plano-t-40: 2.5rem;
    --plano-t-56: 3.5rem;
    --plano-t-64: 4rem;
    --plano-t-72: 4.5rem;
    --plano-t-88: 5.5rem;

    /* EL ALTO DE UNA FILA DEL PLANO (tanda 4). La portada deja de ser una fila de
       piezas de flex y pasa a una rejilla de doce columnas con filas implícitas:
       una sala pesa en ANCHO y en ALTO.

       LA TANDA 5 LA BAJA DE 17 REM A 13. Los 17 salían de empujar el gráfico de
       horas por debajo del pliegue, y el precio lo cazó la revisión de acabado: la
       sala mayor medía 665 × 545 px, su contenido ocupaba los 150 de arriba y en
       medio quedaban 300 px de aguada vacía. Una habitación no se dimensiona por
       lo que hay DEBAJO de ella, se dimensiona por lo que tiene DENTRO. 13 rem
       (208 px) es lo que mide una sala menor llena —rótulo, cifra de 56, línea y
       cota— con su aire; la sala que tiene MESAS crece sola, porque las filas son
       `minmax(--plano-sala-fila, auto)` y la distribución de mesas pide su alto.
       El gráfico vuelve a asomar por el pie del primer pantallazo: está medido y
       anotado en §12, y es el precio de no tener suelo vacío.

       11,5 REM Y NO 13, medido: con 13 la sala mayor daba 416 px y su suelo se
       quedaba en un 29,5 % vacío —dentro del tercio, pero de sobra—. 11,5 (184 px)
       es lo que mide una sala menor LLENA —rótulo, cifra de 56, línea, cota y su
       aire—, así que por debajo de eso la fila no aprieta: crece sola. */
    --plano-sala-fila: 11.5rem;

    /* EL PASO DE LA DISTRIBUCION DE MESAS: el lado de una plaza de comedor. El
       tablero mide 15 px y las sillitas salen 13 px a cada lado, así que 2,2 rem
       (35 px) es lo mínimo que deja dos mesas sin tocarse. */
    --plano-mesa-paso: 2.2rem;

    /* Forma: esquina de muro, no tarjeta */
    --plano-radio-control: 10px;
    --plano-radio-zona: 20px;
    --plano-radio-zona-corto: 6px;
    --plano-esquina-muro: var(--plano-radio-zona) var(--plano-radio-zona-corto)
        var(--plano-radio-zona) var(--plano-radio-zona-corto);
    --plano-pildora: 999px;

    /* Sombra: antes muro y aguada */
    --plano-sombra-alzada: 0 8px 24px -8px rgba(42, 26, 62, 0.25);
    --plano-sombra-hoja: 0 16px 48px -12px rgba(42, 26, 62, 0.32);

    /* Movimiento: de ESTADO; §10 lo vacía */
    --plano-curva: cubic-bezier(0.16, 1, 0.3, 1);
    --plano-tiempo-corto: 150ms;
    --plano-tiempo: 200ms;
    --plano-tiempo-largo: 240ms;
    /* LA BISAGRA DE LA HOJA, el único gesto firmado de la aplicación: 260 ms, un
       punto por encima del resto para que el giro de 14° se lea entero (§9.6). */
    --plano-tiempo-bisagra: 260ms;

    /* Medidas del marco */
    --plano-barra-alto: 64px;
    --plano-barra-hueco: 12px;
    /* EL HUECO DEL CUERPO, que crece con la ventana (§1 de
       `docs/central/fichas-con-pestanas-y-ancho-2026-09-20.md`). Desde que el cajón
       lateral de 240 px se fue, en una pantalla de 1.920 px sobraban 640 px de papel
       vacío a los lados: el cuerpo dejaba 12 px de margen y luego se centraba a
       1.280. Ahora el CONTENEDOR crece con la ventana y lo único que se limita es la
       línea de texto (`--plano-prosa`). El hueco acompaña: 12 px en un móvil, 32 a
       1.280 y 48 a partir de 1.920. Va en `:root` y no dentro de `.plano-cuerpo`
       porque lo leen también piezas que no son hijas del cuerpo (la tira del área,
       que lo compartía, se retiró en D6). */
    --plano-cuerpo-hueco: clamp(12px, 2.5vw, 48px);
    /* EL TOPE DE LA PROSA, escrito una vez (§1). Un párrafo de 1.500 px no se lee:
       el ojo pierde el renglón al volver. Se mide en `ch` —caracteres— porque lo que
       cansa es el número de letras por renglón, no los píxeles. Lo que ya tenía su
       propio `ch` (la ayuda de zona a 34ch, el vacío a 42ch) se queda como está. */
    --plano-prosa: 70ch;
    /* Toque: 44 px, 48 abajo. */
    --plano-toque: 44px;
    --plano-toque-movil: 48px;
    --plano-foco-grosor: 2px;
}

/* 3. LAS TRAMAS — la densidad hace de intensidad */

:root {
    --plano-trama-suave: repeating-linear-gradient(45deg,
        rgba(42, 26, 62, 0.10) 0 1.5px, transparent 1.5px 8px);
    --plano-trama: repeating-linear-gradient(45deg,
        rgba(42, 26, 62, 0.20) 0 1.5px, transparent 1.5px 7px);
    --plano-trama-densa: repeating-linear-gradient(45deg,
        rgba(42, 26, 62, 0.35) 0 2px, transparent 2px 6px);
}

.plano-trama-suave { background-image: var(--plano-trama-suave); }
.plano-trama { background-image: var(--plano-trama); }
.plano-trama-densa { background-image: var(--plano-trama-densa); }

/* 4. LA BASE — el navegador también es del plano */

html {
    /* WebKit, abajo. */
    scrollbar-width: thin;
    scrollbar-color: rgba(42, 26, 62, 0.25) transparent;
}

body {
    background-color: var(--plano-papel);
    color: var(--plano-tinta);
    font-family: var(--plano-familia);
    font-size: var(--plano-t-15);
    font-weight: 420;
    font-stretch: 100%;
    line-height: 1.5;
    /* Archivo trae los pesos. */
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

::selection { background-color: var(--plano-morado-aguada-honda); color: var(--plano-tinta); }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }

::-webkit-scrollbar-thumb {
    background-color: rgba(42, 26, 62, 0.25);
    border-radius: var(--plano-pildora);
    /* Adelgaza el pulgar, no el carril. */
    border: 3px solid transparent;
    background-clip: content-box;
}

::-webkit-scrollbar-thumb:hover { background-color: rgba(42, 26, 62, 0.40); }

input, textarea, select, [contenteditable] { caret-color: var(--plano-morado); }

/* Las tildes no lo tocan. */
a { color: var(--plano-morado); text-underline-offset: 3px; text-decoration-thickness: 1px; }

/* FOCO: 2 px del morado del logotipo, 2 de hueco. */

/* TABULARES EN TODO LO QUE SEA UNA CIFRA, que es lo que hace que una columna de
   importes se lea en diagonal: con las cifras proporcionales, el «1» es la mitad
   de ancho que el «8» y las unidades no caen alineadas. */
table, .mud-table, output, time, .plano-cifra, .plano-cartel, .plano-numero,
.mud-table-cell, .mud-table-pagination { font-variant-numeric: tabular-nums; }

/* 5. TIPOGRAFIA — cuerpo, rótulo y cifra */

.plano-rotulo {
    font-family: var(--plano-familia);
    font-size: var(--plano-t-12);
    font-weight: 600;
    font-stretch: 75%;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--plano-tinta-2);
    line-height: 1.3;
}

.plano-titulo {
    font-size: var(--plano-t-28);
    font-weight: 650;
    font-stretch: 96%;
    letter-spacing: -0.015em;
    line-height: 1.15;
    color: var(--plano-tinta);
    margin: 0;
}

.plano-subtitulo {
    font-size: var(--plano-t-15);
    color: var(--plano-tinta-2);
    margin: 0.25rem 0 0;
    max-width: 62ch;
}

/* UNA CIFRA CON SU UNIDAD NO SE PARTE. «1,40 €» salía en dos líneas en las
   capturas de 390 px de la tanda 1. ES UNA CLASE Y NO UN ESPACIO DURO EN
   `Formato`, porque un `\00a0` arreglaría el euro y dejaría igual «12 de 248
   productos», y además viaja al portapapeles y al Excel. Se cuelga de la PIEL de
   las celdas numéricas: ninguna pantalla tiene que acordarse. */
.plano-cifra { white-space: nowrap; font-variant-numeric: tabular-nums; }

/* LA CIFRA DE CARTEL: la venta del día de una sala de la portada, y lo único de
   toda la web que se pinta a 64 px. `wdth 68` la estrecha para que quepan seis
   cifras con su separador de millar («128.450,75 €») sin bajar de tamaño. */
.plano-cartel {
    font-size: var(--plano-t-64);
    font-weight: 750;
    font-stretch: 68%;
    letter-spacing: -0.03em;
    line-height: 1;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    color: var(--plano-tinta);
}

.plano-secundario { font-size: var(--plano-t-13); color: var(--plano-tinta-2); }

/* 6. LOS MOTIVOS — el arco; los demás, SVG en wwwroot\img\plano\ */

.plano-arco {
    display: inline-block;
    inline-size: 0.75em;
    block-size: 0.75em;
    border-inline-start: 1.5px solid currentColor;
    border-block-end: 1.5px solid currentColor;
    border-end-start-radius: 100%;
    /* Marca, no icono. */
    flex: none;
}

/* `mask-image` y no `<img>` ni SVG copiado: es lo único que tiñe el motivo
   con `currentColor` dejando el dibujo en UN fichero. -webkit- por Safari. */
.plano-motivo {
    display: block;
    background-color: currentColor;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
    flex: none;
}

.plano-motivo-arco {
    -webkit-mask-image: url("../img/plano/arco.svg");
    mask-image: url("../img/plano/arco.svg");
    inline-size: 1.25rem;
    block-size: 1.25rem;
}

.plano-motivo-mesa {
    -webkit-mask-image: url("../img/plano/mesa.svg");
    mask-image: url("../img/plano/mesa.svg");
    inline-size: 1.25rem;
    block-size: 1.25rem;
}

.plano-motivo-cota {
    -webkit-mask-image: url("../img/plano/cota.svg");
    mask-image: url("../img/plano/cota.svg");
    inline-size: 3rem;
    block-size: 1rem;
}

.plano-motivo-sala {
    -webkit-mask-image: url("../img/plano/sala-vacia.svg");
    mask-image: url("../img/plano/sala-vacia.svg");
    inline-size: 10rem;
    block-size: 6.5rem;
}

/* 7. LA PIEL DE MUDBLAZOR — lo que no cabe en el `MudTheme` */

/* 7.1 Botones: píldora */

.mud-button-root {
    border-radius: var(--plano-pildora);
    font-family: var(--plano-familia);
    font-size: var(--plano-t-15);
    font-weight: 560;
    font-stretch: 100%;
    letter-spacing: 0;
    text-transform: none;
    min-height: 40px;
    padding-inline: 1.15rem;
    transition: background-color var(--plano-tiempo) var(--plano-curva),
        color var(--plano-tiempo) var(--plano-curva),
        border-color var(--plano-tiempo) var(--plano-curva),
        transform var(--plano-tiempo-corto) var(--plano-curva);
}

/* (El pulsado ya no es una escala: baja 2 px y pierde su canto. Está en §8.5 bis
   con el resto del relieve, porque ahí es donde se lee entero.) */

.mud-button-filled { box-shadow: none; background-color: var(--plano-morado); color: var(--plano-papel); }

/* Al pasar por encima, el morado se HUNDE en vez de irse a la tinta: un botón
   principal que cambia de familia de color al hover se lee como otro botón. */
.mud-button-filled:hover:not(:disabled) {
    box-shadow: none;
    background-color: var(--plano-morado-honda);
    color: var(--plano-papel);
}

.mud-button-filled-error { background-color: var(--plano-arcilla-honda); }
.mud-button-filled-error:hover:not(:disabled) { background-color: #8e2a1b; }
.mud-button-filled-warning { background-color: var(--plano-mostaza-honda); }
.mud-button-filled-secondary { background-color: var(--plano-tinta); }

.mud-button-outlined {
    border-width: 1.5px;
    border-color: var(--plano-tinta);
    color: var(--plano-tinta);
    background-color: transparent;
}

.mud-button-outlined:hover:not(:disabled) {
    background-color: var(--plano-morado-aguada);
    border-color: var(--plano-morado);
    color: var(--plano-morado);
}

.mud-button-outlined-error { border-color: var(--plano-arcilla-honda); color: var(--plano-arcilla-honda); }

.mud-button-text { color: var(--plano-morado); background-color: transparent; }

.mud-button-text:hover:not(:disabled) {
    background-color: transparent;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.mud-button-text-error { color: var(--plano-arcilla-honda); }

/* DESHABILITADO: TRAMA, NO VELO (tanda 4). La trama y el papel hondo ya dicen
   «esto todavía no se puede pulsar»; lo que hacía el `opacity: 0.65` era rebajar
   ADEMAS el rótulo, y el rótulo hay que poder leerlo —es el que dice qué va a
   pasar cuando se pueda pulsar—. Medido: «Iniciar sesión», que es el estado POR
   OMISION de la pantalla de acceso (los dos campos vacíos), se quedaba en 2,9:1
   sobre su propia trama, por debajo incluso de los 3:1 que pide el texto grande.

   Sin el velo, y con la trama SUAVE (tinta al 10 %) en vez de la normal (al
   20 %) debajo del texto, la tinta rebajada sobre el papel hondo da 6,3:1. El
   botón sigue leyéndose como apagado: no tiene el relleno morado, tiene rayas y
   el cursor no cambia. */
.mud-button-root:disabled,
.mud-button-root.mud-disabled {
    background-image: var(--plano-trama-suave);
    color: var(--plano-tinta-2);
    border-color: var(--plano-linea);
    opacity: 1;
}

.mud-button-filled:disabled, .mud-button-filled.mud-disabled {
    background-color: var(--plano-papel-hondo);
    background-image: var(--plano-trama-suave);
    box-shadow: none;
    color: var(--plano-tinta-2);
}

/* Con el toque entero. */
.mud-icon-button {
    border-radius: var(--plano-pildora);
    color: var(--plano-tinta-2);
    transition: background-color var(--plano-tiempo) var(--plano-curva),
        color var(--plano-tiempo) var(--plano-curva);
}

.mud-icon-button:hover:not(:disabled) {
    background-color: var(--plano-morado-aguada);
    color: var(--plano-morado);
}

/* UN BOTON DE ICONO APAGADO NO SE TRAMA (tanda 4). La trama del botón
   deshabilitado está para que un botón CON ROTULO se lea sin un velo encima; un
   botón de icono no tiene rótulo que proteger, y rayarlo lo convierte en una
   mancha: en la ficha de una factura, las dos flechas de «documento anterior» y
   «siguiente» salían como dos pastillas tachadas que pedían más atención que las
   seis acciones de al lado. Aquí el velo sí es lo que toca. */
.mud-icon-button:disabled,
.mud-icon-button.mud-disabled {
    background-image: none;
    background-color: transparent;
    opacity: 0.45;
}

/* 7.2 Campos rellenos, radio 10 px, sin contorno, subrayado de 2 px al foco.
   LA TANDA 5 CIERRA EL BARRIDO: los 120 campos que seguían declarados
   `Variant.Outlined` —`MudTextField`, `MudNumericField`, `MudSelect`,
   `MudAutocomplete`, `MudDatePicker` y `MudTimePicker`— pasan a `Variant.Filled`
   en el marcado, así que ya no hay dos variantes de campo en el árbol: quedan
   219 `Variant.Outlined` y son BOTONES, avisos, chips y menús, que sí se quieren
   contorneados. Las reglas siguen vistiendo las dos variantes a la vez y no es
   deuda: MudBlazor escribe `mud-input-outlined` también en piezas que no
   declaran variante (los selectores de los propios componentes de fecha), y un
   campo que se colara sin variante seguiría saliendo con la piel del plano. */

.mud-input-control { font-family: var(--plano-familia); }

.mud-input.mud-input-outlined,
.mud-input.mud-input-filled {
    background-color: rgba(42, 26, 62, 0.05);
    border-radius: var(--plano-radio-control);
    color: var(--plano-tinta);
    transition: background-color var(--plano-tiempo) var(--plano-curva),
        box-shadow var(--plano-tiempo) var(--plano-curva);
}

.mud-input.mud-input-outlined:hover,
.mud-input.mud-input-filled:hover { background-color: rgba(42, 26, 62, 0.08); }

/* Fuera el `fieldset` de Outlined. */
.mud-input.mud-input-outlined > .mud-input-outlined-border { border: none; }

/* Por dentro: no mueve la caja. */
.mud-input.mud-input-outlined.mud-focused,
.mud-input.mud-input-filled.mud-focused {
    background-color: rgba(42, 26, 62, 0.05);
    box-shadow: inset 0 -2px 0 0 var(--plano-morado);
}

.mud-input.mud-input-error,
.mud-input.mud-input-error.mud-focused { box-shadow: inset 0 -2px 0 0 var(--plano-arcilla-honda); }

/* La barra animada de Filled sobra. */
.mud-input.mud-input-filled::before,
.mud-input.mud-input-filled::after,
.mud-input-underline::before,
.mud-input-underline::after { border-bottom: none; }

.mud-input-control .mud-input-label {
    color: var(--plano-tinta-2);
    font-family: var(--plano-familia);
    font-size: var(--plano-t-13);
}

.mud-input-label.mud-input-label-shrink { color: var(--plano-tinta-2); }

.mud-input-helper-text { color: var(--plano-tinta-2); font-size: var(--plano-t-12); }
.mud-input-helper-text.mud-input-error { color: var(--plano-arcilla-honda); }

.mud-input-control .mud-input-slot,
.mud-input-control input,
.mud-input-control textarea {
    color: var(--plano-tinta);
    font-family: var(--plano-familia);
    font-size: var(--plano-t-15);
}

/* Casillas, radios, interruptores. */
.mud-checkbox .mud-icon-root,
.mud-radio .mud-icon-root { color: var(--plano-tinta-2); }

.mud-checkbox .mud-checked .mud-icon-root,
.mud-radio .mud-checked .mud-icon-root,
.mud-switch .mud-checked .mud-switch-thumb { color: var(--plano-morado); }

.mud-switch .mud-switch-track { background-color: var(--plano-tinta-2); }
.mud-switch .mud-checked + .mud-switch-track { background-color: var(--plano-morado); }

/* LA BOLITA DEL INTERRUPTOR NO SE ELEVA. Era la última sombra de Material que
   quedaba en la web -la encontró el detector de tarjetas de la tanda 3- y aquí
   la profundidad se dibuja con muro y aguada, no con `box-shadow` (§1). Se
   sustituye por un canto de tinta fina, que además la separa del carril cuando
   está apagada y el carril va en tinta. */
.mud-switch .mud-switch-thumb,
.mud-switch .mud-switch-thumb-medium {
    box-shadow: none;
    border: 1px solid var(--plano-linea);
}

/* LA LISTA DE UN CAMPO DE RELACION, SIN CAJA (tanda 5, punto 2c): dentro de una
   zona, un rectángulo con canto se lee como una tarjeta metida en otra. Lo que
   le da principio y fin pasan a ser sus reglas, en la tinta al 12 % de un
   listado (§4).

   Y se escriben AQUI Y SOLO AQUI: el canto y el radio que `app.css` le ponía
   desde antes del rediseño están borrados, no anulados. Anular un canto desde la
   otra hoja obligaba a ganar la especificidad con un `ul` delante, y dos reglas
   peleándose por el mismo borde es justo lo que hace que nadie sepa cuál manda. */
.campo-lista__filas > .campo-lista__fila:not(:last-child) {
    border-block-end: 1px solid var(--plano-linea-fina);
}

.campo-lista__filas > .campo-lista__fila:first-child {
    border-block-start: 1px solid var(--plano-linea-fina);
}

/* La lista alta se desplaza por dentro, y sin caja el corte hay que decirlo. */
.campo-lista__filas--alta > .campo-lista__fila:last-child {
    border-block-end: 1px solid var(--plano-linea-fina);
}

/* 7.3 Tablas: sin tarjeta */

.mud-table {
    background-color: transparent;
    box-shadow: none;
    border: none;
    border-radius: 0;
    font-family: var(--plano-familia);
}

.mud-table.mud-table-outlined { border: none; }

.mud-table-root { border-collapse: collapse; }

.mud-table-root .mud-table-head .mud-table-cell {
    font-size: var(--plano-t-12);
    font-weight: 600;
    font-stretch: 75%;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--plano-tinta-2);
    background-color: transparent;
    border-bottom: 1.5px solid var(--plano-linea);
    padding-block: 0.6rem;
}

.mud-table-root .mud-table-body .mud-table-cell {
    border-bottom: 1px solid var(--plano-linea-fina);
    color: var(--plano-tinta);
    font-size: var(--plano-t-15);
    padding-block: 0.7rem;
}

/* Sin cebra: compite con la elegida. */
.mud-table-row.mud-table-row-stripe,
.mud-table-striped .mud-table-row:nth-of-type(odd) { background-color: transparent; }

.mud-table-hover .mud-table-row:hover,
.mud-table-row-clickable:hover { background-color: var(--plano-morado-aguada); }

.mud-table-row.mud-selected-row,
.mud-table-row[aria-selected="true"] { background-color: var(--plano-morado-aguada-honda); }

.mud-table-foot .mud-table-cell { border-bottom: none; border-top: 1.5px solid var(--plano-linea); }

/* Discreta y en texto. */
.mud-table-pagination { border-top: none; color: var(--plano-tinta-2); font-size: var(--plano-t-13); }

.mud-table-toolbar { padding-inline: 0; }

/* LA BARRA DE DENTRO DE UNA TABLA CRECE CON SU CONTENIDO (§14, 2026-09-18).
   MudBlazor le fija 64 px de alto, y las dos tablas del master que llevan su
   buscador dentro —Instalaciones y Usuarios de la central— le añadieron una línea
   de ayuda debajo del campo («Por código, nombre, CIF o correo.»): a 64 px fijos
   esa línea se pintaba POR ENCIMA de la cabecera de la tabla. El mínimo se queda
   donde estaba, así que una barra sin ayuda no se mueve ni un píxel. */
.plano-papeles .mud-table-toolbar {
    block-size: auto;
    min-block-size: var(--plano-barra-alto);
    padding-block: 0.5rem;
}

/* TODA CELDA NUMERICA HEREDA `.plano-cifra`: la cifra con su unidad no se parte.
   Se escribe AQUI, en la piel, y no en las 47 definiciones de lista. */
.crud-celda-numero,
.admin-celda-numero,
.mud-table-cell-align-right {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* 7.3 bis LA FILA DE UN LISTADO EN UN MOVIL: LA GRAMATICA DE ETIQUETA
   ===================================================================
   Una tabla no cabe en 390 px. El modo apilado de MudBlazor (`Breakpoint.Sm`)
   pinta CADA celda como un renglón de «nombre de la columna, valor»: veinte
   renglones por producto, con «Familia» repetida veinte veces. Eso no es una
   lista, es un formulario de sólo lectura.

   Aquí la fila pasa a DOS LINEAS (la gramática de etiqueta de §4): arriba el
   nombre en peso 600 y UNA cifra a su derecha; abajo hasta tres datos
   secundarios en tinta rebajada, unidos con « · ». Sin cabecera y sin repetir un
   solo rótulo. El corte son 720 px y no los 600 de MudBlazor: entre 600 y 720 la
   tabla ya no cabe y todavía se pinta como tabla.

   POR QUE LA FILA ES `block` Y NO `grid`: con `grid` cada `<td>` se blockifica,
   así que las celdas secundarias caerían en un renglón CADA UNA y no se podrían
   juntar en una línea con sus puntos. Siendo la fila un bloque se quedan
   `inline` y fluyen seguidas; la cifra y las acciones se anclan a la derecha con
   `position: absolute` sobre el hueco del `padding-inline-end`.

   EL PAPEL DE CADA CELDA LO DICE LA TABLA (2026-09-18), NO LO ADIVINA LA HOJA
   ==========================================================================
   Hasta el 2026-09-18 esto lo decidía la hoja sola: la PRIMERA celda era el
   nombre, la que llevara `crud-celda-numero` era la cifra y las demás bajaban a
   la segunda línea. Con las cuatro columnas del banco salía bien. Con la lista
   de PRODUCTOS de verdad —diez columnas fijas más tres por cada lista de
   precios: veinte en la instalación del usuario— salía mal de tres maneras a la
   vez, y así llegó en una captura hecha en un iPhone:

     1. cada producto ocupaba MAS DE UNA PANTALLA, porque las veinte columnas
        bajaban a la fila, incluidas las vacías, que dejaban su rótulo sin valor;
     2. las NUEVE columnas de precio son las nueve `crud-celda-numero`, así que
        las nueve se anclaban al MISMO hueco de la derecha y se pintaban unas
        encima de otras: nueve «0,00 €» superpuestos sobre los rótulos;
     3. la casilla de selección, el duplicado y la papelera flotaban sueltos
        encima del nombre y se llevaban el primer toque de la fila, que es el que
        tiene que abrir la ficha.

   La salida no es adivinar mejor: es que la TABLA DIGA el papel de cada celda.
   `Services\Crud\PapelesDeColumna.cs` lo reparte en C# —donde se sabe cuántas
   columnas hay y cuáles traen valor— y lo escribe en `data-papel`:

     · `principal`  el nombre: primera línea, peso 600, tinta;
     · `cifra`      UNA sola, anclada a la derecha de la primera línea;
     · `secundaria` hasta tres, en la segunda línea y unidas con « · »;
     · `escritorio` no se pinta: está en la ficha, a un toque;
     · `acciones`   el menú «⋯» de 44 px al final de la fila;
     · `seleccion`  la casilla, que sólo sale en modo «Seleccionar».

   Y `data-vacia` marca la celda que no trae texto. Se decide en C# y no con
   `:empty`, que es frágil: una celda con un espacio, con un enlace o con un
   icono no está vacía para el selector, y una celda vacía dejaba colgando su
   punto de separación.

   LAS TRES FAMILIAS DE TABLA DE LA CENTRAL lo llevan —el marco CRUD, el diario
   de documentos y los listados de la analítica—, y por eso los selectores van
   por ETIQUETA (`tbody > tr > td`) y no por las clases de MudBlazor: las dos
   primeras son `MudTable` y la tercera es un `<table>` a pelo. Una fila de la
   central se lee igual venga de donde venga.

   LAS QUE NO LOS DECLARAN SIGUEN ATENDIDAS, con la regla de antes escrita en
   cuatro líneas (`:not([data-papel])`): la primera celda es el nombre y la
   numérica es la cifra. Son las treinta y pico tablas escritas a mano dentro de
   una ficha, que tienen tres o cuatro columnas y con las que esa regla acierta.

   CON UNA EXCEPCION, Y SE DECIDE SOLA: una tabla que se ESCRIBE —líneas de un
   albarán, grupos de platos de un menú, precios por tarifa— tiene campos dentro
   de las celdas, y apilar la fila en una línea de texto dejaría los campos en
   fila india. `:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))` las deja fuera:
   las viste la gramática de FORMULARIO del final de este bloque. La casilla de
   selección NO cuenta como campo (MudBlazor la pinta como `.mud-checkbox`), así
   que una lista con selección múltiple sí se apila. */

@media (max-width: 719.98px) {
    /* --- 1. LA TABLA SE DESHACE ------------------------------------------ */
    /* Sin columnas no hay nada que encabezar; y con la cabecera se va la fila de
       filtros por columna del diario, que son hasta treinta campos en fila. */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) thead { display: none; }

    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) :is(table, tbody, tfoot) {
        display: block;
        inline-size: 100%;
    }

    /* NINGUN CARRIL POR ENCIMA DE UNA FILA APILADA: un contenedor que se
       desplaza sólo puede RECORTAR lo que ya cabe. Son tres capas, y dos las
       escribe MudBlazor EN LINEA (el alto fijo y el `overflow` de `FixedHeader`
       del diario de documentos). A un atributo `style` no le gana ningún
       selector: es de los sitios donde el §6 admite `!important`. */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))),
    .informe-rejilla:has(.plano-papeles) { overflow: visible; }

    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) .mud-table-container {
        overflow: visible !important;
        max-block-size: none !important;
        block-size: auto !important;
    }

    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) table {
        overflow-x: visible !important;
    }

    /* --- 2. LA FILA ------------------------------------------------------- */
    /* EL CARRIL DE LA DERECHA se reserva SOLO si hay algo que poner en él: un
       listado de la analítica no tiene ni cifra anclada ni acciones, y con el
       carril fijo dejaba 132 px en blanco en cada una de sus cien filas. */
    /* LA FILA ORDENA POR PAPEL Y NO POR COLUMNA, y por eso es `flex` y no `block`.
       El orden de las columnas es el del ESCRITORIO y no tiene por qué empezar
       por el nombre: los tres diarios de documentos empiezan por «Jornada», así
       que la fila de una factura salía con «17/09/2026» en un renglón y
       «A-000400» debajo. Con `order`, el nombre abre la fila siempre, venga en la
       columna que venga, y lo secundario va detrás en el orden de la tabla.

       `column-gap` en vez de espacios dentro del « · »: en una caja de línea, el
       espacio de delante de un `::before` que abre línea se descarta, y el punto
       se pegaba a la palabra. */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr {
        display: flex;
        flex-wrap: wrap;
        align-items: baseline;
        column-gap: 0.3rem;
        position: relative;
        --plano-carril-acciones: 0px;
        --plano-carril-cifra: 0px;
        padding: 0.5rem calc(var(--plano-carril-acciones) + var(--plano-carril-cifra) + 0.15rem) 0.5rem 0.15rem;
        min-block-size: var(--plano-toque-movil);
        border-block-end: 1px solid var(--plano-linea-fina);
    }

    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr:has(:is([data-papel="acciones"], .crud-celda-acciones)) {
        --plano-carril-acciones: calc(var(--plano-toque) + 0.35rem);
    }

    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr:has(:is([data-papel="cifra"]:not([data-vacia]), td:not([data-papel]):is(.crud-celda-numero, .admin-celda-numero))) {
        --plano-carril-cifra: 5.5rem;
    }

    /* La fila con el menú «⋯» abierto ya NO se sube por encima de las demás ni del velo (2026-10-15): el menú está en la capa
       superior, y una fila subida no dejaba cerrarlo tocando en ella fuera del menú (el toque abría la ficha). */

    /* --- 3. LA CELDA ------------------------------------------------------ */
    /* La base: en línea, fina y en tinta rebajada, que es la segunda línea de la
       etiqueta. Los papeles de abajo la pisan. Y sin el `::before` con el que
       MudBlazor rotula cada celda: aquí no hay columnas que rotular. */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > :is(td, th) {
        display: inline;
        border: none;
        padding: 0;
        font-size: var(--plano-t-13);
        font-weight: 420;
        color: var(--plano-tinta-2);
        white-space: normal;
        text-align: start;
    }

    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) :is(tbody, tfoot) > tr > :is(td, th)::before { content: none; }

    /* EL NOMBRE. Con papeles, el que lo diga; sin ellos, la primera celda que no
       sea la casilla, que es el nombre en todas las tablas escritas a mano. */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > [data-papel="principal"],
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > td:not([data-papel]):first-of-type:not(:has(.mud-table-cell-checkbox)),
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > td:has(.mud-table-cell-checkbox) + td:not([data-papel]) {
        display: block;
        /* La primera línea entera, y la PRIMERA venga donde venga su columna. */
        order: 1;
        flex: 1 0 100%;
        font-size: var(--plano-t-15);
        font-weight: 600;
        color: var(--plano-tinta);
    }

    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > [data-papel="secundaria"],
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > td:not([data-papel]) { order: 2; }

    /* LA FILA ENTERA LLEVA A LA FICHA, y no sólo el nombre. El enlace deja de
       pintarse de enlace —la fila es el objetivo, no una palabra dentro de ella—
       y ESTIRA su área de toque sobre la fila con un `::after` que la cubre: son
       los 48 px de alto y los 390 de ancho que pide el §4 para un móvil, en vez
       de los 104 × 16 que mide «Café con leche».
       La fila es `position: relative`, así que el `::after` se ancla a ella. Y no
       tapa las acciones: la celda del «⋯» va DESPUES en el marcado y también está
       posicionada, así que se pinta por encima.

       `position: static`, Y NO ES UN ADORNO: es lo que hace que el `::after` se
       ancle A LA FILA (avería del 2026-09-18 por la noche, el usuario tocando la
       lista de Instalaciones en su iPhone). El truco funcionaba con un `<a>` y no
       con un `<button>` por una sola razón: MudBlazor.min.css le da `position:
       relative` a TODO `button` en su reajuste, con el elemento a pelo como
       selector, así que cada botón de la central es su propio bloque contenedor
       —no hace falta que nadie lo pida— y el `inset: 0` de su pseudo-elemento
       le devolvía SU caja —154 × 23 px, el código y el nombre— en vez de los
       374 × 79 de la fila. La fila se teñía (eso lo pinta `Hover` de MudTable, que
       no necesita el toque) y el clic caía en el texto de la segunda línea, que no
       lleva a ninguna parte. No era cosa de WebKit: medido con el banco, pasaba
       igual en Chromium.

       Va en la regla COMUN y no en `.instalaciones-abrir` porque lo que falla es
       la técnica con un botón, no esa pantalla: cualquier fila que mañana abra con
       un `<button>` nacería con la misma avería. Para un `<a>` no cambia nada: ya
       era estático. */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > [data-papel="principal"] :is(a, .mud-link, .crud-principal) {
        position: static;
        color: inherit;
        font-weight: inherit;
        text-decoration: none;
    }

    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > [data-papel="principal"] :is(a, .mud-link, .crud-principal)::after {
        content: "";
        position: absolute;
        inset: 0;
    }

    /* Y EL ENLACE DE UN DATO SECUNDARIO DEJA DE SERLO EN UN MOVIL. La familia de
       un producto lleva a su ficha, y eso en un escritorio está bien; dentro de
       una fila que entera abre otra cosa, es un objetivo de 54 × 14 px escondido
       debajo del grande. En el teléfono se lee como lo que es —un dato— y la
       familia se abre desde su propia pantalla. */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > [data-papel="secundaria"] :is(a, .mud-link) {
        pointer-events: none;
        color: inherit;
        text-decoration: none;
    }

    /* EL PUNTO QUE UNE los datos secundarios. Con papeles lo pone C# celda a
       celda (`data-separador`) y no la hoja, porque cuál es el PRIMER dato de la
       segunda línea depende de cuáles vengan vacías en ESTA fila —un producto sin
       familia empieza por el IVA— y «el primer hermano visible» no existe como
       selector. Sin papeles se pone a partir de la tercera celda, que es lo que
       hacía antes, y se le quita a las que no están en esa línea. */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > [data-papel="secundaria"][data-separador]::before,
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > td:not([data-papel]):nth-of-type(n+3)::before {
        content: "·";
        margin-inline-end: 0.3rem;
        color: var(--plano-tinta-2);
    }

    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > td:not([data-papel]):is(.crud-celda-numero, .admin-celda-numero, .crud-celda-acciones, .mud-table-cell-checkbox)::before { content: none; }

    /* Y UNA CELDA VACIA NO SE LLEVA EL PUNTO POR DELANTE. En una tabla con
       papeles lo dice `data-vacia`, que se decide en C#; en una sin ellos no hay
       quien lo diga, así que aquí sí vale `:empty` —una celda de sólo texto o no
       tiene nada, o tiene texto— y es lo que quita el «· ·» que dejaban las notas
       en blanco del listado de versiones, cuya celda no está vacía del todo: trae
       un `<span>` vacío, que es lo que pinta un `MudText` sin texto. Por eso hay
       que preguntar las dos cosas: la celda sin nada y la celda cuyo único hijo
       no tiene nada. Es lo que se puede hacer sin saber qué hay dentro; la
       respuesta buena es declarar los papeles, y entonces lo dice `data-vacia`. */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > td:not([data-papel]):empty,
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > td:not([data-papel]):has(> :only-child:empty) { display: none; }

    /* LA CIFRA, a la derecha de la primera línea y a la altura del «⋯». */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > [data-papel="cifra"],
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > td:not([data-papel]):is(.crud-celda-numero, .admin-celda-numero) {
        position: absolute;
        inset-block-start: 0.25rem;
        inset-inline-end: var(--plano-carril-acciones);
        max-inline-size: 5.5rem;
        min-block-size: var(--plano-toque);
        display: flex;
        align-items: center;
        justify-content: flex-end;
        text-align: end;
        white-space: nowrap;
        font-size: var(--plano-t-15);
        font-weight: 600;
        color: var(--plano-tinta);
        font-variant-numeric: tabular-nums;
    }

    /* UNA SOLA CIFRA, TAMBIEN SIN PAPELES (auditoría responsiva, 2026-09-18). La
       regla de arriba ancla al hueco de la derecha TODA celda numérica, y una
       tabla escrita a mano con tres —el listado de versiones tiene la versión de
       base de datos, el tamaño y las instalaciones— las apilaba una encima de
       otra: el mismo defecto que trajo la captura del usuario, con otro origen.
       Se queda la PRIMERA; las demás bajan a la segunda línea como un dato más,
       que es lo que son. `~` es exactamente «las que vienen después de otra». */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr >
        td:is(.crud-celda-numero, .admin-celda-numero) ~ td:not([data-papel]):is(.crud-celda-numero, .admin-celda-numero) {
        position: static;
        display: inline;
        max-inline-size: none;
        min-block-size: 0;
        font-size: var(--plano-t-13);
        font-weight: 420;
        color: var(--plano-tinta-2);
        text-align: start;
    }

    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr >
        td:is(.crud-celda-numero, .admin-celda-numero) ~ td:not([data-papel]):is(.crud-celda-numero, .admin-celda-numero)::before {
        content: " · ";
        color: var(--plano-tinta-2);
    }

    /* POR ENCIMA DEL ENLACE QUE CUBRE LA TARJETA (z-index 1; 2026-10-15). El `::after` del nombre (arriba) se estira sobre
       toda la fila y, en las tarjetas con miniatura (productos, medios de pago), Chromium lo pintaba ENCIMA del «⋯»: tocar
       el «⋯» abría la ficha en vez del menú (medido en las capturas de reports/central/menu-de-fila-2026-10-15). */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > [data-papel="acciones"],
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > td:not([data-papel]).crud-celda-acciones {
        position: absolute;
        inset-block-start: 0.25rem;
        inset-inline-end: 0;
        z-index: 1;
        display: block;
        white-space: nowrap;
    }

    /* 44 px DE OBJETIVO, no los 30 que MudBlazor le da a un icono pequeño. */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > :is([data-papel="acciones"], .crud-celda-acciones) .mud-icon-button {
        min-inline-size: var(--plano-toque);
        min-block-size: var(--plano-toque);
    }

    /* EL NOMBRE NO NECESITA SU PROPIO OBJETIVO DE 44 px cuando la fila entera es
       el objetivo: §8.7 se lo da a todo `.crud-principal` y, con la fila a dos
       líneas, esos 44 px se sumaban a la segunda y dejaban la fila en 80 px.
       Aquí la fila ya mide 48 de mínimo y es ella la que se toca. */
    .plano-papeles .mud-table-body .crud-principal,
    .plano-papeles .mud-table-body .mud-table-cell > .mud-link {
        display: inline;
        min-block-size: 0;
        padding-block: 0;
        margin-block: 0;
    }

    /* LA CASILLA DE SELECCION, SOLO EN MODO «Seleccionar» (y sólo en las tablas
       que tienen ese modo, que son las que declaran papeles). Con la fila a dos
       líneas se quedaba flotando sobre el nombre y robaba el primer toque. */
    /* La CELDA no lleva ninguna clase que la distinga —MudBlazor pinta un `<td
       class="mud-table-cell">` como los demás— así que se pregunta por lo que
       tiene DENTRO, que es su casilla. */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))):not(.plano-seleccionando) tbody > tr > td:has(.mud-table-cell-checkbox),
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))):not(.plano-seleccionando) tbody > tr > td[data-papel="seleccion"] { display: none; }

    /* LO QUE NO SE PINTA, Y VA DESPUES DE LOS PAPELES para ganarles: lo de
       escritorio y lo que viene vacío. La celda entera desaparece, así que no
       deja ni rótulo sin valor ni punto colgando. */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > [data-papel="escritorio"],
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tbody > tr > [data-vacia] { display: none; }

    /* --- 4. EL PIE, EN UNA LINEA ------------------------------------------ */
    /* Un pie es un rótulo y un total: eso es lo que se pinta, y las celdas que no
       traen nada desaparecen en vez de llevarse su punto. */
    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tfoot > tr {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: 0.5rem;
        padding: 0.7rem 0.15rem;
    }

    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tfoot > tr > :is(td, th) {
        display: block;
        border: none;
        padding: 0;
        white-space: nowrap;
    }

    :is(.plano-papeles, .admin-tabla:not(:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)))) tfoot > tr > :is(td, th):empty { display: none; }

    /* --- 5. EL MENU «⋯» DE UNA FILA --------------------------------------- */
    /* Abierto es una hoja alzada pegada al canto derecho de la fila. Los botones
       de dentro son LOS MISMOS que en un escritorio (ver `CrudLista.razor`): lo
       único que cambia es esta hoja. */
    .plano-papeles .crud-acciones-menu {
        display: block;
        position: relative;
    }

    .plano-papeles .crud-acciones-tirador {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        inline-size: var(--plano-toque);
        block-size: var(--plano-toque);
        padding: 0;
        border: none;
        border-radius: 50%;
        background: none;
        color: var(--plano-tinta-2);
        cursor: pointer;
    }

    .plano-papeles .crud-acciones-menu-abierto .crud-acciones-tirador {
        background-color: var(--plano-morado-aguada);
        color: var(--plano-morado);
    }

    /* Abierto NO se coloca aquí (2026-10-15): el panel sale de la tarjeta a la capa superior y lo pone junto al «⋯»
       crud.js (colocarMenuDeFila); su aspecto es el de hoja-limpia.css, el mismo en los dos anchos. */
    .plano-papeles .crud-acciones-panel { display: none; }

    /* --- LAS TABLAS QUE SE ESCRIBEN TAMBIEN SE APILAN (tanda 4) -------------
       La tanda 3 las dejó fuera con `:not(:has(… .mud-input-control))` y su
       motivo era bueno —apilar una fila con campos dentro en una línea de texto
       deja los campos en fila india—, pero la salida que eligió fue peor: seis
       tablas (líneas de albarán y de pedido, unidades adicionales, grupos de
       platos de un menú, precios por tarifa, teclas de balanza y la consulta de
       stock) se quedaban con desplazamiento horizontal, o sea ilegibles en un
       teléfono.

       La gramática que les toca no es la de etiqueta sino la de FORMULARIO: cada
       fila es un bloque, cada campo va en su renglón CON SU ROTULO delante —aquí
       el rótulo sí hace falta: un campo sin nombre no se puede rellenar— y las
       acciones al pie, a lo ancho. El rótulo sale de `data-label`, que es lo que
       MudBlazor ya escribe en cada celda; la celda que no lo traiga no pinta
       ninguno en vez de pintar un hueco.

       LA CASILLA DE SELECCION NO ES UN CAMPO, Y ESTE ERA EL DEFECTO QUE TRAJO LA
       CAPTURA DEL 2026-09-18. La tanda 3 lo dio por hecho con todas las letras
       —«MudBlazor la pinta como `.mud-checkbox`, así que una lista con selección
       múltiple sí se apila»— y era FALSO: la casilla de `MudTable` sale envuelta
       en `<div class="mud-input-control mud-input-control-boolean-input
       mud-table-cell-checkbox">`, o sea que trae un `.mud-input-control` dentro
       del `<tbody>` como cualquier campo.

       El efecto, medido en el banco responsivo: las VEINTIOCHO listas del
       administrador con selección múltiple —productos, categorías, familias,
       menús, listas de precios, ofertas, cajas, empleados…— NUNCA entraron en la
       gramática de etiqueta. Entraban en ésta, la de formulario, y por eso en un
       teléfono cada producto salía como una pila de bloques rotulados «FAMILIA»,
       «CATEGORÍAS», «PLU», «CÓDIGO DE BARRAS», «IVA», «ELABORACIÓN», «PASE»…
       —incluidos los vacíos, con su rótulo y sin valor— y ocupaba más de una
       pantalla. Las que sí se apilaban bien eran justo las que no tienen
       selección múltiple (establecimientos, clientes, formatos de impresión), y
       por eso nadie lo vio: el banco enseñaba una de ésas.

       `:not(.mud-input-control-boolean-input)` es la pregunta exacta —¿hay algún
       campo que NO sea una casilla ni un interruptor?— y la clase la escribe el
       propio MudBlazor. Una tabla que se escriba de verdad sigue entrando aquí. */
    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)) .mud-table-head { display: none; }

    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)) :is(.mud-table-root, .mud-table-body) {
        display: block;
        inline-size: 100%;
    }

    /* Y EL CARRIL HORIZONTAL SE APAGA (tanda 5). Apilada la tabla cabe, y un
       contenedor que se desplaza sólo puede RECORTAR lo que asome. Son dos
       capas: `.admin-tabla`, con su `overflow-x: auto` anterior al rediseño, y
       el `overflow-x` que MudBlazor escribe EN LINEA con `HorizontalScrollbar`
       (líneas de albarán, de pedido, stock). A un atributo `style` no le gana
       ningún selector: es de los sitios donde el §6 admite `!important`. */
    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)) { overflow: visible; }

    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)) .mud-table-root {
        overflow-x: visible !important;
    }

    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)) .mud-table-body .mud-table-row {
        display: block;
        padding: 0.9rem 0.15rem 0.6rem;
        border-block-end: 1px solid var(--plano-linea-fina);
    }

    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)) .mud-table-body .mud-table-cell {
        display: block;
        border: none;
        padding: 0 0 0.75rem;
        white-space: normal;
    }

    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)) .mud-table-body .mud-table-cell[data-label]::before {
        content: attr(data-label);
        display: block;
        margin-block-end: 0.2rem;
        font-size: var(--plano-t-12);
        font-weight: 600;
        font-stretch: 75%;
        letter-spacing: 0.04em;
        text-transform: uppercase;
        color: var(--plano-tinta-2);
    }

    /* UN CAMPO, UN NOMBRE (tanda 6, §13). El rótulo de arriba sale de `data-label`, que es el
       nombre de la COLUMNA, y el campo que hay debajo trae muchas veces el SUYO —la etiqueta
       flotante de MudBlazor—: apilada, la fila decía «CATEGORÍA DE LOS PLATOS» y, tres píxeles
       más abajo, «Categoría». Dos nombres para el mismo hueco no son dos ayudas: son un renglón
       de más por campo, y cuatro campos por fila hacían 42 px de los 529 que medía cada grupo de
       platos en un teléfono.

       SE QUITA EL DE LA COLUMNA Y NO EL DEL CAMPO, y no es indiferente: la etiqueta del campo es
       un `<label>` de verdad, con su `for` al `<input>`, y es la que anuncia un lector de
       pantalla al entrar en él; el rótulo de la columna es contenido GENERADO, que ni se enfoca
       ni se asocia a nada. Quitando el generado no se pierde ni un nombre.

       Y SOLO DONDE HAY OTRO QUE LO SUSTITUYA. De los 16 juegos de campos de las tablas que se
       escriben, la mayoría no le pone etiqueta propia a su campo —el nombre de un grupo, los
       platos, la cantidad de una línea de albarán—: ahí el `data-label` es el ÚNICO nombre que
       tiene el campo y se queda. `:has(.mud-input-control .mud-input-label)` es exactamente esa
       pregunta, resuelta celda a celda y sin tocar el marcado. Una celda de sólo texto tampoco
       entra: no trae campo, así que conserva su rótulo. */
    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input))
        .mud-table-body .mud-table-cell[data-label]:has(.mud-input-control .mud-input-label)::before {
        content: none;
    }

    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)) .mud-table-body .crud-celda-acciones {
        display: flex;
        align-items: center;
        gap: 0.5rem;
        padding-block-end: 0;
    }

    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)) .mud-table-body .mud-table-cell.crud-celda-acciones[data-label]::before,
    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)) .mud-table-body .crud-celda-acciones::before { content: none; }

    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)) .mud-table-body .crud-celda-acciones .mud-icon-button {
        min-inline-size: var(--plano-toque);
        min-block-size: var(--plano-toque);
    }

    /* LA CELDA DE CIFRA DEJA DE ALINEAR A LA DERECHA (tanda 5). `crud-celda-numero`
       existe para que una COLUMNA de importes se lea en diagonal, y apilada no hay
       columna: el rótulo se iba al canto derecho y el valor se quedaba a la
       izquierda, o sea una etiqueta flotando encima de otra cosa. Lo cazó la
       captura de la tabla que se escribe. */
    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)) .mud-table-body .crud-celda-numero {
        text-align: start;
    }

    /* LOS DOS BOTONCITOS DEL CAMPO NUMERICO, TAMBIEN A 44 px (tanda 5). Los cazó
       la medición de la captura nueva: MudBlazor los APILA a 20 × 24 px cada uno,
       o sea dos objetivos imposibles pegados el uno al otro, y en una tabla que
       se escribe hay dos por cada cantidad. Apilada la fila, el campo ocupa el
       ancho entero y sobra sitio, así que se ponen UNO AL LADO DEL OTRO con el
       objetivo completo: la fila no crece ni un píxel y se pueden pulsar. */
    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)) .mud-input-numeric-spin {
        flex-direction: row;
        align-items: center;
    }

    .admin-tabla:has(tbody .mud-input-control:not(.mud-input-control-boolean-input)) .mud-input-numeric-spin .mud-button-root {
        min-inline-size: var(--plano-toque);
        min-block-size: var(--plano-toque);
    }
}

/* 7.3 quater LA TABLETA (720-1024 px): tabla compacta y primera columna fija
   ==========================================================================
   Entre 720 y 1024 px cabe una TABLA —apilar la fila ahí desperdicia media
   pantalla— pero no caben veinte columnas: la lista de productos pedía 1.640 px
   dentro de 720 y el navegador recortaba lo que no entraba, sin decirlo.

   La salida es la segunda de las dos que ofrece el sistema: la tabla se desplaza
   DENTRO de su caja —nunca la página— y la PRIMERA COLUMNA se queda quieta, que
   es lo que permite mirar la novena columna sin perder de vista de qué fila es.
   El relleno baja de 0,6 a 0,45rem y la celda deja de envolver: a este ancho lo
   que sobra es alto, no líneas partidas.

   EL FONDO DE LA COLUMNA FIJA se pinta en DOS capas y no en una: el color de la
   hoja va de `background-color` y la aguada del hover (o la de la fila elegida)
   se le pone encima como `background-image`, que es lo que reproduce exactamente
   lo que se ve en el resto de la fila. Con un solo color, la columna fija se
   quedaba blanca mientras su fila se teñía. */

/* DESDE EL 2026-09-18 ESTO NO ES SOLO DE LA TABLETA (§14). El usuario trajo la
   lista de Productos en una ventana de 2.000 px: sus diecinueve columnas piden
   1.640 px dentro de los 1.560 del contenido, y «PLU» y «CÓD…» se veían
   recortadas en el canto. El carril existía —MudBlazor escribe su `overflow-x` en
   línea— pero NADA decía que hubiera más tabla a la derecha, así que la columna
   cortada se leía como un defecto de pintado y no como algo que se desplaza.
   La columna fija y la señal de continuidad pasan a valer de 720 px para arriba;
   lo que sigue siendo de la tableta es la COMPACTACION (relleno y no envolver). */

@media (min-width: 720px) {
    .plano-papeles { overflow-x: auto; }

    .plano-papeles :is(thead, .mud-table-head) > tr > :first-child,
    .plano-papeles :is(tbody, .mud-table-body) > tr > :first-child {
        position: sticky;
        inset-inline-start: 0;
        z-index: 2;
        background-color: var(--plano-papel);
    }

    /* Con selección múltiple la primera celda es la casilla, que mide 40 px: se
       quedan las DOS, la casilla y el nombre, porque una casilla fija sin su
       nombre al lado no dice de qué fila es. */
    .plano-papeles :is(thead, .mud-table-head) > tr > .mud-table-cell-checkbox + *,
    .plano-papeles :is(tbody, .mud-table-body) > tr > .mud-table-cell-checkbox + * {
        position: sticky;
        inset-inline-start: 2.5rem;
        z-index: 2;
        background-color: var(--plano-papel);
    }

    .plano-papeles :is(tbody, .mud-table-body) > tr:hover > :first-child,
    .plano-papeles :is(tbody, .mud-table-body) > tr:hover > .mud-table-cell-checkbox + * {
        background-image: linear-gradient(var(--plano-morado-aguada), var(--plano-morado-aguada));
    }

    .plano-papeles :is(tbody, .mud-table-body) > tr[aria-selected="true"] > :first-child,
    .plano-papeles :is(tbody, .mud-table-body) > tr[aria-selected="true"] > .mud-table-cell-checkbox + * {
        background-image: linear-gradient(var(--plano-morado-aguada-honda), var(--plano-morado-aguada-honda));
    }

    /* LA SEÑAL DE CONTINUIDAD DE UNA TABLA, con la misma técnica que la tira: dos
       sombras quietas en los cantos y dos tapas que se van con el contenido. Se
       pone en las DOS cajas que pueden ser la que se desplaza —la envoltura de
       MudBlazor, que es la que lleva el `overflow-x` en línea, y la caja del
       listado, que es la que se desplaza en una tabla escrita a mano— porque
       cuál de las dos lo hace depende de `HorizontalScrollbar`. En la que no se
       desplaza no se ve nada: sin recorrido, la tapa está justo encima de su
       sombra. El fondo es el papel de la página, que es lo que hay debajo de una
       tabla del plano (`.admin-panel` es transparente a propósito).

       Y VALE PARA TODA `.admin-tabla`, no sólo para las que declaran papeles: el
       listado de Versiones —que es de las del master y no pasa por el marco CRUD—
       pedía 1.047 px dentro de 744 y se cortaba igual de callado. La auditoría lo
       cazó en cuanto se le enseñó a mirar carriles sin señal. */
    :is(.plano-papeles, .admin-tabla),
    :is(.plano-papeles, .admin-tabla) .mud-table-container {
        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));
    }
}

@media (min-width: 720px) and (max-width: 1023.98px) {
    .plano-papeles :is(td, th) {
        padding-inline: 0.45rem;
        white-space: nowrap;
    }
}

/* 7.3 quinquies LAS COLUMNAS QUE SE ESCONDEN SOLAS (§14, 2026-09-18)
   ==================================================================
   Antes de desplazar, la tabla intenta CABER: cuando el listado se estrecha, las
   columnas de menor prioridad se van, de derecha a izquierda y hasta tres. Cuáles
   son no lo decide la hoja: lo reparte C# (`PapelesDeColumna.Escondibles`) sobre
   las columnas de papel `SoloEscritorio` —las que un teléfono ya no pinta porque
   están en la ficha— y lo escribe en `data-escritorio`. El nombre, la cifra y las
   secundarias no se tocan nunca.

   POR CONSULTA DE CONTENEDOR Y NO DE MEDIOS, y no es un capricho: lo que decide
   si una tabla cabe es el ancho del LISTADO, no el de la ventana. La misma tabla
   dentro de una ficha de dos columnas tiene la mitad de sitio con la ventana
   igual de ancha, y con `@media` las dos se comportarían igual.

   LOS TRES TRAMOS ESTAN MEDIDOS sobre las diecinueve columnas de Productos, que
   es la tabla más ancha de la central: con el listado en 1.280 px sobran unos
   120, que es lo que ocupa una columna de precio; en 1.150, dos; en 1.024, tres.
   Por debajo de eso no se esconde una cuarta: se desplaza, que es lo que hace la
   regla de arriba, y desplazar no esconde nada.

   LO QUE SE ESCONDE SIGUE EN EL MENU «Columnas» de la barra de herramientas, y al
   revés: lo que el usuario quita ahí sale del reparto, así que con seis columnas
   menos puede que ya no haga falta esconder ninguna. */

.plano-papeles {
    container-type: inline-size;
    container-name: listado;
}

@container listado (max-width: 1280px) {
    .plano-papeles :is(td, th)[data-escritorio="1"] { display: none; }
}

@container listado (max-width: 1150px) {
    .plano-papeles :is(td, th)[data-escritorio="2"] { display: none; }
}

@container listado (max-width: 1024px) {
    .plano-papeles :is(td, th)[data-escritorio="3"] { display: none; }
}

/* EL MENU «⋯» NO EXISTE EN UN ESCRITORIO: el envoltorio se desaparece con
   `display: contents` y el tirador no se pinta, así que la celda de acciones
   queda EXACTAMENTE como estaba —los mismos botones, en el mismo sitio, con el
   mismo divisor— y ninguna prueba de escritorio cambia. */
.crud-acciones-menu,
.crud-acciones-panel { display: contents; }

.crud-acciones-tirador { display: none; }

/* LA BARRA DE HERRAMIENTAS DE UN LISTADO (§14, 2026-09-18)
   ========================================================
   Una fila en los dos anchos. En un escritorio: buscador (480 px como mucho),
   «Buscar», «Columnas», «Seleccionar», el contador y «Nuevo» a la derecha. En un
   teléfono: el buscador a todo el ancho con la lupa DENTRO, «Nuevo» en píldora de
   icono a su derecha y lo demás detrás del «⋯».

   EL «⋯» Y EL MENU «Columnas» SON EL MISMO PATRON QUE EL DE UNA FILA: un
   envoltorio que en escritorio desaparece con `display: contents`, así que los
   botones son LOS MISMOS en los dos anchos y ninguno queda dos veces en la
   página con su nombre accesible repetido. */

.crud-buscador-caja {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex: 1 1 16rem;
    min-inline-size: 0;
    max-inline-size: 480px;
}

.crud-buscador-caja .crud-buscador { flex: 1 1 auto; min-inline-size: 0; max-inline-size: none; }

/* LA BARRA, TODA EN LA MISMA LINEA CENTRAL (2026-09-21)
   =====================================================
   La ayuda «Pulsa Intro para buscar.» cuelga DENTRO del mismo `.mud-input-control` que el campo,
   así que la caja del buscador medía el campo MAS la ayuda: con la barra a `center`, «Columnas»,
   el contador y «Nuevo» se centraban respecto de esa caja alta y «Buscar», pegado al canto de
   arriba de la caja, quedaba treinta píxeles por encima. Lo trajo el usuario en «Carta ·
   Productos» a 1600 px.

   La ayuda sale del flujo —cuelga del campo— y su hueco se reserva en el margen de abajo de la
   barra, sólo donde hay ayuda (`:has()`; 1,5rem son los 20 px del renglón más los 3 de su
   margen). La caja vuelve a medir lo que el campo, se pone a `center` para que «Buscar» se
   centre en él, y el `center` de la barra reparte solo.

   NO se alinea a `flex-start`: medido en el banco a 1280 px el campo denso mide 77 px —48 de
   objetivo táctil más 23 del relleno del estilo «filled»— contra los 48 de un botón, así que por
   arriba los botones quedaban 27 px altos. Y sólo por encima de 720 px: abajo la ayuda ya está
   escondida con `clip-path` y a 375 px no cambia nada. */
@media (min-width: 720px) {
    .crud-barra .crud-buscador { position: relative; }

    .crud-barra .crud-buscador > .mud-input-control-helper-container {
        position: absolute;
        inset-block-start: 100%;
        inset-inline: 0;
    }

    .crud-barra:has(.crud-buscador .mud-input-control-helper-container) {
        margin-block-end: calc(0.75rem + 1.5rem);
    }
}

/* El «⋯» de la barra no existe en un escritorio. */
.crud-barra-mas,
.crud-barra-mas-panel { display: contents; }

.crud-barra-mas-tirador { display: none; }

/* EL MENU «Columnas»: el tirador y su panel alzado. El panel es una hoja de las
   que SI flotan (§5), así que lleva sombra alzada y regla fina, y se ancla al
   tirador. */
.crud-columnas { position: relative; display: inline-flex; }

.crud-columnas-panel { display: none; }

.crud-columnas-abierto .crud-columnas-panel {
    display: flex;
    flex-direction: column;
    position: absolute;
    inset-block-start: calc(100% + 4px);
    inset-inline-start: 0;
    z-index: 30;
    min-inline-size: 14rem;
    max-block-size: 60vh;
    overflow-y: auto;
    padding: 0.35rem;
    background-color: var(--plano-hoja);
    border-radius: var(--plano-radio-control);
    box-shadow: var(--plano-sombra-alzada);
}

.crud-columnas-fila {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-block-size: var(--plano-toque);
    padding-inline: 0.5rem;
    border-radius: var(--plano-radio-control);
    font-size: var(--plano-t-13);
    color: var(--plano-tinta);
    cursor: pointer;
    white-space: nowrap;
}

.crud-columnas-fila:hover { background-color: var(--plano-morado-aguada); }

.crud-columnas-fila input { accent-color: var(--plano-morado); inline-size: 16px; block-size: 16px; }

/* LO QUE SOLO SE PINTA EN UN ANCHO (§14, 2026-09-18)
   ==================================================
   Dos clases y nada más, para las celdas que dicen lo mismo de dos maneras según
   quepa el rótulo de su columna: en la lista de Instalaciones del master, la
   celda del cupo pinta «2» debajo de su cabecera en un escritorio y «2
   establecimientos» en un teléfono, donde esa cabecera no existe.

   NO ES UN DUPLICADO DE CONTENIDO: es el MISMO dato con y sin su nombre, y sólo
   uno de los dos está en el árbol de accesibilidad a la vez, porque `display:
   none` saca de él. La alternativa —pintar la cifra sola— es lo que el usuario
   trajo de su teléfono: «· 2 · 20 ·». */
.plano-solo-movil { display: none; }

@media (max-width: 719.98px) {
    .plano-solo-movil { display: inline; }
    .plano-solo-escritorio { display: none; }

    /* LA FILA DE UNA INSTALACION. El código abre la fila entera (el `::after` de
       §7.3 bis lo estira sobre ella) y el nombre va a su lado, en tinta rebajada:
       lo que identifica una instalación es su código, y el nombre es con lo que
       se reconoce. */
    .instalaciones-abrir {
        border: none;
        background: none;
        padding: 0;
        font: inherit;
        color: inherit;
        text-align: start;
        cursor: pointer;
    }

    .instalaciones-abrir code {
        font-family: var(--plano-familia);
        font-variant-numeric: tabular-nums;
    }

    .instalaciones-abrir .plano-solo-movil {
        margin-inline-start: 0.4rem;
        font-weight: 420;
        color: var(--plano-tinta-2);
    }

    /* «ENTRAR» NO SE PINTA: la fila entera entra. Dejarlo sería un segundo botón
       de 104 px para lo mismo, encima del que ya cubre los 390 px de la fila. El
       `⋮` del master se queda, con su objetivo de 44. */
    .instalaciones-tabla .instalaciones-entrar { display: none; }

    .instalaciones-tabla tbody > tr > .crud-celda-acciones .mud-menu { display: inline-flex; }
}

/* El modo «Seleccionar» y el buscador en icono son de móvil: arriba no se ven. */
@media (min-width: 720px) {
    .crud-barra .crud-modo-seleccion { display: none; }
}

/* LA BARRA DE HERRAMIENTAS DE UN LISTADO EN UN MOVIL (auditoría responsiva).
   A 390 px la barra son 374 px útiles y llevaba tres piezas en línea: el
   buscador, un botón «Buscar» con rótulo (104 px) y el contador. El campo se
   quedaba en 180 px y su marcador de posición se cortaba a la mitad.

   El botón pasa a ICONO: la palabra se apaga con `font-size: 0` y no con
   `display: none`, que es la diferencia entre un botón sin rótulo visible y un
   botón sin nombre accesible —el texto sigue en el marcado y lo lee el lector de
   pantalla—. El icono va con su tamaño escrito, que es lo que lo salva del cero. */
@media (max-width: 719.98px) {
    .crud-barra { gap: 0.5rem; flex-wrap: nowrap; }

    /* EL ROTULO DE ZONA QUE REPITE EL TITULO DE LA PAGINA NO SE PINTA (§14). Son
       24 px de «PRODUCTOS» tres renglones debajo de «Productos», y en un teléfono
       cada renglón de la cabecera es un producto menos en pantalla. El `<h2>` se
       queda en el marcado: lo que se va es su dibujo.

       CON LAS DOS CLASES DEL MISMO ELEMENTO, y no es adorno: `app.css` se carga
       DESPUES de esta hoja y le pone `display: flex` a `.admin-panel-cabecera`,
       que tiene la misma especificidad; con una clase sola, el rótulo seguía
       pintándose. Un `@media` no suma especificidad. */
    .admin-panel-cabecera.plano-region-rotulo-repetido { display: none; }

    /* 6rem de BASE y sin tope: la base es lo que decide si la línea se parte, no
       el ancho final. Con la lupa DENTRO del campo y «Nuevo» en píldora de icono,
       las piezas de la fila son tres —buscador, alta y el «⋯»— y el campo crece
       con todo lo que sobra. */
    .crud-barra .crud-buscador-caja { flex: 1 1 6rem; max-inline-size: none; }

    /* LA LUPA, DENTRO DEL CAMPO. Se posiciona sobre su canto derecho en vez de ir
       al lado: al lado se llevaba 48 px de los 374 de la barra, que son justo los
       que necesita «Nuevo». Sigue siendo el MISMO botón —su `data-testid` y su
       estado de ocupado no se tocan— y el campo le deja el hueco con relleno. */
    .crud-barra .crud-boton-buscar {
        position: absolute;
        inset-inline-end: 0;
        inset-block-start: 0;
        font-size: 0;
        min-inline-size: var(--plano-toque-movil);
        inline-size: var(--plano-toque-movil);
        min-block-size: var(--plano-toque-movil);
        padding-inline: 0;
        border: none;
        background: none;
    }

    .crud-barra .crud-boton-buscar .mud-icon-root { font-size: 20px; }

    .crud-barra .crud-boton-buscar :is(.mud-button-icon-start, .mud-button-icon-end) {
        margin-inline: 0;
    }

    .crud-barra .crud-buscador-caja:has(.crud-boton-buscar) .crud-buscador .mud-input-slot {
        padding-inline-end: var(--plano-toque-movil);
    }

    /* UNA SOLA LUPA. El campo lleva la suya de adorno —decorativa, a la izquierda—
       y con el botón de enviar dentro eran DOS lupas en 374 px, una que no hace
       nada y otra que busca. Se queda la que busca. */
    .crud-barra .crud-buscador-caja:has(.crud-boton-buscar) .crud-buscador .mud-input-adornment-start {
        display: none;
    }

    /* EL ORDEN DE LA FILA: buscador, «Nuevo», «⋯». El hueco elástico —que es lo
       que `MudSpacer` pinta, y lo pinta como `.flex-grow-1`— no separa nada aquí:
       se llevaba 75 px de los 374 y dejaba el buscador en 171. */
    .crud-barra > .flex-grow-1 { display: none; }

    /* LA AYUDA DEL BUSCADOR DEJA DE SER UN RENGLON (§14). «Pulsa Intro para
       buscar.» ocupaba una línea entera debajo del campo, y ya lo dice el
       marcador de posición del propio campo: «Buscar y pulsar Intro…». Se
       esconde a la VISTA y no del árbol, porque es a este elemento al que apunta
       el `aria-describedby` de MudBlazor: con `display: none` el campo se
       quedaría sin su descripción. Es el patrón de §7 (`clip-path: inset(50%)`),
       que la auditoría ya sabe que no es contenido visible. */
    .crud-barra .crud-buscador .mud-input-helper-text {
        position: absolute;
        inline-size: 1px;
        block-size: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    /* LA CABECERA DE LA PAGINA, EN UNA FILA CUANDO CABE (§14). La estrella de
       favorito y el botón de recargar bajaban a un renglón propio de 44 px por
       debajo del subtítulo: son dos botones de icono que caben de sobra al lado
       del título, y ese renglón era una fila de producto menos en pantalla.

       SE BAJA LA BASE DEL TEXTO, NO SE QUITA EL `flex-wrap`. Con `nowrap`, una
       pantalla cuya cabecera lleve un botón con rótulo —«Guardar y volver»— le
       comería el ancho al título en vez de bajarse, que es justo el defecto que
       esa envoltura arregló en su día. Con la base en 8rem las dos piezas
       estrechas caben al lado y las anchas siguen bajando solas.

       Por debajo de 600 px manda «la cabecera de página en el teléfono».

       CON `.plano-cuerpo` DELANTE porque `app.css` se carga DESPUES y comparte
       especificidad con estas dos clases. */
    .plano-cuerpo .admin-cabecera {
        align-items: flex-start;
        gap: 0.5rem 0.75rem;
        padding-bottom: 0.75rem;
        margin-bottom: 1rem;
    }

    .plano-cuerpo .admin-cabecera-texto { flex: 1 1 8rem; }

    .plano-cuerpo .admin-cabecera-acciones { flex: 0 0 auto; }
    .crud-barra .crud-buscador-caja { order: 1; }
    .crud-barra .crud-nuevo { order: 2; }
    .crud-barra-mas { order: 3; }

    /* «NUEVO», EN PILDORA DE ICONO. La palabra se apaga con `font-size: 0` y no
       con `display: none`: el rótulo sigue en el marcado y lo lee un lector de
       pantalla, que es la diferencia entre un botón sin texto visible y un botón
       sin nombre. */
    .crud-barra .crud-nuevo {
        flex: none;
        font-size: 0;
        min-inline-size: var(--plano-toque-movil);
        inline-size: var(--plano-toque-movil);
        padding-inline: 0;
    }

    .crud-barra .crud-nuevo .mud-icon-root { font-size: 22px; }

    .crud-barra .crud-nuevo :is(.mud-button-icon-start, .mud-button-icon-end) { margin-inline: 0; }

    /* EL «⋯» DE LA BARRA: lo que no cabe en la fila —«Seleccionar», «Columnas»—
       se guarda detrás de un tirador de 44 px con su hoja alzada. */
    .crud-barra-mas { position: relative; display: inline-flex; flex: none; }

    .crud-barra-mas-tirador {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        inline-size: var(--plano-toque);
        block-size: var(--plano-toque);
        padding: 0;
        border: none;
        border-radius: 50%;
        background: none;
        color: var(--plano-tinta-2);
        cursor: pointer;
    }

    .crud-barra-mas-abierto .crud-barra-mas-tirador {
        background-color: var(--plano-morado-aguada);
        color: var(--plano-morado);
    }

    .crud-barra-mas-panel { display: none; }

    .crud-barra-mas-abierto .crud-barra-mas-panel {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        gap: 0.25rem;
        position: absolute;
        inset-block-start: calc(var(--plano-toque) + 2px);
        inset-inline-end: 0;
        z-index: 25;
        padding: 0.35rem;
        background-color: var(--plano-hoja);
        border-radius: var(--plano-radio-control);
        box-shadow: var(--plano-sombra-alzada);
    }

    .crud-barra-mas-abierto .crud-barra-mas-panel .mud-button-root { white-space: nowrap; }

    /* Dentro del «⋯» el menú de columnas se abre hacia la izquierda: pegado al
       canto derecho de la pantalla, hacia la derecha no cabe. */
    .crud-barra-mas .crud-columnas { display: flex; }

    .crud-barra-mas .crud-columnas-abierto .crud-columnas-panel {
        inset-inline-start: auto;
        inset-inline-end: 0;
    }

    /* EL CONTADOR («3.305 filas») NO SE PINTA. Es un dato, no un control: en la
       tanda anterior se iba a un renglón propio, y ese renglón son 24 px de los
       844 que mide la pantalla de un teléfono, gastados en una cifra que nadie
       compara con nada. La cuenta sigue en el paginador, que es donde se mira. */
    .crud-barra .crud-contador { display: none; }
}

/* 7.4 `mud-paper`: de tarjeta a ZONA — papel con esquina de muro y sin línea,
   en vez del contenedor con canto y sombra. Las elevaciones se apagan en
   bloque; lo que SI se eleva, más abajo. */

.mud-paper {
    background-color: var(--plano-hoja);
    color: var(--plano-tinta);
    border-radius: var(--plano-esquina-muro);
    border: none;
    box-shadow: none;
    background-image: none;
}

.mud-paper-outlined { border: none; }

.mud-paper.mud-paper-square { border-radius: 0; }

[class*="mud-elevation-"] { box-shadow: none; }

/* Con muro: hace falta contorno. */
.plano-zona {
    background-color: var(--plano-hoja);
    border-radius: var(--plano-esquina-muro);
    border-inline-start: 2px solid var(--plano-muro);
    border-block-end: 2px solid var(--plano-muro);
    padding: 1.25rem 1.5rem;
}

/* Sin muro: papel y aire. 28 px A CADA LADO DE LA REGLA, que es lo que separa
   una zona de la siguiente (§4). La primera no lleva aire arriba y la última no
   lleva regla: el borde de la página ya separa. */
.plano-region {
    background-color: transparent;
    margin-block-start: 28px;
    padding-block-end: 28px;
    border-block-end: 1px solid var(--plano-linea-fina);
}

.plano-region:first-child { margin-block-start: 0; }
.plano-region:last-child { padding-block-end: 0; border-block-end: none; }

/* DOS CAMPOS SEGUIDOS NO SON UN BLOQUE. Con la variante rellena, dos campos
   pegados comparten canto y se leen como una caja partida por una raya: en las
   capturas de la tanda 1 hay que contar las etiquetas para saber cuántos hay.
   12 px dentro de una zona y 28 entre zonas (§4): el aire agrupa.

   ES `gap` Y NO UN MARGEN, y lo enseñó la primera captura de la tanda 3: con
   `> * + * { margin-block-start: 12px }` hacía falta ADEMAS anular el margen
   propio de los campos densos de MudBlazor, y ese segundo selector
   —`> .mud-input-control`— pesa más que el primero, así que se llevaba por
   delante los 12 px y los campos volvían a salir pegados. Con `gap` el hueco lo
   pone el CONTENEDOR: no hay margen que anular ni pelea de pesos, y vale igual
   para un campo, una casilla, una tabla o un aviso. */
.plano-region-campos,
.plano-campos {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* MudBlazor le pone su propio aire a los campos densos; el de la zona manda. */
.plano-region-campos > .mud-input-control,
.plano-campos > .mud-input-control { margin-block: 0; }

/* EL TEXTO CORRIDO PARA DONDE PARA UN RENGLON (§1 de
   `docs/central/fichas-con-pestanas-y-ancho-2026-09-20.md`). Lo que se limita al
   quitarle el tope a la página es la LINEA DE TEXTO, no la página: un párrafo
   explicativo a 1.800 px de ancho pierde el renglón al volver. Los campos, las
   tablas y los lienzos no entran aquí: sólo la prosa. */
.plano-region-campos > p,
.admin-panel-cuerpo p { max-inline-size: var(--plano-prosa); }

/* La rejilla de 12 de §4: rotulo (3) y campos (9). En movil el rotulo se pone ENCIMA en vez de
   encogerse: a 390 px tres doceavos son 90 px y «Cumplimiento fiscal» se parte en cuatro. */
.plano-region-rejilla {
    display: grid;
    grid-template-columns: 3fr 9fr;
    gap: 1.5rem;
    align-items: start;
}

.plano-region-campos { min-inline-size: 0; }

@media (max-width: 899.98px) {
    .plano-region-rejilla { grid-template-columns: 1fr; gap: 0.75rem; }
}

/* 7.5 Chips */

.mud-chip {
    border-radius: var(--plano-pildora);
    border: none;
    font-family: var(--plano-familia);
    font-size: var(--plano-t-13);
    font-weight: 540;
    letter-spacing: 0;
    text-transform: none;
    background-color: rgba(42, 26, 62, 0.07);
    color: var(--plano-tinta);
    box-shadow: none;
}

.mud-chip.mud-chip-outlined { border: none; background-color: rgba(42, 26, 62, 0.07); }

/* EL CHIP QUE SE PULSA NO ES UN ÓVALO (repaso del 2026-10-06, a petición del usuario). La píldora se queda en las
   insignias, que solo informan; el chip que filtra (los de un MudChipSet: «Todos», «En línea»…) o que se quita con su
   aspa (los valores de un campo de etiquetas, los filtros de categorías) es un control, y lleva el radio de control de
   todos los botones. */
.mud-chip.mud-clickable,
.mud-chip:has(.mud-chip-close-button) { border-radius: var(--plano-radio-control); }

/* LAS INSIGNIAS DE ESTADO, LAS CUATRO (tanda 4). Hasta la tanda 3 faltaba la de
   ÉXITO: una tienda «Al día» —que el código pinta con `Color.Success`— caía en
   la aguada de tinta por omisión y sobre el papel lila se leía LILA, o sea del
   color de la acción. Un estado correcto no puede vestirse como un botón.

   El reparto es el del §1 y vale para toda la central: correcto = SALVIA,
   atención = MOSTAZA, error = ARCILLA, neutro = TINTA-2, y el MORADO se queda
   para la acción, la selección y lo informativo. Los tonos de texto son los
   hondos, que son los que llegan a AA sobre su propia aguada (§8.3.1). */
/* En TINTA y no en salvia, como el aviso de éxito y como la insignia de atención:
   medido en el banco, la salvia sobre su propia aguada honda da 4,14:1 y el
   mínimo del texto son 4,5. Lo que dice «correcto» es la AGUADA, que posee la
   pastilla entera; el texto sólo tiene que leerse. */
.mud-chip.mud-chip-color-success { background-color: var(--plano-salvia-aguada-honda); color: var(--plano-tinta); }
.mud-chip.mud-chip-color-info { background-color: var(--plano-morado-aguada-honda); color: var(--plano-morado); }
.mud-chip.mud-chip-color-primary { background-color: var(--plano-morado-aguada-honda); color: var(--plano-morado); }
.mud-chip.mud-chip-color-warning { background-color: var(--plano-mostaza-aguada); color: var(--plano-tinta); }
.mud-chip.mud-chip-color-error { background-color: var(--plano-arcilla-aguada); color: var(--plano-arcilla-honda); }
.mud-chip.mud-chip-color-secondary,
.mud-chip.mud-chip-color-default { background-color: rgba(42, 26, 62, 0.07); color: var(--plano-tinta-2); }
.mud-chip.mud-chip-selected { background-color: var(--plano-morado); color: var(--plano-papel); }

/* 7.6 Tabs */

.mud-tabs-tabbar {
    background-color: transparent;
    border-bottom: 1px solid var(--plano-linea);
    box-shadow: none;
}

.mud-tab {
    font-family: var(--plano-familia);
    font-size: var(--plano-t-15);
    font-weight: 540;
    text-transform: none;
    letter-spacing: 0;
    color: var(--plano-tinta-2);
    min-height: var(--plano-toque);
}

.mud-tab.mud-tab-active { color: var(--plano-tinta); font-weight: 640; }
.mud-tab-slider { background-color: var(--plano-morado); block-size: 2px; }

/* 7.7 Avisos: el tono al FONDO */

.mud-alert {
    border-radius: var(--plano-esquina-muro);
    border: none;
    border-inline-start: none;
    box-shadow: none;
    font-family: var(--plano-familia);
    font-size: var(--plano-t-15);
    color: var(--plano-tinta);
    background-color: rgba(42, 26, 62, 0.07);
    /* UN AVISO ES PROSA (§1 de
       `docs/central/fichas-con-pestanas-y-ancho-2026-09-20.md`): desde que la página
       no tiene tope, un aviso de una frase se estiraba a todo el ancho de la ventana
       y la frase quedaba sola en un renglón de 1.900 px. Para donde para un renglón. */
    max-inline-size: var(--plano-prosa);
}

.mud-alert .mud-alert-icon { color: var(--plano-tinta-2); }

.mud-alert[class*="-error"] { background-color: var(--plano-arcilla-aguada); color: var(--plano-tinta); }
.mud-alert[class*="-error"] .mud-alert-icon { color: var(--plano-arcilla-honda); }
.mud-alert[class*="-warning"] { background-color: var(--plano-mostaza-aguada); color: var(--plano-tinta); }
.mud-alert[class*="-warning"] .mud-alert-icon { color: var(--plano-mostaza-honda); }
/* El éxito en SALVIA y la información en MORADO, no los dos en el mismo tono: la
   salvia significa «correcto» y nada más, y un aviso informativo de salvia diría
   que algo ha salido bien cuando lo único que hace es contar algo. */
.mud-alert[class*="-success"] { background-color: var(--plano-salvia-aguada); color: var(--plano-tinta); }
.mud-alert[class*="-success"] .mud-alert-icon { color: var(--plano-salvia); }
.mud-alert[class*="-info"] { background-color: var(--plano-morado-aguada); color: var(--plano-tinta); }
.mud-alert[class*="-info"] .mud-alert-icon { color: var(--plano-morado); }

.mud-snackbar {
    border-radius: var(--plano-esquina-muro);
    border: none;
    box-shadow: var(--plano-sombra-alzada);
    font-family: var(--plano-familia);
}

.mud-snackbar .mud-snackbar-surface {
    background-color: var(--plano-hoja);
    color: var(--plano-tinta);
    border: none;
    border-radius: var(--plano-esquina-muro);
}

/* 7.8 Los que SI se elevan */

.mud-dialog {
    border-radius: var(--plano-esquina-muro);
    background-color: var(--plano-hoja);
    /* `!important` 1: Mud escribe la sombra en `.mud-dialog.mud-paper`; el bloque de arriba se la quitaría. */
    box-shadow: var(--plano-sombra-hoja) !important;
}

.mud-dialog-title {
    font-size: var(--plano-t-20);
    font-weight: 640;
    font-stretch: 96%;
    letter-spacing: -0.01em;
    color: var(--plano-tinta);
}

.mud-dialog-content { color: var(--plano-tinta); font-size: var(--plano-t-15); }
.mud-dialog-actions { border-top: 1px solid var(--plano-linea-fina); padding-block: 0.9rem; }

.mud-popover {
    border-radius: var(--plano-radio-control);
    background-color: var(--plano-hoja);
    color: var(--plano-tinta);
    /* `!important` 2: igual; un menú sin sombra se pierde. */
    box-shadow: var(--plano-sombra-alzada) !important;
    border: 1px solid var(--plano-linea-fina);
}

.mud-list-item, .mud-menu-item {
    font-family: var(--plano-familia);
    font-size: var(--plano-t-15);
    color: var(--plano-tinta);
    border-radius: var(--plano-radio-control);
}

.mud-list-item:hover, .mud-menu-item:hover { background-color: var(--plano-morado-aguada); }

.mud-tooltip {
    background-color: var(--plano-tinta);
    color: var(--plano-papel);
    font-family: var(--plano-familia);
    font-size: var(--plano-t-13);
    border-radius: var(--plano-radio-control);
}

/* 7.9 Esqueletos: trama, no brillo */

.mud-skeleton {
    background-color: var(--plano-papel-hondo);
    background-image: var(--plano-trama-suave);
    border-radius: var(--plano-radio-control);
}

.mud-skeleton.mud-skeleton-circle { border-radius: 50%; }

.mud-skeleton::after {
    /* El barrido de Wave, fuera. */
    background: none;
    animation: none;
}

.mud-skeleton.mud-skeleton-wave,
.mud-skeleton.mud-skeleton-pulse { animation: plano-latido 1.6s var(--plano-curva) infinite; }

@keyframes plano-latido {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.55; }
}

/* 7.10 Barra y cajón de Mud, apagados */

.mud-appbar { background-color: transparent; box-shadow: none; color: var(--plano-tinta); }

.mud-appbar .mud-toolbar { background-color: transparent; }
.mud-drawer { background-color: var(--plano-hoja); border: none; box-shadow: none; }

/* CON UNA EXCEPCION: el cajón de la vista previa del diseñador de impresión, que
   es el único `MudDrawer` de la web y flota SOBRE el lienzo mientras se edita.
   Ahí la profundidad es información —dice qué está encima de qué— y se dibuja
   como una hoja: muro en el canto y la sombra teñida de §1. */
.impresion-editor-cajon.mud-drawer {
    border-inline-start: 2px solid var(--plano-muro);
    box-shadow: var(--plano-sombra-hoja);
}

/* Por si va antes del tema. */
.mud-typography { font-family: var(--plano-familia); }

.mud-divider { border-color: var(--plano-linea-fina); }

/* 8. EL MARCO — LA BARRA (64 px) y EL CUERPO. Desde D2 la navegación es la barra
   lateral (hoja-limpia.css, «BARRA LATERAL (D2)»); los taburetes, la tira del área
   y la barra inferior que vivían aquí se retiraron en D6. */

.plano-marco {
    min-block-size: 100dvh;
    display: flex;
    flex-direction: column;
    background-color: var(--plano-papel);
}

/* 8.1 La barra */

/* EL MARCO DE LA BARRA: la banda de papel que se pega arriba (2026-09-18).
   Hasta esta fecha lo pegajoso era la PILDORA, a 12 px del borde: esos 12 px de
   arriba —y los 12 de cada lado, y el hueco de las esquinas redondas— eran una
   rendija transparente por la que el contenido pasaba al desplazar, cortado.
   Ahora se pega una banda de papel a todo el ancho con la píldora dentro; lo que
   era margen de la barra es relleno del marco, así que las medidas no cambian. */
.plano-barra-marco {
    position: sticky;
    inset-block-start: 0;
    z-index: 1200;
    background-color: var(--plano-papel);
    padding: var(--plano-barra-hueco) var(--plano-barra-hueco) 0;
}

.plano-barra {
    background-color: var(--plano-hoja);
    border-radius: var(--plano-pildora);
    border-block-end: 2px solid var(--plano-muro);
    padding-inline: 1.25rem;
    min-block-size: var(--plano-barra-alto);
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.plano-barra-logo { display: flex; align-items: center; flex: none; }

/* EL LOGOTIPO NO SE DEFORMA NI SE RECOLOREA EN CLARO (PRODUCT.md): sólo se le fija el alto. EN OSCURO el
   trazo morado no se ve sobre la hoja (1,87:1) y lleva el filtro de --plano-logo-filtro (7,36:1), que
   hoja-limpia.css define sólo bajo prefers-color-scheme: dark; sin la variable, `none`. */
.plano-barra-logo img { block-size: 36px; inline-size: auto; display: block; filter: var(--plano-logo-filtro, none); }

.plano-barra-instalacion {
    font-size: var(--plano-t-15);
    font-weight: 600;
    color: var(--plano-tinta);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-inline-size: 22ch;
}

.plano-barra-codigo {
    font-size: var(--plano-t-12);
    font-weight: 600;
    font-stretch: 75%;
    letter-spacing: 0.04em;
    color: var(--plano-tinta-2);
    background-color: rgba(42, 26, 62, 0.07);
    border-radius: var(--plano-pildora);
    padding: 0.15rem 0.55rem;
    white-space: nowrap;
}

/* EL PASE: botón que abre la paleta. */
.plano-pase {
    flex: 1 1 auto;
    min-inline-size: 0;
    max-inline-size: 30rem;
    margin-inline: auto;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-block-size: 38px;
    padding-inline: 0.85rem;
    border-radius: var(--plano-pildora);
    border: 1px solid var(--plano-linea);
    background-color: rgba(42, 26, 62, 0.04);
    color: var(--plano-tinta-2);
    font-family: var(--plano-familia);
    font-size: var(--plano-t-13);
    text-align: start;
    cursor: text;
    transition: background-color var(--plano-tiempo) var(--plano-curva),
        border-color var(--plano-tiempo) var(--plano-curva);
}

.plano-pase:hover { background-color: rgba(42, 26, 62, 0.07); border-color: var(--plano-morado); }
.plano-pase-texto { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.plano-pase-tecla {
    font-family: var(--plano-familia);
    font-size: var(--plano-t-12);
    font-weight: 600;
    font-stretch: 75%;
    color: var(--plano-tinta-2);
    background-color: rgba(42, 26, 62, 0.07);
    border-radius: 6px;
    padding: 0.1rem 0.4rem;
    flex: none;
}

.plano-barra-derecha { display: flex; align-items: center; gap: 0.35rem; flex: none; margin-inline-start: auto; }

/* Mesas redondas, como en la portada. */
.plano-mesas { display: flex; align-items: center; gap: 0.3rem; }

.plano-mesa {
    inline-size: 34px;
    block-size: 34px;
    border-radius: 50%;
    border: 1.5px solid var(--plano-linea);
    background-color: transparent;
    color: var(--plano-tinta-2);
    font-family: var(--plano-familia);
    font-size: var(--plano-t-13);
    font-weight: 620;
    font-stretch: 85%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    transition: background-color var(--plano-tiempo) var(--plano-curva),
        border-color var(--plano-tiempo) var(--plano-curva),
        color var(--plano-tiempo) var(--plano-curva);
}

.plano-mesa:hover { background-color: var(--plano-morado-aguada); border-color: var(--plano-morado); color: var(--plano-morado); }
.plano-mesa[aria-current] { background-color: var(--plano-tinta); border-color: var(--plano-tinta); color: var(--plano-papel); }

.plano-pastilla {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.8rem;
    min-block-size: 34px;
    border-radius: var(--plano-pildora);
    border: none;
    background-color: rgba(42, 26, 62, 0.05);
    color: var(--plano-tinta);
    font-family: var(--plano-familia);
    font-size: var(--plano-t-13);
    font-weight: 520;
    text-decoration: none;
    white-space: nowrap;
    flex: none;
    transition: background-color var(--plano-tiempo) var(--plano-curva),
        color var(--plano-tiempo) var(--plano-curva);
}

.plano-pastilla:hover { background-color: var(--plano-morado-aguada); color: var(--plano-morado); }

.plano-pastilla[aria-current] {
    background-color: var(--plano-tinta);
    color: var(--plano-papel);
    font-weight: 620;
}

/* 8.4 Volver, con el arco */

.plano-volver {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    color: var(--plano-tinta-2);
    font-size: var(--plano-t-13);
    font-weight: 560;
    text-decoration: none;
    min-block-size: var(--plano-toque);
    padding-inline: 0.1rem;
}

.plano-volver:hover { color: var(--plano-morado); text-decoration: underline; text-underline-offset: 3px; }

/* 8.5 El cuerpo */

/* EL CUERPO CRECE CON LA VENTANA (§1 de
   `docs/central/fichas-con-pestanas-y-ancho-2026-09-20.md`). El relleno lateral pasa
   de los 12 px fijos de la barra al hueco que crece, `--plano-cuerpo-hueco`; el aire
   de arriba y de abajo no se toca. */
.plano-cuerpo { flex: 1 1 auto; min-block-size: 0; padding: 1.5rem var(--plano-cuerpo-hueco) 2.5rem; }

/* SIN TOPE DE PAGINA (§1). Antes centraba a 1.280 px, y a 1.920 eso eran 640 px de
   papel en blanco a los lados mientras las tablas escondían columnas. Lo que se
   limita ahora es la LINEA DE TEXTO (`--plano-prosa`) y la columna de campos de una
   ficha (72rem, más abajo), no la página: tablas, listados, lienzos y portada usan
   el ancho que hay. El `margin-inline: auto` se queda por si algo de dentro vuelve a
   ponerse un tope propio. */
.plano-contenido { max-inline-size: none; margin-inline: auto; }

/* 8.5 bis TECLAS Y RELIEVE — el bloque «§8.6» del encargo del 2026-09-18
   =====================================================================
   (El porqué entero, en §16 del rediseño. Lo de la tira del área que nació aquí
   —la rejilla de teclas con icono y estrella— se retiró en D6 con la tira.)

   LO QUE TRAJO EL USUARIO: «la segunda fila de botones me gustaría que fueran
   algo más rectangulares, no tan redondos, y pon botones con relieve, es decir
   que al pulsarlos se vean como apretados o pulsados».

   LA DECISION: la tira del área deja de ser una fila de píldoras y pasa a ser un
   TECLADO. Una píldora dice «etiqueta»; una tecla dice «esto se pulsa», y una
   tecla que se hunde dice además «ya lo has pulsado». Es un cambio deliberado del
   sistema de formas, no un retoque: la píldora se queda SOLO donde es forma por
   concepto —las mesas redondas de los favoritos y las insignias de estado—.

   EL RELIEVE SE DIBUJA CON EL LENGUAJE DEL PLANO Y NO CON EL DE MATERIAL. Nada de
   degradados brillantes ni de sombras difusas: el relieve es un CANTO, o sea una
   línea de 2 px de tinta bajo la tecla SIN NADA DE DESENFOQUE. Es el MURO del
   sistema (§1: la profundidad se dibuja con muro y aguada) llevado a un control
   del tamaño de la mano. Encima, una luz de 1 px de papel para que el canto
   superior no se lea como una raya suelta.

   LOS CUATRO ESTADOS:
     · REPOSO   canto de 2 px + luz de 1 px.
     · HOVER    la aguada sube un punto (del morado al 10 % al 18 %); canto igual.
     · PULSADO  la tecla BAJA 2 px y el canto DESAPARECE —o sea, se come su propio
                canto, que es exactamente lo que hace una tecla de verdad— y se le
                pone una sombra INTERIOR para que se vea hundida.
     · ENCLAVADA (`aria-current`, la pantalla en la que se está) se queda hundida:
                misma sombra interior, fondo de tinta, texto de papel, sin canto y
                desplazada 1 px. Una tecla de interruptor que se quedó dentro.

   EL ESTADO ACTIVO NO DEPENDE DEL RELIEVE (§6 del diseño y WCAG 1.4.1): quien no
   distinga los 2 px sigue teniendo el fondo de tinta, el texto de papel, el peso
   620 y el `aria-current` que lo dice con palabras.

   EL TIEMPO ES ASIMETRICO: 90 ms al bajar y 140 ms al subir. Una tecla responde
   al dedo antes de que el dedo lo note y vuelve con un punto de inercia; iguales,
   el gesto se lee mecánico. `prefers-reduced-motion` lo anula al final de la hoja
   y además aquí abajo se quita el desplazamiento: se pierde el MOVIMIENTO, no el
   cambio de sombra, que es el que dice el estado. */

:root {
    /* LA FICHA DE LA TECLA: 8 px. Entre el radio de control (10, donde se
       escribe) y la esquina corta de muro (6): una tecla no es un campo ni es una
       habitación. */
    --plano-r-tecla: 8px;
    /* El canto, que es también lo que la tecla baja al pulsarse: la tecla se come
       su propio canto, y por eso los dos valores son EL MISMO y no dos fichas. */
    --plano-canto: 2px;

    /* El relieve en reposo: canto de tinta al 22 % SIN DESENFOQUE (el cuarto
       valor es 0) y luz de papel al 70 % dentro del borde de arriba. */
    --plano-tecla-canto: 0 2px 0 0 rgba(42, 26, 62, 0.22),
        inset 0 1px 0 0 rgba(245, 243, 248, 0.70);
    /* Hundida sobre papel o sobre una aguada. */
    --plano-tecla-hundida: inset 0 2px 3px 0 rgba(42, 26, 62, 0.18);
    /* Hundida sobre un RELLENO OSCURO (tinta, morado, arcilla): la tinta al 18 %
       sobre tinta no se ve. La berenjena honda al 55 % es el mismo azul-morado
       del sistema un escalón por debajo de la tinta, así que sigue habiendo UNA
       sola tinta. */
    --plano-tecla-hundida-honda: inset 0 2px 3px 0 rgba(31, 18, 48, 0.55);
    /* El canto de lo que ya va relleno: berenjena honda, que se lee sobre el
       morado, sobre la arcilla y sobre la propia tinta. */
    --plano-tecla-canto-hondo: 0 2px 0 0 rgba(31, 18, 48, 0.55);

    /* Asimétrico: baja deprisa, sube con inercia. */
    --plano-tecla-baja: 90ms;
    --plano-tecla-sube: 140ms;
}

/* --- La pastilla: una tecla, no una píldora ------------------------------- */

/* La tira del área que la estrenó se retiró en D6; la tecla se queda porque la
   usan las pastillas que siguen vivas (el resumen del explorador, la tira de
   precios). 40 px de alto: el de una fila de teclas. */

.plano-pastilla {
    position: relative;
    border-radius: var(--plano-r-tecla);
    min-block-size: 40px;
    gap: 0.5rem;
    padding: 0.3rem 0.7rem;
    justify-content: flex-start;
    box-shadow: var(--plano-tecla-canto);
    transition: background-color var(--plano-tiempo) var(--plano-curva),
        color var(--plano-tiempo) var(--plano-curva),
        box-shadow var(--plano-tecla-sube) var(--plano-curva),
        transform var(--plano-tecla-sube) var(--plano-curva);
}

/* El nombre, a la izquierda y con puntos suspensivos; el entero va en `title`. */

.plano-pastilla:hover {
    background-color: var(--plano-morado-aguada-honda);
    box-shadow: var(--plano-tecla-canto);
}

/* PULSADA: baja 2 px, pierde el canto y se hunde. Las duraciones van en el mismo
   orden que la transición de arriba: los dos colores con su tiempo y el hundido
   con el suyo, más corto. */
.plano-pastilla:active {
    transform: translateY(var(--plano-canto));
    box-shadow: var(--plano-tecla-hundida);
    transition-duration: var(--plano-tiempo), var(--plano-tiempo),
        var(--plano-tecla-baja), var(--plano-tecla-baja);
}

/* ENCLAVADA: se queda dentro. */
.plano-pastilla[aria-current] {
    transform: translateY(1px);
    box-shadow: var(--plano-tecla-hundida-honda);
}

.plano-pastilla[aria-current]:hover { background-color: var(--plano-tinta); }

.plano-pastilla[aria-current]:active { transform: translateY(var(--plano-canto)); }

/* Los chips de filtro de un listado SI son teclas, pero pequeñas: 32 px de alto
   y canto de 1 px, que es lo que le corresponde a media tecla. */
.plano-herramientas-filtros .mud-chip {
    border-radius: var(--plano-r-tecla);
    box-shadow: 0 1px 0 0 rgba(42, 26, 62, 0.22);
}

.plano-herramientas-filtros .mud-chip:active {
    transform: translateY(1px);
    box-shadow: var(--plano-tecla-hundida);
}

/* --- Los botones de toda la aplicación, con su relieve -------------------- */

/* LA FORMA: de píldora a 10 px, el mismo radio de los campos, para que un botón y
   una tecla de la tira se lean del mismo sistema. Alto y objetivos táctiles no se
   tocan: 40 px (48 por debajo de 768) siguen siendo los de siempre. */
.mud-button-root {
    border-radius: var(--plano-radio-control);
    transition: background-color var(--plano-tiempo) var(--plano-curva),
        color var(--plano-tiempo) var(--plano-curva),
        border-color var(--plano-tiempo) var(--plano-curva),
        box-shadow var(--plano-tecla-sube) var(--plano-curva),
        transform var(--plano-tecla-sube) var(--plano-curva);
}

/* EL PULSADO DEJA DE SER UNA ESCALA Y PASA A SER UN HUNDIDO. Escalar al 0,98
   encoge el rótulo y no dice «apretado»: dice «se aleja». Bajar 2 px y perder el
   canto sí lo dice, y es el mismo gesto en toda la aplicación. */
.mud-button-root:active:not(:disabled) {
    transform: translateY(var(--plano-canto));
    transition-duration: var(--plano-tiempo), var(--plano-tiempo),
        var(--plano-tiempo), var(--plano-tecla-baja), var(--plano-tecla-baja);
}

/* PRINCIPAL: canto en el morado hondo, que es su propia familia. */
.mud-button-filled:not(:disabled):not(.mud-disabled) {
    box-shadow: 0 2px 0 0 var(--plano-morado-honda);
}

/* Al pasar, el relleno YA es el morado hondo, así que el canto se iría con él: en
   hover baja a la berenjena honda, que es la tinta del sistema. */
.mud-button-filled:hover:not(:disabled) { box-shadow: var(--plano-tecla-canto-hondo); }

.mud-button-filled:active:not(:disabled) { box-shadow: var(--plano-tecla-hundida-honda); }

.mud-button-filled-error:not(:disabled):not(.mud-disabled) { box-shadow: 0 2px 0 0 #8e2a1b; }
.mud-button-filled-error:hover:not(:disabled) { box-shadow: var(--plano-tecla-canto-hondo); }

.mud-button-filled-secondary:not(:disabled):not(.mud-disabled),
.mud-button-filled-warning:not(:disabled):not(.mud-disabled) {
    box-shadow: var(--plano-tecla-canto-hondo);
}

/* SECUNDARIO (contorneado): canto de tinta al 22 %, y al pulsar se hunde con la
   aguada un punto más densa. */
.mud-button-outlined:not(:disabled):not(.mud-disabled) {
    box-shadow: 0 2px 0 0 rgba(42, 26, 62, 0.22);
}

.mud-button-outlined:active:not(:disabled) {
    box-shadow: var(--plano-tecla-hundida);
    background-color: var(--plano-morado-aguada-honda);
}

/* TERCIARIO (de texto): SIN CANTO. Un botón de texto no es una pieza, es una
   palabra; lo único que hace al pulsarlo es teñirse. */
.mud-button-text:not(:disabled):not(.mud-disabled) { box-shadow: none; }

.mud-button-text:active:not(:disabled) {
    transform: none;
    box-shadow: none;
    background-color: var(--plano-morado-aguada);
}

/* BOTON DE ICONO: redondo y sin canto —un círculo con una línea debajo se lee
   como un botón mal recortado— pero SI se hunde al pulsarlo. El radio se le
   devuelve aquí: un botón de icono es también un `.mud-button-root`, así que la
   regla de los 10 px de arriba le llegaba y lo dejaba en un cuadradito. */
.mud-icon-button { border-radius: var(--plano-pildora); }

.mud-icon-button:not(:disabled):not(.mud-disabled) { box-shadow: none; }

.mud-icon-button:active:not(:disabled) {
    transform: none;
    box-shadow: var(--plano-tecla-hundida);
}

/* DESHABILITADO: trama y ningún canto. Una tecla que no se puede pulsar no tiene
   por qué sobresalir. */
.mud-button-root:disabled,
.mud-button-root.mud-disabled { box-shadow: none; transform: none; }

/* LAS PASTILLAS DE PERIODO DE LA ANALITICA son teclas de la misma familia que la
   tira: la forma y el radio se los da su propia hoja (app.css), pero el RELIEVE
   tiene que venir de aquí, porque en el bloque de la analítica no entra ni una
   sombra que no sea la del tooltip. La elegida va ENCLAVADA, como la pantalla en
   la que se está; el canto de morado que le daría la regla del principal no vale,
   porque su relleno es de TINTA y no de morado. */
.admin-boton-periodo.mud-button-root[aria-pressed="true"] {
    transform: translateY(1px);
    box-shadow: var(--plano-tecla-hundida-honda);
}

/* LA LUPA DE UN TELEFONO NO LLEVA CANTO. En un escritorio «Buscar» es un botón
   contorneado de la fila y su canto es el de todos; en un teléfono el mismo botón
   se mete DENTRO del campo (§ de la barra de herramientas), sin fondo ni contorno,
   y un canto ahí dibuja media caja suelta sobre el relleno del campo. */
@media (max-width: 719.98px) {
    .crud-barra .crud-boton-buscar { box-shadow: none; }
    .crud-barra .crud-boton-buscar:active:not(:disabled) { box-shadow: none; }
}

/* LOS 2 px DEL CANTO, RESERVADOS EN EL LAYOUT. Ni la sombra ni el desplazamiento
   ocupan sitio, así que nada se mueve al pulsar; lo que sí pasa es que en una
   barra que recorta o que pega su siguiente pieza a ras, el canto se corta. Dos
   píxeles de relleno abajo en las dos barras de botones de la web lo evitan. */
.plano-herramientas,
.admin-cabecera-acciones { padding-block-end: var(--plano-canto); }

/* LA CABECERA DE PÁGINA EN EL TELÉFONO (2026-10-08; docs/central/responsivo-
   cabeceras-2026-10-08.md). Con la base de 8rem del §14, un botón con rótulo y
   dos iconos cabían al lado del título y lo dejaban en 130 px («Configuració /
   fiscal» en el iPhone). Por debajo de 600 px el título va a todo el ancho y las
   acciones en su fila: lo que lleva rótulo a la izquierda, los iconos al final
   (`order`) y el primero de ellos los empuja a la derecha. */
@media (max-width: 599.98px) {
    .plano-cuerpo .admin-cabecera-texto { flex: 1 1 100%; }

    .plano-cuerpo .admin-cabecera-acciones {
        flex: 1 1 100%;
        justify-content: flex-start;
    }

    .plano-cuerpo .admin-cabecera-acciones > :is(.mud-icon-button, .admin-refresco, .hoy-en-vivo) { order: 1; }

    .plano-cuerpo .admin-cabecera-acciones > :is(.mud-icon-button, .admin-refresco, .hoy-en-vivo):not(:is(.mud-icon-button, .admin-refresco, .hoy-en-vivo) ~ *) {
        margin-inline-start: auto;
    }

    /* La ayuda de una zona, a todo el ancho: los 34ch de `.plano-region-ayuda`
       son para la columna del rótulo de la rejilla de doce, que aquí no hay. */
    .plano-cuerpo .plano-region-ayuda { max-inline-size: var(--plano-prosa); }
}

/* EL MOVIMIENTO DE LAS TECLAS, ANULADO. Se va el DESPLAZAMIENTO y se quedan el
   canto, el hundido y la aguada: lo que dice el estado no se pierde. (Las fichas
   de tiempo las vacía §10, al final de la hoja, con todas las demás.) */
@media (prefers-reduced-motion: reduce) {
    :root { --plano-tecla-baja: 0.01ms; --plano-tecla-sube: 0.01ms; }

    .plano-pastilla:active,
    .plano-pastilla[aria-current],
    .plano-pastilla[aria-current]:active,
    .plano-herramientas-filtros .mud-chip:active { transform: none; }
}

/* El estado, como una luz. */
.plano-luz {
    inline-size: 8px;
    block-size: 8px;
    border-radius: 50%;
    flex: none;
    background-color: var(--plano-tinta-2);
}

.plano-luz-abierta { background-color: var(--plano-salvia); }
.plano-luz-atencion { background-color: var(--plano-mostaza-honda); }
.plano-luz-sin-conexion { background-color: var(--plano-arcilla-honda); }

/* 8.7 Móvil (los taburetes al pie se retiraron en D6: desde D2 los sustituye el cajón de la barra lateral) */

@media (max-width: 719.98px) {
    .plano-barra-marco { padding-inline: 8px; }
    .plano-barra { padding-inline: 0.75rem; gap: 0.5rem; }

    .plano-barra-instalacion, .plano-barra-codigo { display: none; }
    .plano-pase { max-inline-size: none; }
    .plano-pase-tecla { display: none; }
}

/* --- LOS OBJETIVOS DE UNA PANTALLA QUE SE TOCA, MEDIDOS (tanda 4) -----------
   El §6 del diseño pide 44 px de objetivo y el §4, botones de 48 en un móvil.
   Medido en el banco a 390 px sobre las trece escenas, se quedaban por debajo:
   las pastillas de la tira del área (34), los botones con rótulo (40), el nombre
   de una fila de listado (23) y las migas de una ficha (19). Aquí se suben, y se
   suben POR FAMILIA: una lista de excepciones por pantalla se queda coja en
   cuanto alguien añade una.

   EL CORTE SON 768 px Y NO 720 (auditoría responsiva, 2026-09-18). Los 720 son
   el corte de la TABLA —por debajo la fila se apila, por encima sigue siendo una
   tabla— y eso es una decisión de disposición. Un objetivo táctil no va de
   disposición: va de si la pantalla se toca, y una tableta de 768 px se toca
   igual que un teléfono. Medido a 768 px sobre las dieciocho escenas del banco
   responsivo, con el corte en 720 se quedaban por debajo de 44 las pastillas de
   la tira (34), el pase (38) y el logotipo (36) en TODAS las pantallas. */
@media (max-width: 768px) {
    .mud-button-root { min-height: var(--plano-toque-movil); }

    .plano-pastilla { min-block-size: var(--plano-toque); }

    /* EL NOMBRE DE UNA FILA: el relleno crece y el margen negativo lo devuelve,
       así que el objetivo mide 44 px y la fila NO cambia de alto. La fila entera
       ya lleva a la ficha; esto es para el que apunta al nombre. */
    .mud-table-body .crud-principal,
    .mud-table-body .mud-table-cell > .mud-link {
        display: inline-flex;
        align-items: center;
        justify-content: flex-start;
        /* Y ancho mínimo, que es lo que le faltaba: «Vinos» mide 41 px de ancho
           y un dedo no acierta en 41 px por mucho alto que tenga. */
        min-inline-size: var(--plano-toque);
        min-block-size: var(--plano-toque);
        padding-block: 0.6rem;
        margin-block: -0.6rem;
    }

    /* Las migas: mismo truco, y además ancho mínimo, porque una miga corta
       —«Carta»— mide 31 px de ancho y un dedo no acierta en 31 px. */
    .mud-breadcrumbs .mud-breadcrumb-item a,
    .plano-volver {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-block-size: var(--plano-toque);
        min-inline-size: var(--plano-toque);
    }

    /* El pase y el logotipo de la barra, que se quedaban en 38 y 36 px de alto. */
    .plano-pase,
    .plano-barra-logo { min-block-size: var(--plano-toque); }

    /* UN ENLACE SUELTO DENTRO DE UNA ZONA (§14, 2026-09-18). `d-inline-block` es
       la marca de MudBlazor para un enlace que va SOLO en su renglón, o sea uno
       que hace de acción y no de palabra dentro de una frase —hoy, el «Usuarios»
       de la ficha de una instalación, que medía 60 × 23 px—. El de dentro de un
       párrafo no entra aquí a propósito: subirle el alto partiría la línea. */
    .mud-link.d-inline-block {
        display: inline-flex;
        align-items: center;
        min-block-size: var(--plano-toque);
    }

    /* LA CABECERA ORDENABLE DE UN DIARIO: «Caja», «Base», «Total» y «Tipo» son
       rótulos de cuatro letras, así que el botón que los envuelve medía 39 px de
       ancho por 48 de alto. El ancho mínimo lo arregla sin tocar la tabla. */
    .informe-orden.mud-button-root,
    .admin-tabla-orden { min-inline-size: var(--plano-toque); }

    /* Y EL SELECTOR DE «filas por página», que MudBlazor deja en 37 px. */
    .mud-table-pagination-select,
    .mud-table-pagination .mud-input-root { min-inline-size: var(--plano-toque); }
}

/* Bajo 480 px, el pase se queda en la LUPA SOLA: con el logotipo intacto ahi el texto cabia en
   «Bu…», que dice menos que nada. El nombre sigue en el `aria-label`. */
@media (max-width: 479.98px) {
    .plano-pase-texto { display: none; }
    .plano-pase { flex: 0 0 auto; }
    .plano-mesas { display: none; }

    /* EL HUECO SE APRIETA A 8 px y no a los 12 del suelo de `--plano-cuerpo-hueco`
       (§1 de `docs/central/fichas-con-pestanas-y-ancho-2026-09-20.md`): en un
       teléfono cada píxel de ancho es una columna de tabla. Abajo, el aire y la
       muesca (`env(safe-area-inset-bottom)`) y nada más: la barra inferior de 48 px
       que había que reservar aquí —y en el aviso emergente, la barra de acciones de
       una ficha y el diálogo lateral, que se subían su alto— se fue con la barra
       lateral en D2, y su reserva se retiró en D6 (2026-11-08). */
    .plano-cuerpo {
        padding-inline: 8px;
        padding-block-end: calc(2.5rem + env(safe-area-inset-bottom, 0px));
    }
}

/* Gira sobre su bisagra. */

@keyframes plano-hoja-entra {
    from { transform: translateY(16px) rotateX(6deg); opacity: 0; }
    to { transform: none; opacity: 1; }
}

/* 9. PIEZAS COMUNES — cambia la piel, no la API (la 9.1, la cabecera `.plano-cabecera`, se retiró en D6: ninguna pantalla la pintaba) */

/* 9.2 LA BARRA DE HERRAMIENTAS DEL LISTADO
   ----------------------------------------
   En las capturas de la tanda 1 el buscador flotaba centrado —heredaba el
   `margin-inline: auto` del pase de la barra, donde sí toca— y las pastillas de
   filtro medían 16 px, que no es un objetivo ni de dedo ni de ratón.

   El orden es el de §4: BUSCAR a la izquierda, FILTROS a continuación, ACCION
   PRINCIPAL al final; se lee como se trabaja. Buscador de 40 px (48 en móvil),
   pastillas de 32 (40) y hueco de 8. */

.plano-herramientas {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-block-end: 1rem;
}

/* EL BUSCADOR, A LA IZQUIERDA Y CON SU LUPA. Aquí el pase NO se centra ni se
   estira hasta el infinito: es el primero de la fila y mide lo que necesita. */
.plano-herramientas .plano-pase {
    flex: 0 1 22rem;
    margin-inline: 0;
    min-block-size: 40px;
}

.plano-herramientas-filtros { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* Las pastillas de filtro, con alto de verdad. `min-height` en el chip de Mud y
   no en un envoltorio: el que recibe el clic es el chip. */
.plano-herramientas-filtros .mud-chip {
    min-block-size: 32px;
    padding-inline: 0.85rem;
}

.plano-herramientas-fin { margin-inline-start: auto; display: flex; align-items: center; gap: 0.5rem; }

@media (max-width: 719.98px) {
    /* En un móvil el buscador ocupa la fila entera y sube a 48 px: es el control
       que más se usa de la pantalla y el pulgar no acierta en 40. Y NO se queda
       en la lupa sola, que es lo que hace el pase de la barra por falta de
       sitio: aquí hay una fila para él. */
    .plano-herramientas .plano-pase {
        flex: 1 1 100%;
        min-block-size: var(--plano-toque-movil);
    }

    .plano-herramientas .plano-pase .plano-pase-texto { display: block; }
    .plano-herramientas-filtros .mud-chip { min-block-size: 40px; }
    .plano-herramientas-fin { margin-inline-start: 0; }
}

/* 9.3 LA PORTADA «HOY»: EL PLANO VIVO
   -----------------------------------
   Una SALA por establecimiento y, al lado, «Lo que pide atención». El peso de
   cada sala lo decide su venta de hoy y lo escribe la página en
   `--plano-local-ancho` (§3 y la cabecera de Pages\Admin.razor): va en una ficha
   en línea y no en una clase por tamaño porque sale de una cuenta. */

.plano-hoy {
    display: grid;
    /* Las salas mandan; «Lo que pide atención» es una columna fija a la derecha
       porque es una lista de texto y con `1fr` crecería hasta partir las frases
       por sitios raros. */
    grid-template-columns: minmax(0, 1fr) 20rem;
    gap: 1.5rem;
    align-items: start;
    margin-block-end: 2rem;
}

/* UNA REJILLA DE DOCE CON COLOCACION EXPLICITA Y MUROS COMPARTIDOS (tanda 4).
   -------------------------------------------------------------------------
   La tanda 3 repartía el ancho con `flex-grow` y separaba las salas con 16 px de
   hueco. Salía una FILA DE TARJETAS CON CIFRA, y por dos motivos: todas las salas
   medían lo mismo de alto -sólo cambiaba el ancho- y entre dos había aire, o sea
   dos rectángulos independientes en vez de dos habitaciones de un mismo plano.

   Ahora: rejilla de doce columnas y filas implícitas de `--plano-sala-fila`, y
   la página escribe la COLOCACION de cada sala (columna, ancho, fila y alto) en
   cuatro fichas en línea. El reparto es un mosaico de dos niveles -la mayor a la
   izquierda ocupando todas las filas, las demás apiladas a su derecha- y lo
   calcula `Colocar` en Pages\Admin.razor, que es donde están las ventas.

   HUECO CERO: entre dos salas contiguas hay UN SOLO MURO. Cada sala pinta su
   muro izquierdo y su muro de abajo; los dos que faltan para cerrar el plano
   -arriba y a la derecha- los pinta el contenedor. Así el muro entre la sala A y
   la B es el muro izquierdo de B y nada más: como en un plano de verdad, donde
   dos habitaciones contiguas comparten pared.

   SIN RADIO EN EL CONTENEDOR, y es una desviación anotada (§11): la esquina de
   muro pide `overflow: hidden` para que las salas cuadradas no asomen por las
   esquinas redondeadas, y ese recorte se comería los rótulos de la primera fila,
   que van MONTADOS sobre la línea del muro. El plano de un edificio es un
   rectángulo; la esquina de muro se queda en las zonas, las fichas y la hoja. */
.plano-hoy-salas {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    grid-auto-rows: minmax(var(--plano-sala-fila), auto);
    gap: 0;
    min-inline-size: 0;
    /* Aire para el rótulo de la primera fila, que sobresale medio renglón. */
    margin-block-start: 0.6rem;
    border-block-start: 2px solid var(--plano-muro);
    border-inline-end: 2px solid var(--plano-muro);
}

/* UNA SALA: una habitación del plano, colocada por la página y con dos muros
   propios —el izquierdo y el de abajo—, que son los que comparte con sus
   vecinas. Los otros dos lados NO se pintan: el de arriba es el muro de abajo de
   la sala de encima (o el cierre del contenedor) y el de la derecha es el muro
   izquierdo de la de al lado (o el cierre del contenedor). Dos habitaciones
   contiguas comparten pared; dibujar las dos es dibujar un tabique doble.

   La sala NO lleva radio, por lo mismo que no lo lleva el contenedor: una
   habitación interior de un plano no tiene las esquinas redondeadas. */
.plano-local {
    grid-column: var(--plano-local-col, auto) / span var(--plano-local-ancho, 6);
    grid-row: var(--plano-local-fila, auto) / span var(--plano-local-alto, 1);
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    min-inline-size: 0;
    padding: 1.6rem 1.35rem 1.25rem;
    background-color: var(--plano-hoja);
    /* EL MURO IZQUIERDO VUELVE A SER UN BORDE (tanda 5): el vano se muda al muro
       de abajo, que es el único tramo que queda libre de mesas una vez que las
       mesas son una distribución y no una fila. */
    border-inline-start: 2px solid var(--plano-muro);
    /* Transparente y no `none`: el muro de abajo lo pinta `.plano-local-vano` con
       su hueco, y el borde sigue RESERVANDO los 2 px para que las salas de una
       misma columna se alineen al píxel. */
    border-block-end: 2px solid transparent;
    /* SE ENTINTA AL LLEGAR EL DATO: la sala se pinta en cuanto se sabe que
       existe y toma su color cuando llegan las cifras. 240 ms, lo que §5 le da a
       un cambio de estado; lo anula la ficha de tiempo. */
    transition: background-color var(--plano-tiempo-largo) var(--plano-curva),
        border-color var(--plano-tiempo-largo) var(--plano-curva);
}

/* EL MURO QUE CARGA, CON SU VANO. Nunca es un trozo de papel puesto ENCIMA de la
   línea para taparla —eso tenía dos defectos: sobre una sala tramada el papel se
   veía como una mancha clara, y el hueco dependía de que el fondo del hijo fuera
   igual al del padre, que con `background-image` nunca lo es—. El muro lo pinta
   este elemento con un DEGRADADO que tiene un tramo transparente: el vano es un
   hueco de verdad y funciona igual sobre papel, sobre aguada y sobre trama.

   EL VANO SE MUDA AL MURO DE ABAJO (tanda 5). Estaba en el muro IZQUIERDO, y la
   revisión de acabado lo cazó chocando con la primera mesa: en cuanto las mesas
   dejan de ser una fila pegada al muro de abajo y pasan a ser una DISTRIBUCION
   que ocupa el suelo, el tramo bajo del muro izquierdo es justo donde hay gente
   sentada. El muro de abajo es el otro muro que pinta la sala —o sea el otro que
   COMPARTE: con sus vecinas de la misma columna en escritorio, y con la sala
   siguiente cuando el plano se apila en un móvil—, y su tramo derecho es el único
   que queda libre, porque la distribución de mesas le reserva su banda
   (`.plano-local-mesas`, `padding-inline-end`) y porque la línea de ocupación
   subió por encima de las mesas para dejar el suelo limpio. */
.plano-local-vano {
    position: absolute;
    inset-inline: -2px 0;
    inset-block-end: -2px;
    block-size: 2px;
    background-image: linear-gradient(
        to right,
        var(--plano-muro) 0 calc(100% - 4.8rem),
        transparent calc(100% - 4.8rem) calc(100% - 2.4rem),
        var(--plano-muro) calc(100% - 2.4rem) 100%);
}

/* EL ARCO DE BARRIDO: el cuarto de círculo que describe la hoja al abrirse,
   desde la jamba hasta el quicio. Dos bordes, un radio y NINGUN RELLENO —ni
   `background-color` ni `background-image`—: sobre una sala tramada lo que se
   ve es la línea del arco y la trama por debajo, nunca un cuarto de círculo de
   papel. El quicio es la jamba derecha y la hoja barre hacia dentro. */
.plano-local-vano::after {
    content: "";
    position: absolute;
    inset-inline-end: 2.4rem;
    inset-block-end: 2px;
    inline-size: 2.4rem;
    block-size: 2.4rem;
    background: none;
    border-block-start: 1.5px solid var(--plano-linea);
    border-inline-start: 1.5px solid var(--plano-linea);
    border-start-start-radius: 100%;
}

/* EL ROTULO DEL LOCAL, MONTADO SOBRE EL MURO DE ARRIBA, como la etiqueta de una
   habitación en un plano de interiorismo: sale de la caja, se sienta encima de
   la línea y se come el trozo que ocupa. Es el detalle que más separa «esto es
   un plano» de «esto es una tarjeta con un título dentro». */
.plano-local-cabecera {
    position: absolute;
    inset-block-start: -0.55rem;
    inset-inline-start: 1.1rem;
    max-inline-size: calc(100% - 2.2rem);
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-inline-size: 0;
    padding-inline: 0.4rem;
    /* El rótulo tapa el muro con el papel DE SU SALA. La IMAGEN también se
       hereda: sin ella, en una sala tramada el rótulo salía sobre una placa lisa
       —el mismo defecto que tenía el vano— en vez de sobre la trama. */
    background-color: inherit;
    background-image: inherit;
}

/* El nombre en rótulo condensado: es la etiqueta de la habitación, no un
   título. La cifra es lo que se lee primero. */
.plano-local-nombre {
    font-size: var(--plano-t-12);
    font-weight: 600;
    font-stretch: 75%;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--plano-tinta-2);
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* LA LUZ ENCENDIDA de una sala abierta: un punto de salvia con su halo, que late
   UNA vez al cargar y se queda quieto. Siete luces en bucle convierten la portada
   en un árbol de Navidad, y un latido perpetuo dice «esto acaba de pasar» cada
   segundo, que es falso. */
.plano-local-luz {
    inline-size: 9px;
    block-size: 9px;
    border-radius: 50%;
    flex: none;
    background-color: var(--plano-salvia-viva);
    box-shadow: 0 0 0 0 var(--plano-salvia-aguada-honda);
    animation: plano-luz-enciende 1400ms var(--plano-curva) 1;
}

@keyframes plano-luz-enciende {
    0% { box-shadow: 0 0 0 0 var(--plano-salvia-aguada-honda); }
    60% { box-shadow: 0 0 0 7px rgba(47, 143, 131, 0); }
    100% { box-shadow: 0 0 0 0 rgba(47, 143, 131, 0); }
}

/* LA CIFRA DE CARTEL, DE VERDAD (tanda 4). La tanda 3 la dejaba en 3,4vw, o sea
   49 px a 1.440: más grande que el cuerpo, sí, pero NO la tipografía más grande
   de la página con margen —el título de la portada mide 28— y desde luego no un
   cartel. Ahora 5vw, que son 72 px a 1.440, con el mínimo en 56 y el máximo en
   72. `cqi` pediría un contenedor de consulta por sala; con `vw` la cifra
   depende de la ventana, y a más ventana más ancha es cada sala. */
.plano-local-cartel {
    font-size: clamp(var(--plano-t-56), 5vw, var(--plano-t-72));
    line-height: 1;
    margin: 0.35rem 0 0;
    max-inline-size: 100%;
}

/* Una sala ANCHA (la única del negocio) se permite el peldaño de 88, que es
   justo para lo que está en la escala. La clase la pone la página junto con el
   ancho: leer el número desde un selector de atributo dependería de cómo se
   escriba el estilo en línea, espacio incluido. */
.plano-local-ancha .plano-local-cartel {
    font-size: clamp(var(--plano-t-64), 6.2vw, var(--plano-t-88));
}

/* LA SALA MENOR —una fila de alto y un tercio de ancho o menos— baja al peldaño
   de 56, que es lo que el encargo le permite: en 290 px de habitación, «128.451
   €» a 72 px se saldría por la derecha. Sigue siendo cartel y sigue siendo lo
   más grande de su sala. La clase la pone la página con la colocación. */
.plano-local-menor .plano-local-cartel {
    font-size: clamp(var(--plano-t-40), 4vw, var(--plano-t-56));
}

.plano-local-linea {
    margin: 0;
    font-size: var(--plano-t-13);
    color: var(--plano-tinta-2);
    font-variant-numeric: tabular-nums;
}

/* LA COTA, dibujada como en un plano: una línea con sus dos topes y el número
   al lado. Los topes son los `::before` y `::after` de la línea, así que la
   cota entera son dos elementos y ninguna imagen. */
.plano-local-cota {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0.2rem 0 0;
    font-size: var(--plano-t-13);
    font-weight: 560;
    font-variant-numeric: tabular-nums;
}

.plano-local-cota-linea {
    position: relative;
    inline-size: 2.25rem;
    block-size: 1px;
    flex: none;
    background-color: currentcolor;
}

.plano-local-cota-linea::before,
.plano-local-cota-linea::after {
    content: "";
    position: absolute;
    inset-block: -4px;
    inline-size: 1px;
    background-color: currentcolor;
}

.plano-local-cota-linea::before { inset-inline-start: 0; }
.plano-local-cota-linea::after { inset-inline-end: 0; }

.plano-local-cota-sube { color: var(--plano-salvia); }
.plano-local-cota-baja { color: var(--plano-arcilla-honda); }
.plano-local-cota-sin { color: var(--plano-tinta-2); font-weight: 420; }

/* La frase del estado: sólo la llevan las salas que NO están abiertas. */
.plano-local-aviso {
    margin: 0.2rem 0 0;
    font-size: var(--plano-t-13);
    color: var(--plano-tinta-2);
}

/* LA FRASE DE UNA SALA SIN CONEXION VA SOBRE UNA PLACA DE PAPEL SOLIDA (tanda 4).
   Esa sala está tramada, y arcilla sobre una trama de tinta al 20 % pierde el
   contraste justo donde más falta hace: es la única sala que pide que vayas a
   hacer algo. La placa es papel opaco por encima de la trama —`--plano-hoja`,
   donde la arcilla honda da 5,56:1— y de paso separa la frase del dibujo. */
.plano-local-sin-conexion .plano-local-aviso {
    color: var(--plano-arcilla-honda);
    font-weight: 560;
    align-self: flex-start;
    max-inline-size: 100%;
    padding: 0.3rem 0.6rem;
    border-radius: var(--plano-radio-control);
    background-color: var(--plano-hoja);
}

/* LAS MESAS: UNA DISTRIBUCION DE COMEDOR (tanda 5).
   -------------------------------------------------
   Hasta la tanda 3 eran una fila de puntos de 12 px pegada bajo la cota: un
   indicador, no un dibujo. La tanda 4 las metió dentro de la sala, pero seguían
   siendo UNA FILA —once mesas a lo ancho, pegadas al muro de abajo, con 300 px
   de aguada vacía por encima—, y eso lo cazó la revisión de acabado: un comedor
   no tiene todas las mesas contra la pared del fondo.

   Ahora son una REJILLA AL TRESBOLILLO que usa el alto Y el ancho libres del
   suelo. Las columnas las cuenta la página (`ColumnasDeMesas` en
   Pages\Admin.razor) a partir de cuántas mesas hay y de la proporción de la
   habitación, y las escribe en `--plano-local-mesas-col`: la cuenta necesita
   saber cuántas mesas hay y cuánto mide la sala en la rejilla de doce, y las dos
   cosas están en la página, no aquí.

     · `flex: 1 1 auto` le da TODO el suelo que queda bajo el texto;
     · `align-content: center` y `justify-content: center` centran la
       distribución en ese suelo, que es lo que hace que la sala respire igual
       por arriba que por abajo;
     · las filas impares van CORRIDAS media plaza (`plano-local-mesa-corrida`, la
       pone también la página porque hay que saber en qué fila cae cada mesa):
       eso es el tresbolillo, y es lo que separa un comedor de una cuadrícula;
     · `padding-inline-end` reserva la banda del VANO del muro de abajo, para que
       ninguna mesa se siente en el barrido de la puerta.

   Siguen siendo la CUENTA y no un indicador: veintiuna mesas abiertas son
   veintiún dibujos, con el tope en 24 y «+N» para el resto. */
.plano-local-mesas {
    display: grid;
    grid-template-columns: repeat(var(--plano-local-mesas-col, 4), minmax(var(--plano-mesa-paso), 1fr));
    justify-items: center;
    justify-content: center;
    align-content: center;
    gap: 1.15rem 0.6rem;
    flex: 1 1 auto;
    min-block-size: 0;
    padding-block: 1rem 0.5rem;
    /* La banda del vano: 2,4 rem de hueco más 2,4 de barrido, menos el relleno
       que ya pone la sala. Sin ella, la mesa de la esquina se sienta en la
       puerta, que es el choque que la revisión encontró en el muro izquierdo. */
    padding-inline-end: 3.6rem;
}

/* La casilla de una plaza. El TABLERO lo dibuja el `::before` centrado en ella:
   así la celda puede estirarse con el ancho de la sala y el dibujo se queda del
   tamaño que tiene una mesa. */
.plano-local-mesa {
    position: relative;
    inline-size: 100%;
    block-size: 15px;
}

/* El tablero. OCUPADA = RELLENA DE TINTA, que es lo que significa aquí: cada
   mesa dibujada es un ticket abierto. */
.plano-local-mesa::before {
    content: "";
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 50%;
    margin-inline-start: -7.5px;
    inline-size: 15px;
    block-size: 15px;
    border-radius: 50%;
    background-color: var(--plano-tinta);
    /* LAS SILLAS: sombras redondas con radio negativo, que es un círculo pequeño
       a distancia del tablero. Sale más barato que cuatro elementos y que una
       imagen, y es el mismo dibujo. Cuántas hay lo dice la clase del contenedor;
       cuatro es lo que se dibuja cuando no hay dato de comensales. */
    box-shadow:
        0 -11px 0 -5px var(--plano-tinta-2),
        0 11px 0 -5px var(--plano-tinta-2),
        -11px 0 0 -5px var(--plano-tinta-2),
        11px 0 0 -5px var(--plano-tinta-2);
}

/* MESAS DE DOS, DE CUATRO Y DE SEIS. Cuántas sillas lleva una mesa sale del dato
   y no de la estética: comensales entre tickets abiertos, redondeado, con el
   tope en seis que pide el encargo. Sin comensales se dibujan cuatro, que es la
   mesa de referencia de un comedor, y no se inventa ningún número. */
.plano-local-mesas-2 .plano-local-mesa::before {
    box-shadow:
        -11px 0 0 -5px var(--plano-tinta-2),
        11px 0 0 -5px var(--plano-tinta-2);
}

/* Seis: las seis plazas del hexágono, a 60° una de otra. */
.plano-local-mesas-6 .plano-local-mesa::before {
    box-shadow:
        0 -11px 0 -5px var(--plano-tinta-2),
        0 11px 0 -5px var(--plano-tinta-2),
        -9.5px -5.5px 0 -5px var(--plano-tinta-2),
        -9.5px 5.5px 0 -5px var(--plano-tinta-2),
        9.5px -5.5px 0 -5px var(--plano-tinta-2),
        9.5px 5.5px 0 -5px var(--plano-tinta-2);
}

/* EL TRESBOLILLO: media plaza de corrimiento en las filas impares. Es fijo en
   rem y no la mitad de la celda a propósito: la celda se estira con la sala y un
   corrimiento del 50 % sacaría la última mesa de la habitación. */
.plano-local-mesa-corrida { transform: translateX(1.1rem); }

/* El «+N» cierra la distribución en su propio renglón, centrado: es un texto y
   no una mesa, así que no se sienta en una plaza. */
.plano-local-mesa-mas {
    grid-column: 1 / -1;
    justify-self: center;
    font-size: var(--plano-t-13);
    font-weight: 600;
    font-stretch: 75%;
    color: var(--plano-tinta-2);
    font-variant-numeric: tabular-nums;
}

/* LA LINEA DE OCUPACION VA ENCIMA DE LAS MESAS (tanda 5), no debajo: es el pie
   de foto del dibujo, y dejándola abajo el suelo de la habitación se partía en
   dos y el barrido de la puerta caía justo detrás del texto. */
.plano-local-ocupacion {
    margin: 0.4rem 0 0;
    font-size: var(--plano-t-13);
    color: var(--plano-tinta-2);
    font-variant-numeric: tabular-nums;
}

/* --- Los cuatro estados físicos de una sala (§3) ------------------------- */

/* LOS CUATRO ESTADOS SON CUATRO, Y NINGUNO DEPENDE DE LA COTA (tanda 4). Una
   sala ABIERTA que hoy va por debajo del mismo día de la semana pasada sigue
   siendo una sala abierta: su papel es el de cualquier sala abierta y quien
   cuenta la mala noticia es la COTA, en arcilla, que para eso está. La arcilla
   es el error, lo cerrado y lo que no contesta —nada más—, y la mostaza es la
   atención: sólo la lleva una sala que está cerrando o que sale nombrada en «Lo
   que pide atención». Un plano en el que el papel cambia de color por vender un
   12 % menos que el jueves pasado es un semáforo, no un plano. */

/* ABIERTA: aguada de salvia. El color posee la región. */
.plano-local-abierta { background-color: color-mix(in srgb, var(--plano-salvia-viva) 7%, var(--plano-hoja)); }

/* CERRANDO: mostaza. Ha trabajado y ya no queda nadie sentado.
   DOS ARREGLOS DE LA TANDA 5, porque la revisión leyó esta sala como un error:
   la aguada usa `--plano-mostaza-sala` —el matiz en 97, amarillo y no ámbar— en
   vez del melocotón que salía del ámbar al 12 %, y el estado se DICE con todas
   las letras en el rótulo del muro (abajo), que es lo único que quita del todo
   la duda de si un papel de color es una noticia buena o mala. */
.plano-local-cerrando { background-color: color-mix(in srgb, var(--plano-mostaza-sala) 14%, var(--plano-hoja)); }

/* LA MARCA DE ESTADO EN EL ROTULO DEL MURO: un punto del color del estado y la
   palabra, al lado del nombre del local. El color solo nunca vale (WCAG 1.4.1) y
   aquí además no basta con que valga: hace falta que no se malinterprete. */
.plano-local-marca {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    flex: none;
    font-size: var(--plano-t-11);
    font-weight: 600;
    font-stretch: 75%;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--plano-tinta-2);
}

.plano-local-marca-punto {
    inline-size: 7px;
    block-size: 7px;
    border-radius: 50%;
    flex: none;
    background-color: var(--plano-mostaza-honda);
}

/* SIN CONEXION: contorno DISCONTINUO y trama. El muro deja de ser muro, que es
   exactamente lo que ha pasado: esa sala ya no se sabe si existe. Con los muros
   compartidos de la tanda 4 se sueltan los DOS que pinta la sala; los otros dos
   son de la vecina y no se tocan, porque el que no contesta es este local. */
.plano-local-sin-conexion {
    background-image: var(--plano-trama);
    border-inline-start: 2px dashed var(--plano-arcilla-honda);
}

/* Y el muro que pinta el degradado —el de abajo— se vuelve arcilla, con su vano:
   el hueco sigue siendo hueco. El degradado va a tramos DISCONTINUOS por el
   mismo motivo que el otro muro, y el arco sigue sin relleno: sobre la trama lo
   único que se ve es su línea. */
.plano-local-sin-conexion .plano-local-vano {
    background-image:
        repeating-linear-gradient(to right, var(--plano-arcilla-honda) 0 6px, transparent 6px 10px),
        repeating-linear-gradient(to right, var(--plano-arcilla-honda) 0 6px, transparent 6px 10px);
    background-size: calc(100% - 4.8rem) 100%, 2.4rem 100%;
    background-position: left center, right center;
    background-repeat: no-repeat, no-repeat;
}

.plano-local-sin-conexion .plano-local-vano::after {
    background: none;
    border-color: var(--plano-arcilla-honda);
}

/* UNA SALA SIN CIFRA COLOCA LO QUE TIENE EN MEDIO (tanda 5). Es la del local que
   no contesta: no hay cartel, no hay cota y no hay mesas, sólo la frase que dice
   desde cuándo no se sabe nada. Pegada arriba dejaba dos tercios de habitación
   por debajo y se leía como una caja a medio llenar; en medio se lee como lo que
   es, la ETIQUETA DE UNA HABITACION VACIA en un plano, con su trama alrededor.

   El mosaico llena el rectángulo y no deja huecos —es lo que pidió la tanda 4—,
   así que en una columna de dos habitaciones las dos miden lo que manda la sala
   grande de al lado: el alto de ésta no se puede recortar sin abrirle un hueco al
   plano. Lo que sí se puede es que su suelo esté DIBUJADO, y la trama lo dibuja. */
.plano-local:not(:has(.plano-local-cartel)) { justify-content: center; }

/* SIN VENTAS: trama suave y nada más. Ni rojo ni amarillo: que un local no haya
   vendido todavía no es un fallo, y a las ocho de la mañana es lo normal. */
.plano-local-sin-ventas { background-image: var(--plano-trama-suave); }

.plano-local-sin-ventas .plano-local-cartel { color: var(--plano-tinta-2); }

/* EL ESQUELETO: la habitación en línea discontinua, sin entintar. No lleva vano
   —todavía no se sabe si esa habitación existe ni por dónde se entra—, así que
   sus dos muros son bordes y los dos van discontinuos. */
.plano-local-esqueleto {
    background-color: transparent;
    border-inline-start: 2px dashed var(--plano-linea);
    border-block-end: 2px dashed var(--plano-linea);
}

/* --- «Lo que pide atención» ---------------------------------------------- */

/* PEGAJOSA Y CORTA (tanda 3, retoque 4). A 1.440 px esta columna mide cuatro o
   cinco renglones y las salas de al lado, 400 px de alto: debajo de la lista
   quedaba un palmo de papel en blanco a la derecha de la portada. Ahora la
   columna se queda pegada bajo la barra al desplazar —así sigue a la vista
   mientras se recorren las salas, que es justo lo que una lista de «esto hay que
   mirarlo» tiene que hacer— y el hueco deja de ser hueco: es aire alrededor de
   algo que se mueve con la página.

   EL ALTO DEL MARCO SE MIDE Y YA NO SE ADIVINA (§14, 2026-09-18). Los 9,5rem de
   respaldo son la barra (64) más los taburetes (48) más el aire de los bordes y
   un respiro, y valían mientras la tira del área medía siempre una fila; con la
   tira envuelta en dos el marco mide 56 px más y la columna se pegaba por debajo
   de donde acaba la franja. `--plano-marco-alto` lo escribe `medirMarco` de
   wwwroot\js\plano.js con un `ResizeObserver` sobre la franja. El respaldo se
   queda para el banco estático, donde no hay JavaScript y el marco no cambia. */
.plano-hoy-atencion {
    position: sticky;
    inset-block-start: var(--plano-marco-alto, 9.5rem);
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    padding-inline-start: 1.25rem;
    /* Una regla fina la separa de las salas en vez de una caja: es una columna
       de texto al margen del plano, como la leyenda de un plano de verdad. */
    border-inline-start: 1px solid var(--plano-linea-fina);
}

.plano-hoy-atencion .plano-rotulo { margin: 0; }

.plano-atencion-lista { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }

/* Cada línea es un ENLACE a donde se arregla: una lista de atención que no
   lleva a ningún sitio es una lista de quejas. */
.plano-atencion-fila {
    display: flex;
    align-items: flex-start;
    gap: 0.55rem;
    min-block-size: var(--plano-toque);
    /* Sin sangrado negativo: sacaba la fila 6 px de su columna por cada lado, y
       eso es desbordar. Lo cazó la medición del banco. */
    padding: 0.5rem 0.4rem;
    border-radius: var(--plano-radio-control);
    color: var(--plano-tinta);
    text-decoration: none;
    font-size: var(--plano-t-13);
    line-height: 1.4;
    transition: background-color var(--plano-tiempo) var(--plano-curva);
}

.plano-atencion-fila:hover { background-color: var(--plano-morado-aguada); }
.plano-atencion-fila .plano-luz { margin-block-start: 0.4rem; }

/* `min-inline-size: 0` deja al elemento de flex encogerse por debajo de su
   contenido —sin eso no envuelve— y `overflow-wrap` parte antes de desbordar. */
.plano-atencion-texto { min-inline-size: 0; overflow-wrap: anywhere; }

/* --- Los cortes ---------------------------------------------------------- */

/* Por debajo de 1.024 px «Lo que pide atención» baja debajo de las salas y cada
   sala ocupa el ancho: a media pantalla, una sala de cuatro columnas son 180 px
   y ahí no cabe ni la cifra de cartel ni el nombre del local. */
@media (max-width: 1023.98px) {
    .plano-hoy { grid-template-columns: minmax(0, 1fr); }

    /* EL MOSAICO SE DESHACE Y LAS SALAS SE APILAN, en el orden de la venta. La
       colocación en línea deja de mandar: una habitación de cuatro doceavos a
       390 px son 130 px y ahí no cabe ni el nombre del local. Siguen sin hueco
       entre ellas —un muro entre dos— y el contenedor sigue cerrando el plano. */
    .plano-hoy-salas {
        grid-template-columns: minmax(0, 1fr);
        grid-auto-rows: auto;
    }

    .plano-local {
        grid-column: 1 / -1;
        grid-row: auto;
        /* Apiladas, el muro que comparten es el de ABAJO, que es justo donde la
           tanda 5 puso el vano: el paso de una sala a la siguiente. */
        min-block-size: 9.5rem;
    }

    /* EN UN MOVIL LAS COLUMNAS NO CAMBIAN, y es a propósito: quien decide cuáles
       son las filas impares —las que van corridas— es la página, así que cambiar
       aquí el número de columnas dejaría el tresbolillo desordenado, que se lee
       peor que una cuadrícula. La celda es `minmax(2,2rem, 1fr)` y a 390 px una
       sala de seis columnas todavía da 45 px por plaza: caben. Lo que sí se
       estrecha es la banda del vano, que aquí cuesta un sexto del ancho. */
    .plano-local-mesas { padding-inline-end: 3rem; }

    .plano-local-cartel,
    .plano-local-ancha .plano-local-cartel,
    .plano-local-menor .plano-local-cartel { font-size: var(--plano-t-56); }

    .plano-hoy-atencion {
        /* Debajo de las salas, la columna deja de pegarse: pegada a media
           pantalla taparía la sala que se está mirando. */
        position: static;
        padding-inline-start: 0;
        padding-block-start: 1.25rem;
        border-inline-start: none;
        border-block-start: 1px solid var(--plano-linea-fina);
    }
}

/* DE 1.024 A 1.439 px el mosaico se mantiene entero: la rejilla de doce no
   necesita sitio mínimo por sala como lo necesitaba el `flex-basis` de la tanda
   3, así que las proporciones aguantan hasta el corte de abajo. Lo que se
   estrecha es la sala menor, y por eso su cifra baja al peldaño de 56.

   A PARTIR DE 1.440 px la columna de atención se estrecha de 20 a 16 rem: medido
   en el banco, el cuerpo da 1.290 px y con 20 rem a las salas les quedaban 936.
   Con 16 rem quedan 1.000, que es lo que el mosaico necesita para que la sala
   menor —cuatro doceavos— no baje de 290 px de habitación. */
@media (min-width: 1440px) {
    .plano-hoy { grid-template-columns: minmax(0, 1fr) 16rem; }
}

/* LAS VENTAS POR HORA, DEBAJO DEL PLIEGUE (tanda 4). El encargo de la revisión
   de acabado da dos salidas —bajar el gráfico de la primera pantalla o dejarlo
   en una franja de 180 px— y se toma la primera: el plano manda el primer
   pantallazo a 1440×900 y el gráfico se ve al desplazar. La regla fina de arriba
   es lo que dice «esto ya no es el plano». */
.plano-hoy-horas {
    margin-block-start: 2.5rem;
    padding-block-start: 1.5rem;
    border-block-start: 1px solid var(--plano-linea-fina);
}

/* 9.4 El vacío: dibujo y frase útil */

.plano-vacio {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 0.75rem;
    padding: 3rem 1.5rem;
    color: var(--plano-tinta-2);
}

.plano-vacio .plano-motivo { color: var(--plano-linea); }
.plano-vacio-frase { font-size: var(--plano-t-17); color: var(--plano-tinta); margin: 0; max-inline-size: 42ch; }
.plano-vacio-ayuda { font-size: var(--plano-t-13); margin: 0; max-inline-size: 48ch; }

/* ---------------------------------------------------------------------------
   9.5 LAS ZONAS DE UNA FICHA (§4) — el barrido de la tanda 3
   ---------------------------------------------------------------------------
   `PanelWidget` y `Zona` pintan una `<section class="plano-region">`. Aquí se
   decide qué es esa región en cada contexto, que es lo que permite que 219
   paneles y 48 fichas cambien de forma sin tocar una pantalla.

   FUERA DE UNA FICHA (un widget del panel, un gráfico, una tabla suelta) el
   rótulo se queda ENCIMA: lo de debajo ocupa el ancho entero y un rótulo a la
   izquierda dejaría tres doceavos en blanco a lo largo de toda una tabla.

   DENTRO DE UNA FICHA (`.crud-secciones`) entra la rejilla de doce del §4:
   rótulo 3, campos 9. Es donde el patrón gana algo —la vista recorre los
   rótulos por la izquierda y encuentra el grupo sin leer los campos— y donde el
   diseño lo pide con todas las letras. */

/* EL ROTULO VA A LA IZQUIERDA, Y HAY QUE DECIRLO (lo enseñó la primera captura
   de la tanda 3): este mismo elemento lleva también `.admin-panel-cabecera`,
   que es una fila con `align-items: center` y `justify-content: space-between`.
   Al ponerlo en columna, ese `center` deja de centrar verticalmente y pasa a
   centrar HORIZONTALMENTE: el rótulo salía en medio de su columna y la frase de
   ayuda, debajo y a la izquierda, porque ocupa el ancho entero. Dos cosas del
   mismo bloque alineadas de distinta forma. */
.plano-region-rotulo {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    text-align: start;
    gap: 0.35rem;
    min-inline-size: 0;
}

/* El rótulo de una zona manda sobre el peso que MudBlazor da a un `h2`. */
.plano-region-rotulo .admin-panel-titulo,
.plano-region-rotulo .plano-rotulo { margin: 0; }

.plano-region-ayuda {
    margin: 0;
    font-size: var(--plano-t-13);
    color: var(--plano-tinta-2);
    max-inline-size: 34ch;
}

/* Las acciones de la zona, bajo su rótulo y no flotando a la derecha del ancho
   entero: en la rejilla de doce, «a la derecha» son los campos. */
.plano-region-rotulo .admin-panel-acciones {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    margin-block-start: 0.15rem;
}

/* LA REJILLA DE DOCE, EN TODA LA FICHA (tanda 5, punto 2c). El ámbito pasa de
   `.crud-secciones` —un envoltorio OPCIONAL: en la ficha de producto envuelve
   DOS de sus catorce zonas y las otras doce se quedaban sin rejilla— a
   `.crud-ficha`, el `MudForm` de `CrudFicha` y el cuerpo de las 48. El primero
   se queda porque el ESQUELETO se pinta fuera y tiene que medir igual.

   EL ROTULO MIDE LO QUE MIDE UN ROTULO (§1 de
   `docs/central/fichas-con-pestanas-y-ancho-2026-09-20.md`). Con `3fr 9fr` la
   columna del rótulo crecía con la página: a 1.900 px eran 475 px para dos
   palabras y una frase de ayuda de 34ch. Desde que el cuerpo no tiene tope eso se
   volvió absurdo, así que la proporción se cambia por una MEDIDA:
   `minmax(12rem, 16rem)` —entre 192 y 256 px— y todo lo que sobra son campos. El
   `minmax(0, 1fr)` de la segunda columna es el que deja encoger lo que desborda
   (una tabla ancha), que con `1fr` a secas no se puede. Por debajo de 900 px sigue
   en una columna, como hoy. */
.crud-ficha .plano-region-conrotulo,
.crud-secciones > .plano-region-conrotulo,
.crud-secciones .plano-region-conrotulo {
    display: grid;
    grid-template-columns: minmax(12rem, 16rem) minmax(0, 1fr);
    gap: 1.5rem;
    align-items: start;
}

/* LA COLUMNA DE CAMPOS TIENE TOPE, LA PAGINA NO (§1). Es la otra mitad de la
   decisión: un campo de texto de 1.500 px no se lee ni se rellena, así que los
   campos de una ficha paran a 72rem (1.152 px) aunque la ventana dé 1.920. Dentro
   de esos 72rem la rejilla de campos a dos columnas
   (`.crud-secciones-dos` que no es `.crud-secciones`) saca TRES columnas de
   `minmax(22rem, 1fr)`: eso es aprovechar el ancho sin estirar un campo. */
.crud-ficha .plano-region-campos { max-inline-size: 72rem; }

/* SALVO DONDE EL ANCHO ES EL CONTENIDO (§1): una zona con una tabla, un lienzo o
   una sección declarada ancha va a todo lo que haya, porque ahí el ancho son
   columnas que se ven en vez de columnas escondidas. `:has` ya se usa en esta hoja
   (§7.3 bis), así que no se estrena nada.
   Y la pizarra de precios (`.precios-pizarra`), que es una rejilla de tarifas y no
   un campo: a todo el ancho, decidido al fusionar el tema 1. */
.crud-ficha .plano-region-conrotulo:has(.mud-table, .crud-seccion-ancha, .plano-lienzo, .documentos-tabla, .precios-pizarra) .plano-region-campos {
    max-inline-size: none;
}

/* UNA FICHA DEJA DE REPARTIR SUS ZONAS EN DOS COLUMNAS. La tanda 3 (§10.4.5)
   apagó ahí la rejilla con un motivo bueno —3 de 12 de media pantalla son
   150 px— pero por la salida contraria a la que pide el diseño: el §4 describe
   UN cuerpo de ficha, zonas apiladas con el rótulo a la izquierda. Ahora la
   columna es una y cada zona recupera sus 3 y 9, que a 1.290 px dan 950 px de
   campos. La clase no se quita —da el `min-width: 0` de sus hijos y es la que el
   esqueleto imita—, sólo deja de significar dos columnas. Y el `gap` se va:
   entre zonas el aire ya son los 28 px y la regla de `.plano-region`. */
.crud-secciones.crud-secciones-dos {
    grid-template-columns: 1fr;
    gap: 0;
}

/* Una rejilla de CAMPOS a dos columnas dentro de una zona sí se queda a dos, y
   una zona anidada ahí vuelve a llevar su rótulo encima. */
.crud-secciones-dos:not(.crud-secciones) .plano-region-conrotulo { display: block; }
.crud-secciones-dos:not(.crud-secciones) .plano-region-rotulo { margin-block-end: 0.75rem; }

@media (max-width: 899.98px) {
    .crud-ficha .plano-region-conrotulo,
    .crud-secciones > .plano-region-conrotulo,
    .crud-secciones .plano-region-conrotulo { grid-template-columns: 1fr; gap: 0.75rem; }
}

/* La zona PLEGABLE (`CrudSeccion`): el panel de Mud, sin tarjeta. El tirador es
   la fila entera y el arco de puerta gira al abrirse, que es el mismo motivo de
   apertura de la hoja y del «Volver». */
.plano-region-plegable.mud-expansion-panels,
.plano-region-plegable .mud-expand-panel {
    background-color: transparent;
    box-shadow: none;
    border-radius: 0;
}

.plano-region-plegable .mud-expand-panel-header {
    padding-inline: 0;
    min-block-size: var(--plano-toque);
}

.plano-region-plegable .mud-expand-panel-text { padding-inline: 0; }

/* Mud dibuja una línea entre paneles; aquí la regla ya la pone `.plano-region`. */
.plano-region-plegable .mud-expand-panel::before,
.plano-region-plegable .mud-expand-panel + .mud-expand-panel::before { display: none; }

.plano-region-plegable .mud-expand-panel-header .mud-expand-panel-icon {
    color: var(--plano-tinta-2);
    transition: transform var(--plano-tiempo) var(--plano-curva);
}

/* EL ROTULO Y SU AYUDA, DENTRO DEL TIRADOR (tanda 5): la frase se lee con la
   sección CERRADA, que es cuando sirve para decidir si abrirla. Mud lo pone en
   una fila con el icono al final, así que el bloque tiene que poder encoger;
   sin `min-inline-size: 0` una frase larga echa fuera al icono. */
.plano-region-plegable .mud-expand-panel-header .crud-seccion-cabecera {
    flex: 1 1 auto;
    min-inline-size: 0;
    gap: 0.25rem;
}

/* Con ayuda el tirador mide dos renglones: los 44 px los pone el contenido. */
.plano-region-plegable .mud-expand-panel-header:has(.plano-region-ayuda) {
    padding-block: 0.6rem;
}

/* --- Las tablas DENTRO de una ficha -------------------------------------- */
/* Una tabla dentro de una zona no lleva su propio papel ni su propio canto: es
   contenido de la región, como un campo. */
.plano-region .mud-table,
.plano-region .mud-table-container { background-color: transparent; box-shadow: none; }

/* ---------------------------------------------------------------------------
   9.6 LA HOJA LATERAL: un diálogo que gira sobre su bisagra (§4)
   ---------------------------------------------------------------------------
   Las ediciones cortas y las confirmaciones que NO destruyen nada dejan de ser
   un modal centrado y pasan a una hoja pegada al canto derecho (abajo en
   móvil). Lo destructivo se queda en el centro a propósito: un modal centrado
   corta el paso, y eso es justo lo que tiene que hacer un «¿Borrar?».

   SE CONSIGUE SIN REESCRIBIR UN SOLO DIALOGO: `Hojas.Lateral` le pasa a
   MudBlazor un `DialogOptions` con `Position = CenterRight`, y lo que sigue es
   CSS. Las 35 pantallas con diálogo no cambian de marcado.

   LA MARCA ES `mud-dialog-centerright` Y NO UNA CLASE NUESTRA porque en
   MudBlazor 9 `DialogOptions` ya no tiene `Class`: lo único que llega al
   contenedor es la posición. Funciona porque en toda la central el canto derecho
   es LA HOJA y no hay otro diálogo pegado ahí. El porqué, en `Hojas.cs`.

   LA BISAGRA, Y QUE SE VEA (tanda 4). La tanda 3 la dejó en 4° con 18 px de
   recorrido: sobre el papel es un giro, en la pantalla es un parpadeo que nadie
   distingue de un desvanecido. La revisión de acabado lo dijo con todas las
   letras —«imperceptible»— y tiene razón: si el único momento de movimiento
   firmado de la aplicación no se ve, no existe.

   Ahora son 14° sobre el eje Y con 1.200 px de perspectiva y el quicio en el
   canto derecho, 260 ms con la salida exponencial del sistema. El giro va en
   NEGATIVO: con `transform-origin: right center`, un `rotateY` negativo manda el
   canto izquierdo hacia dentro de la pantalla, que es la hoja abriéndose hacia
   quien mira y no alejándose. Abajo en un móvil, el mismo gesto sobre el eje X.

   POR QUE NO MAREA: la hoja no se mueve de sitio —no hay `translate` que la
   arrastre—, gira sobre un quicio fijo y llega en poco más de un cuarto de
   segundo. Lo que se percibe es una puerta, no una pantalla que se desplaza. Lo
   anula entero `prefers-reduced-motion` (§10). */

.mud-dialog-container.mud-dialog-centerright {
    align-items: stretch;
    justify-content: flex-end;
    /* Mud le da 32 px de aire a la derecha; una hoja va PEGADA al canto. */
    padding-right: 0;
}

.mud-dialog-centerright .mud-dialog {
    margin: 0;
    max-inline-size: min(34rem, 100vw);
    inline-size: min(34rem, 100vw);
    max-block-size: 100dvh;
    block-size: 100dvh;
    display: flex;
    flex-direction: column;
    border-radius: var(--plano-radio-zona) 0 0 var(--plano-radio-zona);
    border-inline-start: 2px solid var(--plano-muro);
    transform-origin: right center;
    animation: plano-bisagra-derecha var(--plano-tiempo-bisagra) var(--plano-curva);
}

/* La hoja ANCHA (`Hojas.LateralAncha`): una tabla de líneas no cabe en 34 rem.
   Se distingue por el ancho que MudBlazor escribe, que es lo único que las
   separa. */
.mud-dialog-centerright .mud-dialog.mud-dialog-width-md {
    max-inline-size: min(48rem, 100vw);
    inline-size: min(48rem, 100vw);
}

.mud-dialog-centerright .mud-dialog-content {
    flex: 1 1 auto;
    overflow-y: auto;
    /* La hoja tiene el aire de una zona, no el relleno de un modal. */
    padding: 1.25rem 1.5rem;
}

.mud-dialog-centerright .mud-dialog-title { padding: 1.25rem 1.5rem 0.75rem; }
.mud-dialog-centerright .mud-dialog-actions { padding: 0.9rem 1.5rem; margin: 0; }

/* 14° y no 4: es el giro que se VE. Sin `translate`: la hoja no viaja, gira. */
@keyframes plano-bisagra-derecha {
    from { transform: perspective(1200px) rotateY(-14deg); opacity: 0; }
    to { transform: perspective(1200px) rotateY(0deg); opacity: 1; }
}

/* En un móvil la hoja entra POR ABAJO, que es de donde viene el pulgar. La
   bisagra pasa al canto inferior; el gesto es el mismo, girado. */
@media (max-width: 719.98px) {
    .mud-dialog-container.mud-dialog-centerright { align-items: flex-end; justify-content: stretch; }

    .mud-dialog-centerright .mud-dialog,
    .mud-dialog-centerright .mud-dialog.mud-dialog-width-md {
        inline-size: 100vw;
        max-inline-size: 100vw;
        block-size: auto;
        max-block-size: 88dvh;
        border-radius: var(--plano-radio-zona) var(--plano-radio-zona) 0 0;
        border-inline-start: none;
        border-block-start: 2px solid var(--plano-muro);
        transform-origin: bottom center;
        animation-name: plano-bisagra-abajo;
        padding-block-end: env(safe-area-inset-bottom, 0);
    }
}

/* El mismo gesto, girado: el quicio es el canto de abajo y la hoja se levanta
   hacia quien mira. 14° también, que sobre el eje X se nota igual. */
@keyframes plano-bisagra-abajo {
    from { transform: perspective(1200px) rotateX(14deg); opacity: 0; }
    to { transform: perspective(1200px) rotateX(0deg); opacity: 1; }
}

/* EL MODAL DESTRUCTIVO se queda CENTRADO —`Hojas.Destructivo`— y no lleva nada
   más: lo que lo distingue es que corta el paso y que su botón va en arcilla,
   que ya lo pone `Color.Error` con la piel de §7.1. Un canto rojo alrededor
   sería el `border-left` de color que el encargo prohíbe. */

/* ---------------------------------------------------------------------------
   9.7 LO QUE FALTABA DE LA PIEL (§4 «Avisos, pestañas, chips…»)
   ---------------------------------------------------------------------------
   Piezas que hasta la tanda 2 se quedaban con el aspecto de MudBlazor porque no
   salían en las cuatro pantallas del banco: el árbol de permisos, la subida de
   ficheros, el calendario, el paginador, las insignias y el aviso emergente. */

/* --- El árbol de permisos ------------------------------------------------ */
/* NO es un `MudTreeView` —la web no usa ninguno—: son paneles plegables por
   área, los mismos de `CrudSeccion`, y por eso ya heredan la zona plegable de
   §9.5. Lo que falta es lo de dentro: las casillas en columnas, para que un
   área de veinte permisos no sean veinte renglones de una línea cada uno. */
.permisos-area {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(18rem, 100%), 1fr));
    gap: 0.15rem 1.5rem;
}

.permisos-area-acciones { grid-column: 1 / -1; display: flex; gap: 0.25rem; }

/* --- Subida de ficheros: el campo de imagen ------------------------------ */
/* La web no usa `MudFileUpload`: sube ficheros con el `InputFile` de Blazor
   dentro de `CampoImagen` y de la imagen de un diseño de impresión. El
   `<input type=file>` va oculto y lo que se pulsa es una `<label>`, así que
   aquí se viste esa etiqueta como un botón secundario del plano —radio de control
   (repaso del 2026-10-06), muro de 1,5 px, aguada al pasar— y el HUECO de la vista previa como lo que es: un
   sitio reservado, en línea discontinua y sin fondo gris. */
.campo-imagen-vista {
    border: 1.5px dashed var(--plano-linea);
    border-radius: var(--plano-esquina-muro);
    background-color: transparent;
}

.campo-imagen-boton {
    border-radius: var(--plano-radio-control);
    border: 1.5px solid var(--plano-tinta);
    color: var(--plano-tinta);
    font-family: var(--plano-familia);
    font-size: var(--plano-t-15);
    font-weight: 560;
}

.campo-imagen-boton:hover { background-color: var(--plano-morado-aguada); border-color: var(--plano-morado); }

/* --- Calendario ---------------------------------------------------------- */
.mud-picker-container, .mud-picker-content { background-color: var(--plano-hoja); color: var(--plano-tinta); }
.mud-picker-toolbar { background-color: var(--plano-morado); color: var(--plano-papel); }
.mud-picker-calendar-header-day { font-family: var(--plano-familia); color: var(--plano-tinta-2); }

.mud-picker-calendar-day.mud-selected,
.mud-picker-calendar-day.mud-button-filled-primary {
    background-color: var(--plano-morado);
    color: var(--plano-papel);
}

/* --- Paginación: en texto, no en botones (§4) ---------------------------- */
/* La paginación de la web es la de `MudTable` (`.mud-table-pagination`, vestida
   en §7.3), no un `MudPagination`: no hay ninguno. Lo que faltaba son sus DOS
   flechas, que salían con el aro de un botón de icono de Material. */
.mud-table-pagination .mud-icon-button {
    border-radius: var(--plano-radio-control);
    color: var(--plano-tinta-2);
}

.mud-table-pagination .mud-icon-button:hover:not(:disabled) { background-color: var(--plano-morado-aguada); }
.mud-table-pagination .mud-select .mud-input-slot { font-size: var(--plano-t-13); }

/* --- El aviso emergente: aguada del tono, sin banda lateral -------------- */
.mud-snackbar {
    border-radius: var(--plano-esquina-muro);
    border: none;
    box-shadow: var(--plano-sombra-alzada);
    font-family: var(--plano-familia);
    font-size: var(--plano-t-15);
    background-color: var(--plano-hoja);
    color: var(--plano-tinta);
}

.mud-snackbar.mud-alert-filled-success { background-color: var(--plano-salvia-aguada-honda); color: var(--plano-tinta); }
.mud-snackbar.mud-alert-filled-info { background-color: var(--plano-morado-aguada-honda); color: var(--plano-tinta); }
.mud-snackbar.mud-alert-filled-warning { background-color: var(--plano-mostaza-aguada); color: var(--plano-tinta); }
.mud-snackbar.mud-alert-filled-error { background-color: var(--plano-arcilla-aguada); color: var(--plano-arcilla-honda); }

/* --- El lienzo NO se viste ----------------------------------------------- */
/* El diseñador de impresión y el editor de salas son LIENZOS: lo que se dibuja
   dentro es EL TRABAJO, no la interfaz. Un ticket que se va a imprimir en papel
   térmico no puede salir en berenjena, y una mesa del plano tiene los siete
   estados del TPV, que manda él (§8.3.5 del diseño). Se viste su CROMO —las
   barras de arriba, los paneles de al lado y los botones, que ya lo heredan de
   §7— y se deja el lienzo en paz.

   Estas dos reglas son justamente eso: la barra del lienzo, que hasta la tanda
   3 se quedaba con el gris de Material porque no la alcanzaba ningún selector. */
.salas-lienzo-barra,
.impresion-diseno-lienzo-barra {
    font-family: var(--plano-familia);
    font-size: var(--plano-t-13);
    color: var(--plano-tinta-2);
    border-block-end: 1px solid var(--plano-linea-fina);
}

/* 10. MOVIMIENTO ANULADO — `prefers-reduced-motion` VACIA las fichas de
   tiempo y con ellas caen todas las transiciones; además corta a mano las
   reglas con `animation` (la hoja, el latido). Se anula el movimiento, no el
   CAMBIO. */

@media (prefers-reduced-motion: reduce) {
    :root {
        --plano-tiempo-corto: 0.01ms;
        --plano-tiempo: 0.01ms;
        --plano-tiempo-largo: 0.01ms;
        --plano-tiempo-bisagra: 0.01ms;
    }

    /* La hoja lateral APARECE puesta: sin giro y sin desvanecido. Se anula el
       movimiento, no el cambio: la hoja sigue abriéndose. */
    .mud-dialog-centerright .mud-dialog { animation: none; }
    .plano-region-plegable .mud-expand-panel-header .mud-expand-panel-icon { transition: none; }
    .mud-skeleton.mud-skeleton-wave, .mud-skeleton.mud-skeleton-pulse { animation: none; }
    .mud-button-root:active:not(:disabled) { transform: none; }

    /* La luz de una sala abierta se queda encendida, sin el latido de entrada:
       el ESTADO no se pierde, lo que se pierde es el movimiento. */
    .plano-local-luz { animation: none; }
}

/* ---------------------------------------------------------------------------
   §17 LA CAJA CON PESTAÑAS DE UNA FICHA
   (docs/central/fichas-con-pestanas-y-ancho-2026-09-20.md §2 y §5)
   ---------------------------------------------------------------------------
   La ficha de un establecimiento son DIECIOCHO bloques apilados y mide más de
   seis pantallas de alto a 1.280 px aunque doce de sus secciones estén
   plegadas; la de un producto, catorce. Desde la tanda del 2026-09-20 cada
   bloque es una PESTAÑA: se ve uno, y la lista de todo lo demás cabe en una
   fila.

   LO QUE ARREGLA EL TEMA 3 (la noche del 2026-09-20), MEDIDO EN LA APLICACION
   ===========================================================================
   La primera versión pegaba la cabecera y la fila a `--plano-marco-alto`, que
   es lo que mide la FRANJA entera —barra, taburetes y tira del área— y lo
   escribe `medirMarco` de plano.js. Pero en una ficha lo único que se queda
   pegado al desplazar es la BANDA DE LA BARRA (`.plano-barra-marco`), que mide
   76 px. Medido en la ficha de un establecimiento: la banda acababa en 76 y el
   bloque pegajoso se clavaba en 265 (1.280 px) o en 263 (1.920 px). Esos 187-189
   px eran una RENDIJA por la que se veía pasar el formulario, y a media ficha
   veintiún elementos del panel quedaban POR ENCIMA del título y de las migas.

   Lo pegajoso se pega a lo PEGADO: el tope es `--plano-banda-alto`, que mide la
   banda de la barra y nada más. Y lo que se pega es SOLO LA FILA DE PESTAÑAS
   (44 px): la cabecera vuelve al flujo, porque una cabecera de tres renglones
   pegada es media pantalla que no se recupera y porque con un bloque por
   pestaña la ficha siempre está a un scroll de su título.

   TODO SIGUE EN EL DOM y lo que cambia es un `hidden`: `MudForm` valida los
   campos de las pestañas cerradas y las pruebas del marco los buscan. Por eso
   aquí no hay ni un `display: none` sobre el contenido en escritorio —lo pone
   el navegador con el atributo— y por eso en móvil hay que ANULARLO a mano. */

:root {
    /* EL ALTO DE LA BANDA DE LA BARRA: lo ÚNICO que se queda pegado arriba en
       una ficha, y por tanto el único tope honesto para lo que se pega DENTRO
       de ella. `.plano-barra-marco` rellena `--plano-barra-hueco` por arriba y
       lleva dentro la píldora de `--plano-barra-alto`; por abajo no rellena, así
       que el número de CSS es exacto (76 px, medido en Chromium) y no un
       respaldo aproximado. `plano.js` lo reescribe midiendo la banda de verdad
       para el día en que la píldora crezca —una instalación con nombre larguísimo
       en una ventana estrecha—, pero sin JavaScript esto ya vale. */
    --plano-banda-alto: calc(var(--plano-barra-alto) + var(--plano-barra-hueco));

    /* LA SOMBRA DE HOJA DE LA FICHA, y es la excepción que el usuario pidió con
       todas las letras el 2026-09-20 («me gustaría que las fichas tuvieran
       relieve»). El sistema dice que una superficie en reposo no lleva sombra;
       la ficha deja de ser una superficie en reposo cuando la fila de pestañas
       que la corona se queda pegada y el resto del papel pasa por DEBAJO de
       ella. Entonces flota de verdad, y una sombra que dice lo que pasa no es
       decoración. Es la más suave del repertorio —8 px de caída, 24 de
       desenfoque, tinta al 18 %, la mitad que la alzada de un menú— y está
       teñida de berenjena como todas. Ver DESIGN.md, «Cards / Containers». */
    --plano-sombra-ficha: 0 8px 24px -12px rgba(42, 26, 62, 0.18);
}

/* --- La ficha: cabecera y avisos, en el flujo ----------------------------- */

/* EL ENVOLTORIO ESTA SIEMPRE, con pestañas y sin ellas, y eso no es un detalle:
   si apareciera y desapareciera, Blazor destruiría y volvería a crear las zonas
   de dentro en el segundo pintado —el que llega cuando ya se han registrado— y
   se registrarían DOS VECES. No pinta nada: lo que pinta es la caja de dentro. */
.plano-ficha { display: block; }

/* LOS AVISOS, ENCIMA DE LA CAJA (§5, decisión 4). El error de guardado y la
   lista del núcleo hablan de la ficha ENTERA, no de la pestaña abierta: dentro
   de la caja se leían como contenido del panel, y con el panel desplazándose
   bajo la fila pegajosa desaparecían justo cuando hacían falta. */
.plano-ficha-avisos:not(:empty) { margin-block-end: 1rem; }

/* --- La caja: la hoja con relieve ---------------------------------------- */

/* LA FICHA ES UNA HOJA SOBRE EL PAPEL. Muro de 2 px a la izquierda y abajo
   —dos lados, como toda habitación del plano—, esquina de muro 20/6 ABAJO y
   cantos rectos arriba, porque arriba el canto lo dibujan las pestañas. La
   sombra, en `--plano-sombra-ficha`, con su motivo escrito ahí. */
.plano-caja {
    background-color: var(--plano-hoja);
    border-inline-start: 2px solid var(--plano-muro);
    border-block-end: 2px solid var(--plano-muro);
    border-start-start-radius: 0;
    border-start-end-radius: 0;
    border-end-end-radius: var(--plano-radio-zona);
    border-end-start-radius: var(--plano-radio-zona-corto);
    box-shadow: var(--plano-sombra-ficha);
}

/* Con una sola pestaña la caja es un envoltorio sin nada: la ficha de un tipo
   de elaboración no tiene de qué elegir y tampoco tiene por qué flotar. */
.plano-caja-sola,
.plano-caja-sola > .plano-caja-panel {
    padding: 0;
    background: none;
    border: none;
    box-shadow: none;
}

/* --- El carril de la fila: lo pegajoso ------------------------------------ */

/* EL CARRIL es la fila más sus dos flechas. Es lo ÚNICO que se pega, y se pega
   al alto de la BANDA de la barra, que es lo único que hay pegado encima. */
.plano-caja-carril {
    position: relative;
    background-color: var(--plano-papel);
    min-inline-size: 0;
}

/* SOLO POR ENCIMA DE 900 px. Por debajo no se pega nada arriba: a 768 px la
   ficha ya es estrecha y un renglón fijo de 44 px se cobra un campo entero; a
   375 la fila ni siquiera se pinta (acordeón). El «Guardar» del pie sigue
   pegado abajo por debajo de 900, como siempre.

   `z-index` MUY por debajo del de la barra (1200) y del de las hojas (1300):
   esto se pega dentro del contenido, no sobre el marco. */
@media (min-width: 900px) {
    .plano-caja-carril {
        position: sticky;
        inset-block-start: var(--plano-banda-alto);
        z-index: 20;
    }
}

/* --- La fila de pestañas -------------------------------------------------- */

/* UNA SOLA FILA, SIEMPRE. Hasta esta noche la fila se ENVOLVIA (`flex-wrap`) y
   en la ficha de un establecimiento salían veinte pestañas en CUATRO renglones
   a 1.280 px y en OCHO a 768: un muro de texto sin jerarquía en el que no se
   distingue lo abierto de lo cerrado. Ahora la fila se desplaza —con el dedo,
   con la rueda lateral, con las flechas del teclado y con los dos botones de los
   extremos— y ninguna pestaña se recorta ni se esconde: se llega a todas.

   La regla de 1,5 px de tinta es el SUELO en el que se apoyan las teclas, el
   mismo grosor con el que una tabla del plano cierra su cabecera. El fondo es
   PAPEL y no hoja: la fila tiene que leerse como una banda distinta del panel
   que hay debajo, que es de lo que se quejaba el usuario. */
.plano-caja-pestanas {
    display: flex;
    flex-wrap: nowrap;
    align-items: flex-end;
    gap: 0.25rem;
    padding-inline: 0.5rem;
    padding-block-start: 0.5rem;
    min-inline-size: 0;
    overflow-x: auto;
    overscroll-behavior-inline: contain;
    scroll-behavior: smooth;
    scroll-snap-type: inline proximity;
    scroll-padding-inline: var(--plano-toque);
    scrollbar-width: none;
    border-block-end: 1.5px solid var(--plano-tinta);
}

.plano-caja-pestanas::-webkit-scrollbar { display: none; }

/* --- Cada pestaña es una TECLA ------------------------------------------- */

/* LA PESTAÑA DE UNA FICHA ES UNA TECLA, no un rótulo subrayado. Lleva el relieve
   del sistema —canto de 2 px sin desenfoque y la luz de 1 px dentro del borde de
   arriba— porque se PULSA, y el radio de tecla (8 px) SOLO ARRIBA, que es la
   forma de una pestaña de carpeta: abajo no redondea porque abajo se apoya.

   El estado lo dicen, EN ESTE ORDEN, el fondo, el texto, el peso y
   `aria-selected`; el relieve va detrás, como manda la regla del estado que no
   depende del relieve. */
.plano-caja-pestana {
    flex: none;
    scroll-snap-align: start;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    min-block-size: var(--plano-toque);
    padding-inline: 1.15rem;
    border: none;
    border-radius: var(--plano-r-tecla) var(--plano-r-tecla) 0 0;
    background-color: var(--plano-papel-hondo);
    box-shadow: var(--plano-tecla-canto);
    color: var(--plano-tinta-2);
    font-family: var(--plano-familia);
    font-size: var(--plano-t-15);
    font-weight: 560;
    letter-spacing: 0;
    text-transform: none;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color var(--plano-tiempo) var(--plano-curva),
        color var(--plano-tiempo) var(--plano-curva),
        box-shadow var(--plano-tecla-sube) var(--plano-curva),
        transform var(--plano-tecla-sube) var(--plano-curva);
}

/* `:not([aria-selected="true"])` y no un orden de reglas: la abierta no se
   despinta al pasar el ratón por encima de ella. */
.plano-caja-pestana:not([aria-selected="true"]):hover {
    background-color: var(--plano-morado-aguada);
    color: var(--plano-morado);
}

/* Al pulsar, BAJA los dos píxeles del canto y se hunde, como toda tecla. */
.plano-caja-pestana:active {
    transform: translateY(var(--plano-canto));
    box-shadow: var(--plano-tecla-hundida);
    transition-duration: var(--plano-tiempo), var(--plano-tiempo),
        var(--plano-tecla-baja), var(--plano-tecla-baja);
}

/* LA ABIERTA VA ENCLAVADA Y ENTRA EN LA CAJA. Relleno de tinta, texto de papel,
   hundida y sin canto; y dos píxeles más de alto con dos píxeles de margen
   negativo, que es lo que hace que su relleno CUBRA la regla en la que se apoyan
   las demás. Ese tramo tapado es todo lo que hace falta para que la tecla y el
   panel se lean como una sola pieza: la pestaña de una carpeta no tiene línea
   entre la lengüeta y la hoja. */
.plano-caja-pestana[aria-selected="true"] {
    background-color: var(--plano-tinta);
    color: var(--plano-papel);
    font-weight: 640;
    box-shadow: var(--plano-tecla-hundida-honda);
    min-block-size: calc(var(--plano-toque) + 2px);
    margin-block-end: -2px;
}

.plano-caja-pestana[aria-selected="true"]:active { transform: none; }

.plano-caja-pestana-rotulo { white-space: nowrap; }

/* El salto de renglón equilibrado de la fila (CajaDePestanas, 2026-11-10): no se pinta salvo en una hoja que deje envolver la fila
   y lo encienda (ficha-producto.css). */
.plano-caja-salto { display: none; }

/* La insignia detrás del rótulo: «Series (3)» dice lo mismo que abrir la
   sección, y aquí lo dice sin abrirla. Sobre el relleno de tinta de la abierta
   pasa a papel, que es de donde sale todo el texto de una pieza entintada. */
.plano-caja-pestana-insignia,
.plano-caja-tirador-insignia {
    font-size: var(--plano-t-13);
    font-weight: 540;
    color: var(--plano-tinta-2);
}

.plano-caja-pestana[aria-selected="true"] .plano-caja-pestana-insignia,
.plano-caja-tirador[aria-expanded="true"] .plano-caja-tirador-insignia {
    color: var(--plano-lila-clara);
}

/* EL PUNTO DE ARCILLA (§2.6): cuántos campos hay que revisar en esa pestaña. Se
   pone tras una validación que falla y se va al revalidar. En arcilla honda
   sobre su propia aguada, que es el reparto del §1 para lo que está mal; sobre
   la tecla entintada se da la vuelta —arcilla llena con texto de berenjena—,
   porque una aguada del 14 % sobre tinta no es un punto, es una mancha. */
.plano-caja-pestana-errores,
.plano-caja-tirador-errores {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-inline-size: 1.25rem;
    padding-inline: 0.3rem;
    border-radius: var(--plano-pildora);
    background-color: var(--plano-arcilla-aguada);
    color: var(--plano-arcilla-honda);
    font-size: var(--plano-t-13);
    font-weight: 640;
}

.plano-caja-pestana[aria-selected="true"] .plano-caja-pestana-errores,
.plano-caja-tirador[aria-expanded="true"] .plano-caja-tirador-errores {
    background-color: var(--plano-arcilla);
    color: var(--plano-berenjena-honda);
}

/* Las píldoras del esqueleto miden como los rótulos que vienen (§2.5) y se
   quedan centradas en el alto de una tecla de verdad, en UNA fila como ella. */
.plano-caja-pestanas .plano-caja-pestana-esqueleto {
    flex: none;
    margin-block: calc((var(--plano-toque) - 1.1rem) / 2);
    margin-inline: 0.75rem;
}

/* --- Las dos flechas de los extremos -------------------------------------- */

/* CUANDO LA FILA NO CABE, HAY QUE DECIRLO Y HAY QUE PODER MOVERLA. El degradado
   de papel a transparente es la misma señal de continuidad que lleva la tira del
   área y que llevan las tablas del plano: lo que se recorta se desvanece en vez
   de cortarse en seco. Encima del degradado va la punta, que es el control.

   NO SE PINTAN SI NO HAY NADA QUE DESPLAZAR: `data-desborda` lo escribe
   `vigilarFila` de crud.js con un `ResizeObserver` y el `scroll` de la fila, y
   sin JavaScript —el banco estático, bUnit— no hay atributo y no hay flechas,
   que es lo correcto: un control que no lleva a ningún sitio. */
.plano-caja-flecha {
    position: absolute;
    inset-block: 0;
    inline-size: var(--plano-toque);
    display: none;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: none;
    background-color: transparent;
    color: var(--plano-tinta);
    cursor: pointer;
    z-index: 2;
}

.plano-caja-flecha-izq { inset-inline-start: 0; background-image: linear-gradient(to right, var(--plano-papel) 55%, transparent); }
.plano-caja-flecha-der { inset-inline-end: 0; background-image: linear-gradient(to left, var(--plano-papel) 55%, transparent); }

.plano-caja-carril[data-desborda="si"] > .plano-caja-flecha { display: inline-flex; }
.plano-caja-carril[data-inicio="si"] > .plano-caja-flecha-izq,
.plano-caja-carril[data-fin="si"] > .plano-caja-flecha-der { display: none; }

/* LA PUNTA APARECE AL PASAR; el degradado se ve siempre. Así la señal de «hay
   más» no depende del ratón y el control no ensucia una fila que no se está
   usando. Sin ratón (`hover: none`) la punta se ve siempre, que es la regla del
   sistema para todo control que sólo salía al pasar. */
.plano-caja-flecha .mud-icon-root {
    font-size: 20px;
    opacity: 0;
    transition: opacity var(--plano-tiempo) var(--plano-curva);
}

.plano-caja-carril:hover .plano-caja-flecha .mud-icon-root,
.plano-caja-carril:focus-within .plano-caja-flecha .mud-icon-root { opacity: 1; }

.plano-caja-flecha:hover { color: var(--plano-morado); }

@media (hover: none) {
    .plano-caja-flecha .mud-icon-root { opacity: 1; }
}

/* --- El panel ------------------------------------------------------------- */

.plano-caja-panel { padding: 1.5rem 1.75rem; }

/* LA ZONA VISIBLE NO NECESITA EL AIRE QUE SEPARA ZONAS. `.plano-region` pone 28
   px arriba y una regla abajo para separarse de la siguiente, y dentro del
   panel no hay siguiente: la que se ve es una.

   DESCENDIENTE Y NO HIJO, y lo enseñó el banco: la ficha de producto envuelve
   siete de sus catorce zonas en un `<div class="crud-secciones">` escrito a
   mano, así que la mitad de las pestañas NO son hijas del panel. Marcarlas con
   `> ` dejaba a esas siete sin nada de este bloque —sin revelado y, en móvil,
   sin tirador— y el defecto sólo se veía en el navegador. `[data-pestana]` ya
   distingue lo que hace falta: sólo lo lleva una zona REGISTRADA, y una zona
   dentro de otra no lo está. */
.plano-caja-panel .plano-region[data-pestana] {
    margin-block-start: 0;
    padding-block-end: 0;
    border-block-end: none;
}

/* EL REVELADO, Y ES LA UNICA ANIMACION DE LA CAJA: el panel entra, la fila de
   pestañas no se mueve. Se dispara sola al quitar el `hidden`, porque pasar de
   `display: none` a visible reinicia las animaciones de CSS: no hace falta ni
   una clase ni una línea de JavaScript para encenderla. */
.plano-caja-panel [data-pestana] {
    animation: plano-caja-revelado var(--plano-tiempo) var(--plano-curva) both;
}

@keyframes plano-caja-revelado {
    from { opacity: 0; transform: translateY(4px); }
    to { opacity: 1; transform: none; }
}

/* --- El acordeón de móvil (§2.7) ------------------------------------------ */

/* El tirador de cada zona NO se pinta en escritorio: ahí lo que manda es la
   fila. Es la misma pieza y el mismo estado con dos pieles, no dos modelos. */
.plano-caja-tirador { display: none; }

@media (max-width: 719.98px) {
    /* La fila se va: veinte teclas a 375 px no son una fila, son un laberinto. */
    .plano-caja-carril { display: none; }

    /* EL TIRADOR ES LA MISMA TECLA, apilada y a todo el ancho: mismo relleno,
       mismo canto, mismo hundido al abrirse y el mismo entintado. Un acordeón
       cuyos renglones son teclas se lee igual que la fila de escritorio, que es
       lo que hace que sean dos pieles y no dos modelos. 48 px, que es el objetivo
       táctil del sistema por debajo de 720. */
    .plano-caja-tirador {
        display: flex;
        align-items: center;
        /* Al principio de la línea, y hay que decirlo: un `<button>` centra su
           contenido por omisión y esto es un renglón de acordeón, no un botón
           centrado. Medido en el banco: sin esto el rótulo salía a 105 px del
           canto en un teléfono de 375. */
        justify-content: flex-start;
        gap: 0.5rem;
        inline-size: 100%;
        min-block-size: var(--plano-toque-movil);
        padding-inline: 0.9rem;
        border: none;
        border-radius: var(--plano-r-tecla);
        background-color: var(--plano-papel-hondo);
        box-shadow: var(--plano-tecla-canto);
        font-family: var(--plano-familia);
        font-size: var(--plano-t-15);
        font-weight: 560;
        color: var(--plano-tinta-2);
        text-align: start;
        cursor: pointer;
        transition: background-color var(--plano-tiempo) var(--plano-curva),
            color var(--plano-tiempo) var(--plano-curva),
            box-shadow var(--plano-tecla-sube) var(--plano-curva);
    }

    .plano-caja-tirador[aria-expanded="true"] {
        background-color: var(--plano-tinta);
        color: var(--plano-papel);
        box-shadow: var(--plano-tecla-hundida-honda);
    }

    .plano-caja-tirador:active { box-shadow: var(--plano-tecla-hundida); }

    /* El arco de puerta, que es el motivo de apertura del sistema: el mismo
       dibujo que marca la vuelta de una ficha y la bisagra de una hoja. Gira al
       abrirse, como en la zona plegable. */
    .plano-caja-tirador-arco {
        color: currentColor;
        flex: none;
        transition: transform var(--plano-tiempo) var(--plano-curva);
    }

    .plano-caja-tirador[aria-expanded="true"] .plano-caja-tirador-arco { transform: rotate(90deg); }

    .plano-caja-tirador-rotulo { flex: 1 1 auto; min-inline-size: 0; }

    /* LO CERRADO SIGUE ENSEÑANDO SU TIRADOR. El navegador esconde entero lo que
       lleva `hidden`; aquí se le devuelve el sitio y se esconde sólo lo de
       dentro, que es lo que convierte la pestaña en un renglón de acordeón.

       `!important` 3, Y LO IMPONE EL NAVEGADOR. La hoja de agente de usuario
       declara hoy `display: none !important` para todo `[hidden]` que no sea
       `until-found` —lleva la marca desde que existe ese valor—, así que
       ninguna regla de autor la gana por especificidad: medido en Chromium,
       con `display: block` a secas los cuatro renglones cerrados del acordeón
       median cero y el móvil enseñaba UNA sección y ningún tirador. Es el mismo
       caso que los dos `!important` del §7.8: no es preferencia, es una regla
       marcada de otro que hay que anular. El atributo se queda porque es lo que
       dice de verdad que la sección está cerrada, y lo que `MudForm` y las
       pruebas del marco necesitan que siga en el DOM. */
    .plano-caja-panel [data-pestana][hidden] { display: block !important; }

    .plano-caja-panel [data-pestana][hidden] > .plano-region-rotulo,
    .plano-caja-panel [data-pestana][hidden] > .plano-region-campos { display: none; }

    /* Entre teclas apiladas, aire: la regla fina que separaba renglones sobra
       cuando cada renglón es una pieza con su propio canto. */
    .plano-caja-panel [data-pestana] + [data-pestana] { margin-block-start: 0.4rem; }

    /* Y un respiro entre la tecla abierta y sus campos. */
    .plano-caja-panel [data-pestana]:not([hidden]) > .plano-region-rotulo { margin-block-start: 0.75rem; }

    .plano-caja-panel { padding: 1rem; }
}

/* --- Movimiento anulado --------------------------------------------------- */

/* El §10 de esta hoja vacía las fichas de tiempo, y eso basta para las
   transiciones; una `animation` con nombre hay que cortarla a mano, como ya se
   hace con la hoja lateral y con el latido de una sala. Se anula el MOVIMIENTO,
   no el cambio: la pestaña sigue abriéndose y la tecla sigue hundiéndose. */
@media (prefers-reduced-motion: reduce) {
    .plano-caja-panel [data-pestana] { animation: none; }
    .plano-caja-tirador-arco { transition: none; }
    .plano-caja-pestana:active { transform: none; }
    .plano-caja-pestanas { scroll-behavior: auto; }
}
