/*
 * assets/css/kit-overrides.css — Correcciones del kit sobre el skin Anvogue.
 *
 * Fichero PROPIO del kit (Anvogue no lo trae). Se carga el ÚLTIMO en
 * components/header.php, después de dist/output-scss.css y
 * dist/output-tailwind.css, porque varias de estas reglas ganan por orden de
 * cascada con la misma especificidad que las originales.
 *
 * NUNCA editar dist/ a mano: se regenera con `npm run sass` / `npm run dev`
 * y cualquier parche allí se perdería. Todo arreglo va aquí, documentado.
 *
 * Cada bloque explica QUÉ regla neutraliza y POR QUÉ.
 */

/* ---------------------------------------------------------------------------
 * 1) .button-main invisible en reposo cuando es <button type="submit|button">
 *
 * SÍNTOMA: el botón "Confirmar pedido" del checkout solo se veía al pasar el
 * ratón por encima (texto blanco sobre fondo blanco en reposo).
 *
 * CAUSA: choque de especificidad entre el SCSS de Anvogue y el preflight de
 * Tailwind, NO del mapeo de colores del kit.
 *   dist/output-scss.css    .button-main            { background-color: var(--black) }   (0,1,0)
 *   dist/output-tailwind.css [type='submit']        { background-color: transparent }    (0,1,0)
 * Un selector de atributo puntúa igual que una clase, y output-tailwind.css se
 * carga después: en empate gana el último, así que el fondo quedaba
 * transparente mientras el texto seguía siendo var(--white). En :hover sí se
 * veía porque `.button-main:hover` puntúa (0,2,0) y gana.
 * Anvogue nunca lo sufrió porque sus botones son <a>/<div> o <button> sin
 * atributo `type` (el selector de elemento `button` puntúa (0,0,1) y pierde).
 *
 * ARREGLO: restaurar el fondo solo donde el preflight lo pisa.
 *   - :not([class*="bg-"]) deja intactos los botones que ya traen su fondo por
 *     una utilidad de Tailwind (bg-white de "Añadir al carrito", bg-surface del
 *     botón "Agotado"...); si no, este override los pintaría de negro.
 *   - :not(:hover) deja que `.button-main:hover` siga mandando en el hover.
 * ------------------------------------------------------------------------- */
.button-main:not([class*="bg-"]):not(:hover) {
    background-color: var(--black);
}

/* ---------------------------------------------------------------------------
 * 2) Tarjeta de producto: al hacer hover desaparecía el nombre y el precio
 *    se desplazaba hacia abajo.
 *
 * SÍNTOMA: en el catálogo (y en cualquier grid de tarjetas), a partir de
 * 1024px, el nombre del producto se ocultaba al pasar el ratón y el precio
 * bajaba ~28px dejando un hueco.
 *
 * CAUSA: efecto de demo de Anvogue (assets/scss/product.scss, regla
 * `.product-item:hover.grid-type` dentro de @media (min-width:1024px)):
 * oculta `.product-name` y baja `.product-price-block` 28px para hacer sitio
 * al selector de colores `.list-color`, que aparece en ese hueco.
 * components/tarjeta-producto.php PODA ese selector de colores (el MVP no
 * tiene variantes), así que la animación se ejecuta pero no aparece nada en
 * su lugar: el nombre se va y el precio baja sin motivo.
 *
 * ARREGLO: anular SOLO esas dos declaraciones. Anvogue ofrece la clase
 * `.hide-color` para tarjetas sin variantes, pero no sirve aquí: su selector
 * puntúa (0,5,0) frente a los (0,6,0) de la regla de hover, así que pierde.
 * Se replica el selector exacto del hover (misma especificidad) y gana por
 * orden de carga. El resto del hover de la tarjeta (zoom de la imagen,
 * acciones laterales) se conserva intacto.
 * ------------------------------------------------------------------------- */
.product-item:hover.grid-type .product-main .product-infor .product-name {
    opacity: 1;
    visibility: visible;
}

.product-item:hover.grid-type .product-main .product-infor .product-price-block {
    transform: none;
}

/* ---------------------------------------------------------------------------
 * 3) Aviso de cookies (K3 Bloque 6) — componente propio del kit.
 *
 * Anvogue no trae banner de cookies, asi que su estilo va aqui y no en dist/.
 * Franja fija abajo, por encima del contenido. En movil se levanta 70px para
 * no quedar tapada por la barra .menu_bar del template (fixed, 70px, z-101),
 * y se le da z-index superior para que quede por encima de ella.
 * ------------------------------------------------------------------------- */
.aviso-cookies {
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    z-index: 102;
    box-shadow: 0 -4px 20px rgb(0 0 0 / 0.08);
}

@media (max-width: 639px) {
    .aviso-cookies {
        bottom: 70px; /* alto de .menu_bar en movil */
    }
}

/* `hidden` debe ganar a las utilidades de display de Tailwind: el aviso sale
   oculto de serie y solo lo muestra assets/js/cookies.js. */
[hidden] {
    display: none !important;
}

/* ---------------------------------------------------------------------------
 * 4) Lista de deseos: widget de demo sin funcion en el MVP (K3 Bloque 7).
 *
 * main.js accede a estos dos elementos SIN comprobar que existan
 * (`wishlistIcon.addEventListener(...)`, `modalWishlist.addEventListener(...)`).
 * Si se quitan del HTML, la primera lanza un TypeError y muere el resto del
 * script: menus, swipers, cantidades y el modal del carrito incluidos. Por eso
 * se OCULTAN en lugar de borrarse.
 *
 * ACTUALIZADO EN L3: aqui tambien se ocultaban `.modal-compare-block`,
 * `.modal-quickview-block` y `.compare-block`. Ese marcado ya NO EXISTE —L2 lo
 * borro del pie, junto con los datos inventados que contenia— y main.js quedo
 * guardado en los dos puntos que lo necesitaban, asi que las reglas apuntaban a
 * nodos inexistentes y el comentario describia una situacion que ya no era
 * cierta. Se retiran para que este fichero no mienta sobre lo que hay.
 *
 * ACTUALIZADO EN F8·W2: la lista de deseos ya tiene BD detras, asi que
 * `.wishlist-icon` DEJA DE OCULTARSE — ahora es el enlace a pages/favoritos.php
 * y su contador lo pinta assets/js/favoritos.js.
 *
 * El MODAL sigue oculto, y no por olvido: su contenido lo pinta
 * handleItemModalWishlist() de main.js desde el almacen de demo, con precios en
 * "$" y ".00" — exactamente lo que obligo a reescribir el mini-carrito en K3.
 * La lista se consulta en SU PAGINA, servida desde el servidor con las tarjetas
 * reales; un modal que ademas habria que reescribir entero no aporta nada que
 * la pagina no de mejor. Se mantiene en el DOM (no se borra) por la razon de
 * siempre: main.js lo referencia sin guarda.
 * ------------------------------------------------------------------------- */
.modal-wishlist-block {
    display: none !important;
}

/* ---------------------------------------------------------------------------
 * 5) RETIRADA EN E1. Limitaba a 45 % el ancho de `.slider-block .sub-img` en
 * movil, porque el recorte PNG del marcado antiguo (fashion1) se pintaba encima
 * del titular. Ese marcado ya no existe: la imagen del slider es ahora una foto
 * a sangre `w-full h-full` (fashion5), asi que la regla no solo sobraba —habria
 * dejado la foto en el 45 % del ancho, ganando por especificidad (0,2,0) al
 * `.w-full` de Tailwind (0,1,0)—. El numero no se reutiliza para que las notas
 * de commits anteriores sigan apuntando a lo que apuntaban.
 * ------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
 * 6) Copyright del pie descolgado a la izquierda (L3).
 *
 * `.footer-bottom` es un flex con `justify-between` pensado para DOS hijos: el
 * copyright a la izquierda y los logos de medios de pago a la derecha. L2
 * retiro los logos —en Nivel 1 el checkout no cobra y anunciar seis formas de
 * pago era una promesa falsa— y con un solo hijo `justify-between` lo deja
 * pegado al margen izquierdo, con toda la fila vacia a su derecha.
 *
 * Se centra hasta que K4 devuelva los logos de los metodos que de verdad
 * funcionen; entonces esta regla sobra y se retira. Por debajo de `lg` el skin
 * ya centraba por su cuenta (`max-lg:justify-center`), asi que esto solo cambia
 * el escritorio.
 * ------------------------------------------------------------------------- */
.footer-bottom {
    justify-content: center;
}

/* ---------------------------------------------------------------------------
 * 7) El bloque de las cuatro ventajas, pegado al pie (E2).
 *
 * SINTOMA: `.benefit-block` (Atencion personal / 14 dias para devolver /
 * Garantia de 3 anos / Envio a domicilio) termina justo donde empieza el gris
 * del pie, sin aire. Pasa en las DOS paginas donde sale: la portada y
 * "Quienes somos".
 *
 * CAUSA (medida, no supuesta): al bloque NUNCA le ha faltado padding inferior;
 * es que en Anvogue nunca lo llevo. Su marcado es `md:pt-20 pt-10`, solo
 * arriba, porque la separacion de abajo la ponia el elemento SIGUIENTE con su
 * propio margen superior: en el index.html del template venia
 * `.testimonial-block ... md:mt-20 mt-10`. Al podar en K3 Bloque 7 los tres
 * bloques de demo que iban detras (resenas inventadas, galeria de Instagram y
 * logos de marcas) se fue con ellos ese colchon, y el pie quedo de vecino
 * inmediato. `.footer-main` no trae margen superior: arranca su fondo gris en
 * el pixel siguiente. Quienes somos (F15) heredo el mismo patron al copiarlo.
 *
 * CORRECCION: devolver EXACTAMENTE el colchon que daba el bloque desaparecido,
 * y por el mismo mecanismo (margen superior del elemento siguiente), no
 * inventando un padding nuevo. Los valores son los del propio diseno, no
 * elegidos: `mt-10` = 2,5rem = 40px y `md:mt-20` = 5rem = 80px, que ademas es
 * el mismo ritmo vertical que el `pt-10 / md:pt-20` de cabecera del bloque.
 *
 * El selector de hermano adyacente hace que la regla solo actue cuando el
 * bloque de ventajas es lo ULTIMO de la pagina, que es el caso averiado. Si
 * algun dia vuelve a haber una seccion detras, esa traera su propio margen y
 * esta regla no llegara a aplicarse.
 * ------------------------------------------------------------------------- */
.benefit-block + #footer {
    margin-top: 40px;
}

@media (min-width: 768px) {
    .benefit-block + #footer {
        margin-top: 80px;
    }
}

/* ---------------------------------------------------------------------------
 * 8) Tope de ancho de las etiquetas de la tarjeta de producto (E1).
 *
 * La chip reutiliza el distintivo que Anvogue ya usa en el catalogo
 * (.list-filtered .item: bg-linear + rounded-full), asi que de estilo propio no
 * hace falta nada... salvo esto: los nombres de etiqueta los escribe el cliente
 * desde el backoffice y el campo admite 80 caracteres. Medido con Instrument
 * Sans, "Edicion limitada de verano 2026" son 188,9 px y la tarjeta a 375 px
 * tiene 161,5: sin tope, una sola etiqueta larga se sale de su columna e invade
 * la vecina. Anvogue no lo sufria porque sus etiquetas eran palabras fijas de
 * demo.
 *
 * Se resuelve con CSS y no acortando el texto en PHP a proposito: el punto de
 * corte depende del ancho real de la columna, que solo conoce el navegador.
 * Va aqui y no con utilidades de Tailwind porque `truncate` y `max-w-full` no
 * estan en el build de dist/ (esta purgado y no se regenera a mano).
 * ------------------------------------------------------------------------- */
.product-tags .product-tag-item {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* -------------------------------------------------------------------------
 * F11 R3 — control de ENTRADA de puntuacion (pages/valorar.php)
 *
 * POR QUE HAY CSS NUEVO AQUI. Anvogue trae estrellas de LECTURA en todas
 * partes (<i class="ph-fill ph-star"> en text-yellow / text-secondary, el par
 * que usa main.js:1290-1298), pero NO trae ningun control de entrada: se
 * comprobaron las 60 paginas HTML, el SCSS y el JS, y los unicos
 * <input type="radio"> del template estan en cart/checkout para los metodos de
 * envio. Su propio #form-review pide nombre, email y mensaje, sin puntuacion.
 *
 * Se resuelve con radios NATIVOS + <label>, que ya se recorren con Tab y
 * flechas sin una linea de JavaScript, y como contenido visible del label van
 * los iconos del propio skin. De estilo propio hace falta solo esto: ocultar el
 * radio sin sacarlo del foco, encender de la marcada hacia abajo, y un foco
 * visible.
 *
 * Los radios se pintan en orden 5..1 en el HTML y el contenedor lleva
 * flex-row-reverse, de modo que se VEN de 1 a 5 de izquierda a derecha. Eso
 * permite encender con el combinador ~, que solo mira hacia delante en el DOM:
 * marcar el 3 enciende los labels de 3, 2 y 1.
 * ------------------------------------------------------------------------- */

/* Tailwind del skin esta purgado y no incluye .sr-only; se define aqui porque
   la usan el radio y los textos alternativos de las estrellas. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border-width: 0;
}

.rate-input .rate label {
    cursor: pointer;
    color: var(--secondary);
    line-height: 1;
}

.rate-input .rate input:checked ~ label {
    color: var(--yellow);
}

/* Vista previa al pasar el raton: apaga todas y enciende de la apuntada hacia
   abajo, para que se vea que se elige "3 de 5" y no "solo la 3". */
.rate-input .rate:hover label {
    color: var(--secondary);
}

.rate-input .rate label:hover,
.rate-input .rate label:hover ~ label {
    color: var(--yellow);
}

/* El radio esta oculto pero SIGUE recibiendo el foco: sin esto, quien navega
   con teclado no veria donde esta. */
.rate-input .rate input:focus-visible + label {
    outline: 2px solid var(--black);
    outline-offset: 2px;
    border-radius: 4px;
}

/* -------------------------------------------------------------------------
 * F11 R5 — solapa de valoraciones de la ficha
 *
 * Anvogue ya trae TODO el estilo del bloque de resenas (.list-review, .item,
 * .rate, .top-overview, .list-rating, .progress), asi que aqui solo hace falta
 * lo que el marcado original no contemplaba:
 *
 * 1) El cuerpo de la valoracion lo escribe un comprador y puede traer saltos de
 *    linea. El .body1 del skin los colapsa como cualquier HTML; con pre-wrap se
 *    respetan los parrafos tal como los escribio. Y las palabras larguisimas
 *    —una URL pegada, por ejemplo— se parten en vez de ensanchar la columna.
 * 2) El ancho de las barras del desglose va en un `style` por fila, calculado
 *    en PHP: es un dato, no una decision de diseno, y no puede vivir en una
 *    clase de utilidad porque el porcentaje cambia con cada producto.
 *    Aqui solo se garantiza la transicion suave, que el skin da a .progress-percent
 *    pero no cuando el ancho llega por atributo.
 * ------------------------------------------------------------------------- */
.desc-item.review .valoracion-cuerpo {
    white-space: pre-wrap;
    word-break: break-word;
    overflow-wrap: break-word;
}

.desc-item.review .list-rating .progress-percent {
    transition: width .3s ease;
}

/* 3) El .heading5 del skin lleva `text-transform: capitalize`, que en un titulo
      de demo no se nota y en una resena real si: "Mas barato de lo que
      esperaba" salia en pantalla como "Mas Barato De Lo Que Esperaba". Lo que
      escribio el comprador se muestra tal cual — es su texto, y ademas la
      fidelidad de lo publicado es justo lo que exige la normativa de resenas. */
.desc-item.review .list-review .heading5 {
    text-transform: none;
}

/* ---------------------------------------------------------------------------
 * 9) Carrusel de categorias del home: tarjetas de tamanos dispares.
 *
 * SINTOMA: en "Nuestras categorias" cada tarjeta salia con un alto distinto y
 * las imagenes pequenas no llenaban su tarjeta (quedaban a su tamano natural
 * con el rotulo descolgado).
 *
 * CAUSA: el skin no dimensiona `.collection-item .bg-img img` (su unica regla
 * es la transicion del hover); Anvogue confiaba en que todas sus imagenes demo
 * tuvieran el MISMO recorte (680x910). En el kit la imagen de categoria la sube
 * el cliente desde el backoffice a cualquier tamano, asi que la uniformidad
 * tiene que garantizarla el CSS, no el recorte previo.
 *
 * ARREGLO: tarjeta cuadrada con la imagen cubriendo el marco. Se elige 1:1
 * porque el placeholder de categoria sin imagen (1000x1000.png) y las fotos de
 * producto del kit ya son cuadrados.
 * ------------------------------------------------------------------------- */
.collection-item .bg-img img {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
}

/* ---------------------------------------------------------------------------
 * 10) F12: footer descuadrado en tablet apaisada (1024-~1071 px) sin redes.
 *
 * SINTOMA: con las tres RRSS de config.php vacias, en ese tramo los datos del
 * cliente quedaban solos en una fila y las tres columnas en la siguiente
 * ocupando media pantalla, con la mitad derecha vacia.
 *
 * CAUSA: .company-infor no baja de 256 px (columna de rotulos 77 + datos con
 * el email indivisible 140 + hueco 12 + pr-7 28) y a esas anchuras su
 * basis-1/4 son 244-255 px. Con flex-wrap el reparto en filas se hace con los
 * tamanos SIN encoger, asi que .right-content (basis-3/4) salta de fila
 * entera y el encogido nunca llega a actuar. Al Anvogue original le pasa
 * IGUAL (medido a 1024: company 257 px, envuelto), pero su columna de
 * newsletter (basis-1/3) completa la segunda fila y el hueco no se ve. El
 * kit solo pinta esa columna ("Siguenos") cuando hay redes configuradas.
 *
 * ARREGLO: sin la columna (clase footer-sin-newsletter, la emite footer.php
 * solo sin redes), a partir de lg se prohibe el salto de fila: al no envolver
 * si actua el encogido, .right-content cede los ~12 px que faltan y el footer
 * queda con el MISMO patron que en escritorio. flex-nowrap y lg:flex-nowrap
 * NO existen en el CSS purgado del skin (auditado contra dist/), por eso la
 * regla vive aqui. El tramo 768-1023 se arregla en el marcado con
 * max-lg:basis-full en .list-nav, que si existe.
 * ------------------------------------------------------------------------- */
@media (min-width: 1024px) {
    .content-footer.footer-sin-newsletter {
        flex-wrap: nowrap;
    }
}

/* ---------------------------------------------------------------------------
 * 11) F8·W2b: el corazon de la tarjeta, oculto en reposo SOLO donde hay raton.
 *
 * W2 lo dejo siempre visible por una razon que sigue en pie: el envoltorio del
 * skin (.list-action-right) solo se revela con :hover, y en una pantalla
 * tactil no hay hover — el control existiria sin poder usarse (§10bis). Pero
 * en escritorio ese comportamiento SI es el del template y es el que se
 * quiere: la tarjeta limpia en reposo y el corazon al pasar por encima.
 *
 * Por eso la regla vive dentro de `hover: hover` y `pointer: fine`, que juntas
 * significan "hay un puntero de verdad capaz de mantener el hover". Un movil o
 * una tableta no entran aqui y se quedan EXACTAMENTE como en W2.
 *
 * Se oculta con `opacity`, NO con display ni visibility: el boton tiene que
 * seguir existiendo para el teclado. Y se revela tambien con :focus-visible
 * porque quien tabula no tiene hover — el mismo motivo por el que el tactil
 * queda fuera.
 *
 * NO se anade `pointer-events: none` en reposo, y conviene dejar escrito por
 * que se descarto DESPUES de haberlo probado: con raton es imposible pulsar
 * sin pasar antes por encima, asi que cuando llega el clic el hover ya ha
 * revelado el boton y esa "proteccion" no evita ningun caso real. A cambio
 * convertia un fallo cosmetico en uno funcional: si el hover no llegaba a
 * aplicarse, el control quedaba imposible de usar — y en un portatil tactil,
 * que entra en esta media query por su raton pero se maneja con el dedo,
 * quedaba imposible SIEMPRE. Entre "se ve poco" y "no se puede usar", §10bis
 * manda elegir lo primero.
 *
 * Un favorito YA MARCADO (.active) se ve SIEMPRE, tambien en reposo: la lista
 * de deseos se consulta de un vistazo sobre el catalogo, y un corazon marcado
 * que hay que descubrir pasando el raton no informa de nada.
 *
 * La duracion no se inventa: el marcado del boton ya declara `duration-300`
 * (Tailwind emite solo `transition-duration`), asi que aqui basta con decir
 * QUE propiedad transiciona para que esos 300 ms del propio marcado surtan
 * efecto. El skin no define transicion para este boton: la unica que existe
 * en dist/ es la de `.style-marketplace`, otra variante de tarjeta.
 *
 * Acotado a `.product-item`: el corazon de la FICHA no cuelga de esa clase
 * (K3 se la quito a la columna de info a proposito) y no se toca. En la pagina
 * de favoritos todas las tarjetas nacen `.active`, asi que tampoco cambia.
 *
 * Q1 anade a estas dos listas el boton de compra rapida, que se comporta
 * igual. No tiene estado `.active` —anadir al carrito no deja el control
 * marcado, el acuse de recibo es el contador y el mini-carrito—, asi que solo
 * aparece en la regla de :hover y en la de :focus-visible.
 * ------------------------------------------------------------------------- */
@media (hover: hover) and (pointer: fine) {
    .product-item .add-wishlist-btn,
    .product-item .compare-btn,
    .product-item .compra-rapida-btn {
        opacity: 0;
        transition-property: opacity;
    }

    .product-item:hover .add-wishlist-btn,
    .product-item .add-wishlist-btn:focus-visible,
    .product-item .add-wishlist-btn.active,
    .product-item:hover .compare-btn,
    .product-item .compare-btn:focus-visible,
    .product-item .compare-btn.active,
    .product-item:hover .compra-rapida-btn,
    .product-item .compra-rapida-btn:focus-visible {
        opacity: 1;
    }
}

/* ---------------------------------------------------------------------------
 * 13) Q1: el :hover del boton de compra rapida.
 *
 * El marcado sale de Anvogue (product-style4.html:1313-1316) pero SIN su clase
 * `.add-cart-btn`, porque esa clase es un gancho que `main.js` engancha en todo
 * el documento al cargar (linea 502 + 512-516: le pone `openModalCart`, que
 * abriria el mini-carrito con su contenido ANTERIOR antes de que vuelva la
 * peticion). Ver la nota larga en components/tarjeta-producto.php.
 *
 * Omitirla cuesta exactamente UNA regla de estilo, la de
 * dist/output-scss.css:2658-2666, donde `.add-cart-btn` comparte declaraciones
 * con `.compare-btn`, `.add-wishlist-btn`, `.quick-view-btn` y
 * `.quick-view-btn-list`. Se replica aqui con nuestra clase y con las MISMAS
 * declaraciones y variables del skin (`--black` / `--white`), para que el
 * boton reaccione al raton igual que sus dos hermanos de la pila.
 *
 * La segunda regla del skin que menciona `.add-cart-btn`
 * (dist/output-scss.css:2667-2675, el globo `.tag-action`) NO se replica: este
 * boton no lleva `.tag-action`, como tampoco lo llevan el corazon ni el de
 * comparar desde que K3 los cambio por `title`.
 *
 * Especificidad: (0,2,1) igual que la del skin, y este fichero se carga el
 * ultimo, asi que no hay empate que resolver con nada.
 * ------------------------------------------------------------------------- */
.product-item .compra-rapida-btn:hover {
    background-color: var(--black);
    color: var(--white);
    cursor: pointer;
}

/* ---------------------------------------------------------------------------
 * 12) C1: comparador de productos.
 *
 * Lo que Anvogue YA resuelve y aqui no se toca: el aspecto del boton
 * `.compare-btn` (fondo, hover, alternancia de iconos y verde del marcado), el
 * panel inferior `.modal-compare-block` y el enrejado de la pagina
 * (`.compare-block .list-product`, `.compare-block .compare-table`). Lo que
 * sigue es lo que su marcado de demo NO contemplaba, cada regla con su motivo.
 * ------------------------------------------------------------------------- */

/* a) EL ESTADO MARCADO, FUERA DE LA TARJETA.
 *
 * El skin alterna los dos iconos del boton (`.compare-icon` visible /
 * `.checked-icon` oculta, y al reves cuando esta `.active`, en verde) con
 * reglas que EXIGEN el ancestro `.product-item`
 * (dist/output-scss.css:2715-2727). La tarjeta lo tiene; la columna de
 * informacion de la ficha NO —K3 le quito esa clase a proposito—, asi que alli
 * el boton se quedaba con los dos iconos encima y sin cambiar al pulsarlo.
 *
 * Se repiten las MISMAS declaraciones sin ese ancestro. No pisa a las del
 * skin: las suyas puntuan mas alto (llevan `.product-item` delante) y dicen
 * exactamente lo mismo, asi que la tarjeta se comporta igual que siempre.
 * El verde es el literal del propio skin (#3DAB25); no hay variable para el. */
.compare-btn .checked-icon {
    display: none;
}

.compare-btn.active .compare-icon {
    display: none;
}

.compare-btn.active .checked-icon {
    display: block;
}

.compare-btn.active i {
    color: #3DAB25;
}

/* b) DESPLAZAMIENTO HORIZONTAL EN MOVIL.
 *
 * Es la regla de `assets/scss/compare.scss:36`, tal cual, cambiandole el
 * selector: colgaba de `.compare-block .content-main`, y esa clase se le ha
 * quitado al contenedor porque en el skin es un GANCHO de datos de demo —
 * `main.js:3103` la busca para sustituir su contenido por "No product in
 * compare" (ver la cabecera de components/comparador-tabla.php). Sin esto, en
 * movil la tabla se comprime hasta ser ilegible en vez de poder arrastrarse. */
@media (max-width: 767.98px) {
    .compare-block .comparador-main {
        overflow-x: auto;
    }

    .compare-block .comparador-main > div {
        max-width: 700px;
        width: 700px;
        overflow-x: auto;
    }
}

/* c) LAS DOS FILAS ALTAS.
 *
 * El skin fija 60 px en todas las filas porque sus datos de demo eran una
 * palabra (marca, talla, color). Aqui hay una descripcion de hasta 255
 * caracteres y una lista de etiquetas que el cliente escribe, asi que dos
 * filas necesitan mas. Los valores son MULTIPLOS EXACTOS de la unidad del
 * template (60 px), no numeros elegidos a ojo, para que el ritmo vertical de
 * la tabla siga siendo el suyo.
 *
 * Tienen que ser ALTURAS FIJAS y no `auto`: la columna de rotulos y la tabla
 * son dos elementos hermanos independientes, y si una fila creciera solo en la
 * tabla, los rotulos dejarian de estar enfrente de su dato. Por eso la celda
 * que puede desbordar (la descripcion) se desplaza por dentro — ver (e). */
.comparador-fila-2 {
    height: 120px;
}

.comparador-fila-3 {
    height: 180px;
}

/* d) EL NOMBRE DEL PRODUCTO, COMO SE GUARDO.
 *
 * La ficha de la cabecera usa `.text-title` del skin, que lleva
 * `text-transform: capitalize` (dist/output-scss.css:477). En un nombre de
 * demo no se nota; en uno real si: "DEMO Camiseta basica" salia como "DEMO
 * Camiseta Basica". El nombre lo escribe el cliente en el backoffice y se
 * pinta tal cual — mismo criterio que el titular de las valoraciones (§8·3). */
.comparador-nombre {
    text-transform: none;
}

/* e) LA DESCRIPCION CORTA.
 *
 * Mismo tratamiento que el cuerpo de las valoraciones (R5): se respetan los
 * saltos de linea que escribio el cliente y las palabras largas se parten en
 * vez de ensanchar la columna. Ademas, si el texto no cabe en los 180 px de su
 * fila, se desplaza DENTRO de la celda: es la unica forma de no romper el
 * enfrentamiento con la columna de rotulos (ver (c)). */
.comparador-descripcion {
    white-space: pre-wrap;
    word-break: break-word;
    overflow-wrap: break-word;
    overflow-y: auto;
}

/* f) LOS BOTONES DE LA FILA DE ACCIONES.
 *
 * `.button-main` del skin lleva `padding: 16px 40px`: 80 px de relleno lateral
 * pensados para un boton suelto a ancho de pagina. En la tabla hay hasta
 * CUATRO columnas repartiendose el ancho —a 1440 px tocan ~215 px por
 * producto, y en movil ~132 px sobre el lienzo de 700 px de (b)—, donde
 * "Anadir al carrito" con ese relleno no cabe. Se reduce el relleno y se deja
 * que el boton ocupe su columna, SIN tocar el resto del estilo (color, radio,
 * mayusculas y transicion siguen siendo los del skin) y SIN afectar a ningun
 * otro boton de la tienda: la regla esta acotada a la tabla. */
.comparador-main .button-main {
    padding: 10px 12px;
    width: 100%;
    text-align: center;
}

/* g) `border-t-0` NO EXISTE en el CSS servido, y sin ella la tabla sale con
 * lineas dobles.
 *
 * Es §10quater de manual. El JS de demo pone a cada celda
 * `border border-line border-t-0 border-r-0` —marco completo menos el borde
 * superior y el derecho, que ya los da la tabla—, pero el build de Tailwind
 * esta purgado a partir del HTML de Anvogue y esa utilidad NO llego a
 * compilarse: solo estan `border-r-0`, `border-b-0`, `border-b`, `border-r` y
 * `border-t` (comprobado una a una en dist/output-tailwind.css). Resultado
 * medido en el navegador: cada celda conservaba su borde superior de 1 px
 * junto al inferior de la fila de arriba, es decir una raya de 2 px entre
 * filas.
 *
 * No se pudo resolver copiando una cadena de clases que ya funcionase en el
 * kit —haria falta `border-l`, que tampoco existe—, asi que la declaracion va
 * aqui, ACOTADA a la tabla del comparador para no introducir una utilidad
 * global que el resto del sitio no tiene. Se conserva la clase en el marcado,
 * que es la del propio skin. */
.comparador-main td.border-t-0 {
    border-top-width: 0;
}

/* ---------------------------------------------------------------------------
 * 14) F17: acuse al usuario (assets/js/avisos.js) — componente propio del kit.
 *
 * Anvogue no trae toast, notice ni snackbar: se buscaron en su HTML, su CSS y
 * su SCSS y no hay ninguno; resuelve todo acuse con modales bloqueantes. Asi
 * que el estilo va aqui y no en dist/, igual que el aviso de cookies de §3, que
 * es el precedente directo de este componente y del que se copia el patron
 * entero (franja fija + `hidden` + esquive de la barra de movil).
 *
 * POR QUE CASI TODO ESTA ESCRITO A MANO. §10quater: se audito el CSS SERVIDO
 * por HTTP y NO sobreviven al purgado ninguna utilidad de `z-*`, ni
 * `shadow-lg`, ni `transition`, ni `opacity-*`, ni `pointer-events-none`, ni
 * `translate-*`, ni los arbitrarios tipo `max-w-[420px]`. Maquetar el acuse con
 * ellas habria dado un bloque sin capa, sin sombra y sin animacion. Lo que SI
 * sobrevive (estructura, tipografia y color) se usa desde el marcado:
 * `bg-white`, `border`, `border-line`, `rounded-xl`, `flex`, `items-center`,
 * `gap-3`, `py-4`, `px-5`, `caption1`, `text-secondary`, `w-full`, `text-xl`,
 * `text-lg`, `rounded-full`, `cursor-pointer`. Aqui solo va lo que no se puede
 * expresar con ellas, propiedad por propiedad:
 *
 *   position/bottom/left  franja fija; copiado de .aviso-cookies.
 *   z-index: 105          POR ENCIMA DEL MINI-CARRITO, que es 104 en el CSS
 *                         servido del skin. El acuse puede aparecer con el
 *                         mini-carrito abierto (es el caso normal tras anadir)
 *                         y su velo cubre la pantalla entera: con capa inferior
 *                         el acuse quedaria debajo del velo. Por encima tambien
 *                         del aviso de cookies (102) y de la .menu_bar (101).
 *   max-width             el arbitrario `max-w-[420px]` no sobrevive.
 *   box-shadow            `shadow-lg` no sobrevive; se toma la sombra del
 *                         propio skin (.box-shadow-sm) subiendo la opacidad,
 *                         porque aqui el bloque flota sobre contenido.
 *   opacity/transform     estado de entrada y salida; sin utilidades que valgan.
 *   transition            250 ms, el mismo valor que espera avisos.js.
 *   white-space: pre-line respeta los saltos de linea que ya traian los textos
 *                         escritos para alert() (comparador.js), sin tocarlos.
 *
 * ABAJO A LA IZQUIERDA, y no a la derecha: a la derecha estan el panel del
 * mini-carrito y el boton "Aceptar" del aviso de cookies. Tapar cualquiera de
 * los dos durante cinco segundos seria cambiar un estorbo por otro, que es
 * justo la queja de Q1 que esta ronda viene a quitar.
 * ------------------------------------------------------------------------- */
.aviso-kit {
    position: fixed;
    bottom: 20px;
    left: 20px;
    max-width: 420px;
    z-index: 105;
    box-shadow: 0 10px 25px 0 rgba(43, 52, 74, 0.22);
    /* OPACIDAD 1 EN REPOSO, y la entrada NO se anima. Medido: si la
       visibilidad depende de que una transicion avance, basta un motor que
       registre la transicion y no la componga para que el acuse se quede
       destapado y con su clase puesta pero con opacidad 0 para siempre, o
       sea invisible. La visibilidad no se juega a una animacion: se
       destapa y se ve. Lo unico que se anima es el deslizamiento de
       entrada y el fundido de SALIDA, donde un fallo solo alarga 250 ms
       un acuse que ya se leyo. */
    opacity: 1;
    transform: translateY(8px);
    transition: opacity 250ms ease, transform 250ms ease;
    /* Mientras no esta visible NO intercepta el raton. Un bloque `fixed` con
       opacidad 0 sigue capturando clics: en la esquina inferior izquierda
       habria un rectangulo muerto durante la entrada y la salida, y tambien
       si el navegador no llega a aplicar la clase. `pointer-events-none` es
       una de las utilidades que NO sobreviven al purgado (§10quater). */
    pointer-events: none;
}

.aviso-kit.esta-visible {
    transform: translateY(0);
    pointer-events: auto;
}

/* Fundido de salida. Va en su propia clase y no en la ausencia de
   .esta-visible para que el estado de reposo (antes de la primera aparicion)
   no sea tambien un estado de desvanecido. */
.aviso-kit.se-va {
    opacity: 0;
}

/* El texto conserva los saltos de linea del literal (F16: los textos no se
   reescriben, solo cambian de transporte).

   Y LLEVA SIEMPRE EL COLOR PRINCIPAL, en las tres clases de pantalla (F18-BIS).
   Antes lo pintaba la utilidad `text-secondary` del marcado, que es el color
   que el sistema de diseno reserva para lo accesorio; un acuse no es accesorio.
   `.aviso-kit [data-aviso-texto]` puntua (0,2,0) y `.text-secondary` (0,1,0),
   asi que gana sin `!important`. */
.aviso-kit [data-aviso-texto] {
    white-space: pre-line;
    color: var(--black);
}

/* -------------------------------------------------------------------------
   TONO. F18-BIS: EL COLOR DE MARCA NO VA NUNCA EN EL TEXTO.
   El texto lleva contraste (--black, 16,48:1) y el color va en la barra y en
   el icono, que son elementos graficos y se rigen por el umbral de 3:1.

   POR QUE, con el numero delante: el tono error pintaba el texto con --red,
   que da 4,27:1 sobre blanco y NO llega al 4,5:1 que WCAG AA pide para texto
   normal. Se auditaron las doce variables de color del skin servidas y NINGUNA
   roja llega (--red 4,27 · --pink 3,57 · --purple 3,35 · --success 2,98); las
   unicas que cumplen son --black y --secondary, que no son rojas. Asi que la
   cura no es oscurecer un rojo —eso seria inventar color fuera de la paleta—:
   es sacar el color del texto. Como marca grafica, --red cumple de sobra.

   AL DIA (CONTRASTE-ERRORES, §25): la decision de este bloque —el texto en
   --black y el color en la barra y el icono— SIGUE EN PIE y no se toca. Lo que
   ha cambiado es la premisa de la ultima frase: el escaparate SI tiene ya un
   rojo propio que llega a texto (`--kit-error`, #B91C1C), porque los mensajes
   de error de las otras ocho superficies eran texto rojo entero y no habia
   donde mover el color. La barra y el icono de aqui pasan a leer ese mismo
   token para que haya UN solo rojo de error, no dos.

   LA BARRA SE PINTA CON UN GRADIENTE, NO CON UN BORDE, y esto no es un capricho
   sino algo MEDIDO. F18 uso `border-left: 6px` en escritorio, donde el ancho
   esta fijado (`width: 620px`) y el borde no mueve nada. Al llevarlo a todas
   las pantallas: en movil tampoco movia (el ancho lo fijan `left`+`right` y
   `box-sizing` es border-box), pero EN TABLET el acuse se ajusta al contenido y
   el borde le sumaba 5 px de ancho en 8 de los 13 textos del kit. Eso es
   geometria, y en tablet la geometria no se toca. Un `background-image` pinta
   la barra sin participar del modelo de caja: cero px de diferencia en las tres
   pantallas. Ademas se recorta solo con el `border-radius` del contenedor.
   ------------------------------------------------------------------------- */
.aviso-kit {
    background-image: linear-gradient(to right, var(--black) 6px, transparent 6px);
}

/* CONTRASTE-ERRORES: el tono ya no sale de `--red` sino de `--kit-error`
   (#B91C1C, §25), que es la única definición del rojo de error del escaparate.
   Como marca gráfica el umbral sigue siendo 3:1 y ahora sobra más todavía:
   6,47:1 sobre el blanco de la franja, donde `--red` daba 4,27:1. */
.aviso-kit.es-error {
    background-image: linear-gradient(to right, var(--kit-error) 6px, transparent 6px);
}

.aviso-kit.es-error [data-aviso-icono] {
    color: var(--kit-error);
}

/* El boton de cierre es un objetivo tactil de verdad, no un icono suelto:
   32x32 es el mismo tamano que el kit ya usa en los botones de la pila de la
   tarjeta (corazon, comparar y compra rapida de Q1, §13). Sin :hover de por
   medio, que en tactil y en teclado no existe (§10bis). */
.aviso-kit-cerrar {
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    background-color: transparent;
    border: 0;
}

.aviso-kit-cerrar:hover {
    background-color: var(--surface);
}

/* El foco del tabulador tiene que VERSE: es la unica forma de saber donde esta
   el teclado, y el acuse no roba el foco, asi que se llega a el tabulando. */
.aviso-kit-cerrar:focus-visible {
    outline: 2px solid var(--black);
    outline-offset: 2px;
}

/* En movil la franja ocupa el ancho util y se levanta por encima de la
   .menu_bar del template (fixed, 70px), exactamente como hace .aviso-cookies:
   el esquive no se redescubre, se copia. */
@media (max-width: 639px) {
    .aviso-kit {
        left: 16px;
        right: 16px;
        max-width: none;
        bottom: 90px; /* 70px de .menu_bar + 20 de margen, el mismo que arriba */
    }
}

/* Sin animacion para quien la ha desactivado en su sistema. La opacidad final
   sigue siendo la misma: cambia el como, no el que. */
@media (prefers-reduced-motion: reduce) {
    .aviso-kit {
        transition: none;
        transform: none;
    }
    .aviso-kit.esta-visible {
        transform: none;
    }
}

/* ---------------------------------------------------------------------------
 * 15) Q2: confirmacion en el control pulsado, y latido del contador.
 *
 * POR QUE EXISTE. Medido en F17-BIS: al anadir al carrito el unico acuse era
 * que se abria el panel del mini-carrito (73,16 % del viewport en escritorio,
 * 79,79 % en movil), y el acuse de texto —cuando lo habia— salia a 418-863 px
 * del control pulsado. Anvogue resuelve esto en sus otros dos botones de
 * tarjeta reforzando EN EL PROPIO CONTROL: `.compare-btn.active` conmuta el
 * icono y lo pinta de verde con `scaleAnimate`, y `.add-wishlist-btn.active`
 * cambia el fondo. Anadir al carrito era la unica de las tres acciones sin
 * refuerzo bajo el dedo. Esta seccion se lo da.
 *
 * NO SE INVENTA NINGUNA ANIMACION. `scaleAnimate` es el keyframe del propio
 * skin (product.scss:879, servido en dist/output-scss.css: escala 1.3 -> 1 en
 * 0,5 s) y aqui solo se reutiliza. No hay pulse, ni shake, ni bounce: la
 * plantilla no los trae y esta ronda no los introduce.
 *
 * CLASE PROPIA CON PREFIJO `kit-`, NO `.active` (§10sexies, leccion de Q1).
 * `.active` esta enganchada POR DOCUMENTO en el JS de la demo: `main.js:357`
 * hace `document.querySelectorAll('.add-wishlist-btn')` y en la 370 le aplica
 * `classList.toggle('active')` a cada uno, en el nivel superior del fichero, o
 * sea que corre siempre. Reutilizar `.active` seria meter nuestro estado en una
 * clase que un script ajeno conmuta por su cuenta. Ademas no ahorraria nada:
 * las reglas del skin estan acopladas a `.compare-btn` / `.add-wishlist-btn`,
 * asi que sobre un boton de carrito no aplicarian igualmente.
 *
 * EL PAR DE COLOR ES DEL SKIN, NO ELEGIDO POR NOSOTROS: fondo `--green` con
 * texto `--black` es exactamente lo que `.button-main:hover` ya hace
 * (dist/output-scss.css). Se toma ese par y no el `#3DAB25` de
 * `.compare-btn.active` porque ese verde sobre blanco da 2,98:1 de contraste
 * —por debajo del 3:1 que WCAG pide a un elemento grafico— mientras que
 * `--green` (#D2EF9A) sobre `--black` da 12,99:1. Mismo lenguaje visual del
 * skin, y legible.
 *
 * LA VISIBILIDAD NO DEPENDE DE LA ANIMACION (regla de F17, entera). El cambio
 * de color y la conmutacion del icono son estado, no animacion: si el motor no
 * compone, o si el usuario ha pedido no ver movimiento, el boton se pone verde
 * y ensena el check igual. Lo unico que se pierde es el escalado.
 * ------------------------------------------------------------------------- */

/* El icono de confirmacion va SERVIDO en el marcado y oculto de serie, como el
   `checked-icon` de Anvogue: el JavaScript no construye marcado. */
.kit-icono-hecho {
    display: none;
}

[data-add-carrito].kit-confirmado .kit-icono-hecho {
    display: inline-block;
    animation: scaleAnimate 0.5s ease;
}

/* En el boton de icono de la tarjeta (Q1) el icono de reposo cede el sitio, que
   es la misma conmutacion que hace `.compare-btn.active` con su par de iconos. */
[data-add-carrito].kit-confirmado .kit-icono-reposo {
    display: none;
}

/* En los botones con texto el check se separa de la palabra. En el de icono no
   hace falta: alli es el unico contenido mientras dura la confirmacion. */
.button-main.kit-confirmado .kit-icono-hecho {
    margin-right: 8px;
}

/* El estado. `!important` en las dos declaraciones porque los tres botones
   traen sus colores en utilidades de Tailwind puestas en el marcado
   (`bg-white text-black` en la ficha) y la cascada las daria por ganadoras: sin
   esto el boton de la ficha se quedaria blanco. Es el mismo par que el skin usa
   en `.button-main:hover`, no un color nuevo.

   EL `:hover` VA EN EL SELECTOR A PROPOSITO, y no sobra. Con raton, tras pulsar
   el puntero SE QUEDA ENCIMA del boton, que es el caso normal y no el raro; y
   el skin trae `.button-main.bg-white:hover { background-color: var(--black) }`
   (dist/output-scss.css), que puntua (0,3,0) sobre el boton de la ficha. Por
   cascada el `!important` deberia bastar, pero MEDIDO en el navegador de
   pruebas el hover se imponia igual y el boton se quedaba negro justo en el
   instante que hay que ver. Nombrar el estado con hover lo cierra sin depender
   de como resuelva cada motor: es el mismo recurso que §1 usa con `:not(:hover)`
   por el mismo choque. */
[data-add-carrito].kit-confirmado,
[data-add-carrito].kit-confirmado:hover {
    background-color: var(--green) !important;
    color: var(--black) !important;
    /* EL COLOR ES ESTADO, NO ANIMACION (regla de F17, y aqui mordio igual).
       `.button-main` trae `transition: all ease 0.4s` del skin, asi que al
       cambiar el fondo el motor abre una transicion de 400 ms; MEDIDO: si no la
       compone, el color se queda en el de partida para siempre y el boton nunca
       se pone verde, mientras que el icono si aparecia porque `display` no es
       animable. La confirmacion no puede depender de que una transicion avance:
       se suprime, y el color entra en el acto. Lo unico que sigue animandose es
       el escalado del check, que es adorno y no informacion. */
    transition: none;
}

/* El latido del contador de la cabecera. Anvogue no anima este elemento —no
   tiene ni una regla propia en todo el skin— pero el keyframe es suyo y esta
   servido: reutilizarlo no es inventar. Se aplica a los DOS nodos, el de
   escritorio y el de la barra movil. */
.cart-quantity.kit-palpita {
    animation: scaleAnimate 0.5s ease;
}

/* Sin movimiento para quien lo ha pedido. El COLOR Y EL ICONO SIGUEN
   CAMBIANDO: lo unico que se suprime es el escalado. */
@media (prefers-reduced-motion: reduce) {
    [data-add-carrito].kit-confirmado .kit-icono-hecho,
    .cart-quantity.kit-palpita {
        animation: none;
    }
}

/* ---------------------------------------------------------------------------
 * 16) F18: el acuse deja de ser accesorio EN ESCRITORIO.
 *
 * POR QUE. El usuario lo probo en las tres clases de pantalla: en movil y en
 * tablet lo ve, en escritorio se le paso desapercibido — y el caso concreto fue
 * un ajuste de cantidad por stock, o sea el sistema cambiandole lo que habia
 * pedido. Cuadra con lo medido en F17-BIS §1.3: el acuse ocupa el 7,29 % del
 * viewport en movil y solo el 2,84 % en escritorio, con la MISMA tipografia y
 * el MISMO color que el aviso de cookies, que si se ve — porque aquel va a
 * ancho completo y ocupa el 9,33 %. El problema no era el acuse: era su escala.
 *
 * TODO LO DE ESTA SECCION VIVE DENTRO DE `min-width: 1024px`, y no es una
 * precaucion generica: movil y tablet estan dados por buenos por el usuario y
 * no se tocan. 1024 es el punto de ruptura que YA usan el skin (8 reglas en
 * dist/output-scss.css) y este mismo fichero (§10, el footer sin newsletter);
 * no se estrena ninguno. El tramo de tablet (768-1023) queda fuera por debajo,
 * que es justo lo que se pretende.
 *
 * QUE SE CORRIGE, ademas del tamano:
 *
 * 1) CONTRASTE DEL TONO ERROR. Estaba en 4,27:1 y AA pide 4,5:1 para texto
 *    normal. Se auditaron las doce variables de color del skin servidas: NINGUNA
 *    roja llega a 4,5:1 (`--red` 4,27 · `--pink` 3,57 · `--purple` 3,35 ·
 *    `--success` 2,98), y las unicas que cumplen son `--black` (16,48:1) y
 *    `--secondary` (5,28:1). Asi que no se oscurece ningun rojo inventando un
 *    tono nuevo: el TEXTO pasa a `--black` y el rojo se queda donde su contraste
 *    si basta —como marca grafica, umbral 3:1, y 4,27 lo supera de sobra—. El
 *    color no se pierde: cambia de sitio, del texto a la barra y al icono.
 *    (AL DIA, CONTRASTE-ERRORES §25: la barra y el icono leen ahora
 *    `--kit-error` en vez de `--red`. El reparto no cambia.)
 *
 * 2) COLOR DE TEXTO. Estaba en `--secondary`, que es el color que el sistema
 *    reserva para lo accesorio. Un acuse no es accesorio. Pasa a `--black`, el
 *    color de texto principal, en los DOS tonos.
 *
 * 3) MARCA DE TONO DE UN VISTAZO: barra de color a la izquierda, de 6 px. Se
 *    elige barra y no icono porque el icono ya existe y ya cambia por tono
 *    (`ph-info` / `ph-warning-circle`, los pone avisos.js) y aun asi no bastaba:
 *    un glifo de 20 px hay que enfocarlo, mientras que un rectangulo solido de
 *    color se percibe en vision periferica, que es exactamente lo que fallaba.
 *    Es CSS puro sobre el borde que el marcado ya trae, asi que no toca el JS ni
 *    el HTML servido. Neutro `--black` para el aviso y `--red` para el error:
 *    dos colores del skin, ambos por encima del 3:1 de elemento grafico.
 *
 * NO SE TOCA NADA DE LO PROHIBIDO: ni el anclaje (sigue fijo abajo a la
 * izquierda), ni el reloj, ni una linea de JavaScript, ni §3, ni §15, ni el
 * mini-carrito. No se introduce ninguna animacion ni ningun color que no
 * estuviera ya servido.
 * ------------------------------------------------------------------------- */
@media (min-width: 1024px) {
    .aviso-kit {
        /* ANCHO FIJO, no solo tope. Con `max-width` el bloque se encoge al
           contenido y el tono error —cuyo texto es corto— quedaba en 342 px
           frente a los 560 del aviso: dos pesos distintos para dos mensajes
           igual de importantes. En movil no pasa porque alli ocupa el ancho
           util entero. Se fija el ancho y los dos tonos pesan lo mismo. */
        width: 620px;
        max-width: calc(100vw - 40px);
        /* Sombra algo mas marcada: el bloque flota sobre mas contenido que en
           movil, donde ocupa casi todo el ancho. Mismo color de sombra del
           skin (`.box-shadow-sm`), subiendo alcance y opacidad. */
        box-shadow: 0 12px 32px 0 rgba(43, 52, 74, 0.28);
    }

    /* Relleno y separacion: las utilidades `py-4 px-5 gap-3` del marcado se
       quedan cortas a este tamano. Se ataca el hijo directo, que es la caja de
       la fila, sin tocar el marcado servido. */
    .aviso-kit > div {
        padding: 24px 28px;
        gap: 16px;
    }

    /* El texto: mas cuerpo y mas peso. SOLO tipografia — el color lo pone la
       base para las tres pantallas (F18-BIS). `.caption1` puntua (0,1,0) y
       esto (0,2,0), asi que gana sin necesidad de `!important`. */
    .aviso-kit [data-aviso-texto] {
        font-size: 17px;
        line-height: 26px;
        font-weight: 500;
    }

    .aviso-kit [data-aviso-icono] {
        font-size: 24px;
    }
}

/* ---------------------------------------------------------------------------
 * 17) E1: LA PORTADA DEJA DE PASAR POR DEBAJO DE LA CABECERA.
 *
 * EL PROBLEMA, MEDIDO. `.header-menu.style-one` es `absolute top-0` dentro de un
 * `#header` sin altura, asi que la cabecera FLOTA sobre lo primero que venga
 * detras. En la portada eso es el hero. Mientras el hero fue el degradado crema
 * del diseno con un recorte PNG, la cabecera —texto rgb(26,26,26)— se leyo
 * siempre. E1 pone esa foto en manos del cliente y con ella se cae la garantia.
 *
 * Medido sobre la captura del navegador con los glifos del menu ocultos, en el
 * pase 2 (interior de tienda, foto oscura), a 1280 px:
 *
 *   enlaces INICIO..CONTACTO   fondo rgb( 26, 26, 26)  ->  1,00:1
 *   iconos de la derecha       fondo rgb( 18, 54, 86)  ->  1,40:1
 *   logo NOMBRE CLIENTE        fondo rgb( 26, 26, 26)  ->  1,00:1
 *
 * 1,00:1 es negro sobre negro. Y NO lo causa el velo de la §18: en esa banda el
 * velo vale cero por diseno. Lo causa la foto. Con el cliente subiendo lo que
 * quiera, esto no es un caso raro: es el caso normal de cualquier foto de
 * interior, de noche o a contraluz.
 *
 * LA CORRECCION es quitar el solape, no anadir mas oscurecimiento: el hero
 * arranca DEBAJO de la cabecera, que queda sobre el fondo blanco de la pagina.
 * A partir de ahi el menu se lee siempre, sea cual sea la foto, y sin velo
 * ninguno. Es ademas la unica salida que RESTA oscurecimiento en vez de sumarlo.
 *
 * Se hace con `margin-top` sobre el bloque del slider y NO tocando la cabecera,
 * que es compartida por las 20 paginas del escaparate: si se pusiera en flujo
 * ahi, las otras 19 —que hoy compensan el solape en su propio breadcrumb—
 * ganarian 74 px de aire de la nada. El selector lleva `.style-five`, que solo
 * usa el slider de la portada, asi que el alcance es exactamente ese.
 *
 * Los valores son los de la PROPIA cabecera, no elegidos: su marcado es
 * `md:h-[74px] h-[56px]`.
 * ------------------------------------------------------------------------- */
.slider-block.style-five {
    margin-top: 56px;
}

@media (min-width: 768px) {
    .slider-block.style-five {
        margin-top: 74px;
    }
}

/* ---------------------------------------------------------------------------
 * 18) E1: velo del titular del slider. EL CONTRASTE NO PUEDE DEPENDER DE LA
 * FOTO QUE SUBA EL CLIENTE.
 *
 * ESTO NO VIENE DEL TEMPLATE, y conviene que quede escrito. Anvogue resuelve la
 * familia de slider "foto a sangre" poniendo el titular en blanco directamente
 * sobre la foto, SIN NINGUNA capa intermedia: revisado entero
 * `assets/scss/slider.scss` del paquete (250 lineas) y las 23 portadas, no hay
 * ni un pseudo-elemento de velo, ni un degradado sobre la imagen, ni una clase
 * `bg-black/40`. Lo que hace el template es elegir A MANO el color del texto de
 * cada pase segun la foto que le toca: en `yoga.html` el pase 1 lleva el titular
 * negro (:1187) y el 2 blanco (:1201), en la misma pagina. Eso funciona cuando
 * las fotos las pone el disenador y no cuando las sube el cliente.
 *
 * MEDIDO, no supuesto. Zona mas clara bajo la caja del texto, sin velo:
 *
 *   pase 1  rgb(255,250,229)  ->  1,05:1
 *   pase 2  rgb(228,202,168)  ->  1,58:1
 *   pase 3  rgb(255,255,255)  ->  1,00:1
 *
 * 1,00:1 es blanco sobre blanco. El minimo WCAG 2.1 para texto normal (el
 * sobretitulo son 12 px) es 4,5:1.
 *
 * OPACIDAD 0,56: sale del caso peor POSIBLE, que no es ninguna de las tres fotos
 * sino el BLANCO PURO, que es lo que puede subir cualquiera manana. Blanco puro
 * velado al 56 % queda en rgb(112,112,112) y el texto blanco da 4,94:1. Con 0,53
 * se llegaria al 4,5 justo y sin margen.
 *
 * FORMA: un FOCO ELIPTICO centrado en el texto, no una franja sobre media foto.
 * La primera version era un `linear-gradient(to left, ...)` que velaba la mitad
 * derecha de arriba abajo; se descarto al verla, porque apaga la foto en toda su
 * altura cuando el texto solo ocupa la banda central.
 *
 * LOS RADIOS SALEN DE MEDIR EL DOM. Caja del texto en % de la caja del pase:
 *
 *              centro x   centro y   semiancho   semialto
 *   1280        74,4 %      50 %       24,4 %     22,8 %
 *    768        73,9 %      50 %       23,9 %     19,0 %
 *    390        65,2 %      50 %       30,5 %     20,2 %
 *
 * Y AQUI ESTA EL DETALLE QUE FALLO EN EL PRIMER INTENTO: una elipse cuyos
 * semiejes valgan lo mismo que la mitad del rectangulo NO contiene sus esquinas.
 * La esquina cae a radio normalizado sqrt(2) = 1,41, asi que el nucleo a plena
 * opacidad tiene que ser 1,41 veces mayor que el semieje del rectangulo. Sin
 * eso, la medida sobre la captura daba 2,96:1 en la esquina inferior derecha
 * —fallando— mientras el centro iba sobrado.
 *
 * De ahi los numeros: nucleo minimo 24,4 x 1,41 = 34,5 % de ancho y
 * 22,8 x 1,41 = 32,2 % de alto en escritorio; 30,5 x 1,41 = 43,1 % y
 * 20,2 x 1,41 = 28,6 % en movil. Con la parada de opacidad plena en el 72 % del
 * radio, el radio total es 34,5/0,72 = 48 % y 32,2/0,72 = 45 % en escritorio, y
 * 43,1/0,72 = 60 % y 28,6/0,72 = 40 % en movil.
 *
 * Esto solo cabe porque la §17 ha sacado la cabecera de encima del hero: con el
 * menu flotando ahi arriba, un nucleo tan alto lo habria vuelto a tapar, y las
 * dos condiciones a la vez eran geometricamente incompatibles.
 *
 * COMO SE PINTA: `background-image` sobre `.slider-item`, que es exactamente la
 * misma caja que ocupa la foto. NO con un pseudo-elemento y NO con `border`, por
 * lo aprendido en F18-BIS: el fondo no entra en el modelo de caja, asi que no
 * desplaza ni un pixel del contenido, no cambia la altura del bloque y no
 * interfiere con el `overflow-hidden` del slide. Y cae en el sitio correcto
 * porque la foto va en `.sub-img` con `z-[-1]`: un z-index negativo se pinta por
 * DEBAJO del fondo de sus ancestros dentro del mismo contexto de apilado, de
 * modo que el fondo de `.slider-item` queda justo entre la foto y el texto sin
 * anadir ningun elemento nuevo al marcado.
 * ------------------------------------------------------------------------- */
.slider-block.style-five .slider-item {
    background-image: radial-gradient(
        ellipse 60% 40% at 65% 50%,
        rgba(0, 0, 0, 0.56) 0%,
        rgba(0, 0, 0, 0.56) 72%,
        rgba(0, 0, 0, 0) 100%
    );
}

@media (min-width: 640px) {
    .slider-block.style-five .slider-item {
        background-image: radial-gradient(
            ellipse 48% 45% at 74% 50%,
            rgba(0, 0, 0, 0.56) 0%,
            rgba(0, 0, 0, 0.56) 72%,
            rgba(0, 0, 0, 0) 100%
        );
    }
}

/* ---------------------------------------------------------------------------
 * 19) VAR-4B: EL SELECTOR DE OPCIONES TAMBIEN SE USA CON EL TECLADO.
 *
 * Anvogue estila `.color-item` y `.size-item` para raton y solo para raton
 * (`dist/output-scss.css:2947-2980`): el borde de seleccion aparece en `:hover`
 * y en `.active`, y el globo con el nombre del termino —`.tag-action`, que es
 * la UNICA via por la que se sabe que muestra es cual sin distinguir colores—
 * pasa de `opacity: 0` a `1` SOLO en `:hover`. Medido con el tabulador real
 * sobre la ficha servida antes de escribir esto: al llegar a la primera muestra
 * el globo seguia en `opacity: 0`, o sea que quien navega con teclado tenia
 * cuatro cuadros de colores y ni un nombre.
 *
 * Se anaden las dos mitades que faltaban, y nada mas:
 *
 *   1. EL NOMBRE EN EL FOCO. Misma declaracion que el `:hover` del skin, con el
 *      mismo selector y el mismo valor; no se toca el `:hover` original. Se usa
 *      `:focus-visible` y no `:focus` para que el globo no salte al pulsar con
 *      el raton, que es cuando el puntero ya lo esta ensenando.
 *
 *   2. UN ANILLO DE FOCO QUE SE VEA SOBRE CUALQUIER COLOR. El del navegador es
 *      `1px auto` y cae PEGADO a la muestra: sobre #1A1A1A no se distingue del
 *      propio cuadro. El anillo va con `outline-offset: 2px`, de modo que su
 *      vecino no es el color de la muestra sino el fondo de la pagina, que es
 *      `#FFFFFF` (medido en el navegador, no supuesto): `--black` #1F1F1F sobre
 *      #FFFFFF da 16,48:1, y WCAG 2.4.11 pide 3:1. Al ser un anillo EXTERIOR el
 *      numero no depende del color de la muestra, que es justo lo que hace
 *      falta cuando ese color lo elige el cliente.
 *
 * NO se toca el aspecto de `.active`: el estado elegido lo marca el borde de
 * 2 px que el skin ya pinta, y encima `aria-pressed`. El foco y la seleccion
 * son dos cosas distintas y se ven distintas (anillo separado contra borde
 * pegado).
 *
 * 3. UNA MUESTRA CLARA TIENE QUE TENER CONTORNO. El color lo escribe el
 *    cliente, asi que puede dar de alta "Blanco roto" (#FAF7F2, 1,07:1 sobre el
 *    #FFFFFF de la pagina): un control de interfaz que desaparece. Quien decide
 *    si hace falta es el SERVIDOR, con la formula de WCAG, en
 *    `components/opciones-variante.php`; aqui solo esta el valor.
 *
 *    El skin trae la idea (`.color-item.border-line`) pero no un valor que
 *    sirva: `--line` es #E9E9E9 y da 1,21:1 sobre blanco, o sea otro contorno
 *    invisible. Se usa #595F66, 6,45:1 sobre #FFFFFF y 6,04:1 sobre ese mismo
 *    blanco roto, que NO es un color nuevo del kit: es el que
 *    `admin/public/css/kit-admin-overrides.css` ya usa en `.kit-muestra-color`
 *    para este problema exacto, con su cifra escrita alli.
 *
 *    Se pinta con `box-shadow: inset` y NO con `border`, a proposito: el borde
 *    de esta muestra ya esta ocupado por el estado ELEGIDO (`.active` lo pone a
 *    2 px `--black`), y disputarselo obligaria a una cadena de `:not()` y
 *    dejaria a las muestras claras sin marca de seleccion visible. Un anillo
 *    interior no toca el modelo de caja, no mueve un pixel y convive con el
 *    borde: en una muestra clara elegida se ven los dos.
 * ------------------------------------------------------------------------- */
.list-color .color-item:focus-visible .tag-action {
    opacity: 1;
}

.list-color .color-item:focus-visible,
.list-size .size-item:focus-visible {
    outline: 2px solid var(--black);
    outline-offset: 2px;
}

.list-color .color-item.kit-muestra-clara {
    box-shadow: inset 0 0 0 1px #595F66;
}

/* ---------------------------------------------------------------------------
 * 20) VAR-4C: LA COMBINACION QUE NO EXISTE, Y LA QUE NO QUEDA.
 *
 * EL SKIN YA TIENE ESTE LENGUAJE, y no hay que inventarlo: `product-out-of-stock
 * .html` marca las muestras de un producto agotado con `filter: grayscale(0.9)`
 * mas un ASPA dibujada con `::before`/`::after`
 * (dist/output-scss.css:3173-3200). Es una forma, no un color, que es
 * justo lo que hace falta aqui. Se re-ancla, con TRES desviaciones declaradas:
 *
 * 1) POR ITEM, no por bloque. El selector del skin es
 *    `.product-detail.out-of-stock .product-infor.style-out-of-stock .color-item`:
 *    marca TODAS las muestras a la vez, porque alli el agotado es del producto
 *    entero. Aqui lo imposible es UNA opcion dada la otra, y cambia con cada
 *    clic, asi que la marca cuelga de una clase propia del item.
 *
 * 2) SIN `pointer-events: none` NI `border: none`. El skin apaga el elemento;
 *    aqui NO se puede, porque el requisito es que el motivo SE LEA: hay que
 *    poder llegar con el tabulador a la opcion imposible, oirla anunciada como
 *    no disponible (`aria-disabled`, que lo pone variantes.js) y pulsarla para
 *    que DIGA por que no. Un `disabled` de verdad la sacaria del tabulador y la
 *    dejaria muda — el defecto que esta ronda viene a evitar, no a repetir.
 *
 * 3) EL ASPA SE PINTA CON GRADIENTES, NO CON LOS DOS PSEUDO-ELEMENTOS DEL SKIN.
 *    Los suyos miden 150% y necesitan `overflow: hidden` en el boton para no
 *    desbordarse; ese `overflow` recortaria el globo `.tag-action`, que vive
 *    FUERA de la muestra (`top: -32px`) y es la unica via por la que se sabe que
 *    muestra es cual sin distinguir colores. Perder el nombre para ganar un aspa
 *    seria cambiar accesibilidad por decoracion. Con un solo `::after` a
 *    `inset: 0` y dos gradientes se dibuja la misma aspa sin recortar nada, y
 *    encima queda POR ENCIMA de la <img> de una muestra con foto, que con
 *    `background-image` sobre el boton no pasaria. Misma tecnica que
 *    `.kit-muestra-vacia` de kit-admin-overrides.css.
 *
 * EL COLOR DEL ASPA SE MIDE, y el del skin no servia: usa `--line` (#E9E9E9),
 * 1,21:1 sobre blanco. Como el fondo de la muestra lo elige el cliente y puede
 * ser cualquiera, no hay un color de aspa que garantice contraste sobre todos.
 * Se resuelve en dos capas: un VELO blanco al 62 % que aclara la muestra sea
 * cual sea, y el aspa en `--black` (#1F1F1F) encima. Medido el peor caso, negro
 * puro:
 *
 *   #000000 velado -> #9E9E9E   aspa #1F1F1F ->  6,15:1
 *   #1A1A1A velado -> #A8A8A8   aspa #1F1F1F ->  6,93:1
 *   #1F6FEB velado -> #AAC8F7   aspa #1F1F1F ->  9,67:1
 *   #FFFFFF velado -> #FFFFFF   aspa #1F1F1F -> 16,48:1
 *
 * El velo ademas deja la muestra palida, que es un segundo indicio de "esta no
 * se puede" independiente del aspa. Que la muestra velada pierda contraste
 * contra la pagina (el negro baja a 2,68:1) NO incumple 1.4.11: la norma exime
 * expresamente a los componentes inactivos, y esta lo esta.
 *
 * LOS DOS PARRAFOS DE MOTIVO siguen la doctrina de §16: el TEXTO en `--black`
 * (16,48:1 sobre el blanco de la pagina) y el rojo del skin reservado al ICONO,
 * que es marca grafica y le basta con 3:1. No se inventa ningun tono nuevo ni
 * se oscurece ningun rojo.
 *
 * AL DIA (CONTRASTE-ERRORES, §25): el icono ya no lee `--red` (4,27:1) sino
 * `--kit-error` (#B91C1C, 6,47:1 sobre blanco). El reparto no cambia —texto en
 * `--black`, color en el icono—; cambia de donde sale el rojo.
 * ------------------------------------------------------------------------- */
.kit-opcion-imposible {
    filter: grayscale(0.9);
    cursor: not-allowed;
}

.kit-opcion-imposible::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background-color: rgba(255, 255, 255, 0.62);
    background-image:
        linear-gradient(to top right,
            transparent calc(50% - 1px), var(--black) calc(50% - 1px),
            var(--black) calc(50% + 1px), transparent calc(50% + 1px)),
        linear-gradient(to top left,
            transparent calc(50% - 1px), var(--black) calc(50% - 1px),
            var(--black) calc(50% + 1px), transparent calc(50% + 1px));
}

/* La pildora de texto no es cuadrada: el aspa se dibuja igual, pero el texto
   tiene que seguir leyendose por debajo del velo, asi que ahi el aspa no lo
   tapa — se queda en el velo mas el `grayscale`, y el nombre del termino sigue
   siendo legible, que es lo que de verdad identifica a una pildora. */
.list-size .kit-opcion-imposible::after {
    background-image: none;
}

.list-size .kit-opcion-imposible {
    text-decoration: line-through;
}

.kit-combi-imposible {
    color: var(--black);
    margin: 0;
}

/* CONTRASTE-ERRORES: el icono pasa de `--red` a `--kit-error` (§25). Sigue
   siendo marca gráfica con umbral 3:1; sube de 4,27:1 a 6,47:1 sobre blanco. */
.kit-combi-imposible i {
    color: var(--kit-error);
    margin-right: 4px;
}

/* ---------------------------------------------------------------------------
 * 21) VAR-4C: LA MUESTRA ELEGIDA SE TIENE QUE VER, SEA DEL COLOR QUE SEA.
 *
 * MEDIDO, no supuesto: el skin marca la elegida con
 * `.list-color .color-item.active { border-color: var(--black) }`
 * (dist/output-scss.css:2947). `--black` es #1F1F1F, y la muestra «Negro» de la
 * semilla es #1A1A1A: el borde sobre su propia muestra da **1,03:1**, o sea que
 * elegir Negro no se ve. Se pilló en la captura de esta ronda, con Negro
 * elegido y sin ninguna diferencia visible frente a no elegido.
 *
 * No es un problema de contraste de texto: es que el ESTADO desaparece. Y el
 * color de la muestra lo escribe el cliente, asi que no hay un color de borde
 * que valga para todos — el mismo callejon que la muestra clara de VAR-4B, y se
 * resuelve igual: sacando la marca FUERA de la muestra, donde su vecino es el
 * fondo de la pagina y no un color desconocido.
 *
 * Anillo doble con `box-shadow`: primero 2 px de `--white`, que separa, y luego
 * 2 px de `--black`, que marca. Contra el #FFFFFF de la pagina, `--black` da
 * **16,48:1** (umbral 3:1 de WCAG 1.4.11 para elemento no textual). Al ser
 * exterior el numero NO depende del color de la muestra.
 *
 * `box-shadow` y no `outline` a proposito: el `outline` ya esta ocupado por el
 * anillo de FOCO de §19, y son dos estados distintos que tienen que poder verse
 * a la vez —una muestra puede estar enfocada y elegida—. Asi el foco queda por
 * fuera del anillo de eleccion y no hay que elegir entre uno u otro.
 *
 * NO sustituye al borde del skin, se suma: en las muestras claras el borde de
 * `--black` sigue viendose y aqui solo se anade el refuerzo exterior.
 *
 * Y NO ES LA UNICA SENIAL, que es lo que pide 1.4.1: el rotulo del eje escribe
 * el nombre de lo elegido («Color: Negro») y el boton lleva `aria-pressed`.
 * ------------------------------------------------------------------------- */
.list-color .color-item.active {
    box-shadow: 0 0 0 2px var(--white), 0 0 0 4px var(--black);
}

/* ---------------------------------------------------------------------------
 * 22) VAR-5B: EL ATAJO «ELEGIR OPCIONES» ES UN OBJETIVO TACTIL DE VERDAD.
 *
 * El control re-ancla la cadena de clases del `.quick-shop-btn` de Anvogue
 * (ver la nota larga en components/tarjeta-producto.php), y con ella hereda un
 * problema del skin: `.text-button-uppercase` baja a 12px/16px por debajo de
 * 767.98px, asi que el mismo `py-3` que en escritorio da 46 px de alto se
 * queda en 39 en movil. Justo donde mas duele, que es una tarjeta de catalogo
 * de 154 px que se pulsa con el pulgar.
 *
 * 44 px NO es un numero inventado para esta ronda: es el que el kit ya exige
 * en el paginador del catalogo (`w-[44px] h-[44px]`, pages/catalogo.php), y el
 * que la leccion de F11-R5 dejo escrita en docs/REQUERIMIENTOS_SISTEMA.md
 * despues de que un boton que debia medir 44x44 se sirviera de 11x26.
 *
 * `min-height` y no `height`: si algun dia el nombre del producto obligara al
 * texto a envolver, el control tiene que CRECER, no recortar. Y no se toca el
 * `py-3`, que es lo que da el aire en escritorio.
 *
 * No hace falta regla de `:hover` —las dos variantes `hover:` del skin SI
 * estan en el Tailwind servido, comprobado— ni de `:focus-visible`: el anillo
 * por defecto del navegador se ve entero porque este enlace va FUERA del
 * `.product-thumb`, que es el unico contenedor de la tarjeta con
 * `overflow: hidden`.
 * ------------------------------------------------------------------------- */
.elegir-opciones-btn {
    min-height: 44px;
}

/* ---------------------------------------------------------------------------
 * 21) BUSCADOR: LA LUPA SE PUEDE PULSAR CON EL PULGAR.
 *
 * Las dos lupas del escaparate (modal de footer.php y menu movil de
 * header.php) han pasado de <i> inerte a <button type="submit"> de un <form>
 * real al catalogo. Un boton hay que poder pulsarlo, y la del menu movil es la
 * que mas se usa en telefono.
 *
 * 44 px no sale de ninguna utilidad de Tailwind aqui: el skin sirve
 * `rem = 14px` (assets/css/fuentes.css), asi que `w-12` (3rem) mide 42 px
 * MEDIDOS a 375, `w-11` (2.75rem, los 44 exactos) no esta en
 * dist/output-tailwind.css porque ningun template la usaba, y `w-14` se iria a
 * 49 y desbordaria el campo. Se fijan con `min-*`, que es exactamente lo que
 * la §20 hace en `.elegir-opciones-btn` y lo que
 * docs/REQUERIMIENTOS_SISTEMA.md dejo escrito tras F11-R5.
 *
 * La clase es PROPIA (.kit-lupa-buscar) y no `.form-search button`: ese
 * selector alcanzaria tambien al boton "Buscar" del catalogo, que vive con
 * `top-1 bottom-1` DENTRO de un campo de 44 px de alto en movil — forzarle
 * 44 de alto lo haria desbordar su propio campo.
 *
 * El padding del campo del menu movil sube a 48 px por lo mismo: `pl-12` son
 * esos 42 px, y el texto escrito pasaria por debajo de una lupa de 44.
 * ------------------------------------------------------------------------- */
.kit-lupa-buscar {
    min-width: 44px;
    min-height: 44px;
}

#menu-mobile .form-search input {
    padding-left: 48px;
}

/* ---------------------------------------------------------------------------
 * 23) TECLADO-CANTIDAD: LOS CONTROLES DE CANTIDAD Y DE QUITAR SON BOTONES.
 *
 * El marcado ha pasado de `<i>` + `<div>` a `<button>` + `<input type="number">`
 * (components/linea-carrito.php y pages/producto.php). No hace falta reponer
 * casi nada de aspecto: el reset de Tailwind ya le quita al boton el fondo, el
 * borde y el relleno, y le hereda tipografia y color (dist/output-tailwind.css
 * :197-243), asi que las MISMAS clases `.ph-bold .ph-plus` pintan el mismo glifo
 * que pintaban sobre el `<i>`. Lo que si hace falta es lo que un `<i>` no tenia:
 * tamano de objetivo, un campo que no parezca un campo, y un foco que se vea.
 *
 * 1) 44 px MEDIDOS, y por eso el bloque pierde su relleno lateral.
 *
 *    El icono medido a 375 era de 14x14 en el carrito y 16x16 en la ficha:
 *    objetivos de un tercio de lo que hay que dar. 44 no sale de ninguna
 *    utilidad de Tailwind —el skin sirve `rem = 14px`, asi que `w-12` da 42 y
 *    `w-11` no esta compilada—, se fija con `min-*` como en §20 y §21.
 *
 *    Y hay una cuenta que obliga a tocar el bloque: 44 + 44 no caben en los
 *    70 px que el `.quantity-block` del carrito medi­a a 375 (`w-20`), ni en los
 *    100 de escritorio con su `md:p-3`. El minimo honesto es
 *    44 (menos) + 32 (campo) + 44 (mas) = 120, y para llegar a 120 sin ensanchar
 *    la fila mas de lo imprescindible se le quita al bloque el relleno LATERAL
 *    (el vertical tambien, que ya lo dan los 44 px de alto de los controles).
 *    El borde y el fondo del bloque no se tocan: sigue viendose igual.
 *
 *    Medido despues, a 375: la columna de cantidad del carrito pasa de 100 a
 *    120 y los tres controles miden 44x44 clavados. Lo que esa columna gana lo
 *    sueltan las dos de su derecha (ver la regla `.kit-columna-cantidad`).
 *
 * 2) EL CAMPO NO PUEDE PARECER UN CAMPO. Es el mismo numero de siempre en el
 *    mismo sitio; que ahora se pueda escribir en el no autoriza a meter una caja
 *    blanca con borde dentro de otra. Fondo transparente, centrado y sin las
 *    flechas nativas de `type="number"`, que duplicarian los dos botones que
 *    tiene al lado. Las flechas del TECLADO siguen funcionando: eso es del tipo
 *    de campo, no de su adorno.
 *
 * 3) UN FOCO QUE SE VEA, CON `outline-offset` NEGATIVO. §19 lo saco fuera del
 *    control porque alli el vecino era el color de una muestra; aqui el vecino
 *    de los pasos es el borde del bloque y el campo, a cero pixeles: un anillo
 *    exterior se solaparia con los dos. Va por DENTRO de los 44 px, que para eso
 *    sobran. Color `--black` (#1F1F1F), y los fondos reales sobre los que cae
 *    son dos, los dos medidos en el navegador y no supuestos:
 *      · `--surface` #F7F7F7 en el bloque del carrito -> 15,39:1
 *      · `--white`  #FFFFFF  en el bloque de la ficha y en la columna del
 *        aspa de quitar -> 16,48:1
 *    WCAG 2.4.11 pide 3:1. `--white` es estructural del skin y no se configura
 *    (ver el contrato de branding en CLAUDE.md); `--surface` tampoco.
 *
 * ALCANCE ACOTADO, como pide §21: clases propias (`.kit-paso-cantidad`,
 * `.kit-campo-cantidad`, `.kit-quitar-linea`, `.kit-bloque-cantidad`) y no
 * `.quantity-block button`, que alcanzaria a cualquier control que el skin meta
 * ahi dentro manana.
 * ------------------------------------------------------------------------- */
.kit-bloque-cantidad {
    padding: 0;
    min-width: 120px;   /* 44 + 32 + 44 */
}

/* La COLUMNA de la fila del carrito crece con el bloque, y no es un detalle.
   Sus anchos son porcentuales (`w-1/6`), asi que un hijo `flex-shrink-0` de 120
   no ensancha la fila: se DESBORDA. Medido a 375 antes de esta regla, el bloque
   salia de 356 a 476 dentro de una columna de 366 a 466 y se montaba 10 px sobre
   el precio de la izquierda, que a ese ancho ya iba justo.

   Con el minimo en la columna, medido otra vez a 375: la fila NO se ensancha
   —sigue en 600, dentro del `overflow-x: auto` que el `.list-product` del
   carrito ya tenia—, y los 20 px salen de las dos columnas que si pueden
   encoger: total 100 -> 86 y quitar 50 -> 44 (justo los 44 del boton). Ni una
   se monta sobre otra a 375, 768, 1024 ni 1440. */
.kit-columna-cantidad {
    min-width: 120px;
}

.kit-paso-cantidad,
.kit-quitar-linea {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    min-width: 44px;
    min-height: 44px;
}

.kit-campo-cantidad {
    flex: 1 1 auto;
    width: 100%;
    min-width: 32px;
    min-height: 44px;
    text-align: center;
    background-color: transparent;
    -moz-appearance: textfield;
    appearance: textfield;
}

.kit-campo-cantidad::-webkit-outer-spin-button,
.kit-campo-cantidad::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.kit-paso-cantidad:focus-visible,
.kit-quitar-linea:focus-visible,
.kit-campo-cantidad:focus-visible {
    outline: 2px solid var(--black);
    outline-offset: -2px;
}

/* EL ANILLO NO SE DESVANECE. El aspa de quitar lleva del skin la utilidad
   `duration-300` sobre un `transition-property: all` heredado, asi que el
   `outline` entraba en la transicion: medido a mitad de camino daba
   rgb(45,34,34) y offset -1px, o sea 300 ms hasta llegar a los 2 px de
   #1F1F1F. Un indicador de foco tiene que estar entero EN CUANTO llega el
   foco. Se acota la transicion a `color`, que es lo unico para lo que el skin
   la puso (`hover:text-black`), y se deja fuera el resto. */
.kit-quitar-linea {
    transition-property: color;
}

/* ---------------------------------------------------------------------------
 * 24) TIENDA-VACIA: LA SALIDA DE UN ESTADO VACIO SE PUEDE PULSAR.
 *
 * Los cinco estados vacios del kit —carrito, favoritos, comparador, ficha 404 y
 * el catalogo sin productos— terminan igual: una frase y UN boton que lleva a
 * algun sitio. Ese boton es lo unico que se puede hacer en esa pantalla, asi
 * que es justo el que no puede fallar bajo el pulgar.
 *
 * MEDIDO a 375 antes de esta regla: 141x36 los cuatro que ya existian, 179x36
 * el que anade esta ronda. Es el mismo defecto que §20 dejo escrito para
 * `.elegir-opciones-btn`: `.text-button-uppercase` baja a 12px por debajo de
 * 767.98px, asi que el `py-2` de `.button-main` da 52 px en escritorio y se
 * queda en 36 en movil. Y 44 no sale de ninguna utilidad de Tailwind, porque el
 * skin sirve `rem = 14px` (assets/css/fuentes.css): `w-12` mide 42, no 48.
 *
 * POR QUE LA LISTA DE SELECTORES Y NO UNA CLASE PROPIA EN LOS CINCO. Los cuatro
 * que ya existian se sirven SIEMPRE en el HTML (nacen ocultos y los destapa el
 * JS), asi que anadirles una clase moveria los bytes de tres paginas que esta
 * ronda tiene que dejar identicas al byte. Se les alcanza por el `id` que ya
 * llevan —que existe justamente para identificar el estado vacio— y solo lo
 * nuevo estrena clase. El 404 de la ficha no tiene id, y se le alcanza por su
 * `.thank-you-block`, que en esa pagina solo envuelve ese bloque.
 *
 * NO se toca `.button-main` a secas ni `.content-main .block-button`: ese
 * segundo selector alcanzaria tambien al «Comparar productos» del mini-carrito,
 * que va en todas las paginas y no es la salida de ningun vacio.
 * ------------------------------------------------------------------------- */
#carrito-vacio .button-main,
#favoritos-vacio .button-main,
#comparador-vacio .button-main,
.thank-you-block .content-main .button-main,
.kit-vacio .button-main {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* ---------------------------------------------------------------------------
 * ENVIO-FLUJO — EL SELECTOR DE ENTREGA DEL CHECKOUT.
 *
 * Los colores NO salen de las utilidades del skin. `.text-red` es #DB4444, que
 * sobre blanco da 4,27:1 y no llega al 4,5:1 que WCAG 1.4.3 exige a
 * texto — es el mismo motivo por el que VAR-2B1 le puso clase propia al aviso
 * de imagen rota. Los tres tonos de aquí están medidos sobre el fondo blanco de
 * la tarjeta del checkout.
 *
 * Y NUNCA SOLO COLOR: el método no disponible se distingue además por su opacidad
 * y por el motivo escrito debajo, no por el tono del texto.
 * ------------------------------------------------------------------------- */

/* Aviso de que el importe o el método han cambiado. Azul informativo, no rojo:
   no es un error del comprador, es una consecuencia de su dirección. */
.kit-aviso-envio {
    background: #E7F0FB;
    color: #0B3D6B;          /* 8,59:1 sobre #E7F0FB */
    border-left: 4px solid #1A5FA8;
}

/* El método que no aplica: atenuado, sin puntero, y con su motivo debajo. */
.kit-metodo-no {
    opacity: .65;
    cursor: not-allowed;
}
/* CONTRASTE-ERRORES: era un rojo propio (#7A1414). Un motivo por el que un
   método de entrega NO se puede usar es un aviso, así que lleva el rojo de
   error del escaparate y no uno suyo: `--kit-error`, 6,47:1 sobre blanco. */
.kit-motivo {
    color: var(--kit-error);
}
.kit-sin-direccion {
    color: #14532D;          /* 8,93:1 sobre blanco */
}
.kit-instrucciones {
    color: #3F3F46;          /* 10,15:1 sobre blanco */
}
.kit-sin-envio-aviso {
    background: #E7F5EC;
    color: #14532D;          /* 7,95:1 sobre #E7F5EC */
}

/* El botón del camino SIN JavaScript. 44 px de alto: es un objetivo táctil de
   pleno derecho, y es el único control con el que se recalcula cuando no hay
   script. */
.kit-btn-envio {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding-left: 1.25rem;
    padding-right: 1.25rem;
}

/* Los radios del selector: 24 px reales y su etiqueta entera es zona de clic,
   así que el objetivo efectivo lo da el `label`, que ocupa la fila.
   CHECKOUT-FORMULARIO: el gancho pasa de `#form-envio` a `#bloque-envio`. El
   selector dejó de ser un formulario propio —sus radios pertenecen ahora al de
   confirmar, por el atributo `form`— pero sigue siendo el mismo bloque en la
   misma caja: lo que cambia es la etiqueta que lo envuelve, no el estilo. */
#bloque-envio input[type="radio"] {
    width: 24px;
    height: 24px;
}
#bloque-envio label {
    min-height: 44px;
    display: flex;
    align-items: flex-start;
    padding-top: .5rem;
    padding-bottom: .5rem;
}

/* ---------------------------------------------------------------------------
 * CHECKOUT-FORMULARIO — LAS PUERTAS QUE ERAN ENLACES Y AHORA SON BOTONES.
 *
 * «Volver al carrito», «Añádelo en el carrito», «Cambiar el cupón en el
 * carrito» y «Entrar con mi cuenta» han pasado de `<a>` a `<button
 * type="submit">` para que lo tecleado viaje antes de navegar. Lo que hacen no
 * ha cambiado —llevan a la misma pantalla— y por tanto TAMPOCO DEBE CAMBIAR SU
 * ASPECTO: un control que cambia de pinta sin cambiar de función es una
 * pantalla distinta para el comprador aunque el código sepa que es la misma.
 *
 * Esta clase deshace lo que el navegador le pone de suyo a un `<button>` (fondo
 * gris, borde, tipografía propia, alineación centrada) y lo devuelve al flujo
 * del texto, para que las clases del skin —`text-button`, `hover-underline`,
 * `text-secondary`, `underline`— pinten exactamente lo que pintaban en el
 * enlace. No lleva color ni tamaño: eso sigue viniendo de esas clases, que son
 * las mismas de antes.
 *
 * `cursor: pointer` porque sin él un `<button>` sale con la flecha; los enlaces
 * de al lado llevan la mano y esto está entre ellos.
 * ------------------------------------------------------------------------- */
.kit-boton-enlace {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: inherit;
    text-align: inherit;
    cursor: pointer;
}

/* ---------------------------------------------------------------------------
 * ENVIO-FLUJO — EL FOCO DEL SELECTOR, VISIBLE.
 *
 * MEDIDO Y ROTO: el skin de Anvogue anula el `outline` de los `input`, así que
 * los radios del método y el campo del código postal recibían el foco sin que
 * se viera NADA —`outlineStyle: none` y `boxShadow: none` con y sin foco, misma
 * pinta en los dos estados—. Quien navegue con teclado no sabría dónde está.
 * El botón «Actualizar envío» sí lo tenía (el `outline: auto` del navegador),
 * lo que confirma que la supresión venía del skin y no del navegador.
 *
 * Se le pone anillo propio, y con `:focus-visible` y no con `:focus`: así
 * aparece a quien navega con teclado y no en cada clic de ratón, que es lo que
 * el navegador ya distingue por nosotros.
 *
 * El color es el mismo azul del resto de avisos de envío (#1A5FA8), que da
 * 5,29:1 sobre el blanco de la tarjeta — por encima del 3:1 que WCAG 1.4.11
 * pide a un indicador no textual, y por encima incluso del 4,5:1 de texto.
 * ------------------------------------------------------------------------- */
/* CHECKOUT-FORMULARIO — mismo gancho nuevo, y el anillo SE EXTIENDE al
   formulario de confirmar. No es una mejora de propina: al retirar el campo
   «Código postal (para calcular el envío)» —había dos `cp` en la pantalla— su
   función se muda al `cp` de la dirección, y ese campo NO tenía anillo, así que
   sin esto quien navega con teclado perdería el indicador justo en el control
   que hereda el trabajo. Se repone donde acaba de irse, y de paso lo tienen los
   otros nueve campos: el skin de Anvogue anula el `outline` de todos por igual
   y el motivo por el que aquél lo llevaba —que el foco se vea— nunca fue
   exclusivo suyo. */
#bloque-envio input[type="radio"]:focus-visible,
#bloque-envio button:focus-visible,
#form-checkout input:focus-visible,
#form-checkout textarea:focus-visible {
    outline: 3px solid #1A5FA8;
    outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
 * 25) CONTRASTE-ERRORES — UN SOLO ROJO PARA LO QUE VA MAL, Y QUE SE LEA.
 *
 * EL DEFECTO, MEDIDO. La utilidad `.text-red` del skin es #DB4444
 * (dist/output-tailwind.css:2725, `--red` en assets/scss/globals.scss:24). Con
 * ella el escaparate pintaba TODOS sus mensajes de error, y ninguno llegaba al
 * 4,5:1 que WCAG 1.4.3 pide a texto normal:
 *
 *     · sobre el blanco de la página ............ 4,27:1   (errores de campo)
 *     · sobre `--surface` #F7F7F7 ............... 3,98:1   (píldora del flash,
 *                                                 cupón rechazado, #avatar-error)
 *
 * Y no es que se quedara corto en un caso: #DB4444 NO alcanza 4,5:1 sobre
 * NINGÚN fondo, ni siquiera sobre blanco puro. No hay fondo que lo salve.
 *
 * (Corrección de dato: el bloque ENVIO-FLUJO de más arriba decía que `.text-red`
 * era #DC3545 con 4,30:1. El hex era erróneo; lo servido es #DB4444 y 4,27:1.
 * La conclusión de aquel bloque —que no llega a AA— era y sigue siendo cierta.)
 *
 * EL COLOR, ELEGIDO CON LA CIFRA Y SOBRE LOS DOS FONDOS REALES. Se midieron los
 * dos candidatos sobre TODAS las superficies del censo, no sólo sobre blanco:
 *
 *     color      blanco   #F7F7F7   #E9E9E9 (`--line`)
 *     #DB4444    4,27      3,98      3,51      <- lo que había
 *     #C42121    5,86      5,47      4,82
 *     #B91C1C    6,47      6,04      5,33      <- ELEGIDO
 *
 * SE ELIGE #B91C1C POR EL MARGEN, no por gusto. Los dos candidatos cumplen hoy;
 * lo que los separa es cuánto aguantan si el fondo se oscurece — y el fondo de
 * este kit ES CONFIGURABLE (`COLOR_FONDO` de config.php pinta `body`, ver el
 * contrato de branding en CLAUDE.md). Calculado el gris más oscuro que cada uno
 * soporta sin bajar de 4,5:1: #C42121 aguanta hasta #E2E2E2 y #B91C1C hasta
 * #D8D8D8. Diez tonos más de margen sobre una variable que escribe el cliente.
 *
 * UN SOLO COLOR PARA TEXTO Y PARA GRÁFICO, y esto se comprobó, no se supuso: el
 * umbral del gráfico es 3:1 (WCAG 1.4.11) y el del texto 4,5:1 (1.4.3), así que
 * bastaba con que el color del texto —el exigente— sirviera también de gráfico.
 * #B91C1C da 6,04:1 en el peor fondo del censo: pasa el 3:1 con más del doble.
 * NO hacen falta dos tonos, y por tanto no se crean.
 *
 * UNA SOLA DEFINICIÓN, y se retiran las otras. Antes de esta ronda el rojo de
 * error estaba escrito en TRES sitios distintos: `--red` del skin (mensajes,
 * barra e icono del acuse §16, icono de combinación imposible §20) y el #7A1414
 * de `.kit-motivo` (ENVIO-FLUJO). Los tres pasan a leer `--kit-error`, que es
 * la única declaración del tono en todo el escaparate. Si algún día hay que
 * moverlo, se mueve aquí y en ningún otro sitio.
 *
 * LO QUE NO ES UN ERROR NO SE TOCA, y por eso NO se redefine `.text-red` a
 * secas: esa utilidad también pinta cosas que no comunican ningún problema, y
 * cambiarlas sería el efecto colateral que esta ronda tiene que evitar. Se
 * quedan exactamente como estaban (medidas y anotadas en el informe):
 *
 *     · el aspa «quitar del carrito» y el chip «Limpiar filtros» del catálogo
 *       — son ACCIONES destructivas, no avisos;
 *     · el asterisco de campo obligatorio y el «Eliminar» de la libreta de
 *       direcciones — lo mismo;
 *     · la insignia «Oferta» (`bg-red`), la barra de vendidos y el corazón de
 *       favoritos activo — son marca comercial.
 *
 * SÓLO CSS: ni una línea de marcado, ni de PHP, ni de JavaScript. Las nueve
 * superficies se alcanzan por atributos y por `id` que el HTML YA trae
 * (`data-error`, `role="status"`, `.flash-mensajes`), que es la misma técnica
 * que §24 usó para no mover un byte de las páginas servidas.
 *
 * ESPECIFICIDAD, comprobada una por una: `.text-red` puntúa (0,1,0), y cada
 * selector de aquí puntúa (0,2,0) o (1,0,0). Ganan sin `!important`.
 * ------------------------------------------------------------------------- */
:root {
    --kit-error: #B91C1C;
}

/* TEXTO que comunica un problema — umbral 4,5:1 (WCAG 1.4.3).
   Las nueve superficies del censo, por el gancho que cada una ya tenía:
     · `.flash-mensajes .text-red` .... píldora de error de components/cuenta-flash.php
                                       (carrito, checkout, login, registro, mi-cuenta,
                                       recuperar, restablecer y valorar), sobre #F7F7F7;
     · `[data-error].text-red` ........ los 9 errores de campo del checkout y los 5
                                       del contacto, sobre blanco;
     · los tres `id` .................. el error general del checkout, el del contacto
                                       y el del avatar de mi cuenta;
     · `.text-red[role="status"]` ..... el cupón retirado, que se pinta con el MISMO
                                       marcado en components/cupon-carrito.php (sobre
                                       #F7F7F7) y en pages/checkout.php (sobre blanco). */
.flash-mensajes .text-red,
[data-error].text-red,
#error-checkout,
#error-contacto,
#avatar-error,
.text-red[role="status"] {
    color: var(--kit-error);
}

/* EL GRÁFICO que comunica un problema —umbral 3:1 (WCAG 1.4.11)— NO se
   redeclara aquí. Sus tres reglas ya existían y se han REESCRITO EN SU SITIO
   para que lean `--kit-error`, que es lo que pide no tener dos definiciones:
   duplicarlas al final habría dejado justo las dos que esta ronda retira.
     · `.aviso-kit.es-error` (barra) e icono del acuse .......... §16
     · `.kit-combi-imposible i` (combinación que no existe) ..... §20
     · `.kit-motivo` (método de entrega que no aplica) .......... ENVIO-FLUJO */

/* ---------------------------------------------------------------------------
 * 26) AVISOS-SENAL — LA BARRA DE LA PÍLDORA DE ERROR, Y EL CONTADOR QUE NO
 *     LLEGABA A PINTARSE.
 *
 * 1) LA BARRA DE `.flash-mensajes .text-red`.
 *
 * El porqué está razonado en components/cuenta-flash.php: las dos ramas del
 * flash compartían fondo, relleno, radio y margen, y sólo las separaba el color
 * del texto (WCAG 1.4.1). El icono es la señal fuerte y va en el marcado; esto
 * es la segunda, y aquí la señal NO es de qué color es la barra sino que la
 * barra ESTÁ: el aviso neutro no lleva ninguna.
 *
 * `background-image` Y NO `border-left`, copiando §16 y por su misma medición:
 * un borde participa del modelo de caja y le sumaría 6 px de ancho a la
 * píldora; un gradiente no, y además se recorta solo con el `rounded-lg` que la
 * píldora ya trae. La píldora tiene `background-color: #F7F7F7` de `bg-surface`
 * y el gradiente se pinta ENCIMA, así que los dos conviven sin que uno anule al
 * otro (`background-image` y `background-color` son propiedades distintas).
 *
 * Cero bytes de HTML: se alcanza por el mismo selector que ya existe en §25.
 *
 * 2) `.kit-contador-limite` — EL AVISO DE «QUEDAN POCOS CARACTERES».
 *
 * ESTABA MUERTO Y NO SE VEÍA QUE LO ESTUVIERA. pages/valorar.php hacía
 * `classList.toggle('text-red', quedan <= 50)` sobre un nodo que ya lleva
 * `text-secondary`. Las dos utilidades puntúan (0,1,0), así que decide el ORDEN
 * del fichero compilado — y en dist/output-tailwind.css `.text-red` está en la
 * línea 2725 y `.text-secondary` en la 2730. Gana `.text-secondary` SIEMPRE.
 * Comprobado en el navegador con un nodo que llevaba las dos clases: sale
 * `rgb(105, 108, 112)`. La clase se añadía al DOM y el color no cambiaba nunca.
 *
 * SE ARREGLA EN VEZ DE RETIRARSE porque el aviso importa: el cuerpo de la
 * valoración tiene un `maxlength` de 1000 y quien escribe largo necesita saber
 * que se acerca al tope ANTES de que el campo deje de aceptar teclas.
 *
 * CLASE PROPIA DEL KIT Y NO UNA UTILIDAD DEL SKIN, que es la lección de arriba:
 * este fichero se carga el último, así que con la misma especificidad (0,1,0)
 * gana por cascada. Es la salida estable; pelearse por el orden dentro de
 * `dist/` no lo es, y `dist/` no se toca.
 *
 * AQUÍ EL COLOR NO ES LA ÚNICA SEÑAL, y por eso basta con el color: el texto
 * dice literalmente cuántos caracteres quedan, así que el número ya lo cuenta
 * todo y el rojo sólo lo subraya. No hace falta icono.
 * ------------------------------------------------------------------------- */
.flash-mensajes .text-red {
    background-image: linear-gradient(to right, var(--kit-error) 6px, transparent 6px);
}

.kit-contador-limite {
    color: var(--kit-error);
}

/* ---------------------------------------------------------------------------
 * 27) FICHA-OPCIONES — EL EJE ES UN `<fieldset>`, Y SUS OPCIONES SE PUEDEN
 *     PULSAR CON EL PULGAR.
 *
 * 1) `.kit-eje` — QUE EL GRUPO PUEDA ENCOGER.
 *
 * El bloque de cada eje ha pasado de `<div>` a `<fieldset>` para que su rótulo
 * visible sea tambien el nombre del grupo (el porqué está en
 * components/opciones-variante.php). El reset de Tailwind le quita al `fieldset`
 * el margen y el relleno (dist/output-tailwind.css:341-343) y el borde se lo
 * quita la regla `*` de `border-width: 0`, así que el aspecto no cambia. Lo que
 * NO le quita nadie es el `min-inline-size: min-content` que los navegadores le
 * dan de serie: un `fieldset` se niega a encoger por debajo del ancho mínimo de
 * su contenido, aunque su contenedor sea más estrecho.
 *
 * Con la semilla no se nota —el término más ancho es «40 W»—, pero el catálogo
 * de términos lo escribe el CLIENTE, y basta un «Blanco roto perla» para que la
 * columna de la ficha deje de poder encoger y la página desborde a lo ancho. Se
 * pone a 0, que es lo que hace cualquier elemento normal. La utilidad `min-w-0`
 * de Tailwind no sirve: el dist de Anvogue está purgado sobre su propio HTML y
 * no la trae compilada — el mismo caso que §20 y §21 con las suyas.
 *
 * 2) 44 px EN LAS MUESTRAS Y EN LAS PÍLDORAS, MEDIDOS.
 *
 * Misma cuenta que §23 y por el mismo motivo. El skin sirve `rem = 14px`, así que
 * `w-12 h-12` NO da 48: da **42x42**, medido a 375 sobre la ficha servida antes
 * de escribir esto (las dos muestras del altavoz 42x42, las dos píldoras 42 de
 * alto). Son 7/8 de lo que la clase promete y quedan por debajo de los 44 px que
 * este kit ya se exige en los pasos de cantidad, en la lupa del buscador (§21) y
 * en el botón sin JavaScript del envío.
 *
 * Va con `min-*` y NO tocando `w-12`/`h-12`, para que a `rem = 16px` el control
 * siga midiendo los 48 del template: esto es un SUELO, no un tamaño nuevo.
 *
 * ALCANCE POR `[data-eje]`, que es el marcador que el componente ya emite en la
 * lista de cada eje, y no por `.list-color .color-item`. Comprobado antes de
 * elegirlo: hoy NO hay ni una muestra fuera de este componente —K3 podó las de
 * las tarjetas del catálogo con el resto de los datos de demo, y el catálogo
 * servido no trae un solo `.color-item`—, así que el selector ancho no rompería
 * nada AHORA. Se acota igual, porque el molde del skin para esas muestras sigue
 * vivo en `dist/output-scss.css:2933` y es de `w-8 h-8`: el día que la tarjeta
 * recupere las suyas (está en la cola: unificar ficha y tarjeta), un suelo de 44
 * las inflaría y rompería la rejilla sin que nadie tocara este fichero. Es la
 * misma acotación que §21 y §23 dejaron escrita.
 * ------------------------------------------------------------------------- */
.kit-eje {
    min-inline-size: 0;
}

[data-eje] .color-item,
[data-eje] .size-item {
    min-width: 44px;
    min-height: 44px;
}

/* ---------------------------------------------------------------------------
 * 28) REDES-PINTADO: LOS ICONOS DE RED DEL PIE SE PUEDEN PULSAR CON EL PULGAR.
 *
 * En MOVIL el pie es el UNICO sitio donde estan las redes: el bloque de la
 * franja oscura lleva `max-md:hidden` (herencia del template) y por debajo de
 * 768 px sale `display: none`, medido a 375. O sea que el enlace de WhatsApp
 * que hay aqui es el unico camino que tiene un comprador con telefono, y ese
 * es justo el aparato donde se pulsa con el dedo.
 *
 * Y MEDIA 21 x 26 px. El enlace no tiene mas caja que la de su icono: el
 * template lo pinta como un `<a>` con un dibujo dentro y `gap-6` de separacion,
 * sin relleno. A `rem = 14px` (assets/css/fuentes.css) el `text-2xl` del
 * template da 24 px de tipo, y el glifo ocupa 21 de ancho. Es exactamente el
 * defecto que F11-R5 dejo escrito en docs/REQUERIMIENTOS_SISTEMA.md, cuando un
 * boton que debia medir 44x44 se sirvio de 11x26.
 *
 * 44 px es el suelo que este kit ya exige en tres sitios: el paginador del
 * catalogo, `.elegir-opciones-btn` (§22) y `.kit-lupa-buscar` (§21). Aqui se
 * aplica igual, con `min-*` —un SUELO, no un tamano nuevo— y con `flex` para
 * que el icono siga centrado en la caja que ahora es mas grande que el.
 *
 * SOLO POR DEBAJO DE 768 px, y esa es la parte que no se puede saltar: en
 * escritorio el puntero es preciso y el template pinta estos iconos a 24 px con
 * `gap-6`. Un suelo de 44 en escritorio los separaria mas de lo que el template
 * manda, y la regla de oro del proyecto es que lo visible sale del template. El
 * corte es `767.98px`, el mismo que ya usan §24 y §26.
 *
 * NO CUESTA UN BYTE DE HTML: el selector va por `.list-social a`, que es la
 * clase que el propio template ya pone en la fila. Sin clase nueva, sin
 * atributo nuevo, y por tanto sin coste en las trece rutas.
 * ------------------------------------------------------------------------- */
@media (max-width: 767.98px) {
    #footer .list-social a {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 44px;
        min-height: 44px;
    }
}

/* ---------------------------------------------------------------------------
 * 29) FICHA-NAVEGACION: EL «ANTERIOR/SIGUIENTE» DE LA FICHA SE PUEDE PULSAR
 *     CON EL PULGAR.
 *
 * MISMO DEFECTO QUE LA §28, MEDIDO IGUAL Y EN EL MISMO APARATO. A 375 px el
 * bloque de la miga de pan NO se esconde —se comprobo antes de escribir esto:
 * `display: flex` y caja real, el template no le pone `max-md:hidden` como si
 * le pone a la franja de redes—, asi que los dos enlaces son objetivos tactiles
 * de verdad. Y MIDEN 141 x 21 y 138 x 21 px.
 *
 * EL ANCHO SOBRA Y EL ALTO NO. Estos dos enlaces llevan rotulo ademas de icono,
 * asi que por ancho van holgados; el que se queda corto es el alto, y por el
 * mismo motivo exacto que en el pie: a `rem = 14px` (assets/css/fuentes.css) el
 * `text-2xl` del template da 24 px de tipo y la caja del enlace no tiene mas
 * relleno que el de su contenido. 21 px es menos de la mitad del suelo.
 *
 * POR ESO SOLO SE TOCA `min-height`, y no `min-width` como en la §28: un suelo
 * de ancho aqui no arreglaria nada —ya se cumple— y en cambio es la clase de
 * regla que un dia infla algo que no debia. Se pone el suelo que falta y nada
 * mas.
 *
 * SOLO POR DEBAJO DE 768 px, misma acotacion y mismo corte (`767.98px`) que
 * §24, §26 y §28. En escritorio el puntero es preciso y el template pinta esta
 * fila a la altura de su texto; subirla a 44 engordaria la banda de la miga de
 * pan por encima de lo que el template manda, y lo visible sale del template.
 *
 * NO CUESTA UN BYTE DE HTML: `.prev-btn` y `.next-btn` son las clases que el
 * propio template pone en esos dos elementos (`product-default.html`), no unas
 * inventadas para esta regla.
 *
 * SE ACOTA CON `.breadcrumb-product` DELANTE aunque hoy no haga falta, y eso
 * esta comprobado, no supuesto: `prev-btn` y `next-btn` no tienen NI UNA regla
 * en `dist/output-scss.css` (cero coincidencias) y en el HTML del template no
 * aparecen en ningun otro sitio que esta fila. Son nombres genericos —el skin
 * tiene carruseles por todas partes— y el dia que uno los reutilice, un suelo
 * de 44 px suelto le descuadraria las flechas. Misma acotacion preventiva que
 * §27 dejo escrita para las muestras de color.
 * ------------------------------------------------------------------------- */
@media (max-width: 767.98px) {
    .breadcrumb-product .prev-btn,
    .breadcrumb-product .next-btn {
        min-height: 44px;
    }
}

/* ---------------------------------------------------------------------------
 * 30) CATEGORIAS-NAVEGACION: LA HIJA SE VE COLGANDO DE SU MADRE, Y LA LINEA
 *     SALE DEL ANIDAMIENTO, NO DE UN DIBUJO.
 *
 * El marcado ya dice la verdad: desde esta ronda la sublista de subcategorias
 * va DENTRO del `<li>` de su madre, en las tres listas —menu de escritorio,
 * menu movil y filtro lateral del catalogo—. Esta regla solo pinta lo que ese
 * anidamiento ya significa.
 *
 * EL SELECTOR SE AGARRA A LA ESTRUCTURA Y NO A UNA CLASE NUEVA, y eso no es
 * elegancia: es que sean LA MISMA COSA. Si el sangrado colgara de una clase
 * puesta a mano, alguien podria ponerla sin anidar —y entonces la pantalla
 * diria «cuelga de» donde el arbol de accesibilidad dice «hermanas», que es
 * exactamente el defecto que esta ronda venia a evitar—. Con `li > ul` no se
 * puede: o esta anidada de verdad, o no hay sangrado ni linea.
 *
 * LA LINEA ES UN `border-left`, no una imagen ni un glifo. Un `::before` con un
 * caracter de dibujo lo leeria un lector de pantalla; un borde, no. Y el color
 * es `var(--line)`, la variable que el propio skin usa para todas sus
 * separaciones, no un gris inventado.
 *
 * POR QUE AQUI Y NO CON UTILIDADES DE TAILWIND. Porque no las hay: el build
 * esta congelado y `border-l` NO esta compilado en dist/output-tailwind.css
 * (cero coincidencias, comprobado). `border-line` si esta, pero sin `border-l`
 * no pinta ningun lado. Escribirlo aqui es la salida que el propio kit tiene
 * declarada para esto (CLAUDE.md: los arreglos sobre el skin van en
 * kit-overrides.css, nunca editando dist/).
 *
 * EL SANGRADO VA EN `padding` Y LA LINEA EN EL BORDE DEL MISMO CONTENEDOR, para
 * que la separacion entre la linea y el texto de la hija sea la misma en las
 * tres listas sin tener que cuadrarla a mano en cada una.
 *
 * NO SE TOCA EL ESTADO ACTIVO: `.menu-tab .tab-item.active` y
 * `.active > .has-line-before::before` son del skin y siguen mandando en la
 * hija igual que en la madre, porque la hija lleva las mismas clases.
 *
 * `aria-current="location"` ES LA RAMA ACTUAL, Y ES MAS SUAVE POR RESTA.
 * Dentro de una subcategoria hay dos cosas ciertas —«estas en Hogar» y «Hogar
 * esta dentro de Textil»— y la lista las dice las dos sin gritarlas igual. El
 * estado exacto del skin son DOS senyales: el color `--black` y el subrayado
 * que `.active > .has-line-before::before` estira al 100 %. La rama se queda
 * con UNA: el color, sin el subrayado. No hay tercer tono inventado ni variable
 * nueva —seria `--secondary2` (#A0A0A0), que es MAS CLARO que el `--secondary`
 * (#696C70) de una entrada normal y dejaria a la madre menos visible que sus
 * vecinas, o sea lo contrario de lo que se quiere decir—.
 *
 * Y EL ATRIBUTO NO ES UNA CLASE INVENTADA PARA PINTAR: `aria-current="location"`
 * es el valor que el estandar reserva para «esta entrada contiene la pagina
 * actual», asi que lo anuncia un lector de pantalla aunque no vea el color. La
 * senyal visible y la audible son el mismo atributo, no dos cosas que alguien
 * tenga que acordarse de poner juntas.
 * ------------------------------------------------------------------------- */
.menu-main .sub-menu li > ul,
#menu-mobile .list-nav li > ul,
.filter-type.menu-tab li > ul {
    padding-left: 12px;
    border-left: 1px solid var(--line);
    margin-left: 4px;
}

.menu-main .sub-menu [aria-current="location"],
#menu-mobile .list-nav [aria-current="location"],
.filter-type.menu-tab [aria-current="location"] .type-name {
    color: var(--black);
}

/* ---------------------------------------------------------------------------
 * 31) CATEGORIAS-NAVEGACION: LAS DOS LISTAS DE CATEGORIAS SE PUEDEN PULSAR CON
 *     EL PULGAR.
 *
 * MISMO DEFECTO QUE §28 Y §29, MEDIDO IGUAL Y EN EL MISMO APARATO. A 375 px
 * reales, TODAS las entradas de categoria miden 328 x 21 px en el menu movil y
 * 328 x 21 en el filtro lateral (la hija sangrada, 311 x 21). El ancho sobra;
 * el alto es menos de la mitad del suelo de 44.
 *
 * Y NO LO HA TRAIDO ESTA RONDA, que es la parte que hay que decir: los 21 px
 * son los que ya median antes de que existiera ninguna hija —la madre y la
 * categoria sin hijas miden exactamente lo mismo que la hija—. El sangrado no
 * ha encogido nada; lo que ha hecho esta ronda es MIRAR, porque le tocaba
 * comprobar que la hija sigue siendo pulsable. Se arregla la lista entera y no
 * solo las hijas: dejar la hija a 44 y su madre a 21 seria peor que no tocarlo.
 *
 * SOLO `min-height`, como en §29 y por el mismo motivo: por ancho van holgadas
 * (328 px de los 375) y un suelo de ancho no arreglaria nada. Y `min-*` es un
 * SUELO, no un tamano nuevo: una entrada de dos lineas sigue creciendo.
 *
 * SOLO POR DEBAJO DE 768 px, misma acotacion y mismo corte (`767.98px`) que
 * §24, §26, §28 y §29. El submenu de escritorio ni siquiera existe ahi (el
 * `.menu-main` lleva `max-lg:hidden`) y por encima el puntero es preciso: subir
 * a 44 las filas del filtro lateral en escritorio engordaria la columna por
 * encima de lo que el template manda, y lo visible sale del template.
 *
 * LOS DOS GANCHOS SON CLASES QUE YA ESTABAN, y ninguna se ha inventado para
 * esto — no cuesta un byte de HTML:
 *   · `#menu-mobile .list-nav a.pl-4` — el `pl-4` es el sangrado que K3 puso a
 *     las categorias para colgarlas de «Catalogo», y COMPROBADO en pantalla:
 *     lo llevan 4 de los 12 enlaces de ese menu, que son exactamente las
 *     categorias. Inicio, Contacto o Mi carrito no lo llevan y no se tocan.
 *   · `.filter-type-block ul.list-type a.item` — `ul` porque desde esta ronda
 *     la lista de categorias ES una lista; el bloque de etiquetas que hay justo
 *     debajo sigue siendo `div > a` y por eso NO entra aqui.
 *
 * ⚠ ANOTADO Y NO TOCADO: ese bloque de etiquetas (F14) tiene el MISMO alto de
 * 21 px y el mismo problema. Queda fuera porque esta ronda es la de las tres
 * listas de CATEGORIAS y arreglar de paso lo que no se ha medido es como se
 * cuelan los cambios que nadie pidio. Ronda propia.
 * ------------------------------------------------------------------------- */
@media (max-width: 767.98px) {
    #menu-mobile .list-nav a.pl-4,
    .filter-type-block ul.list-type a.item {
        min-height: 44px;
    }
}

/* ---------------------------------------------------------------------------
 * 32) CATALOGO-HUECO: LAS FILAS DE LA REJILLA DEJAN DE ESTIRARSE PARA IGUALAR
 *     LA ALTURA DE LA COLUMNA DE FILTROS.
 *
 * SINTOMA MEDIDO, NO DESCRITO. En /catalogo/demo-textil a 1280 px, entre la
 * primera fila de tres tarjetas y la segunda habia 610,5 px de aire. Las dos
 * filas de la rejilla median 1 057,5 px CADA UNA cuando el contenido de una
 * tarjeta mide 477. El sobrante —1 161 px— se repartia exacto entre las dos:
 * 580,5 y 580,5, mas los 30 del `gap` = los 610,5 que se ven.
 *
 * DE DONDE SALE: DE UNA REGLA DEL PROPIO TEMPLATE, en dist/output-scss.css
 * (linea 3571, byte a byte la misma que trae el Anvogue original):
 *
 *     @media (min-width: 1280px) {
 *       .shop-product.breadcrumb1:has(.sidebar) .list-product {
 *         min-height: calc(100% - 180px);
 *       }
 *     }
 *
 * Ese `100 %` se resuelve contra `.list-product-block`, que es hermano flexible
 * de `.sidebar` y por tanto ESTIRADO a la altura de la mas alta de las dos
 * columnas. Medido en la misma pantalla: sidebar 2 325 px → bloque 2 325 →
 * suelo de la rejilla 2 325 − 180 = 2 145, cuando su altura natural son 1 040.
 * Y la rejilla no declara `align-content`, asi que el reparto por defecto
 * (`normal`, que en rejilla es `stretch`) mete todo ese sobrante DENTRO de las
 * filas en vez de dejarlo debajo.
 *
 * EL PUNTO DE CORTE ES EL 1280 DE ESA `@media`, Y NO EL NUMERO DE COLUMNAS.
 * Comprobado a los dos lados: a 1279 px `min-height` computa `0px`, las filas
 * miden 504,66 y el hueco es de 28 px (el relleno propio de la tarjeta). A
 * 1280 computa `calc(100% - 180px)` y las filas saltan a 1 057,5. En tableta no
 * se ve porque la regla NO EXISTE ahi, no porque la rejilla cambie de forma: a
 * 1024 px siguen siendo TRES columnas y DOS filas —igual que a 1280— y el hueco
 * no aparece. Por arriba no muere en ningun ancho: a 1536 y a 2560 el hueco
 * crece a 590 px, porque el contenedor ya esta topado y solo crece la columna.
 *
 * EL TEMPLATE YA LO HACE, y por eso esto es un OVERRIDE y no un arreglo de algo
 * nuestro. Su propia maqueta shop-breadcrumb1.html —rejilla de tres columnas
 * con la columna de filtros al lado— se salva por 28 px: trae NUEVE tarjetas,
 * tres filas y 1 491 px naturales contra un suelo de 1 463. Quitandole tres
 * tarjetas en el navegador, sin tocar un byte de su HTML ni de su CSS, sus dos
 * filas pasan de 495 a 539,5 px y aparece el mismo hueco. La regla estaba
 * dormida, no sana.
 *
 * QUE HEMOS PUESTO NOSOTROS: nada de la regla, y todo del tamano. Lo que hace
 * enorme el hueco es que NUESTRA columna izquierda es larguisima —lleva el
 * widget «Productos nuevos», 1 448 px de los 2 325—, y el suelo de la rejilla
 * es la altura de esa columna. En la maqueta del template la columna mide
 * 1 289 px y el hueco sale de 74,5. El commit 00ffa4c no lo creo: al hacer que
 * la categoria madre incluya los productos de sus hijas, /catalogo/demo-textil
 * paso de 2 productos a 6 y por primera vez tuvo DOS filas en esa ruta, que es
 * la condicion que le faltaba a la regla para morder.
 *
 * ADEMAS LOS 180 px NO SON LOS NUESTROS. En nuestro marcado, de lo alto del
 * bloque a lo alto de la rejilla hay 118 px (`filter-heading` 40 +
 * `list-filtered` 34 + margenes), no 180. La constante del template descuenta
 * 62 px de mas, asi que el suelo se pasa incluso en sus propios terminos.
 *
 * POR QUE `min-height: 0` Y NO `align-content: start`. Las dos apilan las filas
 * arriba, pero solo una deja el sobrante FUERA de la caja. Medido en la misma
 * pantalla: con `align-content: start` las filas vuelven a 505 px pero la
 * rejilla sigue midiendo hasta el pixel 2 645 — una caja fantasma de 1 105 px
 * por debajo de la ultima tarjeta, que empujaria hacia abajo todo lo que venga
 * detras (el paginador, cuando la categoria tenga mas de doce productos). Con
 * `min-height: 0` la caja termina justo en la ultima tarjeta, en el 1 540, y el
 * sobrante se queda donde tiene que quedarse: al fondo de la columna derecha,
 * exactamente igual que a 1279 px, donde el escaparate ya se veia bien.
 *
 * SE MANTIENE LA `@media` DE 1280 aunque por debajo la declaracion seria
 * inocua (ahi el suelo ya es 0). Acotarla al ancho que la necesita es lo mismo
 * que §24, §26, §28, §29 y §31 hacen con su corte de 767,98: la regla dice
 * DONDE esta el defecto, no solo como taparlo.
 *
 * SE ACOTA CON `.list-product-block` EN MEDIO, y no se copia el selector del
 * template tal cual, porque ese selector coge DOS elementos de la pagina: la
 * rejilla del catalogo y el `.list-product` del widget de novedades del
 * sidebar. Solo uno es el defecto. Y el otro es INMUNE por estructura, medido y
 * no supuesto: su contenedor `.filter-novedades` no tiene altura impuesta por
 * nadie, asi que el `100 %` es su propio contenido, y el suelo solo morderia si
 * el titular que lleva encima pasara de 180 px — mide 44. Dejarlo fuera cuesta
 * una clase mas en el selector y evita tocar lo que no se ha roto.
 *
 * Y LA ACOTACION ADEMAS GANA POR ESPECIFICIDAD, no solo por orden de carga:
 * (0,5,0) contra los (0,4,0) del template —`:has(.sidebar)` puntua como su
 * argumento, una clase—. Esta regla seguiria mandando aunque un dia alguien
 * moviera este fichero de sitio en el <head>.
 *
 * NO CUESTA UN BYTE DE HTML: `list-product-block` y `list-product` son las dos
 * clases que el propio template pone en esos contenedores, y `shop-product
 * breadcrumb1` es la seccion que K3 copio de shop-sidebar-list.html. Ni una
 * clase nueva, ni un atributo nuevo: las 17 rutas no se mueven.
 * ------------------------------------------------------------------------- */
@media (min-width: 1280px) {
    .shop-product.breadcrumb1:has(.sidebar) .list-product-block .list-product {
        min-height: 0;
    }
}

/* ---------------------------------------------------------------------------
 * 33) COMPARADOR-CABECERA — EL DISTINTIVO DEL COMPARADOR NO PINTA UN CERO, Y
 *     SU CELDA DE MOVIL SE PUEDE PULSAR CON EL PULGAR.
 *
 * 1) `.comparador-quantity:empty` — SIN NADA QUE COMPARAR, NO SE PINTA NADA.
 *
 * El icono nuevo de la cabecera copia al del corazon, distintivo incluido. Pero
 * el del carrito pinta un CIRCULO NEGRO CON UN «0» cuando el carrito esta vacio,
 * y eso es lo que esta ronda decidio no repetir: un distintivo sirve para avisar
 * de que hay algo, y uno que dice «cero» es ruido en todas las paginas de todas
 * las visitas que no comparan nada — o sea, casi todas.
 *
 * EL `<span>` VIAJA IGUAL, Y VACIO. No se deja de emitir, y eso es deliberado:
 * es lo unico que permite que al anyadir el primero con JavaScript aparezca el
 * numero SIN que el guion construya marcado, que es la regla de este kit —el
 * guion solo escribe `textContent`, igual que `carrito.js` con `.cart-quantity`.
 * Mismo criterio que el `checked-icon` de la tarjeta: servido y oculto.
 *
 * Y `display: none` NO ES SOLO ESTETICA: saca el nodo del arbol de
 * accesibilidad, asi que con la lista vacia el enlace se anuncia «Comparador» y
 * no «(vacio) Comparador». Con dos productos dice «2 Comparador», que es
 * exactamente la forma que ya tienen sus dos hermanos —«3 Ver el carrito» y
 * «0 Mi lista de deseos», leidas del arbol y no supuestas—.
 *
 * SIN ACOTAR POR ANCHURA, al contrario que las §28, §29 y §31: no es un suelo
 * tactil, es «no ensenyes un hueco vacio», y eso vale igual en movil que en
 * escritorio. El selector es la clase propia del kit y no `.quantity`, que la
 * llevan tambien el carrito y la lista de deseos: los suyos NUNCA estan vacios
 * hoy, pero una regla sobre la clase compartida decidiria por ellos sin que
 * nadie lo haya pedido.
 *
 * CERO BYTES DE HTML: `comparador-quantity` es la clase que el marcado necesita
 * de todas formas para que el guion encuentre los dos nodos —el de escritorio y
 * el de la barra de movil—, igual que `cart-quantity` en el carrito.
 *
 * 2) `.menu_bar-link` — LA BARRA INFERIOR, A 44 px DE ALTO.
 *
 * MEDIDO A 375 px, no supuesto: con la celda nueva la barra pasa de cuatro
 * columnas de 90 px a cinco de 72, y el rotulo mas largo —«Comparar»— mide
 * 57,39 px, asi que por ANCHO sobra. Lo que no sobraba es el ALTO del area
 * pulsable: el enlace se ajusta a su contenido —icono de 24 mas rotulo— y se
 * queda por debajo del suelo de 44 px que este kit ya exige en §21, §22, §28,
 * §29 y §31 y en el paginador del catalogo.
 *
 * SOLO `min-height`, como en §29 y §31 y por el mismo motivo: por ancho van
 * holgadas y un suelo de ancho no arreglaria nada. Y `min-*` es un SUELO, no un
 * tamanyo nuevo: la barra sigue midiendo sus 70 px de alto y lo que crece es la
 * caja pulsable del enlace dentro de ella.
 *
 * SOLO POR DEBAJO DE 768 px, misma acotacion y mismo corte (`767.98px`) que
 * §24, §26, §28, §29 y §31. Por encima esta barra ni siquiera existe: lleva
 * `sm:hidden`, o sea que desaparece a partir de 640. La acotacion no cambia nada
 * en la practica y se pone igual, por la misma razon de siempre: una regla que
 * dice donde vale es una regla que no sorprende el dia que alguien mueva el
 * `sm:hidden`.
 *
 * CERO BYTES DE HTML: `menu_bar-link` es la clase que el propio template pone en
 * las celdas. Ni una clase nueva, ni un atributo nuevo.
 * ------------------------------------------------------------------------- */
.comparador-quantity:empty {
    display: none;
}

@media (max-width: 767.98px) {
    .menu_bar-inner .menu_bar-link {
        min-height: 44px;
    }
}

/* ---------------------------------------------------------------------------
 * 34) ACUSE-CLIC — UN CONTROL QUE ESTA TRABAJANDO SE VE QUE ESTA TRABAJANDO.
 *
 * POR QUE EXISTE. Medido en RENDIMIENTO-CENSO (docs/TIENDA_rendimiento.md §5.2)
 * y reproducido en esta ronda: entre que el comprador pulsa y que el servidor
 * contesta pasan 1,1-1,4 s en los que NO CAMBIA NADA en pantalla. Ni el boton,
 * ni el cursor, ni un anuncio. Y el silencio produce el segundo clic, que por el
 * cerrojo de sesion de PHP cuesta el doble (§4.1 del mismo documento: tres
 * operaciones a la vez acaban en 2 995 ms en vez de 1 096).
 *
 * DE DONDE CUELGA: de `aria-busy="true"`, que es el atributo que
 * `assets/js/avisos.js` pone y quita. No hay ni una clase nueva ni un byte nuevo
 * de HTML: el estado es semantico y el aspecto lo lee de ahi.
 *
 * ============================================================
 * NO HAY NI UNA ANIMACION EN ESTA SECCION, Y ES LA DECISION.
 * ============================================================
 * La forma habitual de decir «esperando» es una rueda que gira, y una rueda que
 * gira obliga a declarar `prefers-reduced-motion` y a mantener el respaldo para
 * quien lo tiene puesto. Aqui el efecto se consigue con dos propiedades quietas
 * —el cursor y una atenuacion— asi que NO HAY MOVIMIENTO QUE SUPRIMIR: la regla
 * de movimiento reducido no aplica porque no hay nada que reducir. Es menos que
 * declarar y menos que mantener, que es exactamente lo que pedia la ronda.
 *
 * `filter: opacity()` Y NO LA PROPIEDAD `opacity`, y esto SI es importante.
 * El boton de compra rapida de la tarjeta vive con `opacity: 0` y solo aparece
 * al pasar el raton por encima (es del skin). Una regla `opacity: .55` de aqui
 * GANARIA a esa —kit-overrides.css se carga el ultimo por contrato— y el boton
 * se haria visible sobre la tarjeta justo mientras trabaja, que es un defecto
 * nuevo. `filter` es OTRA propiedad y se aplica sobre el resultado ya pintado,
 * asi que MULTIPLICA en vez de sustituir: sobre un boton oculto sigue oculto
 * (0 x 0,55 = 0) y sobre uno visible lo atenua. Comprobado en el navegador con
 * los dos casos, no deducido.
 *
 * `cursor: progress` Y NO `wait`: `progress` es «sigo trabajando pero la
 * interfaz responde», que es literalmente lo que pasa —el resto de la pagina se
 * usa con normalidad—; `wait` dice «no se puede hacer nada», y no es verdad.
 * El cursor SE HEREDA, asi que el icono de dentro del boton tambien lo lleva y
 * no hay que enumerar hijos.
 *
 * NADA DE `pointer-events: none`, aunque parezca el remate natural: apagaria el
 * clic ANTES de llegar al manejador, y el manejador es justamente donde vive la
 * bandera que descarta la segunda pulsacion. Ademas se llevaria por delante el
 * `cursor: progress`, que no se pinta sobre algo que no recibe puntero. Lo que
 * impide la segunda peticion es JavaScript, no CSS.
 *
 * VALE IGUAL PARA UN BOTON Y PARA UNA REGION. Sobre el boton dice «tu clic ha
 * llegado»; sobre un trozo de pagina que se esta recalculando —el importe del
 * envio en el checkout— dice «esta cifra todavia no es la buena». Es el mismo
 * atributo y el mismo aspecto porque es el mismo hecho.
 * ------------------------------------------------------------------------- */
[aria-busy="true"] {
    cursor: progress;
    filter: opacity(0.55);
    /* LA SENYAL ENTRA EN EL ACTO, y esto no es una precaucion teorica: MEDIDO.
       `.button-main` trae `transition: all ease 0.4s` del skin, asi que el
       navegador abria una transicion sobre `filter` y la atenuacion tardaba
       400 ms en aparecer — un tercio del tiempo que dura la operacion entera
       (1 100-1 400 ms segun el censo). Sin esta linea, el boton del cupon
       marcaba `opacity(1)` en el instante del clic y `opacity(0.55)` a los
       400 ms; con ella marca `opacity(0.55)` en el mismo milisegundo. El boton
       del comparador no lo sufria porque el suyo no lleva esa transicion, que
       es exactamente la clase de diferencia que solo aparece midiendo los dos.

       Es ademas la misma decision, con las mismas palabras, que §15 tomo con el
       color de la confirmacion: un ESTADO no puede depender de que una
       transicion avance. Y de paso deja esta seccion sin nada que animar, que
       es lo que permite no tener que declarar movimiento reducido. */
    transition: none;
}

/* ---------------------------------------------------------------------------
 * 35) CUPON-FICHA — EL VALE DE LA FICHA LLEVA EL COLOR DE LA MARCA, Y EL COLOR
 *     NO TOCA NI UNA LETRA.
 *
 * QUE NO SE USE EL ROJO DEL TEMPLATE ES UNA DECISION, Y TIENE DOS MOTIVOS
 * MEDIDOS. El vale de `product-discount.html` va en `--red` (#DB4444) y lo lleva
 * escrito A MANO dentro del `fill` de un SVG, asi que:
 *
 *   1. NO SEGUIRIA A LA MARCA. `--red` es estructural del skin y el contrato de
 *      branding del kit (CLAUDE.md) no lo mapea a nada: con el cliente de hoy
 *      —`COLOR_PRIMARIO = #CC7700`, naranja— el escaparate entero seria naranja
 *      y este bloque rojo. Y aunque alguien remapeara `--red`, un hex dentro de
 *      un `fill` no lee variables: no cambiaria.
 *   2. Y ESE ROJO YA ARRASTRA UNA DEUDA DE CONTRASTE. `CUPON-FLUJO` la midio y
 *      la dejo declarada: `#DB4444` da 4,27:1 sobre blanco, por debajo del 4,5:1
 *      que WCAG AA pide para texto normal.
 *
 * ASI QUE EL COLOR SALE DE `--purple`, QUE ES DONDE EL KIT MAPEA `COLOR_PRIMARIO`
 * (lo inyecta components/header.php), Y VA SOLO EN EL TRAZO.
 *
 * ES LA MISMA REGLA QUE §25 Y F18-BIS DEJARON ESCRITA —«el color de marca no va
 * nunca en el texto»— y aqui se cumple entera: el texto del vale lo pintan
 * `caption1`, `text-title` y `text-secondary`, que son los tokens de contraste
 * del skin, y `--purple` solo pinta el BORDE y la linea de puntos. Un borde es
 * un elemento grafico y su umbral es 3:1 (WCAG 1.4.11), no 4,5:1.
 *
 * MEDIDO CON EL VALOR DE HOY, `#CC7700` sobre el blanco de la ficha: **3,38:1**.
 * Cumple el 3:1 de elemento grafico y NO cumpliria el 4,5:1 de texto — que es
 * exactamente por lo que no hay ni una letra de este color.
 *
 * LO QUE ESTO HEREDA Y HAY QUE SABER: el umbral depende de `COLOR_PRIMARIO`, o
 * sea del cliente. Un primario muy claro bajaria de 3:1 y el vale perderia su
 * borde visible. Es la misma dependencia que ya tienen `.bg-purple` y
 * `.text-purple` desde K3 Bloque 7, no una nueva; queda dicha aqui porque este
 * bloque es el primero que apoya un LIMITE de forma en ese color.
 *
 * -------------------------------------------------------------------------
 * 2) `.kit-vale` NO DESBORDA A 375 px.
 *
 * El vale no tiene anchura propia: la fija su contenido, y su contenido incluye
 * una condicion redactada que puede ser larga («en pedidos desde 30,00 €, si tu
 * pedido paga portes»). A 375 px con `rem = 14px` eso se sale de la pantalla y
 * arrastra la pagina entera al desplazamiento horizontal, que es el defecto que
 * §24, §26 y §32 ya persiguieron en otras piezas.
 *
 * `max-width: 100%` lo ata al contenedor, y el `min-width: 0` es el que hace que
 * de verdad funcione: sin el, un hijo flexible no baja de su tamano de contenido
 * y el `max-width` del padre no llega a aplicarse. Es la misma pareja que §27
 * necesito para que un `<fieldset>` pudiera encoger.
 *
 * SIN TOCAR EL `gap` NI EL `flex-wrap`, que son del marcado del template: lo que
 * se acota es el limite, no la maqueta.
 * ------------------------------------------------------------------------- */
.kit-vale {
    border-color: var(--purple);
    max-width: 100%;
    min-width: 0;
}

.kit-vale .top {
    border-bottom-color: var(--purple);
}

/* El texto de la condicion parte por donde pueda: es una frase, no un codigo, y
   a 375 px la alternativa a partirla es sacarla de la pantalla. */
.kit-vale .right {
    min-width: 0;
}

/* ---------------------------------------------------------------------------
 * 36) BUSCADOR-LUPA — sin texto dentro, el boton del buscador del catalogo no
 * tiene de donde sacar su tamano, y hay que darselo.
 * ------------------------------------------------------------------------- */

/* `.button-main` solo tenia ancho por su texto: sin el se queda en los 32 px de
   sus dos paddings, que ni es cuadrado ni se puede tocar. */
.kit-lupa-catalogo {
    min-width: 44px;
    padding-left: 0;
    padding-right: 0;
}

/* El icono heredaba los 12 px del texto del boton, que para una lupa que ya no
   lleva ninguna palabra al lado se queda corto: sube a 18. */
.kit-lupa-catalogo i {
    font-size: 18px;
    line-height: 1;
}

/* La zona tactil llega a 44 px de ALTO sin tocar la maqueta: el boton vive con
   `top-1 bottom-1` dentro de un campo de 44, asi que agrandarlo lo desbordaria
   (§21 ya lo dejo escrito). El area activa la extiende este pseudo-elemento
   —transparente y sin pintar nada— 4 px por arriba y otros 4 por abajo. */
.kit-lupa-catalogo::after {
    content: "";
    position: absolute;
    inset: -4px 0;
}

/* El hueco que el campo le reserva. Lo llevaban `pr-24` y `md:pr-[110px]` en el
   marcado, y NINGUNA de las dos esta compilada en `dist/output-tailwind.css`:
   el `padding-right` servido era 0 y lo tecleado corria por debajo del boton.
   Son 52 y no 56 por el sidebar a 768 px, que es donde el campo se queda mas
   estrecho (192 px): con 56 el placeholder se cortaba por 1,9 px. */
.filter-search-block .form-search input {
    padding-right: 52px;
}

/* El anillo de foco, sobre un boton casi negro. El blanco da 16,48:1 medidos
   contra el rgb(31,31,31) del boton, muy por encima del 3:1 que WCAG 1.4.11
   pide a un indicador; va POR DENTRO (`outline-offset` negativo) porque el
   campo se pinta sobre el borde del boton y un anillo por fuera quedaria
   medio tapado. */
.kit-lupa-catalogo:focus-visible {
    outline: 3px solid #FFFFFF;
    outline-offset: -5px;
}
