/* ==========================================================================
   FICHA DE PRODUCTO — GRAN ALMAZARA
   assets/css/single-product.css
   ========================================================================== */

/* ─── Container helpers (específicos de este template) ── */

.ga-container {
    width: 100%;
    max-width: 1280px;
    margin-inline: auto;
    padding-inline: clamp(1rem, 4vw, 2.5rem);
}

.ga-container--narrow {
    max-width: 820px;
}


/* ─── Breadcrumb — RETIRADO ──────────────────────────
   Aquí vivían las reglas de .ga-product__breadcrumb: el fondo verde de la barra,
   el color de sus enlaces y los tres retoques del marcado de Rank Math.

   Se retiran porque la barra ya no se pinta en NINGUNA ficha
   (page-templates/single-product-custom.php) y estas reglas eran EXCLUSIVAS de
   ella: el prefijo .ga-product__ solo lo escribía esa plantilla, así que ni una
   sola de ellas puede llegar a casar hoy con nada.

   ⚠ NO CONFUNDIR CON .ga-breadcrumb, sin el __product: esa es la de page.php,
     está viva y no se ha tocado.

   Si algún día vuelven las migas a la ficha, esta sección se recupera del
   historial de git junto con el <nav> de la plantilla; las dos se quitaron en el
   mismo cambio. */


/* ─── Zona Superior ──────────────────────────────── */

.ga-product__top {
    padding-block: var(--ga-space-xl);
    background: var(--ga-blanco);
}

/* Sin la barra de migas, el padding de arriba dejaba una franja blanca vacía
   entre la cabecera y la foto. Se recorta al mismo valor que ya usa Eventos
   —.ga-product-single--eventos .ga-product__top, en main.css—, que es lo que
   hace que las dos fichas arranquen exactamente a la misma altura.

   Va acotado con :not(--eventos) y NO tocando la regla de arriba, para que no
   haya forma de que este cambio alcance a la ficha de Eventos: allí sigue
   mandando su propia regla, que no se ha tocado. El padding de ABAJO se queda
   como estaba, que lo pone el padding-block de la regla anterior. */
.ga-product-single:not(.ga-product-single--eventos) .ga-product__top {
    padding-top: var(--ga-space-sm);
}

/* (El margen de la disponibilidad se decide al final de este archivo, en el
   bloque de los huecos de la columna de compra: allí se ajusta a la vez que el
   gap del contenedor, que es con lo que se suma. Aquí había una primera versión
   con solo margen superior y se ha retirado para no tener dos reglas del mismo
   selector peleándose por orden de aparición, que es lo que hizo que un cambio
   de color de este mismo archivo no llegara a verse.) */

.ga-product__grid {
    display: grid;
    grid-template-columns: 55% 1fr;
    gap: var(--ga-space-xl);
    align-items: start;
}

/* ——— SIN GALERÍA: UNA SOLA COLUMNA ———
   Apadrina un Olivo no tiene foto que enseñar, así que su columna no se pinta. Sin
   esta regla, la rejilla seguiría reservando el 55 % de la izquierda y la columna de
   compra se quedaría arrinconada a la derecha con un hueco enorme al lado.

   🔴 minmax(0, 1fr) Y NO 1fr, por lo de siempre: el mínimo por defecto de una pista
   es el ancho de su contenido, y el desplegable de plan o un nombre largo podrían
   ensancharla por encima del contenedor. Con el 0 de mínimo, la columna encoge y el
   contenido parte donde toca. Es cómo se corta el ancho mínimo sin min-width.

   ⚠ EL ANCHO SE ACOTA CON UN max-width EN LA COLUMNA, no estrechando la rejilla: la
     ficha completa seguiría midiendo lo mismo y el bloque de compra quedaría estirado
     de lado a lado, con líneas larguísimas. Centrado y con un tope de lectura se lee
     como una ficha y no como un formulario a pantalla completa.

   ⚠ NO ALCANZA A NADIE MÁS: el modificador lo pinta la plantilla solo cuando
     $ga_es_apadrina, que lleva su propio ! $ga_es_eventos. */
.ga-product__grid--sin-galeria {
    grid-template-columns: minmax(0, 1fr);
}

.ga-product__grid--sin-galeria .ga-product__purchase {
    max-width: 34rem;
    margin-inline: auto;
}


/* ─── Galería ────────────────────────────────────── */

.ga-product__gallery {
    position: sticky;
    top: calc(var(--ga-nav-height) + 1.5rem);
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.ga-product__gallery-main {
    aspect-ratio: 1 / 1;
    overflow: hidden;
    border-radius: var(--ga-radius-md);
    background: var(--ga-naranja-claro);
    position: relative;
}

.ga-product__gallery-main img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: opacity 0.25s ease;
}

.ga-product__gallery-main img.is-fading { opacity: 0; }

/* ——— LA BOTELLA DE 500 ML, AL TAMAÑO DE LAS DEMÁS ———
   🔴 LA CAUSA NO ESTÁ EN EL CSS: ESTÁ EN LA FOTO. Ese archivo trae MÁS AIRE
   ALREDEDOR del producto que los de la 2 L y la 5 L —cada uno está fotografiado con
   su propio encuadre—, así que a igual tamaño de recuadro la botella se ve más
   chica aunque el recuadro mida exactamente lo mismo. No es resolución, ni
   object-fit, ni un ancho mal puesto.

   Ya está diagnosticado y resuelto igual en otros tres sitios del tema, y esta es la
   cuarta vez que aparece: la sección "Nuestros Aceites" de la home, la parrilla de
   la tienda y el carrusel de relacionados llevan su propia corrección para ESTE
   MISMO SKU. Lo definitivo es reexportar la foto recortada; mientras tanto, se
   compensa escalándola.

   SE ESCALA SOLO LA <img>, con el origen centrado por defecto. El recuadro no
   cambia de tamaño ni se mueve un píxel, y su overflow: hidden contiene lo que
   sobresale: como lo que sobresale es aire, recorta margen y no producto.

   🔴 POR QUÉ EL 1.18 ANTERIOR SE QUEDABA CORTO — LA CUENTA ESTABA MAL HECHA.
   Aquel número salía de restarle al 1.35 de la home lo que se suponía que el
   `object-fit: cover` ya recortaba por su cuenta. Pero AQUÍ EL COVER NO RECORTA
   NADA: el recuadro es cuadrado (aspect-ratio: 1/1) y la foto de producto también,
   y cuando las dos proporciones coinciden, `cover`, `contain` y `fill` dan
   exactamente el mismo resultado. No había nada que descontar, así que el punto de
   partida bueno era el 1.35 de la home, no algo por debajo.

   Se sube a 1.45 para que la botella llene el recuadro en vez de flotar en él. El
   1.40 es el valor más alto que está COMPROBADO en el tema —es el que usa la home
   al pasar el ratón sobre esta misma foto, sin que la botella se corte—, así que
   1.45 va un paso por encima de lo probado.

   ⚠ ES UN SOLO NÚMERO Y HAY QUE REMATARLO A OJO. No hay forma de abrir la imagen en
     un navegador desde aquí. Si el tapón o la base llegaran a tocar el borde, se
     baja a 1.40 —que es terreno conocido— o a 1.35. Si aún se ve pequeña, se sube.

   ⚠ EL TECHO NO ES ESTÉTICO, ES DE RESOLUCIÓN. A partir de cierta escala la foto se
     ve blanda porque se está pintando más grande de lo que mide el archivo. Con el
     tamaño 'woocommerce_single' por defecto de WooCommerce (600px) y un recuadro de
     unos 550px en escritorio, a 1.45 la imagen se pinta a unos 800px: ya por encima
     de lo que da el archivo, y el doble en una pantalla de densidad 2. Para llegar
     nítida a esta escala la foto de producto tendría que rondar los 1600px de lado.

   ⚠ Y LA SOLUCIÓN DE VERDAD NO ES ESTA REGLA: es reexportar la foto RECORTADA, con
     la botella ocupando el encuadre como en las de 2 L y 5 L. El día que se suba,
     se borra esto y las otras tres correcciones de main.css.

   ⚠ ALCANCE: solo la foto GRANDE. Las miniaturas y las flechas de la galería no
     entran en este selector, así que no se enteran. Y se aplica a TODAS las fotos de
     este producto, no solo a la primera, que es lo que hace que al cambiar de imagen
     no se vea un salto de tamaño. */
.ga-product-single--sku-ga-bell-500-oct .ga-product__gallery-main img {
    transform: scale(1.45);
}

/* ——— LOS TARROS DE ACEITUNAS, MÁS GRANDES DENTRO DEL MISMO RECUADRO ———
   MISMO PROBLEMA Y MISMO MECANISMO QUE LA BOTELLA DE 500 ML DE AQUÍ ARRIBA, así
   que no se repite el razonamiento: se escala SOLO la <img>, el recuadro no
   cambia de tamaño ni se mueve, y su overflow: hidden contiene lo que sobresale.
   Se ha hecho a propósito con la misma herramienta para no tener dos formas
   distintas de resolver lo mismo en el mismo archivo.

   🔴 LA CAUSA VUELVE A ESTAR EN LA FOTO, Y ESTA VEZ ESTÁ MEDIDA. Las ocho fichas
   de tarro traen las mismas cinco imágenes, todas de 1024×1024, y en las de
   estudio el tarro ocupa alrededor del 60 % del alto del archivo: el resto es
   fondo blanco. A igual recuadro, el tarro se ve pequeño aunque el recuadro mida
   lo que tiene que medir. Lo definitivo es reexportarlas recortadas; mientras
   tanto, se compensa escalando.

   🔴 DE DÓNDE SALE EL 1.35, QUE NO ES UN NÚMERO A OJO. El tope no lo pone el tarro
   suelto sino la foto de "frontal y trasera", la de DOS tarros juntos, que es la
   que más alto ocupa: su contenido va aproximadamente del 18 % al 85 % del alto
   del archivo. Como el escalado sale del CENTRO del recuadro y ese contenido está
   un poco por debajo del centro, el borde que primero se toca es el de ABAJO:

     borde inferior = 50 % + (85 % − 50 %) × escala
     a 1.35 → 50 + 35 × 1.35 = 97,3 % del alto  → queda margen
     a 1.43 → 50 + 35 × 1.43 = 100 %            → la base del tarro toca el borde

   Por eso 1.35 y no más: deja cerca de un 3 % de aire por debajo, que es lo justo
   para absorber que el encuadre no es idéntico en los ocho productos. El más
   ajustado de todos es la Gordal Aliñada, cuyos tarros suben y bajan un poco más
   que los demás; es el que hay que mirar primero si algún día se sube el valor.
   Con 1.35 el par de tarros pasa de ocupar dos tercios del recuadro a llenar el
   90 % de su alto, y el tarro suelto pasa del 60 % al 81 %.

   ⚠ NO SE SUBE MÁS AUNQUE "QUEPA". A partir de 1.40 el margen inferior de la foto
     de dos tarros se queda en nada y cualquier producto nuevo con un encuadre un
     dedo más alto saldría con la base cortada. Si Jaime lo quiere aún más grande,
     lo que hay que cambiar son las fotos, no este número.

   ⚠ NITIDEZ: aquí no se pierde. El archivo mide 1024 px y el recuadro ronda los
     600 px en escritorio, así que a 1.35 la foto se pinta a unos 810 px, todavía
     por debajo de lo que da el archivo. Es el caso contrario al del 500 ml de
     arriba, que a 1.45 sí se pasa. En pantallas de densidad 2 la foto ya iba
     justa antes de este cambio, y esto no lo empeora en proporción.

   ⚠ ALCANCE: solo la foto GRANDE. Las miniaturas viven en
     .ga-product__gallery-thumbs y las flechas son hermanas del marco, dentro de
     .ga-product__gallery-fila: ninguna de las dos entra en este selector. Y se
     aplica a LAS CINCO fotos del producto, no solo a la primera —todas son <img>
     dentro del marco—, que es lo que hace que al cambiar de foto no se vea un
     salto de tamaño.

   ⚠ EL transform NO ENSANCHA LA MAQUETACIÓN. Es la razón por la que se escala y
     no se agranda la caja: un transform no amplía el ancho de maquetación, así que
     a 360 px no puede aparecer desbordamiento horizontal por su culpa (es lo mismo
     en lo que se apoyan los carruseles de la tienda, 🪤 nº 1).

   La clase la pinta single-product-custom.php y sale de la CATEGORÍA del producto,
   no de una lista de SKU: un tarro nuevo la hereda solo. Los packs de tarros y las
   fichas de Eventos se quedan fuera desde el PHP. */
.ga-product-single--aceitunas .ga-product__gallery-main img {
    transform: scale(1.35);
}

/* ——— LA MERMELADA: SOLO SU SEGUNDA Y TERCERA FOTO ———
   TERCERA VEZ QUE APARECE EL MISMO PROBLEMA Y TERCERA VEZ QUE SE USA LA MISMA
   HERRAMIENTA: se escala SOLO la <img>, el recuadro no cambia de tamaño ni se mueve
   un píxel, y su overflow: hidden se queda con lo que sobresale —que es aire, no
   producto—. Es a propósito: no hay dos formas distintas de resolver esto en el
   tema, y quien toque una de las tres entiende las otras dos.

   🔴 AQUÍ SÍ SE ACOTA A DOS FOTOS, Y ES LA DIFERENCIA CON LAS OTRAS DOS REGLAS. En
   el 500 ml y en los tarros se escalan TODAS las fotos del producto, justamente para
   que al cambiar de imagen no se vea un salto de tamaño. En la mermelada no se puede
   hacer eso: la primera está bien encuadrada y agrandarla la cortaría. Así que se
   escogen la 2ª y la 3ª por POSICIÓN, que es exactamente el concepto que pide el
   encargo, con la misma forma de contar que ya usa el mapa de fotos de Eventos: se
   cuenta sobre la galería tal y como se ve, empezando por 1 en la imagen destacada.

   ⚠ SE ASUME UN SALTO DE TAMAÑO AL PASAR DE LA 1ª A LA 2ª. Es la contrapartida
     inevitable de escalar solo dos, y se prefiere a dejarlas diminutas. Desaparece
     solo el día que se reexporten las fotos.

   nth-of-type y no nth-child: dentro del marco NO hay más que <img> —el bucle de la
   plantilla no pinta otra cosa—, pero contar por tipo aguanta que mañana se meta ahí
   un rótulo o un adorno sin descolocar qué foto se agranda.

   🔴 DE DÓNDE SALE EL 1.40, CON LA CUENTA HECHA. Es la misma aritmética de los
   tarros de aquí arriba. En la foto de estudio de la mermelada el tarro ocupa
   aproximadamente del 18 % al 85 % del alto del archivo; como el escalado sale del
   CENTRO del recuadro, el borde que primero se toca es el de abajo:

     borde inferior = 50 % + (85 % − 50 %) × escala
     a 1.40 → 50 + 35 × 1.40 = 99 %    → entra entero, con un 1 % de aire
     a 1.43 → 50 + 35 × 1.43 = 100 %   → la base del tarro toca el borde

   Con 1.40 el tarro pasa de ocupar dos tercios del recuadro a llenar casi su alto
   entero, que es lo que se pedía, y se queda justo por debajo del punto de corte.
   1.40 es además el valor más alto COMPROBADO en este tema —es el que usa la home al
   pasar el ratón sobre esta misma foto sin que el tarro se corte—, así que no es un
   número inventado.

   ⚠ ESTE NÚMERO ESTÁ MEDIDO SOBRE LA FOTO FRONTAL, QUE ES LA ÚNICA QUE SE PUEDE
     ABRIR DESDE EL TEMA (assets/images). Las de la galería viven en la biblioteca de
     medios y desde aquí no se ven, así que si la 2ª o la 3ª vienen con otro encuadre
     hay que rematarlo a ojo: si el tarro toca un borde se baja a 1.35 —terreno
     conocido, es el de los tarros de aceituna—, y si aún se ve pequeño se sube.
     Es UN solo número y está en un solo sitio.

   ⚠ NITIDEZ. Con un archivo de 1024 px —el tamaño de las demás fotos de producto del
     catálogo— y un recuadro de unos 600 px en escritorio, a 1.40 la foto se pinta a
     unos 840 px: todavía por debajo de lo que da el archivo, así que no se ablanda.
     Si estas dos se subieron a 600 px, a esta escala se verán blandas y lo que hay
     que hacer es volver a subirlas más grandes, no bajar la escala.

   ⚠ ALCANCE: solo la foto GRANDE, igual que las otras dos reglas. Las miniaturas
     viven en .ga-product__gallery-thumbs y las flechas son hermanas del marco, dentro
     de .ga-product__gallery-fila: ninguna de las dos entra en este selector.

   ⚠ EL transform NO ENSANCHA LA MAQUETACIÓN, así que a 360 px no puede aparecer
     desbordamiento horizontal por su culpa (🪤 nº 1).

   La clase --mermelada la pinta single-product-custom.php desde $ga_es_mermelada, la
   misma variable que decide las cantidades en tarros y la descripción plegada. */
.ga-product-single--mermelada .ga-product__gallery-main .ga-product__gallery-foto:nth-of-type(2),
.ga-product-single--mermelada .ga-product__gallery-main .ga-product__gallery-foto:nth-of-type(3) {
    transform: scale(1.40);
}


/* ─── Galería por capas (fichas que NO son de Eventos) ───────────────────────
   Todas las fotos se pintan a la vez, apiladas en la misma celda, y cambiar de
   foto es encender una y apagar otra. Así se quitó el destello crema: antes se
   apagaba la única imagen, se esperaba, y solo entonces se le cambiaba el src;
   en ese hueco lo que se veía era el fondo del marco.

   🔴 REJILLA DE 1×1 Y NO position: absolute. Con absolute las fotos saldrían del
   flujo y la figura se quedaría sin contenido que le diera alto: en Chrome de
   Android eso colapsa el marco y la foto no se ve (es la trampa nº 11 del
   claude.md, que ya pasó en la página Nosotros). Compartiendo celda de rejilla
   siguen en el flujo y el alto lo marcan el aspect-ratio del marco y ellas
   mismas. */
/* 🔴 LA REJILLA YA NO DEPENDE DE :has(), Y ESA ERA LA CAUSA QUE QUEDABA.
   Antes este selector era `.ga-product__gallery-main:has(.ga-product__gallery-foto)`
   y, para los navegadores sin :has(), había al final del bloque una vía
   alternativa que ocultaba las fotos con display:none. Ese respaldo es justo lo
   que NO se puede hacer: una imagen con display:none no se descodifica hasta que
   se muestra, así que al cambiar de foto había que esperar a que el navegador la
   descodificara y en ese hueco se veía el marco. El fundido, además, no existía.

   Acotando por la clase del <main> en vez de por el contenido, la rejilla se
   aplica siempre y el respaldo sobra. Se ha borrado.

   ⚠ REJILLA DE 1×1 Y NO position: absolute. Con absolute las fotos saldrían del
     flujo; aquí el marco tiene aspect-ratio propio y aguantaría, pero se mantiene
     la rejilla porque es lo que ya funcionaba y porque en Chrome de Android una
     figura sin contenido en flujo se colapsa (🪤 nº 11).

   FONDO BLANCO, NO CREMA: última red por si llegara a verse el fondo un instante.
   El blanco se confunde con el de las propias fotos de producto, que van
   recortadas sobre blanco; con el crema, cualquier hueco cantaba. */
.ga-product-single:not(.ga-product-single--eventos) .ga-product__gallery-main {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    background: var(--ga-blanco);
}

/* Las que no se ven van SOLO a opacidad 0. Nunca display:none ni
   visibility:hidden: las dos impiden que el navegador descodifique la imagen de
   antemano, que es de lo que depende que el cambio sea instantáneo.

   pointer-events: none para que las capas apagadas no intercepten el ratón: están
   apiladas encima unas de otras y, aunque no se vean, siguen ocupando la misma
   caja. */
.ga-product-single .ga-product__gallery-foto {
    grid-area: 1 / 1;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    opacity: 0;
    pointer-events: none;
    /* En una rejilla el z-index funciona sin necesidad de posicionar nada. */
    z-index: 1;
    transition: opacity 180ms ease;
}

.ga-product-single .ga-product__gallery-foto.is-activa {
    opacity: 1;
    pointer-events: auto;
}

/* La que entra se pinta POR ENCIMA de la que sale. La de abajo se queda opaca
   hasta que la de arriba ha llegado del todo, así que en ningún fotograma se ve
   el fondo del marco. */
.ga-product-single .ga-product__gallery-foto.is-entrando {
    z-index: 2;
}

/* Ahorro de movimiento: el cambio es instantáneo, sin fundido.

   ⚠ ESTO OBLIGA AL JS A NO FIARSE SOLO DE transitionend: sin transición ese
     evento NO se dispara nunca, y sin la red de seguridad del temporizador la
     foto saliente se quedaría encendida para siempre debajo de la nueva. Está
     contemplado en gaGaleria(). */
@media (prefers-reduced-motion: reduce) {
    .ga-product-single .ga-product__gallery-foto {
        transition: none;
    }
}

.ga-product__gallery-thumbs {
    display: flex;
    gap: 0.625rem;
    flex-wrap: wrap;
}

.ga-gallery-thumb {
    width: 72px;
    height: 72px;
    border-radius: var(--ga-radius-sm);
    overflow: hidden;
    border: 2px solid transparent;
    cursor: pointer;
    background: var(--ga-naranja-claro);
    padding: 0;
    transition: border-color var(--ga-transition-fast), transform var(--ga-transition-fast);
    flex-shrink: 0;
}

.ga-gallery-thumb:hover { border-color: var(--ga-naranja-apagado); transform: translateY(-1px); }
.ga-gallery-thumb.is-active { border-color: var(--ga-verde-oliva-oscuro); }

.ga-gallery-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Vídeo placeholder */
.ga-product__video-placeholder {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1.25rem 1.5rem;
    background: var(--ga-naranja-claro);
    border-radius: var(--ga-radius-md);
    border: 1.5px dashed var(--ga-amarillo-pastel);
    color: var(--ga-verde-oliva-oscuro);
}

.ga-product__video-btn {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: var(--ga-verde-oliva-oscuro);
    color: var(--ga-blanco);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.ga-product__video-texto {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    font-family: var(--ga-font-body);
}

.ga-product__video-texto strong {
    font-size: var(--ga-text-sm);
    font-weight: 600;
    color: var(--ga-verde-oliva-oscuro);
}

.ga-product__video-texto span {
    font-size: var(--ga-text-xs);
    color: var(--ga-verde-montanas);
}


/* ─── Información de compra ──────────────────────── */

.ga-product__purchase {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
}

.ga-product__cat-tag {
    display: inline-block;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--ga-naranja-apagado);
    text-decoration: none;
}

.ga-product__cat-tag:hover { text-decoration: underline; }

.ga-product__name {
    font-family: var(--ga-font-display);
    font-size: clamp(1.6rem, 2.5vw, 2.2rem);
    font-weight: 600;
    line-height: 1.15;
    color: var(--ga-verde-oliva-oscuro);
    margin: 0;
}

/* Precio WooCommerce */
.ga-product__price-wrap {
    display: flex;
    align-items: baseline;
    gap: 1rem;
    flex-wrap: wrap;
}

/* Dos selectores para el mismo aspecto, y cada uno tiene su motivo:

   .woocommerce-Price-amount → el precio de los productos SIMPLES, que lo sigue
     pintando get_price_html() con el marcado de WooCommerce.

   .ga-precio-cabecera → el de los productos VARIABLES, que se escribe a mano
     precisamente para NO llevar ninguna clase de WooCommerce: esa clase es la
     diana por la que otros scripts encontraban el contenedor y lo reescribían.

   Los dos tienen que verse idénticos: es el mismo precio en el mismo sitio, y
   cualquier diferencia de tamaño movería la ficha al pasar de uno a otro. */
.ga-product__price .woocommerce-Price-amount,
.ga-product__price .ga-precio-cabecera {
    font-family: var(--ga-font-display);
    font-size: clamp(1.8rem, 3vw, 2.4rem);
    font-weight: 600;
    color: var(--ga-naranja-apagado);
    line-height: 1;
}

/* El JS solo le cambia el texto, nunca el marcado, así que el alto de la línea no
   varía: el precio cambia sin que la ficha dé ningún salto. */
.ga-product__price .ga-precio-cabecera {
    display: inline-block;
}

.ga-product__price del .woocommerce-Price-amount {
    font-size: 1.1rem;
    color: var(--ga-amarillo-pastel);
}

.ga-product__price ins {
    text-decoration: none;
}

/* ——— EL PRECIO ANTERIOR TACHADO DE LOS VARIABLES ———
   Mismos dos valores que la regla de aquí arriba —1,1rem y el amarillo pastel—, y
   NO es duplicar por duplicar: son dos marcados distintos para lo mismo. El de
   arriba es el de WooCommerce, que sigue pintando los productos SIMPLES; este es el
   que se escribe a mano para los VARIABLES, precisamente para que no lleve la clase
   .woocommerce-Price-amount por la que otros scripts encontraban el precio y lo
   reescribían con su versión. Los dos tienen que verse idénticos: es el mismo
   precio en el mismo sitio.

   El tachado en sí lo pone el navegador: es un <del>, y no hace falta declararlo.

   El margen separa el precio anterior del actual. Va solo a la derecha para que al
   ocultarse no deje ningún hueco suelto. */
.ga-product__price .ga-precio-cabecera__antes {
    font-size: 1.1rem;
    color: var(--ga-amarillo-pastel);
    margin-inline-end: 0.5rem;
}

/* 🔴 HACE FALTA DECLARARLO. El [hidden] del navegador vale display: none, pero
   pierde contra cualquier regla de display con más peso, y aquí el elemento vive
   dentro de un contenedor que ya declara display: inline-block. Sin esta línea, el
   precio anterior seguiría viéndose en las modalidades que no están rebajadas. */
.ga-product__price .ga-precio-cabecera__antes[hidden] {
    display: none;
}

.ga-product__sku {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    color: var(--ga-amarillo-pastel);
    letter-spacing: 0.06em;
}

/* Descripción corta */
.ga-product__short-desc {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    line-height: 1.7;
    color: var(--ga-verde-oliva-oscuro);
    border-top: 1px solid var(--ga-naranja-claro);
    border-bottom: 1px solid var(--ga-naranja-claro);
    padding-block: 1rem;
}

.ga-product__short-desc p { margin: 0 0 0.5rem; }
.ga-product__short-desc p:last-child { margin-bottom: 0; }
.ga-product__short-desc ul { padding-left: 0; list-style: none; }
.ga-product__short-desc ul li {
    padding: 0.25rem 0;
    padding-left: 1.2em;
    position: relative;
}
.ga-product__short-desc ul li::before {
    content: '·';
    position: absolute;
    left: 0;
    color: var(--ga-naranja-apagado);
    font-weight: 700;
}

/* Stock */
.ga-product__stock {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.ga-product__stock.is-in-stock  { color: #2d7a2d; }
.ga-product__stock.is-out-of-stock { color: #c0392b; }

/* ——— LA CAMISETA AVISA EN NARANJA ———
   No es un producto que esté "disponible" sin más: son 15 unidades y no habrá más,
   así que su línea dice "Últimas unidades" —eso lo decide la plantilla— y se pinta en
   un naranja de urgencia en lugar del verde de arriba.

   🔴 UNA SOLA DECLARACIÓN LO TIÑE TODO, y ese es el motivo de hacerlo aquí y no en
   tres reglas. El punto indicador se dibuja con background-color: currentColor y su
   halo con dos color-mix sobre currentColor —está en main.css—, así que al cambiar el
   `color` de la línea cambian a la vez el texto "Últimas unidades", el "Envío 24-48 h"
   y el círculo con su latido. Ni un color repetido, y nada que se pueda desincronizar.

   🔴 EL NARANJA ES UNA VARIABLE Y VIVE ACOTADA AQUÍ, no en el :root de style.css.
   No es un color de la paleta de marca —esa tiene el dorado, el verde y el marrón— y
   soltarlo en el :root invitaría a usarlo en cualquier parte. Declarándolo sobre el
   modificador de la prenda, solo existe dentro de esta ficha: fuera de ella la
   variable ni siquiera está definida.

   ⚠ CONTRASTE COMPROBADO: #c2410c sobre el blanco de la columna da 5,18:1, por encima
     del 4,5:1 que pide la norma para texto —el verde al que sustituye da 5,34:1, así
     que se lee prácticamente igual de bien— y sigue leyéndose inequívocamente naranja
     y no marrón, que es lo que tiene que comunicar.

   ⚠ SOLO SE PINTA ESTA LÍNEA. El botón de comprar, los sellos y el resto de la ficha
     siguen en dorado: esta regla no toca nada más que .ga-product__stock. */
.ga-product-single--textil {
    --ga-textil-naranja: #c2410c;
}

.ga-product-single--textil .ga-product__stock.is-in-stock {
    color: var(--ga-textil-naranja);
}


/* =============================================================================
   LA MERMELADA · "¿CON QUÉ LA PRUEBO?" — LA REJILLA DE MARIDAJES
   =============================================================================
   Ocupa el sitio de la tabla comparativa de los aceites. La SECCIÓN no se viste
   aquí: el marcado lleva .ga-product__comparativa, la misma clase que las otras
   dos, y de ella salen el relleno vertical, el fondo blanco y el aire bajo el
   titular. Lo único propio es la rejilla y la tarjeta.

   🔴 LA TARJETA NO ESTRENA LENGUAJE VISUAL: es la receta de .ga-tc-marco, el marco
   de la tabla a la que sustituye —borde de 1px en el crema de marca, radio de 10px
   y fondo blanco—, y su tipografía es la de las tarjetas de la sección de las tres
   fotos. Ni un color ni un tamaño inventados: todo sale de las variables de marca.

   🔴 LAS SEIS MIDEN LO MISMO Y ACABAN A LA MISMA ALTURA, y eso lo da la rejilla
   sola: los elementos de un grid se estiran a la altura de su fila por defecto
   (align-items: stretch), así que las tres de cada fila cierran parejas aunque una
   lleve una línea más de texto. No hace falta ni subgrid ni alturas fijas. */
.ga-maridajes__grid {
    display: grid;
    /* 🔴 minmax(0, 1fr) Y NO 1fr. El mínimo por defecto de una pista es el ancho de
       su contenido, y "Con anchoas o boquerones" ensancharía su columna y con ella
       la fila entera. Con el 0 de mínimo la pista encoge y el texto parte donde
       toca: es cómo se corta el ancho mínimo sin usar min-width.

       UNA SOLA COLUMNA DE PARTIDA, y las tres llegan en el breakpoint de abajo. Al
       ser mobile-first, a 360px se apilan sin que haya que deshacer nada. */
    grid-template-columns: minmax(0, 1fr);
    gap: var(--ga-space-sm);

    /* 🔴 LAS SEIS A LA MISMA ALTURA, NO SOLO LAS DE CADA FILA. Un grid ya estira sus
       elementos hasta la altura de SU fila, así que las tres de arriba habrían
       cerrado parejas entre sí y las tres de abajo entre sí, pero las dos filas
       podrían acabar con alturas distintas. Con las filas implícitas a 1fr todas
       miden lo que la más alta, y las seis tarjetas quedan idénticas.

       No hace falta ninguna altura fija ni ningún subgrid: la más alta manda y las
       demás la siguen, así que si mañana se cambia un texto se reajusta solo. */
    grid-auto-rows: 1fr;

    /* Es un <ul>: se le quitan la viñeta y el sangrado, que son decoración. */
    margin: 0;
    padding: 0;
    list-style: none;
}

@media (min-width: 861px) {

    /* El mismo tramo en el que la sección de las tres fotos pasa a tres columnas,
       para que las dos rejillas de la ficha cambien a la vez. */
    .ga-maridajes__grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: var(--ga-space-md);
    }
}

.ga-maridaje {
    /* ——— FONDO CREMA DE MARCA ———
       Antes eran blancas sobre la sección blanca y solo las separaba el filete. Con
       el crema se leen como seis piezas y no como seis recuadros dibujados sobre el
       fondo.

       El borde pasa al verde pálido de marca, que es EXACTAMENTE el que llevan las
       tarjetas de "Elige la cantidad" en esta misma ficha: sobre el crema, el filete
       en --ga-naranja-claro que tenían antes se habría vuelto invisible, porque es
       el mismo color que ahora rellena la tarjeta. Así que el borde no se pierde,
       cambia al tono que esta ficha ya usa para enmarcar una tarjeta. */
    background-color: var(--ga-naranja-claro);
    border: 1px solid var(--ga-amarillo-pastel);
    border-radius: 10px;

    box-sizing: border-box;
    padding: var(--ga-space-md);

    /* ——— LA SOMBRA, EN REPOSO Y TRANSPARENTE ———
       🔴 NACE CON LA SOMBRA PUESTA PERO INVISIBLE, y no es un rodeo: pasar de
       `none` a una sombra deja la transición a merced de cómo interpole cada motor
       el valor inicial. Declarándola desde el principio con la MISMA geometría y
       alfa 0, lo único que cambia al pasar el ratón es la opacidad del color, que
       es un tramo que todos los navegadores animan igual de bien, y la salida es
       tan suave como la entrada.

       Los números son los de --ga-shadow-md (el mismo 74,74,47 de las sombras de
       marca) escritos a mano porque dentro de un rgba() no se puede meter un var().
       Es el mismo recurso que ya usa el resto del proyecto para sus sombras.

       ⚠ UNA SOMBRA NO OCUPA SITIO: se pinta fuera de la caja y no entra en el
         cálculo de la maquetación, así que la tarjeta no puede moverse ni empujar a
         las de al lado. Es justo por eso que el efecto es una sombra y no una
         escala ni un translateY. */
    box-shadow: 0 4px 16px rgba(74, 74, 47, 0);
    transition: box-shadow var(--ga-transition-normal);
}

/* ——— Y AL PASAR EL RATÓN, SE ENCIENDE ———
   🔴 ACOTADO A LOS PUNTEROS DE VERDAD. En una pantalla táctil no hay "pasar por
   encima": el navegador simula un hover al tocar y lo deja pegado hasta que tocas
   otra cosa, así que la tarjeta se quedaría con la sombra encendida sin que nadie
   entienda por qué. Con (hover: hover) y (pointer: fine) el efecto solo existe
   donde hay ratón o trackpad.

   ⚠ LO ÚNICO QUE CAMBIA ES LA SOMBRA. Ni tamaño, ni posición, ni borde, ni
     relleno: la tarjeta se queda exactamente donde está. */
@media (hover: hover) and (pointer: fine) {

    .ga-maridaje:hover {
        box-shadow: var(--ga-shadow-md);
    }
}

/* Ahorro de movimiento: la sombra sigue apareciendo —es información, no adorno—
   pero sin transición, de golpe. */
@media (prefers-reduced-motion: reduce) {

    .ga-maridaje {
        transition: none;
    }
}

.ga-maridaje__titulo {
    margin: 0 0 0.4rem;

    /* La negrita que pide el encargo, en la Inter del cuerpo y no en la serif de
       los títulos de sección: es un rótulo dentro de una tarjeta, del mismo rango
       que el nombre de una opción, no un titular. */
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-base);
    font-weight: 700;
    line-height: 1.35;
    color: var(--ga-verde-oliva-oscuro);

    /* 🔴 text-wrap: wrap ANULA EL balance DE LA REGLA GENERAL DE TÍTULOS. Esa regla
       alcanza a todos los h1–h6 y reparte las palabras en líneas de largo parecido
       en vez de llenar cada una: en un rótulo de tarjeta deja "Con anchoas o" y
       "boquerones" con un margen derecho enorme. Es la trampa nº 16 del claude.md,
       y se corrige acotado, sin tocar la regla general. */
    text-wrap: wrap;

    /* Corta el ancho mínimo sin min-width. */
    overflow-wrap: break-word;
}

.ga-maridaje__texto {
    margin: 0;

    /* La misma receta que el texto de las tarjetas de las tres fotos, un escalón
       por debajo del rótulo que encabeza. */
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    line-height: 1.6;
    color: var(--ga-verde-oliva-oscuro);
    overflow-wrap: break-word;
}

/* ——— EL PUNTO DE DISPONIBILIDAD CUANDO NO HAY EXISTENCIAS ———
   El punto es el mismo de eventos y toma su color del texto (currentColor), así
   que aquí ya sale en el rojo del aviso sin escribir ningún color.

   🔴 LO QUE HAY QUE APAGAR ES LA ONDA. Late para decir "esto está vivo, hay
   stock"; junto a un "agotado" diría justo lo contrario del texto que acompaña.
   Se le quita el ::after, que es donde vive el latido, y se le baja el tono al
   círculo para que informe sin llamar la atención.

   Se apaga con opacidad y no con otro color a propósito: así sigue siendo el
   mismo rojo del texto —un color de marca menos que mantener— y, además, la
   opacidad no cambia el tamaño ni empuja al texto de al lado.

   La regla de prefers-reduced-motion no hace falta repetirla: la de main.css
   apunta a .ga-eventos-stock__punto::after sin acotar, así que ya alcanza también
   a este punto. */
.ga-product-single .ga-product__stock.is-out-of-stock .ga-eventos-stock__punto {
    opacity: 0.55;
}

.ga-product-single .ga-product__stock.is-out-of-stock .ga-eventos-stock__punto::after {
    display: none;
}

/* Selector de cantidad */
.ga-product__qty-row {
    display: flex;
    align-items: center;
}

.ga-qty-wrapper {
    display: inline-flex;
    align-items: center;
    border: 1.5px solid var(--ga-amarillo-pastel);
    border-radius: var(--ga-radius-sm);
    overflow: hidden;
    background: var(--ga-blanco);
}

.ga-qty-btn {
    width: 42px;
    height: 46px;
    background: none;
    border: none;
    font-size: 1.2rem;
    font-weight: 400;
    color: var(--ga-verde-oliva-oscuro);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background var(--ga-transition-fast), color var(--ga-transition-fast);
    flex-shrink: 0;
}

.ga-qty-btn:hover {
    background: var(--ga-verde-oliva-oscuro);
    color: var(--ga-blanco);
}

.ga-qty-input {
    width: 56px;
    height: 46px;
    border: none;
    border-inline: 1.5px solid var(--ga-amarillo-pastel);
    text-align: center;
    font-family: var(--ga-font-body);
    font-size: 1rem;
    font-weight: 600;
    color: var(--ga-verde-oliva-oscuro);
    background: var(--ga-blanco);
    -moz-appearance: textfield;
    appearance: textfield;
}

.ga-qty-input::-webkit-inner-spin-button,
.ga-qty-input::-webkit-outer-spin-button { -webkit-appearance: none; appearance: none; }

/* Botones CTA */
.ga-product__cta-buttons {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    margin-top: 1.25rem;   /* espacio respecto al selector de cantidad */
}

.ga-btn--xl {
    padding: 1.1rem 2rem;
    font-size: 0.82rem;
    letter-spacing: 0.1em;
    justify-content: center;
    text-align: center;
}

/* "Comprar ahora" es el botón principal (aparece primero visualmente) */
.ga-product__btn-buy-now {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    order: -1;   /* sube encima de "Añadir al carrito" */
}

/* "Añadir al carrito" pasa a secundario (outline) */
.ga-product__btn-cart {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    order: 0;
}

.ga-btn--outline-dark {
    background: transparent;
    color: var(--ga-verde-oliva-oscuro);
    border: 2px solid var(--ga-verde-oliva-oscuro);
}

.ga-btn--outline-dark:hover {
    background: var(--ga-verde-oliva-oscuro);
    color: var(--ga-blanco);
    transform: translateY(-2px);
    box-shadow: var(--ga-shadow-sm);
}

/* Agotado */
.ga-product__agotado {
    padding: 1.25rem;
    background: var(--ga-naranja-claro);
    border-radius: var(--ga-radius-sm);
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    color: var(--ga-verde-oliva-oscuro);
}

.ga-product__agotado a {
    color: var(--ga-naranja-apagado);
    font-weight: 600;
    text-decoration: none;
}

/* Banda de confianza */
.ga-product__trust-band {
    display: flex;
    gap: 0.75rem;
    padding: 1rem 1.25rem;
    background: var(--ga-naranja-claro);
    border-radius: var(--ga-radius-sm);
    border: 1px solid var(--ga-amarillo-pastel);
}

.ga-trust-item {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex: 1;
    min-width: 0;
}

.ga-trust-item svg {
    flex-shrink: 0;
    color: var(--ga-verde-montanas);
}

.ga-trust-item div {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
}

.ga-trust-item strong {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    font-weight: 700;
    color: var(--ga-verde-oliva-oscuro);
    letter-spacing: 0.03em;
    line-height: 1.2;
}

.ga-trust-item span {
    font-family: var(--ga-font-body);
    font-size: 0.68rem;
    color: var(--ga-verde-montanas);
}


/* ─── Zona Media — Acordeón ──────────────────────── */

.ga-product__accordion-zone {
    padding-top: 2rem;
    padding-bottom: var(--ga-space-xl);
    background: var(--ga-naranja-claro);
}

.ga-accordion__item {
    border-bottom: 1px solid var(--ga-amarillo-pastel);
}

.ga-accordion__item:first-child {
    border-top: 1px solid var(--ga-amarillo-pastel);
}

.ga-accordion__trigger {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.25rem 0;
    background: none;
    border: none;
    cursor: pointer;
    text-align: left;
    font-family: var(--ga-font-body);
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--ga-verde-oliva-oscuro);
    letter-spacing: 0.02em;
    transition: color var(--ga-transition-fast);
}

.ga-accordion__trigger:hover { color: var(--ga-naranja-apagado); }

.ga-accordion__chevron {
    flex-shrink: 0;
    transition: transform var(--ga-transition-normal);
    color: var(--ga-naranja-apagado);
}

.ga-accordion__item.is-open .ga-accordion__chevron {
    transform: rotate(180deg);
}

.ga-accordion__body {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}

.ga-accordion__inner {
    padding-bottom: 1.5rem;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    line-height: 1.75;
    color: var(--ga-verde-oliva-oscuro);

    /* Corta las palabras que no quepan enteras. Hasta ahora ninguna respuesta tenía
       ninguna, pero las preguntas frecuentes de los aceites traen una dirección de
       correo —21 caracteres sin un solo espacio donde partir—, y una palabra que no
       cabe es lo único que puede sacar texto fuera de su caja en una pantalla
       estrecha. Es la forma de cortar el ancho mínimo sin recurrir a min-width. */
    overflow-wrap: break-word;
}

.ga-accordion__inner p { margin: 0 0 0.75rem; }
.ga-accordion__inner p:last-child { margin-bottom: 0; }
.ga-accordion__inner a { color: var(--ga-naranja-apagado); font-weight: 600; }
.ga-accordion__inner a:hover { text-decoration: underline; }

/* Ficha técnica — tabla */
.ga-ficha-table {
    width: 100%;
    border-collapse: collapse;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
}

.ga-ficha-table thead th {
    font-weight: 700;
    font-size: var(--ga-text-xs);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--ga-verde-montanas);
    padding: 0.5rem 0.875rem;
    border-bottom: 2px solid var(--ga-amarillo-pastel);
    text-align: center;   /* encabezado de información nutricional centrado */
}

.ga-ficha-table tbody th,
.ga-ficha-table tbody td {
    padding: 0.625rem 0.875rem;   /* padding horizontal para separar del borde */
    border-bottom: 1px solid rgba(195, 196, 170, 0.4);
    vertical-align: top;
}

.ga-ficha-table tbody th {
    font-weight: 600;
    color: var(--ga-verde-oliva-oscuro);
    width: 38%;
    padding-right: 1rem;
}

.ga-ficha-table tbody td {
    color: var(--ga-verde-montanas);
}

.ga-nutricion-nota {
    font-size: var(--ga-text-xs);
    color: var(--ga-verde-montanas);
    text-align: right;
    margin-bottom: 0.5rem;
    font-style: italic;
}

/* Listas de envío / devolución */
.ga-info-lista {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.ga-info-lista li {
    padding-left: 1.4rem;
    position: relative;
}

.ga-info-lista li::before {
    content: '→';
    position: absolute;
    left: 0;
    color: var(--ga-naranja-apagado);
    font-weight: 700;
}


/* ─── Comparativa ────────────────────────────────── */

.ga-product__comparativa {
    padding-block: var(--ga-space-xl);
    background: var(--ga-blanco);
}

/* Esta sección ya NO tiene subtítulo, así que el título tampoco necesita el hueco
   que .ga-section__titulo reserva debajo para cuando lo lleva: sin esto quedaría un
   escalón de 0,75rem entre el título y la tabla que no pinta nada.

   Va acotado a la comparativa: el resto de secciones de la ficha siguen con su
   subtítulo y con su margen intacto. La separación de verdad entre el bloque del
   encabezado y la tabla la sigue poniendo .ga-section__header--center. */
.ga-product__comparativa .ga-section__titulo {
    margin-bottom: 0;
}

/* ——— EL AIRE ENTRE EL TÍTULO Y LA TABLA ———
   ═══════════════════════════════════════════════════════════════════════════
   🔴 EL SALIENTE SE ESTABA COMIENDO LA SEPARACIÓN, Y POR ESO SE VEÍAN PEGADOS.
   La separación de esta sección era --ga-space-lg (2,5rem, 40px) y el saliente de
   la columna destacada sobresale 3rem (48px) por encima de la tabla. Como va en
   posición absoluta NO EMPUJA NADA: se limita a invadir esos 48px hacia arriba.
   O sea que no es que quedara poco aire —es que el saliente llegaba 8px POR
   ENCIMA de donde acababa el título y lo pisaba.

   Se arregla en dos pasos, los dos con medidas del sistema de espaciado:

   1) La separación de la sección sube un escalón, de --ga-space-lg a
      --ga-space-xl (4rem). Vale para TODAS las fichas, tengan columna destacada o
      no: en un pack o en un tarro de aceitunas la tabla también respira más.

   2) Y cuando HAY columna destacada, el marco baja además lo que mide el
      saliente. Así la separación se mide desde el borde superior del saliente y
      no desde la fila de títulos, que es lo que se pedía: el hueco visible acaba
      siendo el mismo —4rem— en los dos casos.

   🔴 EL DESPLAZAMIENTO USA LA MISMA VARIABLE QUE DEFINE EL SALIENTE, no un número
   copiado. Si algún día se cambia el alto de esa franja —por ejemplo porque la
   frase pase a dos líneas—, la separación se ajusta sola y no hay que acordarse
   de tocar dos sitios.
   ═══════════════════════════════════════════════════════════════════════════ */
.ga-product__comparativa .ga-section__header--center {
    margin-bottom: var(--ga-space-xl);
}

.ga-product__comparativa .ga-tc-marco--con-destacada {
    margin-top: var(--ga-tc-saliente-arriba);
}


/* =============================================================================
   COMPARATIVA — TABLA DE LOS TRES FORMATOS Y "OTROS AOVE"
   =============================================================================
   Sustituye a la rejilla de divs que no alineaba. El porqué del cambio está
   explicado en la plantilla, junto al marcado; aquí basta con lo que afecta al
   CSS: una <table> reparte las columnas ella sola y no hay forma de que una celda
   caiga bajo la que no es.

   🔴 table-layout: fixed NO ES OPCIONAL. Sin él, una tabla se ensancha hasta que
   le cabe el contenido y NO encoge por debajo de eso: con cinco columnas se
   saldría de la página en cuanto la pantalla no diera (🪤 nº 1). Con el reparto
   fijo mandan los anchos del <colgroup> y el texto que no quepa envuelve.
   ============================================================================= */

/* ——— EL MARCO DE LA TABLA ———
   Vale para LAS DOS tablas, la de escritorio y la de móvil: las dos vuelven a ser
   un rectángulo completo y las dos lo dibujan aquí, de una pieza. (Hubo una
   temporada en que la de escritorio desarmaba este borde para poder esconder la
   celda de la esquina; eso está revertido y contado unas líneas más abajo.)

   🔴 EL BORDE Y EL REDONDEO VAN AQUÍ Y NO EN LA <table>, y hay DOS motivos.

   Uno: con border-collapse: separate —obligatorio aquí, porque con collapse el
   navegador ignora los border-radius— un borde puesto en la propia tabla se
   dibuja pegado a las celdas de los extremos y se solapa con ellas.

   Dos, y es el que explica la línea descuadrada que se veía arriba y a la
   izquierda: el tema padre le pone un borde asimétrico a toda <table> (está
   contado con detalle en .ga-tc, aquí debajo). Sacando el borde de la tabla y
   dándoselo a un div de alrededor, no hay nada con lo que competir ni con lo que
   solaparse: rodea los cuatro lados por igual, con el mismo grosor y el mismo
   tono.

   ⚠ Y EL RECORTE ES LO QUE HACE QUE LOS FONDOS RESPETEN LAS ESQUINAS. Sin él, el
     fondo dorado de la primera columna y el blanco del bloque saldrían cuadrados
     por debajo del redondeo. Se declara dos veces: `clip` recorta igual pero NO
     convierte al elemento en contenedor de scroll, que es lo que hace `hidden` y
     lo que atrapa el gesto táctil en móvil (🪤 nº 3). El `hidden` queda de
     respaldo para navegadores que no entiendan `clip`. */
.ga-tc-marco {
    border: 1px solid var(--ga-naranja-claro);
    border-radius: 10px;
    overflow: hidden;
    overflow: clip;

    /* ⚠ EL MARCO YA NO LLEVA NINGUNA SOMBRA, NI EN REPOSO NI AL PASAR EL RATÓN, Y
       NO ES UN OLVIDO. La tenía —transparente en reposo y encendida en hover—, y
       se ha quitado a conciencia: ahora quien se levanta del papel es la COLUMNA
       DESTACADA, no la tabla entera. Dos cosas elevándose a la vez se anulaban.

       La sombra vive ahora en las celdas de esa columna; está más abajo, en el
       bloque de la columna destacada. Y en los productos que no destacan ninguna
       —packs, aceitunas, la aceitera— la tabla se ve completamente plana, sin
       sombra por ninguna parte. */

}

/* ═══════════════════════════════════════════════════════════════════════════
   🔴 EL MARCO DE ESCRITORIO YA NO DIBUJA NADA. LEER ESTO ANTES DE TOCARLO.
   ═══════════════════════════════════════════════════════════════════════════
   Hubo una época en que la celda de la esquina tenía que quedar invisible, y para
   conseguirlo el borde bajó del marco a las celdas: el marco es un rectángulo y su
   borde pasa POR ENCIMA y POR LA IZQUIERDA de esa celda por definición, así que
   mientras estuviera ahí, la esquina "vacía" seguía teniendo dos líneas
   dibujándola. El contorno se montó entonces a trozos y salía un escalón.

   🔴 ESO SE HA REVERTIDO. La esquina ya no está vacía: lleva el rótulo "GRAN
   ALMAZARA" y es una cabecera más, así que la tabla vuelve a ser un rectángulo
   completo y el marco vuelve a dibujarlo de una pieza —borde, redondeo de 10px y
   recorte—, igual que en la tabla de móvil. Aquí ya no hay ninguna regla que se lo
   desarme, y por eso la lista de reglas que repartían el contorno celda a celda ha
   desaparecido de este archivo.

   ⚠ LO QUE NO SE PUEDE PERDER DE VISTA AL VOLVER ATRÁS: si además del borde del
     marco se le pone un borde SUPERIOR a las celdas de la cabecera, quedan dos
     rayas de 1px pisándose y se ve el escalón que costó localizar en su día. Por
     eso la franja de la cabecera solo lleva borde ABAJO. Está anotado también en
     su regla.

   ⚠ Y NO LLEVA SOMBRA. La tuvo, con su efecto al pasar el ratón, y se retiró
     entera —incluidos el hover y su regla de movimiento reducido— cuando la
     elevación pasó a la columna destacada. Si algún día se le quiere devolver,
     conviene quitársela antes a la columna: las dos a la vez se anulan. */

.ga-tc {
    width: 100%;
    table-layout: fixed;

    /* 🔴 ESTAS DOS LÍNEAS SON EL ARREGLO DEL BORDE DESCUADRADO Y DE LA ÚLTIMA FILA,
       Y CONVIENE SABER POR QUÉ ESTÁN. El tema padre trae la hoja de tablas clásica
       de WordPress, que le pone a CUALQUIER <table>:

           border-width: 1px 0 0 1px;   → línea SOLO arriba y a la izquierda
           margin: 0 0 1.5em;           → un hueco muerto DEBAJO de la tabla

       Lo primero es exactamente lo que se veía: raya marcada arriba y a la
       izquierda y nada a la derecha ni abajo, con pinta de sombra mal puesta. Lo
       segundo metía 1,5em de aire entre la última fila y el borde del marco, así
       que esa fila parecía más alta y no terminaba a la altura de las demás.

       Las celdas ya neutralizaban su parte (`border: none` más abajo), pero la
       <table> nunca reseteaba la suya. Con esto, el ÚNICO borde de todo el bloque
       es el del marco, idéntico en los cuatro lados, y la última fila termina
       pegada a él como el resto.

       Basta con la clase para ganarle al selector de elemento del padre: no hace
       falta ningún !important. */
    border: 0;
    margin: 0;

    /* ⚠ separate Y NO collapse, Y ESTO HAY QUE SABERLO ANTES DE TOCARLO. Con
       border-collapse: collapse el navegador IGNORA el border-radius de las
       celdas: es parte de cómo funciona el modelo de bordes colapsados, no un
       fallo. Y este diseño necesita esquinas redondeadas en las celdas de las
       esquinas del bloque crema.

       Con separate + border-spacing: 0 el resultado visual es idéntico —las
       celdas siguen pegadas y las rayas no se duplican, porque solo se dibuja el
       borde de ABAJO— y además los radios funcionan. */
    border-collapse: separate;
    border-spacing: 0;

    font-family: var(--ga-font-body);
}

/* Los anchos, fijados por el <colgroup>. El concepto se lleva algo menos de un
   cuarto y el resto va a partes iguales entre las cuatro columnas de datos
   (78 % / 4 = 19,5 %).

   👉 DE DÓNDE SALE EL 22 %. La frase más larga de la columna es "Atención
   directa, sin centralita": unos 210 px con la tipografía del cuerpo a 14 px, más
   los ~18 px de relleno de la celda. A pantalla completa el contenedor mide
   1200 px, así que el 22 % son 264 px y la línea entra entera con un margen
   pequeño y deliberado: el borde de la columna queda justo detrás del texto en
   vez de dejar el hueco vacío que había con el 25 %.

   ⚠ NO BAJAR MÁS. Por debajo del 21 % esa frase parte en dos líneas, que es
     justo lo que se ha venido a quitar. Y lo que le quita el concepto se lo
     quedan las cuatro columnas de datos, que iban apretadas. */
.ga-tc__col-concepto { width: 22%; }
.ga-tc__col-dato     { width: 19.5%; }

/* ——— LAS CELDAS ———
   Relleno compacto e igual en todas, y sin ningún borde lateral: no hay líneas
   verticales en toda la tabla. El relleno vertical baja para que la tabla se
   recorra de un vistazo en vez de obligar a bajar la mirada fila a fila. */
.ga-tc th,
.ga-tc td {
    padding: 0.5rem 0.55rem;
    border: none;
    vertical-align: middle;
    font-size: var(--ga-text-sm);
    font-weight: 400;
    line-height: 1.4;
    color: var(--ga-verde-oliva-oscuro);
    /* Con el ancho ya fijado, esto es lo que parte una palabra larga en vez de
       dejar que se salga de su celda. Sin min-width por ninguna parte. */
    overflow-wrap: break-word;
    word-wrap: break-word;
}

/* ——— TODAS LAS FILAS DEL CUERPO, LA MISMA ALTURA ———
   Antes cada fila medía lo que le pedía su contenido, y eso daba tres alturas
   distintas: "Cosecha" (una línea) era la más baja, "Ideal para" (dos líneas)
   quedaba en medio y las de iconos eran las más altas. Con una altura común, la
   tabla se recorre en horizontal sin que el ojo tenga que recalcular dónde cae
   cada fila.

   👉 DE DÓNDE SALEN LOS 4rem. Es la altura que pide el contenido más alto, que NO
   es el que parece: son las filas de iconos. Su marca mide 3rem —icono de 24px,
   0,25rem de hueco y la etiqueta "No siempre" debajo— y las celdas ponen 0,5rem
   de relleno arriba y otro abajo: 3 + 1 = 4rem. Las dos líneas de "Ideal para"
   ocupan menos (unos 2,45rem con su interlineado) y entran con holgura.

   Así que este número no aprieta nada: es el alto que la fila más alta YA tenía,
   aplicado ahora a todas. Las etiquetas "No siempre" siguen cabiendo dentro sin
   empujar su fila, que es justo lo que se pedía.

   ⚠ ES ALTURA, NUNCA ANCHURA. Aquí no hay ni puede haber min-width: los anchos
     los fija el <colgroup> y `table-layout: fixed` no se toca. En una celda de
     tabla `height` funciona como un mínimo, así que si un día el contenido
     creciera la fila crece en vez de recortarlo: se prefiere una fila desigual a
     un texto cortado.

   El centrado vertical ya lo trae la regla de arriba (vertical-align: middle) y
   es lo que reparte el aire sobrante por igual arriba y abajo.

   Solo el CUERPO: la cabecera tiene su propio relleno, más generoso, para que la
   franja dorada pese. */
.ga-tc.ga-tc--esc tbody th,
.ga-tc.ga-tc--esc tbody td {
    height: 4rem;
}

/* El concepto a la izquierda y centrado en vertical, con el mismo tamaño en todas
   las filas. El PESO sí se sobrescribe, en la regla que va justo debajo de esta:
   los conceptos van en negrita.

   Su ancho y su alineación no los toca nada de aquí: el ancho lo fija el
   <colgroup> y la alineación es este text-align. */
.ga-tc__concepto {
    text-align: left;
    padding-left: 0.6rem;

    /* VERDE MUY CLARO: el verde de marca apenas diluido en blanco, para que la
       columna de rótulos se distinga de la franja dorada de la cabecera y de las
       columnas de datos sin pesar más que ellas.

       Se usa el verde montañas y no el verde oliva oscuro porque a estas
       diluciones el oliva tira a gris y deja de leerse como verde.

       Dos declaraciones, como en el resto del archivo: la primera es el blanco de
       siempre —respaldo para navegadores anteriores a color-mix (2023), que se
       quedan con la columna en blanco y NUNCA sin fondo— y la segunda la tiñe
       donde se pueda. */
    background-color: var(--ga-blanco);
    background-color: color-mix(in srgb, var(--ga-verde-montanas) 9%, var(--ga-blanco));
}

/* Los conceptos, en negrita: son el rótulo de cada fila y ahora mandan sobre los
   valores, que siguen en peso normal.

   ⚠ EL SELECTOR LLEVA th A PROPÓSITO, y no es un capricho de estilo. El peso lo
     fija .ga-tc th, .ga-tc td (font-weight: 400), que puntúa 0-1-1; una regla de
     clase sola (.ga-tc__concepto, 0-1-0) PERDERÍA y el texto seguiría fino. Con el
     elemento delante son 0-2-1 y gana sin necesidad de ningún !important.

   Vale para las dos versiones de la tabla, la de escritorio y la de móvil: las dos
   usan esta misma clase en su columna de conceptos. */
.ga-tc th.ga-tc__concepto {
    font-weight: 700;

    /* 👉 AQUÍ NO SE DECLARA NINGÚN `color`, Y ES INTENCIONADO. Los conceptos van en
       el VERDE OSCURO de marca, que es exactamente lo que ya les da la regla
       general de celdas (.ga-tc th, .ga-tc td). Repetirlo aquí sería tener el
       mismo valor escrito dos veces y arriesgarse a que un día se cambie uno y no
       el otro; dejándolo fuera, el color de toda la tabla se toca en un solo
       sitio.

       Llegó a estar en negro con `var(--ga-negro-suave, #1a1a14)`. Se ha
       revertido, pero conviene recordar por qué llevaba respaldo: esa variable
       está en la paleta de la documentación y NO se declara en el :root de
       style.css, así que sin él la declaración se invalida y el texto acaba
       heredando el color del ancestro (🪤 nº 15). Si algún día vuelve, vuelve con
       su respaldo. */
}

.ga-tc__nuestra,
.ga-tc__otros {
    text-align: center;
}

/* La única línea de la tabla: una raya horizontal bajo cada fila.

   Va en las celdas y no en la <tr> porque con border-collapse: separate una fila
   no pinta bordes.

   👉 SE VE MÁS QUE ANTES, Y EL CAMBIO ES DE CONTRASTE, NO DE GROSOR. Sigue en 1px:
   una raya de 1,5px cae entre píxeles y el navegador la difumina, así que se ve
   más gorda pero más sucia, justo al revés de lo que se busca. Lo que sube es el
   tono, del crema clarísimo (--ga-naranja-claro, que sobre blanco casi no
   existía) al verde oliva de marca diluido al 25 %.

   ⚠ SIGUE SIN HABER NI UNA SOLA LÍNEA VERTICAL, y ahí está la diferencia entre
     una tabla que se lee de un vistazo y una cuadrícula: las rayas guían el ojo a
     lo largo de la fila, no encierran cada dato en su casilla.

   🔴 LA ÚLTIMA FILA NO LLEVA RAYA, Y NO ES UN OLVIDO NI UN TRATO DE FAVOR: abajo
   está el borde del marco, a un píxel de distancia. Con las dos, el canto
   inferior de la tabla se vería el doble de grueso que los tres restantes, que es
   exactamente el defecto que se arregló en su día. La raya separa filas ENTRE SÍ;
   la de abajo del todo no separa nada. El alto, el ancho y el relleno de esa fila
   son idénticos a los de las demás. */
.ga-tc tbody tr:not(:last-child) th,
.ga-tc tbody tr:not(:last-child) td {
    border-bottom: 1px solid var(--ga-amarillo-pastel);
    border-bottom: 1px solid color-mix(in srgb, var(--ga-verde-oliva-oscuro) 25%, var(--ga-blanco));
}

/* ——— LA CABECERA, LO COMÚN A LAS DOS TABLAS ———
   Tamaño, peso, versalitas, relleno de partida y el DORADO INTENSO de los rótulos,
   que es el mismo en las dos: en escritorio sobre la franja de dorado clarísimo y
   en móvil sobre blanco. Este es el único sitio donde se declara ese color, así
   que no hay dos valores que puedan descuadrarse.

   La celda de la esquina no lleva texto, así que se queda fuera de la regla del
   dorado; su fondo se decide más abajo. */
.ga-tc thead th {
    padding-top: 0.7rem;
    padding-bottom: 0.7rem;
    font-size: var(--ga-text-xs);
    font-weight: 700;
    letter-spacing: 0.05em;
    line-height: 1.25;
    text-transform: uppercase;
}

.ga-tc thead .ga-tc__nuestra,
.ga-tc thead .ga-tc__otros {
    color: var(--ga-naranja-apagado);
}

/* ——— LA FRANJA DE LA CABECERA ———
   ═══════════════════════════════════════════════════════════════════════════
   FRANJA CONTINUA EN DORADO MUY CLARO, CON LOS NOMBRES EN DORADO INTENSO.
   ═══════════════════════════════════════════════════════════════════════════
   El fondo va en las CELDAS, no en un recuadro interior: como las <th> están
   pegadas —border-spacing es 0—, sus fondos se tocan y se leen como una única
   banda sin costuras.

   Las esquinas superiores redondeadas no se declaran aquí y no hace falta: las
   recorta el marco, que ya tiene su border-radius de 10px y su overflow.

   👉 EL <span class="ga-tc__rotulo"> DEL MARCADO SE QUEDA SIN ESTILOS, y es
   correcto: sin ninguna regla que lo toque es un <span> pelado, o sea texto
   normal dentro de su celda. No se ve, no ocupa y no estorba. Sigue en el HTML
   porque este cambio es solo de CSS.

   ⚠ SOLO EN LA TABLA DE ESCRITORIO. La de móvil tiene otras cabeceras ("Gran
     Almazara" y "Otras marcas") y se queda exactamente como está hoy. */

/* El alto de la franja, para las CINCO celdas de la fila —incluida la de la
   esquina—, porque si una sola tuviera otro relleno la fila entera se
   descuadraría. El relleno LATERAL no se toca: lo pone la regla general de
   celdas, igual que en todas las filas del cuerpo, y es lo que mantiene la
   cabecera alineada al milímetro con el resto de la tabla. */
.ga-tc.ga-tc--esc thead th {
    padding-top: 1.1rem;
    padding-bottom: 1.1rem;

    /* 🔴 POR LA LÍNEA BASE, NO POR EL CENTRO. Las celdas de la tabla van centradas
       en vertical, y con textos de tamaños distintos —el nombre de la columna
       destacada es mayor que los otros tres— centrar deja cada rótulo a una altura
       distinta: se ven desalineados aunque estén "centrados".

       Alineando por la línea base, los cuatro títulos se apoyan en la MISMA raya
       imaginaria, que es como se lee una fila de encabezados.

       Solo la fila de cabecera: el cuerpo conserva su centrado, que es lo que
       mantiene los tiques a la misma altura fila a fila. */
    vertical-align: baseline;
}

/* ——— LA FRANJA, EN LAS CINCO CELDAS ———
   🔴 AHORA ENTRA TAMBIÉN LA DE LA ESQUINA, y por eso el selector es `th` a secas y
   no una lista de clases de columna. Esa celda ya no está vacía: lleva el rótulo
   "GRAN ALMAZARA" y es un encabezado más, con el mismo fondo y el mismo dorado que
   los otros cuatro. Con las cinco pintadas, la franja vuelve a recorrer la fila de
   lado a lado.

   👉 EL COLOR DEL TEXTO SÍ SE DECLARA AQUÍ, Y HACE FALTA. Los otros cuatro
   rótulos ya salen dorados por `.ga-tc thead .ga-tc__nuestra`, pero la celda de la
   esquina lleva la clase .ga-tc__concepto, y esa tiene su propia regla de color más
   abajo —el verde oscuro de la columna—. Sin este `color`, el rótulo de la esquina
   saldría verde y los otros cuatro dorados.
   Cuenta 0-2-2 y le gana a `.ga-tc th.ga-tc__concepto` (0-2-1) por número de
   elementos, sin ningún !important.

   ⚠ SOLO BORDE ABAJO, NUNCA ARRIBA NI A LOS LADOS. El contorno exterior de la
     tabla lo vuelve a dibujar el marco, de una pieza; si la franja añadiera aquí
     su propio borde superior quedarían DOS rayas de 1px pisándose en el canto de
     arriba, desplazadas una de otra, que es el escalón que ya costó localizar una
     vez. Y un borde lateral por celda dibujaría rayas verticales entre columnas y
     la franja se leería como una cuadrícula.

   Dos declaraciones en el fondo: la primera es un color de la paleta tal cual,
   para navegadores anteriores a color-mix (2023); la segunda afina el tinte donde
   se pueda. Así la franja nunca se queda sin fondo. */
.ga-tc.ga-tc--esc thead th {
    background-color: var(--ga-naranja-claro);
    background-color: color-mix(in srgb, var(--ga-naranja-apagado) 12%, var(--ga-blanco));

    color: var(--ga-naranja-apagado);

    border-bottom: 1px solid var(--ga-naranja-apagado);
}

/* ——— LA CELDA DE "GRAN ALMAZARA": CENTRADA Y CON BRILLO ———
   ═══════════════════════════════════════════════════════════════════════════
   Es la primera celda de la cabecera, la que cruza con la columna de conceptos.
   Lleva el nombre de la marca, así que se le da el trato de las otras cuatro
   —centrada— y un barrido de luz suave que la distinga sin gritar.

   1) CENTRADO. Su clase .ga-tc__concepto la alinea a la izquierda y le da un
      relleno izquierdo mayor, que es lo que necesitan los rótulos de las filas del
      cuerpo. Aquí se revierten las dos cosas: el relleno vuelve a ser el mismo por
      los dos lados —si no, "centrado" quedaría medio milímetro corrido— y el texto
      al centro. El centrado vertical ya lo trae la regla general de celdas
      (vertical-align: middle), así que no hace falta declararlo.

   2) EL BRILLO ES EL MECANISMO QUE YA USA EL PROYECTO, no uno nuevo: un
      linear-gradient con la banda de luz en el medio, el fondo estirado al 250 %
      de ancho y la animación moviendo SOLO background-position. Es exactamente lo
      que hacen el botón de carrito de las tarjetas y los títulos de sección.

      Se reutilizan sus mismos @keyframes ga-home-card-brillo, declarados en
      main.css. Las @keyframes son globales del documento —no pertenecen a la hoja
      donde se escriben—, así que se pueden usar desde aquí; y main.css siempre
      está cargada en la ficha, porque single-product.css depende de ella.

      🔴 EL BRILLO VA EN LAS LETRAS, NO EN EL FONDO, Y ESA ES LA DIFERENCIA CON LA
      PRIMERA VERSIÓN. El degradado se recorta sobre el texto con
      background-clip: text. Por eso NO se declara aquí, en la celda, sino en el
      <span> de dentro: si se pusiera en la <th>, el recorte se llevaría por
      delante también su background-color —el dorado claro de la franja—, y la
      celda se quedaría sin fondo mientras las otras cuatro lo conservan. En el
      span, la celda mantiene su fondo intacto y el degradado solo afecta a las
      letras.

      🔴 SUAVE, Y ESO SE CONSIGUE CON EL RITMO: 14s en lugar de los 6s del título
      de sección. Esos @keyframes barren en la primera mitad y descansan la
      segunda, así que son 7 segundos de recorrido lento y otros 7 de reposo: se
      percibe de refilón y no compite con la tabla.

      ⚠ NADA DE ESTO TOCA LA GEOMETRÍA. Las propiedades de fondo no ocupan sitio ni
        provocan recálculo de maquetación: la celda mide, pesa y se alinea igual
        con brillo que sin él, y la cabecera no se descuadra respecto a las demás
        columnas.

   3) ALCANCE. No hace falta ninguna comprobación de eventos aquí: esta tabla NO SE
      PINTA en las fichas de eventos —la plantilla la envuelve en su
      `if ( ! $ga_es_eventos )`, que se calcula con function_exists() y
      ga_eventos_es_personalizable()—, y además el selector exige .ga-tc--esc, que
      solo existe dentro de ese bloque. La ficha de eventos no llega a tener esta
      celda.
   ═══════════════════════════════════════════════════════════════════════════ */
.ga-tc.ga-tc--esc thead .ga-tc__concepto {
    text-align: center;
    padding-left: 0.55rem;
}

/* El rótulo, en bloque en línea: le da al degradado una caja propia y previsible
   sobre la que calcular el 250 % de ancho. No cambia nada de la maquetación —sigue
   centrado por el text-align de su celda— pero evita que el fondo se reparta de
   forma imprevisible si el texto llegara a partirse en dos líneas. */
.ga-tc.ga-tc--esc thead .ga-tc__concepto .ga-tc__rotulo {
    display: inline-block;
}

/* 🔴 EL RECORTE, SOLO DONDE FUNCIONA. Fuera de este @supports no se declara NADA
   de color: el rótulo se queda con el dorado de marca que hereda de la regla de la
   franja. Ese es el respaldo, y es automático: un navegador que no entienda
   background-clip: text simplemente no entra aquí y ve el texto dorado de siempre.
   NUNCA transparente ni invisible.

   Es el mismo idioma que ya usa el título de sección de la tienda en main.css: los
   mismos porcentajes del degradado, el mismo 250 % de ancho, el mismo no-repeat y
   la misma posición de partida. Solo cambia el ritmo.

   El rango 100 % → 0 % de los @keyframes mantiene el degradado cubriendo siempre
   las letras —el fondo no se repite—, así que el texto no puede quedarse sin
   pintar en ningún fotograma.

   El #F5EEDD de la banda es el dorado muy suave documentado en el claude.md, y es
   EXACTAMENTE el que usa el brillo del título de sección: se repite a propósito,
   para que los dos destellos del sitio sean el mismo y no dos parecidos. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {

    .ga-tc.ga-tc--esc thead .ga-tc__concepto .ga-tc__rotulo {
        background-image: linear-gradient(
            100deg,
            var(--ga-naranja-apagado) 0%,
            var(--ga-naranja-apagado) 45%,
            #F5EEDD                   50%,
            var(--ga-naranja-apagado) 55%,
            var(--ga-naranja-apagado) 100%
        );
        background-size: 250% 100%;
        background-repeat: no-repeat;
        background-position: 100% center;

        -webkit-background-clip: text;
        background-clip: text;
        -webkit-text-fill-color: transparent;
        color: transparent;

        animation: ga-home-card-brillo 14s linear infinite;
    }
}

/* Sin animación para quien la haya desactivado en su sistema, y con el dorado
   MACIZO: se deshace el recorte en vez de dejar el degradado congelado, para que
   no quepa ninguna duda de que el texto se ve y se ve en su color de marca.

   Va DESPUÉS del @supports y con el mismo selector: mismo peso, gana el último. */
@media (prefers-reduced-motion: reduce) {

    .ga-tc.ga-tc--esc thead .ga-tc__concepto .ga-tc__rotulo {
        background-image: none;
        animation: none;
        -webkit-text-fill-color: currentColor;
        color: var(--ga-naranja-apagado);
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   LA COLUMNA DEL FORMATO QUE SE ESTÁ VIENDO
   ═══════════════════════════════════════════════════════════════════════════
   En la ficha de la garrafa de 2 L se resalta la columna de 2 L, y así con las
   tres. Quién la lleva lo decide la plantilla —añade .ga-tc__destacada a las
   celdas de esa columna, de arriba abajo— y aquí solo se pinta.

   ⚠ SOLO EN ESCRITORIO, Y NO HACE FALTA NINGÚN @media PARA ESO. Por debajo de
     860px esta tabla entera se oculta y sale la de móvil, que tiene otras dos
     columnas —"Gran Almazara" y "Otras marcas"— y ninguna de formato. O sea que en
     móvil no hay nada que destacar: el problema del saliente en pantallas
     estrechas no llega a existir.

   No se toca ni un texto: solo color y fondo.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════════
   LA TARJETA: UN SOLO ELEMENTO PARA TODA LA COLUMNA
   ═══════════════════════════════════════════════════════════════════════════
   🔴 EL FONDO Y LA SOMBRA YA NO VAN CELDA A CELDA, Y ESE ERA EL PROBLEMA DE RAÍZ.
   Cada celda proyectaba su propia sombra, así que en las juntas entre filas
   quedaban huecos y el conjunto se veía a trozos. Se arreglaba a base de capas
   laterales sin desplazamiento vertical, que es un apaño: por muy bien calculado
   que esté, siguen siendo doce sombras intentando parecer una.

   Ahora hay UN elemento —el div .ga-tc-columna— que cubre la columna entera, de la
   punta del saliente de arriba a la del de abajo. Lleva él el verde, el redondeo y
   la sombra. Una sola caja no tiene juntas: la sombra es continua por
   construcción, sin trucos.

   ——— CÓMO SABE DÓNDE VA ———
   El marco es su referencia (position: relative, más abajo) y los porcentajes de
   un elemento absoluto se miden sobre la caja de relleno de ese marco, que es
   exactamente la que ocupa la tabla. O sea que un 19,5 % aquí y un 19,5 % del
   <colgroup> son el mismo ancho, siempre, sin que haya que medir nada por JS.

   La cuenta: la columna de conceptos se lleva el 22 % y cada columna de datos el
   19,5 %, así que la destacada empieza en 22 % + su índice × 19,5 %. El índice lo
   pone la plantilla en --ga-tc-col, y es el MISMO número con el que decide qué
   celdas llevan la clase: no pueden descuadrarse.

   ⚠ SI ALGÚN DÍA CAMBIAN LOS ANCHOS DEL <colgroup>, HAY QUE CAMBIARLOS AQUÍ. Son
     los dos únicos sitios donde vive ese reparto.
   ═══════════════════════════════════════════════════════════════════════════ */
.ga-tc-marco--con-destacada {
    /* Referencia de la tarjeta. No cambia nada de la maquetación. */
    position: relative;
}

.ga-tc-columna {
    position: absolute;

    /* Arriba llega hasta el techo del saliente, que es la franja de la frase;
       abajo, hasta la punta del saliente inferior. */
    top: calc(-1 * var(--ga-tc-saliente-arriba));
    bottom: calc(-1 * var(--ga-tc-saliente-abajo));

    left: calc(22% + var(--ga-tc-col) * 19.5%);
    width: 19.5%;

    background-color: var(--ga-verde-oliva-oscuro);
    border-radius: 10px;

    /* 🔴 DETRÁS DEL TEXTO Y SIN RECIBIR CLICS. Va primero en el marcado y sin
       z-index propio, así que las celdas —que sí están posicionadas— se pintan por
       encima y su texto y sus tiques se leen sin estorbo. El pointer-events lo
       saca además del alcance del ratón: no puede robar un clic ni tapar la
       selección de un texto. */
    pointer-events: none;

    /* En reposo, sin sombra. La misma estructura que en el hover para que la
       transición tenga desde dónde interpolar: `none` no vale. */
    box-shadow:
        0 6px 28px -4px rgba(74, 74, 47, 0),
        0 0 12px  -2px rgba(74, 74, 47, 0);

    transition: box-shadow 240ms ease;
}

/* Los dos altos de los salientes, en un solo sitio: los usan la tarjeta y la
   franja de la frase, y tienen que valer lo mismo o quedaría un escalón.

   👉 EL DE ARRIBA ES FIJO Y ESO ESTÁ MEDIDO. La frase ocupa una línea de 0,75rem
   (unos 16px) y, a 861px —el ancho más justo en el que esta tabla se sigue
   mostrando—, la columna da unos 166px y la frase pide unos 146: entra en una
   línea. Aun partiéndose en dos ocuparía unos 31px, que siguen cabiendo en los
   48px de la franja. */
.ga-tc-marco--con-destacada {
    /* El de abajo es la MEDIDA BUENA y manda: es la referencia de la tarjeta. */
    --ga-tc-saliente-abajo: 14px;

    /* 🔴 EL DE ARRIBA NO LLEVA NÚMERO PROPIO: APUNTA AL DE ABAJO. Llegó a valer
       3rem para alojar la frase, y eso dejaba la columna sobresaliendo más de tres
       veces por arriba que por abajo: la tarjeta se veía descompensada. Ahora la
       frase se ajusta al saliente y no al revés (ver su regla, más abajo).

       Escrito así, los dos NO PUEDEN desajustarse nunca: no hay dos números que
       alguien tenga que acordarse de cambiar a la vez. Si mañana se retoca el
       saliente, se retoca una línea y los dos lados la siguen.

       ⚠ Y de paso se ajusta sola la separación con el título: la regla que baja el
         marco usa esta misma variable, así que el hueco bajo el título sigue
         midiendo lo mismo sin tocar nada. */
    --ga-tc-saliente-arriba: var(--ga-tc-saliente-abajo);
}

/* Las celdas de la columna: ya SIN fondo ni sombra propios. Solo el color del
   texto, y el position: relative que las levanta por encima de la tarjeta. */
.ga-tc.ga-tc--esc thead th.ga-tc__destacada,
.ga-tc.ga-tc--esc tbody td.ga-tc__destacada {
    background-color: transparent;
    color: var(--ga-blanco);
    /* Sin esto el texto quedaría DEBAJO del verde: la tarjeta está posicionada y
       las celdas normales se pintan en la capa de fondos, por detrás. No cambia
       nada de la maquetación: una celda en position: relative sigue ocupando
       exactamente lo mismo. */
    position: relative;

    /* ——— SIN RAYAS QUE CORTEN EL VERDE ———
       Dos reglas dibujaban una línea horizontal a través de esta columna: la que
       separa las filas del cuerpo (border-bottom en verde oliva diluido) y la que
       cierra la franja de la cabecera (border-bottom dorado). Las dos partían el
       fondo verde en trozos.

       🔴 SE APAGA EL COLOR, NO SE QUITA EL BORDE, Y ESA ES LA CLAVE DEL PUNTO 4.
       Con `border-bottom: 0` la celda perdería 1px de alto y su contenido —centrado
       en vertical— se movería medio píxel respecto al de las columnas vecinas, que
       sí conservan su borde. Dejando el borde puesto y solo transparente, la caja
       mide EXACTAMENTE lo mismo que antes: no se mueve nada.

       Y se ve verde continuo porque el fondo de una celda se pinta por debajo de
       su borde (background-clip vale border-box por defecto): donde el borde no
       pinta, asoma el verde.

       ⚠ SOLO EN ESTA COLUMNA. Las rayas de las demás y las de la columna de
         etiquetas de la izquierda no se tocan: sus celdas no llevan esta clase. */
    border-bottom-color: transparent;

    /* ⚠ AQUÍ YA NO HAY NINGUNA SOMBRA, Y NO ES UN OLVIDO. Las celdas llevaban
       cuatro capas laterales cada una para simular una sombra continua sin que se
       vieran las juntas entre filas. Todo eso sobra desde que la sombra la lleva
       .ga-tc-columna, que es UNA sola caja: no tiene juntas que disimular. */
}

/* ——— EL NOMBRE DEL FORMATO, EN DORADO ———
   Solo el rótulo. El aviso de debajo y todos los textos y tiques del cuerpo de la
   columna siguen en blanco: la regla de arriba les da el color y esta solo pisa el
   de este <span>.

   ⚠ CONTRASTE MEDIDO: el dorado de marca sobre el verde oliva oscuro da 4,0:1.
     Pasa el mínimo para texto grande, pero se queda algo por debajo del 4,5:1 que
     se le pide a un texto de este tamaño. Está anotado a propósito: si algún día
     se quiere ir sobre seguro, el blanco sobre ese mismo verde da 8,8:1. */
.ga-tc.ga-tc--esc thead th.ga-tc__destacada .ga-tc__rotulo {
    /* Bloque en línea: le da al degradado del brillo una caja propia y previsible
       sobre la que calcular su ancho. No cambia la maquetación —sigue centrado por
       el text-align de su celda— y el aviso de debajo ya es un bloque, así que
       cae a su línea igual. */
    display: inline-block;

    /* Bastante mayor que el resto de cabeceras (0,75rem): es el nombre del formato
       que el cliente está viendo y tiene que ganarles de un vistazo. A 861px —el
       ancho más justo en el que esta tabla se sigue mostrando— la columna da unos
       166px de texto y "GARRAFA 2 L" pide unos 121: entra sin partirse. */
    font-size: 1rem;
    line-height: 1.2;

    /* El dorado macizo. Es también el RESPALDO del brillo: si el navegador no sabe
       recortar un degradado sobre el texto, no entra en el @supports de más abajo
       y el nombre se queda exactamente así. Nunca transparente. */
    color: var(--ga-naranja-apagado);
}

/* ——— EL BRILLO DEL NOMBRE ———
   El mismo mecanismo que lleva "GRAN ALMAZARA" y que los títulos de sección de la
   tienda: un degradado con la banda de luz en el medio, el fondo estirado al 250 %
   y la animación moviendo SOLO background-position. Se reutilizan sus mismos
   @keyframes, declarados en main.css —las @keyframes son globales del documento,
   no de la hoja donde se escriben—.

   🔴 TODO EN DORADOS, y esa es la diferencia con el de la esquina. Aquí el texto
   va sobre verde oscuro, así que la base es el dorado de marca y el destello un
   dorado más claro: el nombre se sigue leyendo dorado en todo momento y el
   contraste sube al pasar la banda, nunca baja.

   Suave: 14s, y esos @keyframes barren en la primera mitad y descansan la
   segunda, o sea 7 segundos de recorrido lento y otros 7 de reposo.

   El rango 100 % → 0 % mantiene el degradado cubriendo siempre las letras —el
   fondo no se repite—, así que el texto no puede quedarse sin pintar en ningún
   fotograma. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {

    .ga-tc.ga-tc--esc thead th.ga-tc__destacada .ga-tc__rotulo {
        background-image: linear-gradient(
            100deg,
            var(--ga-naranja-apagado) 0%,
            var(--ga-naranja-apagado) 45%,
            #F5EEDD                   50%,
            var(--ga-naranja-apagado) 55%,
            var(--ga-naranja-apagado) 100%
        );
        background-size: 250% 100%;
        background-repeat: no-repeat;
        background-position: 100% center;

        -webkit-background-clip: text;
        background-clip: text;
        -webkit-text-fill-color: transparent;
        color: transparent;

        animation: ga-home-card-brillo 14s linear infinite;
    }
}

/* Sin animación para quien la haya desactivado, y con el dorado MACIZO: se deshace
   el recorte en vez de dejar el degradado congelado, para que no quepa duda de que
   el nombre se ve y se ve en su color. Va DESPUÉS del @supports y con el mismo
   selector: mismo peso, gana el último. */
@media (prefers-reduced-motion: reduce) {

    .ga-tc.ga-tc--esc thead th.ga-tc__destacada .ga-tc__rotulo {
        background-image: none;
        animation: none;
        -webkit-text-fill-color: currentColor;
        color: var(--ga-naranja-apagado);
    }
}

/* 🔴 EL TIQUE, INVERTIDO. Su círculo es verde oliva sobre fondo blanco en el resto
   de la tabla; sobre esta columna, ese verde sobre verde DESAPARECERÍA. Se le da
   la vuelta: círculo blanco con el trazo en verde. Es la combinación de más
   contraste posible —8,8:1— y, sobre todo, conserva la geometría intacta: el
   mismo círculo de 24px en el mismo sitio, así que los tiques de esta columna
   siguen alineados al píxel con los de las demás. */
.ga-tc.ga-tc--esc tbody td.ga-tc__destacada .ga-compara__icono--si {
    background-color: var(--ga-blanco);
    color: var(--ga-verde-oliva-oscuro);
}

/* ⚠ EL SALIENTE INFERIOR YA NO ES UN PSEUDOELEMENTO. Lo era —un ::after de 16px
   colgando de la última celda—, y se ha quitado porque .ga-tc-columna ya llega
   hasta ahí: su `bottom` negativo cubre ese trozo con el mismo verde y el mismo
   redondeo, y de una pieza con el resto. Tener los dos habría dado dos cajas
   superpuestas y una junta visible justo donde antes estaba el problema. */

/* ——— LA SOMBRA APARECE AL PASAR EL RATÓN POR LA COLUMNA ———
   🔴 SOLO POR LA COLUMNA DESTACADA, no por el resto de la tabla. Y hay un problema
   que resolver para conseguirlo: quien tiene que dibujar la sombra es
   .ga-tc-columna, pero el ratón nunca pasa por encima de ella —lleva
   pointer-events: none y además está DETRÁS de las celdas—. Hace falta detectar el
   hover en un sitio y pintarlo en otro.

   Eso es exactamente lo que resuelve :has(): se le pregunta al MARCO si contiene
   alguna celda destacada con el ratón encima, y en ese caso se enciende la sombra
   de la tarjeta, que es hermana suya. Sin JavaScript y sin tocar el marcado.

   ⚠ SI EL NAVEGADOR NO ENTIENDE :has(), LA REGLA SE IGNORA Y NO PASA NADA MALO: la
     columna se ve igual —verde, con su saliente y su texto—, simplemente sin la
     sombra al pasar el ratón. Se pierde el adorno, nunca la información.

   ⚠ Va dentro de @media (hover: hover) A PROPÓSITO. En una pantalla táctil un
     :hover sin guardia se queda PEGADO después de tocar: la sombra aparecería al
     primer toque y ya no se iría. Con la guardia, el efecto solo existe donde hay
     un ratón de verdad. (En móvil, además, esta tabla ni se pinta.)

   Una sola caja, una sola sombra: dos capas, una amplia que da el volumen y otra
   corta y ceñida que perfila el canto. Rodea la tarjeta por los cuatro lados sin
   un solo corte, porque no hay nada que cortar. */
@media (hover: hover) {

    .ga-tc-marco--con-destacada:has(.ga-tc__destacada:hover) .ga-tc-columna {
        box-shadow:
            0 6px 28px -4px rgba(74, 74, 47, 0.40),
            0 0 12px  -2px rgba(74, 74, 47, 0.28);
    }
}

/* Quien haya pedido menos animación en su sistema ve el mismo cambio de sombra,
   pero instantáneo: se le quita la transición, nunca el efecto. */
@media (prefers-reduced-motion: reduce) {

    .ga-tc-columna {
        transition: none;
    }
}

/* 🔴 Y ESTO ES LO QUE DEJA SALIR AL SALIENTE. El marco recorta a sus cuatro lados
   —lo necesita para que los fondos de las celdas respeten sus esquinas
   redondeadas—, así que sin esto los dos pseudoelementos se cortarían justo en el
   borde y no se vería nada.

   overflow-clip-margin le dice al recorte cuántos píxeles más debe dejar pasar.
   Tiene que cubrir el saliente Y su sombra, que se difumina bastante más allá.
   Es la propiedad hecha para esto, y no obliga a renunciar al recorte ni a
   rehacer las esquinas.

   ⚠ DEGRADA SOLA Y SIN ROMPER NADA: un navegador que no la entienda recorta como
     siempre y la columna se ve verde, con su texto blanco y sus tiques
     invertidos, pero a ras de la tabla. Se pierde el saliente y nada más. */
.ga-tc-marco--esc {
    /* 🔴 EL NÚMERO TIENE QUE CUBRIR EL SALIENTE Y SU SOMBRA. Con 24px la sombra se
       cortaba en seco justo en la parte que se ve por fuera de la tabla, y ese fue
       uno de los motivos de que no se apreciara.

       Hoy los salientes miden 14px cada uno y la sombra se difumina hasta unos
       26px más allá: unos 40 en total. Se deja en 80 a propósito, con margen de
       sobra, porque no cuesta nada y evita que el efecto se recorte si mañana se
       agranda el saliente o se sube la sombra.

       Solo permite PINTAR más allá del recorte: no ensancha la caja, no ocupa
       sitio y no puede provocar desbordamiento de la página. */
    overflow-clip-margin: 80px;
}

/* ——— LA COLUMNA DE CONCEPTOS, POR LOS COSTADOS ———
   Solo el borde DERECHO, y en el tono neutro de las rayas de la tabla.

   El izquierdo no se declara porque ya está: es el borde del marco, que vuelve a
   rodear la tabla entera y es de ese mismo tono claro. Ponerle además uno propio
   a la celda dejaría dos rayas juntas en el canto izquierdo.

   ⚠ ESTA ES LA ÚNICA LÍNEA VERTICAL DE TODA LA TABLA, y es deliberada: separa la
     columna de rótulos de los datos. Entre las cuatro columnas de datos no hay
     ninguna, que es lo que evita que esto se lea como una cuadrícula. */
.ga-tc.ga-tc--esc tbody .ga-tc__concepto {
    border-right: 1px solid var(--ga-amarillo-pastel);
    border-right: 1px solid color-mix(in srgb, var(--ga-verde-oliva-oscuro) 25%, var(--ga-blanco));
}

/* ——— EL DESTACADO DE LAS TRES COLUMNAS PROPIAS ———
   🔴 EL FONDO VA EN LAS CELDAS, NO EN UNA CAJA APARTE, y ese es el arreglo. Antes
   era un div absoluto colocado sobre la rejilla: al no estar atado a ninguna
   columna, cualquier cambio de anchos lo dejaba flotando en el sitio equivocado.
   Como fondo de las propias celdas, el crema sigue SIEMPRE a su columna, mida lo
   que mida. */
.ga-tc__nuestra {
    background-color: var(--ga-blanco);
}

/* Se redondean las esquinas de abajo del bloque de las tres columnas propias. Las
   celdas de en medio siguen rectas, así que se leen como una sola pieza continua.

   🔴 ARRIBA YA NO SE REDONDEA NADA, Y ES OBLIGATORIO QUE ASÍ SEA. Había dos
   reglas que redondeaban la esquina de la primera y la tercera columna DENTRO de
   la fila de cabecera. Con la cabecera en blanco no se notaban; ahora que es una
   franja dorada continua, ese radio le abriría dos muescas a media franja, en
   mitad de la tabla. Las esquinas de arriba las recorta el marco, que para eso
   tiene su radio y su overflow, y las recorta donde toca: en los extremos de la
   tabla, no en el borde de una columna cualquiera. */
.ga-tc tbody tr:last-child .ga-tc__nuestra--ini { border-bottom-left-radius: 10px; }
.ga-tc tbody tr:last-child .ga-tc__nuestra--fin { border-bottom-right-radius: 10px; }

/* ——— LA MARCA DENTRO DE SU CELDA ———
   Una columna para poder poner la nota debajo del icono sin sacarla de la celda.

   🔴 EL min-height ES LO QUE IGUALA LAS OCHO FILAS DE GARANTÍAS. Seis de ellas
   llevan una nota bajo el icono ("No siempre", "Variable") y dos no: sin reservar
   ese hueco, esas dos filas serían más bajas y los ticks de la columna dejarían
   de estar alineados en vertical, que es justo lo que hace legible una tabla de
   marcas. Reservando la altura de icono + nota en TODAS, la nota aparece y
   desaparece sin mover nada.

   Es min-height y no height, así que si algún día una nota ocupa dos líneas la
   celda crece en vez de recortarla. (El claude.md prohíbe min-width, no
   min-height: aquí no hay ningún ancho que forzar.) */
.ga-tc__marca {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.25rem;
    min-height: 3rem;
}

/* ——— LOS ICONOS ———
   El círculo es el <span> y el trazo va dentro en SVG, del mismo estilo de línea
   que los sellos de confianza. Tamaño fijo y flex: 0 0 auto para que no se
   deforme cuando la nota de debajo ocupa dos líneas. */
.ga-compara__icono {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 24px;
    height: 24px;
    border-radius: 50%;
}

/* El sí: círculo verde relleno con el tick en blanco. */
.ga-compara__icono--si {
    background-color: var(--ga-verde-oliva-oscuro);
    color: var(--ga-blanco);
}

/* El no: círculo oscuro con la equis. El casi negro de marca para separarse del
   verde del sí y que no se confundan de un vistazo.

   ⚠ El respaldo de --ga-negro-suave es obligatorio: esa variable está en la
     paleta pero no llega a declararse en el :root de style.css, y un var() que no
     resuelve descarta la declaración entera. */
.ga-compara__icono--no {
    background-color: var(--ga-negro-suave, #1a1a14);
    color: var(--ga-blanco);
}

/* El "a medias" ("No siempre", "Variable"): ni sí ni no, y por eso va en GRIS
   NEUTRO. Antes usaba --ga-amarillo-pastel, que es un pastel verdoso: junto al
   círculo verde del sí se leía como un sí flojo en vez de como un matiz.

   El gris no se inventa: sale del casi negro de marca diluido en blanco, que es la
   misma manera de trabajar que las sombras del sitio. El respaldo de
   --ga-negro-suave es obligatorio —está en la paleta pero no llega a declararse en
   el :root de style.css, y un var() que no resuelve descarta la declaración
   entera—, y la primera declaración de cada par cubre además a los navegadores sin
   color-mix. */
.ga-compara__icono--parcial {
    background-color: rgba(26, 26, 20, 0.14);
    background-color: color-mix(in srgb, var(--ga-negro-suave, #1a1a14) 14%, var(--ga-blanco));

    color: rgba(26, 26, 20, 0.55);
    color: color-mix(in srgb, var(--ga-negro-suave, #1a1a14) 55%, var(--ga-blanco));
}

/* La aclaración de "no siempre" o "variable": pequeña y en el MISMO gris que su
   icono, para que las dos piezas se lean como una sola cosa.

   ⚠ El color va explícito y ya NO hay opacity. Con la opacidad encima del color
     gris el texto se quedaba lavado y desigual según el fondo de la celda; el tono
     se fija de una vez y no depende de por dónde caiga. */
.ga-compara__nota {
    font-size: var(--ga-text-xs);
    line-height: 1.3;

    color: rgba(26, 26, 20, 0.55);
    color: color-mix(in srgb, var(--ga-negro-suave, #1a1a14) 55%, var(--ga-blanco));

    /* Centrada bajo su icono. El align-items del contenedor ya la centra como
       caja; esto centra además el texto si llegara a partirse en dos líneas. */
    text-align: center;
}

/* Texto solo para lectores de pantalla: fuera de la vista pero en el árbol de
   accesibilidad. Aquí lo usan los ticks —un icono decorativo no dice "sí" ni
   "no" en voz alta— y la celda vacía de la esquina de la cabecera. Misma técnica
   de 1px recortado que los radios de la ficha: nada de display:none, que lo
   sacaría también del lector. */
.ga-compara__oculto {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    padding: 0;
    border: 0;
    overflow: hidden;
    white-space: nowrap;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
}


/* ——— LAS TARJETAS DE FORMATO (solo móvil) ——— */
.ga-compara-mov__tarjetas {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--ga-space-sm);
    margin-bottom: var(--ga-space-md);
}

.ga-compara-mov__tarjeta {
    box-sizing: border-box;
    padding: 1rem 1.15rem;
    background-color: var(--ga-naranja-claro);
    border-radius: 10px;
}

.ga-compara-mov__nombre {
    margin: 0 0 0.6rem;
    font-family: var(--ga-font-display);
    font-size: 1.15rem;
    font-weight: 700;
    line-height: 1.2;
    color: var(--ga-verde-oliva-oscuro);
}

.ga-compara-mov__dato {
    margin: 0 0 0.45rem;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    line-height: 1.45;
    color: var(--ga-verde-oliva-oscuro);
    overflow-wrap: break-word;
}

.ga-compara-mov__dato:last-child {
    margin-bottom: 0;
}

/* La etiqueta del dato ("Formato", "Cosecha"…), en su propia línea y en
   versalitas pequeñas: separa el rótulo del valor sin gastar una columna. */
.ga-compara-mov__etiqueta {
    display: block;
    font-size: var(--ga-text-xs);
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    opacity: 0.65;
}


/* ——— QUÉ SE VE EN CADA ANCHO ———
   🔴 CON display:none, NO CON visibility NI CON opacity: la versión que no toca
   tiene que desaparecer también del árbol de accesibilidad, o un lector de
   pantalla leería la comparativa DOS VECES seguidas. */
.ga-compara-mov {
    display: none;
}

@media (max-width: 860px) {

    /* Se esconde el MARCO y no solo la tabla: si se ocultara únicamente la tabla,
       quedaría un rectángulo con borde y sin nada dentro. */
    .ga-tc-marco--esc {
        display: none;
    }

    .ga-compara-mov {
        display: block;
    }

    /* Con tres columnas el concepto se lleva la mitad y las dos de marcas se
       reparten el resto. */
    .ga-tc--mov .ga-tc__col-concepto { width: 50%; }
    .ga-tc--mov .ga-tc__col-dato     { width: 25%; }

    /* A 360px el concepto se queda en unos 160px: la letra baja un punto para que
       quepan dos o tres palabras por línea en vez de una. */
    .ga-tc--mov th,
    .ga-tc--mov td {
        padding-inline: 0.3rem;
        font-size: var(--ga-text-xs);
    }

    /* Se le deja algo de relleno a la izquierda aunque el resto de la celda se
       apriete: esta columna lleva fondo dorado y con el texto pegado al canto se
       vería el tinte cortando la primera letra. */
    .ga-tc--mov .ga-tc__concepto {
        padding-left: 0.45rem;
    }

    /* Sin espaciado extra en las versalitas: "Gran Almazara" tiene que partir en
       dos líneas dentro de su columna sin desbordarla. */
    .ga-tc--mov thead th {
        letter-spacing: 0.02em;
    }

    .ga-compara__nota {
        font-size: 0.65rem;
    }
}


/* ─── Beneficios ─────────────────────────────────── */

.ga-product__beneficios {
    padding-top: var(--ga-space-lg);
    /* ⚠ LOS DOS BAJAN A LA VEZ, DE 6rem A 4rem, Y ESO ES LO IMPORTANTE. Sobraba
       fondo vacío por encima del titular; recortando solo el de arriba la franja
       se habría quedado coja, con menos aire arriba que abajo. Como el titular y
       los textos son contenido —van DENTRO del relleno—, la simetría de la franja
       depende de que estos dos números sigan siendo iguales. Si algún día se
       cambia uno, hay que cambiar el otro.

       El equivalente para móvil está en el @media de 860px, unas líneas más
       abajo, y también lleva los dos iguales. */
    padding-bottom: var(--ga-space-lg);
    background: var(--ga-naranja-claro);
}

.ga-beneficios__heading {
    font-family: var(--ga-font-display);
    font-size: clamp(1.4rem, 2.5vw, 2rem);
    font-weight: 600;
    color: var(--ga-verde-oliva-oscuro);
    text-align: center;
    margin: 0 0 var(--ga-space-lg);
    line-height: 1.25;
}

/* =============================================================================
   COSECHA TEMPRANA — TRES FOTOS EN FILA
   =============================================================================
   Sustituye a los cuatro recuadros de beneficios con icono. Conserva la sección
   que los envolvía (.ga-product__beneficios) y su titular
   (.ga-beneficios__heading): solo cambia lo de dentro, así que el sitio en la
   ficha, el fondo crema y el aire de la sección siguen siendo los de siempre.

   ⚠ LAS REGLAS DE .ga-beneficios__grid Y .ga-beneficio* DE AQUÍ ABAJO SE QUEDAN
     SIN USAR: eran las de los recuadros viejos. No se borran en este cambio para
     no mezclar dos cosas en el mismo encargo, pero son deuda: si dentro de un
     tiempo nadie ha recuperado aquel diseño, lo suyo es quitarlas.
   ============================================================================= */

/* ——— EL TITULAR DE LA SECCIÓN ———
   Todo lo tipográfico —la serif, el tamaño con clamp y el verde oliva— lo trae
   ya .ga-section__titulo, la clase compartida de la ficha. Aquí solo se añade lo
   que esta sección necesita de más: centrarlo y separarlo de las fotos.

   .ga-section__titulo trae un margen inferior de 0,75rem, pensado para cuando
   lleva un subtítulo debajo. Aquí no lo hay y las fotos quedarían pegadas, así
   que se sube al aire de sección.

   ⚠ SIN LÍNEA DECORATIVA, ni encima ni debajo: no se declara ningún borde, y la
     clase compartida tampoco trae ninguno.

   El text-wrap: balance de la regla general de títulos se deja tal cual, y aquí
   SÍ juega a favor: es un titular corto y centrado, que es justo el caso para el
   que se puso —reparte las palabras en líneas de largo parecido en vez de dejar
   una sola palabra suelta en la segunda (🪤 nº 16)—. */
.ga-product-single .ga-cosecha__titular {
    text-align: center;
    margin: 0 0 var(--ga-space-lg);

    /* Sube por encima del tamaño que trae .ga-section__titulo (1,6–2,4rem) para
       que siga mandando sobre los títulos de cada foto, que también han crecido.
       La jerarquía es lo que hay que conservar, no el número: con los títulos de
       bloque en 1,3–1,55rem, este se va a 1,9–2,8rem y la distancia entre los dos
       se mantiene.

       Sigue en clamp, así que en móvil no se dispara: el mínimo manda a 360px. */
    font-size: clamp(1.9rem, 3.4vw, 2.8rem);
}

.ga-cosecha__grid {
    display: grid;
    /* Una sola columna de partida; las tres en fila las pone el @media de abajo.
       minmax(0, 1fr) desde el principio: sin ese 0 de mínimo, una foto que no
       quisiera encoger ensancharía su columna y sacaría la fila fuera de la
       página. Es la vía del proyecto para cortar el ancho mínimo sin min-width. */
    grid-template-columns: minmax(0, 1fr);
    gap: var(--ga-space-md);
}

/* Tres columnas iguales a partir de tablet grande. Por debajo van apiladas y en
   el mismo orden del marcado, sin reordenar nada.

   🔴 EL HUECO ENTRE COLUMNAS BAJA A 1rem, Y ESO ES LO QUE AGRANDA LAS FOTOS. El
   ancho de la sección no cambia —lo fija .ga-container— así que todo lo que se le
   quita al hueco se lo reparten las tres columnas. Con los 2rem de antes se iban
   4rem enteros en separación; con 1rem son 2rem, y cada foto gana unos 0,66rem de
   ancho y, al ser cuadradas, otro tanto de alto. */
@media (min-width: 861px) {

    .ga-cosecha__grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        /* ⚠ EL HUECO SE VUELVE A DOBLAR: de 2rem a 4rem. Y esto tiene un precio
           que conviene tener presente, porque el ancho de la sección es fijo: los
           dos huecos suman ahora 8rem en vez de 4rem, y esos 4rem de más salen de
           las fotos. En una pantalla ancha cada una pierde algo más de 20px de
           lado. Es la contrapartida de verlas separadas y no como un bloque
           continuo. */
        column-gap: var(--ga-space-lg);
    }

    /* ——— MENOS MARGEN A LOS LADOS PARA GANAR ANCHO DE FOTO ———
       🔴 ESTE ES EL ÚNICO SITIO DEL QUE SE PUEDE SACAR ANCHO SIN TOCAR NADA MÁS.
       El aire lateral de la sección lo pone el padding de .ga-container, que
       reparte de 1rem a 2,5rem según la pantalla. Recortándolo a la mitad, esos
       centímetros se los reparten las tres columnas.

       ⚠ Y ES POCO, CONVIENE SABERLO: lo que de verdad limita el ancho es el
         max-width de 1280px del contenedor, que no se toca porque es el mismo de
         toda la ficha —si se subiera, esta sección sobresaldría por los lados
         respecto a la foto del producto y al acordeón, y se vería descuadrada—.
         En una pantalla ancha el recorte del padding devuelve unos 40px que se
         reparten entre tres, así que las fotos crecen poco; el cambio que sí se
         nota es el hueco. En pantallas medianas, donde el padding es proporcional
         al ancho, se gana bastante más.

       ⚠ SOLO DE 861px PARA ARRIBA. En móvil ese padding es el único margen que
         separa la foto del borde de la pantalla, y recortarlo dejaría la imagen
         pegada al canto.

       El padding de ARRIBA y ABAJO de la sección no se toca: aquí solo se cambia
       el lateral, que es otra propiedad y otra regla. */
    .ga-product-single .ga-product__beneficios .ga-container {
        /* Al mínimo razonable: por debajo de 0,5rem las fotos quedarían pegadas
           al canto de la franja crema y se perdería el marco. */
        padding-inline: clamp(0.5rem, 1vw, 0.75rem);
    }
}

/* ——— LAS TRES CELDAS COMPARTEN FILAS ———
   🔴 SIN ESTO, CADA BLOQUE SE ORGANIZA POR SU CUENTA: si un párrafo ocupa un
   renglón más que los otros, su título queda a distinta altura y la fila se ve
   descuadrada. Con subgrid, las tres celdas se cuelgan de las MISMAS tres filas
   del contenedor —foto, título y texto—, así que cada franja mide lo que el más
   alto de los tres y los tres títulos arrancan a la misma altura.

   Se hace con filas compartidas y no con una altura fija porque una altura
   escrita a mano habría que recalcularla cada vez que cambie un texto, y se
   quedaría corta el día que alguien alargue uno.

   ⚠ VA DENTRO DE UN @supports porque subgrid no existe en navegadores anteriores
     a 2023. Donde no esté, cada bloque se maquetará por su cuenta como hasta
     ahora: los títulos podrán quedar a distinta altura, pero se ve todo y nada se
     rompe. Y va dentro del @media porque apilados, en móvil, no hay filas que
     compartir: cada bloque va uno debajo de otro. */
@media (min-width: 861px) {
    @supports (grid-template-rows: subgrid) {

        .ga-cosecha__grid {
            /* Las tres franjas del contenedor: foto, título y texto. */
            grid-template-rows: auto auto auto;
            /* A 0 porque la separación entre las tres piezas ya la ponen sus
               propios márgenes; con un row-gap además se sumaría. */
            row-gap: 0;
        }

        .ga-cosecha__item {
            display: grid;
            grid-row: span 3;
            grid-template-rows: subgrid;
        }
    }
}

.ga-cosecha__item {
    text-align: center;
}


/* =============================================================================
   LA SECCIÓN DE LAS TRES FOTOS, EN CARRUSEL EN MÓVIL
   =============================================================================
   En escritorio son tres columnas y no se toca nada. Por debajo de 861px —el mismo
   punto en el que la rejilla ya pasaba a una sola columna— las tres tarjetas dejan
   de apilarse y se ven de una en una, deslizando con el dedo y en bucle infinito.

   🔴 LA CLASE .is-carrusel LA PONE EL JS, Y ESO ES LA RED DE SEGURIDAD. Sin
   JavaScript no hay clones que hagan el bucle, así que tampoco se activa el
   deslizamiento: la sección se queda apilada en vertical, que es como estaba y se lee
   perfectamente. Nada de un carrusel a medias con tres tarjetas sueltas.

   🔴 SCROLL NATIVO, NO transform, Y ESTE ES EL PUNTO DELICADO DEL BLOQUE. El
   claude.md guarda dos experiencias opuestas: la tienda tuvo que abandonar el scroll
   nativo porque una fila real más ancha que el viewport INFLABA el viewport de
   maquetación (🪤 nº 1), y en cambio el carrusel de sellos de Nosotros funciona con
   scroll-snap nativo (🪤 nº 12). La diferencia está en dónde vive el overflow: aquí
   el contenedor mide exactamente el 100 % del ancho de .ga-container y la fila
   desborda HACIA DENTRO de él, que es el caso que sí funciona. El overflow no toca ni
   html ni body, que siguen con su cortafuegos intacto.

   Se elige el nativo y no el transform porque el bucle infinito que se pide —clones a
   los lados y reposicionamiento invisible— necesita poder colocar el carrusel en una
   posición concreta sin animación, y `scrollLeft` hace eso en una línea.

   ⚠ overscroll-behavior-x SOLO EN EL EJE X Y SOLO AQUÍ. En el body está prohibido
     —bloquea el scroll vertical en Chrome de Android, 🪤 nº 2—, pero en un contenedor
     de scroll horizontal es justo lo que impide que al llegar al final el gesto se
     encadene con el "volver atrás" del navegador.

   ⚠ flex-basis EXPLÍCITO Y max-width, NUNCA min-width: es la receta del carrusel del
     proyecto. Con el 100 % cada tarjeta ocupa el ancho disponible y se ve una a la
     vez; con scroll-snap-stop: always, un gesto pasa una sola tarjeta y no tres. */
@media (max-width: 860px) {

    .ga-product-single:not(.ga-product-single--eventos) .ga-cosecha__grid.is-carrusel {
        display: flex;
        gap: var(--ga-space-sm);

        overflow-x: auto;
        overscroll-behavior-x: contain;
        scroll-snap-type: x mandatory;

        /* La barra de scroll se oculta: el indicador son los puntos de abajo. */
        scrollbar-width: none;
        -ms-overflow-style: none;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-cosecha__grid.is-carrusel::-webkit-scrollbar {
        display: none;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-cosecha__grid.is-carrusel > .ga-cosecha__item {
        flex: 0 0 100%;
        max-width: 100%;

        /* 🔴 `start` Y NO `center`, PARA QUE LA CUENTA DEL BUCLE SEA EXACTA. El JS
           calcula la posición de cada tarjeta como índice × (ancho + hueco), que es
           justo donde ancla `start`. Con `center` el resultado es el mismo mientras
           las tarjetas midan el 100 % del contenedor, pero deja de serlo en cuanto
           alguien cambie ese ancho, y entonces el salto invisible aterrizaría unos
           píxeles al lado. Con `start` la fórmula y el anclaje son la misma cosa.

           scroll-snap-stop: always → un gesto pasa UNA tarjeta, no tres. */
        scroll-snap-align: start;
        scroll-snap-stop: always;
    }
}

/* 🔴 EL aspect-ratio ES LO QUE EVITA EL SALTO DE MAQUETACIÓN. El navegador
   reserva el alto de la foto ANTES de tenerla descargada, así que el título y el
   texto de debajo nacen ya en su sitio y no bajan de golpe cuando la imagen
   llega. Sin él, con loading="lazy", el salto sería visible en cada una.

   ⚠ CUADRADO (1/1) PORQUE LAS FOTOS ORIGINALES LO SON. Con el 4/3 de antes,
     object-fit: cover recortaba por arriba y por abajo para rellenar una caja más
     ancha que alta: no deformaba, pero se comía parte de la imagen. Con la misma
     proporción que el original no recorta nada, y cover se queda de todos modos
     como red por si alguna foto no fuera exactamente cuadrada.

   Las tres comparten proporción, que es lo que hace que los tres títulos
   arranquen a la misma altura pase lo que pase con las fotos. */
.ga-cosecha__foto {
    display: block;
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    border-radius: 10px;
    margin-bottom: var(--ga-space-sm);
}

/* El hueco cuando la foto no aparece: mismo tamaño y mismo radio, en el crema de
   marca. La fila no se descuadra y los otros dos bloques siguen alineados. */
.ga-cosecha__foto--vacia {
    background-color: var(--ga-naranja-claro);
}

/* ——— LA SEGUNDA FOTO DE LA MERMELADA, ENCUADRADA UN PUNTO MÁS ABAJO ———
   🔴 SE MUEVE EL ENCUADRE, NO LA IMAGEN NI SU RECUADRO. object-position solo decide
   QUÉ TROZO de la foto se ve dentro del hueco; el hueco mide y pesa exactamente lo
   mismo, y ni la imagen ni lo que tiene alrededor se desplazan un píxel. Por eso no
   se usa un margen ni un transform: cualquiera de los dos movería algo de la
   maquetación, y aquí no se quiere mover nada.

   🔴 DE DÓNDE SALE EL 35 %, CON LA CUENTA HECHA. Esta foto es de 1200 × 1500 —4:5 en
   vertical, la única de las tres que no es cuadrada— y el hueco es un cuadrado con
   object-fit: cover, así que la imagen se escala por el ancho y le sobra alto:

     alto renderizado = 1500 × (lado ÷ 1200) = 1,25 × lado
     sobrante = 0,25 × lado, que es lo que se reparte entre arriba y abajo

   Con el 50 % por defecto ese sobrante se parte en dos y se recortan por igual el
   10 % de arriba y el 10 % de abajo de la foto. Bajando el valor, la ventana sube y
   se ve más parte alta:

     al 35 % → se recorta un 7 % por arriba y un 13 % por abajo
     el desplazamiento real es 0,15 × 0,25 = 3,75 % del alto del hueco
     (unos 20 px en escritorio y unos 12 px a 360 px)

   Es el "lo justo para que se note" que se pedía: se gana un 3 % de cielo por arriba
   y se pierde otro tanto por abajo. Para afinarlo se toca SOLO ese número —bajarlo
   sube más la imagen, subirlo la devuelve al centro—, y es imposible que aparezcan
   franjas vacías: con `cover` la foto tapa siempre el hueco entero, valga lo que
   valga esta propiedad.

   ⚠ ACOTADO POR PARTIDA DOBLE, Y LAS DOS PARTES HACEN FALTA:

     · .ga-product-single--mermelada → solo la ficha de la mermelada. Esa clase la
       pinta la plantilla desde $ga_es_mermelada, que lleva su propio ! $ga_es_eventos,
       así que ni las fichas de aceite ni las de aceitunas ni las de Eventos la tienen.
       Importa de verdad: ESTA MISMA FOTO se usa también en la página Nosotros
       (page-nosotros.php), y allí no la alcanza este selector ni de lejos.

     · :nth-of-type(2) → solo el bloque del medio. Los tres .ga-cosecha__item son
       <div> hermanos que el bucle pinta en orden, así que el segundo es siempre el de
       "De aceituna verde y en frío". La primera y la tercera se quedan centradas.

   ⚠ NI TAMAÑO NI POSICIÓN, NI NADA QUE ANIMAR: la regla base de .ga-cosecha__foto no
     declara ninguna transición y esto no añade ninguna, así que no hay estado —hover,
     foco ni ningún otro— que pueda mover el encuadre. */
.ga-product-single--mermelada .ga-cosecha__item:nth-of-type(2) .ga-cosecha__foto {
    object-position: 50% 35%;
}

/* Misma serif y mismo criterio que los títulos de bloque del resto de la ficha
   —.ga-beneficio__titulo usaba estos valores—, para que la sección no estrene
   una tipografía propia. */
.ga-cosecha__titulo {
    font-family: var(--ga-font-display);
    /* Crece de 1,2rem fijo a un clamp: en pantalla grande llega a 1,55rem y en
       móvil no baja de 1,3rem, que sigue siendo más de lo que tenía. Va en clamp
       y no en un número fijo porque esta columna mide un tercio del ancho en
       escritorio y el total en móvil: un mismo valor se vería enorme en uno de
       los dos casos. */
    font-size: clamp(1.3rem, 1.6vw, 1.55rem);
    /* 700 para que despegue de su párrafo. Es el peso más alto que se carga de
       Cormorant (functions.php pide 300, 400, 600 y 700), así que existe de
       verdad y el navegador no tiene que fingirlo engordando el trazo, que es lo
       que deja las letras sucias. */
    font-weight: 700;
    line-height: 1.25;
    color: var(--ga-verde-oliva-oscuro);
    margin: 0 0 0.7rem;
}

.ga-cosecha__texto {
    font-family: var(--ga-font-body);
    /* De 14px a 16px. Se queda en --ga-text-base y no sube más para no comerse la
       distancia con el título: entre 16px de Inter y 1,3rem de Cormorant en
       negrita todavía se lee cuál manda, que es la jerarquía que había que
       conservar. */
    font-size: var(--ga-text-base);
    line-height: 1.65;
    color: var(--ga-verde-oliva-oscuro);
    margin: 0;
    /* Corta el ancho mínimo del texto sin min-width. */
    overflow-wrap: break-word;
}


.ga-beneficios__grid {
    display: grid;
    grid-template-columns: 1fr;             /* móvil: 1 columna */
    gap: 1.25rem;
    margin-top: 0;
}

@media (min-width: 600px) {
    .ga-beneficios__grid {
        grid-template-columns: repeat(2, 1fr);  /* tablet: 2 columnas */
        gap: 1.5rem;
    }
}

@media (min-width: 900px) {
    .ga-beneficios__grid {
        grid-template-columns: repeat(4, 1fr);   /* escritorio: 4 en fila */
        gap: 2rem;
    }
}

.ga-beneficio {
    text-align: center;
    padding: 2rem 1.5rem;
    background: var(--ga-blanco);
    border: 1px solid var(--ga-amarillo-pastel);
    border-radius: var(--ga-radius-md);
    box-shadow: var(--ga-shadow-sm);
    transition: transform var(--ga-transition-normal), box-shadow var(--ga-transition-normal);
}

.ga-beneficio:hover {
    transform: translateY(-4px);
    box-shadow: var(--ga-shadow-md);
}

.ga-beneficio__icono {
    width: 72px;
    height: 72px;
    border-radius: 50%;
    background: var(--ga-naranja-claro);
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto 1.25rem;
    color: var(--ga-verde-oliva-oscuro);
}

.ga-beneficio__titulo {
    font-family: var(--ga-font-display);
    font-size: 1.2rem;
    font-weight: 600;
    color: var(--ga-verde-oliva-oscuro);
    margin: 0 0 0.75rem;
}

.ga-beneficio__texto {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    line-height: 1.7;
    color: var(--ga-verde-montanas);
    margin: 0;
}


/* ─── Reseñas ────────────────────────────────────── */

.ga-product__resenhas {
    padding-block: var(--ga-space-xl);
    background: var(--ga-blanco);
}

.ga-resenhas__global {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    margin-top: 0.75rem;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    color: var(--ga-verde-montanas);
}

.ga-resenhas__global strong { color: var(--ga-verde-oliva-oscuro); font-size: 1rem; }

.ga-stars {
    color: var(--ga-naranja-apagado);
    font-size: 1.2rem;
    letter-spacing: 0.05em;
    line-height: 1;
}

.ga-stars--sm { font-size: 0.95rem; }

/* ─── Slider viewport + track ────────────────────── */

.ga-resenhas__viewport {
    overflow: hidden;
    margin-top: var(--ga-space-lg);
}

.ga-resenhas__track {
    display: flex;
    gap: 1.5rem;
    transition: transform 0.3s ease;
    will-change: transform;
}

/* ─── Tarjeta de reseña: ancho fijo por breakpoint ─ */

.ga-resenya {
    flex: 0 0 100%;          /* móvil: 1 visible */
    min-width: 0;
    box-sizing: border-box;
    background: var(--ga-naranja-claro);
    border-radius: var(--ga-radius-md);
    padding: 1.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.875rem;
}

@media (min-width: 640px) {
    .ga-resenya {
        flex: 0 0 calc((100% - 1.5rem) / 2);   /* tablet: 2 visibles */
    }
}

@media (min-width: 1024px) {
    .ga-resenya {
        flex: 0 0 calc((100% - 3rem) / 3);      /* desktop: 3 visibles */
    }
}

/* ─── Controles del slider ───────────────────────── */

.ga-resenhas__controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 1.5rem;
}

.ga-resenhas__dots {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 24px;
}

.ga-resenhas__dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--ga-amarillo-pastel);
    border: none;
    padding: 0;
    cursor: pointer;
    transition: background 0.25s ease, transform 0.25s ease;
}

.ga-resenhas__dot.is-active {
    background: var(--ga-verde-oliva-oscuro);
    transform: scale(1.4);
}

.ga-resenhas__nav {
    display: flex;
    gap: 0.625rem;
}

.ga-resenhas__btn {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: transparent;
    border: 1.5px solid var(--ga-verde-oliva-oscuro);
    color: var(--ga-verde-oliva-oscuro);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex-shrink: 0;
    transition: background 0.25s ease, color 0.25s ease, border-color 0.25s ease, opacity 0.25s ease;
}

.ga-resenhas__btn:hover:not(:disabled) {
    background: var(--ga-naranja-apagado);
    border-color: var(--ga-naranja-apagado);
    color: var(--ga-blanco);
}

.ga-resenhas__btn:disabled {
    opacity: 0.3;
    cursor: not-allowed;
}

.ga-resenya__header {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.ga-resenya__autor {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    font-family: var(--ga-font-body);
}

.ga-resenya__autor strong {
    font-size: var(--ga-text-sm);
    font-weight: 700;
    color: var(--ga-verde-oliva-oscuro);
}

.ga-resenya__autor span {
    font-size: var(--ga-text-xs);
    color: var(--ga-verde-montanas);
}

.ga-resenya__fecha {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    color: var(--ga-amarillo-pastel);
}

.ga-resenya__texto {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    line-height: 1.7;
    color: var(--ga-verde-oliva-oscuro);
    margin: 0;
}


/* ─── Productos relacionados ─────────────────────── */

.ga-product__relacionados {
    padding-block: var(--ga-space-xl);
    background: var(--ga-naranja-claro);
}

.ga-relacionados__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1.75rem;
    margin-top: var(--ga-space-lg);
}

.ga-related-card {
    background: var(--ga-blanco);
    border-radius: var(--ga-radius-md);
    overflow: hidden;
    transition: transform var(--ga-transition-normal), box-shadow var(--ga-transition-normal);
}

.ga-related-card:hover {
    transform: translateY(-4px);
    box-shadow: var(--ga-shadow-md);
}

.ga-related-card__imagen {
    aspect-ratio: 1 / 1;
    overflow: hidden;
    background: var(--ga-naranja-claro);
}

.ga-related-card__imagen img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform 0.5s ease;
}

.ga-related-card:hover .ga-related-card__imagen img {
    transform: scale(1.04);
}

.ga-related-card__info {
    padding: 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.ga-related-card__cat {
    font-family: var(--ga-font-body);
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--ga-naranja-apagado);
}

.ga-related-card__nombre {
    font-family: var(--ga-font-display);
    font-size: 1rem;
    font-weight: 600;
    color: var(--ga-verde-oliva-oscuro);
    margin: 0;
    line-height: 1.3;
}

.ga-related-card__nombre a {
    color: inherit;
    text-decoration: none;
}

.ga-related-card__nombre a:hover { color: var(--ga-naranja-apagado); }

.ga-related-card__precio .woocommerce-Price-amount {
    font-family: var(--ga-font-body);
    font-size: 1rem;
    font-weight: 700;
    color: var(--ga-naranja-apagado);
}

.ga-btn--sm {
    padding: 0.6rem 1.25rem;
    font-size: 0.72rem;
    letter-spacing: 0.1em;
    text-align: center;
    display: block;
}


/* ─── FAQ ────────────────────────────────────────── */

.ga-product__faq {
    padding-block: var(--ga-space-xl);
    background: var(--ga-blanco);
}

/* ——— EN APADRINA UN OLIVO, MÁS PEGADAS ———
   🔴 AHÍ ESTA SECCIÓN NO ESTÁ DONDE EN TODAS LAS DEMÁS, y de eso viene el problema.
   En el resto de la tienda las preguntas van al final, después de "También te puede
   interesar", separando dos bloques que no tienen nada que ver entre sí: los 4rem de
   arriba y de abajo están bien ahí. En Apadrina se pintan JUSTO DEBAJO del
   desplegable "Descripción del producto", y ahí esos mismos 4rem —sumados a los 4rem
   de relleno inferior del bloque de compra por arriba, y a los 4rem del superior de
   "También te puede interesar" por abajo— dejaban 8rem por cada lado. Las preguntas
   son la continuación natural de la descripción, así que se quedaban flotando lejos
   de aquello a lo que responden.

   Con --ga-space-md las dos uniones bajan de 8rem a 5,5rem: siguen siendo dos
   secciones distintas y no se tocan, pero se leen seguidas.

   🔴 SE TOCA SOLO EL RELLENO DE ESTA SECCIÓN, no el de sus dos vecinas. Es lo que
   mantiene el cambio acotado: el bloque de compra y "También te puede interesar"
   conservan su medida, así que ninguna otra unión de ninguna otra ficha se mueve.

   ⚠ ACOTADO POR SKU, que es el gancho que este archivo ya usa para lo que solo le
     toca a un producto —lo mismo hace la regla de la etiqueta del pack de tres
     tarros—. El claude.md prohíbe cambiar los SKU, así que es estable, y es además
     el mismo con el que functions.php § 11 reconoce este producto para capturar el
     número de olivo. Su especificidad (0-2-0) gana a la regla base (0-1-0) esté donde
     esté en el archivo. */
.ga-product-single--sku-ga-olv-apadrina .ga-product__faq {
    padding-block: var(--ga-space-md);
}

.ga-faq__item .ga-accordion__trigger {
    font-size: var(--ga-text-sm);
    font-weight: 500;
}


/* ─── Secciones compartidas ──────────────────────── */

.ga-section__header--center {
    text-align: center;
    margin-bottom: var(--ga-space-lg);
}

.ga-section__eyebrow {
    display: block;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.15em;
    color: var(--ga-naranja-apagado);
    margin-bottom: 0.6rem;
}

.ga-section__titulo {
    font-family: var(--ga-font-display);
    font-size: clamp(1.6rem, 3vw, 2.4rem);
    font-weight: 600;
    color: var(--ga-verde-oliva-oscuro);
    margin: 0 0 0.75rem;
    line-height: 1.15;
}

.ga-section__subtitulo {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    color: var(--ga-verde-montanas);
    max-width: 560px;
    margin: 0 auto;
    line-height: 1.6;
}


/* ─── Responsive ─────────────────────────────────── */

@media (max-width: 1024px) {
    .ga-product__grid {
        grid-template-columns: 1fr 1fr;
        gap: var(--ga-space-lg);
    }
}

@media (max-width: 860px) {
    .ga-product__grid {
        grid-template-columns: 1fr;
    }

    .ga-product__gallery {
        position: static;
    }

    .ga-beneficios__grid,
    .ga-relacionados__grid {
        grid-template-columns: 1fr;
        gap: 1.25rem;
    }
}

@media (max-width: 640px) {
    .ga-product__trust-band {
        flex-direction: column;
    }

    .ga-product__accordion-zone { padding-top: 2rem; padding-bottom: var(--ga-space-lg); }
    .ga-product__comparativa    { padding-block: var(--ga-space-lg); }

    /* La separación del título vuelve a su escalón normal en móvil. Aquí no hay
       nada que compensar: por debajo de este ancho la tabla de escritorio no se
       pinta —sale la de móvil, que no tiene columnas de formato— y por tanto
       tampoco hay saliente. Los 4rem de escritorio serían demasiado aire en una
       pantalla estrecha; el sitio va compacto en móvil. */
    .ga-product__comparativa .ga-section__header--center {
        margin-bottom: var(--ga-space-lg);
    }
    /* El equivalente móvil de la franja de cosecha: los dos rellenos iguales, y
       los dos bajan un escalón igual que en escritorio. Esta regla es POSTERIOR a
       la de más arriba y la pisa, así que sin tocarla aquí el recorte no se vería
       en el móvil. */
    .ga-product__beneficios     { padding-top: var(--ga-space-md); padding-bottom: var(--ga-space-md); }
    .ga-product__resenhas       { padding-block: var(--ga-space-lg); }
    .ga-product__relacionados   { padding-block: var(--ga-space-lg); }
    .ga-product__faq            { padding-block: var(--ga-space-lg); }

    .ga-product__cta-buttons {
        gap: 0.6rem;
    }
}

@media (min-width: 860px) {
    .ga-product__cta-buttons {
        flex-direction: row;
    }

    .ga-product__btn-cart,
    .ga-product__btn-buy-now {
        flex: 1;
    }
}


/* =============================================================================
   FORMULARIO DE VARIACIONES (productos variables que NO son de Eventos)
   =============================================================================
   Este marcado NO lo escribe la plantilla: lo pinta WooCommerce con
   woocommerce_variable_add_to_cart(), así que las clases son las suyas
   (.variations, .single_variation_wrap, .woocommerce-variation-price…) y no
   llevan el prefijo ga-.

   🔴 ESTILOS MÍNIMOS, NO UN REDISEÑO. Lo único que se busca aquí es que el
   selector herede la tipografía y los colores de marca y no cante al lado del
   resto de la ficha. El rediseño de este formulario es una fase aparte.

   TODO VA ACOTADO CON .ga-product-single, la clase del <main> de la ficha: el
   mismo marcado aparece en otras pantallas de WooCommerce y no se toca allí.
   ============================================================================= */

/* 🔴 LA TABLA DE VARIACIONES SE APILA, Y ESTO NO ES ESTÉTICA: ES EL ARREGLO DE UN
   DESBORDAMIENTO. WooCommerce pinta las variaciones en una <table> de dos
   columnas —etiqueta y desplegable—, y una tabla NO encoge por debajo del ancho
   mínimo de su contenido: con un atributo de nombre largo, a 360px la fila se
   hace más ancha que la columna y saca la página de madre (🪤 nº 1).

   Pasando la tabla y sus partes a `block`, la etiqueta queda encima de su
   desplegable, cada fila ocupa el ancho disponible y no hay tabla que pueda
   desbordar. Es además cómodo en móvil, que es de donde viene el 70 % del
   tráfico.

   Nada de min-width: el ancho mínimo se corta con overflow-wrap en la etiqueta
   y con el 100 % del desplegable. */
.ga-product-single .variations,
.ga-product-single .variations tbody,
.ga-product-single .variations tr,
.ga-product-single .variations th,
.ga-product-single .variations td {
    display: block;
    width: 100%;
    padding: 0;
    border: 0;
    text-align: left;
}

.ga-product-single .variations tr + tr {
    margin-top: var(--ga-space-sm);
}

/* La etiqueta del atributo ("Talla", "Variedad"…), con el mismo aire y peso que
   las etiquetas del formulario de personalización de Eventos, para que los dos
   formularios de la tienda se lean igual.

   🔴 LOS TRES SELECTORES SON LA MISMA ETIQUETA VISTA DESDE SITIOS DISTINTOS: los dos
   primeros son las que pinta WooCommerce dentro de su tabla de variaciones ("Tarro
   1" y "Tarro 2") y el tercero es la del tarro 3, que la escribe la plantilla porque
   la Gordal no es un atributo. Comparten regla para que se lean igual, que es justo
   lo que se pide de ellas.

   🔴 Y POR ESO SE FIJAN TAMBIÉN LAS TRES HEREDADAS DE ABAJO. Con solo la tipografía,
   el cuerpo, el peso y el color declarados, las dos de WooCommerce y la nuestra NO
   estaban garantizadas idénticas: line-height, letter-spacing y text-transform se
   HEREDAN, y las de WooCommerce viven dentro de un <th> de una <table> mientras que
   la del tarro 3 vive en un <div>. Cualquier regla de Astra o del plugin que toque
   `th` o `table` teñía a dos de las tres y a la otra no, y ahí es donde nacía la
   diferencia de formato: no en lo que este archivo declaraba, sino en lo que se
   colaba por debajo.

   Fijándolas, las tres resuelven el mismo valor venga lo que venga de fuera. Los
   valores son los neutros —los que ya tenía la del tarro 3— porque son los que
   coinciden con el resto de etiquetas de formulario del sitio, las de Contacto y las
   de Eventos, que es a lo que apunta el comentario de arriba.

   ⚠ SI LAS DE WOOCOMMERCE SE VEÍAN EN VERSALITAS O CON MÁS ESPACIADO, ERA POR ESA
     HERENCIA Y AHORA DEJARÁN DE VERSE ASÍ. Es el precio de que las tres sean
     iguales, y es lo que se pidió; si el aspecto bueno fuera aquel, lo que hay que
     cambiar son estos tres valores —aquí, en un solo sitio, y les llega a las tres—
     y no volver a dejar la del tarro 3 a su suerte. */
.ga-product-single .variations th label,
.ga-product-single .variations .label label,
.ga-product-single .ga-pack-tarro3__label {
    display: block;
    margin-bottom: 0.35rem;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    font-weight: 500;
    line-height: 1.4;
    letter-spacing: normal;
    text-transform: none;
    color: var(--ga-verde-oliva-oscuro);
    overflow-wrap: break-word;
}

/* 🔴 DEVOLVER LA ETIQUETA DEL ATRIBUTO EN LA FICHA DEL PACK DE TRES TARROS.
   La regla de arriba da FORMATO a la etiqueta, pero en esta ficha no se veía
   ninguna: la celda que la contiene venía oculta desde fuera del tema.

   QUIÉN LA OCULTABA. El plugin de swatches (variation-swatches-woo) pone en el
   <body> de TODA ficha de producto la clase cfvsw-label-none —es su ajuste de
   "posición de la etiqueta" puesto en "ninguna"— y su hoja lleva:

       .cfvsw-label-none table.variations tr th.label { display: none !important }

   Con los swatches puestos eso tiene sentido: la etiqueta la pintaba el propio
   swatch. Pero en esta ficha los swatches se retiran para poder usar
   desplegables, y al irse ellos la etiqueta ya no la pinta nadie: la fila queda
   oculta y el desplegable sale a pelo. Por eso el "Tarro 3" sí se leía y los
   otros dos no: el 3 no vive dentro de .variations, es marcado propio.

   POR QUÉ ESTA REGLA VA ACOTADA AL SKU Y NO A TODA LA TIENDA. Esa clase del
   plugin está en el <body> de TODA ficha de producto, se le hayan quitado los
   swatches o no, así que una regla general levantaría la ocultación en sitios
   donde la etiqueta no tiene que verse.

   ⚠ Y EN LA CAMISETA SIGUE SIN VERSE, AUNQUE YA NO USE SWATCHES. A ella también
     se le retiran ahora (ga_ficha_sin_swatches, functions.php § 29), pero su
     etiqueta se deja escondida A PROPÓSITO: allí el rótulo lo pone la plantilla
     con su propio "Elige tu talla" —fuera del formulario y con el mismo formato
     que "Personaliza tu pack"—, y levantar esta ocultación le añadiría un
     segundo título "Talla" justo encima del desplegable. Con un solo atributo se
     lee mejor un encabezado propio; con tres, como en el pack, hace falta el
     nombre de cada campo, y por eso allí sí se levanta.

   El SKU es el gancho seguro: claude.md prohíbe cambiarlo, y ya se usa así en
   este mismo archivo.

   EL !important NO ES PEREZA: la declaración del plugin lo lleva, y a un
   !important solo se le gana con otro. La especificidad se sube doblando la
   clase del <main> (0-4-2 contra 0-3-3), así que gana esté donde esté esa hoja
   en el orden de carga y no depende de qué se encole antes.

   `block` y no `table-cell`: es lo que vale para el resto de la tabla, que ahí
   arriba se apila entera para no desbordar a 360px. */
.ga-product-single.ga-product-single--sku-ga-pack-aceitunas .variations tr th.label {
    display: block !important;
}

/* 🔴 16px CLAVADOS EN EL DESPLEGABLE. Por debajo de ese tamaño, iOS hace zoom
   automático al abrirlo y deja la página descolocada. Es el mismo criterio que
   ya siguen los campos del formulario de Contacto y los de Eventos.

   box-sizing: border-box para que el relleno no se sume al 100 % del ancho y
   acabe sobresaliendo de la columna. */
/* 🔴 AQUÍ HABÍA UNA COPIA DEL ESTILO DEL DESPLEGABLE, Y SE HA IDO. Estos <select>
   de variación llevaban su propio juego de relleno, borde y radio, parecido pero no
   igual al del desplegable de cantidad que tienen justo encima: mismo bloque de
   compra, dos desplegables con dos aspectos.

   Ahora el selector de variación se ha añadido a las DOS reglas que ya visten al de
   cantidad —la base común con .ga-modalidad__select, más abajo en este archivo, y el
   ajuste propio del de cantidad—, así que comparten flecha, tipografía, relleno,
   grosor de borde, radio y foco por herencia y no por copia. Si se retoca uno, se
   retocan los tres.

   El único valor que sobrevive aquí es el 16px del tamaño de letra, y ese ya lo trae
   la regla común: por debajo de ese tamaño iOS hace zoom al abrir el desplegable y
   deja la página descolocada. */

/* El enlace "Limpiar" que aparece al elegir una variación. Discreto y solo
   cambia de color al pasar por encima. */
.ga-product-single .reset_variations {
    display: inline-block;
    margin-top: 0.4rem;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    color: var(--ga-verde-oliva-oscuro);
    transition: color var(--ga-transition-normal);
}

.ga-product-single .reset_variations:hover,
.ga-product-single .reset_variations:focus-visible {
    color: var(--ga-naranja-apagado);
}

.ga-product-single .single_variation_wrap {
    margin-top: var(--ga-space-sm);
}

/* El precio de la variación elegida: la misma familia y el mismo verde que el
   precio de la ficha, para que al elegir talla no cambie de estilo.

   ⚠ En las fichas que NO son de Eventos este precio va OCULTO (regla de aquí
   abajo). Se deja estilado igualmente porque en Eventos sí se ve, y porque si
   algún día se dejara de ocultar no aparecería sin formato. */
.ga-product-single .woocommerce-variation-price {
    display: block;
    margin-bottom: var(--ga-space-sm);
    font-family: var(--ga-font-display);
    font-size: var(--ga-text-2xl);
    font-weight: 600;
    color: var(--ga-verde-oliva-oscuro);
}

/* 🔴 UN SOLO PRECIO EN PANTALLA. Desde que la cabecera muestra el precio de la
   variación elegida, este de aquí abajo es el mismo importe repetido a dos
   dedos de distancia, y encima con el sufijo del periodo pegado detrás.

   SE OCULTA, NO SE QUITA DEL DOM, y esa diferencia importa: WooCommerce lo
   rellena en cada cambio de variación, y el JS de la cabecera lo usa como
   respaldo para leer el importe cuando la variación no trae su propio
   price_html. Si se eliminara del marcado, ese respaldo se quedaría sin fuente.

   Solo fuera de Eventos: allí no hay productos variables, pero el :not() deja la
   regla acotada por si alguno se marcara como tal. */
.ga-product-single:not(.ga-product-single--eventos) .woocommerce-variation-price {
    display: none;
}

/* Aviso de "no disponible" cuando la combinación elegida no existe. */
.ga-product-single .woocommerce-variation-availability {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    color: var(--ga-verde-montanas);
}

/* La fila de cantidad + botón. En fila si cabe y envolviendo si no: sin
   min-width y sin nada que pueda pasarse del ancho de la columna. */
.ga-product-single .woocommerce-variation-add-to-cart {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ga-space-sm);
}


/* =============================================================================
   DESCRIPCIÓN CORTA EN LA COLUMNA DE LA FOTO (fichas que NO son de Eventos)
   =============================================================================
   La descripción corta se ha mudado de la columna de compra a la de la foto, y
   queda debajo de la imagen y de sus miniaturas. La columna de compra se queda
   solo con lo que cierra la venta.

   Conserva su clase .ga-product__short-desc —y con ella su tipografía, sus
   filetes y sus colores de siempre—; este modificador solo añade el aire que
   antes le daba estar en la otra columna.

   Es el mismo patrón que ya usaba Eventos con .ga-eventos-desc: cada rama tiene
   su modificador para que las dos puedan afinarse por separado sin pisarse.
   ============================================================================= */

.ga-product-single .ga-product__short-desc--gal {
    margin-top: var(--ga-space-xs);
}

/* ——— FUERA LA RAYA DE ABAJO DE LA DESCRIPCIÓN CORTA ———
   🔴 ERAN DOS RAYAS DE DOS DUEÑOS DISTINTOS, y por eso se veían pegadas: la que
   cierra la descripción corta (border-bottom) y la que abre el acordeón
   (.ga-accordion__item:first-child { border-top }). Cada una es correcta por
   separado; juntas hacen una doble línea con un hueco en medio.

   Se quita la de la descripción y se queda la del acordeón, que es la que marca
   dónde empieza la lista de apartados.

   Y con ella se va su relleno inferior: ese 1rem estaba para separar el texto de
   SU raya, y sin raya solo es hueco muerto. El de arriba se queda, porque su
   raya sigue ahí.

   Acotado con --gal, el modificador de las fichas que no son de Eventos: allí la
   descripción corta lleva .ga-eventos-desc y conserva sus dos filetes. */
.ga-product-single .ga-product__short-desc--gal {
    border-bottom: none;
    padding-bottom: 0;
}


/* =============================================================================
   LA MERMELADA — DESCRIPCIÓN CORTA PLEGADA A TRES LÍNEAS
   =============================================================================
   Solo existe en su ficha: la plantilla pinta este marcado únicamente cuando el
   producto es la mermelada, así que en el resto de la tienda ninguno de estos
   selectores encuentra nada y no cambia ni un píxel.

   🔴 EL RECORTE ES max-height + overflow, NO display:none NI line-clamp, y las dos
   descartadas lo fueron por un motivo concreto:

     · display:none quitaría el texto de la caja de renderizado. Aquí hace falta
       justo lo contrario: que esté, que se pueda leer por un buscador y que se
       pueda ANIMAR al abrirlo.
     · -webkit-line-clamp recorta por número de líneas, que suena a lo que se
       pide, pero NO SE PUEDE ANIMAR —se pasa de 3 líneas a todas de golpe— y se
       comporta de forma irregular cuando dentro hay varios bloques, que es
       exactamente el caso: esta descripción lleva párrafos y una lista.

   🔴 LAS TRES LÍNEAS SE CALCULAN, NO SE INVENTAN. `3lh` son tres alturas de línea
   del propio elemento: si mañana se retoca el interlineado o el cuerpo de
   .ga-product__short-desc, el recorte lo sigue solo y siguen siendo tres líneas.
   La declaración de encima es el respaldo para navegadores sin la unidad `lh`, y
   da el mismo resultado con los valores de hoy (1,7 de interlineado × 3).

   ⚠ NADA DE UN max-height GRANDE INVENTADO para el estado abierto: el claude.md lo
     prohíbe expresamente y con razón. Abierto NO lleva max-height ninguno; la
     altura de la animación la mide el JS en el momento y la suelta al terminar. */
/* ——— UN POCO DE AIRE BAJO EL BOTÓN ———
   .ga-product__short-desc--gal se quedó sin relleno inferior a propósito: se le
   quitó su raya de abajo y aquel 1rem pasó a ser hueco muerto. Aquí vuelve a hacer
   falta, y por un motivo distinto: debajo del botón empieza el acordeón con su
   propia línea, y sin nada en medio "Seguir leyendo" quedaría pegado a ella.
   Solo en la mermelada, que es la única ficha que tiene botón ahí. */
.ga-product-single .ga-product__short-desc--plegable {
    padding-bottom: var(--ga-space-xs);
}

.ga-product-single .ga-product__desc-clamp {
    overflow: hidden;
    /* La variable ya trae su curva (300ms ease): añadirle otra aquí invalidaría la
       declaración entera y el despliegue saldría de golpe. */
    transition: max-height var(--ga-transition-normal);
}

.ga-product-single .ga-product__desc-clamp.is-plegada {
    max-height: calc(1.7em * 3);
    max-height: 3lh;
}

/* Quien haya pedido menos movimiento no ve el despliegue animado: abre y cierra
   igual, pero de golpe. */
@media (prefers-reduced-motion: reduce) {

    .ga-product-single .ga-product__desc-clamp {
        transition: none;
    }
}

/* ——— "SEGUIR LEYENDO" / "MOSTRAR MENOS" ———
   🔴 SIN ASPECTO DE BOTÓN. Es un <button> porque lo que hace es una acción y no un
   destino, pero se viste como lo que parece: un enlace de texto. Por eso hay que
   deshacer a mano lo que el navegador —y Astra— le ponen a un <button>: fondo,
   borde, relleno y tipografía propia.

   🔴 AL PASAR POR ENCIMA SOLO CAMBIA EL COLOR. Ni tamaño, ni posición, ni grosor
   de subrayado: el subrayado existe SIEMPRE, en los dos estados, así que no puede
   empujar nada al aparecer. Es la regla de estabilidad de layout del claude.md.

   El !important del fondo y el borde no es pereza: Astra estiliza los <button> de
   la ficha con selectores que ganan a una clase suelta, y es el mismo remedio que
   ya usan los botones de la tienda. */
.ga-product-single .ga-product__leer-mas {
    display: inline-block;
    margin-top: 0.6rem;
    padding: 0 !important;

    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    font-weight: 600;
    line-height: 1.5;
    letter-spacing: 0.01em;
    text-decoration: underline;
    text-underline-offset: 0.2em;
    overflow-wrap: break-word;

    background: none !important;
    border: none !important;
    border-radius: 0 !important;
    box-shadow: none !important;
    color: var(--ga-verde-oliva-oscuro) !important;
    cursor: pointer;

    transition: color var(--ga-transition-normal);
}

.ga-product-single .ga-product__leer-mas:hover,
.ga-product-single .ga-product__leer-mas:focus-visible {
    color: var(--ga-naranja-apagado) !important;
}

/* El foco por teclado sí se ve, y se dibuja FUERA con outline-offset para no
   ensanchar el elemento ni mover lo que tiene al lado. */
.ga-product-single .ga-product__leer-mas:focus-visible {
    outline: 2px solid var(--ga-naranja-apagado);
    outline-offset: 3px;
}


/* =============================================================================
   EL ORDEN DE LA FICHA EN MÓVIL (≤860px) — FICHAS QUE NO SON DE EVENTOS
   =============================================================================
   🔴 ESTE BLOQUE HA HECHO FALTA POR ALGO QUE NO ERA EVIDENTE: el sistema de
   `display: contents` + `order` que reordena la ficha en móvil EXISTÍA SOLO PARA
   EVENTOS. Está en main.css acotado con .ga-product-single--eventos, así que en
   una ficha normal nunca llegó a aplicarse: sus dos columnas se apilaban tal
   cual, primero la de la foto entera y después la de compra.

   Consecuencia directa de mudar la descripción corta: al ser ahora el último
   bloque de la columna de la foto, en móvil habría quedado ENTRE LA FOTO Y EL
   NOMBRE, que es justo donde no debe estar. Sin este bloque, el cambio de la
   columna izquierda habría estropeado el recorrido en móvil.

   ⚠ SE ESCRIBE APARTE Y NO SE TOCA EL DE EVENTOS. Son dos listas de `order`
   independientes: aquella tiene bloques que aquí no existen (la cuadrícula de
   botellas, el contacto, el desplegable de la descripción larga) y esta tiene
   dos que allí no existen (las miniaturas y el formulario de variaciones). Con
   una sola lista compartida, o las miniaturas se caían al final o había que
   renumerar los de Eventos, que ya están validados.

   El :not() es lo que las mantiene separadas: este bloque solo alcanza a las
   fichas SIN la clase de Eventos, así que las dos nunca coinciden en la misma
   página.

   RECORRIDO QUE QUEDA EN MÓVIL:
     nombre y precio → foto → disponibilidad → opciones y añadir al carrito
     → sellos → descripción corta
   ============================================================================= */

@media (max-width: 860px) {

    /* Las dos columnas se disuelven y sus hijos pasan a ser celdas del grid, que
       en este ancho ya es de una sola columna. Es lo único que permite intercalar
       bloques de una columna con los de la otra: `order` solo reordena hermanos,
       y sin esto la foto y el nombre son primos. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__gallery,
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__purchase {
        display: contents;
    }

    /* Al dejar de ser cajas, las columnas pierden su `gap` (1rem y 1,25rem). Si
       no se repone aquí, la separación entre bloques pasaría a ser la del grid y
       la ficha quedaría desparramada. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__grid {
        row-gap: var(--ga-space-sm);
    }

    /* 🔴 SUELO DE SEGURIDAD, Y VA EL PRIMERO. El `order` por defecto es 0, que es
       MENOR que todos los de abajo: cualquier bloque que se añada mañana a una de
       las dos columnas y no se enumere aquí se colaría EL PRIMERO de la ficha,
       por delante del nombre del producto. Con un 20 de partida cae al final, que
       es un fallo visible y sin consecuencias.

       Va con `> * > *` porque los hijos del grid son ahora los NIETOS: las
       columnas siguen ahí como elementos, aunque no generen caja. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__grid > * > * {
        order: 20;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-product__cat-tag {
        order: 1;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-product__name {
        order: 2;
    }

    /* 🔴 LA DISPONIBILIDAD VA ANTES QUE EL PRECIO, Y ESE ES EL ORDEN BUENO. Se
       decidió primero para los tres aceites y se ha extendido a toda la tienda: al
       entrar, lo que se lee es el nombre, si está disponible y solo entonces cuánto
       cuesta. En el marcado la disponibilidad va DESPUÉS del precio —el orden de
       escritorio— y es este `order` el que la sube.

       ⚠ NO HAY UN BLOQUE APARTE QUE PISE ESTOS NÚMEROS. Estuvo acotado a los aceites
         con una clase propia y, al valer para todos, se ha fundido aquí: los valores
         de abajo son los definitivos y no hay una segunda lista que mantener. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__stock {
        order: 3;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-product__price-wrap {
        order: 4;
    }

    /* 🔴 LOS DOS SELECTORES HACEN FALTA, Y ESTO ES FÁCIL DE ROMPER SIN ENTERARSE.
       Al sacar las flechas de encima de la foto, el marco pasó a ir envuelto en
       .ga-product__gallery-fila. Con `display: contents` en las columnas, los
       hijos del grid son los NIETOS: cuando hay envoltorio el hijo es la FILA, y
       cuando no lo hay —producto de una sola imagen— sigue siendo el MARCO.

       Sin la línea de la fila, en los productos con varias fotos la imagen se
       habría ido al FINAL de la ficha en móvil: no por un fallo del orden, sino
       porque la fila no estaría enumerada y caería en el suelo de seguridad
       (order: 20) que hay unas líneas más arriba. El suelo hizo su trabajo
       —mandarla al final en vez de colarla la primera—, pero el sitio bueno es
       este. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__gallery-fila,
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__gallery-main {
        order: 5;
    }

    /* Las miniaturas, pegadas a su foto: son la misma pieza. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__gallery-thumbs {
        order: 6;
    }

    /* Las tres caras del mismo sitio, y nunca se pintan dos a la vez: el
       formulario propio en un producto simple, el nativo de WooCommerce en uno
       variable y el aviso cuando no hay existencias. */
    /* "Elige la cantidad" va entre la disponibilidad y el formulario, igual que
       en escritorio. Al añadirlo aquí se corrieron un puesto los tres de abajo:
       sin un número propio habría caído al suelo de seguridad (20) y habría
       aparecido al final de la ficha, detrás de la descripción. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-cantidad {
        order: 7;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-product__cart-form,
    .ga-product-single:not(.ga-product-single--eventos) .variations_form,
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__agotado {
        order: 8;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-product__trust-band {
        order: 9;
    }

    /* Y la descripción corta cierra, después de todo el bloque de compra. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__short-desc--gal {
        order: 10;
    }

    /* El acordeón, detrás de ella: es información de consulta y va la última de
       la ficha apilada.

       ⚠ SE ENUMERA AUNQUE EL SUELO DE SEGURIDAD (order: 20) YA LO MANDARÍA AL
         FINAL. Confiar en el suelo funcionaría hoy y dejaría de funcionar el día
         que se añada otro bloque sin numerar: los dos caerían en 20 y su orden lo
         decidiría el marcado, no esta lista. Estando enumerado, el sitio del
         acordeón es una decisión escrita y no una casualidad. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__acordeon-col {
        order: 11;
    }
}


/* =============================================================================
   ELIGE LA CANTIDAD (fichas que NO son de Eventos)
   =============================================================================
   Recuadros apilados, SIN círculo de radio: el estado se lee por el color del
   borde y del fondo. No enseñan precio: en un producto variable el importe
   depende además de la modalidad, y dos cifras que se contradicen en pantalla
   generan más dudas que ayuda.
   ============================================================================= */

.ga-product-single .ga-cantidad {
    display: grid;
    /* minmax(0,…) para que las filas puedan encoger por debajo del ancho de su
       contenido sin recurrir a min-width. */
    grid-template-columns: minmax(0, 1fr);
    gap: var(--ga-space-xs);
    margin-bottom: var(--ga-space-sm);
}

/* 🔴 EL ENCABEZADO VA EN INTER, NO EN CORMORANT, Y ESE ERA EL PROBLEMA DE FONDO.
   Iba en la serif de títulos y por eso se leía más flojo que las opciones que
   encabeza: Cormorant tiene el trazo mucho más fino y la altura de x mucho más
   baja que Inter, así que al lado de una fila en Inter siempre iba a perder.
   Cambiando la familia se resuelve de verdad; subirle el peso no lo arreglaba.

   ⚠ Y CON LA FAMILIA YA CORREGIDA, EL 700 SOBRABA. Se probó a 700 y 20px y
     quedaba pesado: en Inter, un 700 a ese tamaño pinta como un titular, no como
     un encabezado de bloque dentro de la columna de compra. Baja a 600 y a 18px.

   El peso 600 es ahora el MISMO que el de los títulos de las tarjetas —"1
   botella", "Compra única"—, así que los cuatro textos se leen como una sola
   familia. Lo que sigue distinguiendo al encabezado es el tamaño: 18px frente a
   16px, un solo escalón de la misma rampa. Igualarlos del todo habría borrado la
   diferencia entre el título y las opciones que encabeza, que es justo lo que se
   arregló en el paso anterior.

   ⚠ El respaldo de --ga-negro-suave es OBLIGATORIO: esa variable está en la
     paleta del proyecto pero NO llega a declararse en el :root de style.css, y
     un var() que no resuelve no cae al valor por defecto de la propiedad —hace
     que la declaración entera se descarte y el color pase a heredarse, que en
     esta web acaba siendo el dorado de los enlaces de Astra—. */
/* ⚠ .ga-textil-unidad ENTRA AQUÍ AUNQUE ESTA REGLA ESTÉ CASI ENTERA PISADA. La de
     "ENCABEZADOS DE BLOQUE", más abajo en este mismo archivo, vuelve a declarar la
     tipografía, el tamaño, el peso, el interlineado y el color, y al ir después con
     la misma especificidad es la que manda hoy. Se añade igualmente a las DOS para
     que la frase de la camiseta quede sujeta a la MISMA cascada que el rótulo al que
     acompaña: si mañana se retoca cualquiera de las dos, o deja de existir una, los
     dos textos siguen resolviendo igual. Estar solo en la que hoy gana funcionaría
     hoy y se rompería en silencio el día que eso cambie. */
.ga-product-single .ga-cantidad__titulo,
.ga-product-single .ga-textil-unidad {
    margin: 0 0 0.25rem;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-lg);
    font-weight: 600;
    line-height: 1.2;
    color: var(--ga-negro-suave, #1a1a14);
}

/* 🔴 EL BORDE EXISTE SIEMPRE Y MIDE SIEMPRE 2px. En reposo va en el verde pálido
   de marca y en la fila marcada pasa a dorado: lo único que cambia es el COLOR.
   Si el borde se añadiera solo al marcar, la fila crecería 4px y empujaría a
   todas las de abajo cada vez que se cambia de opción.

   box-sizing: border-box por lo mismo: el borde va por dentro y no ensancha la
   fila.

   position: relative es OBLIGATORIO, no decorativo: el radio de dentro va en
   posición absoluta y sin un ancestro posicionado se colocaría respecto a la
   página. Al llegarle el foco por teclado, el navegador desplazaría la página
   hasta esa esquina. */
.ga-product-single .ga-cantidad__fila {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ga-space-xs);
    box-sizing: border-box;
    margin: 0;
    padding: 1.05rem 1.15rem;
    background-color: var(--ga-blanco);
    border: 2px solid var(--ga-amarillo-pastel);
    /* ⚠ 10px A PRUEBA, y por eso va escrito y no como variable: la escala de
       radios del proyecto solo tiene --ga-radius-sm (4px) y --ga-radius-md (8px),
       y 10px no es ninguno de los dos. Si el valor se da por bueno, lo suyo es
       añadirlo a esa escala en style.css y usarlo aquí y en las tarjetas de
       .ga-modalidad, que llevan el mismo número. Mientras sea una prueba, son dos
       sitios que hay que cambiar a la vez. */
    border-radius: 10px;
    cursor: pointer;
    transition: border-color var(--ga-transition-normal),
                background-color var(--ga-transition-normal);
}

.ga-product-single .ga-cantidad__fila:hover {
    border-color: var(--ga-naranja-apagado);
}

/* :has() viste la fila cuyo radio está marcado. Ver la red de seguridad del
   final del bloque: sin :has() el círculo del radio vuelve a aparecer. */
.ga-product-single .ga-cantidad__fila:has(.ga-cantidad__radio:checked) {
    border-color: var(--ga-naranja-apagado);
    background-color: var(--ga-naranja-claro);
}

/* Halo de foco para el teclado. Va en box-shadow —no en borde ni en padding—
   porque la sombra se pinta FUERA de la caja y no ocupa sitio: no mueve ni
   agranda nada. Dos capas: un hueco blanco y el anillo dorado, para que se vea
   también sobre la fila ya marcada, que tiene el borde de ese mismo dorado. */
.ga-product-single .ga-cantidad__fila:has(.ga-cantidad__radio:focus-visible) {
    box-shadow: 0 0 0 2px var(--ga-blanco),
                0 0 0 4px var(--ga-naranja-apagado);
}

/* 🔴 EL RADIO SE OCULTA A LA VISTA, PERO SIGUE VIVO Y OPERATIVO.
   Nada de display:none ni visibility:hidden: los dos lo sacan del recorrido del
   tabulador y del lector de pantalla, y el bloque dejaría de poder usarse sin
   ratón. Esta es la técnica de accesibilidad de siempre —1px recortado— que lo
   deja fuera de la vista conservándolo en el árbol de accesibilidad.

   Se recorta por partida doble a propósito: clip-path es el que vale hoy y
   clip, aunque esté obsoleto, es el que entienden los navegadores antiguos. */
/* ——— EL CÍRCULO DE SELECCIÓN ———
   🔴 ES EL <input> DE VERDAD, NO UN ADORNO. Aquí había un radio ESCONDIDO —el
   patrón de "solo para lectores de pantalla", con clip-path— porque el estado
   elegido lo señalaba únicamente el fondo de la fila. Ahora se enseña.

   Que sea el control real y no un <span> decorativo tiene tres consecuencias que se
   consiguen gratis: se marca solo al pulsar en cualquier punto de la fila —porque
   todo va dentro de un <label>—, el lector de pantalla lo anuncia UNA vez y no dos,
   y el teclado lo recorre con las flechas como cualquier grupo de radios. No hay
   nada que sincronizar entre el dibujo y el estado, porque son la misma cosa.

   Los valores son los MISMOS que ya usaba "Otra cantidad", que es la referencia que
   se pidió: 1rem de diámetro, borde de 2px en el dorado de marca y fondo blanco.

   ⚠ appearance: none apaga el círculo que pinta el navegador, que es distinto en
     cada motor y no se puede colorear. El dibujo entero lo pone el CSS: el borde
     hace el aro y el ::before de abajo hace el punto.

   ⚠ Como esta regla base ya deja el radio visible, las que hay más abajo para
     "Otra cantidad" y las de respaldo de @supports not (:has()) repiten lo mismo y
     se han quedado sin efecto propio. Se dejan tal cual: no estorban, y quitarlas
     tocaría un bloque que funciona sin ganar nada. */
/* ═══════════════════════════════════════════════════════════════════════════
   EL CÍRCULO DE SELECCIÓN — UN SOLO MECANISMO PARA LAS CUATRO OPCIONES
   ═══════════════════════════════════════════════════════════════════════════
   🔴 EL PUNTO YA NO ES UN ::before DEL <input>, Y AHÍ ESTABA EL FALLO DE RAÍZ.
   Antes el círculo era el propio <input> y el punto su pseudoelemento. Un <input>
   es un elemento REEMPLAZADO: el navegador dibuja su interior a su manera y no
   construye dentro un árbol de cajas normal, así que el pseudoelemento no tiene un
   padre real contra el que centrarse. Donde el motor lo renderiza, acaba colocado
   por la línea de texto que lo rodea —con el interlineado que herede del <label>—,
   y de ahí que se viera a distinta altura en cada opción. Dos intentos de arreglarlo
   con cuentas de píxeles no podían funcionar: el problema no era la cuenta, era que
   el punto no estaba dentro del círculo.

   AHORA SON DOS <span> DE VERDAD, uno dentro del otro, y el centrado lo hace el
   flex del padre. Es la misma solución que el claude.md ya documenta para la
   casilla RGPD del formulario de contacto: input colapsado + elemento hermano que
   dibuja el control. Aquella dice, además, "NO volver a estilizar el input
   directamente", que es exactamente lo que se estaba haciendo aquí.

   Ventajas que no son teóricas:
     · El centrado no depende del texto de al lado, ni del interlineado, ni de que
       el navegador renderice pseudoelementos sobre un control de formulario.
     · Es UNA regla para las cuatro opciones —tarjetas de cantidad, "Otra cantidad"
       y las dos de compra—, así que una opción nueva sale centrada sin tocar nada.
     · Astra ya no puede pisarlo: no hay ningún input estilizado que capturar.

   EL <input> VUELVE A ESTAR OCULTO pero sigue siendo el control real: dentro del
   <label>, se marca al pulsar en cualquier punto de la opción, lo anuncia el lector
   de pantalla y el teclado lo recorre con las flechas. El <span> lleva aria-hidden
   porque es dibujo, no dato. */
.ga-product-single .ga-cantidad .ga-cantidad__radio,
.ga-product-single .ga-modalidad .ga-modalidad__radio {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    padding: 0;
    border: 0;
    overflow: hidden;
    white-space: nowrap;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
}

/* EL CÍRCULO. Tamaño fijo con border-box, así que el borde va por dentro y el aro
   mide 1rem exactos. inline-flex + align-items + justify-content centran a su hijo
   en los dos ejes, sea cual sea el tamaño del punto: si mañana se cambia cualquiera
   de los dos, sigue centrado sin tocar una cuenta.

   flex: 0 0 auto para que no lo estruje la fila cuando el texto ocupa dos líneas. */
.ga-product-single .ga-radio {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 1rem;
    height: 1rem;
    background-color: var(--ga-blanco);
    border: 2px solid var(--ga-naranja-apagado);
    border-radius: 50%;
    cursor: pointer;
    transition: border-color var(--ga-transition-normal);
}

/* EL PUNTO. Sin posición ni márgenes: lo coloca el flex del padre y nada más.

   🔴 EXISTE SIEMPRE Y MIDE SIEMPRE LO MISMO: al marcar solo cambia su COLOR, de
   transparente a dorado. El truco habitual es que nazca con scale(0) y crezca, y
   aquí no vale: eso es un cambio de tamaño, y en esta web ningún estado cambia de
   tamaño ni de posición. */
.ga-product-single .ga-radio__punto {
    width: 0.4rem;
    height: 0.4rem;
    border-radius: 50%;
    background-color: transparent;
    transition: background-color var(--ga-transition-normal);
}

/* El estado marcado, para las cuatro opciones. El selector + exige que el <span>
   vaya INMEDIATAMENTE detrás de su <input> en el marcado; así está escrito en la
   plantilla y hay que mantenerlo. */
.ga-product-single .ga-cantidad__radio:checked + .ga-opcion .ga-radio__punto,
.ga-product-single .ga-modalidad__radio:checked + .ga-modalidad__cuerpo .ga-radio__punto {
    background-color: var(--ga-naranja-apagado);
}

/* ═══════════════════════════════════════════════════════════════════════════
   EL ENVOLTORIO DE LA OPCIÓN — CÍRCULO Y TEXTO, SOLOS
   ═══════════════════════════════════════════════════════════════════════════
   🔴 POR QUÉ EXISTE. Los tres arreglos anteriores fueron sobre el posicionamiento
   y ninguno aguantó, porque el problema no estaba en el círculo: estaba en QUIÉN
   MÁS COMPARTÍA FILA CON ÉL. La fila lleva además la etiqueta "Recomendado" —o el
   campo numérico, o la píldora "Envío gratis"—, y al envolver, el reparto vertical
   se calculaba contra todo ese conjunto. El círculo quedaba centrado sobre dos
   líneas en vez de sobre la suya.

   Con este envoltorio, dentro solo están el círculo y su texto. Lo que haya fuera
   —etiquetas, campos— es HERMANO, no vecino de reparto: cuando la fila envuelve
   baja la etiqueta, y el círculo ni se entera. Es la misma estructura en los cuatro
   sitios, así que también es una sola regla.

   ⚠ SIN flex-wrap: el círculo y su texto no se separan nunca en dos líneas. El
     texto sí puede partir DENTRO de su propio span, que es lo que se quiere.

   ⚠ line-height IGUAL AL DEL TEXTO de la opción. Hace falta para el cálculo de la
     regla siguiente: si no coincidieran, el círculo se alinearía contra una línea
     que no es la que ve el cliente. */
.ga-product-single .ga-opcion {
    display: flex;
    align-items: center;
    gap: var(--ga-space-xs);
    line-height: 1.3;
}

/* ——— EL ENVOLTORIO SE QUEDA CON EL SITIO SOBRANTE DE LA FILA ———
   🔴 ESTO ES LO QUE MANDA LA ETIQUETA "RECOMENDADO" AL BORDE DERECHO, y hay que
   entender por qué hizo falta añadirlo, porque el síntoma despistaba.

   Antes de que existiera este envoltorio, los hijos directos de la fila eran el
   texto y la etiqueta, y era .ga-cantidad__texto —que es flex: 1 1 auto— quien se
   quedaba con todo el hueco libre y empujaba la etiqueta hasta el borde. Al meter
   círculo y texto dentro de .ga-opcion para arreglar el centrado, ESE crecimiento
   se quedó dentro del envoltorio: el texto sigue creciendo, pero solo dentro de su
   caja. La fila pasó a tener dos hijos que no crecen —.ga-opcion, que sin `flex`
   declarado vale 0 1 auto, y la etiqueta, que es 0 0 auto—, así que los dos se
   apelotonaron a la izquierda y el hueco sobrante se fue todo a la derecha DE la
   etiqueta. De ahí que saliera pegada al nombre.

   La etiqueta nunca se movió del marcado: sigue siendo hermana de .ga-opcion,
   dentro de la fila, como debe. Lo que se perdió fue el reparto del espacio, y eso
   es lo que devuelve esta regla: el envoltorio vuelve a quedarse con lo que sobra,
   igual que antes hacía el texto, un nivel más arriba. Nada de márgenes calculados
   a mano ni de position.

   ⚠ ACOTADO A LAS FILAS DE CANTIDAD, y hace falta: .ga-opcion se usa TAMBIÉN en las
     dos tarjetas de "Opciones de compra", donde su hermana es la píldora "Envío
     gratis". Sin el `> .ga-cantidad__fila` de delante, esa píldora se iría también
     al borde derecho de su línea, que no es lo que se ha pedido ni lo que hace hoy.

   ⚠ EL CÍRCULO NO SE MUEVE. Crecer solo le da más ancho al envoltorio; la altura a
     la que se apoya el círculo la siguen decidiendo el align-self y el margen en em
     de la regla de aquí abajo, que no se tocan. Y con el flex-wrap de la fila, si a
     360px no cabe todo, lo que baja de línea es la etiqueta —.ga-opcion crece pero
     también encoge (1 1 auto) y su texto parte en dos dentro de su propia caja—,
     nunca el círculo, que va pegado a su texto dentro del envoltorio. */
.ga-product-single .ga-cantidad__fila > .ga-opcion {
    flex: 1 1 auto;
}

/* ——— MENOS EN "OTRA CANTIDAD" ———
   Ahí la hermana no es una etiqueta que deba irse al borde, sino el campo donde se
   escribe la cifra, y su sitio es justo detrás del texto. Es el mismo trato de
   excepción que ya tenía .ga-cantidad__texto en esta fila —flex: 0 1 auto, unas
   líneas más abajo— y se mantiene, ahora un nivel más arriba. */
.ga-product-single .ga-cantidad__fila--otra > .ga-opcion {
    flex: 0 1 auto;
}

/* ——— EL CÍRCULO, SOBRE LA PRIMERA LÍNEA DEL TEXTO ———
   align-self: flex-start lo lleva al techo del envoltorio, que es donde empieza el
   texto. Desde ahí baja la mitad de lo que le sobra a la línea sobre el círculo,
   con lo que queda centrado sobre la PRIMERA línea y no sobre el bloque entero
   cuando el texto parte en dos a 360px.

   🔴 EL DESPLAZAMIENTO VA EN em Y NO EN rem, Y ESA ES LA DIFERENCIA CON EL INTENTO
   ANTERIOR. En em se calcula sobre el tamaño de letra heredado, así que la cuenta
   —(línea − círculo) / 2— se rehace sola si cambia la tipografía de la opción. Un
   valor fijo en rem se quedaba viejo en cuanto algo cambiaba de tamaño, que es
   justo lo que pasaba.

   El 1.3 es el interlineado del texto, el mismo que declara el envoltorio de
   arriba: si se cambia allí, hay que cambiarlo aquí. */
.ga-product-single .ga-opcion > .ga-radio {
    align-self: flex-start;
    margin-top: calc((1.3em - 1rem) / 2);
}

/* ——— DÓNDE SE APOYA EL CÍRCULO EN LAS FILAS DE CANTIDAD ———
   ⚠ ESTO ES POSICIÓN, NO CENTRADO. El punto lo sigue centrando el flex de .ga-radio,
     que es el mecanismo único. Aquí solo se decide a qué altura de la fila queda el
     aro, igual que la regla equivalente de las tarjetas de compra.

   🔴 Y ES LO QUE EXPLICA QUE SE VIERA BIEN EN UNOS PRODUCTOS Y MAL EN OTROS. La fila
   es flex con flex-wrap: wrap y align-items: center, y lo que lleva dentro CAMBIA CON
   EL PRODUCTO: la palabra ("2 botellas" / "2 tarros"), las cifras de cada formato y,
   en una sola fila, la etiqueta "Recomendado". En cuanto la fila envuelve —porque la
   etiqueta cae abajo, o porque a 360px el texto parte en dos— align-items: center
   centraba el círculo sobre LAS DOS LÍNEAS y el aro bajaba. El punto seguía centrado
   dentro de su círculo; el que se había ido de sitio era el círculo entero, y a la
   vista es lo mismo.

   Por eso pasaba en unos productos sí y en otros no: la fila que lleva "Recomendado"
   es la más ancha y es la primera en envolver. El 500 ml la tiene en la opción de 3,
   la garrafa de 2 L y la de 5 L en la de 4, y los tarros de aceitunas NO la tienen
   —su recomendación de 4 no está entre sus cantidades—, así que ahí no se notaba.

   ARREGLO: el círculo se alinea al principio de la fila y baja lo justo para quedar
   centrado sobre la PRIMERA línea del texto:
       (1,3rem de línea del texto − 1rem del círculo) / 2 = 0,15rem
   Es el mismo cálculo, y el mismo número, que usa la regla de las tarjetas de compra.

   ⚠ VA SOLO SOBRE EL CÍRCULO, con align-self, y NO cambiando el align-items de la
     fila. Si se tocara la fila, la etiqueta "Recomendado" también se subiría al borde
     superior, y hoy va centrada con el texto. Así no se mueve nada más.

   En una fila de una sola línea —que es el caso normal— el resultado es exactamente
   el mismo que antes: el círculo queda centrado sobre esa línea. */
/* ⚠ AQUÍ HABÍA UN align-self MÁS UN margin-top DE 0,15rem SOBRE EL CÍRCULO, Y SE HA
     RETIRADO A PROPÓSITO. Colocaba el aro respecto a la FILA entera, que es
     precisamente el reparto del que había que sacarlo. Con el envoltorio nuevo esa
     alineación la resuelve .ga-opcion, y dejar las dos habría vuelto a bajarlo: el
     desplazamiento se habría aplicado dos veces. */

/* Las opciones vuelven a la tipografía de CUERPO —Inter, la de párrafos y
   botones—, en peso 600 para que sigan pesando como opciones principales.

   ⚠ EL NÚMERO BAJA MUCHO (20px → 16px) Y EL CAMBIO SE VE PEQUEÑO. No es una
     errata ni un exceso: Inter tiene la altura de x bastante mayor que
     Cormorant, así que a igual tamaño declarado pinta más alto. Estos 16px en
     Inter miden en pantalla casi lo mismo que los 20px en Cormorant, y por eso
     un paso de 20 a 18 se habría visto como un AUMENTO en vez de la bajada
     ligera que se busca. */
/* ⚠ ESTOS VALORES SE REPITEN EN OTRAS DOS REGLAS DE ESTE ARCHIVO —el bloque de
   tipografía y el de "Opciones de compra"— y las tres tienen que decir lo mismo.
   No es redundancia por descuido: son tres reglas con el mismo selector separadas
   por cientos de líneas, y cuando empatan en especificidad gana la última. Si una
   se queda con un valor viejo, cambiar cualquiera de las otras deja de tener
   efecto sin que nada avise, que es exactamente lo que pasó con el color de la
   frase de la suscripción. Al decir las tres lo mismo, da igual cuál gane. */
.ga-product-single .ga-cantidad__texto {
    flex: 1 1 auto;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-base);
    font-weight: 400;
    line-height: 1.3;
    color: var(--ga-verde-oliva-oscuro);
    /* Corta el ancho mínimo del contenido sin min-width. */
    overflow-wrap: break-word;
}


/* =============================================================================
   INFORMACIÓN NUTRICIONAL — TARJETA CERRADA
   =============================================================================
   Antes era una tabla suelta con bordes en cada celda y un texto flotando encima
   del marco. Ahora es una tarjeta: cabecera, filas separadas solo por una línea
   horizontal y una nota al pie, todo dentro del mismo recuadro.

   Sigue siendo una <table> de verdad —son datos tabulares y cada valor tiene que
   estar atado a su nutriente para quien use un lector de pantalla—; lo que se ha
   quitado son los bordes de celda y la fila de cabecera, que eran decoración.
   ============================================================================= */

.ga-product-single .ga-nutri {
    box-sizing: border-box;
    padding: 0.9rem 1.1rem;

    /* Casi blanco, con un matiz cálido: el dorado de marca al 4 % sobre blanco.
       Lo justo para que la tarjeta se despegue del fondo de la página sin llegar
       a leerse como un color.

       Dos declaraciones, y las dos hacen falta: la primera es el blanco de
       siempre, que entiende cualquier navegador; la segunda lo tiñe y solo se
       aplica donde color-mix existe. Sin ese respaldo, un navegador antiguo se
       quedaría sin fondo y la tarjeta enseñaría lo que hubiera detrás. */
    background-color: var(--ga-blanco);
    background-color: color-mix(in srgb, var(--ga-naranja-apagado) 4%, var(--ga-blanco));

    border: 1px solid var(--ga-amarillo-pastel);
    border-radius: 10px;
}

/* La cabecera de la tarjeta. Va fuera de la tabla porque no describe columnas:
   es el título del bloque. */
.ga-product-single .ga-nutri__cab {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
    padding-bottom: 0.6rem;
    border-bottom: 1px solid var(--ga-amarillo-pastel);
}

.ga-product-single .ga-nutri__cab-titulo {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ga-verde-oliva-oscuro);
}

.ga-product-single .ga-nutri__cab-ref {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    color: var(--ga-verde-oliva-oscuro);
    opacity: 0.7;
}

/* 🔴 table-layout: fixed ES LO QUE EVITA EL SCROLL HORIZONTAL, y es la clave de
   todo el bloque. Una tabla normal se ensancha hasta que le cabe el contenido y
   NO encoge por debajo de ese ancho: en la columna estrecha de la ficha se salía
   y había que darle su propio scroll (🪤 nº 1). Con el reparto fijo, las columnas
   valen el porcentaje que se les diga y el texto que no quepa ENVUELVE en dos
   líneas en vez de empujar. Sin min-width por ningún lado. */
.ga-product-single .ga-nutri__tabla {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
}

/* Sin líneas verticales: solo una raya fina entre filas. La última no la lleva,
   porque de separarla del pie ya se encarga el margen del pie. */
.ga-product-single .ga-nutri__tabla tr {
    border-bottom: 1px solid var(--ga-amarillo-pastel);
}

.ga-product-single .ga-nutri__tabla tr:last-child {
    border-bottom: none;
}

.ga-product-single .ga-nutri__tabla th,
.ga-product-single .ga-nutri__tabla td {
    padding: 0.5rem 0;
    border: none;
    vertical-align: baseline;
    /* Parte las palabras largas antes que desbordar la celda. */
    overflow-wrap: break-word;
}

/* 🔴 NINGUNA LÍNEA VERTICAL, PASE LO QUE PASE.
   ═══════════════════════════════════════════════════════════════════════
   La regla de aquí arriba ya pone `border: none` en las celdas, así que la raya
   que se ve entre el nutriente y su valor NO la dibuja este tema: no hay una sola
   declaración de border-left, border-right ni border-inline en ninguna de sus
   hojas. Viene de fuera —Astra trae estilos de tabla propios—, y desde aquí no
   puedo ver cuál es exactamente ni con qué selector gana.

   Así que en vez de adivinarlo, se cierra la puerta: se nombran los dos bordes
   laterales por separado —un longhand no lo puede pisar un `border` de fuera
   salvo que vaya después y con más peso— y se sube el selector añadiendo la clase
   de la tarjeta. El !important es la última cerradura, y es el mismo criterio que
   ya se usa en este proyecto contra los estilos de WooCommerce: contra una
   declaración !important ajena no compite nada más.

   Las rayas HORIZONTALES no se tocan: las pone `tr { border-bottom }` unas líneas
   más arriba y se quedan tal cual. */
.ga-product-single .ga-nutri .ga-nutri__tabla,
.ga-product-single .ga-nutri .ga-nutri__tabla tr,
.ga-product-single .ga-nutri .ga-nutri__tabla th,
.ga-product-single .ga-nutri .ga-nutri__tabla td {
    border-left: none !important;
    border-right: none !important;
}

/* El nombre del nutriente: peso normal, alineado a la izquierda. El 58 % le deja
   sitio de sobra al valor sin que ninguno de los dos se estrangule a 360px. */
.ga-product-single .ga-nutri__tabla th {
    width: 58%;
    text-align: left;
    font-weight: 400;
    color: var(--ga-verde-oliva-oscuro);
}

/* El valor: en negrita y pegado al borde derecho de la tarjeta, que es lo que
   permite leer la columna de cifras de un vistazo. */
.ga-product-single .ga-nutri__tabla td {
    text-align: right;
    font-weight: 600;
    color: var(--ga-verde-oliva-oscuro);
}

/* Los subvalores: sangrados respecto a su nutriente y en un tono más apagado.
   La sangría va en padding y no en margin porque una celda de tabla no admite
   margen. La opacidad afecta solo al nombre, no a su cifra: el dato se lee
   igual de claro que los demás. */
.ga-product-single .ga-nutri__sub th {
    padding-left: 1.1rem;
    opacity: 0.75;
}

.ga-product-single .ga-nutri__pie {
    margin: 0.8rem 0 0;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    font-style: italic;
    line-height: 1.5;
    color: var(--ga-verde-oliva-oscuro);
    opacity: 0.75;
}


/* ——— EL AVISO LEGAL, EN SU PROPIO BLOQUE ———
   Fuera de la tarjeta a propósito: no es un dato nutricional, es la razón por la
   que esos datos están ahí. Mezclarlo dentro lo haría parecer una fila más.

   🔴 EL ESCUDO SE DIBUJA DESDE AQUÍ, NO DESDE EL MARCADO. El contenido de este
   apartado pasa por wp_kses_post(), que BORRA las etiquetas <svg>: un icono
   puesto en el HTML desaparecería sin dejar rastro. Como fondo de un ::before no
   pasa por el filtro.

   El color va escrito en hexadecimal dentro del data URI porque es un archivo
   aparte para el navegador y ahí var() no llega: es el valor exacto de
   --ga-verde-oliva-oscuro. Si algún día cambia ese verde, hay que cambiarlo
   también aquí. */
.ga-product-single .ga-nutri__legal {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    box-sizing: border-box;
    margin-top: var(--ga-space-sm);
    padding: 0.7rem 0.9rem;
    background-color: #f4fdf2;
    border-radius: 10px;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    line-height: 1.5;
    /* ⚠ ESTO YA NO PINTA EL ICONO. El escudo va como imagen de fondo del ::before
       de aquí abajo, con su color escrito dentro, así que cambiar este `color`
       afecta SOLO al texto y el escudo se queda en su verde oscuro. Si el icono
       fuera un <svg> con currentColor, esta línea lo habría teñido de negro sin
       querer. */
    color: var(--ga-negro-suave, #1a1a14);
}

.ga-product-single .ga-nutri__legal::before {
    content: "";
    /* flex: 0 0 auto para que el icono no se estruje cuando el texto ocupa dos o
       tres líneas: mantiene su tamaño y el texto envuelve a su lado. */
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    /* Baja el escudo lo justo para que su centro quede a la altura de la primera
       línea de texto en vez de rozar el borde de arriba. */
    margin-top: 0.1rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%234a4a2f' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
}

.ga-product-single .ga-nutri__legal span {
    /* Corta el ancho mínimo del texto sin min-width. */
    overflow-wrap: break-word;
}


/* ——— LA ETIQUETA "RECOMENDADO" ———
   Va a la derecha de la fila sin necesidad de empujarla: .ga-opcion —el envoltorio
   del círculo y el texto, su única hermana— es flex: 1 1 auto, así que se queda con
   todo el sitio sobrante y la etiqueta cae pegada al borde. Y el flex-wrap de la
   fila la baja de línea si a 360px no cupiera, en lugar de desbordar la tarjeta.

   ⚠ ESE flex: 1 1 auto ESTABA EN .ga-cantidad__texto Y AHORA ESTÁ EN .ga-opcion.
     Cuando se creó el envoltorio, el crecimiento se quedó dentro de él y la etiqueta
     se vino al lado del nombre. Está explicado entero en la regla del envoltorio.

   ⚠ EL ALTO ESTÁ MEDIDO PARA QUE NO ENSANCHE LA FILA. Con 12px de letra,
     interlínea 1,2, 0,15rem de relleno arriba y abajo y 1px de borde, la píldora
     mide unos 21px: prácticamente lo mismo que la línea de texto de al lado
     (16px × 1,3). Si fuera más alta, la fila recomendada quedaría más gruesa que
     las demás y la lista se vería descuadrada. */
.ga-product-single .ga-cantidad__etiqueta {
    flex: 0 0 auto;
    display: inline-block;
    padding: 0.15rem 0.5rem;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    line-height: 1.2;
    text-transform: uppercase;
    /* Blanco sobre el dorado de marca. Decisión de Jaime, tomada sabiendo que ese
       par da 2,2:1 de contraste: el fondo dorado se queda como está. */
    color: var(--ga-blanco);
    border: 1px solid transparent;
    border-radius: var(--ga-radius-sm);
    white-space: nowrap;

    /* ═══════════════════════════════════════════════════════════════════════
       EL MISMO BRILLO QUE LA PÍLDORA "ENVÍO GRATIS"
       ═══════════════════════════════════════════════════════════════════════
       Mismo mecanismo y las MISMAS keyframes (ga-home-card-brillo, en main.css):
       un degradado con una banda de luz, el fondo ampliado al 250 % y una
       animación que solo mueve background-position.

       🔴 QUE SOLO SE ANIME background-position ES LO QUE GARANTIZA QUE LA FILA NO
       SE MUEVA. Un resplandor con box-shadow o un cambio de escala desplazarían
       el texto de al lado en cada latido.

       🔴 EL DEGRADADO YA NO REPITE EL DORADO: VA DE TRANSPARENTE A TRANSPARENTE.
       Antes los extremos eran el propio dorado y la banda era el crema de marca,
       un color OPACO: al pasar tapaba el fondo por completo y el barrido se veía
       como una franja clara marcada.

       Ahora el dorado lo pone solo background-color, y encima pasa un degradado
       que es transparente salvo en el centro, donde lleva un blanco muy diluido.
       Como es translúcido, el dorado se sigue viendo a través de él y lo único
       que hace la banda es aclararlo un punto al pasar: un destello, no un
       reflejo.

       ⚠ El 0.28 es la palanca de la intensidad: subirlo marca más el barrido,
         bajarlo lo apaga. Con 1 se volvería a ver una franja blanca sólida.

       El blanco va en rgba y no como variable porque dentro de un rgba() no se
       puede meter una var(): los números son los de --ga-blanco. Es el mismo
       recurso que ya usa el proyecto para las sombras de marca.

       El mecanismo no cambia en nada: mismas keyframes, mismo ancho del 250 % y
       la misma animación de background-position. */
    background-color: var(--ga-naranja-apagado);
    background-image: linear-gradient(
        100deg,
        transparent 0%,
        transparent 45%,
        rgba(255, 255, 255, 0.28) 50%,
        transparent 55%,
        transparent 100%
    );
    background-size: 250% 100%;
    background-repeat: no-repeat;
    background-position: 100% center;
    animation: ga-home-card-brillo 8s linear infinite;
}

/* Ahorro de movimiento: dorado sólido, sin degradado ni animación. Mismo criterio
   que el botón del carrito de la tienda y que la píldora de la suscripción. */
@media (prefers-reduced-motion: reduce) {
    .ga-product-single .ga-cantidad__etiqueta {
        background-image: none;
        animation: none;
    }
}


/* ═══════════════════════════════════════════════════════════════════════════════
   Y EL BRILLO TAMBIÉN EN LAS LETRAS DE "RECOMENDADO"
   ═══════════════════════════════════════════════════════════════════════════════
   La píldora ya tenía su banda de luz cruzando el fondo dorado. Esto añade la misma
   banda recortada SOBRE EL TEXTO, que es el brillo que el proyecto usa en el lema de
   Nosotros y en los títulos de sección de la tienda.

   🔴 POR QUÉ HACEN FALTA DOS ELEMENTOS. background-clip: text recorta a la silueta
   de las letras TODOS los fondos del elemento, incluido el background-color. Puesto
   en la píldora, el dorado del fondo se recortaría también y la píldora se quedaría
   sin fondo. Por eso la plantilla envuelve la palabra en .ga-cantidad__etiqueta-txt:
   la capa de fuera pinta la píldora, la de dentro solo las letras.

   🔴 LAS DOS BANDAS VAN SINCRONIZADAS, Y ES A PROPÓSITO. La interior usa las MISMAS
   keyframes que la píldora (ga-home-card-brillo, de main.css), la misma duración de
   8s, el mismo ancho del 250 % y el mismo arranque en 100% center. Al ser idénticas,
   no se ven dos destellos persiguiéndose: se ve UNA sola luz cruzando la píldora que
   al pasar por encima de las letras también las aclara.

   🔴 LOS TONOS SALEN DE LOS QUE YA TIENE LA ETIQUETA. El texto es blanco sobre el
   dorado de marca, así que el degradado va de blanco a blanco y lo único que cambia
   es la banda: el resto de las letras baja a un 92 % de blanco y la banda pasa al
   blanco entero. Ese es el "algo más claro" que la recorre.

   ⚠ EL 0.92 ES LA PALANCA, Y TIENE UN COSTE MEDIDO. Blanco puro sobre ese dorado da
     2,2:1 —un par que Jaime aprobó sabiéndolo—; al 92 % el texto se compone con algo
     del dorado de detrás y queda en torno a 2,1:1. Es una décima, y la banda devuelve
     el blanco entero cada vez que pasa. Subirlo apaga el destello; bajarlo lo marca
     más y empeora la lectura.

   ⚠ EL BRILLO NO MUEVE NADA. Solo se anima background-position: ni tamaño, ni
     posición, ni sombra. La píldora y la fila miden exactamente lo mismo con brillo y
     sin él.
   ═══════════════════════════════════════════════════════════════════════════════ */

/* 🔴 LA REGLA BASE ES EL RESPALDO, Y VA SIEMPRE. Color macizo, sin degradado y sin
   recorte: es lo que ve un navegador sin background-clip: text. Nunca transparente,
   nunca invisible. El @supports de abajo solo añade el brillo encima. */
.ga-product-single .ga-cantidad__etiqueta-txt {
    color: var(--ga-blanco);
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {

    .ga-product-single .ga-cantidad__etiqueta-txt {
        background-image: linear-gradient(
            100deg,
            rgba(255, 255, 255, 0.92) 0%,
            rgba(255, 255, 255, 0.92) 45%,
            rgba(255, 255, 255, 1) 50%,
            rgba(255, 255, 255, 0.92) 55%,
            rgba(255, 255, 255, 0.92) 100%
        );
        background-size: 250% 100%;
        background-repeat: no-repeat;
        background-position: 100% center;

        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;

        animation: ga-home-card-brillo 8s linear infinite;
    }
}

/* Ahorro de movimiento: letras blancas macizas, sin degradado ni animación. Va
   DESPUÉS del @supports para poder deshacer lo que aquel pone, y devuelve el color
   explícitamente: sin esa línea el texto se quedaría en transparent y desaparecería,
   que es justo lo que no puede pasar. */
@media (prefers-reduced-motion: reduce) {

    .ga-product-single .ga-cantidad__etiqueta-txt {
        background-image: none;
        animation: none;
        color: var(--ga-blanco);
    }
}


/* ─── "Otra cantidad": la salida secundaria ──────────────────────────────────
   Sin recuadro, sin fondo y con el texto más pequeño y apagado, para que no
   compita con las opciones de arriba.

   El borde SIGUE estando y SIGUE midiendo 2px: solo se vuelve transparente. Si
   se quitara con border:none, la fila perdería 4px de alto y de ancho y su
   texto dejaría de alinearse con el de los recuadros. */
.ga-product-single .ga-cantidad__fila--otra {
    padding-top: 0.15rem;
    padding-bottom: 0.15rem;
    background-color: transparent;
    border-color: transparent;
    border-radius: 0;
}

/* Ni al pasar el ratón ni al marcarla aparece recuadro: aquí el único aviso es
   el color del texto (y el campo, que se enciende). */
.ga-product-single .ga-cantidad__fila--otra:hover,
.ga-product-single .ga-cantidad__fila--otra:has(.ga-cantidad__radio:checked) {
    background-color: transparent;
    border-color: transparent;
}

/* Ahora todas las opciones van ya en Inter, así que aquí la familia solo se
   repite para dejar clavado que este control es de formulario pase lo que pase
   con la regla de arriba. Lo que de verdad lo separa de las cuatro opciones
   principales es el tamaño, el peso y el tono apagado. */
.ga-product-single .ga-cantidad__fila--otra .ga-cantidad__texto {
    flex: 0 1 auto;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    font-weight: 400;
    /* 🔴 DE DÓNDE SALÍA EL VERDE: de aquí mismo. Estaba puesto a
       --ga-verde-montanas, el verde de subtítulos, para que la opción se leyera
       como secundaria. No lo heredaba de ningún sitio.

       Ahora usa el color de texto principal. Lo que la sigue marcando como
       secundaria es el tamaño y el peso, no el color.

       ⚠ El respaldo de --ga-negro-suave es obligatorio: la variable está en la
         paleta del proyecto pero no llega a declararse en el :root de
         style.css, y un var() que no resuelve hace que la declaración entera se
         descarte y el color pase a heredarse —que en esta web acaba siendo el
         dorado de los enlaces de Astra—. */
    color: var(--ga-negro-suave, #1a1a14);
}

/* El texto ya NO cambia de color al marcarse: se queda siempre en el color
   principal. Quien avisa de la selección es el punto dorado de al lado, que para
   eso se hizo visible. */



/* 🔴 16px CLAVADOS. Por debajo de ese tamaño, iOS hace zoom automático al
   escribir y deja la página descolocada. Mismo criterio que el resto de campos
   del proyecto.

   El ancho va en ch, la unidad que mide lo que ocupa una cifra en la tipografía
   que se esté usando: 3 dígitos más el relleno y el borde. Es un ancho FIJO y
   no un porcentaje, así que no se come la fila; y al no ser un min-width,
   tampoco impone ningún ancho mínimo al conjunto.

   El borde y el radio son los mismos que los del desplegable de variaciones y
   los de la casilla de cantidad de la ficha: 1px de --ga-amarillo-pastel y
   --ga-radius-sm. */
.ga-product-single .ga-cantidad__campo {
    flex: 0 0 auto;
    box-sizing: border-box;
    width: calc(3ch + 1.4rem);
    padding: 0.35rem 0.5rem;
    font-family: var(--ga-font-body);
    font-size: 16px;
    text-align: center;
    color: var(--ga-verde-oliva-oscuro);
    background-color: var(--ga-blanco);
    border: 1px solid var(--ga-amarillo-pastel);
    border-radius: var(--ga-radius-sm);
    /* Solo se anima el color del borde: el grosor no cambia en ningún estado. */
    transition: border-color var(--ga-transition-normal);
    /* Fuera las flechitas de incrementar y decrementar. En Firefox basta con
       esto; en los navegadores de motor WebKit/Blink hacen falta además los dos
       pseudo-elementos de aquí abajo, porque ahí las flechas son un trozo del
       propio control y appearance no las alcanza. */
    -moz-appearance: textfield;
    appearance: textfield;
}

.ga-product-single .ga-cantidad__campo::-webkit-outer-spin-button,
.ga-product-single .ga-cantidad__campo::-webkit-inner-spin-button {
    -webkit-appearance: none;
    appearance: none;
    margin: 0;
}

/* Al enfocar cambia el COLOR del borde y nada más: mismo grosor, mismo ancho,
   mismo sitio. Se quita el outline del navegador porque el propio borde ya hace
   de aviso de foco. */
.ga-product-single .ga-cantidad__campo:focus {
    outline: none;
    border-color: var(--ga-naranja-apagado);
}

/* Deshabilitado mientras su fila no está marcada: solo cambia la opacidad, ni
   el tamaño ni el sitio. */
.ga-product-single .ga-cantidad__campo:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* ─── Aquí vivía la red de seguridad para navegadores sin :has() ─────────────
   Deshacía el recorte del radio para que volviera a verse, porque el aviso de
   "esta es la opción marcada" dependía entero de :has() y sin él no quedaba
   ningún indicador.

   🔴 SE HA RETIRADO, Y HAY QUE DEJARLA RETIRADA. Ya no hace falta: el punto
   marcado se pinta con `:checked + .ga-radio`, un selector de hermano adyacente
   que funciona en cualquier navegador. Y si se dejara, haría daño: ahora hay un
   círculo dibujado de verdad, así que devolver el radio nativo pintaría DOS
   controles uno al lado del otro.

   El :has() sigue usándose para el fondo y el borde de la fila elegida. Donde no
   exista se pierde ese realce, pero el punto dorado sigue diciendo cuál está
   marcada, que era justo lo que este respaldo venía a garantizar. */


/* =============================================================================
   OPCIONES DE COMPRA — DOS TARJETAS EN LUGAR DEL DESPLEGABLE
   =============================================================================
   Solo en los productos que tienen un único atributo llamado "Modalidad de
   compra". El PHP lo comprueba y, si se cumple, le pone al <main> la clase
   .ga-product-single--modalidad, que es el gancho de todo este bloque. En la
   Camiseta o en el Pack de 3 Tarros esa clase no existe y aquí no se aplica
   nada.

   Las tarjetas repiten a propósito el lenguaje visual de "Elige la cantidad":
   borde de 2px siempre presente que solo cambia de color, fondo suave al
   marcarse y ningún círculo de radio a la vista. Son el mismo tipo de decisión y
   tienen que leerse igual.
   ============================================================================= */

/* 🔴 EL DESPLEGABLE NATIVO SE OCULTA, PERO SIGUE EN EL MARCADO Y SIGUE VIVO.
   Es él quien le dice a WooCommerce qué variación se compra; las tarjetas solo
   le escriben dentro. Si se quitara del DOM, el formulario se enviaría sin
   variación y el producto no se podría comprar.

   El enlace "Limpiar" se va con él: vaciar la elección dejaría las dos tarjetas
   marcando algo que el desplegable ya no tiene. */
.ga-product-single--modalidad .variations,
.ga-product-single--modalidad .reset_variations {
    display: none;
}

.ga-product-single .ga-modalidad {
    display: grid;
    /* minmax(0,…) para que las tarjetas puedan encoger por debajo del ancho de
       su contenido sin recurrir a min-width. */
    grid-template-columns: minmax(0, 1fr);
    gap: var(--ga-space-xs);
    margin-bottom: var(--ga-space-sm);
}

/* Mismo encabezado que el de "Elige la cantidad", con los mismos valores, para
   que los dos bloques se lean como hermanos. Ver allí por qué va en Inter y no
   en la serif de títulos. */
.ga-product-single .ga-modalidad__titulo {
    margin: 0 0 0.25rem;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-lg);
    font-weight: 600;
    line-height: 1.2;
    color: var(--ga-negro-suave, #1a1a14);
}

/* ——— MENOS AIRE ANTES DE "OPCIONES DE COMPRA" ———
   ⚠ ESE HUECO NO ES UN margin-top DE .ga-modalidad: este bloque no tiene
   ninguno. Se suma de tres sitios distintos:

     · margin-bottom de .ga-cantidad
     · gap de la columna .ga-product__purchase ..... 1,25rem  ← el grande
     · margin-top de .single_variation_wrap

   Aquí se quita el tercero. Los otros dos se atacan en el bloque
   "LOS TRES HUECOS DE LA COLUMNA DE COMPRA", al final de este archivo: en su
   momento no se tocó el gap por miedo a mover el nombre y el precio, y ese fue
   el error —era el sumando grande, y por eso bajar márgenes no se notaba—. */
.ga-product-single--modalidad .single_variation_wrap {
    margin-top: 0;
}

/* ——— EL AIRE ENTRE LAS TARJETAS Y LOS BOTONES DE COMPRA ———
   Ese hueco no es de una sola regla: se suma el margen inferior de .ga-modalidad
   y el superior de .ga-product__cta-buttons. El primero se queda a cero y todo el
   espacio se decide en el segundo, para tener una sola palanca en vez de dos
   números que hay que sumar mentalmente.

   ⚠ EL MARGEN ES EL SITIO CORRECTO, aunque por medio haya un `gap`. Los botones
     van dentro de .woocommerce-variation-add-to-cart, que es un flex con
     gap: 0,35rem, y en un contenedor flexible el margen del hijo NO se solapa con
     el gap: se SUMA. Así que subir este número sí mueve el hueco, y lo mueve solo
     aquí: el gap sigue valiendo lo mismo para el resto y nada más se desplaza.

   ⚠ Y NO TOCA AL MARGEN DE ABAJO. Lo que separa los botones de la franja de
     sellos es el gap de la columna (0,35rem), que es otra regla y no se roza.

   Acotado a --modalidad para no tocar la ficha de un producto simple, donde este
   margen separa los botones del selector de cantidad y está bien como está.

   ⚠ ESTE NÚMERO TAMBIÉN DECIDE DÓNDE TERMINA LA COLUMNA DERECHA, y por eso se ha
     bajado de 1,5rem a 1rem: el bloque de compra acababa por debajo del acordeón
     de la columna de la foto y los dos finales quedaban descuadrados. Un rem
     sigue dando aire de sobra —los botones no se pegan al bloque de suscripción—
     y acerca los dos remates.

     No busca cuadrarlos al píxel, y no tendría sentido intentarlo: la diferencia
     entre columnas depende del largo de la descripción, de cuántas opciones de
     cantidad tenga el producto y de si lleva bloque de suscripción, así que un
     número que cuadrara en un aceite descuadraría en otro. Es un ajuste de
     equilibrio, no una alineación.

   1rem es la palanca: subirlo despega más los botones, bajarlo los acerca. */
.ga-product-single--modalidad .ga-modalidad {
    margin-bottom: 0;
}

.ga-product-single--modalidad .ga-product__cta-buttons {
    margin-top: 1rem;
}


/* =============================================================================
   LOS TRES HUECOS DE LA COLUMNA DE COMPRA — DONDE ESTABAN DE VERDAD
   =============================================================================
   🔴 POR QUÉ BAJAR LOS MÁRGENES NO SERVÍA DE NADA. Dos de los tres huecos no los
   ponía ningún margen: los pone el `gap` de la columna.

       .ga-product__purchase { display: flex; flex-direction: column; gap: 1.25rem }

   Un `gap` NO es un margen y no se puede anular desde el hijo: es un hueco que
   abre el CONTENEDOR entre sus hijos, y da igual que el hijo tenga margin 0 —el
   hueco sigue ahí—. Peor: los márgenes del hijo se SUMAN al gap en vez de
   solaparse con él (en un contenedor flexible los márgenes tampoco se colapsan
   entre hermanos). Por eso cada vez que se bajaba un margen el hueco apenas se
   movía: se estaba tocando el sumando pequeño y no el grande.

   DE DÓNDE SALÍA CADA UNO:

     a) "Otra cantidad" → "Opciones de compra"
        gap de la columna (1,25rem) + margen inferior de .ga-cantidad.
        El bloque de modalidad va dentro del <form>, así que entre .ga-cantidad y
        el formulario hay un gap entero de la columna.

     b) "Opciones de compra" → botones
        Este SÍ era de márgenes, porque los dos viven dentro del formulario y ahí
        no hay gap que valga. Sumaban el margen de .ga-modalidad y el de
        .ga-product__cta-buttons. Se añade además el margen que WooCommerce le
        pone a su propio .single_variation, que no es nuestro y no se veía.

     c) botones → sellos de confianza
        Otro gap entero de la columna MÁS el margin-bottom que WooCommerce le da
        a `form.cart` en su hoja (2em, unos 32px). Ese era el más grande de los
        tres y no estaba en ningún archivo de este tema.

   CÓMO SE CORRIGE: se baja el gap de la columna y se devuelve aire con márgenes
   propios SOLO donde hacía falta —la cabecera de la columna, donde el nombre y
   el precio sí querían respirar—. Así los tres bloques del final quedan
   encadenados sin apretar el título contra el precio.

   ⚠ EN MÓVIL ESTE gap NO EXISTE. A ≤860px las dos columnas pasan a
     `display: contents` y sus huecos los pone el row-gap de .ga-product__grid,
     que espacia TAMBIÉN la foto y el nombre. Ahí no se toca: bajarlo movería la
     ficha entera. Lo que sí mejora en móvil son los márgenes de este bloque, que
     se suman a ese row-gap igual que aquí.
   ============================================================================= */

/* El gap baja a un mínimo común y CADA hueco que necesite más se lo gana con su
   propio margen. Es al revés de como estaba: antes el contenedor repartía un
   hueco generoso a todos y no había forma de quitárselo a los de abajo, porque un
   margen del hijo solo puede SUMAR al gap, nunca restarle. Poniendo el suelo bajo
   y subiendo donde hace falta, se controla hueco por hueco.

   Los dos que se quieren apretados —el bloque de compra contra la franja de
   sellos— se quedan con este 0,35rem y nada más. */
.ga-product-single:not(.ga-product-single--eventos) .ga-product__purchase {
    gap: 0.35rem;
}


/* =============================================================================
   LOS DOS HUECOS QUE SEGUÍAN SIN MOVERSE — LO QUE FALTABA
   =============================================================================
   Los ajustes de más arriba se quedaron cortos porque cada hueco tenía un
   sumando MÁS que no estaba mirado. En los dos casos era el mismo tipo de pieza:
   un `gap` de un contenedor intermedio, que no se ve al leer los márgenes de los
   bloques implicados porque no pertenece a ninguno de los dos.

   a) DESCRIPCIÓN CORTA → ACORDEÓN (columna de la foto)
      Se había puesto a cero el margen del acordeón y quitado el filete y el
      relleno inferior de la descripción, y aun así quedaban 2rem. Faltaban:

        · gap de .ga-product__gallery ............... 1rem
        · padding-top del primer botón del acordeón . 1rem

      El primero es el hueco que la columna abre entre TODOS sus hijos, y el
      segundo es el aire interno del propio botón, que separa su texto del filete
      de arriba. Ninguno de los dos es un margen, y por eso no aparecían al
      buscar márgenes.

   b) BOTONES → FRANJA DE SELLOS (columna de compra)
      El gap de la columna ya estaba en 0,35rem y el margen del formulario a
      cero. Lo que faltaba estaba DENTRO del formulario:

        · gap de .woocommerce-variation-add-to-cart . 1rem
        · margin-top de .ga-product__express ........ 0,5rem

      Ese contenedor es un flex y su gap separa los botones de lo que WooCommerce
      o la pasarela pinten después —los botones de pago exprés—, así que el hueco
      se abre por debajo de "Añadir al carrito" aunque el formulario no tenga
      ningún margen.

   ⚠ Y HAY UNA TERCERA POSIBILIDAD QUE NO PUEDO DESCARTAR DESDE AQUÍ: que el
     archivo no esté llegando al servidor. Es la tercera vez seguida que un cambio
     "no surte efecto" estando escrito en el archivo local. Antes de dar por bueno
     este bloque conviene comparar fechas en FileZilla y purgar la caché.
   ============================================================================= */

/* ——— (a) LA COLUMNA DE LA FOTO ———
   El gap baja a la mitad. Afecta también a la separación entre la foto y la
   descripción corta, que estaba igual de holgada, así que la columna entera gana
   en compacidad. */
.ga-product-single:not(.ga-product-single--eventos) .ga-product__gallery {
    gap: 0.5rem;
}

/* Y el aire de encima del PRIMER título del acordeón, que es el que cuenta para
   este hueco. Los demás conservan su relleno: es lo que da ritmo a la lista y
   separa un apartado del siguiente. */
.ga-product-single .ga-product__acordeon-col .ga-accordion__item:first-child .ga-accordion__trigger {
    padding-top: 0.5rem;
}

/* ——— (b) EL FINAL DE LA COLUMNA DE COMPRA ———
   Todo lo que va por debajo de los botones pasa al mismo ritmo que la columna
   (0,35rem), de modo que la franja de sellos queda tan pegada por arriba como lo
   está el resto de la columna entre sí. */
.ga-product-single:not(.ga-product-single--eventos) .woocommerce-variation-add-to-cart {
    gap: 0.35rem;
}

.ga-product-single:not(.ga-product-single--eventos) .ga-product__express {
    margin-top: 0.35rem;
}

/* ——— LA FRANJA DE SELLOS SE SEPARA DE LOS BOTONES ———
   Aquí este margen estuvo a CERO, y con el gap de la columna en 0,35rem la franja
   quedaba a menos de seis píxeles del botón de "Añadir al carrito": los dos se
   leían como una sola pieza, como si los sellos fueran parte del botón. Y no lo
   son: el botón es la acción y la franja es la garantía que la acompaña.

   Sube a --ga-space-sm, que es la medida de separación del proyecto y no un número
   suelto. El hueco real es la SUMA del gap y este margen —en un contenedor flexible
   los márgenes del hijo se suman al gap, no lo absorben—, así que queda en 1,35rem
   en escritorio.

   🔴 SE PONE AQUÍ Y NO EN EL gap DE LA COLUMNA, y esa es la parte importante. El
   gap separa a TODOS los hijos por igual: subirlo habría abierto también el hueco
   entre el selector de cantidad y los botones, que está ajustado a conciencia y que
   el encargo pedía expresamente no tocar. Un margen solo afecta a quien lo lleva.

   ⚠ EN MÓVIL LA CUENTA ES OTRA Y SALE BIEN SOLA. Por debajo de 860px las columnas
     pasan a display: contents y el hueco lo pone el row-gap de la rejilla, que ya
     es de 1rem; sumado a este margen da 2rem. Suena a mucho más que en escritorio,
     pero es la misma proporción: allí el ritmo de la columna es 0,35rem y el hueco
     queda en casi cuatro veces el ritmo; aquí el ritmo es 1rem y queda en el doble.
     Por eso vale el MISMO valor para los dos y no hacen falta dos números. */
.ga-product-single:not(.ga-product-single--eventos) .ga-product__trust-band {
    margin-top: var(--ga-space-sm);
}

/* El aire que se le devuelve a la cabecera: sin esto, el nombre del producto
   quedaría pegado al precio. Se suma al gap, así que el hueco real es la suma de
   los dos. */
.ga-product-single:not(.ga-product-single--eventos) .ga-product__price-wrap {
    margin-top: 0.5rem;
}

/* ——— LA LÍNEA DE DISPONIBILIDAD, CON AIRE POR LOS DOS LADOS ———
   Es un dato corto entre dos bloques grandes —el precio arriba, "Elige la
   cantidad" abajo— y pegada a los dos se leía como parte de ellos. Es el único
   bloque de la columna que pide separación por arriba Y por abajo; el resto se
   encadena.

   ⚠ EL MARGEN ES EL SITIO CORRECTO PARA TOCAR ESTO, aunque el hueco lo formen dos
     cosas. La columna es un flex con gap: 0,35rem, y en un contenedor flexible el
     margen del hijo NO se solapa con el gap, se SUMA. Así que subir el margen sí
     mueve el hueco, y lo mueve solo aquí: el gap sigue valiendo lo mismo para
     todos los demás bloques, que no se enteran.

   Arriba va algo más aire que abajo —1,2 frente a 0,9— porque encima tiene el
   precio, que es la pieza de más peso visual de la columna y necesita más
   distancia para no absorber esta línea. Con el gap sumado, el hueco real es de
   ~1,55rem por arriba y ~1,25rem por abajo. */
.ga-product-single:not(.ga-product-single--eventos) .ga-product__stock {
    margin-top: 1.2rem;
    margin-bottom: 0.9rem;
}

/* .ga-cantidad ya no necesita separarse por su cuenta: con el gap reducido, el
   hueco hasta "Opciones de compra" queda en 0,6rem. */
.ga-product-single:not(.ga-product-single--eventos) .ga-cantidad,
.ga-product-single--modalidad .ga-cantidad {
    margin-bottom: 0;
}

/* 🔴 EL MARGEN DE form.cart NO ES NUESTRO: lo pone la hoja de WooCommerce, y por
   eso no aparecía por ninguna parte al buscarlo en este tema. Son 2em bajo el
   formulario, justo entre los botones de compra y la franja de sellos. Se anula
   aquí, acotado a la ficha propia: en el carrito y en el resto de pantallas de
   WooCommerce sigue haciendo su trabajo. */
.ga-product-single:not(.ga-product-single--eventos) form.cart,
.ga-product-single:not(.ga-product-single--eventos) form.variations_form {
    margin-bottom: 0;
}

/* Lo mismo dentro del formulario: el contenedor de la variación y su envoltorio
   traen márgenes de WooCommerce que aquí solo abren hueco, porque el precio que
   llevan dentro va oculto y no se ve nada de lo que separan. */
.ga-product-single:not(.ga-product-single--eventos) .single_variation_wrap,
.ga-product-single:not(.ga-product-single--eventos) .single_variation_wrap .single_variation,
.ga-product-single:not(.ga-product-single--eventos) .single_variation_wrap .woocommerce-variation {
    margin-top: 0;
    margin-bottom: 0;
}


/* =============================================================================
   SELLOS DE CONFIANZA EN VERDE OSCURO (fichas que NO son de Eventos)
   =============================================================================
   La franja iba a dos verdes: el título en verde oliva oscuro y el icono y la
   línea pequeña en --ga-verde-montanas, el verde claro de subtítulos. Eso hacía
   que la franja entera se leyera clara y descolorida.

   Ahora los tres elementos comparten el verde oscuro de marca. La jerarquía
   entre el título y su línea pequeña la siguen marcando el TAMAÑO y la OPACIDAD,
   no un color distinto, que es lo que se pidió: la línea pequeña es más pequeña
   y algo más tenue, pero del mismo verde.

   ⚠ Acotado fuera de Eventos: allí la franja dice otra cosa —envío incluido, sin
     devolución por ser a medida— y tiene sus propios ajustes en main.css. */

/* ——— LOS TRES SELLOS, REPARTIDOS Y CENTRADOS ———
   🔴 POR QUÉ SE VEÍAN DESCENTRADOS, QUE NO ERA UN PROBLEMA DE MÁRGENES. Cada
   sello ya se llevaba un tercio exacto de la franja (flex: 1), pero DENTRO de su
   tercio el contenido se apoyaba a la izquierda. Como los tres textos miden
   distinto —"Envío" es mucho más corto que "Pago seguro"—, cada bloque dejaba un
   hueco distinto a su derecha y el conjunto se leía torcido, con más aire al
   final de la franja que al principio.

   Centrando el contenido dentro de cada tercio, el sobrante se reparte por igual
   a los dos lados de cada sello y la franja queda simétrica.

   align-items: center ya venía puesto y es lo que alinea el icono con su texto;
   al ser el mismo en los tres, los tres se leen igual. */
.ga-product-single:not(.ga-product-single--eventos) .ga-trust-item {
    justify-content: center;
}


/* =============================================================================
   EL ACORDEÓN, EN LA COLUMNA DE LA FOTO
   =============================================================================
   Se ha mudado de su franja a lo ancho a la columna izquierda, bajo la
   descripción corta. Conserva TODAS sus clases —.ga-accordion__item, __trigger,
   __body, __inner— y por tanto su aspecto y su JS: lo único que cambia es dónde
   está y el ancho del que dispone. Este bloque solo ajusta lo que se resiente al
   pasar de una franja de 820px a una columna de la mitad.

   .ga-product__accordion-zone ya no existe en el marcado —era la franja crema y
   su relleno— y su regla se ha quedado sin nada a lo que aplicarse.
   ============================================================================= */

/* ——— PEGADO A LA DESCRIPCIÓN CORTA ———
   El hueco eran 2rem: 1rem del gap de la columna más 1rem de margen propio. Se
   queda solo con el gap. */
.ga-product-single .ga-product__acordeon-col {
    margin-top: 0;

    /* 🔴 FONDO OPACO EXPLÍCITO, Y NO ES DECORACIÓN. Un bloque de texto sin fondo
       propio dentro de una columna que el navegador promociona a su propia capa
       —lo que hace con position: sticky— se repinta al desplazarse sin saber qué
       tiene detrás, y ahí es donde el texto sale lavado o directamente blanco.
       Declarando el fondo, el navegador sabe sobre qué pinta y usa el suavizado
       bueno. Es blanco sobre blanco: no se ve nada nuevo, y quita el fallo. */
    background-color: var(--ga-blanco);
}

/* 🔴 LA COLUMNA DEJA DE SER STICKY EN CUANTO LLEVA ACORDEÓN, Y ESTA ES LA
   CORRECCIÓN DE FONDO DEL TEXTO BLANCO.

   El `position: sticky` de .ga-product__gallery se puso cuando esa columna era
   solo la foto: corta, y merecía la pena dejarla a la vista mientras se recorría
   la columna de compra. Con el acordeón dentro ya no es corta —suele pasar de
   largo a la de compra—, así que sticky no aporta nada: no hay recorrido que
   acompañar.

   Lo que sí aporta es el problema. Un elemento sticky es lo único de esta ficha
   cuyo pintado depende del scroll: el navegador lo saca a una capa aparte y la
   recompone en cada desplazamiento. Quitándolo desaparece la capa, y con ella la
   única vía por la que el texto podía repintarse mal.

   :has() acota el cambio a las fichas que de verdad llevan acordeón; donde no lo
   haya, la columna sigue siendo sticky como siempre. Y en Eventos ni entra: allí
   el acordeón está vacío y este elemento no existe. */
.ga-product-single .ga-product__gallery:has(.ga-product__acordeon-col) {
    position: static;
}

/* 🔴 EL COLOR DE LOS TÍTULOS QUEDA CLAVADO, PASE LO QUE PASE.
   Además del color se fija -webkit-text-fill-color, que es una propiedad aparte
   y MANDA SOBRE color cuando existe: hay técnicas de esta misma web —los brillos
   de los titulares— que la ponen en transparent para dejar ver un degradado
   detrás. Si una de ellas llegara aquí por herencia, el título se volvería
   invisible y `color` no lo salvaría. Declarándola, ninguna puede.

   Va sobre el botón Y sobre su span: si el color se hereda, basta con el botón;
   si algo se lo pusiera al span directamente, un valor heredado no gana. */
.ga-product-single .ga-product__acordeon-col .ga-accordion__trigger,
.ga-product-single .ga-product__acordeon-col .ga-accordion__trigger > span {
    color: var(--ga-verde-oliva-oscuro);
    -webkit-text-fill-color: var(--ga-verde-oliva-oscuro);
    /* Sin degradado detrás que pueda quedar a la vista si algo activara el
       recorte del texto. */
    background: none;
    opacity: 1;
}

/* El dorado al pasar el ratón se conserva: es un cambio de color y nada más. */
.ga-product-single .ga-product__acordeon-col .ga-accordion__trigger:hover,
.ga-product-single .ga-product__acordeon-col .ga-accordion__trigger:hover > span,
.ga-product-single .ga-product__acordeon-col .ga-accordion__trigger:focus-visible,
.ga-product-single .ga-product__acordeon-col .ga-accordion__trigger:focus-visible > span {
    color: var(--ga-naranja-apagado);
    -webkit-text-fill-color: var(--ga-naranja-apagado);
}


/* =============================================================================
   LO MISMO PARA LAS PREGUNTAS FRECUENTES — EL TÍTULO SE VEÍA BLANCO
   -----------------------------------------------------------------------------
   🔴 EL SÍNTOMA: la pregunta salía BLANCA sobre el fondo blanco de la sección —o
   sea, invisible— y solo aparecía, en dorado, mientras se le pasaba el ratón por
   encima. Justo al revés de lo que uno espera de un fallo de hover.

   POR QUÉ. Es el mismo caso que el acordeón de aquí arriba y el mismo que en su día
   dejó invisible la X del carrito, así que ya son tres:

     · El VERDE de reposo lo pone .ga-accordion__trigger (más arriba en este
       archivo). Puntúa 0-1-0 y NO lleva !important.
     · El DORADO del ratón lo pone main.css, y ese SÍ lleva !important.
     · El bloque de main.css que defiende al botón de Astra anula con !important el
       fondo, el borde y la sombra... pero NO el color.

   Resultado: en reposo, el color del botón que hereda del tema padre le gana sin
   esfuerzo a un 0-1-0 y lo deja en blanco; al pasar el ratón, el !important del
   dorado se impone y el texto reaparece. Encaja con el síntoma exactamente.

   ⚠ HIPÓTESIS DESCARTADAS, COMPROBADAS UNA A UNA, no por eliminación perezosa:
     · Recorte de degradado sobre el texto: en este archivo hay tres bloques con
       background-clip: text, y los tres van sobre .ga-tc__rotulo y
       .ga-sellos-ficha__texto. Ninguno es ancestro del acordeón ni le llega.
     · Variable sin declarar: --ga-verde-oliva-oscuro, --ga-naranja-apagado,
       --ga-transition-fast y --ga-font-body están declaradas las cuatro.
     · Estado mal repartido: no hay ninguna regla propia que ponga blanco a este
       botón, ni con su clase ni con un selector de <button>. Se buscó en los dos
       archivos de CSS del tema.

   EL ARREGLO ES EL QUE YA FUNCIONA AHÍ ARRIBA, no uno nuevo: color fijado a 0-3-0
   —que gana por ESPECIFICIDAD, sin un solo !important— y, con él,
   -webkit-text-fill-color, que es una propiedad aparte y MANDA SOBRE color cuando
   existe: si alguna técnica de brillo de esta web llegara aquí por herencia y la
   pusiera en transparent, `color` no salvaría el texto y esto sí.

   Va sobre el botón Y sobre su span: si el color se hereda basta con el botón, pero
   si algo se lo pusiera al span directamente, un valor heredado no gana.

   ⚠ NO ALCANZA A LA FICHA DE EVENTOS y no hace falta acotarlo más: allí las
     preguntas frecuentes son <details>/<summary> nativos y no existe ni un solo
     .ga-accordion__trigger, así que este selector no tiene a quién aplicarse. La
     sección de aquí se pinta en la rama else de if ( $ga_es_eventos ), que se
     calcula con function_exists( 'ga_eventos_es_personalizable' ).
   ============================================================================= */

.ga-product-single .ga-product__faq .ga-accordion__trigger,
.ga-product-single .ga-product__faq .ga-accordion__trigger > span {
    color: var(--ga-verde-oliva-oscuro);
    -webkit-text-fill-color: var(--ga-verde-oliva-oscuro);
    /* Sin degradado detrás que pueda quedar a la vista si algo activara el recorte
       del texto: aquí no queremos brillo, solo color macizo. */
    background: none;
    opacity: 1;
}

/* Ratón, foco de teclado Y PREGUNTA ABIERTA, los tres en dorado.
   El estado abierto se lee de aria-expanded, que es lo que ya alterna el JS del
   acordeón —junto con la clase .is-open del contenedor—, así que no hace falta
   tocar ni una línea de JavaScript ni inventar una clase nueva. Y al colgar del
   atributo, la pregunta abierta se queda dorada aunque el ratón se vaya a otra
   parte de la página, que es lo que se pedía.

   Ninguno de los tres estados cambia tamaño ni posición: solo el color. El chevron
   los sigue solo, porque su trazo va en currentColor. */
.ga-product-single .ga-product__faq .ga-accordion__trigger:hover,
.ga-product-single .ga-product__faq .ga-accordion__trigger:hover > span,
.ga-product-single .ga-product__faq .ga-accordion__trigger:focus-visible,
.ga-product-single .ga-product__faq .ga-accordion__trigger:focus-visible > span,
.ga-product-single .ga-product__faq .ga-accordion__trigger[aria-expanded="true"],
.ga-product-single .ga-product__faq .ga-accordion__trigger[aria-expanded="true"] > span {
    color: var(--ga-naranja-apagado);
    -webkit-text-fill-color: var(--ga-naranja-apagado);
}

/* Por si algún día alguien le pusiera la clase de la animación de entrada a un
   ancestro: esa animación arranca en opacidad 0, y en un bloque de consulta como
   este no aporta nada más que el riesgo de quedarse a medias. */
.ga-product-single .ga-product__acordeon-col.ga-animate,
.ga-product-single .ga-product__acordeon-col .ga-animate {
    opacity: 1;
    transform: none;
}

/* 🔴 EL TÍTULO TIENE QUE PODER PARTIRSE, Y ESTO NO ES ESTÉTICA. El botón es un
   flex con el texto a un lado y el chevrón al otro; en una columna estrecha,
   "Información nutricional" no cabe en una línea, y un elemento de un flex NO
   encoge por debajo del ancho de su contenido salvo que se le diga. Sin esto, el
   título empujaría al chevrón fuera de la caja.

   flex: 1 1 auto le da permiso a encoger y overflow-wrap parte la palabra si
   hiciera falta —a 360px "nutricional" sola ya va justa—. Nada de min-width:
   el ancho mínimo se corta así. */
.ga-product-single .ga-product__acordeon-col .ga-accordion__trigger > span:first-child {
    flex: 1 1 auto;
    overflow-wrap: break-word;
    /* text-wrap: balance viene de la regla general de títulos y aquí dejaría las
       dos líneas cortadas a media caja (🪤 nº 16). */
    text-wrap: wrap;
}

/* El chevrón nunca encoge ni se parte: es lo que marca que el apartado se abre. */
.ga-product-single .ga-product__acordeon-col .ga-accordion__chevron {
    flex: 0 0 auto;
}

/* Un punto menos de letra y algo menos de alto: en la columna estrecha los cinco
   títulos seguidos se comían mucho sitio. Sigue siendo la misma tipografía. */
.ga-product-single .ga-product__acordeon-col .ga-accordion__trigger {
    padding: 1rem 0;
    font-size: 0.9rem;
}

/* Las tablas del interior son el punto delicado: una <table> NO encoge por debajo
   del ancho mínimo de su contenido y en esta columna se saldría (🪤 nº 1). Se le
   deja desbordar HACIA DENTRO, con su propio scroll horizontal, que es lo único
   que no arrastra a la página entera.

   overflow-x en un contenedor acotado y nunca en html/body. */
.ga-product-single .ga-product__acordeon-col .ga-ficha-table {
    display: block;
    overflow-x: auto;
    /* Sin esto, la tabla en block se queda con el ancho de su contenido y vuelve
       a desbordar en vez de scrollear. */
    max-width: 100%;
}

.ga-product-single:not(.ga-product-single--eventos) .ga-trust-item svg {
    color: var(--ga-verde-oliva-oscuro);
}

.ga-product-single:not(.ga-product-single--eventos) .ga-trust-item strong {
    color: var(--ga-verde-oliva-oscuro);
}

/* La opacidad no cambia el tamaño ni la posición: solo aparta un poco esta línea
   sin sacarla del mismo color. */
.ga-product-single:not(.ga-product-single--eventos) .ga-trust-item span {
    color: var(--ga-verde-oliva-oscuro);
    opacity: 0.75;
}


/* =============================================================================
   LA COLUMNA DE COMPRA, CON LA TIPOGRAFÍA DE LA FICHA DE EVENTOS
   =============================================================================
   🔴 POR QUÉ SE VEÍA "DEMASIADO NEGRA": por el COLOR, no por el peso. Los
   encabezados y los títulos de las tarjetas se habían ido poniendo en
   --ga-negro-suave (#1a1a14), un casi negro, mientras que TODA la columna de
   Eventos usa un solo color para el texto: --ga-verde-oliva-oscuro (#4a4a2f).
   Ese verde oliva es bastante más cálido y se integra con el resto de la ficha;
   el negro se despegaba y hacía que todo pareciera más pesado.

   LA ESCALA DE EVENTOS, que es la que se copia aquí (main.css, bloque
   .ga-eventos-perso):

     · título de bloque .... Cormorant, clamp(1.15rem, 1.6vw, 1.4rem), peso 600
     · etiqueta ............ Inter, --ga-text-sm, peso medio (500)
     · texto secundario .... Inter, --ga-text-xs, MISMO color + opacity 0.7

   Los tres en --ga-verde-oliva-oscuro. Fíjate en el tercero: el texto secundario
   NO cambia de color, se aparta con TAMAÑO y OPACIDAD. Eso es lo que hace que la
   columna se lea como una sola pieza en vez de como cuatro tonos distintos.

   ⚠ ESTO DESHACE UN CAMBIO ANTERIOR A PROPÓSITO. Los encabezados habían pasado a
     Inter porque en Cormorant se leían flojos; la escala de Eventos usa Cormorant
     y aquí manda esa, que es el objetivo: que las dos fichas se vean de la misma
     familia. El tamaño de arriba es mayor que el que tenía, así que no vuelve a
     quedarse corto.

   ⚠ NO SE TOCA NADA DE EVENTOS. Aquí solo se escriben clases que existen
     únicamente fuera de Eventos (.ga-cantidad-, .ga-modalidad-).
   ============================================================================= */

/* ——— ENCABEZADOS DE BLOQUE ———
   🔴 ESTA ES LA REGLA QUE DE VERDAD VISTE A ESTOS TEXTOS: va después de la de más
   arriba, con la misma especificidad, así que es la suya la que se ve.

   .ga-textil-unidad —"Solo hay 15 unidades…", encima del selector de talla de la
   camiseta— se añade aquí para que se lea COMO SU HERMANO y no como una nota al pie:
   la misma tipografía, el mismo cuerpo, el mismo grosor, el mismo interlineado y el
   mismo color que el "Elige tu talla" que tiene justo debajo. Y se consigue
   COMPARTIENDO ESTA MISMA DECLARACIÓN, no copiando sus valores: el día que se retoque
   el rótulo, la frase se retoca con él sin que nadie tenga que acordarse.

   ⚠ NO ALCANZA A EVENTOS, como el resto de este bloque: .ga-textil-unidad solo la
     pinta la plantilla dentro de la rama de la prenda, que lleva su propio
     ! $ga_es_eventos. */
.ga-product-single .ga-cantidad__titulo,
.ga-product-single .ga-modalidad__titulo,
.ga-product-single .ga-textil-unidad {
    font-family: var(--ga-font-display);
    font-size: clamp(1.15rem, 1.6vw, 1.4rem);
    font-weight: 600;
    line-height: 1.25;
    color: var(--ga-verde-oliva-oscuro);
}

/* ——— TÍTULOS DE LAS TARJETAS ———
   La receta de la etiqueta de Eventos —Inter, peso medio, verde oliva— un
   escalón por encima en tamaño, porque aquí no son una etiqueta sobre un campo
   sino la opción que se elige. */
.ga-product-single .ga-cantidad__texto,
.ga-product-single .ga-modalidad__nombre {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-base);
    /* Peso normal: son opciones a elegir, no titulares. Este valor está repetido
       en las reglas propias de cada bloque, y las tres deben coincidir (ver el
       aviso en .ga-cantidad__texto). */
    font-weight: 400;
    color: var(--ga-verde-oliva-oscuro);
}

/* ——— ETIQUETAS ———
   "Entrega cada:" es exactamente una etiqueta de campo: misma receta que en
   Eventos, sin cambiar ni el tamaño. */
.ga-product-single .ga-modalidad__freq-txt {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    font-weight: var(--ga-weight-medium);
    color: var(--ga-verde-oliva-oscuro);
}

/* ——— TEXTOS SECUNDARIOS ———
   Mismo color que todo lo demás; lo que los aparta es el tamaño y la opacidad.
   "Otra cantidad" es la salida secundaria del bloque de cantidad y se comporta
   igual que una ayuda. */
.ga-product-single .ga-cantidad__fila--otra .ga-cantidad__texto {
    font-size: var(--ga-text-sm);
    font-weight: 400;
    color: var(--ga-verde-oliva-oscuro);
    opacity: 0.7;
}

/* (Aquí vivía el estilo del precio de cada tarjeta. Los precios se han quitado
   del bloque, así que la regla se va con ellos: el importe lo lleva ahora solo el
   precio de la cabecera.) */

/* ——— LA FRASE DE LA SUSCRIPCIÓN ———
   ⚠ ESTA ES LA ÚNICA QUE SE APARTA DE LA PALETA DE EVENTOS, y es una petición
     expresa: negro apagado en vez del verde oliva del resto. Se consigue con el
     casi negro de marca y opacidad, no con un gris inventado, así que sigue
     siendo un color del sistema y no destaca por encima del nombre de la opción.

     El respaldo de --ga-negro-suave es obligatorio: la variable está en la paleta
     del proyecto pero no llega a declararse en el :root de style.css, y un var()
     que no resuelve hace que la declaración entera se descarte y el color pase a
     heredarse —que en esta web acaba siendo el dorado de los enlaces de Astra—. */
/* (El color de la frase NO se escribe aquí. Se escribía, y no servía de nada:
   más abajo hay otra regla con el mismo selector que ganaba por ir después. Está
   corregida allí, en el bloque de "Opciones de compra", que es su sitio. Dejarla
   también aquí solo daría dos sitios donde buscar la próxima vez.) */

/* Borde de 2px SIEMPRE, en las dos tarjetas y en todos sus estados: lo único
   que cambia es el color. Si apareciera al marcar, la tarjeta crecería 4px y
   empujaría a la de abajo cada vez que se cambia de opción.

   position: relative es obligatorio, no decorativo: el radio va en posición
   absoluta y sin un ancestro posicionado se colocaría respecto a la página, de
   modo que al llegarle el foco por teclado el navegador saltaría hasta allí. */
.ga-product-single .ga-modalidad__tarjeta {
    position: relative;
    display: block;
    box-sizing: border-box;
    margin: 0;
    padding: 1.05rem 1.15rem;
    background-color: var(--ga-blanco);
    border: 2px solid var(--ga-amarillo-pastel);
    /* Mismo 10px a prueba que las filas de .ga-cantidad: los dos bloques van
       juntos en la misma columna y con radios distintos se verían desparejados.
       Ver el aviso completo allí. */
    border-radius: 10px;
    cursor: pointer;
    transition: border-color var(--ga-transition-normal),
                background-color var(--ga-transition-normal);
}

.ga-product-single .ga-modalidad__tarjeta:hover {
    border-color: var(--ga-naranja-apagado);
}

.ga-product-single .ga-modalidad__tarjeta:has(.ga-modalidad__radio:checked) {
    border-color: var(--ga-naranja-apagado);
    background-color: var(--ga-naranja-claro);
}

/* Halo de foco en box-shadow: se pinta FUERA de la caja, así que no ocupa sitio
   ni mueve nada. Dos capas —hueco blanco y anillo dorado— para que se distinga
   también sobre la tarjeta ya marcada, que tiene el borde de ese mismo dorado. */
.ga-product-single .ga-modalidad__tarjeta:has(.ga-modalidad__radio:focus-visible) {
    box-shadow: 0 0 0 2px var(--ga-blanco),
                0 0 0 4px var(--ga-naranja-apagado);
}

/* 🔴 EL RADIO SE OCULTA A LA VISTA PERO SIGUE VIVO Y OPERATIVO. Ni display:none
   ni visibility:hidden: los dos lo sacan del recorrido del tabulador y del
   lector de pantalla, y las tarjetas dejarían de poder usarse sin ratón. Es la
   técnica de accesibilidad de siempre —1px recortado—, la misma que usa el
   bloque de cantidad. */

/* ——— DÓNDE SE COLOCA EL CÍRCULO EN LAS TARJETAS DE COMPRA ———
   ⚠ ESTO ES POSICIÓN, NO CENTRADO. El punto de dentro lo sigue centrando el flex de
     .ga-radio, igual que en las filas de cantidad: aquí solo se decide dónde va el
     aro dentro del recuadro. Por eso el mecanismo de centrado sigue siendo uno solo
     para las cuatro opciones.

   🔴 EN absolute Y NO EN EL FLUJO, por la ALTURA a la que tiene que quedar. El
   recuadro no es una línea: lleva el título, debajo una frase explicativa y, en el
   de la suscripción, una etiqueta y un desplegable. En el flujo, el círculo
   quedaría centrado sobre TODO ese bloque, o sea a la altura de la explicación en
   vez de la del título.

   Fuera del flujo se le puede clavar la altura de la primera línea:
       1,05rem  el relleno superior del recuadro
     + 0,15rem  la mitad de lo que le sobra a la línea del título sobre el círculo
                (título de 1rem con interlineado 1,3 → línea de 1,3rem; círculo de
                1rem; (1,3 − 1) / 2 = 0,15rem)
     = 1,2rem
   El recuadro ya venía con position: relative, así que no ha hecho falta tocarlo.

   ⚠ En las filas de cantidad NO hace falta nada de esto: allí la fila es flex con
     align-items: center y una sola línea de texto, así que el círculo se alinea
     solo. */
/* ⚠ AQUÍ HABÍA UNA REGLA QUE COLOCABA EL CÍRCULO EN absolute, a 1,2rem del techo del
     recuadro, con esa altura calculada a mano. SE HA RETIRADO: el círculo ya no
     cuelga del recuadro, está dentro de la línea del título junto a él, así que se
     alinea solo y no hay ninguna coordenada que mantener. */

/* El hueco para el círculo. Va en el CUERPO del recuadro y no en el recuadro
   mismo, para que solo se aparte el contenido y el borde exterior se quede donde
   estaba: el recuadro no cambia ni de ancho ni de sitio, y sigue alineado con el
   desplegable de cantidad de arriba.

   1,75rem = 1rem del círculo + 0,75rem de aire hasta el texto. */
/* ——— LO QUE VA DEBAJO DEL TÍTULO, ALINEADO CON ÉL ———
   Antes el recuadro entero llevaba un padding-left para dejarle sitio al círculo,
   que iba flotando en absolute. Ahora el círculo está DENTRO de la línea del título,
   así que ese relleno sobra: aplicarlo empujaría también el título y lo dejaría
   más a la derecha de lo que estaba.

   Lo que sí hace falta es que la nota, el desplegable de frecuencia y el aviso de
   confianza arranquen bajo el TEXTO del título y no bajo el círculo. Por eso el
   sangrado va sobre los hermanos de la línea del título y no sobre el recuadro.

   La medida no es un número inventado: es lo que ocupa el círculo más el hueco que
   .ga-opcion abre entre él y su texto. Si cambiara cualquiera de los dos, esto
   sigue cuadrando. */
.ga-product-single .ga-modalidad__cuerpo > :not(.ga-modalidad__linea) {
    padding-left: calc(1rem + var(--ga-space-xs));
}

/* El gap sube un punto para dar el aire que pedía la píldora respecto a la nota
   de debajo. Va aquí y no como margen de la fila porque este contenedor es una
   rejilla: su gap se abre entre TODAS sus filas, así que el mismo valor separa el
   renglón del nombre de la nota y la nota del desplegable de frecuencia. Un
   margen suelto en la fila descuadraría ese ritmo. */
.ga-product-single .ga-modalidad__cuerpo {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.65rem;
}

/* Nombre a la izquierda y etiqueta pegada al borde derecho.

   🔴 align-items: center Y NO baseline, Y ESTE ERA EL FALLO DE LA PÍLDORA CAÍDA.
   Con `baseline` el navegador alinea las LÍNEAS BASE del texto: la del nombre y
   la del texto de dentro de la píldora. Pero la píldora tiene relleno y borde
   propios, así que para que su texto quede a la altura del otro tiene que bajar
   toda la caja —justo el relleno superior—, y por eso se veía descolgada hacia la
   nota. Con `center` lo que se alinea son las dos cajas por su centro, que es lo
   que se busca: el nombre y la píldora centrados entre sí en el mismo renglón.

   El flex-wrap es la red de seguridad de 360px: si la píldora no cupiera al lado
   del nombre, baja de línea en lugar de desbordar la tarjeta. Al bajar sola queda
   a la izquierda, que es lo correcto cuando ya no hay nada con lo que alinearse. */
.ga-product-single .ga-modalidad__linea {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

/* Peso normal y el mismo verde oliva del resto de la columna: es una opción a
   elegir, igual que "1 botella" o "2 botellas", y no tiene por qué pesar más que
   ellas. El peso y el color van juntos aquí para que no se repartan entre dos
   reglas —ese reparto es el que hizo que un cambio de color de este mismo archivo
   no llegara a verse—. */
.ga-product-single .ga-modalidad__nombre {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-base);
    font-weight: 400;
    line-height: 1.3;
    color: var(--ga-verde-oliva-oscuro);
    overflow-wrap: break-word;
}

/* ——— LAS PÍLDORAS DE LAS TARJETAS ———
   🔴 :empty SIGUE HACIENDO FALTA aunque hoy las dos lleven texto. Un <span> vacío
   en un contenedor flexible sigue contando como hijo: aunque no mida nada de
   ancho, el `gap` de la línea se abre delante de él y queda un espacio suelto
   detrás del nombre. Si algún día se vacía una, no deja rastro. */
.ga-product-single .ga-modalidad__etiqueta:empty {
    display: none;
}

/* La píldora de "Envío gratis": verde oscuro de marca con la letra clara. Es la
   única de la ficha con fondo fuerte, y ese contraste es el mensaje.

   El texto se escribe en la plantilla en minúsculas y sube a mayúsculas aquí:
   así el marcado se lee natural y, si mañana hay que quitar las versalitas, se
   toca una línea de CSS y no el texto.

   white-space: nowrap para que "Envío gratis" no se parta en dos dentro de la
   píldora; si no cabe al lado del nombre, lo que baja de línea es la píldora
   entera, que lo resuelve el flex-wrap de la fila.

   (Aquí vivía además una variante neutra, la de "Solo esta vez". Esa etiqueta se
   ha quitado de la tarjeta de compra única y su regla se va con ella: no la usaba
   nada más.) */
.ga-product-single .ga-modalidad__etiqueta {
    display: inline-block;
    padding: 0.2rem 0.5rem;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    line-height: 1.4;
    text-transform: uppercase;
    color: var(--ga-blanco);
    border: 1px solid transparent;
    border-radius: var(--ga-radius-sm);
    white-space: nowrap;

    /* ═══════════════════════════════════════════════════════════════════════
       EL BRILLO, CALCADO DEL BOTÓN DE CARRITO DE LA TIENDA
       ═══════════════════════════════════════════════════════════════════════
       Mismo mecanismo que .ga-home-card__cart en main.css, pieza por pieza: un
       degradado con una banda de luz en el centro, el fondo ampliado al 250 % y
       una animación que SOLO mueve background-position.

       🔴 QUE SOLO SE ANIME background-position ES LO IMPORTANTE, no un detalle de
       eficiencia: es lo que garantiza que la píldora no cambie de tamaño ni de
       sitio mientras brilla. Un resplandor con box-shadow o un cambio de escala
       la moverían, y aquí eso además descolocaría el nombre de al lado, que
       comparte renglón con ella.

       Los dos colores van en variables locales: el degradado se construye a
       partir de ellas una sola vez y no hay que repetirlo si algún día cambia el
       verde. La banda de luz es ese mismo verde aclarado —el mismo tono que usa
       el botón del carrito—, para que se lea como un reflejo y no como otro
       color encima.

       background-color debajo del degradado: si un navegador no pintara la
       imagen, la píldora sigue siendo verde y la letra blanca sigue leyéndose. */
    --ga-pildora-fondo: var(--ga-verde-oliva-oscuro);
    --ga-pildora-luz:   #7a7a54;

    background-color: var(--ga-pildora-fondo);
    background-image: linear-gradient(
        100deg,
        var(--ga-pildora-fondo) 0%,
        var(--ga-pildora-fondo) 45%,
        var(--ga-pildora-luz) 50%,
        var(--ga-pildora-fondo) 55%,
        var(--ga-pildora-fondo) 100%
    );
    background-size: 250% 100%;
    background-repeat: no-repeat;
    background-position: 100% center;
    animation: ga-home-card-brillo 8s linear infinite;
}

/* Ahorro de movimiento: verde sólido, sin degradado ni animación. Mismo criterio
   que el botón del carrito de la tienda. */
@media (prefers-reduced-motion: reduce) {
    .ga-product-single .ga-modalidad__etiqueta {
        background-image: none;
        animation: none;
    }
}


/* ——— LA NOTA DE CONFIANZA DE LA SUSCRIPCIÓN ———
   Se lee como una aclaración, no como una tercera opción: un tinte verde muy
   suave, sin brillo —ese se queda solo en la píldora— y sin recuadro completo,
   que la convertiría visualmente en hermana de las dos tarjetas de arriba, que sí
   son seleccionables. Lo que la señala es el filete verde de la izquierda, el
   gesto de toda la vida para marcar un inciso. */
.ga-product-single .ga-modalidad__confianza {
    margin: 0;
    padding: 0.7rem 0.9rem;
    border: none;
    border-left: 2px solid var(--ga-verde-oliva-oscuro);

    /* ═══════════════════════════════════════════════════════════════════════
       VERDE MANZANA MUY CLARO — ⚠ ÚNICO COLOR DE LA FICHA FUERA DE LA PALETA
       ═══════════════════════════════════════════════════════════════════════
       🔴 ESTE VALOR NO SALE DE NINGUNA VARIABLE DE MARCA, Y ES UNA EXCEPCIÓN
       ELEGIDA A PROPÓSITO POR JAIME, no un descuido. Conviene saber por qué no se
       podía sacar de la paleta: los dos verdes que hay —#4a4a2f y #7f8649— son
       verdes OLIVA, muy poco saturados y tirando a tierra. Al diluirlos para
       hacer un fondo claro se van a un beige grisáceo; por mucho que se ajuste la
       proporción, nunca dan un verde fresco. Este tono es de otra familia.

       Antes aquí había un color-mix sobre --ga-verde-montanas con su respaldo en
       rgba. Ya no hace falta ninguno de los dos: un hexadecimal plano lo entiende
       cualquier navegador y no puede quedarse sin fondo.

       ⚠ SI ALGÚN DÍA ESTE VERDE SE USA EN OTRO SITIO, su lugar es el :root de
         style.css como una variable más de la paleta. Mientras sea el único punto
         de la web que lo lleva, tenerlo aquí escrito es más honesto que inflar la
         paleta con un color de un solo uso. */
    background-color: #f4fdf2;

    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    line-height: 1.5;
    /* El mismo verde oscuro que el filete de la izquierda: la caja entera queda
       en un solo color y se lee como una pieza.

       Contraste sobre el verde manzana del fondo (#f4fdf2): 8,7:1, muy por encima
       del 4,5:1 que pide un texto de este tamaño.

       Lo hereda también el <strong>, que no declara color propio: así "Precio
       cerrado:" no puede quedarse descolgado en otro color el día que se retoque
       este. */
    color: var(--ga-verde-oliva-oscuro);
    /* Corta el ancho mínimo del contenido sin min-width. */
    overflow-wrap: break-word;

    /* 🔴 PARTE DE OPACIDAD 0 Y ESE ES EL ESTADO DE REPOSO. La clase .is-visible
       —que ponen el PHP al cargar y el JS al cambiar de opción— es la que lo
       enciende. Solo se anima la opacidad: la altura no se toca, que es lo que
       daría el salto brusco al aparecer. */
    opacity: 0;
    /* ⚠ Los 150 ms tienen que coincidir con GA_MODALIDAD_FUNDIDO en
       assets/js/single-product.js: es el tiempo que espera el JS antes de sacar
       el mensaje del flujo. Si aquí fuera más, se cortaría a medio fundido. */
    transition: opacity 150ms ease;
}

.ga-product-single .ga-modalidad__confianza.is-visible {
    opacity: 1;
}

/* Solo "Precio cerrado:" en negrita: es el titular de la nota y lo que hace que
   se entienda de un vistazo sin leerla entera. El resto de la frase conserva su
   peso.

   Se declara el peso en vez de dejar el que trae el navegador para <strong>
   —que es 700— porque en Inter ese 700 al lado de un 400 canta demasiado en un
   texto pequeño. Con 600 destaca lo justo. El color es el mismo que el de la
   frase: lo que separa las dos palabras es el peso, nada más. */
.ga-product-single .ga-modalidad__confianza strong {
    font-weight: 600;
    color: inherit;
}

/* 🔴 SIN ESTA REGLA EL MENSAJE NO SE ESCONDERÍA. El navegador trae su propio
   [hidden] { display: none }, pero es una regla de la hoja del navegador y
   cualquier `display` que pongamos nosotros le gana. Aquí no declaramos ninguno
   —un <p> ya es de bloque—, así que hoy funcionaría igual; se deja escrito porque
   el día que alguien le ponga un display a esta caja, el mensaje se quedaría
   visible en la compra única sin que nada avisara. Es el mismo caso que el campo
   condicional del formulario de Contacto. */
.ga-product-single .ga-modalidad__confianza[hidden] {
    display: none;
}

/* 🔴 ESTA ES LA REGLA QUE MANDA SOBRE EL COLOR DE LA FRASE, Y POR QUÉ EL CAMBIO
   ANTERIOR NO SE VEÍA. Se había escrito el negro apagado en otra regla del bloque
   de tipografía, con el MISMO selector y por tanto la MISMA especificidad
   (0-2-0). Cuando dos reglas empatan en especificidad gana la que va DESPUÉS en
   el archivo, y aquella quedó ANTES que esta: el dorado de aquí seguía ganando.

   No era cuestión de subir la especificidad ni de poner un !important: bastaba
   con corregir el color donde de verdad se decide, que es esta línea. */
.ga-product-single .ga-modalidad__nota {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    line-height: 1.5;
    color: var(--ga-negro-suave, #1a1a14);
    opacity: 0.65;
    overflow-wrap: break-word;
}

.ga-product-single .ga-modalidad__freq {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    /* Más aire entre "Entrega cada:" y el desplegable: pegados se leían como una
       sola pieza y costaba ver dónde empieza el control. */
    gap: 0.85rem;
}

.ga-product-single .ga-modalidad__freq-txt {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    font-weight: 500;
    color: var(--ga-negro-suave, #1a1a14);
}

/* 🔴 16px CLAVADOS. Por debajo de ese tamaño, iOS hace zoom automático al abrir
   el desplegable y deja la página descolocada. Mismo criterio que el resto de
   campos del proyecto.

   🔴 POR QUÉ SE CORTABA EL TEXTO, QUE NO ERA UN PROBLEMA DE ANCHO SINO DE FLEX.
   El desplegable es un hijo de .ga-modalidad__freq, que es un contenedor
   flexible, y ahí todo hijo nace con flex-shrink: 1: puede ENCOGERSE por debajo
   de lo que mide su contenido para que la fila cuadre. Con "Entrega cada:"
   delante, lo que sobraba era poco y el desplegable se comía la diferencia
   recortando su propio texto. Darle más ancho no habría servido de nada mientras
   pudiera encogerse.

   flex: 0 0 auto lo deja a su tamaño natural, ni crece ni encoge, y con el
   flex-wrap del padre, si algún día no cupiera bajaría de línea en lugar de
   recortarse. El max-width del 100% es el tope que garantiza que nunca se salga
   de la tarjeta. Todo sin min-width. */
.ga-product-single .ga-modalidad__select,
.ga-product-single .ga-cantidad__select,
.ga-product-single .variations select,
.ga-product-single .ga-pack-tarro3__select {
    box-sizing: border-box;
    flex: 0 0 auto;
    /* fit-content: exactamente lo que mide la opción más larga, ni más ni menos,
       sin recurrir a un min-width. El relleno de abajo es lo que de verdad le da
       cuerpo: un desplegable ajustado al texto se ve pequeño por mucho que el
       ancho sea el correcto. */
    width: fit-content;
    max-width: 100%;
    /* El hueco de la derecha es el del texto (1,3rem) MÁS lo que ocupa la flecha
       (0,7rem), para que la flecha quede a 1,3rem del borde: la misma distancia
       que el texto tiene a la izquierda. */
    padding: 0.8rem 3.3rem 0.8rem 1.3rem;

    /* 🔴 LA FLECHA SE DIBUJA A MANO PORQUE LA NATIVA NO SE PUEDE COLOCAR. La que
       pinta el navegador va pegada al borde derecho y NO la mueve el
       padding-right: es parte del control, no del contenido, y cada motor la
       sitúa a su manera. Por eso se apaga el control con appearance: none y se
       pone una flecha propia como fondo, que sí se posiciona al milímetro.

       De paso, deja de haber tres flechas distintas según el navegador.

       ⚠ EL COLOR VA ESCRITO EN HEXADECIMAL DENTRO DEL SVG, y no es un color
         inventado: es el valor exacto de --ga-verde-oliva-oscuro. Un data URI es
         un archivo aparte para el navegador y ahí dentro var() no llega. Si algún
         día cambia ese verde en style.css, hay que cambiarlo también aquí. */
    -webkit-appearance: none;
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='9' viewBox='0 0 14 9' fill='none' stroke='%234a4a2f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 1.3rem center;
    background-size: 0.7rem auto;
    font-family: var(--ga-font-body);
    font-size: 16px;
    line-height: 1.4;
    color: var(--ga-verde-oliva-oscuro);
    background-color: var(--ga-blanco);
    border: 1px solid var(--ga-amarillo-pastel);
    border-radius: var(--ga-radius-sm);
    cursor: pointer;
    /* Solo se anima el color del borde: el grosor no cambia en ningún estado. */
    transition: border-color var(--ga-transition-normal);
}

.ga-product-single .ga-modalidad__select:focus,
.ga-product-single .ga-cantidad__select:focus,
.ga-product-single .variations select:focus,
.ga-product-single .ga-pack-tarro3__select:focus {
    outline: none;
    border-color: var(--ga-naranja-apagado);
}


/* ——— EL DESPLEGABLE DE LOS PACKS, DE LA FAMILIA DE LAS TARJETAS DE ABAJO ———
   De la regla compartida de aquí arriba se queda con lo que de verdad importa —el
   appearance: none, la flecha dibujada a mano, la tipografía y los colores—, y aquí
   se le cambia solo lo que lo separaba de "Compra única" y "Compra recurrente".
   Sobrescribir cuatro propiedades es mejor que copiar la regla entera: la flecha en
   SVG y el reset del control siguen escritos una sola vez.

   🔴 EL ANCHO ERA EL PROBLEMA DE FONDO, Y VENÍA DE `width: fit-content`. Ese valor
   es lo correcto para el selector de "Entrega cada", que vive dentro de una tarjeta
   y se ajusta a su texto; aquí dejaba el control descolgado a la izquierda mientras
   las tarjetas de debajo ocupaban toda la columna. Con width: 100% pasa a estirarse
   como ellas, y como .ga-cantidad y .ga-modalidad son las dos rejillas de UNA sola
   columna minmax(0,1fr) sin ancho máximo ni relleno lateral, los bordes izquierdo y
   derecho caen exactamente en la misma vertical. Sin ningún número escrito a mano
   que cuadrar.

   El box-sizing: border-box ya venía de la regla compartida, así que el borde y el
   relleno van por dentro de ese 100% y no lo desbordan.

   ⚠ EL RELLENO DERECHO NO ES EL MISMO NÚMERO QUE EL IZQUIERDO, Y NO ES UNA ERRATA:
     tiene que dejar sitio a la flecha. Sale de la misma cuenta que la regla de
     arriba, con las medidas de la tarjeta: 1,15rem del borde + 0,7rem que ocupa la
     flecha + 1,15rem de aire hasta el texto = 3rem. Y la flecha se recoloca a esos
     mismos 1,15rem del borde, para que quede a la misma distancia que el texto por
     el otro lado.

   ⚠ EL ALTO SE IGUALA POR EL RELLENO VERTICAL, no con una altura fija. Las tarjetas
     llevan dos o tres líneas dentro y el desplegable una sola: clavarle su altura
     exacta pediría un número inventado que se rompería al cambiar cualquier texto.
     Con el mismo padding-block que ellas —1,05rem— el control respira igual y se
     lee como parte del mismo grupo, que es lo que se busca.

   El borde sube de 1px a 2px y el radio de 4px a 10px: son los de las tarjetas. El
   :focus de aquí arriba solo cambia el COLOR del borde, y con 2px en los dos
   estados el grosor no varía, así que nada se mueve al enfocarlo.

   ⚠ ESTO NO ALCANZA A LOS TRES FORMATOS DE ACEITE: .ga-cantidad__select solo lo
     pinta la plantilla en los packs. En el 500 ml, la 2 L y la 5 L siguen las
     tarjetas de botellas, que no llevan esta clase. */
.ga-product-single .ga-cantidad .ga-cantidad__select,
.ga-product-single .variations select,
.ga-product-single .ga-pack-tarro3__select {
    width: 100%;
    padding: 1.05rem 3rem 1.05rem 1.15rem;
    background-position: right 1.15rem center;
    border-width: 2px;
    border-radius: 10px;
}


/* =============================================================================
   LOS DESPLEGABLES CONFIRMAN LO QUE YA ESTÁ ELEGIDO
   =============================================================================
   Un desplegable con una opción puesta y otro todavía vacío se ven exactamente
   igual: los dos con el borde pastel neutro y el fondo blanco. Hay que leer el
   texto de dentro para saber cuál falta, y en un pack donde hay que elegir dos
   variedades eso es justo lo que no debería costar.

   A partir de aquí el aspecto DICE el estado: neutro mientras no hay nada
   elegido, borde dorado y fondo crema en cuanto lo hay. Es el mismo par de
   colores con el que ya se pinta el tarro 3 —que nace elegido—, así que los tres
   campos del pack acaban leyéndose igual cuando están los tres resueltos.

   🔴 TODO VA ACOTADO CON :not(.ga-product-single--eventos), y esa clase NO es una
   convención: es exactamente el resultado de la comprobación que pide el encargo.
   La plantilla la pinta con
       function_exists( 'ga_eventos_es_personalizable' )
       && ga_eventos_es_personalizable( $pid )
   y nada más, así que preguntar por la clase aquí es preguntar por esa función
   sin tener que tocar el PHP.
   ============================================================================= */

/* ——— PASO 1 · EL DESPLEGABLE DE CANTIDAD, SIEMPRE EN DORADO ———
   Este no tiene estado vacío: nace con una cantidad puesta y no se puede dejar
   sin elegir. Si el dorado significa "esto ya está decidido", aquí lo está
   siempre, y por eso el borde va fijo y no depende de ninguna clase.

   ⚠ SOLO EL BORDE. El fondo se queda blanco y el texto en el verde de siempre,
     los dos por herencia de la regla común: aquí no se vuelven a escribir. Y el
     grosor tampoco se toca —siguen siendo los 2px de arriba—, así que el campo
     mide exactamente lo mismo que antes y no se mueve nada.

   ⚠ NO ALCANZA A .ga-modalidad__select, el de "Entrega cada". Ese vive dentro de
     la tarjeta de compra recurrente y tiene su propio lenguaje de color; el
     encargo habla del de "Elige la cantidad" y a ese se limita. */
.ga-product-single:not(.ga-product-single--eventos) .ga-cantidad .ga-cantidad__select {
    border-color: var(--ga-naranja-apagado);
}

/* ——— PASO 2 · LOS DESPLEGABLES DE VARIACIÓN, SEGÚN ESTÉN O NO ELEGIDOS ———
   El estado lo marca el JS poniendo y quitando .is-elegida (gaVariacionElegida).
   Sin JS no se pone nunca, y entonces todos se quedan en el aspecto neutro de la
   regla común: es la degradación correcta, porque sin JS tampoco funcionan las
   variaciones de WooCommerce.

   Aquí abajo NO hay estado "vacío" escrito, y es a propósito: el vacío es
   simplemente no llevar la clase, o sea la regla común de siempre. Escribirlo
   otra vez sería duplicar el aspecto neutro en dos sitios y arriesgarse a que un
   día se cambie uno y no el otro. Por eso el 2.5 —volver a "Elige una opción"—
   sale gratis: el JS quita la clase y el campo vuelve solo a lo que era.

   ⚠ LA TRANSICIÓN SE AMPLÍA AQUÍ Y NO EN LA REGLA COMÚN. Aquella solo anima el
     color del borde, y tocarla alcanzaría también al desplegable de "Entrega
     cada" y al del tarro 3, que no cambian de fondo en ningún momento. Se anima
     lo que de verdad cambia —borde y fondo—, y NADA de tamaño ni de posición: ni
     el grosor del borde, ni el relleno, ni el ancho, ni la tipografía entran en
     esta transición ni en la clase de abajo. */
.ga-product-single:not(.ga-product-single--eventos) .variations select {
    transition: border-color var(--ga-transition-normal),
                background-color var(--ga-transition-normal);
}

/* ⚠ EL FONDO VA DECLARADO DOS VECES Y NO ES UNA ERRATA: es el patrón del
     proyecto. La primera línea es el crema de marca a pelo, que entiende
     cualquier navegador; la segunda lo afina con color-mix a un crema apenas
     insinuado sobre blanco, y solo la aplican los navegadores que sepan de
     color-mix. Son EXACTAMENTE las dos mismas líneas del tarro 3, para que un
     tarro recién elegido y el que viene puesto de fábrica no se distingan.

   ⚠ EL TEXTO NO SE TOCA: sigue en --ga-verde-oliva-oscuro por la regla común. Y
     conviene que siga así, porque sobre este crema da 8,4:1 —y algo más sobre la
     versión con color-mix, que es aún más clara—, muy por encima del 4,5:1 que
     pide la norma. En dorado se quedaría en unos 2,2:1. */
.ga-product-single:not(.ga-product-single--eventos) .variations select.is-elegida {
    background-color: var(--ga-naranja-claro);
    background-color: color-mix(in srgb, var(--ga-naranja-apagado) 8%, var(--ga-blanco));
    border-color: var(--ga-naranja-apagado);
}

/* Aquí vivía la misma red de seguridad para navegadores sin :has(), y se ha
   retirado por lo mismo que la de las filas de cantidad: el punto marcado ya no
   depende de :has() —lo pinta `:checked + .ga-radio`— y devolver el radio nativo
   dibujaría un segundo control al lado del círculo. */


/* =============================================================================
   LOS DOS BOTONES DENTRO DEL FORMULARIO DE VARIACIONES
   =============================================================================
   Los botones son los MISMOS que en cualquier otra ficha y su aspecto ya está
   resuelto: todas sus reglas —colores, esquinas, hover, la fila a partir de
   700px— van con selectores de descendencia (.ga-product-single
   .ga-product__cta-buttons …), así que les alcanzan igual estando ahora un nivel
   más adentro, dentro del formulario de WooCommerce. No hay que repetir ni una.

   Aquí solo hacen falta dos cosas: encajar el contenedor en la caja flexible de
   WooCommerce y vestir el estado deshabilitado, que en el resto de fichas no
   existía porque allí los botones nunca se cierran.
   ============================================================================= */

/* .woocommerce-variation-add-to-cart es un flex que envuelve. Con el campo de
   cantidad oculto, este contenedor es su único hijo visible, y el 100 % de base
   lo deja ocupando la línea entera en vez de encogerse a lo que midan los
   botones. Es 100 % del ANCHO DISPONIBLE, no un ancho fijo: no puede sacar una
   fila más ancha que el viewport. */
.ga-product-single .woocommerce-variation-add-to-cart .ga-product__cta-buttons {
    flex: 1 1 100%;
}

/* 🔴 CERRADO = SOLO OPACIDAD Y CURSOR. Ni el borde, ni el relleno, ni el tamaño
   de letra: el botón ocupa exactamente lo mismo abierto que cerrado, así que al
   habilitarse no da ningún salto ni empuja a lo que tiene debajo. */
.ga-product-single .ga-product__cta-buttons .ga-btn:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

/* ⚠ Y HAY QUE APAGARLES EL HOVER A MANO. Un <button disabled> no recibe clics,
   pero :hover SÍ le sigue casando en los navegadores, así que sin esto el botón
   cerrado se seguiría iluminando al pasar por encima y parecería pulsable.

   Se repiten sus colores de reposo, que es lo único que se puede hacer: no hay
   forma de "cancelar" una regla de hover, solo de volver a declarar lo mismo.

   Puntúan 0-5-0, por encima del 0-4-0 y el 0-3-0 de las reglas de hover de
   main.css. Los !important del de carrito son los de siempre: contra las
   declaraciones !important de woocommerce.css no compite nada más. */
.ga-product-single .ga-product__cta-buttons .ga-product__btn-cart:disabled:hover,
.ga-product-single .ga-product__cta-buttons .ga-product__btn-cart:disabled:focus-visible {
    background-color: var(--ga-blanco) !important;
    border-color: var(--ga-verde-oliva-oscuro) !important;
    color: var(--ga-verde-oliva-oscuro) !important;
}

.ga-product-single .ga-product__cta-buttons .ga-product__btn-buy-now:disabled:hover,
.ga-product-single .ga-product__cta-buttons .ga-product__btn-buy-now:disabled:focus-visible {
    background-color: var(--ga-naranja-apagado);
    border-color: var(--ga-naranja-apagado);
    color: var(--ga-blanco);
}


/* 🔴 EL CAMPO DE CANTIDAD NATIVO SE OCULTA, PERO NO SE QUITA DEL MARCADO.
   Es el único que WooCommerce lee al añadir al carrito: el bloque de arriba se
   limita a escribir en él. Si se eliminara, el producto se añadiría siempre de
   uno en uno.

   Son los dos sitios donde aparece: el del formulario propio de los productos
   simples y el que pinta WooCommerce dentro del formulario de variaciones.
   Solo fuera de Eventos, donde las unidades las gobierna su propio campo. */
.ga-product-single:not(.ga-product-single--eventos) .ga-product__qty-row,
.ga-product-single:not(.ga-product-single--eventos) .woocommerce-variation-add-to-cart .quantity {
    display: none;
}

/* 🔴 Y ESTE ES EL QUE DE VERDAD LO ESCONDE EN LOS PRODUCTOS VARIABLES.
   La regla de arriba busca .quantity, que es la clase que pinta la plantilla de
   WooCommerce, y en la rama de los variables no llegaba a casar: ese recuadro
   con el "1" se estaba viendo bajo las tarjetas de compra. Depender del marcado
   de WooCommerce —o del de Astra, que también reescribe estas plantillas— es
   frágil: basta una actualización para que la clase cambie y el campo reaparezca
   sin que nadie haya tocado nada.

   Por eso la plantilla envuelve ese campo en .ga-product__qty-oculta, un div
   nuestro, y se oculta el envoltorio. Lo de dentro da igual cómo se llame.

   Sigue en el DOM y sigue enviándose —display:none no impide el envío, solo lo
   impediría un campo deshabilitado—: es el que WooCommerce lee al añadir al
   carrito y en el que escribe el bloque "Elige la cantidad". */
.ga-product-single .ga-product__qty-oculta {
    display: none;
}


/* =============================================================================
   GALERÍA — FLECHAS EN LUGAR DE MINIATURAS (fichas que NO son de Eventos)
   =============================================================================
   La fila de miniaturas se oculta y su función pasa a dos flechas sobre la foto.

   🔴 SE OCULTAN, NO SE QUITAN DEL MARCADO, y no es por costumbre: las flechas
   FUNCIONAN pulsando la miniatura que toca. Son ellas las que guardan la URL de
   cada foto, su texto alternativo y cuál se está viendo. Si se borraran del
   HTML, las flechas se quedarían sin nada que pulsar.

   En Eventos no hay ni miniaturas ni flechas: la foto la decide el formulario.
   ============================================================================= */

.ga-product-single:not(.ga-product-single--eventos) .ga-product__gallery-thumbs {
    display: none;
}

/* ——— LA FILA: FLECHA · FOTO · FLECHA ———
   Las columnas de las flechas se cobran lo que miden ellas (auto) y la del medio
   se lleva TODO lo que sobra.

   🔴 minmax(0, 1fr) Y NO 1fr A SECAS. Un 1fr pelado vale como mínimo el ancho del
   CONTENIDO de la celda, así que una foto que no quisiera encoger ensancharía su
   columna y sacaría la fila fuera de la ficha. Con el 0 de mínimo, la columna de
   la foto puede estrecharse todo lo que haga falta y nunca hay desbordamiento.
   Es la vía del proyecto para cortar el ancho mínimo sin usar min-width.

   align-items: center las deja centradas respecto al alto de la foto sin tener
   que posicionarlas ni calcular nada: lo hace la propia rejilla. */
.ga-product-single .ga-product__gallery-fila {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 0.4rem;
}

/* Solo la flecha: ni disco, ni borde, ni sombra. El disco blanco tenía sentido
   cuando iban superpuestas sobre la foto y había que separarlas de ella; fuera de
   la imagen sobra.

   ⚠ EL 44x44 SE QUEDA AUNQUE EL FONDO SEA TRANSPARENTE, y es lo importante de
     esta regla: es el área mínima que hay que poder tocar con el dedo. El icono
     mide 22px, así que sin esta caja el objetivo real sería la mitad de lo
     recomendado y fallar el toque sería lo normal en móvil. El fondo se ve o no
     se ve; el área que responde al dedo sigue estando. */
.ga-product-single .ga-gallery-flecha {
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 44px;
    height: 44px;
    padding: 0;
    color: var(--ga-naranja-apagado);
    background-color: transparent;
    border: none;
    box-shadow: none;
    cursor: pointer;
    /* Solo el color se anima: ni tamaño, ni posición, ni sombra que empuje. */
    transition: color var(--ga-transition-normal);
}

/* 🔴 EL transform: none NO ES DECORATIVO. .ga-btn:active aplica en toda la web un
   translateY(1px) scale(0.98) como respuesta al pulsar; estos botones no llevan
   esa clase, pero se deja declarado para que ninguna regla futura pueda moverlos
   al pulsarlos. Lo único que cambia entre estados es el color. */
.ga-product-single .ga-gallery-flecha:hover,
.ga-product-single .ga-gallery-flecha:focus-visible,
.ga-product-single .ga-gallery-flecha:active {
    color: var(--ga-verde-oliva-oscuro);
    transform: none;
}

/* Sin fondo ya no hay sombra sobre la que montar el halo, así que el foco se
   marca con un contorno. Tampoco ocupa sitio: no mueve ni agranda nada. */
.ga-product-single .ga-gallery-flecha:focus-visible {
    outline: 2px solid var(--ga-naranja-apagado);
    outline-offset: 2px;
}

/* ——— MÓVIL Y TABLET (≤860px): LAS FLECHAS, DEBAJO DE LA FOTO ———
   A esos anchos, dos columnas de 44px se comen casi un tercio de la foto. Antes
   que dejar la botella en una tira estrecha, las flechas bajan y se ponen en
   fila bajo la imagen, centradas y separadas.

   La foto ocupa las dos columnas de la primera fila y cada flecha se coloca a un
   lado del centro en la segunda. Va con colocación explícita —fila y columna— y
   no con el orden del marcado, porque en el HTML las flechas siguen estando una
   antes y otra después de la foto: es lo que hace que en escritorio se coloquen
   solas a los lados. */
@media (max-width: 860px) {

    .ga-product-single .ga-product__gallery-fila {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: 1rem;
        row-gap: 0.75rem;
    }

    .ga-product-single .ga-product__gallery-fila .ga-product__gallery-main {
        grid-row: 1;
        grid-column: 1 / -1;
    }

    .ga-product-single .ga-gallery-flecha--prev {
        grid-row: 2;
        grid-column: 1;
        justify-self: end;
    }

    .ga-product-single .ga-gallery-flecha--next {
        grid-row: 2;
        grid-column: 2;
        justify-self: start;
    }
}


/* =============================================================================
   PAGO EXPRÉS — APPLE PAY, GOOGLE PAY, AMAZON PAY Y LINK EN DOS COLUMNAS
   =============================================================================
   Apilados hacían cuatro filas y se comían la columna de compra entera. En dos
   columnas ocupan la mitad de alto y dejan de competir con "Comprar ahora" y
   "Añadir al carrito", que son los que cierran la venta.

   🔴 SOLO SE TOCA EL CONTENEDOR. El interior de cada botón lo pinta la pasarela
   —muchos son un iframe— y no se toca ni una regla suya: ni colores, ni logos,
   ni tipografía. Las condiciones de Apple y de Google sobre sus botones son
   además bastante estrictas con eso.

   Los dos envoltorios están en la plantilla, uno por cada gancho de esa zona,
   porque la pasarela puede colgarse de cualquiera de los dos según su versión.
   ============================================================================= */

/* El que no reciba nada no existe: sin esto quedaría un hueco vacío con su
   margen justo debajo del botón de comprar. */
.ga-product-single .ga-product__express:empty {
    display: none;
}

/* minmax(0, 1fr) y no 1fr a secas: un 1fr pelado vale como mínimo el ancho del
   CONTENIDO de la celda, así que un botón que no quisiera encoger ensancharía su
   columna y sacaría la fila fuera de la ficha. Con el 0 de mínimo, la columna
   puede estrecharse todo lo que haga falta. Es la vía del proyecto para cortar
   el ancho mínimo sin usar min-width. */
.ga-product-single .ga-product__express {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem;
    margin-top: var(--ga-space-xs);
}

/* Alto máximo contenido, para que ninguno sobresalga del otro y para bajarles el
   peso visual frente a los dos botones principales.

   ⚠ EN LOS BOTONES QUE SON UN IFRAME ESTO PUEDE NO BASTAR: su alto lo fija por
     dentro el script de la pasarela y desde fuera no hay forma de cambiarlo sin
     recortarlos. Si alguno sigue saliendo demasiado alto, se baja en los ajustes
     de esa pasarela, que es donde se configura el alto del botón. */
.ga-product-single .ga-product__express > * {
    height: auto;
    max-height: 44px;
    margin: 0;
}

/* A 360px cada columna se queda en unos 150px, y un "Pagar con Link" o un
   "Buy with Amazon Pay" ahí ya no se lee. En ese tramo vuelven a una sola
   columna: mejor dos filas legibles que dos columnas ilegibles. */
@media (max-width: 360px) {
    .ga-product-single .ga-product__express {
        grid-template-columns: minmax(0, 1fr);
    }
}


/* =============================================================================
   VALORACIONES DE LA FICHA — BLOQUE EDITORIAL
   =============================================================================
   Tres reseñas quietas, apiladas y sin caja. Sustituye al mosaico rotatorio de la
   home, que aquí se repetía tal cual y hacía que la ficha pareciera un trozo de la
   portada.

   🔴 ESTAS CLASES SON NUEVAS Y PROPIAS DE LA FICHA (.ga-val-). No comparten ni una
   con .ga-opiniones-, que es lo de la home: así este bloque no puede heredar de
   allí ningún fondo, ninguna caja ni ninguna animación, y —sobre todo— el carrusel
   de la portada NO SE VE AFECTADO por nada de lo que hay aquí abajo.

   Y por lo mismo, el JavaScript que convierte el mosaico en carrusel dentro de la
   ficha (gaOpinionesFichaMontar, en main.js) ya no encuentra nada: busca
   #ga-opiniones-grid y en esta sección no existe. Se queda sin hacer nada sin
   tocarle una línea, que es la forma limpia de quitar el movimiento.
   ============================================================================= */

/* 🔴 EL RELLENO DE ABAJO VA A CERO, Y ES LO QUE CIERRA EL HUECO CON "TAMBIÉN TE
   PUEDE INTERESAR". Merece la explicación entera, porque el síntoma engañaba:

   QUÉ PASABA. El hueco no lo ponía nadie: lo ponían DOS, y se sumaban.
       .ga-product__valoraciones  padding-block  → 4rem por abajo   (esta regla)
       .ga-eventos-rel            padding-top    → 4rem por arriba  (main.css)
   Total, 8rem —128px— entre la fila de sellos y el titular de abajo, el doble que
   entre cualesquiera otras dos secciones de la ficha. El título de la sección de
   abajo no añade nada: .ga-section__titulo nace con margen superior 0, o sea que
   no había un tercer sumando escondido.

   POR QUÉ SE ARREGLA AQUÍ Y NO ALLÍ, que es lo que decide todo lo demás:
     · Este relleno lo escribe la MISMA declaración para arriba y para abajo. El de
       ARRIBA separa las valoraciones de la tabla comparativa y no se toca, así que
       se pasa a la forma de dos valores y solo se cambia el segundo.
     · El de .ga-eventos-rel, además de vivir en main.css, lo comparten LAS DOS
       fichas: en la de eventos ese carrusel viene detrás de otra sección distinta.
       Tocarlo obligaría a acotar con :not(--eventos) y a cambiar un ritmo que
       funciona. Se deja como está.

   CUÁNTO SE LE DEJA, Y POR QUÉ NO CERO. Primero se puso a cero, y con las 4rem que
   pone .ga-eventos-rel por su cuenta el hueco quedaba corto: los sellos se leían
   pegados al titular de abajo. Ahora se le devuelve 1,5rem, que sumadas a esas
   4rem dan 5,5rem — entre las 8rem del principio y las 4rem a las que se quedó.
   Suficiente para que se sigan leyendo como dos bloques y bastante menos que el
   doble hueco original.

   ⚠ ES UN VALOR DE LA PALETA, NO UN NÚMERO SUELTO: --ga-space-md. La paleta va
     1rem · 1,5rem · 2,5rem · 4rem, así que el escalón exacto de 2rem que daría la
     media aritmética no existe y se coge el de al lado.

   ⚠ SI HICIERA FALTA MÁS AIRE, SE SUBE ESTE MISMO VALOR AL SIGUIENTE ESCALÓN:
     --ga-space-lg (2,5rem), que dejaría el hueco en 6,5rem. Y para menos, a
     --ga-space-sm (1rem) → 5rem. Es el único número que hay que tocar: el relleno
     de .ga-eventos-rel se queda quieto.

   ⚠ NO HACE FALTA ACOTAR ESTA REGLA A LOS PRODUCTOS QUE NO SON DE EVENTOS: la
     sección entera cuelga de un if ( ! $ga_es_eventos ) en la plantilla —calculado
     con function_exists( 'ga_eventos_es_personalizable' )—, así que en una ficha de
     eventos no llega a existir. La de eventos tiene sus propias valoraciones, más
     abajo y con otro marcado.

   EN MÓVIL SALE SOLO: a ≤768px .ga-eventos-rel baja su relleno superior a 2,5rem,
   así que con este cero el hueco queda en 2,5rem con los sellos apilados —
   proporcionado, y sin que nada se solape porque son rellenos positivos que solo
   separan. */
.ga-product__valoraciones {
    padding-block: var(--ga-space-xl) var(--ga-space-md);
    background: var(--ga-blanco);
}

/* Columna de lectura estrecha: una cita larga a todo lo ancho de la pantalla se
   lee mal. Es max-width, nunca min-width. */
.ga-product__valoraciones .ga-val {
    max-width: 720px;
    margin-inline: auto;
}

/* ——— EL MARCO: DONDE SE APILAN LAS PÁGINAS ———
   🔴 REJILLA DE UNA SOLA CELDA, Y ESA ES LA PIEZA CLAVE DE TODO EL BLOQUE. Todas
   las páginas ocupan la MISMA celda (grid-area: 1/1), así que se superponen y el
   alto del marco es automáticamente el del grupo MÁS ALTO. Eso es lo que impide
   que el contenido de debajo salte al cambiar de página, y sale solo: no hay que
   medir nada por JavaScript ni escribir un alto a mano que se quede corto el día
   que una reseña crezca. Es un mecanismo de ALTURA; aquí no hay ningún min-width.

   ⚠ POR ESO LAS PÁGINAS INACTIVAS SE OCULTAN CON visibility Y NO CON display:none.
     Un elemento en display:none no cuenta para el tamaño de la rejilla, y el marco
     encogería al alto de la página visible: volveríamos a tener saltos.

   El recorte es lo que mantiene el desplazamiento DENTRO del bloque: los 24px que
   entran y salen no asoman por ningún lado y no pueden dar scroll horizontal a la
   página. Se declara dos veces: `clip` recorta igual pero NO convierte al elemento
   en contenedor de scroll, que es lo que hace `hidden` y lo que atrapa el gesto
   táctil en móvil (🪤 nº 3). El `hidden` queda de respaldo para navegadores que no
   entiendan `clip`. */
.ga-product__valoraciones .ga-val__marco {
    display: grid;
    overflow: hidden;
    overflow: clip;
}

/* ——— CADA PÁGINA ———
   En reposo, invisible y desplazada. La transición de visibility va con retraso
   igual a la duración: visibility no interpola —salta—, así que si saltara al
   empezar, la página que sale desaparecería de golpe a mitad del movimiento. */
.ga-product__valoraciones .ga-val__pagina {
    grid-area: 1 / 1;
    opacity: 0;
    visibility: hidden;
    transition:
        opacity 350ms ease,
        transform 350ms ease,
        visibility 0s linear 350ms;
}

/* Hacia dónde SALE la página que se va. Con `:not(.is-activa)` estas reglas no
   compiten nunca con la de la página activa: se aplican solo a las demás. */
.ga-product__valoraciones .ga-val[data-ga-dir="adelante"] .ga-val__pagina:not(.is-activa) {
    transform: translateX(-24px);
}

.ga-product__valoraciones .ga-val[data-ga-dir="atras"] .ga-val__pagina:not(.is-activa) {
    transform: translateX(24px);
}

/* De dónde VIENE la que va a entrar. El JS le pone esta clase un instante, sin
   transición, para colocarla en su punto de partida antes de encenderla.

   ⚠ VAN DESPUÉS de las dos reglas de arriba a propósito: empatan en especificidad
     y gana la última, que es la que tiene que mandar en ese instante. */
.ga-product__valoraciones .ga-val__pagina.is-preparada {
    transition: none;
}

.ga-product__valoraciones .ga-val[data-ga-dir="adelante"] .ga-val__pagina.is-preparada {
    transform: translateX(24px);
}

.ga-product__valoraciones .ga-val[data-ga-dir="atras"] .ga-val__pagina.is-preparada {
    transform: translateX(-24px);
}

/* La página visible: en su sitio y sin retraso en la visibility. */
.ga-product__valoraciones .ga-val__pagina.is-activa {
    opacity: 1;
    visibility: visible;
    transform: translateX(0);
    transition:
        opacity 350ms ease,
        transform 350ms ease,
        visibility 0s linear 0s;
}

/* ——— CADA RESEÑA ———
   Sin tarjeta, sin borde, sin sombra y sin fondo: lo único que separa una de otra
   es una línea fina. La primera no la lleva, para no dibujar una raya suelta justo
   debajo del titular. */
.ga-product__valoraciones .ga-val__item {
    margin: 0;
    padding: var(--ga-space-lg) 0;
    border-top: 1px solid var(--ga-amarillo-pastel);
}

.ga-product__valoraciones .ga-val__item:first-child {
    border-top: 0;
    padding-top: 0;
}

.ga-product__valoraciones .ga-val__item:last-child {
    padding-bottom: 0;
}

/* ——— LAS ESTRELLAS ———
   Dorado de marca y pequeñas: encabezan la reseña sin robarle protagonismo a la
   cita. El interletrado las separa un poco para que se lean como cinco y no como
   una mancha. */
.ga-product__valoraciones .ga-val__estrellas {
    font-size: var(--ga-text-sm);
    line-height: 1;
    letter-spacing: 0.12em;
    color: var(--ga-naranja-apagado);
}

/* ——— LA CITA: LA PROTAGONISTA ———
   Serif de titulares, cursiva y cuerpo grande. Es lo único que pesa en el bloque.

   ⚠ SIN COMILLAS DECORATIVAS Y SIN NINGÚN CONTENEDOR. El <blockquote> trae de
     serie un margen y un relleno del navegador que lo indentarían como una cita de
     libro; se ponen a cero para que el texto arranque a ras del resto.

   El clamp reduce el cuerpo en pantallas estrechas —de 1,55rem a 1,15rem— sin
   necesidad de una media query: a 360px la cita entra sin desbordar. Y el
   overflow-wrap parte una palabra larga en vez de dejar que se salga. */
.ga-product__valoraciones .ga-val__cita {
    margin: 0.75rem 0 0;
    padding: 0;
    border: 0;
    quotes: none;

    font-family: var(--ga-font-display);
    font-size: clamp(1.15rem, 2.4vw, 1.55rem);
    font-style: italic;
    font-weight: 400;
    line-height: 1.4;
    color: var(--ga-verde-oliva-oscuro);

    /* La regla general de títulos del tema reparte las líneas a lo balanceado, y
       en un párrafo largo eso deja todas las líneas cortadas a media caja
       (🪤 nº 16). Aquí el texto llena la línea. */
    text-wrap: wrap;
    overflow-wrap: break-word;
}

.ga-product__valoraciones .ga-val__cita::before,
.ga-product__valoraciones .ga-val__cita::after {
    content: none;
}

/* ——— EL NOMBRE ———
   Versalitas pequeñas y apagadas: firma la cita sin competir con ella. El respaldo
   de --ga-negro-suave es obligatorio —está en la paleta pero no se declara en el
   :root de style.css— y sin él la declaración se invalida y el color se hereda
   (🪤 nº 15). */
.ga-product__valoraciones .ga-val__nombre {
    margin-top: 0.9rem;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ga-negro-suave, #1a1a14);
    opacity: 0.55;
}

/* ——— LOS CONTROLES ———
   Las dos flechas, centradas y pegadas al fondo del marco.

   🔴 LA SEPARACIÓN ES CASI CERO A PROPÓSITO, Y NO ES UN DESCUIDO. Tenía 2,5rem, y
   ahí es donde se veían flotando a media distancia. El aire que se percibe no lo
   pone este margen: lo pone la propia caja de la flecha, que mide 44px por zona de
   toque mientras el icono ocupa 22, o sea unos 11px transparentes por arriba. Con
   0,25rem más, el hueco visible ronda los 15px, que es lo que se quería.

   ⚠ NO HACE FALTA ANCLARLAS AL FONDO CON NINGUNA REGLA, Y CONVIENE ENTENDER POR
     QUÉ. El marco de arriba es una rejilla de una sola celda donde TODAS las
     páginas se superponen, y las que no se ven siguen ocupando su sitio
     —se ocultan con visibility, no con display—. Eso hace que su alto sea SIEMPRE
     el del grupo más alto, no el del que se está viendo: no cambia al pasar de
     página. Y como estas flechas van justo después, en el flujo normal, heredan
     esa quietud: se quedan clavadas a la misma altura pase lo que pase, y lo que
     hay debajo tampoco se mueve.

     Es también la razón de que no haya aquí ningún min-height con un número
     inventado: la altura mínima ya la fija el contenido real, y un número a mano
     se quedaría corto el día que alguien alargue una reseña.

     La contrapartida, asumida: en un grupo más corto que el más alto queda un
     hueco entre la última reseña y las flechas. Es el precio de que nada salte, y
     es justo el trato que se pidió. */
.ga-product__valoraciones .ga-val__nav {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--ga-space-md);
    margin-top: 0.25rem;
}

/* Flechas finas, solo el trazo: sin fondo, sin borde, sin círculo y sin sombra.
   El !important en esas tres es por las reglas de botón del tema padre, que ganan
   a cualquier selector de clase razonable (🪤 nº 6).

   La caja de 44px es ZONA DE TOQUE, no adorno: es la medida cómoda para el dedo en
   móvil y no se ve, porque no pinta nada. Se declara con width/height, nunca con
   min-width, y vale igual en escritorio: así no hace falta cambiarla por ancho. */
.ga-product__valoraciones .ga-val__flecha {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    background: none !important;
    border: 0 !important;
    box-shadow: none !important;
    border-radius: 0;
    color: var(--ga-naranja-apagado);
    cursor: pointer;
    /* Solo se anima el color: ningún estado cambia tamaño ni posición. */
    transition: color 200ms ease, opacity 200ms ease;
    /* Sin el velo que pintan Android e iOS al tocar un botón. */
    -webkit-tap-highlight-color: transparent;
}

/* El trazo sigue al botón y solo al botón: stroke y fill son atributos de
   presentación y cualquier regla CSS de fuera los ganaría sin despeinarse. */
.ga-product__valoraciones .ga-val__flecha svg {
    stroke: currentColor !important;
    fill: none !important;
}

.ga-product__valoraciones .ga-val__flecha:hover,
.ga-product__valoraciones .ga-val__flecha:focus,
.ga-product__valoraciones .ga-val__flecha:focus-visible {
    color: var(--ga-verde-oliva-oscuro) !important;
}

/* Con el teclado hace falta ver dónde está el foco. El outline se dibuja FUERA de
   la caja y no ocupa sitio: no mueve ni agranda nada. */
.ga-product__valoraciones .ga-val__flecha:focus-visible {
    outline: 2px solid var(--ga-naranja-apagado);
    outline-offset: 2px;
}

/* ⚠ AQUÍ NO HAY NI ESTADO DESHABILITADO NI CONTADOR, Y NO ES UN OLVIDO. Los hubo:
   la flecha de cada extremo se atenuaba y entre las dos iba un "1 / 7". El paso es
   ahora circular —desde el último grupo se vuelve al primero y al revés—, así que
   no existen extremos que deshabilitar, y el indicador se ha retirado a propósito:
   entre las dos flechas no va nada. */

/* =============================================================================
   LOS TRES SELLOS, BAJO LAS VALORACIONES
   =============================================================================
   Tres afirmaciones sueltas, en fila y sin adorno: icono lineal dorado arriba y
   texto en versalitas debajo. Sin caja, sin borde, sin fondo y sin sombra —van
   sobre el mismo blanco de la sección—, y sin ningún estado: no son enlaces ni
   botones, así que no hay hover, ni foco, ni cursor de mano que declarar.
   ============================================================================= */

.ga-product__valoraciones .ga-sellos-ficha {
    list-style: none;
    padding: 0;

    /* 🔴 EL TAMAÑO DEL ICONO, EN UN SOLO SITIO. Lo consumen el ancho Y el alto de
       la imagen, así que con este número se cambian los dos a la vez y no hay
       forma de dejar uno desparejado del otro. La versión de móvil solo tiene que
       redefinir esta línea.

       Los archivos son de 512×512, así que a 100px hay margen de sobra: aguantan
       nítidos hasta unos 170px incluso en las pantallas más densas (DPR 3). */
    --ga-sello-ico: 100px;

    /* El primero, corregido con un FACTOR sobre el anterior —no con píxeles—, para
       que la corrección siga valiendo en móvil sin repetir el número. El porqué del
       0,86 está explicado en la regla del icono, más abajo. */
    --ga-sello-ico-1: calc(var(--ga-sello-ico) * 0.86);

    /* Cuánto se sube ese primer icono para que su base case con la de los otros
       dos. NEGATIVO = HACIA ARRIBA. En porcentaje del alto de la propia imagen, así
       que se escala solo en móvil. Los dos porqués —el mecanismo y por qué está
       estimado— están en la regla del icono, más abajo. */
    --ga-sello-1-subir: -6%;

    /* Y cuánto se BAJA el tercero, por el motivo contrario. POSITIVO = HACIA ABAJO.
       Se afinan por separado: son dos dibujos distintos y cada uno lleva su propio
       aire dentro del lienzo. */
    --ga-sello-3-bajar: 6%;

    display: grid;
    /* 🔴 minmax(0, 1fr) Y NO 1fr. El mínimo por defecto de una pista de rejilla es
       el ancho de su contenido: "Apoyo directo al agricultor" en versalitas y con
       interletrado ensancharía su columna y con ella la fila entera. Con el 0 de
       mínimo, la pista encoge y el texto parte donde toca. Es cómo se corta el
       ancho mínimo sin usar min-width. */
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--ga-space-md);

    /* 🔴 ARRIBA, NO ESTIRADOS. Sin esto cada sello ocuparía todo el alto de la fila
       y su contenido se repartiría de otra forma según lo que midiera: un texto de
       dos líneas y otro de una arrancarían a alturas distintas. Anclando el
       contenido al techo, los tres iconos quedan clavados a la misma altura y los
       tres textos empiezan en la misma línea, ocupen una línea o dos. */
    align-items: start;

    /* ⚠ SIN max-width: ocupan el ancho completo del contenedor de la sección. Lo
       tuvieron —720px, para alinearse con las citas—, y se les ha quitado para que
       cada columna tenga sitio de sobra para su texto. El ancho máximo y el
       relleno lateral ya los pone .ga-container. */

    /* Aire generoso por arriba, para que se lean como un bloque aparte y no como
       una línea más de las reseñas.

       SUBE DE 4rem A 5rem AL CRECER EL ICONO. Con el sello de 44px, 4rem bastaba
       para despegarlo de las reseñas; con 100px la fila pesa mucho más y a esa
       misma distancia se leía pegada a la última cita, como si formara parte de
       ella. No hay variable de 5rem en la paleta, así que se compone con dos que
       sí existen en vez de escribir un número suelto. */
    margin-block: calc(var(--ga-space-xl) + var(--ga-space-sm)) 0;
    margin-inline: 0;
}

/* 🔴 REJILLA DE DOS FILAS, Y NO UNA COLUMNA FLEX. ES EL MECANISMO QUE MANTIENE LOS
   TRES TEXTOS A LA MISMA ALTURA, Y ES DELIBERADO.

   Con la columna flex que había antes, el alto de la zona del icono lo ponía el
   propio icono: en cuanto uno mide menos que los otros —que es justo lo que hace
   falta aquí para igualarlos ópticamente—, su texto sube y los tres dejan de
   arrancar en la misma línea.

   Con la primera fila FIJADA a --ga-sello-ico, esa zona mide siempre lo mismo mida
   lo que mida la imagen que lleva dentro. El texto de los tres empieza entonces
   exactamente a la misma altura, sin depender del tamaño de cada icono. Es una
   garantía estructural, no un ajuste a ojo: si mañana se cambia un icono por otro
   de otro tamaño, los textos siguen alineados solos. */
.ga-product__valoraciones .ga-sellos-ficha__item {
    display: grid;
    grid-template-rows: var(--ga-sello-ico) auto;
    justify-items: center;

    /* De 0,8rem a 1,1rem. NO es proporcional al icono a propósito: si creciera al
       mismo ritmo que él (44→100 es más del doble) el texto se despegaría y cada
       sello se leería como dos cosas sueltas en vez de como un bloque. Sube lo
       justo para que el icono no se apoye encima de las versalitas.

       Al ser un gap de rejilla entre dos filas, el hueco icono-texto es idéntico
       en los tres aunque sus iconos midan distinto. */
    gap: 1.1rem;

    text-align: center;
}

/* El icono es una IMAGEN (.webp de 512×512), ya no un SVG dibujado, así que aquí
   no hay nada de color: el que traiga el archivo es el que se ve. Por eso se han
   retirado las reglas de color, stroke y fill que había antes: sobre un <img> no
   pintan nada.

   🔴 EL ALTO VA DECLARADO A PROPÓSITO, Y HAY QUE DEJARLO. Astra y WooCommerce
   llevan un `img { height: auto }` que, con el ancho fijo, le devolvería a la
   imagen su proporción de origen. Hoy daría igual —las tres son cuadradas—, pero
   el día que se cambie una por otra que no lo sea, la fila se descuadraría sola.
   Con alto fijo + object-fit: contain, la imagen se ajusta DENTRO de su caja sin
   deformarse y sin mover a sus vecinas, sea cual sea su proporción.
   El selector es 0-2-0 y gana a esas reglas sin necesitar !important.

   ⚠ ANCHO Y ALTO SALEN DE LA MISMA VARIABLE: la caja es siempre cuadrada, pase lo
     que pase.

   align-self: end APOYA LA IMAGEN EN EL SUELO DE SU FILA. Como la fila mide
   siempre --ga-sello-ico, los tres iconos quedan con la base en la misma línea
   aunque uno sea más pequeño: el que mengua lo hace hacia arriba, no flotando en
   mitad del hueco. */
.ga-product__valoraciones .ga-sellos-ficha__ico {
    width: var(--ga-sello-ico);
    height: var(--ga-sello-ico);
    object-fit: contain;
    align-self: end;
}

/* ——— EL PRIMER SELLO, IGUALADO ÓPTICAMENTE ———
   Los tres archivos tienen el MISMO lienzo (512×512), pero el dibujo del agricultor
   lo llena bastante más que los otros dos, así que a igual tamaño de caja se ve
   mayor. Como el desajuste está DENTRO de la imagen, no se arregla en el archivo
   desde aquí: se compensa dándole menos caja.

   ⚠ EL 0.86 ES UN PUNTO DE PARTIDA, NO UNA MEDIDA. No hay en este equipo ningún
     decodificador de WebP con el que medir cuánto ocupa cada dibujo dentro de su
     lienzo, así que el factor está estimado y hay que rematarlo A OJO en el
     navegador. Es UN SOLO NÚMERO: si el primero sigue viéndose grande, se baja
     (0.82, 0.78…); si se ha quedado pequeño, se sube. Nada más que tocar.

   Va como FACTOR y no como píxeles para que el ajuste valga igual en escritorio y
   en móvil: 100px → 86px arriba, 80px → 68,8px en el móvil, sin repetir el número
   en la media query.

   El selector es :first-child, o sea POSICIONAL: si algún día se reordenan los
   sellos, la corrección se queda con el primero de la fila y hay que moverla al que
   corresponda. */
.ga-product__valoraciones .ga-sellos-ficha__item:first-child .ga-sellos-ficha__ico {
    width: var(--ga-sello-ico-1);
    height: var(--ga-sello-ico-1);

    /* 🔴 Y ADEMÁS SE SUBE UN POCO, CON transform, QUE ES LA CLAVE DE QUE ESTO NO
       DESCUADRE NADA.

       El problema: aun con la caja apoyada en el suelo de su fila, el dibujo del
       agricultor lleva menos aire por debajo dentro de su propio lienzo que los
       otros dos, así que su base se veía más baja que la de sus vecinos.

       ❌ NO se corrige recortando el hueco icono-texto: eso subiría la imagen a
          costa de bajar el texto, y los tres textos dejarían de arrancar a la misma
          altura, que es justo lo que sostiene toda la alineación de esta fila.
       ✅ transform NO participa en el flujo: mueve lo que se PINTA y deja la caja
          donde estaba. La fila del icono sigue midiendo --ga-sello-ico, el texto no
          se entera, y ni la altura total de la fila ni su separación con las
          valoraciones cambian un píxel.

       El valor va en PORCENTAJE a propósito: un translateY en % se resuelve contra
       el ALTO DE LA PROPIA IMAGEN, así que la corrección se escala sola —en móvil
       el icono mide menos y el empujón se reduce en la misma proporción— sin
       repetir el número en la media query ni necesitar calc.

       ⚠ ESTIMADO, NO MEDIDO, por lo mismo que el 0.86 de aquí arriba. Se remata a
         ojo subiendo o bajando ese único porcentaje.

       Cabe de sobra: el icono ocupa el 86 % de su fila y está apoyado abajo, así
       que tiene un 14 % de hueco libre por encima y el empujón es de un 6 %. No
       puede solaparse con nada, ni en escritorio ni apilado en móvil. */
    transform: translateY(var(--ga-sello-1-subir));
}

/* ——— EL TERCER SELLO, BAJADO ———
   El mismo caso que el primero pero al revés: el dibujo de la furgoneta lleva MÁS
   aire por debajo dentro de su lienzo, así que su base se veía más alta que la de
   sus vecinas y hay que empujarla hacia abajo.

   Mismo mecanismo y mismos motivos que arriba —transform para no tocar el flujo,
   porcentaje para que se escale solo en móvil, valor estimado y no medido—, así que
   no se repiten aquí. La única diferencia es el signo: POSITIVO es hacia abajo.

   No puede solaparse con su texto: el empujón es de un 6 % del icono (6px en
   escritorio, 4,8 en móvil) y el hueco hasta el texto es de 1,1rem (17,6px) y
   0,95rem (15,2px). Queda más de media separación libre en los dos casos.

   El selector es POSICIONAL, como el del primero: si se reordenan los sellos, esta
   corrección se queda con el tercero de la fila y hay que moverla al que toque. */
.ga-product__valoraciones .ga-sellos-ficha__item:nth-child(3) .ga-sellos-ficha__ico {
    transform: translateY(var(--ga-sello-3-bajar));
}

.ga-product__valoraciones .ga-sellos-ficha__texto {
    font-family: var(--ga-font-body);

    /* Sube de 0,75rem a 0,85rem: gana presencia sin acercarse a los titulares de
       sección, que van en serif y por encima de 1,6rem. El interletrado baja de
       0,12em a 0,09em a la vez, porque los textos nuevos son bastante más largos y
       con el espaciado anterior se partirían antes de tiempo. */
    font-size: 0.85rem;
    letter-spacing: 0.09em;

    font-weight: 600;
    line-height: 1.45;
    text-transform: uppercase;

    /* El verde oscuro macizo. Es también el RESPALDO del brillo: si el navegador no
       sabe recortar un degradado sobre el texto, no entra en el @supports de más
       abajo y el sello se queda exactamente así. Nunca transparente. */
    color: var(--ga-verde-oliva-oscuro);

    /* Que una palabra larga parta en vez de salirse de su columna. */
    overflow-wrap: break-word;
}

/* ——— EL BRILLO DE LOS SELLOS ———
   El mismo mecanismo que llevan el nombre del formato de la tabla comparativa y los
   títulos de sección de la tienda: un degradado con la banda de luz en el medio, el
   fondo estirado al 250 % y la animación moviendo SOLO background-position. Se
   reutilizan sus mismos @keyframes, declarados en main.css —las @keyframes son
   globales del documento, no de la hoja donde se escriben—.

   🔴 LA BASE ES EL VERDE, NO EL DORADO, Y ESO ES LO QUE SALVA LA LECTURA. Aquí el
   texto va sobre fondo blanco: si la base fuera dorada, el sello entero se quedaría
   en 2,3:1 de contraste y sería ilegible. Con el verde de base, el texto mantiene
   sus 8:1 de siempre y lo único que cambia es la franja estrecha por la que pasa el
   destello.

   🔴 Y EL DESTELLO NO ES EL DORADO PURO, SINO UN DORADO PROFUNDO —el de marca
   mezclado con el propio verde—. Con el dorado tal cual, las letras que cruza la
   banda bajan a 2,3:1 y desaparecen un instante; con la mezcla se quedan en 3,2:1,
   que ya se lee. La primera declaración del degradado usa el dorado de la paleta
   tal cual, para navegadores anteriores a color-mix (2023); la segunda afina el
   tono donde se pueda.

   Suave y lento: 16s. Esos @keyframes barren en la primera mitad y descansan la
   segunda, o sea 8 segundos de recorrido y otros 8 de reposo.

   El rango 100 % → 0 % mantiene el degradado cubriendo siempre las letras —el fondo
   no se repite—, así que el texto no puede quedarse sin pintar en ningún
   fotograma. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {

    .ga-product__valoraciones .ga-sellos-ficha__texto {
        background-image: linear-gradient(
            100deg,
            var(--ga-verde-oliva-oscuro) 0%,
            var(--ga-verde-oliva-oscuro) 45%,
            var(--ga-naranja-apagado)    50%,
            var(--ga-verde-oliva-oscuro) 55%,
            var(--ga-verde-oliva-oscuro) 100%
        );
        background-image: linear-gradient(
            100deg,
            var(--ga-verde-oliva-oscuro) 0%,
            var(--ga-verde-oliva-oscuro) 45%,
            color-mix(in srgb, var(--ga-naranja-apagado) 70%, var(--ga-verde-oliva-oscuro)) 50%,
            var(--ga-verde-oliva-oscuro) 55%,
            var(--ga-verde-oliva-oscuro) 100%
        );

        background-size: 250% 100%;
        background-repeat: no-repeat;
        background-position: 100% center;

        -webkit-background-clip: text;
        background-clip: text;
        -webkit-text-fill-color: transparent;
        color: transparent;

        animation: ga-home-card-brillo 16s linear infinite;
    }
}

/* Sin animación para quien la haya desactivado, y con el verde MACIZO: se deshace
   el recorte en vez de dejar el degradado congelado, para que no quepa duda de que
   el texto se ve y se ve en su color. Va DESPUÉS del @supports y con el mismo
   selector: mismo peso, gana el último. */
@media (prefers-reduced-motion: reduce) {

    .ga-product__valoraciones .ga-sellos-ficha__texto {
        background-image: none;
        animation: none;
        -webkit-text-fill-color: currentColor;
        color: var(--ga-verde-oliva-oscuro);
    }
}

/* =============================================================================
   REMATE DEL FINAL DE LA FICHA — ENLACE A LA PÁGINA DE EVENTOS
   -----------------------------------------------------------------------------
   Una sola frase centrada, enlazada ENTERA, que cierra la ficha por debajo de
   "También te puede interesar".

   ⚠ EL SELECTOR YA NO CUELGA DE .ga-product__valoraciones. Al mudarse el párrafo
     al final de la ficha dejó de estar dentro de esa sección, así que las reglas
     van sobre su propia clase. Si se vuelve a mover, esto le sigue valiendo.
   ============================================================================= */

.ga-sellos-evento {
    /* ARRIBA 2,5rem: lo que lo despega del carrusel de "También te puede interesar",
       que cierra a ras porque no lleva relleno inferior. Ese valor NO se toca.

       🔴 ABAJO, CERO. Ya no es la última pieza de la ficha —debajo van las preguntas
       frecuentes— y el hueco entre las dos cosas se le deja ENTERO al relleno
       superior de esa sección. Es la misma idea que gobierna el resto de este
       bloque: cada separación con UN SOLO dueño, para no volver a sumar dos
       rellenos sin darse cuenta. */
    margin: var(--ga-space-lg) 0 0;
    text-align: center;

    /* Corta el ancho mínimo del contenido sin recurrir a min-width, para que a
       360px la frase parta en dos líneas en vez de empujar la caja. */
    overflow-wrap: break-word;
}

/* ——— CUANDO EL CONTACTO VIENE JUSTO DETRÁS DEL ENLACE ———
   🔴 EL PROBLEMA ES UNA SUMA DE DOS CEROS. El enlace cierra con margen inferior 0
   —se lo deja entero a la sección de abajo, que es la regla de este bloque: cada
   separación con un solo dueño— y el bloque de contacto abre con padding-top 0, por
   la misma razón vista desde el otro lado. Mientras entre los dos hay preguntas
   frecuentes no se nota, porque el aire lo pone esa sección; en cuanto no las hay,
   los dos ceros se encuentran y el enlace queda pegado al "¿Sigues teniendo alguna
   duda?".

   🔴 POR ESO LA REGLA ES UNA ADYACENCIA Y NO UNA FICHA CONCRETA. El `+` solo casa
   cuando el contacto va INMEDIATAMENTE detrás del enlace, que es exactamente la
   situación rota. Donde las preguntas frecuentes siguen en medio —el resto de la
   tienda— este selector no encuentra nada y no cambia absolutamente nada. Acotarlo
   por SKU habría arreglado la ficha de hoy y dejado la trampa puesta para la
   siguiente que se quedara sin preguntas en medio.

   El valor es el MISMO --ga-space-lg que el enlace ya tiene por arriba, así que
   queda centrado entre el carrusel que lo precede y el contacto que lo sigue, en
   lugar de colgando de uno de los dos.

   ⚠ SE TOCA EL RELLENO SUPERIOR DEL CONTACTO, NO EL INFERIOR DEL ENLACE. Da el mismo
     hueco, pero deja intactas las dos separaciones que el encargo pedía no mover: la
     del enlace con el carrusel de arriba y la del contacto con el pie de abajo.

   ⚠ EVENTOS NO ENTRA: el enlace solo lo pinta la plantilla fuera de Eventos —va
     dentro de un if ( ! $ga_es_eventos )—, así que en una ficha personalizada no
     existe y la adyacencia no puede darse.

   La especificidad (0-4-0, porque :has() toma la de su argumento) gana de sobra a la
   regla de main.css que pone ese padding a 0 (0-2-0). */
.ga-product-single .ga-container:has(.ga-sellos-evento) + .ga-eventos-contacto {
    padding-top: var(--ga-space-lg);
}

/* 🔴 SELECTOR DE TRES CLASES (0-3-0) A PROPÓSITO, PARA NO NECESITAR !important.
   Astra estiliza los enlaces del contenido y ya nos ha pisado los botones de la
   tienda antes (está anotado como trampa en el claude.md). Con la clase del
   párrafo delante, este selector queda por encima de cualquier regla de enlace del
   tema padre sin recurrir a la fuerza bruta. El hover hereda ese peso y sube uno
   más, así que tampoco puede perder.

   Es un enlace NORMAL: ni fondo, ni borde, ni relleno, ni aspecto de botón. Solo
   texto subrayado fino. */
.ga-product-single .ga-sellos-evento .ga-sellos-evento__enlace {
    font-family: var(--ga-font-body);

    /* Discreto: por debajo del texto de los sellos en peso visual, para que remate
       el bloque sin competir con él. */
    font-size: 0.95rem;
    font-weight: 400;
    line-height: 1.5;
    letter-spacing: 0.01em;

    color: var(--ga-verde-oliva-oscuro);

    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.28em;

    background-color: transparent;
    border: 0;
    padding: 0;

    /* 🔴 SOLO EL COLOR TRANSICIONA. Nada de tamaño, nada de posición: ni transform,
       ni cambio de grosor de subrayado, ni padding. Al pasar el ratón, la frase se
       queda EXACTAMENTE donde está y solo se vuelve dorada. */
    transition: color 0.3s ease;
}

/* Hover y foco de teclado, el mismo tratamiento: solo color. El anillo de foco del
   navegador se deja intacto a propósito —no se toca el outline—, porque es lo que
   permite seguir el enlace con el tabulador y no altera la maquetación. */
.ga-product-single .ga-sellos-evento .ga-sellos-evento__enlace:hover,
.ga-product-single .ga-sellos-evento .ga-sellos-evento__enlace:focus-visible {
    color: var(--ga-naranja-apagado);
}

/* ——— MÓVIL: LOS TRES APILADOS ———
   En 640px se rompe la fila. Es el punto en que tres columnas de versalitas se
   quedan tan estrechas que el texto empieza a partirse en tres y cuatro líneas y
   la fila se lee peor apretada que apilada. Cada sello conserva su montaje: icono
   arriba, texto debajo, todo centrado. */
@media (max-width: 640px) {

    .ga-product__valoraciones .ga-sellos-ficha {
        grid-template-columns: minmax(0, 1fr);

        /* 🔴 EL SEPARADOR ENTRE SELLOS SE QUEDA EN 1,5rem Y NO SUBE. Apilados, cada
           sello mide ahora unos 135px en vez de 80, así que la fila entera ronda
           los 450px de alto: es lo que cuesta el icono grande. Ensanchar también
           este hueco sumaría otro tanto de scroll sin ganar legibilidad, porque
           apilados ya se separan solos. */
        gap: var(--ga-space-md);

        /* 2,5rem en vez de los 5rem de escritorio: apilado, el corte de columna ya
           marca el cambio de bloque y el aire de sobremesa dejaría un vacío enorme
           en una pantalla estrecha. */
        margin-block-start: var(--ga-space-lg);

        /* 80px. El icono sigue mandando sobre el texto, pero deja sitio para las
           dos líneas de versalitas sin alargar de más la columna.
           Holgura de sobra: 360px de pantalla menos el relleno de .ga-container
           dejan más de 300px libres para una imagen de 80. */
        --ga-sello-ico: 80px;
    }

    /* El hueco icono-texto baja con el icono, en la misma proporción que arriba. */
    .ga-product__valoraciones .ga-sellos-ficha__item {
        gap: 0.95rem;
    }
}


/* ——— MÓVIL ———
   El montaje no cambia: sigue apilado, que es como nace, y con los mismos
   controles —las flechas ya nacen a tamaño de dedo—. Solo se recorta el aire,
   porque en una pantalla estrecha el espaciado generoso de escritorio deja la
   sección demasiado larga. El cuerpo de la cita ya lo reduce su clamp, sin media
   query. */
@media (max-width: 860px) {

    /* 🔴 TAMBIÉN EN DOS VALORES, Y NO POR SIMETRÍA: SIN ESTO EL AJUSTE NO LLEGA AL
       MÓVIL. Esta regla redeclara padding-block con UN SOLO valor, y un valor único
       vale para arriba Y para abajo: se comería lo que se decide arriba y el hueco
       con "También te puede interesar" volvería a ser otro de 860px para abajo,
       justo donde más se nota. El de arriba sí se queda en 2,5rem, que es lo que
       separa esta sección de la que tiene encima y no se toca.

       Y por abajo va un escalón MENOS que en escritorio —1rem en vez de 1,5rem—,
       porque el vecino también recorta: a ≤768px .ga-eventos-rel baja su relleno
       superior de 4rem a 2,5rem. Así el hueco queda en 3,5rem con los sellos
       apilados, proporcionado a una pantalla estrecha, en vez de las 5rem del
       principio o las 2,5rem a las que se quedó. */
    .ga-product__valoraciones {
        padding-block: var(--ga-space-lg) var(--ga-space-sm);
    }

    .ga-product__valoraciones .ga-val__item {
        padding-block: var(--ga-space-md);
    }

    /* ⚠ LAS FLECHAS NO LLEVAN AQUÍ NINGÚN MARGEN, y no es un olvido: tenían uno
       propio para móvil cuando el de escritorio era grande. Ahora el de base ya es
       mínimo —0,25rem— y sirve igual en las dos anchuras, así que repetirlo aquí
       solo sería un número más que mantener. */
}

/* ——— MOVIMIENTO REDUCIDO ———
   El cambio de página es directo: ni desvanecimiento ni desplazamiento. No se
   quita la funcionalidad, solo la animación. */
@media (prefers-reduced-motion: reduce) {

    .ga-product__valoraciones .ga-val__pagina,
    .ga-product__valoraciones .ga-val__pagina.is-activa,
    .ga-product__valoraciones .ga-val__flecha {
        transition: none;
    }

    .ga-product__valoraciones .ga-val__pagina:not(.is-activa) {
        transform: none;
    }
}


/* =============================================================================
   "TAMBIÉN TE PUEDE INTERESAR" — SOLO EN LAS FICHAS QUE NO SON DE EVENTOS
   -----------------------------------------------------------------------------
   🔴 ESE CARRUSEL LO PINTAN LAS DOS FICHAS CON EL MISMO MARCADO, así que sus
   reglas base —que viven en assets/css/main.css, bloque .ga-eventos-rel- (prefijo
   histórico: hoy sirve a toda la tienda)— NO se pueden editar sin cambiar también
   la ficha de eventos. Lo de aquí abajo se limita a sobrescribirlas para las
   fichas normales.

   EL ACOTADO: .ga-product-single:not(.ga-product-single--eventos). La clase
   --eventos solo la lleva el <main> en esa categoría, así que el :not() deja las
   fichas de eventos EXACTAMENTE como están. Puntúa 0-3-0 frente al 0-1-0 de las
   reglas compartidas, de modo que gana por ESPECIFICIDAD y no por orden de
   aparición: también a las que viven dentro de sus media queries, que no suman
   especificidad (main.css se carga antes que este archivo, pero no se depende de
   ello).

   ⚠ ES EL MISMO TRATAMIENTO QUE YA TIENE LA FICHA DE EVENTOS, no un invento. Allí
     el carrusel va sin marco desde hace tiempo y está validado; aquí se replica en
     lugar de inventar una variante distinta, para que las dos fichas se lean
     igual.
   ============================================================================= */

/* ——— FUERA LA CAJA ———
   Sin recuadro, sin fondo propio y sin relleno: la foto, el nombre, el precio y el
   botón se apoyan directamente sobre el blanco de la sección.

   🔴 EL RELLENO SE VA CON EL BORDE, Y NO ES OPCIONAL. Ese 1rem existía para
   separar el contenido del marco. Sin marco se queda en espacio muerto: sumado al
   hueco de 1rem que ya hay entre tarjetas, dejaba casi 3rem entre una foto y la
   siguiente y la fila se leía desparramada, con las tarjetas sin forma. Quitándolo,
   la separación real entre tarjetas pasa a ser justo el hueco de la pista —1rem—,
   que es la medida con la que ya funciona esta misma fila en la ficha de eventos.
   De paso, las fotos ganan ese ancho y la fila se lee mejor.

   El :hover del borde que ponen las reglas compartidas se queda en nada: un borde
   de 0 no tiene color que cambiar. No hace falta anularlo, y no se pierde el aviso
   de que la tarjeta responde, porque el nombre ya se pone dorado al pasar por
   encima con su propia regla —un cambio de COLOR, que no mueve nada—. */
.ga-product-single:not(.ga-product-single--eventos) .ga-eventos-rel__tarjeta {
    padding: 0;
    background-color: transparent;
    border: 0;
}

/* ——— EL RECUADRO DE LA FOTO, EN BLANCO ———
   🔴 SIN ESTO EL ENCARGO NO SE CUMPLE. La regla compartida le pone al recuadro de
   la foto el crema de marca (--ga-naranja-claro). Mientras había marco no se
   notaba; al quitarlo, ese crema se convierte en el ÚNICO rectángulo que queda a
   la vista y el recuadro no desaparece: se muda de sitio.

   Y arregla de paso un fallo conocido: hay productos cuya foto viene SIN FONDO,
   con el PNG transparente —la mermelada y el aceitunero—, y en ellos el crema se
   colaba por detrás del producto dibujando un rectángulo de otro color en mitad de
   la fila. Es el mismo diagnóstico que ya está escrito y resuelto para la ficha de
   eventos, en main.css.

   ⚠ A los productos que SÍ traen fondo no les afecta: la <img> va con
     object-fit: cover al 100 % de ancho y alto, así que cubre el recuadro entero y
     no deja ver ni un píxel de lo que hay detrás.

   El redondeo sube de --ga-radius-sm a --ga-radius-md: sin marco alrededor, la que
   da forma a la tarjeta es la foto, y la esquina tiene que acompañar. */
.ga-product-single:not(.ga-product-single--eventos) .ga-eventos-rel__foto {
    background-color: var(--ga-blanco);
    border-radius: var(--ga-radius-md);
}

/* ——— EL BOTÓN "VER PRODUCTO", REDONDEADO ———
   .ga-btn declara border-radius: 0 a propósito para toda la web ("estilo recto,
   más elegante"), así que el redondeo hay que pedirlo aquí.

   ⚠ 10px VA EN PÍXELES Y NO EN VARIABLE porque no hay ninguna que valga eso: la
     paleta tiene --ga-radius-sm (4px), --ga-radius-md (8px) y --ga-radius-full.
     Es un valor pedido expresamente, no un color inventado.

   🔴 SOLO EL RADIO. Ni tamaño, ni color, ni relleno, ni tipo de letra: el botón
   sigue heredando .ga-btn--outline-dark --sm igual que antes, y su hover y su foco
   siguen siendo los de siempre —cambian color de fondo, de borde y de texto, nunca
   el grosor del borde ni el relleno—, así que ningún estado mueve la tarjeta ni la
   fila. */
.ga-product-single:not(.ga-product-single--eventos) .ga-eventos-rel__btn {
    border-radius: 10px;
}


/* ——— EL CARRIL DE LAS FLECHAS ———
   Las flechas van en position:absolute contra los bordes de .ga-eventos-rel__zona.
   Sin reservarles sitio se apoyarían ENCIMA de la primera y la última tarjeta, así
   que la zona abre un pasillo a cada lado con su relleno y el carrusel se estrecha
   justo lo que ocupan ellas.

   🔴 ESTO ES LO ÚNICO DE LAS FLECHAS QUE HABÍA QUE REPLICAR. Su aspecto —dorado,
   sin fondo, sin caja, y con el hover cambiando solo el color— ya lo pintan las
   reglas de .ga-eventos-rel__flecha de main.css, que NO llevan ancestro y por tanto
   valen igual en las dos fichas. El carril, en cambio, sí estaba acotado con
   .ga-product-single--eventos, y sin él las flechas taparían producto.

   Las medidas son las MISMAS que usa Eventos, leídas de la misma variable: el hueco
   que abre la zona y lo que mide la flecha salen del mismo número, así que no
   pueden descuadrarse. Y el relleno es POSITIVO: no hay ningún valor negativo que
   pueda sacar nada fuera del ancho de la sección. */
.ga-product-single:not(.ga-product-single--eventos) .ga-eventos-rel__zona {
    --ga-ev-rel-flecha: 2.25rem;
    padding-inline: calc(var(--ga-ev-rel-flecha) + var(--ga-space-xs));
}


/* ——— EL BOTÓN "VER PRODUCTO": VERDE, Y SIN MOVERSE ———
   En reposo va hueco con el borde y el texto en el verde oliva oscuro de marca; al
   pasar el ratón se invierte —fondo verde y texto blanco— conservando el mismo
   borde. El redondeo de 10px y el tamaño no cambian.

   ⚠ ESTUVO EN DORADO Y SE HA DEVUELTO AL VERDE. El dorado es el acento de la ficha
     de EVENTOS, donde este mismo botón sí va dorado; fuera de allí desentonaba.

   ⚠ SÍ, ESTOS COLORES SON LOS MISMOS QUE YA DA .ga-btn--outline-dark, y aun así se
     escriben. No es redundancia por descuido: esta regla tiene que existir de todos
     modos —por el transform, por la sombra y por la transición—, y dejar los
     colores escritos aquí hace que se lea de un vistazo cómo queda el botón sin
     tener que ir a buscar la clase base a main.css. Salen de la MISMA variable, así
     que no pueden desincronizarse.

   🔴 Y AQUÍ SE LE QUITA LA ELEVACIÓN. Esto era lo segundo del encargo y la causa
   estaba localizada, no repartida:

       assets/css/single-product.css, .ga-btn--outline-dark:hover
       → transform: translateY(-2px) + box-shadow: var(--ga-shadow-sm)

   Esa regla le da el tirón de 2px hacia arriba a CUALQUIER botón con esa clase, y
   este la lleva. No se toca allí —la comparten otros botones de la ficha, y el
   encargo era este bloque—: se anula aquí, solo para él.

   ⚠ Y TAMBIÉN AL PULSAR, que es la mitad que se escapa si solo se mira el hover.
     main.css declara para toda la web .ga-btn:active { transform: translateY(1px)
     scale(0.98) } como respuesta táctil. Es un salto pequeño, pero es movimiento, y
     la regla del proyecto no distingue: ningún estado cambia tamaño ni posición.
     Se anula igual, y solo aquí: en el resto de la web ese efecto sigue intacto.

   ⚠ LA TRANSICIÓN SE ESTRECHA A LOS TRES COLORES. .ga-btn declara `transition: all`,
     que incluye transform y box-shadow: quedaría apuntando a propiedades que ya no
     cambian. Enumerándolas, no queda ninguna transición huérfana y además se evita
     que un cambio futuro en .ga-btn vuelva a animar algo que aquí no debe moverse.

   Los selectores puntúan 0-3-0 y 0-4-0, por encima del 0-2-0 de las reglas que
   sobrescriben, así que ganan por especificidad y no por orden de archivos. */
.ga-product-single:not(.ga-product-single--eventos) .ga-eventos-rel__btn {
    background-color: transparent;
    color: var(--ga-verde-oliva-oscuro);
    border-color: var(--ga-verde-oliva-oscuro);
    transition:
        background-color var(--ga-transition-normal),
        border-color var(--ga-transition-normal),
        color var(--ga-transition-normal);
}

.ga-product-single:not(.ga-product-single--eventos) .ga-eventos-rel__btn:hover,
.ga-product-single:not(.ga-product-single--eventos) .ga-eventos-rel__btn:focus-visible {
    background-color: var(--ga-verde-oliva-oscuro);
    color: var(--ga-blanco);
    border-color: var(--ga-verde-oliva-oscuro);
}

/* Ni al pasar el ratón, ni con el teclado, ni al pulsar: el botón se queda quieto y
   solo cambian sus colores. */
.ga-product-single:not(.ga-product-single--eventos) .ga-eventos-rel__btn:hover,
.ga-product-single:not(.ga-product-single--eventos) .ga-eventos-rel__btn:focus,
.ga-product-single:not(.ga-product-single--eventos) .ga-eventos-rel__btn:focus-visible,
.ga-product-single:not(.ga-product-single--eventos) .ga-eventos-rel__btn:active {
    transform: none;
    box-shadow: none;
}


/* ——— EL HUECO SOBRE LAS PREGUNTAS FRECUENTES ———
   Aquí hubo una regla que le recortaba a esa sección el relleno de arriba hasta
   1,5rem, y SE HA QUITADO. Merece quedar escrito por qué, porque quitar una regla
   parece dejar el encargo sin hacer y es justo al revés:

   HISTORIA. El hueco entre "¿Tienes un evento próximamente…?" y el titular
   "Preguntas frecuentes" eran 8rem, y otra vez por SUMA de dos rellenos: las 4rem
   de abajo del párrafo del enlace y las 4rem de arriba de la sección. El titular no
   aportaba nada, .ga-section__titulo nace con margen superior 0. Se pidió juntarlos
   al mínimo y quedaron en 1,5rem; se quedó corto, y ahora se busca el punto medio.

   POR QUÉ NO HAY REGLA NUEVA. El punto medio ya lo daba la propia sección: su
   relleno superior de siempre es --ga-space-xl (4rem), y --ga-space-lg (2,5rem) por
   debajo de 860px. Con el margen inferior del enlace en cero —que es lo que de
   verdad arreglaba el problema, la SUMA de dos rellenos—, esos valores dejan el
   hueco justo entre medias: la mitad de las 8rem del principio y bastante más que
   las 1,5rem de después.

   Escribir aquí una regla con esos mismos números sería repetir lo que el archivo
   ya dice más arriba, y dos sitios declarando lo mismo acaban descuadrados en
   cuanto alguien toca uno. Sin regla, el hueco lo gobierna UN solo valor.

   CÓMO QUEDA:
       escritorio  0 (enlace) + 4rem   = 4rem     ← eran 8rem, y luego 1,5rem
       ≤860px      0 (enlace) + 2,5rem = 2,5rem   ← eran 6,5rem, y luego 1,5rem

   Y en móvil sale más apretado sin tener que pedirlo, que es lo que se quiere en
   una pantalla estrecha: la sección ya nació con esa proporción.

   ⚠ SI HICIERA FALTA AFINARLO, el número está en .ga-product__faq —el padding-block
     de la regla base y el de su media query—, pero OJO: esa clase la llevan también
     las preguntas frecuentes de la ficha de EVENTOS. Para tocar solo estas hay que
     acotar con .ga-product-single:not(.ga-product-single--eventos) y usar
     padding-top, nunca el atajo padding-block, que se llevaría por delante la
     separación de abajo. */


/* =============================================================================
   TARROS DE ACEITUNAS — LA FICHA REPARTIDA DE OTRA MANERA
   =============================================================================
   Solo en los tarros. La puerta es la clase .ga-product-single--aceitunas, que
   pinta single-product-custom.php a partir de la CATEGORÍA del producto y que ya
   deja fuera los packs y las fichas de Eventos. En aceites, packs y todo lo demás
   ninguno de estos selectores existe, así que esas fichas no cambian.

   QUÉ CAMBIA, EN DOS MOVIMIENTOS:

     1. La descripción corta y los cuatro desplegables se van a la columna de
        compra, bajo la franja de sellos. Eso lo hace el PHP: aquí abajo solo se
        ajusta la separación con esa franja.

     2. El hueco que dejan bajo la foto lo ocupa "No te quedes sin probar los
        demás aliños", que REUTILIZA TAL CUAL la maquetación de "Combínalas con
        otras del mismo tamaño" de las fichas de Eventos.

   🔴 NO SE TOCA UNA SOLA REGLA DE ESA CUADRÍCULA. Las .ga-eventos-combina-* viven
   en main.css y —pese al prefijo— NO están acotadas a Eventos: son selectores de
   clase sueltos, así que valen en cualquier ficha. De ahí salen, sin copiar nada,
   las proporciones de la tarjeta, el borde, el radio, el fondo de carga y el
   reparto en tres columnas. Lo de aquí abajo es SOLO lo que esa cuadrícula no
   traía, y todo cuelga del modificador propio --alinos, que Eventos no lleva:
   ninguna de estas reglas puede alcanzar a la ficha de Eventos.
   ============================================================================= */

/* ——— (1) LA SEPARACIÓN CON LA FRANJA DE SELLOS ———
   La columna de compra es un flex en columna con un gap de 0,35rem —a propósito,
   para que el bloque de compra y la franja de sellos queden encadenados—, y contra
   una caja con borde ese hueco se queda corto: el texto arrancaba pegado a la
   franja.

   Se le devuelve aire con un margen propio, que se SUMA al gap (en un contenedor
   flexible los márgenes de hermanos no se colapsan): 0,35 + 1 = 1,35rem.

   Los DOS selectores hacen falta: si el producto no tuviera descripción corta, el
   primer bloque tras la franja sería el acordeón, y sin su línea se quedaría
   pegado. El + los ata a la franja, así que el margen solo aparece cuando de
   verdad van detrás de ella. */
.ga-product-single--aceitunas .ga-product__trust-band + .ga-product__short-desc--gal,
.ga-product-single--aceitunas .ga-product__trust-band + .ga-product__acordeon-col,
.ga-product-single--sku-ga-acc-aceitunero .ga-product__trust-band + .ga-product__acordeon-col {
    margin-top: var(--ga-space-sm);
}

/* ——— (2a) LA COLUMNA DE LA FOTO DEJA DE IR PEGADA ———
   Mismo motivo, y mismo arreglo, que el que ya lleva .ga-product__grid--combina en
   las fichas de Eventos: con position: sticky, la parte de abajo de esta columna
   —justo la cuadrícula de aliños— se quedaría permanentemente fuera de la vista.

   Se escribe aquí y no se reutiliza aquella regla a propósito: aquella pertenece
   al bloque de Eventos y su clase la pone la cuadrícula de botellas. Con la suya
   propia, esta ficha no depende de que aquel bloque siga existiendo.

   Solo en escritorio: por debajo de 861px la columna ya no es pegajosa. */
@media (min-width: 861px) {

    .ga-product-single--aceitunas .ga-product__gallery {
        position: static;
    }
}

/* Aire por encima del bloque: el gap de esta columna es de 0,5rem y un bloque con
   título necesita algo más para no parecer parte de la foto. 0,5 + 1 = 1,5rem. */
.ga-eventos-combina--alinos {
    margin-top: var(--ga-space-sm);

    /* ═══════════════════════════════════════════════════════════════════════
       LOS TRES TIEMPOS DEL CICLO DE AÑADIR AL CARRITO — FUENTE ÚNICA
       ═══════════════════════════════════════════════════════════════════════
       🔴 EL JS LOS LEE DE AQUÍ, NO LOS REPITE. gaAlinosCarrito(), en
       single-product.js, saca estos tres valores con getComputedStyle sobre este
       mismo elemento. Es la única forma de que el temporizador del tique y las
       transiciones que lo pintan no se desincronicen: cambiar un número aquí
       cambia las dos mitades a la vez.

       Y no es una precaución teórica. El fallo típico de estas confirmaciones es
       exactamente ese: contar el tiempo del tique desde el clic mientras el fundido
       de entrada se come los primeros milisegundos, de modo que el tique se ve
       bastante menos de lo que dice el número. Aquí el JS suma CONFIRMAR + TIQUE
       precisamente para que el segundo se cuente DESDE QUE EL TIQUE ESTÁ DEL TODO
       VISIBLE.

         confirmar → dorado que pasa a verde y carrito que se cruza con el tique
         tique     → cuánto se queda el tique quieto, ya del todo visible
         volver    → verde que vuelve al dorado y tique que devuelve el carrito

       La vuelta es más lenta que la ida a propósito: la ida acompaña a un clic que
       el cliente acaba de dar y tiene que sentirse inmediata; la vuelta es el
       sistema recogiendo, y si va igual de rápida se lee como un parpadeo.

       🔴 LA IDA BAJA A 120ms, Y VA CON EL CAMBIO DE ORDEN DEL JS. Desde que la
       confirmación se pinta EN EL CLIC —sin esperar al servidor—, esta duración es
       lo único que separa el dedo del tique. A 200ms todavía se percibía el carrito
       yéndose; a 120 el cambio se lee como instantáneo y sigue sin ser un corte
       seco. Por debajo de 100 deja de leerse como una transición y empieza a parecer
       un salto. */
    --ga-alinos-confirmar: 120ms;
    --ga-alinos-tique:     1500ms;
    --ga-alinos-volver:    250ms;
}

/* ——— TRES COLUMNAS EN TODOS LOS ANCHOS: 3 + 3 + 2 ———
   Aquí hubo un tramo con CUATRO columnas por encima de 601px, para que los ocho
   elementos —las siete variedades que no son la que se está viendo, más el
   aceitunero— cayeran en dos filas exactas. Se vuelve a TRES, que es lo que pide el
   diseño: tres filas de 3, 3 y 2.

   LAS DOS ÚLTIMAS QUEDAN A LA IZQUIERDA SIN TENER QUE PEDIRLO. Una rejilla coloca sus
   elementos desde el principio de cada fila, y ni esta regla ni la base tocan
   justify-content, así que las dos sobrantes ocupan la primera y la segunda columna.
   Para centrarlas habría que pedirlo expresamente, y no se pide.

   Y LAS TARJETAS CRECEN SOLAS: de unos 159px a unos 215px en pantalla ancha, y de
   unos 103px a unos 138px en el tramo más justo de la ficha (861px, cuando vuelve a
   tener dos columnas y esta rejilla se mete en la estrecha). En móvil no cambia
   absolutamente nada: por debajo de 601px ya estaba en tres columnas.

   🔴 EL ESCALADO DE LAS FOTOS NO SE TOCA, Y NO ES UN OLVIDO. El 1.35 del bloque (2d)
   es un transform, o sea una proporción: la foto se pinta un 35 % más grande QUE SU
   TARJETA, mida esta lo que mida. Al ensanchar la tarjeta, la foto ensancha con ella
   y el tarro sigue llenando exactamente el mismo 90 % del recuadro que llenaba con
   cuatro columnas. Subir el número ahora no haría que llenara más "porque hay sitio":
   haría que se saliera, porque el margen que queda es porcentual y sigue siendo el
   mismo 3 %. Por eso la tarjeta más ancha se ve mejor sin cambiar una sola cifra.

   minmax(0, 1fr) y no 1fr a secas: es lo que deja a las celdas encoger por debajo del
   ancho de su contenido sin recurrir a min-width, que en este proyecto no se usa. Sin
   ese minmax, un nombre largo ensancharía su columna y la fila podría acabar siendo
   más ancha que el viewport.

   ⚠ SE DECLARA AQUÍ AUNQUE LA REGLA BASE YA DIGA TRES. Podría bastar con borrar el
     tramo de cuatro y dejar que mandara .ga-eventos-combina__rejilla, que es la
     cuadrícula de botellas de Eventos… y ahí está el problema: entonces este bloque
     dependería de que aquella no cambie nunca. Escrito aquí, el 3 + 3 + 2 es una
     decisión de esta rejilla y no una casualidad heredada. Sigue acotado a --alinos,
     así que Eventos no se entera de nada. */
.ga-eventos-combina--alinos .ga-eventos-combina__rejilla {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

/* ——— EL ÁREA DE IMAGEN, EN BLANCO Y NO EN CREMA ———
   🔴 LO PIDE EL ACEITUNERO, PERO SE LE PONE A LAS OCHO. Su foto viene con el fondo
   TRANSPARENTE, así que lo que se veía por detrás era el crema del recuadro y su
   tarjeta desentonaba con las demás. Las fotos de tarro, en cambio, vienen recortadas
   sobre blanco, de modo que su recuadro crema solo asomaba por los bordes: poco, pero
   lo justo para que las nueve no casaran del todo.

   Poniendo blanco en TODAS, el fondo de la foto y el del recuadro son el mismo color
   en las de tarro —el crema desaparece— y el aceitunero cae sobre ese mismo blanco.
   La fila queda uniforme y ninguna tarjeta canta.

   Es exactamente el mismo criterio, y por el mismo motivo, que el de la galería
   grande de estas fichas, que también se pasó a blanco: "el blanco se confunde con el
   de las propias fotos de producto, que van recortadas sobre blanco; con el crema,
   cualquier hueco cantaba".

   ⚠ SOLO EL FONDO. El borde de 1px en amarillo pastel, el radio y el recorte se
     quedan como están: siguen viniendo de la cuadrícula de Eventos y no se tocan.

   ⚠ NI EL VELO NI EL CÍRCULO SE ENTERAN. La capa oscura va con inset: 0 DENTRO de
     este mismo recuadro, así que sigue cubriendo exactamente el área de la imagen —el
     borde queda fuera, como antes—, y el círculo lo sigue centrando el flex de esa
     capa. Ninguno de los dos depende del color del fondo.

   ⚠ Y NO ALCANZA A EVENTOS: su cuadrícula no lleva el modificador --alinos, así que
     sus miniaturas conservan el crema de siempre. */
.ga-eventos-combina--alinos .ga-eventos-combina__foto {
    background-color: var(--ga-blanco);
}

/* ——— (2b) EL NOMBRE, SIEMPRE VISIBLE ———
   En Eventos el nombre vive DENTRO del velo que tapa la foto al pasar el ratón, y
   el nombre de debajo solo aparece donde no hay ratón. Aquí el velo no lleva texto
   —encima va el círculo de carrito— así que el nombre tiene que verse siempre, con
   ratón y sin él.

   Se enciende el que YA EXISTE en el marcado en vez de inventar otro: hereda de
   Eventos la tipografía, el color, el centrado y su separación con la foto. Lo único
   que cambia aquí es el TAMAÑO y el alto reservado; ni una cosa ni la otra alcanzan
   a la cuadrícula de Eventos, que no lleva el modificador --alinos. */
.ga-eventos-combina--alinos .ga-eventos-combina__nombre-fijo {
    display: block;

    /* UN ESCALÓN DE LA RAMPA, DE 12 A 14px. Es el mismo salto que separa cualquier
       par de tamaños contiguos del proyecto, así que no hay ningún número nuevo. Y
       sigue muy por debajo del título del bloque, que va en Cormorant entre 19 y 24px:
       el nombre se lee más cómodo pero no compite con él ni cambia la jerarquía. */
    font-size: var(--ga-text-sm);

    /* ——— DOS LÍNEAS RESERVADAS SIEMPRE ———
       Al quitar el peso, unos nombres pasan a caber en una línea y otros siguen
       necesitando dos, y entonces las tarjetas de una misma fila acaban de alto
       distinto y la rejilla se ve descuadrada por abajo.

       Con un suelo de dos líneas, la de una línea reserva el mismo hueco que la de
       dos y todas cierran a la misma altura.

       🔴 min-height Y NO height. Es un SUELO, no un alto fijo: los nombres más
       largos —"Cóctel de Aceitunas y Encurtidos · Sabor Anchoa" en una tarjeta
       estrecha— siguen necesitando tres líneas y las tienen. Con un `height` se
       saldrían de su caja o habría que cortarlos, y en este proyecto un nombre de
       producto no se corta nunca con puntos suspensivos.

       LA CUENTA VA EN em, NO EN PÍXELES: 1,3 es el interlineado que hereda de
       Eventos, así que dos líneas son 2,6em de su PROPIO tamaño de letra. Si mañana
       se cambia el font-size de aquí arriba, el hueco se ajusta solo y no hay dos
       números que sincronizar. (min-height sí está permitido; el prohibido es
       min-width.) */
    min-height: calc(2 * 1.3em);
}

/* =============================================================================
   (2c) LO QUE PASA AL PASAR EL RATÓN: CAPA OSCURA + CÍRCULO DE CARRITO
   =============================================================================
   Sobre la foto se apilan TRES capas, y este es el orden de arriba abajo:

     3 · la capa oscura         (.ga-alinos__velo)      z-index 2
         └ el círculo           (.ga-alinos__cart)      — sin posición propia
     2 · la cubierta, el enlace (.ga-alinos__cubierta)  z-index 1
     1 · la foto                (.ga-eventos-combina__img)

   Las dos de arriba van en position: absolute dentro de .ga-eventos-combina__foto,
   que ya viene de Eventos con position: relative, aspect-ratio 1/1 y overflow
   hidden. Al estar FUERA DEL FLUJO, ninguna puede cambiar el tamaño ni la posición
   de la tarjeta ni de la foto: el hueco que ocupan es siempre el mismo, se vean o
   no, y lo único que cambia entre estados es el color y la opacidad.

   🔴 EL CÍRCULO NO SE COLOCA: LO COLOCA LA CAPA. La capa cubre exactamente la caja
   de la foto y centra por flex; el círculo es su ÚNICO hijo y no lleva ni top, ni
   left, ni transform. Así el centrado no depende de compensar nada.

   ⚠ ANTES SÍ DEPENDÍA, Y POR ESO SALÍA DESPLAZADO. El círculo iba suelto, con
     top/left al 50 % y un translate(-50%,-50%) que lo recolocaba. Ese montaje
     centra solo mientras nadie le toque el transform; en cuanto una regla de otro
     sitio se lo cambia, el 50 % se queda sin compensar y el círculo se va hacia la
     derecha y hacia abajo justo la mitad de su tamaño. Con el flex no hay nada que
     compensar, así que no hay nada que se pueda descompensar.

   🔴 EL VELO NO RECIBE EL RATÓN, PERO EL CÍRCULO SÍ. La capa va con
   pointer-events: none para que el clic la atraviese y llegue a la cubierta que
   tiene debajo; el círculo, que es su hijo, lo recupera con pointer-events: auto.
   Por eso la capa puede estar POR ENCIMA de la cubierta sin comerse ni un clic.
   ============================================================================= */

/* ——— LA CAPA OSCURA ———
   Cubre EXACTAMENTE la caja de la foto: con inset: 0 dentro de
   .ga-eventos-combina__foto se ajusta a su caja de relleno, o sea la imagen entera
   y ni un píxel más —el borde de la miniatura se queda fuera y el nombre, que es
   hermano de esta caja, ni se roza—.

   NEGRO PURO al 55%, el mismo criterio que el velo de Eventos y por el mismo
   motivo: cualquier velo de color —verde, gris o cálido— TIÑE la foto; el negro
   solo le quita luz. Se queda cuatro puntos por debajo de aquel (62%) porque aquí
   no hay texto blanco que sostener encima, solo un círculo dorado que ya destaca
   por sí mismo, y con menos velo el tarro se sigue viendo.

   🔴 SE ENCIENDE POR EL COLOR DEL FONDO, NO POR LA OPACIDAD DE LA CAPA, y esto es
   lo que permite que el círculo sea hijo suyo. Si se apagara la capa con
   opacity: 0, se llevaría por delante al círculo que lleva dentro... y en los
   táctiles el círculo tiene que verse SIN capa oscura. Dejando la capa siempre
   presente y transparente, cada uno decide por su cuenta: la capa se oscurece con
   el ratón y el círculo se muestra cuando le toca.

   El negro transparente de partida se escribe con el alfa a cero —y no con la
   palabra transparent— para que la transición vaya de negro a negro y no pase por
   ningún tono intermedio raro. */
.ga-eventos-combina--alinos .ga-alinos__velo {
    position: absolute;
    inset: 0;
    z-index: 2;

    display: flex;
    align-items: center;
    justify-content: center;

    background-color: rgba(0, 0, 0, 0);
    pointer-events: none;
    transition: background-color var(--ga-transition-normal);
}

/* ——— LA CUBIERTA ———
   El enlace a la ficha, extendido sobre toda la foto. No pinta nada: solo recoge el
   clic. Existe porque el círculo es un <a> y no puede vivir dentro de otro <a>, así
   que el enlace de la tarjeta no puede envolver la foto (ver el comentario largo de
   la plantilla).

   Va POR DEBAJO de la capa, que no recibe el ratón: pulsar en cualquier punto de la
   foto lleva a la ficha, y pulsar en el círculo añade al carrito. */
.ga-eventos-combina--alinos .ga-alinos__cubierta {
    position: absolute;
    inset: 0;
    z-index: 1;
    /* Sin fondo ni borde: es una zona de clic, no una capa que se vea. */
    background: none;
    border: 0;
}

/* El aro de foco de la cubierta no debe salir: no la enfoca nadie (tabindex="-1") y
   el foco visible de la tarjeta lo da el enlace del nombre. */
.ga-eventos-combina--alinos .ga-alinos__cubierta:focus,
.ga-eventos-combina--alinos .ga-alinos__cubierta:focus-visible {
    outline: none;
}

/* ——— EL CÍRCULO DE CARRITO ———
   SIN POSICIÓN PROPIA: ni position, ni top, ni left, ni transform. Lo centra el flex
   de la capa que lo contiene, en los dos ejes y de una vez. Es lo único que hace
   falta y es lo que garantiza que siga centrado pase lo que pase con la foto —por
   ejemplo, al escalarla, que es lo que se hace más abajo—.

   🔴 HAY QUE ANULAR EL TAMAÑO Y LA FORMA QUE TRAE DE LA TIENDA, Y AHORA MÁS QUE
   ANTES. Allí .ga-home-card__cart es una celda de una fila de botones
   (flex: 0 0 28% + max-width: 28% + border-radius: 5px). Mientras el círculo iba en
   posición absoluta, el `flex` se apagaba solo —un elemento posicionado en absoluto
   deja de ser ítem flexible—; ahora que ES ítem flexible de la capa, ese
   `flex: 0 0 28%` vuelve a estar vivo y le daría al círculo el 28 % del ancho de la
   foto. Por eso se pone `flex: 0 0 auto` y se le dan medidas propias: sin esa línea
   el círculo cambiaría de tamaño con el ancho de la tarjeta.

   44px (2,75rem) NO ES UN NÚMERO CUALQUIERA: es el objetivo táctil mínimo
   recomendado. A 360px la miniatura mide unos 104px, así que el círculo ocupa poco
   más de un tercio de la foto: se pulsa con comodidad sin comerse la imagen. */
.ga-eventos-combina--alinos .ga-alinos__cart {
    flex: 0 0 auto;
    width: 2.75rem;
    height: 2.75rem;
    max-width: none;
    border-radius: 50%;
    box-sizing: border-box;

    /* La capa que lo contiene no recibe el ratón, para no comerse los clics que van
       a la ficha; el círculo lo recupera, porque él sí tiene que poder pulsarse. */
    pointer-events: auto;

    /* 🔴 DORADO DE MARCA, Y SE CAMBIA POR LA VARIABLE, NO POR EL FONDO. main.css
       declara el fondo y el borde de este botón con !important —se defiende de los
       estilos de Astra y de WooCommerce, que le ganarían en especificidad—, así que
       intentar reescribir background-color aquí sería pelear contra un !important.

       Pero ese fondo está construido a partir de dos variables locales, y eso es
       justo lo que el bloque de main.css dice que hay que redefinir para cambiarle
       el color a un estado. Se toca la variable y el !important trabaja a favor.

       ⚠ NO SE TOCA --ga-cart-luz, la otra mitad del par. Esa variable solo la usa el
         degradado del brillo, que aquí está apagado unas líneas más abajo: darle un
         valor obligaría a inventarse un dorado aclarado que no está en la paleta, y
         no lo vería nadie. Se queda con el que trae de main.css. */
    --ga-cart-fondo: var(--ga-naranja-apagado);

    /* Sin el barrido de luz de la tienda: allí es un botón ancho dentro de una
       tarjeta y el destello se lee bien; aquí son varios círculos pequeños sobre
       fotos, y todos esos degradados moviéndose a la vez ensucian la cuadrícula. El
       !important es obligado: el degradado de main.css lo lleva también. */
    background-image: none !important;
    animation: none;

    /* 🔴 REJILLA DE 1×1 PARA PODER CRUZAR LOS DOS ICONOS. main.css lo deja en
       inline-flex, que los pondría UNO AL LADO DEL OTRO; con la rejilla comparten
       celda y se apilan, que es lo que permite fundir el carrito con el tique en vez
       de cambiarlos de golpe. No cambia ni el tamaño ni la posición del círculo: las
       medidas son las de arriba y el contenido sigue centrado.

       Es el mismo recurso que usa la galería de la ficha para cruzar sus fotos sin
       pantallazo (🪤 nº 17): apilar y cruzar opacidades, nunca encender y apagar. */
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    place-items: center;

    /* 🔴 OCULTO CON visibility, NO CON pointer-events. La tentación es apagarlo con
       pointer-events: none y encenderlo con auto, y ahí está la trampa: main.css usa
       justo esa propiedad para BLOQUEAR el botón mientras la petición está en curso
       (.ga-home-card__cart[aria-disabled="true"]), que es lo que impide que un doble
       clic añada dos unidades. Un pointer-events: auto nuestro, con más
       especificidad, desactivaría esa protección sin que se note hasta que alguien
       pulse dos veces.

       visibility: hidden deja el círculo fuera del alcance del ratón igual de bien,
       no toca esa propiedad y tampoco cambia tamaño ni posición.

       ⚠ NACE VISIBLE. Este es el estado de los TÁCTILES, que es donde no hay hover:
         allí el círculo se ve siempre y no hay capa oscura. Quien lo esconde es el
         bloque @media (hover: hover) de más abajo. Escrito al revés —nacer oculto y
         encenderlo en los táctiles— un navegador que no entendiera la consulta
         dejaría el círculo invisible y sin forma de añadir; así, lo peor que puede
         pasar es que se vea siempre, que es lo mismo que en un móvil. */
    opacity: 1;
    visibility: visible;

    /* ESTA ES LA TRANSICIÓN DE VUELTA (--ga-alinos-volver). La de IDA, más corta, la
       declara .is-ok unas líneas más abajo: la duración del cambio de color depende
       de hacia dónde va, y en CSS eso se consigue declarando la transición en los dos
       estados. Es el mismo recurso que usan las flechas de la página Nosotros. */
    transition: opacity var(--ga-transition-normal),
                visibility var(--ga-transition-normal),
                background-color var(--ga-alinos-volver),
                border-color var(--ga-alinos-volver);
}

/* El icono, más pequeño que en la tienda: allí son 28px en un botón ancho, y aquí
   se quedarían sin aire dentro de un círculo de 44. A 22px queda un margen de 11px
   por lado y el círculo se lee como un círculo.

   Las DOS clases, porque son los dos SVG que se turnan: el carrito y el tique. Si
   solo se ajustara uno, al confirmar el icono cambiaría de tamaño, que es
   exactamente lo que no puede pasar. */
.ga-eventos-combina--alinos .ga-alinos__cart .ga-home-card__cart-ico,
.ga-eventos-combina--alinos .ga-alinos__cart .ga-home-card__cart-ok {
    /* LOS DOS EN LA MISMA CELDA: apilados, no en fila. Es lo que permite cruzarlos
       con opacidad.

       🔴 display: block ES OBLIGATORIO Y ANULA UNA REGLA DE main.css. Allí el tique
       nace con display: none y solo aparece —también de golpe— cuando el botón lleva
       la clase .ga-anadido. Un elemento con display: none no se puede fundir: no
       existe hasta que existe del todo. Aquí los dos existen siempre y lo único que
       cambia es su opacidad, que sí se anima.

       Esa regla de main.css puntúa 0-2-0 y esta 0-3-0, así que gana por
       especificidad y no por orden de carga. */
    grid-area: 1 / 1;
    display: block;

    width: 1.375rem;
    height: 1.375rem;

    /* El icono es blanco sobre el dorado de marca, y ese par da 2,3:1 de contraste:
       suficiente para verse, corto para la norma de elementos gráficos (3:1). Se
       respeta el blanco porque es la decisión de diseño, y se le añade una sombra
       oscura muy corta que le dibuja el borde. No cambia el color: solo lo despega.
       Es el mismo recurso que usa el texto del velo de Eventos. */
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35));

    /* La VUELTA, igual que en el círculo. La ida la declara .is-ok. */
    transition: opacity var(--ga-alinos-volver);
}

/* Estado de reposo: se ve el carrito y el tique está apagado. */
.ga-eventos-combina--alinos .ga-alinos__cart .ga-home-card__cart-ico {
    opacity: 1;
}

.ga-eventos-combina--alinos .ga-alinos__cart .ga-home-card__cart-ok {
    opacity: 0;
}

/* ——— AL CONFIRMARSE: VERDE OSCURO Y TIQUE, LOS DOS EN FUNDIDO ———
   La clase .is-ok la pone y la quita gaAlinosCarrito() en single-product.js, que es
   quien gobierna el ciclo entero.

   ⚠ YA NO SE USA .ga-anadido, la clase de las tarjetas de la tienda. El ciclo de
     aquí no es el de allí —tiene espera, fundido de ida, tiempo de tique contado
     desde que se ve y fundido de vuelta—, así que lleva sus propias clases. De paso,
     las reglas de .ga-anadido de main.css (que cambian los iconos con display, sin
     transición posible) dejan de aplicarse solas, sin tener que anular nada.

   🔴 EL VERDE ES AHORA --ga-verde-montanas, EL VERDE CLARO DE MARCA. Antes era el
   verde oliva oscuro. Se aclara porque el oscuro, sobre una capa negra al 55 %,
   pesaba demasiado: la confirmación se leía como un apagón en mitad de la foto en
   vez de como un "hecho".

   NO ES UN COLOR NUEVO NI UN color-mix: --ga-verde-montanas está en la paleta desde
   el principio y es LA VARIABLE DE ÉXITO del proyecto —la que usan los subtítulos,
   el "compra en tienda" y, sobre todo, la confirmación de las tarjetas de la tienda
   en main.css—. Así que este círculo y el de la tienda confirman ahora con el mismo
   verde, que es como debería haber sido desde el principio.

   ⚠ EL TIQUE BLANCO SE SIGUE LEYENDO: blanco sobre #7f8649 da 3,89:1, por encima del
     3:1 que pide la norma para elementos gráficos. Es menos que los 9,2:1 del oliva
     oscuro que había antes, pero sigue estando en regla y el tique es una forma
     grande y simple, no texto pequeño. Además conserva la sombra corta que ya llevan
     los dos iconos, que le dibuja el borde.

   ═══════════════════════════════════════════════════════════════════════════
   🔴 POR QUÉ ESTE SELECTOR ES TAN LARGO — EL VERDE SE PERDÍA A RATOS
   ═══════════════════════════════════════════════════════════════════════════
   Aquí había antes un simple `.ga-eventos-combina--alinos .ga-alinos__cart.is-ok`,
   con un comentario que decía que puntuaba 0-4-0 y ganaba a los :hover, :focus y
   :active de más abajo. ERA FALSO, Y ESE FUE EL FALLO:

     .ga-eventos-combina--alinos .ga-alinos__cart.is-ok    → 3 clases    = 0-3-0
     .ga-eventos-combina--alinos .ga-alinos__cart:hover    → 2 clases
                                                            + 1 pseudoclase = 0-3-0

   UNA PSEUDOCLASE PUNTÚA EN LA MISMA COLUMNA QUE UNA CLASE. Los dos selectores
   empataban a 0-3-0, y en un empate manda el que va DESPUÉS en el archivo… que era
   el del dorado. Resultado: mientras el ratón seguía encima —o mientras el enlace
   conservaba el foco después del clic, que en Chrome y Firefox es siempre— el
   círculo se quedaba DORADO durante toda la confirmación, y el verde solo asomaba
   cuando el puntero y el foco se habían ido. De ahí el "unas veces sí y otras no":
   no dependía del ciclo, dependía de dónde estuviera el ratón.

   ✅ SE ARREGLA CON ESPECIFICIDAD, NO CON !important. Dos medidas a la vez:

     · se cuelga de la celda, que sube el selector base a 0-4-0;
     · y se enumeran los tres estados interactivos, que suben a 0-5-0.

   Con la primera bastaría hoy; la segunda es la que garantiza que siga bastando si
   mañana alguien añade otra regla de hover. Es exactamente el mismo recurso que usa
   main.css en su propio estado de "añadido", y por el mismo motivo.

   ⚠ AL TOCAR ESTE BLOQUE, CONTAR LAS PSEUDOCLASES. Es el error que costó este fallo:
     :hover, :focus y :active NO son "medio punto", valen lo mismo que una clase. */
.ga-eventos-combina--alinos .ga-eventos-combina__celda .ga-alinos__cart.is-ok,
.ga-eventos-combina--alinos .ga-eventos-combina__celda .ga-alinos__cart.is-ok:hover,
.ga-eventos-combina--alinos .ga-eventos-combina__celda .ga-alinos__cart.is-ok:focus,
.ga-eventos-combina--alinos .ga-eventos-combina__celda .ga-alinos__cart.is-ok:active {
    --ga-cart-fondo: var(--ga-verde-montanas);

    /* La transición de IDA, más corta que la de vuelta. Se redeclara entera porque
       una transition no se hereda por partes: lo que no se nombre aquí se quedaría
       sin animar mientras la clase esté puesta. */
    transition: opacity var(--ga-transition-normal),
                visibility var(--ga-transition-normal),
                background-color var(--ga-alinos-confirmar),
                border-color var(--ga-alinos-confirmar);
}

/* El cruce de iconos: el carrito se va y el tique llega, a la vez y con la misma
   duración, así que en ningún momento se ven los dos ni se ve el círculo vacío.

   SE CUELGAN DE LA CELDA IGUAL QUE EL COLOR, y no porque hoy haga falta: hoy ninguna
   regla de :hover, :focus o :active toca la opacidad de los iconos, así que el tique
   sí se veía siempre —el fallo del color no le afectaba—. Se sube de todos modos por
   dos motivos: que todo el estado confirmado puntúe igual y no haya que volver a
   contar clase por clase, y que si mañana alguien añade un hover sobre los iconos no
   pueda devolver el carrito en mitad de la confirmación. */
.ga-eventos-combina--alinos .ga-eventos-combina__celda .ga-alinos__cart.is-ok .ga-home-card__cart-ico {
    opacity: 0;
    transition: opacity var(--ga-alinos-confirmar);
}

.ga-eventos-combina--alinos .ga-eventos-combina__celda .ga-alinos__cart.is-ok .ga-home-card__cart-ok {
    opacity: 1;
    transition: opacity var(--ga-alinos-confirmar);
}

/* 🔴 EL CÍRCULO SE QUEDA DORADO AL PASARLE EL RATÓN POR ENCIMA, Y ESTA REGLA ES LA
   QUE LO CONSIGUE. Sin ella no se quedaría: main.css pinta estos tres estados de
   VERDE (#63663a al pasar el ratón, #3a3a22 al pulsar) porque allí el botón parte
   del verde, y esas reglas se aplican igual aquí. El resultado sería un círculo que
   aparece dorado y se vuelve verde en cuanto el ratón lo alcanza, que es justo lo
   contrario de lo que se pide.

   Se devuelven los tres al MISMO dorado en vez de inventar un dorado oscurecido
   para el hover: la paleta no tiene esa variante, y el proyecto no admite colores
   fuera de las variables de marca. Tampoco hace falta ninguna señal extra —el
   círculo apareciendo YA es la respuesta al ratón— y la confirmación del clic sigue
   siendo inconfundible, porque salta al verde oscuro con el tique.

   ⚠ ESTOS TRES ESTADOS NO PUEDEN CON EL VERDE DE LA CONFIRMACIÓN, y es a propósito:
     puntúan 0-3-0 y el bloque de .is-ok de más arriba puntúa 0-4-0 y 0-5-0. Antes
     empataban con él y le ganaban por orden, que es exactamente el fallo que se ha
     corregido. */
.ga-eventos-combina--alinos .ga-alinos__cart:hover,
.ga-eventos-combina--alinos .ga-alinos__cart:focus,
.ga-eventos-combina--alinos .ga-alinos__cart:active {
    --ga-cart-fondo: var(--ga-naranja-apagado);
}

/* =============================================================================
   EL CONTORNO PUNTEADO AL PULSAR — DE DÓNDE SALÍA Y CÓMO SE QUITA
   =============================================================================
   🔴 NO ERA DEL NAVEGADOR NI UN box-shadow DEL TEMA: ES UNA REGLA DE ASTRA. En su
   hoja principal (assets/css/minified/main.min.css) hay, heredada del tema base del
   que sale Astra:

       a:focus { outline: thin dotted }

   El círculo es un <a>, y al pulsarlo con el ratón el navegador se lo queda enfocado
   —eso pasa en Chrome y en Firefox, y el preventDefault() del JS no lo evita, porque
   el foco se asigna en el mousedown—. Con el foco puesto, esa regla de Astra pinta el
   punteado y ahí se queda hasta que se pulse en otro sitio.

   Y no lo tapaba nada: main.css sí declara un aro dorado para este botón, pero lo
   hace con :focus-visible, que en un clic de ratón NO casa. Así que el único
   contorno que se veía al pulsar era el de Astra.

   ✅ LA SOLUCIÓN NO ES QUITAR EL FOCO, SINO DISTINGUIR CÓMO SE LLEGÓ A ÉL. Son dos
   reglas y el orden entre ellas importa:

     · :focus         → sin contorno. Cubre el clic de ratón, que es donde molesta.
     · :focus-visible → el aro dorado de marca, continuo. Es el que el navegador
                        activa cuando se llega con el tabulador, y va DESPUÉS para
                        ganar el empate: las dos puntúan 0-3-0 y cuando se navega con
                        teclado casan las dos a la vez.

   Hacía falta repetir aquí el aro dorado —ya existe en main.css— porque aquel puntúa
   0-2-0 y el :focus de aquí arriba, 0-3-0, se lo habría llevado por delante también
   en el teclado. Es el mismo dorado y las mismas medidas: no es un aro nuevo.

   ⚠ SOLO ESTE CÍRCULO. Los dos selectores cuelgan de .ga-eventos-combina--alinos, así
     que ningún otro botón de la web cambia: el punteado de Astra sigue donde estaba.

   ⚠ UN outline NO OCUPA SITIO EN EL LAYOUT: se pinta por fuera de la caja y no empuja
     nada. Ni al enfocar ni al dejar de enfocar se mueve un píxel de la cuadrícula. */
.ga-eventos-combina--alinos .ga-alinos__cart:focus {
    outline: none;
}

.ga-eventos-combina--alinos .ga-alinos__cart:focus-visible {
    outline: 2px solid var(--ga-naranja-apagado);
    outline-offset: 2px;
}

/* ——— EL BLOQUEO: SOLO BLOQUEA, YA NO ATENÚA ———
   El aria-disabled dura AHORA TODO EL CICLO —desde el clic hasta que el tique se ha
   ido— porque hasta entonces el círculo no debe admitir otro clic. Si además
   atenuara, el tique se vería a media luz durante todo su minuto de gloria, que es
   justo lo contrario de lo que se quiere.

   Así que aquí se separan las dos cosas que main.css tenía juntas: el bloqueo se
   queda y la atenuación se va. Llegó a haber un estado de espera atenuado
   (.is-cargando) para el rato que la petición estaba en el aire; desde que la
   confirmación se pinta en el mismo clic ya no hay tal rato, y esa clase se ha
   retirado —el hueco que dejó está documentado unas líneas más abajo—.

   🔴 LAS DOS LÍNEAS SON OBLIGATORIAS. main.css bloquea el botón con
   pointer-events: none y esa regla puntúa 0-2-0; el pointer-events: auto que el
   círculo necesita para poder pulsarse dentro de la capa puntúa lo mismo, y al vivir
   en un archivo que se carga después le ganaría por orden. Repitiéndolo aquí acotado
   (0-3-0) vuelve a mandar. Y el opacity: 1 anula el 0,6 de main.css, que si no
   apagaría el tique. */
.ga-eventos-combina--alinos .ga-alinos__cart[aria-disabled="true"] {
    opacity: 1;
    pointer-events: none;
}

/* 🔴 AQUÍ ESTABA EL ESTADO DE ESPERA (.is-cargando), QUE ATENUABA EL CÍRCULO
   MIENTRAS LA PETICIÓN VIAJABA. SE HA IDO CON EL CAMBIO DE ORDEN.

   Tenía todo el sentido cuando la confirmación llegaba DESPUÉS de la respuesta:
   había un hueco que rellenar y esa atenuación era la señal de "te he oído". Ahora
   no hay hueco —el verde y el tique se pintan en el mismo clic—, así que atenuar
   solo serviría para enseñar la confirmación a media luz durante los primeros
   milisegundos, que es exactamente el retraso percibido que se quería quitar.

   La clase ya no la pone nadie en single-product.js. */

/* ——— EL AVISO DE QUE ALGO NO HA IDO ———
   Solo aparece si la petición falla. Lo crea single-product.js y lo cuelga del
   <body>, no de la tarjeta.

   🔴 position: fixed, Y ESA ES LA RAZÓN DE QUE ESTÉ FUERA DE LA CUADRÍCULA. El
   encargo prohíbe que nada cambie el tamaño o la posición del círculo, de la foto o
   de la tarjeta. Metido dentro de la celda, este rótulo empujaría la rejilla entera
   hacia abajo al aparecer; fuera del flujo, no puede mover un píxel de la página.

   ⚠ Y NO PUEDE DESBORDAR A 360px: el ancho es un min() contra el 92 % del viewport,
     así que en una pantalla estrecha se queda por dentro con margen a los dos lados.
     Sin min-width, que en este proyecto no se usa: si el texto no cabe, parte, y para
     eso lleva overflow-wrap.

   Nace apagado y sin poder recibir el ratón: es un mensaje, no un botón, y no debe
   tapar nada de lo que haya debajo. Lo único que cambia al aparecer es la opacidad,
   así que ni siquiera él se mueve. */
.ga-alinos__aviso {
    position: fixed;
    left: 50%;
    bottom: 1.25rem;
    transform: translateX(-50%);
    z-index: 9999;

    width: min(92vw, 26rem);
    box-sizing: border-box;
    margin: 0;
    padding: 0.85rem 1.15rem;

    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    line-height: 1.4;
    text-align: center;
    overflow-wrap: break-word;

    color: var(--ga-blanco);
    background-color: var(--ga-verde-oliva-oscuro);
    border-radius: var(--ga-radius-sm);
    box-shadow: 0 4px 24px rgba(74, 74, 47, 0.28);

    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity var(--ga-transition-normal),
                visibility var(--ga-transition-normal);
}

.ga-alinos__aviso.is-visible {
    opacity: 1;
    visibility: visible;
}

/* =============================================================================
   DONDE SÍ HAY RATÓN
   =============================================================================
   Todo el comportamiento de hover vive aquí dentro. Fuera de este bloque queda el
   estado de los TÁCTILES, que es el de partida: círculo dorado siempre visible y
   sin capa oscura, para que se pueda añadir igual sin un gesto que no existe.

   Se decide por la CAPACIDAD del dispositivo y no por el ancho, igual que hace
   Eventos con su velo: una tableta grande o un portátil táctil también se quedan
   fuera, que es lo que se quiere.
   ============================================================================= */
@media (hover: hover) {

    /* Con ratón, el círculo arranca apagado: la tarjeta se ve limpia y la foto no
       compite con nada hasta que el visitante se interesa por ella. */
    .ga-eventos-combina--alinos .ga-alinos__cart {
        opacity: 0;
        visibility: hidden;
    }

    /* Y al pasar por encima se encienden los dos a la vez, la capa y el círculo.

       :focus-within además del :hover para quien navega con el teclado: al llegar al
       enlace del nombre o al propio círculo, la tarjeta se enciende igual. Sin esa
       mitad, el círculo podría recibir el foco siendo invisible.

       LA CAPA SE ENCIENDE POR EL COLOR, no por la opacidad: la caja está siempre
       ahí, lo que cambia es el alfa de su fondo. Ver el porqué en su regla base —en
       resumen: si se apagara con opacity, el círculo que lleva dentro se apagaría
       con ella, y en los táctiles tiene que verse sin capa oscura—.

       Solo cambian color, opacidad y visibilidad: ni tamaño ni posición, así que la
       cuadrícula no se mueve un píxel. */
    .ga-eventos-combina--alinos .ga-eventos-combina__celda:hover .ga-alinos__velo,
    .ga-eventos-combina--alinos .ga-eventos-combina__celda:focus-within .ga-alinos__velo {
        background-color: rgba(0, 0, 0, 0.55);
    }

    .ga-eventos-combina--alinos .ga-eventos-combina__celda:hover .ga-alinos__cart,
    .ga-eventos-combina--alinos .ga-eventos-combina__celda:focus-within .ga-alinos__cart {
        opacity: 1;
        visibility: visible;
    }

    /* 🔴 Y DURANTE EL CICLO, LA CAPA SE QUEDA OSCURA AUNQUE EL RATÓN SE VAYA.
       La clase .is-anadiendo la pone el JS en la celda al pulsar y la quita cuando
       el tique ha terminado de irse. Sin esto, apartar el ratón justo después de
       pulsar —que es lo normal: se pulsa y se sigue— dejaría la confirmación
       flotando sobre la foto sin fondo.

       Va DENTRO del bloque de hover a propósito: en un táctil no hay capa oscura ni
       en reposo ni durante el ciclo, que es como se decidió que se viera ahí. */
    .ga-eventos-combina--alinos .ga-eventos-combina__celda.is-anadiendo .ga-alinos__velo {
        background-color: rgba(0, 0, 0, 0.55);
    }
}

/* 🔴 Y EL CÍRCULO TAMPOCO SE ESCONDE DURANTE EL CICLO, por el mismo motivo: la
   confirmación tiene que verse entera, con el ratón encima o sin él.

   Va FUERA del bloque de hover porque en un táctil el círculo ya se ve siempre y
   esta regla no cambia nada allí; y va DESPUÉS de ese bloque a propósito: empata en
   especificidad (0-4-0) con la regla del hover y necesita ganarle el desempate por
   orden. Lo que dicen las dos es lo mismo, así que el empate no tiene consecuencias,
   pero el orden deja claro cuál manda.

   ⚠ Y NO REINICIA NADA SI EL RATÓN VUELVE A ENTRAR: esto es CSS, no escucha eventos.
     El ciclo lo llevan los temporizadores del JS, que no saben ni les importa dónde
     está el ratón. */
.ga-eventos-combina--alinos .ga-eventos-combina__celda.is-anadiendo .ga-alinos__cart {
    opacity: 1;
    visibility: visible;
}

/* ——— MOVIMIENTO REDUCIDO ———
   La capa y el círculo aparecen de golpe en vez de fundirse. No se pierde nada: la
   cuadrícula es estática y no hay ninguna animación más que quitar. */
@media (prefers-reduced-motion: reduce) {

    .ga-eventos-combina--alinos .ga-alinos__velo,
    .ga-eventos-combina--alinos .ga-alinos__cart,
    .ga-eventos-combina--alinos .ga-alinos__cart.is-ok,
    .ga-eventos-combina--alinos .ga-alinos__cart .ga-home-card__cart-ico,
    .ga-eventos-combina--alinos .ga-alinos__cart .ga-home-card__cart-ok,
    .ga-eventos-combina--alinos .ga-alinos__cart.is-ok .ga-home-card__cart-ico,
    .ga-eventos-combina--alinos .ga-alinos__cart.is-ok .ga-home-card__cart-ok,
    .ga-alinos__aviso {
        transition: none;
    }

    /* 🔴 SE QUITAN LAS TRANSICIONES, NO EL TIQUE. El cambio pasa a ser directo pero
       el tique se sigue viendo el MISMO tiempo: el JS lee esta misma preferencia y
       pone a cero las dos duraciones de fundido, dejando --ga-alinos-tique intacto.
       Quien no quiere movimiento no quiere que le quiten la confirmación. */
    .ga-eventos-combina--alinos {
        --ga-alinos-confirmar: 0ms;
        --ga-alinos-volver:    0ms;
    }
}

/* =============================================================================
   (2d) LAS FOTOS DE LAS VARIEDADES, MÁS GRANDES DENTRO DE LA MISMA TARJETA
   =============================================================================
   MISMO PROBLEMA, MISMO MECANISMO Y MISMO NÚMERO que la foto grande de estas
   fichas, unos cuantos miles de líneas más arriba en este archivo (el bloque "LOS
   TARROS DE ACEITUNAS, MÁS GRANDES DENTRO DEL MISMO RECUADRO"). No se repite el
   razonamiento entero; lo que hay que saber es esto:

   · LA CAUSA ESTÁ EN LA FOTO, NO EN LA TARJETA. Estas miniaturas son la imagen
     destacada de cada producto, que en las ocho variedades es la misma toma: los
     DOS tarros juntos, de frente y de espaldas, sobre fondo blanco. En ese archivo
     el producto ocupa alrededor del 67 % del alto y el resto es blanco, así que a
     igual tarjeta el tarro se ve pequeño aunque la tarjeta mida lo que debe.

   · SE ESCALA SOLO LA <img>, con el origen centrado por defecto. La tarjeta no
     cambia de tamaño ni se mueve un píxel: un transform no toca el flujo, y el
     overflow: hidden que .ga-eventos-combina__foto ya trae de Eventos recorta lo
     que sobresale, que es aire y no producto.

   · EL 1.35 ES EL MISMO QUE ARRIBA, Y NO POR comodidad: es literalmente la misma
     foto en una caja de la misma proporción —las dos son cuadradas—, así que el
     margen que queda es el mismo porcentaje en las dos. Si no corta en la foto
     grande, no corta aquí. El tope lo pone el borde de ABAJO, porque el contenido
     está un poco por debajo del centro:

         borde inferior = 50 % + (85 % − 50 %) × 1.35 = 97,3 %  → queda margen
         a 1.43 llegaría al 100 %                              → la base tocaría

     Queda cerca de un 3 % de aire por debajo. La más ajustada de las ocho es la
     Gordal Aliñada, que es la que hay que mirar primero si algún día se sube.

   · LO DEFINITIVO SIGUE SIENDO REEXPORTAR LAS FOTOS RECORTADAS. El día que se
     suban, se borra esta regla y la de la foto grande a la vez.

   ⚠ NO AFECTA NI AL CÍRCULO NI A LA CAPA OSCURA. Las dos son hermanas de la <img>,
     no hijas suyas, así que el transform no las alcanza: la capa sigue cubriendo la
     caja entera de la foto y el círculo sigue centrado por el flex de la capa.

   ⚠ Y NO ALCANZA A EVENTOS: la clase de la imagen es compartida, pero el selector
     cuelga de .ga-eventos-combina--alinos, que su cuadrícula no lleva. */
.ga-eventos-combina--alinos .ga-eventos-combina__img {
    transform: scale(1.35);
}

/* ——— LA EXCEPCIÓN: LO QUE YA VIENE RECORTADO NO SE ESCALA ———
   🔴 EL 1.35 DE ARRIBA ES PARA LAS FOTOS DE TARRO, Y SOLO PARA ELLAS. Está calculado
   sobre un encuadre concreto —el par de tarros ocupando el 67 % del alto, con el
   resto en blanco—, así que no es un número que valga para cualquier foto.

   El ACEITUNERO es el caso contrario: su archivo ya viene recortado al borde y el
   producto ocupa cerca del 90 % del alto. Escalándolo un 35 % más se saldría del
   recuadro por arriba y por abajo, y perdería la tapa y la base. Sin escalar ocupa
   casi exactamente lo mismo que un tarro YA escalado (90 % frente a 90 %), que es de
   lo que se trata: que las ocho tarjetas se vean igual de llenas, no que lleven
   todas el mismo número.

   La clase la pinta la plantilla a partir de un dato de la propia ficha, no de una
   lista de slugs en el CSS: si mañana entra otro producto con la foto ya recortada,
   se marca en el PHP y esta regla lo recoge sola. */
.ga-eventos-combina--alinos .ga-alinos__celda--ajustada .ga-eventos-combina__img {
    transform: none;
}

/* ——— EL ORDEN EN MÓVIL (≤860px) ———
   La cuadrícula de aliños CIERRA la ficha apilada. Va en la columna de la foto, y a
   este ancho las dos columnas pasan a display: contents, así que compite en la
   misma lista de order que todo lo demás.

   El recorrido que queda es exactamente el pedido:
     nombre y precio → foto → disponibilidad → opciones y añadir al carrito
     → sellos (9) → descripción corta (10) → desplegables (11) → aliños (12)

   ⚠ SE ENUMERA AUNQUE EL SUELO DE SEGURIDAD (order: 20) YA LO MANDARÍA AL FINAL.
     Confiar en el suelo funcionaría hoy y dejaría de funcionar el día que se añada
     otro bloque sin numerar: los dos caerían en 20 y su orden lo decidiría el
     marcado, no esta lista. Es el mismo criterio con el que está enumerado el
     acordeón unas líneas más arriba. */
@media (max-width: 860px) {

    .ga-product-single:not(.ga-product-single--eventos) .ga-eventos-combina--alinos {
        order: 12;
    }
}


/* =============================================================================
   TARROS DE ACEITUNAS — "¿CUÁL ES LA TUYA?", LA GUÍA DE VARIEDADES
   =============================================================================
   La tabla que sustituye a la comparativa de los aceites en las fichas de tarro.
   Ocho filas —una por variedad— y cuatro columnas de atributos.

   🔴 CASI TODO LO VISUAL SE HEREDA Y NO SE REPITE. El marcado lleva .ga-tc-marco y
   .ga-tc, las clases base de la tabla de aceites, así que de allí vienen ya:

     · el marco: borde de 1px en naranja claro, radio de 10px y recorte;
     · la tabla: ancho completo, table-layout: fixed y los reseteos de borde y
       margen que WordPress le mete a cualquier <table>;
     · las celdas: relleno, tamaño, peso, interlineado, color y overflow-wrap;
     · la línea separadora entre filas;
     · la cabecera: mayúsculas, peso 700 y espaciado entre letras.

   Aquí abajo está SOLO lo que aquella tabla no tiene: los anchos de esta, los
   puntos de las escalas y la fila destacada. Ni un color ni un tamaño copiados.

   ⚠ SIN --esc NI --mov. Aquella tabla se pinta dos veces, una por ancho, porque
     con cinco columnas de producto no cabe en un teléfono. Esta es UNA sola para
     todos los anchos: sus cuatro columnas de atributo son estrechas y caben.
   ============================================================================= */

/* ——— MENOS AIRE ENTRE EL TÍTULO Y LA TABLA ———
   La sección comparte .ga-product__comparativa con la tabla de los aceites, y allí
   la cabecera deja 6rem por debajo. Allí hace falta: su columna destacada tiene un
   saliente por ARRIBA que se mete en ese hueco. Esta tabla no destaca ninguna
   columna —destaca una fila, y su saliente es lateral—, así que esos 6rem eran aire
   muerto entre el titular y la primera línea.

   Baja a 2rem, y va acotado con el modificador de la sección para que la tabla de
   los aceites conserve exactamente el suyo. */
.ga-product__comparativa--variedades .ga-section__header--center {
    margin-bottom: var(--ga-space-md);
}

/* ——— LOS ANCHOS ———
   🔴 LA COLUMNA DE NOMBRES SE MIDE, NO SE REPARTE. Iba al 32 %, y un porcentaje en
   una pantalla ancha le daba casi 390px cuando el nombre más largo —"Cóctel de
   Aceitunas y Encurtidos"— necesita unos 260: sobraba más de un dedo de fondo crema
   vacío a la derecha. Ahora lleva una medida fija, calculada para que ese nombre
   entre en UNA línea con su margen interior y el borde de la columna caiga justo
   detrás.

   DE DÓNDE SALEN LOS 17rem: son 32 caracteres en Inter a 16px —unos 241px contando
   que cuatro son espacios— más los dos rellenos laterales de la celda, que suman
   17,6px. Da unos 259px y se redondea a 272 para tener holgura: una fuente que
   renderice un pelo más ancha no debe partir el nombre.

   ⚠ ES UNA CONSTANTE MEDIDA, Y HAY QUE SABERLO. Si algún día entra una variedad con
     el nombre más largo que el Cóctel, o se cambia el tamaño de letra de la tabla,
     este número se queda corto y ese nombre pasará a dos líneas. Es el sitio donde
     mirar.

   LAS OTRAS CUATRO A `auto`, QUE ES LO QUE LAS DEJA IGUALES ENTRE SÍ. Con
   table-layout: fixed, el navegador reparte a partes iguales lo que sobra entre las
   columnas sin ancho declarado: no hay que calcular ningún porcentaje ni ajustarlo
   cuando cambie el de al lado.

   Y ninguna necesita min-width: el ancho lo fija el colgroup y el overflow-wrap que
   .ga-tc ya le da a las celdas parte lo que no quepa. */
.ga-tcv__col-nombre { width: 17rem; }
.ga-tcv__col-dato   { width: auto; }

/* ——— EL TAMAÑO DE LETRA ———
   Sube un escalón de la rampa en las dos: las celdas de 14 a 16px y la cabecera de
   12 a 14px. La tabla de aceites tiene cinco columnas de las que tres son de texto
   largo y necesita ir apretada; esta tiene cuatro columnas de una o dos palabras y
   se puede permitir el tamaño de lectura normal.

   🔴 LOS SELECTORES LLEVAN LAS DOS CLASES (.ga-tc.ga-tcv) A PROPÓSITO. Las reglas
   que hay que ganar son .ga-tc th, .ga-tc td y .ga-tc thead th, que puntúan
   exactamente lo mismo que .ga-tcv th o .ga-tcv thead th: con una sola clase se
   empataría y el resultado dependería de quién va después en el archivo. Con las
   dos, se gana por especificidad y da igual dónde acabe este bloque. */
/* ═══════════════════════════════════════════════════════════════════════════
   EL ALTO DE FILA, EN CUATRO NÚMEROS Y UNA CUENTA
   ═══════════════════════════════════════════════════════════════════════════
   🔴 TODAS LAS FILAS MIDEN EXACTAMENTE LO MISMO, CABECERA INCLUIDA, Y NO ES POR
   CASUALIDAD: se les fija el mismo alto a todas las celdas. Con relleno a secas no
   bastaría, porque una celda cuyo texto parte en dos líneas estira SU fila y la
   deja más alta que las demás —"Cóctel de Aceitunas y Encurtidos" lo hace en cuanto
   la pantalla baja de unos 900px—.

   LA CUENTA RESERVA SITIO PARA EL PEOR CASO: tantas líneas como pueda ocupar el
   texto más largo, por su interlineado, más los dos rellenos. Como en esta web el
   box-sizing es border-box, ese alto YA incluye el relleno y no hay que sumarlo dos
   veces. Y en una celda de tabla el alto es un MÍNIMO, así que si algún día un
   contenido pidiera más, crecería en vez de recortarse: nunca se pierde texto.

   🔴 EL ALTO SE CALCULA CON --ga-tcv-fuente Y NO CON em, Y ESA ES LA CLAVE DE QUE
   LA CABECERA MIDA IGUAL. La cabecera va un escalón más pequeña que el cuerpo; con
   `em` cada celda calcularía su alto sobre SU propio tamaño de letra y la fila de
   arriba saldría más baja que las demás. Con una variable compartida, las nueve
   filas resuelven el mismo número.

   Los cuatro valores viven aquí y el bloque de móvil los reescribe: cambiar el aire
   de la tabla es tocar una línea, no perseguir rellenos por medio archivo. */
.ga-tcv {
    --ga-tcv-fuente:    var(--ga-text-base);
    --ga-tcv-relleno:   0.95rem;
    --ga-tcv-relleno-x: 0.55rem;
    /* Dos líneas: es lo que llega a ocupar el nombre más largo en el tramo más
       estrecho del escritorio. Por encima de unos 900px todo cabe en una y la fila
       queda con aire de sobra, que es justo lo que se buscaba. */
    --ga-tcv-lineas:    2;
}

.ga-tc.ga-tcv th,
.ga-tc.ga-tcv td {
    font-size: var(--ga-tcv-fuente);

    /* El MISMO relleno para las cinco columnas, la primera incluida: así los
       nombres quedan centrados en su fila igual que los puntos y los textos. */
    padding: var(--ga-tcv-relleno) var(--ga-tcv-relleno-x);

    /* El 1.4 es el interlineado que .ga-tc th/td le da a estas celdas. Si allí se
       cambiara, aquí hay que cambiarlo: son el mismo dato escrito dos veces, y no
       hay forma de leerlo desde calc(). */
    height: calc(var(--ga-tcv-lineas) * 1.4 * var(--ga-tcv-fuente) + 2 * var(--ga-tcv-relleno));
}

.ga-tc.ga-tcv thead th {
    font-size: var(--ga-text-sm);
}

/* ——— LA CABECERA ———
   El dorado y el centrado. Lo demás —mayúsculas, tamaño, peso, espaciado— ya viene
   de .ga-tc thead th.

   El color se declara aquí y no se reutiliza .ga-tc__nuestra porque aquella clase
   arrastra además el fondo crema de las columnas de producto, que en esta tabla no
   pinta nada. */
.ga-tcv thead th {
    color: var(--ga-verde-oliva-oscuro);
    text-align: center;
}

/* ——— LA FRANJA DE LA CABECERA: VERDE MUY CLARO ———
   🔴 ESTE FONDO ES EL DE LA PRIMERA COLUMNA DE LA TABLA DE ACEITES, copiado de
   .ga-tc__concepto: el mismo color-mix del verde montañas al 9 % sobre blanco, con
   el mismo respaldo en blanco para navegadores sin color-mix. No es un verde nuevo
   ni uno parecido; es exactamente aquel.

   Se hereda por copia y no por selector porque allí la clase que lo lleva
   —.ga-tc__concepto— arrastra además la alineación a la izquierda y el relleno
   propios de una columna de conceptos, que aquí no pintan nada.

   ⚠ LA LÍNEA DE ABAJO YA NO ES DORADA. Lo era cuando la franja también tiraba a
     dorado y hacía de remate; con el fondo en verde clarísimo, una línea dorada se
     quedaba como un resto de otra cosa. Pasa a ser la MISMA línea que separa las
     filas del cuerpo —el verde oliva al 25 % sobre blanco—, de modo que toda la
     tabla se divide con un solo trazo y no con dos que compiten.

   LA ESQUINA ENTRA TAMBIÉN, y esto lo pedía el encargo expresamente: la celda donde
   se cruzan la primera fila y la primera columna sigue a la FILA, no a la columna.
   Sin ella, la franja arrancaría en la segunda columna y la cabecera se vería
   cortada por la izquierda. */
.ga-tcv thead th,
.ga-tcv thead .ga-tcv__esquina {
    background-color: var(--ga-blanco);
    background-color: color-mix(in srgb, var(--ga-verde-montanas) 9%, var(--ga-blanco));
    border-bottom: 1px solid var(--ga-amarillo-pastel);
    border-bottom: 1px solid color-mix(in srgb, var(--ga-verde-oliva-oscuro) 25%, var(--ga-blanco));
}

/* ——— LA COLUMNA DE NOMBRES: CREMA Y DORADO ———
   Alineada a la izquierda, que es como se lee una lista, y un punto más de peso que
   el resto.

   🔴 SE INTERCAMBIA EL TRATAMIENTO CON LA CABECERA. Este fondo crema y este dorado
   son los que llevaba la primera FILA hasta ahora: el color-mix del dorado de marca
   al 12 % sobre blanco, con el naranja claro de respaldo. La cabecera, a cambio, se
   ha quedado con el verde clarísimo. La tabla pasa así a tener el peso visual en la
   columna de nombres, que es lo que se busca en un catálogo donde lo que se compara
   son las variedades y no los atributos.

   ⚠ ESTE PAR TIENE POCO CONTRASTE: el dorado sobre el crema da 2,1:1, por debajo
     del 4,5:1 que la norma pide para texto corrido. Es el mismo par que llevaba la
     cabecera hasta hoy —así que no es nuevo en la web—, pero allí eran cuatro
     rótulos cortos en mayúsculas y negrita, y aquí son ocho nombres de producto,
     que es texto de leer. Queda anotado a conciencia: si algún día se quiere
     corregir, lo que hay que cambiar es el COLOR DEL TEXTO —no el fondo—, y el
     candidato de la paleta es --ga-marron-oscuro, que es de la misma familia cálida
     y sube el contraste por encima de 8:1. */
.ga-tcv th.ga-tcv__nombre {
    text-align: left;
    font-weight: 600;
    color: var(--ga-naranja-apagado);
    background-color: var(--ga-naranja-claro);
    background-color: color-mix(in srgb, var(--ga-naranja-apagado) 12%, var(--ga-blanco));
}

/* ——— LA LÍNEA DORADA QUE CIERRA LA PRIMERA COLUMNA ———
   Un filete de 1px en el dorado de marca, a lo alto de TODA la tabla: por eso la
   lleva también la celda de la esquina, que es la que continúa la línea en la fila
   de la cabecera. Sin ella, el trazo arrancaría en la segunda fila.

   🔴 NO DESPLAZA NADA. El ancho de la columna lo fija el colgroup y el box-sizing
   de esta web es border-box, así que el píxel del borde se descuenta por dentro de
   esos 17rem: ni la columna crece ni las de al lado se mueven. Es también la razón
   de que no pueda provocar desplazamiento horizontal en la página.

   Va en el borde de la celda y no en el <col> porque un borde puesto en una columna
   solo lo pinta el navegador con border-collapse: collapse, y esta tabla usa
   separate —lo necesita para que los border-radius del marco funcionen—. */
.ga-tcv th.ga-tcv__nombre,
.ga-tcv thead .ga-tcv__esquina {
    border-right: 1px solid var(--ga-naranja-apagado);
}

/* Y dentro de la fila destacada desaparece: ahí el verde tiene que verse de un lado
   a otro sin nada que lo corte.

   TRANSPARENTE Y NO `none`: el borde sigue ocupando su píxel, así que esa fila mide
   exactamente lo mismo que las demás y el texto de su primera celda no se corre un
   punto respecto al de las otras. Es el mismo criterio que ya se sigue con la línea
   horizontal de esa fila. */
.ga-tcv tbody tr.is-destacada th.ga-tcv__nombre {
    border-right-color: transparent;
}

/* Los cuatro atributos, centrados en su columna. */
.ga-tcv tbody td {
    text-align: center;
}

/* ——— LOS PUNTOS DE INTENSIDAD Y PICANTE ———
   Tres por celda, iguales en las dos columnas: mismo tamaño y misma separación, que
   es lo que permite comparar dos filas de un vistazo.

   inline-flex y no tres elementos sueltos: así el grupo se centra como una sola
   pieza y el hueco entre puntos lo pone el gap, sin márgenes que se acumulen.

   flex: 0 0 auto en cada punto para que no los estruje la celda: son la única cosa
   de esta tabla que no puede encoger, porque un círculo aplastado deja de leerse
   como un círculo. No es un min-width: es un ítem flexible que no cede. */
.ga-tcv__puntos {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.34rem;

    /* 🔴 CENTRADO VERTICAL DE VERDAD, Y HACE FALTA DECIRLO. La celda ya alinea su
       contenido al medio, pero un inline-flex se coloca por su LÍNEA BASE, y la
       línea base de una caja sin texto dentro es su borde inferior: los puntos
       quedaban colgando un par de píxeles por debajo del centro. Con las filas
       bajas apenas se veía; ahora que son bastante más altas, cantaría. */
    vertical-align: middle;
}

/* Los puntos suben con la letra: de 8 a 10px, y el hueco de 4,5 a 5,5. Se mantiene
   la proporción que tenían respecto al texto, que es lo que hace que la escala se
   lea como parte de la fila y no como un adorno pegado. */
.ga-tcv__punto {
    flex: 0 0 auto;
    width: 0.62rem;
    height: 0.62rem;
    border-radius: 50%;

    /* 🔴 EL GRIS CLARO SALE DE UNA VARIABLE DE MARCA, NO ES UN GRIS INVENTADO. Se
       aclara el verde oliva con blanco, que es el mismo recurso —y la misma
       técnica— con la que esta hoja calcula la línea separadora de las filas unas
       cuantas líneas más arriba. Así el apagado es un tono de la paleta y no un
       color suelto que nadie sabría de dónde salió.

       La primera declaración es el respaldo para navegadores sin color-mix: el
       amarillo pastel de marca, que es el tono claro que ya usan los bordes. Si
       color-mix no se entiende, esa línea es la que queda. */
    background-color: var(--ga-amarillo-pastel);
    background-color: color-mix(in srgb, var(--ga-verde-oliva-oscuro) 20%, var(--ga-blanco));
}

/* 🔴 EL ENCENDIDO ES VERDE OSCURO, NO DORADO. El dorado se ha quedado para el
   nombre de la variedad y para el filete que cierra su columna; usarlo también en
   los puntos repartía el acento por toda la fila y la escala dejaba de destacar.

   Sobre el fondo claro de las celdas da 9,1:1, así que se lee muchísimo mejor que
   el dorado, que se quedaba en 2,3:1. Y frente al apagado —el gris claro— hay 6,5:1
   de diferencia, que es lo que permite contar los encendidos de un vistazo. */
.ga-tcv__punto.is-on {
    background-color: var(--ga-verde-oliva-oscuro);
}

/* ——— LA FILA DE LA VARIEDAD QUE SE ESTÁ VIENDO ———
   Verde oscuro a lo ancho de toda la fila, su nombre en dorado y el resto en
   blanco. Es el equivalente de la columna destacada de la tabla de aceites, pero
   aquí no hace falta ningún elemento decorativo: una fila SÍ existe como elemento
   —es un <tr>—, así que basta con pintarle el fondo a sus celdas.

   🔴 EL VERDE SE VE CONTINUO PORQUE NO HAY LÍNEAS VERTICALES QUE LO CORTEN, y no
   porque se oculten: esta tabla no tiene ninguna. La de aceites tampoco: sus celdas
   solo llevan border-bottom, la línea que separa una fila de la siguiente. Así que
   no hay nada que apagar, y por eso aquí no aparece ninguna regla para ello.

   ⚠ LA QUE SÍ HABÍA QUE APAGAR ES LA HORIZONTAL, y solo su color. Un separator
     claro cruzando el verde lo partía en dos. Se pone transparente en vez de
     quitarlo: el borde sigue ocupando su píxel, así que la fila destacada mide
     exactamente lo mismo que las demás y la tabla no da ningún salto.

   Y las esquinas se redondean solas: el recorte de .ga-tc-marco obliga a la fila a
   respetar el radio del marco cuando es la primera o la última. */
.ga-tcv tbody tr.is-destacada th,
.ga-tcv tbody tr.is-destacada td {
    background-color: var(--ga-verde-oliva-oscuro);
    color: var(--ga-blanco);
    border-bottom-color: transparent;
}

/* 🔴 EL DORADO SE QUEDA SOLO PARA EL NOMBRE. Todo lo demás de la fila —los dos
   textos y los seis puntos— va en blanco. Con el nombre siendo lo único dorado, es
   lo primero que se mira dentro de la fila, que es de lo que se trata: decirte cuál
   estás viendo. */
.ga-tcv tbody tr.is-destacada th.ga-tcv__nombre {
    color: var(--ga-naranja-apagado);
}

/* ——— LOS PUNTOS SOBRE EL VERDE: BLANCOS, Y AHORA SÍ HACE FALTA ———
   🔴 ESTA REGLA VOLVIÓ, Y CONVIENE SABER POR QUÉ, PORQUE ANTES SE QUITÓ. Hubo una
   versión con los seis puntos en blanco que se descartó: entonces los de reposo
   eran DORADOS, y el dorado sobre el verde oscuro ya daba 4,0:1, así que dejarlos
   tal cual se leía mejor que pasarlos a blanco.

   Ahora el encendido de reposo es VERDE OSCURO, que es exactamente el color del
   fondo de esta fila: dejarlo sin tocar haría desaparecer los puntos encendidos por
   completo. Blanco es la única salida, y por eso la regla vuelve.

   ENCENDIDO Y APAGADO SE DISTINGUEN POR OPACIDAD, NO POR COLOR: los seis son del
   mismo blanco y lo que cambia es cuánto se ven. Entre uno y otro hay 4,0:1, que es
   de sobra para contar los encendidos de un golpe de vista.

   ⚠ EL APAGADO ES EL PUNTO FLOJO, Y QUEDA DICHO. Un blanco al 30 % sobre el verde
     se queda en 2,3:1 contra el fondo: se intuye, pero no destaca. Es el precio de
     que los tres puntos vivan sobre un fondo oscuro y solo se distingan por
     opacidad. Si alguna vez se ve demasiado tenue, el número a subir es esa
     opacidad —hasta un 40 % gana bastante y sigue leyéndose como "apagado"—.

   ⚠ NI TAMAÑO NI SEPARACIÓN CAMBIAN. Los seis miden lo mismo que en las otras siete
     filas y llevan el mismo hueco: en esta web ningún estado cambia de tamaño, y
     además así las ocho filas se pueden comparar en vertical. */
.ga-tcv tbody tr.is-destacada .ga-tcv__punto {
    background-color: var(--ga-blanco);
    opacity: 0.3;
}

.ga-tcv tbody tr.is-destacada .ga-tcv__punto.is-on {
    background-color: var(--ga-blanco);
    opacity: 1;
}

/* ═══════════════════════════════════════════════════════════════════════════
   EL SALIENTE: LA FILA DESTACADA SE SALE POR LOS DOS LADOS
   ═══════════════════════════════════════════════════════════════════════════
   Es el efecto de tarjeta que la tabla de aceites le da a su columna destacada,
   puesto en horizontal: la fila sobresale por la izquierda y por la derecha del
   resto de la tabla, con las esquinas redondeadas en esos dos extremos.

   🔴 SE SALE DEL MARCO GRACIAS AL RELLENO LATERAL DE .ga-tcv-marco, NO CON
   overflow-clip-margin. El marco lleva overflow: clip para que la tabla respete sus
   esquinas redondeadas, y eso recortaba los dos salientes. Se probó primero con
   overflow-clip-margin —que es lo que hace la tabla de los aceites en
   .ga-tc-marco--esc— y NO FUNCIONÓ de forma fiable: esa propiedad se descarta en
   silencio donde no se entiende, y el saliente no llegaba a verse. El porqué
   completo está en la regla de .ga-tcv-marco, unas líneas más abajo.

   Con relleno lateral del ancho del saliente, los dos caen DENTRO de la caja del
   marco y no hay recorte que valga. El coste es que la tabla se mete esos milímetros
   hacia dentro; a cambio, funciona en todos los navegadores sin excepción.

   De ahí que no empuje ni desalinee nada:

     · los seudoelementos van en position: absolute, o sea FUERA DEL FLUJO: no
       ocupan sitio, no ensanchan ninguna fila y no pueden desplazar una celda;
     · las columnas no cambian de ancho, porque la tabla sigue midiendo lo mismo;
     · y no cabe desbordamiento horizontal: el saliente mide 0,55rem (8,8px) y el
       .ga-container que envuelve la sección reserva 16px de relleno como mínimo a
       cada lado, así que la punta verde se queda dentro de ese hueco y no llega
       nunca al borde de la página.

   ⚠ YA NO HAY NAVEGADOR EN EL QUE ESTO SE DEGRADE: el relleno lateral es CSS de
     toda la vida, así que el saliente asoma igual en cualquier móvil, por viejo que
     sea. Esa era justo la contrapartida que
     acepta la columna destacada de los aceites.

   ⚠ EL RADIO ES 8px Y EL DEL MARCO 10px: la fila se redondea un punto MENOS que la
     caja que la contiene, que es lo que hace que una curva anide dentro de otra sin
     que se vean paralelas.
   ═══════════════════════════════════════════════════════════════════════════ */
.ga-tcv-marco {
    --ga-tcv-saliente: 0.55rem;

    /* 🔴 POR QUÉ EL SALIENTE NO SE VEÍA, Y POR QUÉ AHORA SÍ.
       ═══════════════════════════════════════════════════════════════════════
       Las reglas del saliente estaban bien escritas —::before en la primera celda
       y ::after en la última, simétricas—, pero NUNCA LLEGABAN A VERSE: el marco
       lleva `overflow: clip` (de .ga-tc-marco, línea 1214 de este archivo) para
       redondear las esquinas de la tabla, y ese recorte se comía los dos salientes,
       que por definición caen FUERA de la caja de la tabla.

       Aquí se intentaba resolver con `overflow-clip-margin: 16px`, que es la
       propiedad pensada justo para eso: ensanchar la zona de recorte. Y es una
       apuesta demasiado frágil para algo que tiene que verse sí o sí:

         · solo funciona si el navegador aplicó `overflow: clip`; donde se quede en
           el `overflow: hidden` de respaldo de la línea anterior, se IGNORA;
         · Safari no la entiende hasta la 16.4, y este sitio es 70 % móvil;
         · y cuando no se entiende no avisa: la declaración se descarta en silencio
           y el saliente simplemente no está. Que es exactamente lo que pasaba.

       ✅ LA SOLUCIÓN NO DEPENDE DE NINGUNA PROPIEDAD MODERNA: en vez de pedirle al
       marco que recorte más lejos, se le da RELLENO LATERAL del ancho del saliente.
       Así los dos salientes caen DENTRO de la caja del marco y el recorte ya no
       tiene nada que comerse. El `overflow: clip` se queda intacto, así que las
       esquinas se siguen redondeando igual que hasta hoy.

       ⚠ SIMÉTRICO POR CONSTRUCCIÓN: es el MISMO valor por los dos lados —el relleno
         con padding-inline y el desplazamiento con el calc de ±saliente—, así que no
         hay forma de que un lado salga más largo que el otro.

       ⚠ NI EMPUJA NI DESALINEA NADA. Los salientes son pseudoelementos en
         `position: absolute`: están fuera del flujo, no ocupan sitio en la fila y no
         pueden mover ni una columna. Las demás filas siguen exactamente donde
         estaban; la destacada es la única que se extiende.

       ⚠ Y NO PUEDE DESBORDAR LA PÁGINA, que es la ventaja de fondo de hacerlo así:
         todo el saliente ocurre DENTRO del marco, que sigue midiendo lo que medía.
         Antes, con overflow-clip-margin, el efecto se pintaba fuera de su caja y
         había que fiarse de que el contenedor tuviera hueco. Ahora no hay nada que
         comprobar: por construcción, la tabla no ha crecido ni un píxel. */
    padding-inline: var(--ga-tcv-saliente);

    /* 🔴 Y CON EL RELLENO HAY QUE APAGAR EL BORDE DEL MARCO. Ese relleno es lo que
       deja sitio a los salientes, pero tiene un efecto secundario: separa el borde
       de .ga-tc-marco (línea 1215: 1px solid var(--ga-naranja-claro)) del filo de
       las celdas. Hasta entonces el borde iba pegado a la tabla y se leía como su
       contorno; ahora queda a unos milímetros por fuera y se ve como una línea
       suelta que NO coincide con donde acaba cada fila. Es esa línea, no un borde
       nuevo: no se añadió nada, se separó lo que ya estaba.

       Se apaga con transparent y NO con `border: 0`, que es la diferencia que
       importa: a cero, la caja perdería 1px por cada lado y toda la tabla se
       movería medio píxel. En transparente ocupa exactamente lo mismo y solo deja
       de verse, que es la regla de este proyecto para cualquier ajuste visual.

       ⚠ NO SE PIERDE NADA MÁS: el redondeo de las esquinas lo hace el border-radius
         con el overflow: clip, no el borde, así que la tabla se sigue recortando en
         curva igual que siempre. Y la línea dorada separadora, la cabecera y el
         fondo crema de la primera columna son de las CELDAS: ni se tocan. */
    border-color: transparent;
}

.ga-tcv tbody tr.is-destacada th.ga-tcv__nombre,
.ga-tcv tbody tr.is-destacada td.ga-tcv__fin {
    position: relative;
}

.ga-tcv tbody tr.is-destacada th.ga-tcv__nombre::before,
.ga-tcv tbody tr.is-destacada td.ga-tcv__fin::after {
    content: '';
    position: absolute;
    top: 0;
    /* 🔴 EL -1px NO SOBRA. Un elemento en absoluto se coloca contra la caja de
       RELLENO de su ancestro, y la celda pinta su fondo hasta la de BORDE: entre
       las dos hay justo el píxel de la línea separadora, así que con bottom: 0 el
       saliente se quedaría un pelo corto y asomaría una muesca clara en su esquina.
       En la última fila, que no lleva esa línea, ese píxel de más lo recorta el
       overflow del marco. */
    bottom: -1px;
    width: var(--ga-tcv-saliente);
    background-color: var(--ga-verde-oliva-oscuro);
}

.ga-tcv tbody tr.is-destacada th.ga-tcv__nombre::before {
    left: calc(-1 * var(--ga-tcv-saliente));
    border-radius: 8px 0 0 8px;
}

.ga-tcv tbody tr.is-destacada td.ga-tcv__fin::after {
    right: calc(-1 * var(--ga-tcv-saliente));
    border-radius: 0 8px 8px 0;
}

/* ——— PANTALLAS ESTRECHAS ———
   🔴 LAS CUATRO COLUMNAS SE QUEDAN, QUE ES LO QUE PEDÍA EL ENCARGO. No hay versión
   móvil aparte ni desplazamiento lateral: lo que se ajusta es el relleno, el ancho
   del nombre y el tamaño de la letra, y el resto lo resuelve el table-layout: fixed
   que ya trae .ga-tc —la tabla no puede ensancharse por su contenido, así que no
   hay forma de que se salga de la página—.

   Las cuentas a 360px: el contenedor deja unos 328px y el marco 326 por dentro. Con
   el nombre al 26 %, su columna se queda en unos 85px y las cuatro de atributo en
   unos 60px cada una. Descontado el relleno, a cada dato le quedan unos 50px.

   EL TAMAÑO VA EN clamp Y NO EN UN VALOR POR BREAKPOINT: entre 360 y 600px la letra
   crece con la pantalla en vez de dar un salto, y el suelo de 0,7rem es lo que hace
   que "Crujiente" —la palabra más larga de las cuatro columnas— quepa en una línea
   en el ancho más estrecho. Por encima de 600 manda el techo y se lee el tamaño
   normal de la tabla.

   ⚠ SI ALGÚN DÍA UN VALOR NUEVO ES MÁS LARGO QUE "Crujiente", lo que hay que mirar
     es ese suelo. Bajarlo hace que quepa; el límite razonable está en 0,65rem,
     porque por debajo deja de leerse a un palmo de la cara. La alternativa buena no
     es encoger más la letra: es acortar el valor. */
@media (max-width: 600px) {

    /* EL SALIENTE SE QUEDA, SOLO QUE MÁS CORTO. El encargo dejaba prevista la
       salida de suprimirlo si no cabía, y no hace falta usarla: al resolverse con
       relleno DENTRO del marco, el saliente no puede desbordar la página por mucho
       que se estreche la pantalla. Lo único que cuesta son sus 6,4px por lado, que
       salen del ancho de la tabla y no del de la página.

       Baja de 0,55 a 0,4rem (6,4px) por proporción, no por espacio: el marco es
       mucho más estrecho aquí y un saliente igual de largo se comería visualmente
       la tabla. Sigue holgadamente dentro de los 16px que reserva el contenedor a
       cada lado, así que la página no puede desbordar. */
    .ga-tcv-marco {
        --ga-tcv-saliente: 0.4rem;
    }

    /* LOS CUATRO NÚMEROS DEL ALTO, REESCRITOS PARA EL MÓVIL. El alto se recalcula
       solo a partir de ellos: aquí no se toca ninguna regla de celda.

       EL TAMAÑO sigue en clamp, con el techo en el de la tabla y la pendiente
       inclinada: así solo se queda pequeño en los anchos más estrechos y a partir
       de unos 530px ya se lee al tamaño completo. El suelo de 0,7rem es el que
       decide si las palabras parten: la más larga de las cuatro columnas mide nueve
       caracteres —"Ensaladas", "Aperitivo", "compartir"— y a ese tamaño entra justa.
       Si algún día un valor nuevo es más largo, lo que hay que acortar es el valor.

       🔴 TRES LÍNEAS Y NO DOS, Y ES EL NOMBRE QUIEN LO OBLIGA. Aquí la columna de
       nombres se queda en unos 78px, y "Cóctel de Aceitunas y Encurtidos" no cabe
       en dos líneas ni bajando la letra: "Encurtidos" ya ocupa una entera. Con dos
       reservadas, esa fila crecería y sería la única más alta, que es exactamente lo
       que no puede pasar. Se reserva la tercera y las nueve vuelven a medir igual.

       El relleno baja de 0,95 a 0,7rem: con una línea más que reservar, mantenerlo
       habría dejado unas filas desproporcionadas en una pantalla estrecha. */
    .ga-tcv {
        --ga-tcv-fuente:    clamp(0.7rem, 3vw, var(--ga-text-base));
        --ga-tcv-relleno:   0.7rem;
        --ga-tcv-relleno-x: 0.25rem;
        --ga-tcv-lineas:    3;
    }

    /* La cabecera, un escalón por debajo de las celdas: son cuatro rótulos de una
       palabra —"Intensidad" es el más largo— y así entran sin partirse. */
    .ga-tc.ga-tcv thead th {
        font-size: clamp(0.62rem, 2.4vw, var(--ga-text-sm));
        letter-spacing: 0.02em;
    }

    /* El nombre cede ancho a los datos: es la columna que mejor aguanta partir en
       dos líneas, porque son varias palabras. */
    .ga-tcv__col-nombre { width: 24%; }
    .ga-tcv__col-dato   { width: 19%; }

    /* Los puntos bajan con la letra, manteniendo la proporción. */
    .ga-tcv__punto {
        width: 0.5rem;
        height: 0.5rem;
    }

    .ga-tcv__puntos {
        gap: 0.26rem;
    }
}


/* =============================================================================
   LOS DOS BRILLOS DE LA GUÍA DE VARIEDADES
   =============================================================================
   Dos textos con el destello de marca: "GRAN ALMAZARA" en la esquina y el nombre
   de la variedad que se está viendo.

   🔴 ES EL MISMO MECANISMO QUE YA HAY EN ESTE ARCHIVO, PIEZA POR PIEZA. No se
   inventa nada: un degradado con la banda de luz en el medio, el fondo estirado al
   250 %, sin repetir, arrancando en el 100 % y animando SOLO background-position.
   Los @keyframes son los de main.css —ga-home-card-brillo—, que son globales del
   documento y no de la hoja donde se declaran, así que no hay que redeclararlos.
   Y la misma duración, 14s, que además barren en la primera mitad y descansan en
   la segunda: siete segundos de recorrido y otros siete de reposo.

   Lo ÚNICO que cambia entre los dos es la pareja de colores, y eso lo decide el
   fondo sobre el que va cada uno.

   🔴 EL RESPALDO ES AUTOMÁTICO Y ESTÁ EN EL ORDEN DE LAS REGLAS. El color macizo se
   declara FUERA del @supports; el recorte y el `color: transparent` solo entran
   dentro. Un navegador que no sepa recortar un degradado sobre texto no cruza esa
   puerta y se queda con el color macizo: nunca un texto transparente ni invisible.
   ============================================================================= */

/* Bloque en línea: le da al degradado una caja propia y previsible sobre la que
   calcular su 250 % de ancho. No cambia la maquetación —el rótulo sigue donde lo
   pone el text-align de su celda— ni el alto de la fila: un inline-block se ajusta
   a su contenido. Es lo mismo que hace .ga-tc__rotulo en la tabla de aceites. */
.ga-tcv .ga-tcv__rotulo {
    display: inline-block;
}

/* ═══════════════════════════════════════════════════════════════════════════
   1 · "GRAN ALMAZARA", EN LA ESQUINA
   ═══════════════════════════════════════════════════════════════════════════
   🔴 TODO EN VERDES, y esa es la diferencia con el de los aceites. Aquel va sobre
   la franja dorada clarísima y por eso es dorado; este va sobre el verde muy claro
   de la cabecera, así que la base es el verde oliva oscuro y el destello el verde
   montañas —el claro de la paleta—. El texto se lee VERDE en todo momento, que es
   lo que se pedía: la banda lo aclara al pasar, no lo cambia de color.

   Los dos son variables de marca; no hay ningún tono nuevo.

   BANDA POCO MARCADA: los dos verdes están cerca, así que el destello se nota como
   un reflejo y no como un cambio de color. Es a propósito.

   ⚠ CONTRASTE: en reposo, el verde oliva oscuro sobre esa franja da 8,2:1. Al paso
     de la banda, las pocas letras que quedan bajo ella bajan a 3,5:1 durante un
     instante. Es un tránsito breve sobre una parte del texto y el resto sigue en
     8,2:1; si alguna vez molestara, lo que hay que hacer es acercar más el destello
     a la base, no quitarlo.

   El color macizo lo hereda de .ga-tcv thead th, pero se repite aquí a propósito:
   este rótulo es el que se queda sin color si el @supports no entra, así que su
   respaldo tiene que estar escrito en su propia regla y no depender de heredarlo. */
.ga-tcv thead .ga-tcv__esquina .ga-tcv__rotulo {
    color: var(--ga-verde-oliva-oscuro);
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {

    .ga-tcv thead .ga-tcv__esquina .ga-tcv__rotulo {
        background-image: linear-gradient(
            100deg,
            var(--ga-verde-oliva-oscuro) 0%,
            var(--ga-verde-oliva-oscuro) 45%,
            var(--ga-verde-montanas)     50%,
            var(--ga-verde-oliva-oscuro) 55%,
            var(--ga-verde-oliva-oscuro) 100%
        );
        background-size: 250% 100%;
        background-repeat: no-repeat;
        background-position: 100% center;

        -webkit-background-clip: text;
        background-clip: text;
        -webkit-text-fill-color: transparent;
        color: transparent;

        animation: ga-home-card-brillo 14s linear infinite;
    }
}

/* Sin animación para quien la haya desactivado en su sistema, y con el verde
   MACIZO: se deshace el recorte en vez de dejar el degradado congelado, para que no
   quepa ninguna duda de que el texto se ve y se ve en su color de marca.

   Va DESPUÉS del @supports y con el mismo selector: mismo peso, gana el último. */
@media (prefers-reduced-motion: reduce) {

    .ga-tcv thead .ga-tcv__esquina .ga-tcv__rotulo {
        background-image: none;
        animation: none;
        -webkit-text-fill-color: currentColor;
        color: var(--ga-verde-oliva-oscuro);
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   2 · EL NOMBRE DE LA VARIEDAD QUE SE ESTÁ VIENDO
   ═══════════════════════════════════════════════════════════════════════════
   🔴 TODO EN DORADOS, copiado del nombre del formato destacado de la tabla de
   aceites: la misma base —el dorado de marca— y el mismo destello, ese #F5EEDD que
   el claude.md documenta como el dorado muy suave y que usan también los títulos de
   sección de la tienda. Se repite a propósito para que todos los destellos del
   sitio sean EL MISMO y no tres parecidos.

   Va sobre el verde oscuro de la fila, así que el nombre se lee dorado en todo
   momento y el contraste SUBE al pasar la banda, nunca baja: de 4,0:1 en reposo
   hacia arriba.

   ⚠ SOLO LA FILA DESTACADA. Los otros siete nombres se quedan en dorado macizo
     sobre crema, sin brillo: el selector exige .is-destacada y ninguna de estas
     reglas los alcanza. Si brillaran los ocho, el destello dejaría de señalar nada.

   ⚠ NO MUEVE NADA. Lo único que se toca del rótulo es cómo se pinta su texto —un
     fondo recortado y su color—; ni el tamaño de letra, ni el relleno, ni la caja.
     La fila mide y se alinea exactamente igual que antes de encenderlo.

   El dorado macizo va fuera del @supports y es a la vez el color normal y el
   respaldo, igual que en la esquina. */
.ga-tcv tbody tr.is-destacada th.ga-tcv__nombre .ga-tcv__rotulo {
    color: var(--ga-naranja-apagado);
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {

    .ga-tcv tbody tr.is-destacada th.ga-tcv__nombre .ga-tcv__rotulo {
        background-image: linear-gradient(
            100deg,
            var(--ga-naranja-apagado) 0%,
            var(--ga-naranja-apagado) 45%,
            #F5EEDD                   50%,
            var(--ga-naranja-apagado) 55%,
            var(--ga-naranja-apagado) 100%
        );
        background-size: 250% 100%;
        background-repeat: no-repeat;
        background-position: 100% center;

        -webkit-background-clip: text;
        background-clip: text;
        -webkit-text-fill-color: transparent;
        color: transparent;

        animation: ga-home-card-brillo 14s linear infinite;
    }
}

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

    .ga-tcv tbody tr.is-destacada th.ga-tcv__nombre .ga-tcv__rotulo {
        background-image: none;
        animation: none;
        -webkit-text-fill-color: currentColor;
        color: var(--ga-naranja-apagado);
    }
}


/* =============================================================================
   PACK DE ACEITUNAS — EL TERCER TARRO Y EL AVISO DE SELECCIÓN
   =============================================================================
   Solo existen en la ficha del pack de tres tarros: los pinta la plantilla desde
   el gancho woocommerce_after_variations_table, y solo cuando el producto tiene
   los atributos "tarro-1" y "tarro-2". En cualquier otra ficha estas reglas no
   encuentran nada a lo que aplicarse.
   ============================================================================= */

/* La fila del tercer tarro se separa de las dos de arriba con la MISMA medida que
   WooCommerce deja entre sus filas de atributos (.variations tr + tr), para que las
   tres se lean como una sola lista y no como dos más una. */
.ga-product-single .ga-pack-tarro3 {
    margin-top: var(--ga-space-sm);
}

/* La etiqueta, calcada de la de los atributos de WooCommerce: se le añade el mismo
   selector a la regla que ya las viste, unas líneas más arriba en este archivo, en
   lugar de repetir aquí tipografía, peso y color. */

/* ——— EL DESPLEGABLE DESACTIVADO ———
   Hereda todo el aspecto del de cantidad y de los de variación —flecha, tipografía,
   relleno, borde y radio— porque su selector está añadido a esas mismas reglas.
   Aquí solo se dice cómo se ve APAGADO.

   🔴 SE VE DESACTIVADO, PERO SE LEE. Baja el contraste del fondo, no el del texto:
   con el texto atenuado, "Gordal Aliñada (incluida siempre)" —que es información
   útil, no una opción descartada— se habría quedado a media luz. Así se entiende
   que no se puede tocar y se sigue leyendo perfectamente.

   ⚠ NI TAMAÑO NI POSICIÓN: mide exactamente lo mismo que los otros dos y ocupa su
     sitio en la fila. Lo único que cambia es el color del fondo y el cursor. */
/* 🔴 BORDE DORADO Y FONDO CREMA, PORQUE YA ESTÁ ELEGIDO. Este tarro no se elige
   —la Gordal va siempre— así que se pinta como lo que es, una opción ya tomada.

   ⚠ ESTE PAR DE COLORES YA NO ES SOLO SUYO. Desde que los tarros 1 y 2 confirman
     su selección (.is-elegida, bloque "LOS DESPLEGABLES CONFIRMAN LO QUE YA ESTÁ
     ELEGIDO"), los tres campos comparten exactamente el mismo aspecto una vez
     resueltos, que es justo lo que se buscaba: el 3 deja de ser la excepción y
     pasa a ser el ejemplo de cómo se ve un tarro decidido. Las dos líneas de
     background-color de aquí abajo están copiadas allí a propósito; si se cambia
     este crema, hay que cambiarlo también allí.

   ⚠ NI TAMAÑO NI POSICIÓN CAMBIAN: el grosor del borde sigue siendo el mismo que en
     los otros dos —2px, que viene de la regla común del desplegable de cantidad— y
     solo cambia su COLOR. El campo mide exactamente igual y ocupa su sitio en la
     fila. */
.ga-product-single .ga-pack-tarro3__select {
    background-color: var(--ga-naranja-claro);
    background-color: color-mix(in srgb, var(--ga-naranja-apagado) 8%, var(--ga-blanco));
    border-color: var(--ga-naranja-apagado);
    cursor: default;

    /* 🔴 SIN FLECHA. Llegó a llevarla, en dorado para que no desentonara, y se ha
       quitado: una flecha de desplegable es una invitación a desplegar, y este campo
       no se puede abrir. Prometía algo que al pulsarlo no pasaba.

       Basta con apagar la imagen: el appearance: none de la regla común sigue
       ocultando la flecha que dibujaría el navegador por su cuenta, así que no
       reaparece ninguna.

       ⚠ EL RELLENO DERECHO SE QUEDA COMO ESTABA, y es a propósito: son los 3rem que
         la regla común reserva para la flecha. Quitarlos no se vería —el texto va a
         la izquierda y el campo ocupa todo el ancho— y en cambio obligaría a
         escribir aquí un padding propio, o sea a duplicar una medida. El resto del
         aspecto no cambia, que es lo que se pedía. */
    background-image: none;
}

/* ——— EL TEXTO DE DENTRO, EXACTAMENTE EL DE LOS OTROS DOS ———
   🔴 LA REGLA SIGUE EXISTIENDO SOLO POR EL DESACTIVADO. El navegador atenúa por su
   cuenta el texto de un <select> deshabilitado, y en algunos motores bastante: sin
   esto, "Gordal Aliñada (incluida siempre)" se vería a media luz aunque heredara el
   color correcto. El opacity: 1 y el color explícito son lo que le devuelven la
   misma fuerza que tienen los tarros 1 y 2.

   🔴 Y EL COLOR ES EL MISMO QUE EL SUYO, NO UNO PROPIO. Aquí estuvo un tiempo el
   negro de marca (--ga-negro-suave), puesto pensando en el contraste; el efecto
   secundario era que este campo se leía en un tono distinto al de los otros dos y la
   lista de tres tarros dejaba de verse como una sola cosa. Ahora repite el
   --ga-verde-oliva-oscuro de la regla común de los desplegables, que es el que ya
   tienen "Chupadedos" y "Manzanilla con Hueso": misma tipografía, mismo cuerpo,
   mismo grosor y mismo color, porque todo lo demás ya le llegaba de esa regla común
   y lo único que se salía de ella era esta línea.

   ⚠ EL CONTRASTE SIGUE SIENDO HOLGADO: el verde oliva oscuro (#4a4a2f) sobre el
     crema del campo desactivado da del orden de 9:1, muy por encima del 4,5:1 que
     pide la norma para texto. Se pierde el 15:1 del negro y se gana la coherencia
     con los otros dos, que es lo que se ha pedido; no hay ningún problema de
     lectura. El borde y el fondo siguen dorados: la señal de "esto ya está puesto"
     la dan ellos, que no son texto.

   ⚠ NI TAMAÑO NI POSICIÓN: solo el color. */
.ga-product-single:not(.ga-product-single--eventos) .ga-pack-tarro3__select:disabled {
    color: var(--ga-verde-oliva-oscuro);
    opacity: 1;
}

/* ——— EL AVISO DE QUE FALTAN VARIEDADES ———
   Aparece mientras el tarro 1 o el tarro 2 estén sin elegir y desaparece en cuanto
   WooCommerce resuelve una variación. Lo enciende y lo apaga el JS con el atributo
   `hidden`, que es el mismo dato con el que decide si los botones se pueden pulsar:
   así el aviso y los botones no pueden contradecirse.

   role="status" en el marcado para que un lector de pantalla lo anuncie sin robar
   el foco.

   ⚠ EL [hidden] NECESITA ESTA REGLA. El display de aquí abajo gana al display:none
     que el navegador le da a [hidden] por defecto, así que sin ella el aviso se
     vería siempre. Es la misma pareja de reglas que ya lleva el campo condicional
     del formulario de Contacto, y por el mismo motivo. */
.ga-product-single .ga-pack-aviso {
    display: block;
    margin: var(--ga-space-xs) 0 0;
    padding: 0.7rem 0.9rem;

    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    line-height: 1.45;
    color: var(--ga-verde-oliva-oscuro);
    overflow-wrap: break-word;

    background-color: var(--ga-naranja-claro);
    background-color: color-mix(in srgb, var(--ga-naranja-apagado) 10%, var(--ga-blanco));
    border-left: 3px solid var(--ga-naranja-apagado);
    border-radius: var(--ga-radius-sm);
}

.ga-product-single .ga-pack-aviso[hidden] {
    display: none;
}


/* =============================================================================
   LA CAMISETA — LAS CUATRO TARJETAS DE TALLA
   =============================================================================
   Aquí hay MUY POCO, y es a propósito: las tarjetas las construye el JS con las
   MISMAS clases que las de "Elige la cantidad" del aceite (.ga-cantidad__fila,
   .ga-opcion, .ga-radio, .ga-cantidad__texto), así que el tamaño, el borde, el
   círculo y su centrado, el hover, el halo de foco y la confirmación al elegir
   —fondo crema y borde dorado— les llegan enteros de aquellas reglas. Y el
   contenedor lleva .ga-cantidad, de donde salen la rejilla de una columna, el hueco
   entre tarjetas y el margen inferior. No se ha copiado ni un valor.

   Lo único propio es lo de aquí abajo: esconder el desplegable al que sustituyen y
   pintar la talla agotada. */

/* ——— FUERA EL DESPLEGABLE, PERO SOLO CUANDO YA HAY TARJETAS ———
   🔴 LA CLASE LA PONE EL JS, Y LA PONE AL FINAL DE TODO. Si el script no corre, o si
   falla antes de terminar, esta clase no llega a existir y el <select> nativo se ve
   y funciona con normalidad. Escondiéndolo desde el servidor, un fallo del JS habría
   dejado la ficha sin ninguna forma de elegir talla.

   🔴 SE ESCONDE, NO SE QUITA DEL DOM. Es el campo real de la variación: WooCommerce
   lo lee y lo escribe, y de él sale el variation_id que viaja al carrito. Un campo
   con display:none SE SIGUE ENVIANDO —lo que no se envía es uno deshabilitado—, así
   que esconderlo no le quita nada.

   Se esconde la TABLA entera y no solo el <select>: con ella se va la celda de la
   etiqueta del atributo, que en esta ficha ya venía oculta por el ajuste del plugin
   de swatches, y cualquier resto que WooCommerce pinte ahí dentro. */
.ga-product-single.is-tallas-tarjetas .variations {
    display: none;
}


/* =============================================================================
   APADRINA UN OLIVO — EL NÚMERO DE OLIVO Y EL RÓTULO DEL PLAN
   =============================================================================
   Aquí hay muy poco, y es a propósito. El desplegable del olivo lleva la clase
   .ga-cantidad__select, la del selector de packs, así que la flecha dibujada a mano,
   la tipografía, el relleno, el borde de 2px, el radio y el ancho completo le llegan
   de aquellas reglas. Y los dos rótulos llevan .ga-cantidad__titulo, el de "Elige la
   cantidad". Ni un valor copiado.

   ⚠ EL DESPLEGABLE DEL OLIVO NO SE ESCONDE NUNCA, a diferencia del de la variación:
     ese es un campo de verdad —name="ga_olivo"— y es el que viaja en el POST hasta
     functions.php § 11. Las tarjetas de plan sustituyen al OTRO. */

/* Lo único propio: el aire que separa el rótulo del plan del desplegable del olivo,
   para que se lea como un apartado nuevo y no como una línea suelta pegada al campo
   anterior. Es la misma medida y el mismo motivo que "Personaliza tu pack". */
.ga-product-single .ga-apadrina-plan__titulo {
    margin-top: var(--ga-space-sm);
}

/* ——— LA TALLA AGOTADA ———
   El JS marca la tarjeta y deshabilita su radio, así que ya no se puede elegir ni
   con el ratón ni con el teclado. Esto solo lo cuenta a la vista.

   ⚠ NI TAMAÑO NI POSICIÓN: la tarjeta mide exactamente lo mismo que las otras tres
     —mismo relleno y mismo borde de 2px, que sigue existiendo y solo cambia de
     color— y lo único que se toca es el color y la opacidad del contenido. Es la
     regla de estabilidad de layout del claude.md.

   ⚠ Y SIN HOVER: la regla de abajo devuelve el borde a su tono apagado también al
     pasar por encima, porque .ga-cantidad__fila:hover lo pone dorado y en una talla
     que no se puede comprar eso prometería algo que no va a pasar. */
.ga-product-single .ga-talla__fila.is-agotada {
    cursor: default;
}

.ga-product-single .ga-talla__fila.is-agotada .ga-opcion {
    opacity: 0.55;
}

.ga-product-single .ga-talla__fila.is-agotada,
.ga-product-single .ga-talla__fila.is-agotada:hover {
    border-color: var(--ga-amarillo-pastel);
}


/* =============================================================================
   PACK DE TRES TARROS — EL ENCABEZADO "PERSONALIZA TU PACK"
   =============================================================================
   Solo existe en la ficha del pack: lo pinta la plantilla, y solo cuando el
   producto tiene los atributos "tarro-1" y "tarro-2".

   🔴 EL FORMATO NO SE DECLARA AQUÍ. El elemento lleva también la clase
   .ga-cantidad__titulo, la de "Elige la cantidad", así que la tipografía, el
   tamaño, el peso, el color y el interlineado le llegan de aquella regla. Los dos
   son apartados hermanos de la misma columna y tienen que leerse igual; si algún
   día se retoca ese rótulo, este lo sigue solo.

   Lo único propio es lo de aquí abajo: el aire que lo separa del bloque de
   cantidad y su sitio en la ficha apilada.
   ============================================================================= */

/* ——— EL AIRE DE ARRIBA ———
   Sin esto, el rótulo quedaría a 1,35rem del desplegable de cantidad —el gap de la
   columna más el margen inferior de .ga-cantidad— y a solo 0,25rem del "Tarro 1"
   que encabeza. Con las dos distancias tan parecidas, no se leería como el
   principio de un apartado nuevo sino como una línea suelta entre dos campos.

   Se le añade la separación por arriba y se deja intacta la de abajo: un
   encabezado tiene que estar MÁS CERCA de lo que encabeza que de lo que deja
   atrás. El total queda en unos 2,2rem por arriba contra 0,25 por abajo. */
.ga-product-single .ga-pack-perso__titulo {
    margin-top: var(--ga-space-sm);
}

/* ——— SU SITIO EN LA FICHA APILADA ———
   🔴 SIN ESTA REGLA EL RÓTULO SE VA AL FINAL DE LA FICHA. Por debajo de 860px las
   dos columnas pasan a display: contents y el orden lo deciden los `order` de esa
   lista; cualquier bloque que no esté enumerado cae en el suelo de seguridad
   (order: 20) y aparece detrás de todo. Es justo la trampa que el propio bloque de
   ordenación deja advertida.

   Va con el MISMO número que .ga-cantidad, no con uno intermedio: entre elementos
   que empatan en `order` manda el orden del marcado, y en el marcado este rótulo
   va justo después del bloque de cantidad. Así queda entre ella y el formulario
   (order: 8) sin necesidad de renumerar nada. */
@media (max-width: 860px) {

    .ga-product-single:not(.ga-product-single--eventos) .ga-pack-perso__titulo {
        order: 7;
    }
}


/* =============================================================================
   PRENDAS — "SOLO HAY 15 UNIDADES, ASÍ QUE LIMITAMOS LA COMPRA A UNA POR PEDIDO"
   =============================================================================
   La frase que abre el apartado de la talla, encima del rótulo "Elige tu talla".
   Solo existe en la ficha de una prenda: la pinta la plantilla dentro de la rama
   de la prenda, que lleva su propio ! $ga_es_eventos.

   🔴 SU FORMATO NO SE DECLARA AQUÍ, Y ESO ES EL PUNTO. Antes era una línea pequeña
   y discreta con su propia tipografía, su propio cuerpo y su propio color a media
   tinta, y se veía como una nota al pie de algo. Ahora tiene que leerse como
   HERMANA del rótulo que va debajo, así que se ha añadido a las dos reglas que ya
   visten a .ga-cantidad__titulo —la de "ENCABEZADOS DE BLOQUE" y la de más arriba—
   en lugar de copiar aquí sus valores. Comparten declaración: si mañana se retoca
   ese rótulo, esta frase se retoca con él y no hay dos sitios que sincronizar.

   Es el mismo mecanismo que ya usa "Personaliza tu pack", y por el mismo motivo.

   ⚠ LO QUE QUEDA AQUÍ ES SOLO LO QUE NO ES FORMATO: el aire de arriba, que es cosa
     suya porque es ella quien abre el apartado, y el corte de palabra. Si se añade
     algo más a este bloque, ojo: va DESPUÉS de aquellas dos en el archivo y con la
     misma especificidad, así que cualquier propiedad que se escriba aquí las gana y
     rompe justo lo que este bloque existe para conseguir. */
.ga-product-single .ga-textil-unidad {
    /* El aire de arriba es el mismo que tenía el rótulo "Elige tu talla" cuando
       encabezaba él el apartado: 1rem de margen más los 1,25rem de hueco de la
       columna, unos 2,25rem en total. Ahora el que abre el apartado es este texto,
       así que la separación se muda con él.

       ⚠ EL SHORTHAND ES DELIBERADO: deja además el margen inferior en 0 y anula el
         `0 0 0.25rem` que le llega de la regla compartida de arriba. Ese cuarto de
         rem estaba pensado para un rótulo pegado a su campo; aquí, entre las dos
         líneas, la separación la da el hueco de la columna y nada más. */
    margin: var(--ga-space-sm) 0 0;

    /* Ni min-width ni nada que fije un ancho: la frase es larga y a 360px la caja
       es estrecha, así que lo único que hace falta es que pueda partir. */
    overflow-wrap: break-word;
}

/* ——— LA SEPARACIÓN ENTRE LA EXPLICACIÓN Y EL RÓTULO ———
   🔴 ESTE ES EL ÚNICO SITIO DESDE EL QUE SE REGULA ESE HUECO, y conviene saber por
   qué es este y no el margen inferior de la frase: la frase manda sobre el aire que
   tiene POR ENCIMA (su propio margin-top) y el rótulo sobre el que la separa de ella.
   Cada distancia en una sola mano, así que tocar una nunca mueve la otra.

   DE DÓNDE SE PARTE. El rótulo trae 1rem de margen superior propio, pensado para
   cuando es él quien abre el apartado. Sumado al hueco de la columna darían 2,25rem,
   exactamente la misma distancia que hay por encima de la frase: con las dos
   separaciones iguales, la frase dejaría de leerse como la entrada del apartado y
   pasaría a parecer la cola del bloque anterior. Por eso no se deja tal cual.

   PERO TAMPOCO EN CERO. Estuvo así, y con los dos textos ya al mismo cuerpo —la
   frase se subió al formato del rótulo— quedaban pegados: 1,25rem entre dos líneas
   de ese tamaño se leen como un párrafo de dos líneas, no como dos cosas distintas.

   EL PUNTO MEDIO, Y CON MEDIDA DEL PROYECTO. Con --ga-space-xs quedan 1,75rem entre
   los dos —el hueco de la columna más medio rem— contra 2,25rem por encima de la
   frase. Es aproximadamente una línea de altura a este cuerpo, así que se leen como
   dos líneas separadas; y sigue siendo MENOS que el aire de arriba, que es lo que
   mantiene a las dos como una pieza frente a lo que tienen encima. Invertir esa
   proporción las partiría en dos apartados, que es justo lo que no se busca.

   ⚠ NO SE TOCA EL MARGEN SUPERIOR DE LA FRASE. Su separación con lo que tiene encima
     se queda exactamente como estaba; lo único que se mueve es este hueco de aquí.

   ⚠ A 360px LA PROPORCIÓN AGUANTA. Ahí el cuerpo baja al mínimo del clamp (1,15rem)
     y el hueco de la rejilla apilada es 1rem, así que quedan 1,5rem entre los dos
     contra 2rem por arriba: la misma jerarquía, a menor escala.

   ⚠ ACOTADO CON EL HERMANO ADYACENTE, ASÍ QUE NO ALCANZA AL PACK. "Personaliza tu
     pack" lleva ese mismo rótulo y NO tiene ningún .ga-textil-unidad delante, así
     que conserva su margen de siempre. Sin este selector habría hecho falta una
     clase nueva solo para esto. */
.ga-product-single .ga-textil-unidad + .ga-pack-perso__titulo {
    margin-top: var(--ga-space-xs);
}

/* ——— SU SITIO EN LA FICHA APILADA ———
   🔴 SIN ESTA REGLA LA FRASE SE VA AL FINAL DE LA FICHA. Por debajo de 860px las dos
   columnas pasan a display: contents y el orden lo deciden los `order`; lo que no
   está enumerado cae en el suelo de seguridad (order: 20) y aparece detrás de todo.
   Es la trampa nº 13 del claude.md, y este párrafo es justo el tipo de bloque nuevo
   contra el que avisa.

   Va con el MISMO 7 que el rótulo al que acompaña, no con un número intermedio:
   entre elementos que empatan en `order` manda el orden del marcado, y en el marcado
   la explicación va justo antes del rótulo. Así los dos viajan juntos sin renumerar
   nada. */
@media (max-width: 860px) {

    .ga-product-single:not(.ga-product-single--eventos) .ga-textil-unidad {
        order: 7;
    }
}


/* =============================================================================
   TODA LA TIENDA EN MÓVIL · TÍTULO, DISPONIBILIDAD Y PRECIO, COMPACTOS
   =============================================================================
   El ORDEN de esas tres piezas no se decide aquí: está arriba, en el bloque de
   `order` del apilado, fundido con los valores de siempre. Aquí solo se quitan los
   márgenes que sobran cuando la ficha se apila.

   ⚠ ESTO ESTUVO ACOTADO A LOS TRES ACEITES con una clase propia y se ha extendido a
     toda la tienda: es presentación, no contenido, así que vale igual en un tarro,
     un pack, la mermelada, la camiseta o el aceitunero. Al valer para todos, la
     clase --aceites se ha retirado en lugar de dejarla sin uso.

   ⚠ LA CAMISETA CONSERVA SU TEXTO Y SU COLOR. Estas reglas tocan .ga-product__stock,
     que es el mismo elemento diga lo que diga por dentro: allí pone "Últimas
     unidades" en naranja y aquí no se declara ni un texto ni un color, solo se
     quitan dos márgenes. Se mueve el bloque, no lo que dice. */
@media (max-width: 860px) {

    /* ═══════════════════════════════════════════════════════════════════════
       Y LOS TRES, COMPACTOS
       ═══════════════════════════════════════════════════════════════════════
       🔴 LOS MÁRGENES QUE SOBRAN ESTÁN CALCULADOS PARA LA FICHA DE ESCRITORIO, no
       para esta. El precio trae 0,5rem por arriba y la disponibilidad 1,2rem por
       arriba y 0,9rem por abajo, y ese 1,2 está puesto —lo dice su propio
       comentario— porque en escritorio encima tiene el precio y debajo "Elige la
       cantidad", dos bloques grandes entre los que hace falta aire.

       Apilada, esos márgenes se SUMAN al row-gap de 1rem que la rejilla le da a
       todas las celdas, así que entre el precio y la disponibilidad quedaban 2,2rem
       y antes del precio 1,5rem: el bloque del título abría con un hueco enorme.

       Poniéndolos a cero, la separación la marca únicamente el row-gap de la
       rejilla —1rem parejo entre las tres piezas—, que es el aire justo para
       distinguirlas sin que se lean como tres bloques sueltos. No se inventa
       ninguna medida: se quitan las que aquí sobran y manda la que ya existía.

       ⚠ NO SE TOCA EL row-gap. Es de la rejilla entera y bajarlo apretaría también
         el formulario, los sellos y el acordeón, que no lo han pedido. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__price-wrap {
        margin-top: 0;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-product__stock {
        margin-top: 0;
        margin-bottom: 0;
    }
}


/* =============================================================================
   TODA LA TIENDA EN MÓVIL · LOS SELLOS EN FILA DE TRES
   =============================================================================
   La barra de confianza es una fila de tres en escritorio, pero por debajo de 640px
   el sitio la apila en columna —`flex-direction: column`, unas líneas más arriba en
   este archivo—. En los tres formatos de aceite se quiere que siga siendo una fila,
   con los tres sellos uno al lado del otro.

   🔴 EL PUNTO DE CORTE ES 640px Y NO 860px A PROPÓSITO. Es el que gobierna ESTE
   comportamiento: la barra no se apila al apilarse la ficha (860), sino en el
   escalón de ajustes finos (640), así que es ahí donde hay que contestarle. Usar el
   otro habría dejado el tramo de 860 a 640 con la fila puesta dos veces por dos
   reglas distintas, y el apilado seguiría apareciendo por debajo.

   🔴 SE PASA A GRID, NO SE LE DA LA VUELTA AL FLEX. Con `display: grid` y tres
   pistas iguales, el `flex-direction: column` de la regla base deja de tener efecto
   —no hay flex que dirigir— y los tres sellos reparten el ancho a partes iguales sin
   depender de un `flex: 1` que hay que ir contrarrestando.

   🔴 minmax(0, 1fr) Y NO 1fr, que es la regla de oro aquí: el mínimo por defecto de
   una pista es el ancho de su contenido, y "Devolución" o "100 % protegido"
   ensancharían su columna y con ella la barra por encima del viewport. Con el 0 de
   mínimo la pista encoge y el texto parte donde toca. Es cómo se corta el ancho
   mínimo sin usar un solo min-width.

   LAS CUENTAS A 360px, que es donde esto se decide: quitando el relleno lateral del
   contenedor de la ficha y el de la propia barra, y los dos huecos entre columnas,
   a cada sello le quedan unos 95px. "Devolución" —la palabra más larga— mide unos
   64px a 0,7rem en negrita sin interletrado, así que entra con holgura; "Pago
   seguro" y "100 % protegido" llevan espacio y parten en dos líneas por sí solas.
   El overflow-wrap está puesto igualmente como red: si algún día se cambia un texto
   por otro más largo, partirá en vez de desbordar.

   ⚠ EL ICONO BAJA A 20px DESDE EL CSS. En el HTML va con width y height de 24, pero
     no se puede tocar la plantilla en este encargo —ni hace falta—: esos atributos
     solo reservan proporción, y el tamaño real lo manda el CSS. Los 4px que se
     ahorran por sello son los que dejan respirar al texto.

   ⚠ NI TAMAÑO NI POSICIÓN EN NINGÚN ESTADO: aquí no hay hover ni foco, la barra no
     es interactiva.

   ⚠ ACOTADO A TODO LO QUE NO ES EVENTOS. Estuvo limitado a los tres aceites con una
     clase propia y se ha extendido: es presentación y vale igual en cualquier ficha
     que tenga esta barra. Apadrina un Olivo no hace falta excluirlo a mano —su ficha
     ya no pinta la barra, así que la regla no encuentra nada—, y Eventos queda fuera
     por el :not(), porque allí los tres sellos dicen otra cosa.

   ⚠ EN ESCRITORIO NO CAMBIA NADA: todo esto vive dentro del media query. */
@media (max-width: 640px) {

    .ga-product-single:not(.ga-product-single--eventos) .ga-product__trust-band {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 0.4rem;
        padding: 0.85rem 0.6rem;
    }

    /* Cada sello, en columna y centrado: el icono encima de su texto. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-trust-item {
        flex-direction: column;
        align-items: center;
        gap: 0.3rem;
        text-align: center;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-trust-item div {
        align-items: center;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-trust-item svg {
        width: 20px;
        height: 20px;
    }

    /* Un punto menos de cuerpo y sin interletrado: en una columna de 95px, esos
       0,03em por letra son varios píxeles que no sobran. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-trust-item strong {
        font-size: 0.7rem;
        letter-spacing: normal;
        overflow-wrap: break-word;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-trust-item span {
        font-size: 0.65rem;
        line-height: 1.3;
        overflow-wrap: break-word;
    }
}


/* =============================================================================
   LAS DOS TABLAS COMPARATIVAS EN MÓVIL
   =============================================================================
   Afecta a la tabla de garantías de las fichas de aceite (.ga-tc--mov) y a la guía
   de variedades de las de aceituna (.ga-tcv). En escritorio no cambia nada: todo
   vive dentro del punto de corte de 860px que la ficha ya usa.

   ⚠ EVENTOS NO ENTRA: ninguna de las dos secciones se pinta en una ficha
     personalizada, y además el selector del antetítulo lleva su :not() escrito. */
@media (max-width: 860px) {

    /* ——— SIN ANTETÍTULO ———
       "NUESTROS ACEITES" y "NUESTRAS ACEITUNAS" se van en móvil: con el título justo
       debajo, el antetítulo solo añadía una línea más en una pantalla estrecha.

       ⚠ EL :not() DEJA FUERA A LOS MARIDAJES DE LA MERMELADA, que comparten la clase
         .ga-product__comparativa y conservan su "MARIDAJES". Solo se quita en las dos
         tablas que se han pedido. */
    .ga-product-single:not(.ga-product-single--eventos)
    .ga-product__comparativa:not(.ga-product__comparativa--maridajes)
    .ga-section__eyebrow {
        display: none;
    }


    /* ——— TABLA DE ACEITE · LA PRIMERA COLUMNA, MÁS ESTRECHA ———
       Se llevaba la mitad del ancho para textos que no la necesitan, dejando las dos
       columnas de marcas apretadas. Repartiendo 34/33/33, las de datos casi doblan su
       sitio y el concepto sigue leyéndose en dos líneas como mucho. */
    .ga-tc--mov .ga-tc__col-concepto { width: 34%; }
    .ga-tc--mov .ga-tc__col-dato     { width: 33%; }

    /* ——— TODO CENTRADO, EN LOS DOS EJES ———
       El centrado vertical es lo que alinea entre sí los iconos de una misma fila
       cuando uno lleva nota debajo ("No siempre") y el otro no. */
    .ga-tc--mov th,
    .ga-tc--mov td,
    .ga-tcv th,
    .ga-tcv td {
        text-align: center;
        vertical-align: middle;
        /* Corta el ancho mínimo del texto sin recurrir a min-width. */
        overflow-wrap: break-word;
    }

    /* Un punto menos de cuerpo para que quepa holgado a 360px sin dejar de leerse. */
    .ga-tc--mov,
    .ga-tcv {
        font-size: var(--ga-text-xs);
    }

    /* ——— LA COLUMNA DE GRAN ALMAZARA, RESALTADA ———
       🔴 EL VERDE VA EN TODAS SUS CELDAS, CABECERA INCLUIDA, y por eso se lee como una
       columna-tarjeta continua de arriba abajo en vez de como celdas sueltas: no hay
       ningún hueco de fondo entre una fila y la siguiente. Es el mismo efecto que en
       escritorio tiene la columna destacada.

       El redondeo de las esquinas inferiores ya se lo dan las reglas de
       .ga-tc__nuestra--ini / --fin que existen para escritorio, así que aquí no se
       vuelve a declarar.

       ⚠ EL TEXTO PASA A BLANCO, incluido el de la cabecera: sobre el verde oliva
         oscuro, el color con el que sale en escritorio no tendría contraste. Blanco
         sobre #4a4a2f da del orden de 9:1, muy por encima del 4,5:1 de la norma. */
    .ga-tc--mov .ga-tc__nuestra,
    .ga-tc--mov thead .ga-tc__nuestra {
        background-color: var(--ga-verde-oliva-oscuro);
        color: var(--ga-blanco);
    }

    /* El icono hereda el color del texto, así que se vuelve blanco con él. */
    .ga-tc--mov .ga-tc__nuestra svg {
        color: currentColor;
    }
}


/* =============================================================================
   TABLA DE ACEITE EN MÓVIL · CUATRO REMATES
   =============================================================================
   Todo dentro del punto de corte de 860px, así que en escritorio la tabla no cambia.
   Y todo acotado a .ga-compara-mov / .ga-tc--mov, que es marcado que solo existe
   fuera de Eventos. */
@media (max-width: 860px) {

    /* ——— 1 · FUERA EL RESUMEN DE FORMATOS ———
       Las tarjetas de "Bell 500 ml", "Garrafa 2 L" y "Garrafa 5 L" con su cosecha y
       su "ideal para". En escritorio esa información vive en las columnas de la tabla
       grande; aquí se quedaban como tres bloques sueltos encima de la comparativa.

       ⚠ SE OCULTA SOLO LA REJILLA DE TARJETAS, no .ga-compara-mov entera: dentro de
         ese contenedor va también la tabla de garantías, que es justo la que se
         queda. */
    .ga-compara-mov__tarjetas {
        display: none;
    }


    /* ——— 2 · SIN LÍNEAS DENTRO DE LA COLUMNA VERDE ———
       🔴 SE VUELVE TRANSPARENTE EL BORDE, NO SE QUITA. Con `border-bottom: 0` la
       celda perdería 1px de alto y su contenido —centrado en vertical— se movería
       medio píxel respecto al de las columnas de al lado. En transparente, la celda
       mide EXACTAMENTE lo mismo y no se descoloca nada.

       Y se ve verde continuo porque el fondo de una celda se pinta por debajo de su
       borde (background-clip vale border-box por defecto): donde el borde no pinta,
       asoma el verde. Es la misma técnica que ya usa la columna destacada de
       escritorio.

       ⚠ SOLO EN ESTA COLUMNA: las rayas de "Otras marcas" y las de la columna de
         conceptos no se tocan, porque sus celdas no llevan esta clase. */
    .ga-tc--mov .ga-tc__nuestra {
        border-bottom-color: transparent;
    }


    /* ——— 3 · TIC VERDE SOBRE CÍRCULO BLANCO ———
       Sobre el fondo verde de la columna, un tic blanco se leía flojo. Pasa a verde
       de marca dentro de un círculo blanco relleno, que es lo que le da contraste y
       lo convierte en un sello.

       Medidas fijas y iguales para todos —16px de icono más 4px de relleno a cada
       lado, o sea un círculo de 24px— para que los cuatro se vean del mismo tamaño y
       alineados entre sí. El centrado en la celda ya lo dan el flex de .ga-tc__marca
       y el vertical-align: middle que se puso en el bloque anterior.

       ⚠ box-sizing: content-box A PROPÓSITO: así el relleno se SUMA a los 16px en vez
         de comérselos, y el icono conserva su tamaño dentro del círculo. */
    .ga-tc--mov .ga-tc__nuestra .ga-tc__marca svg {
        box-sizing: content-box;
        width: 16px;
        height: 16px;
        padding: 4px;
        color: var(--ga-verde-oliva-oscuro);
        background-color: var(--ga-blanco);
        border-radius: var(--ga-radius-full);
    }


    /* ——— 4 · LA COLUMNA SOBRESALE POR ARRIBA Y POR ABAJO ———
       Como la pestaña vertical que tiene en escritorio. El saliente se dibuja con dos
       pseudoelementos, uno en la celda de la cabecera y otro en la última del cuerpo.

       🔴 UN PSEUDOELEMENTO ABSOLUTO NO OCUPA SITIO, y esa es la clave para cumplir el
       "no descoloca nada": no entra en el cálculo de la maquetación, así que ni la
       fila crece ni las otras columnas se mueven. Añadir relleno a esas celdas sí las
       habría movido, porque habría estirado toda la fila.

       Los 14px son los mismos que usa el saliente de escritorio
       (--ga-tc-saliente-abajo), para que las dos versiones se vean igual de largas.

       ⚠ EL MARCO TIENE QUE DEJAR ASOMAR. .ga-tc-marco recorta con overflow: clip para
         que la tabla no desborde sus esquinas redondeadas, y ese recorte se comería el
         saliente. Se le da margen vertical para hacerle sitio y se levanta el recorte
         SOLO en esta tabla de móvil.

       ⚠ NO PUEDE DESBORDAR A LOS LADOS: los dos pseudoelementos van pegados a los
         bordes de su celda con left/right a 0, así que no se salen ni un píxel del
         ancho de la columna. El saliente es solo vertical. */
    .ga-compara-mov .ga-tc-marco {
        overflow: visible;
        margin-block: 14px;
    }

    .ga-tc--mov thead .ga-tc__nuestra,
    .ga-tc--mov tbody tr:last-child .ga-tc__nuestra {
        position: relative;
    }

    .ga-tc--mov thead .ga-tc__nuestra::before,
    .ga-tc--mov tbody tr:last-child .ga-tc__nuestra::after {
        content: "";
        position: absolute;
        left: 0;
        right: 0;
        height: 14px;
        background-color: var(--ga-verde-oliva-oscuro);
    }

    .ga-tc--mov thead .ga-tc__nuestra::before {
        top: -14px;
        border-radius: 10px 10px 0 0;
    }

    .ga-tc--mov tbody tr:last-child .ga-tc__nuestra::after {
        bottom: -14px;
        border-radius: 0 0 10px 10px;
    }

    /* ⚠ Y LA CELDA DEJA DE REDONDEARSE POR ABAJO. Las reglas de escritorio le dan
       esquinas redondeadas a la última fila de la columna (--ini y --fin), y ahí es
       lo correcto porque es donde termina la tarjeta. Aquí no termina: debajo cuelga
       el saliente. Con las dos redondeadas se veía un pellizco justo en la unión, así
       que la celda se deja recta y el redondeo lo pone solo la punta. */
    .ga-tc--mov tbody tr:last-child .ga-tc__nuestra--ini,
    .ga-tc--mov tbody tr:last-child .ga-tc__nuestra--fin {
        border-bottom-left-radius: 0;
        border-bottom-right-radius: 0;
    }
}


/* =============================================================================
   TABLA DE ACEITE EN MÓVIL · LA LÍNEA QUE NO SE IBA, Y EL LOGO DE LA ESQUINA
   ============================================================================= */
@media (max-width: 860px) {

    /* ——— LA LÍNEA DE LA COLUMNA VERDE: ERA UN PROBLEMA DE ESPECIFICIDAD ———
       🔴 EL border-bottom-color: transparent DEL BLOQUE ANTERIOR NUNCA LLEGÓ A
       APLICARSE. La raya no la pinta la celda por su cuenta: la pinta

           .ga-tc tbody tr:not(:last-child) th,
           .ga-tc tbody tr:not(:last-child) td      (línea 1448 de este archivo)

       cuya especificidad es 0-2-3 —dos clases contando el :not(), más tres
       elementos—, mientras que aquella regla era .ga-tc--mov .ga-tc__nuestra, o sea
       0-2-0. Perdía por los tres elementos, así que el borde seguía pintándose y la
       raya seguía viéndose. No era que el color no funcionara: es que esa
       declaración nunca ganó.

       La de aquí abajo repite la MISMA forma del selector que pinta la raya y le
       añade la clase de la columna: 0-3-3, que gana sin discusión y sin recurrir a
       !important.

       ⚠ SIGUE SIENDO transparent Y NO border: 0: con el borde a cero la celda
         perdería 1px de alto y su contenido, centrado en vertical, se movería medio
         píxel respecto a las columnas de al lado. En transparente mide exactamente lo
         mismo y el verde asoma por debajo.

       ⚠ SOLO EN ESTA COLUMNA: las rayas de "Otras marcas" y las de la columna de
         conceptos no se tocan, porque sus celdas no llevan .ga-tc__nuestra. */
    .ga-tc--mov tbody tr:not(:last-child) .ga-tc__nuestra {
        border-bottom-color: transparent;
    }

    /* Y la raya que cierra la cabecera, por el mismo motivo y con el mismo criterio:
       dentro de la columna verde no debe verse ninguna división. */
    .ga-tc--mov thead tr .ga-tc__nuestra {
        border-bottom-color: transparent;
    }


    /* ——— EL LOGO DE LA ESQUINA ———
       Pequeño, centrado y con aire por los cuatro lados para que no toque los bordes
       de su celda.

       ⚠ SIN min-width Y CON max-width: 100%: si la celda se estrechara, el logo
         encoge con ella en vez de empujar la columna. El height: auto conserva su
         proporción.

       ⚠ NI HOVER NI FOCO: es una imagen decorativa dentro de una celda, no un enlace,
         así que no tiene ningún estado que pueda mover nada. */
    /* 🔴 EL LOGO ES UN SELLO CIRCULAR, o sea CUADRADO. Va a 42px: a 56 se comía su
       celda y pesaba más que los rótulos de las columnas de al lado, que son de los
       que tiene que tirar el ojo. Con 42 sigue leyéndose la casa y el aro con el
       nombre —no queda como una motita— y respira.

       ⚠ EL width MANDA Y height: auto LO SIGUE: el sello es 1:1 y así se mantiene.
         Los atributos width/height del HTML son 56 y no se tocan porque no son un
         tamaño, son la PROPORCIÓN que el navegador reserva antes de descargar la
         imagen para que la tabla no dé un salto; 56×56 y 42×42 son la misma
         proporción, así que siguen siendo correctos.

       ⚠ EL max-width EN % Y EL height: auto SON LO QUE IMPIDE QUE DESCOLOQUE LA
         TABLA. La primera columna mide el 34% del ancho, que a 360px son unos 105px:
         el sello cabe con holgura, pero si la pantalla fuera aún más estrecha el
         logo encogería con su celda en vez de empujar la columna y desbordar. Sin
         min-width en ninguna parte, como manda el proyecto.

       ⚠ EL MARGEN ES EL AIRE QUE SE PIDIÓ, y sube con el recorte: 0.75rem arriba y
         abajo, y auto a los lados, que es lo que lo centra. El sello queda más
         pequeño Y más suelto, que es justo lo que se buscaba. */
    .ga-tc--mov .ga-tc__logo {
        display: block;
        width: 42px;
        max-width: 100%;
        height: auto;
        margin: 0.75rem auto;
    }
}


/* =============================================================================
   TABLA DE ACEITE EN MÓVIL · "OTRAS MARCAS", EN NEGRO EN VEZ DE EN DORADO
   ============================================================================= */
@media (max-width: 860px) {

    /* El dorado de los dos títulos de columna lo pone

           .ga-tc thead .ga-tc__nuestra,
           .ga-tc thead .ga-tc__otros { color: var(--ga-naranja-apagado); }

       en la línea 1471 de este archivo, con especificidad 0-2-1. La regla de aquí
       abajo suma 0-4-1, así que gana sin necesidad de !important.

       ⚠ SOLO EL TÍTULO DE LA COLUMNA. Las marcas de "no siempre" y los textos de
         esa columna siguen exactamente igual: esta regla vive dentro del <thead> y
         no alcanza al cuerpo de la tabla.

       ⚠ "GRAN ALMAZARA" NO SE TOCA. Su título va aparte porque el selector solo
         nombra a .ga-tc__otros; el de la columna verde conserva su color.

       ⚠ ESCRITORIO INTACTO, POR PARTIDA DOBLE: esto está dentro del media query Y
         acotado a .ga-tc--mov, que es la tabla que solo existe en móvil.

       ⚠ EVENTOS FUERA: el :not() lo deja fuera explícitamente. Además su ficha ni
         siquiera pinta la tabla comparativa, así que es un cinturón sobre otro.

       ⚠ --ga-negro-suave NO ESTÁ DECLARADA en el :root (🪤 nº 15 del claude.md), y
         un var() que no resuelve haría que el texto HEREDARA el color del ancestro
         —que aquí es justo el dorado que se quiere quitar—. De ahí el respaldo. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-tc--mov thead .ga-tc__otros {
        color: var(--ga-negro-suave, #1a1a14);
    }
}


/* =============================================================================
   "DESLIZA PARA VER MÁS" · LA INDICACIÓN BAJO EL CARRUSEL DE LAS TRES FOTOS
   =============================================================================
   El nodo .ga-cosecha__desliza lo CREA el JS al montar el carrusel y lo BORRA al
   desmontarlo, así que estas reglas solo tienen a quién aplicarse en móvil. El
   media query es, aun así, un cinturón sobre otro: si algún día alguien escribiera
   el aviso en la plantilla, en escritorio seguiría sin verse.

   ⚠ EL VAIVÉN MUEVE LA FLECHA Y NADA MÁS. La animación va sobre el <span> de la
     flecha, no sobre el párrafo: así el hueco del aviso no cambia y las tarjetas
     del carrusel no se enteran de nada.

   ⚠ NO PUEDE DESBORDAR. El párrafo es un flex centrado que ocupa el ancho de su
     sección —que ya tiene sus márgenes—, y la flecha se desplaza 6px DENTRO de él,
     con espacio de sobra a los lados incluso a 360px. Ninguna fila crece.
   ============================================================================= */
@media (max-width: 860px) {

    .ga-product-single:not(.ga-product-single--eventos) .ga-cosecha__desliza {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 0.45rem;

        margin: 0.9rem 0 0;
        padding: 0;

        /* El dorado de marca, que es el color con el que esta web señala "por aquí".
           Con opacidad para que sugiera sin competir con las fotos. */
        color: var(--ga-naranja-apagado);
        opacity: 0.85;

        /* 🔴 EL DESVANECIDO NO QUITA EL HUECO: solo baja la opacidad. Si el aviso
           desapareciera del flujo, todo lo que hay debajo subiría de golpe justo
           después de que el usuario haya deslizado, o sea con el dedo aún en la
           pantalla. Se prefiere un espacio en blanco a un salto. */
        transition: opacity 0.5s ease;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-cosecha__desliza.is-oculto {
        opacity: 0;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-cosecha__desliza-texto {
        font-family: var(--ga-font-body);
        font-size: var(--ga-text-xs);
        font-weight: 500;
        letter-spacing: 0.02em;
        line-height: 1;

        /* El texto toma el color del párrafo en vez de repetirlo: un solo valor que
           mantener si mañana se cambia el tono. */
        color: currentColor;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-cosecha__desliza-flecha {
        display: inline-flex;
        animation: ga-cosecha-vaiven 1.6s ease-in-out infinite;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-cosecha__desliza-flecha svg {
        display: block;
        width: 18px;
        height: 18px;
    }

    /* Un vaivén corto y lento. 6px es suficiente para que el ojo lo capte de reojo y
       lo bastante poco para no convertirse en un parpadeo molesto al leer la ficha. */
    @keyframes ga-cosecha-vaiven {
        0%, 100% { transform: translateX(0); }
        50%      { transform: translateX(6px); }
    }

    /* Quien ha pedido menos movimiento no lo recibe: la flecha se queda quieta y
       sigue señalando a la derecha, que es lo que de verdad comunica el gesto. */
    @media (prefers-reduced-motion: reduce) {
        .ga-product-single:not(.ga-product-single--eventos) .ga-cosecha__desliza-flecha {
            animation: none;
        }
    }
}


/* =============================================================================
   LOS TRES SELLOS EN TIRA DESLIZABLE · MÓVIL
   =============================================================================
   La clase .is-carril la pone y la quita el JS al cruzar los 640px, así que estas
   reglas solo tienen a quién aplicarse en móvil. El media query es, aun así, un
   cinturón sobre otro.

   🔴 640px Y NO 860px, Y NO ES UN DESPISTE. Es el punto de corte que ESTA fila ya
   usaba para romperse: por encima, los tres sellos caben cómodos en sus tres
   columnas y convertirlos en tira sería empeorarlos. Se respeta el corte que la
   sección ya tenía en vez de inventarle uno nuevo.

   🔴 POR QUÉ AQUÍ SÍ VALE EL SCROLL NATIVO. La trampa nº 1 del claude.md prohíbe
   filas más anchas que el viewport porque INFLAN el viewport de maquetación. Eso
   ocurre cuando la fila desborda HACIA FUERA. Aquí el contenedor mide el 100% de su
   columna y las tarjetas se miden en PORCENTAJE DE ÉL: lo que desborda es el
   contenido dentro del contenedor, que es quien scrollea. Es el montaje que la
   trampa nº 12 da por bueno —el carrusel de sellos de Nosotros—, no el que la nº 1
   prohíbe. La diferencia está en QUIÉN desborda.

   ⚠ overflow-x SOLO AQUÍ, NUNCA EN html NI EN body. El cortafuegos de la raíz no se
     toca ni se necesita: este contenedor se basta.
   ============================================================================= */
@media (max-width: 640px) {

    .ga-product-single:not(.ga-product-single--eventos) .ga-product__valoraciones .ga-sellos-ficha.is-carril {

        /* De rejilla apilada a tira. El display gana a la regla de arriba por
           especificidad, no por orden: 0-4-0 contra 0-2-0. */
        display: flex;
        flex-wrap: nowrap;

        overflow-x: auto;
        overflow-y: hidden;

        /* Que el gesto no se encadene con la página cuando se llega al final de la
           tira: sin esto, en Android el navegador puede interpretarlo como un
           "atrás". Va EN EL CONTENEDOR, que es donde no puede bloquear nada —en el
           body sería la trampa nº 2. */
        overscroll-behavior-x: contain;

        /* El encuadre al soltar. `always` obliga a que cada gesto avance UN sello y
           no tres de golpe. */
        scroll-snap-type: x mandatory;

        /* 🔴 pan-x Y pan-y, LOS DOS. Aquí decía solo `pan-y pinch-zoom` y ESO ERA LO
           QUE IMPEDÍA DESLIZAR LA TIRA: touch-action no dice qué gestos se bloquean,
           dice cuáles se PERMITEN. Con `pan-y` el navegador entiende "de este
           elemento solo salen gestos verticales" y descarta el horizontal antes de
           que llegue al scroller. La fila estaba bien montada y desbordaba de verdad
           —por eso se veía el sello y medio, y por eso la barra medía bien—, pero el
           dedo no llegaba nunca a moverla.

           ⚠ EL VALOR VIENE DE COPIAR EL PATRÓN EQUIVOCADO. En los carruseles de la
             TIENDA el `pan-y` es correcto, y justo por lo contrario: allí el
             desplazamiento lo hace el JS con transform y el navegador NO debe
             scrollear en horizontal. Aquí el scroll es NATIVO, así que hay que
             dejarle pasar el gesto horizontal. Mismo aspecto, mecanismos opuestos.

           pan-y se mantiene para que arrastrar en diagonal siga pasándole el turno al
           scroll vertical de la página en vez de secuestrarlo, y pinch-zoom para no
           quitarle el zoom a nadie. */
        touch-action: pan-x pan-y pinch-zoom;

        /* La barra de scroll del sistema sobra: ya hay una propia y más legible. */
        scrollbar-width: none;

        gap: var(--ga-space-sm);
        margin-block-start: var(--ga-space-lg);
        margin-block-end: 0;
        padding-block: 0;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-sellos-ficha.is-carril::-webkit-scrollbar {
        display: none;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-sellos-ficha.is-carril .ga-sellos-ficha__item {

        /* 🔴 flex-basis EXPLÍCITO, NADA DE min-width. Es la regla del proyecto y
           además aquí min-width sería un suelo, no una medida: la tarjeta podría
           crecer y descuadrar el encuadre del snap.

           62% deja ver un sello entero y buena parte del siguiente, que es lo que le
           dice al ojo "esto se desliza" sin necesidad de ningún cartel. A 360px son
           unos 190px por sello: de sobra para el icono y sus dos líneas. */
        flex: 0 0 62%;
        max-width: 62%;

        scroll-snap-align: center;
        scroll-snap-stop: always;
    }

    /* ——— LA BARRA INDICADORA ———
       Un riel fino en el verde de marca muy diluido, con el tramo visible encima en
       dorado. La crea el JS y la borra al desmontar. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-sellos-ficha__barra {
        position: relative;
        overflow: hidden;

        /* 🔴 EL ANCHO SE LIMITA PARA QUE LA BARRA NO PAREZCA OTRA SECCIÓN. A todo lo
           ancho se leía como un separador; a 120px se lee como lo que es, un
           indicador. Centrada con margin auto. */
        width: 120px;
        max-width: 60%;
        height: 3px;

        margin: var(--ga-space-sm) auto 0;

        background-color: color-mix(in srgb, var(--ga-verde-oliva-oscuro) 18%, transparent);
        border-radius: var(--ga-radius-full);
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-sellos-ficha__tramo {

        /* Ocupa el riel entero y el JS lo encoge con scaleX: así el ancho real nunca
           cambia y la altura de la sección tampoco puede moverse. */
        display: block;
        width: 100%;
        height: 100%;

        background-color: var(--ga-naranja-apagado);
        border-radius: inherit;

        /* El origen a la izquierda es lo que hace que al encogerse se quede pegado al
           principio del riel en vez de recogerse hacia el centro. */
        transform-origin: left center;
        transform: translateX(0) scaleX(1);

        /* Un pelín de suavizado para que el tramo no dé tirones entre fotograma y
           fotograma. Corto a propósito: si fuera largo, la barra iría por detrás del
           dedo y dejaría de indicar dónde estás. */
        transition: transform 0.12s linear;

        will-change: transform;
    }

    /* Quien ha pedido menos movimiento sigue teniendo la barra —es información, no
       adorno—, pero sin el suavizado: salta de posición en vez de deslizarse. */
    @media (prefers-reduced-motion: reduce) {
        .ga-product-single:not(.ga-product-single--eventos) .ga-sellos-ficha__tramo {
            transition: none;
        }
    }
}


/* =============================================================================
   "COMPRAR AHORA" · BRILLO SUAVE EN MÓVIL
   =============================================================================
   🔴 EL MECANISMO ES EL QUE YA USA EL PROYECTO, NO UNO NUEVO: un linear-gradient
   con la banda de luz en el medio, el fondo estirado al 250 % de ancho y la
   animación moviendo SOLO background-position. Es exactamente lo que hacen el
   botón de carrito de las tarjetas, los títulos de sección y las esquinas de las
   dos tablas comparativas.

   Se reutilizan sus mismos @keyframes ga-home-card-brillo, declarados en main.css.
   Las @keyframes son GLOBALES DEL DOCUMENTO —no pertenecen a la hoja donde se
   escriben—, así que se pueden usar desde aquí; y main.css siempre está cargada en
   la ficha, porque single-product.css depende de ella. No hay que redeclararlas.

   ⚠ NADA DE ESTO TOCA LA GEOMETRÍA. Las propiedades de fondo no ocupan sitio ni
     provocan recálculo de maquetación: el botón mide, pesa y se coloca igual con
     brillo que sin él. Tampoco hay hover ni foco nuevos, así que ningún estado
     puede mover nada.

   ⚠ ALCANCE. El :not() deja fuera a eventos, y además "Comprar ahora" NO SE PINTA
     en sus fichas: ese botón añade al carrito por GET y no mandaría los campos de
     personalización, así que la plantilla no lo imprime. Es un cinturón sobre otro.
   ============================================================================= */
@media (max-width: 860px) {

    .ga-product-single:not(.ga-product-single--eventos) .ga-product__btn-buy-now {

        /* 🔴 LA REFERENCIA ES main.css, LÍNEAS 10272-10283: el brillo de
           .ga-tienda-novedad__btn.ga-btn--primary, que es EL MISMO TIPO DE BOTÓN que
           este —dorado de marca con letra blanca— y por tanto la comparación
           correcta. Allí: linear-gradient a 100deg, banda del 45 % al 55 %, fondo al
           250 % de ancho, background-position de partida en 100% center y los
           @keyframes ga-home-card-brillo. Aquí se copian los cinco.

           🔴 LA BANDA ES BLANCA Y TRANSLÚCIDA, Y EL DEGRADADO NO PINTA EL DORADO.
           Esta es la diferencia con las dos versiones anteriores, y es lo que hace
           que sea de verdad un reflejo:

             · los tramos que no son la banda son TRANSPARENTES, no dorados. El
               dorado lo pone el background-color del propio botón y se ve A TRAVÉS.
               Así el degradado solo puede AÑADIR luz; le es imposible oscurecer nada
               ni desviar el tono, que es lo que hacían los flancos oscuros de antes.

             · la banda es blanco de marca rebajado con color-mix hasta un 16 %: un
               velo, no una franja. Y con dos paradas intermedias al 8 % para que los
               bordes se difuminen en vez de cortar.

           ⚠ EL DEGRADADO NECESITA QUE EL background-color ESTÉ PUESTO, porque ahora
             es él quien pinta el dorado. Lo declara .ga-btn--primary, pero se repite
             abajo a propósito: si el color viviera solo en otra hoja, un cambio allí
             dejaría este botón transparente y no se entendería por qué.

           MÁS SUTIL Y ADEMÁS MÁS LEGIBLE. Al no oscurecer los flancos, el texto
           blanco se lee igual que en reposo (2,28:1) en todo el botón salvo bajo la
           línea, donde baja a 1,98:1 un instante. Las versiones anteriores llegaban
           a 1,80:1 y a 1,63:1 en ese punto.

           👉 Nota aparte, y NO es cosa de este cambio: blanco sobre dorado son 2,28:1
              de partida, que ya es bajo. Es el estilo del botón en toda la web y
              cambiarlo sería otra tarea. */
        background-color: var(--ga-naranja-apagado);

        background-image: linear-gradient(
            100deg,
            transparent 0%,
            transparent 46%,
            color-mix(in srgb, var(--ga-blanco) 8%, transparent) 49%,
            color-mix(in srgb, var(--ga-blanco) 16%, transparent) 50%,
            color-mix(in srgb, var(--ga-blanco) 8%, transparent) 51%,
            transparent 54%,
            transparent 100%
        );

        background-size: 250% 100%;
        background-repeat: no-repeat;

        /* La posición de partida, como en la referencia: el barrido empieza fuera,
           por la derecha, y entra. Sin esto la primera pasada arrancaría a medias. */
        background-position: 100% center;

        /* 8s, EXACTAMENTE EL RITMO DE LA REFERENCIA. Estos @keyframes barren en la
           primera mitad y descansan en la segunda, así que son cuatro segundos de
           recorrido y otros cuatro de reposo. Se dejan los 14s de la versión
           anterior a propósito: lo que se pedía es que el botón se comporte como el
           resto de la web, y el resto de la web va a 8. */
        animation: ga-home-card-brillo 8s linear infinite;

        /* 🔴 EL TEXTO, BLANCO, DECLARADO AQUÍ TAMBIÉN. En reposo ya lo era por
           .ga-btn--primary; se repite para que las tres reglas de estado de aquí
           abajo tengan de dónde partir y para que el color del botón no dependa de
           una hoja distinta. */
        color: var(--ga-blanco);
    }

    /* ═══════════════════════════════════════════════════════════════════════
       EL TEXTO DORADO: DE DÓNDE VENÍA Y POR QUÉ SE ARREGLA AQUÍ
       ═══════════════════════════════════════════════════════════════════════
       🔴 NO ERA EL BRILLO. Este botón nunca ha llevado background-clip: text ni
       ningún degradado sobre las letras: el reflejo va sobre el FONDO y siempre fue
       así. La culpa es de otra regla, en main.css, líneas 19630-19635:

           .ga-product-single .ga-product__btn-buy-now:hover,
           .ga-product-single .ga-product__btn-buy-now:focus-visible,
           .ga-product-single .ga-product__btn-buy-now:active {
               background-color: var(--ga-blanco);
               border-color: var(--ga-naranja-apagado);
               color: var(--ga-naranja-apagado);      ← EL TEXTO DORADO
           }

       Es la inversión de hover pensada para ESCRITORIO: fondo blanco, letras
       doradas. En un ratón se ve un instante y se entiende. En una pantalla táctil
       no hay "salir del hover": el :active salta en cada toque y el :hover SE QUEDA
       PEGADO después de tocar, hasta que se toca en otro sitio. De ahí el "a veces
       se ve dorado", que en realidad era "cada vez que lo tocas y después".

       Y con el brillo puesto quedaba aún peor: la inversión cuenta con que el fondo
       se vuelva blanco, pero un background-IMAGE tapa al background-COLOR, así que
       el fondo seguía dorado y solo cambiaba el texto. Letras doradas sobre dorado.

       ✅ ARREGLO: en móvil, los tres estados se quedan con el mismo aspecto que el
       botón en reposo. No hay inversión que valga en una pantalla donde el hover no
       se puede abandonar.

       ⚠ SIN !important. Estos selectores suman 0-4-0 —dos clases, el :not() y la
         pseudoclase de estado— frente a los 0-3-0 de main.css, así que ganan por
         especificidad. No dependen del orden de carga de las hojas, que es justo lo
         que no se puede dar por bueno aquí: main.css se carga ANTES.

       ⚠ NI TAMAÑO NI POSICIÓN: solo se devuelven tres colores a lo que ya eran. El
         borde conserva su grosor de 2px en los tres estados, así que el botón no
         crece ni empuja a su vecino.

       ⚠ ESCRITORIO INTACTO: todo esto vive dentro del media query. Con ratón, la
         inversión de main.css sigue funcionando exactamente igual. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__btn-buy-now:hover,
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__btn-buy-now:focus-visible,
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__btn-buy-now:active {
        background-color: var(--ga-naranja-apagado);
        border-color: var(--ga-naranja-apagado);
        color: var(--ga-blanco);
    }

    /* 🔴 APAGADO NO BRILLA. En los productos VARIABLES —la camiseta, el pack de tres
       tarros— este botón nace con `disabled` hasta que el cliente elige su variación,
       y el estado apagado es solo un opacity: 0.45: el brillo seguiría corriendo por
       debajo, atenuado pero visible. Un botón que destella mientras no se puede
       pulsar invita justo al clic que no va a hacer nada.

       El :disabled suma una pseudoclase, así que gana a la regla de arriba por
       especificidad (0-4-0 contra 0-3-0) y no hace falta !important. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-product__btn-buy-now:disabled {
        background-image: none;
        animation: none;
    }

    /* Ahorro de movimiento: sin degradado y sin animación. Al quitar la imagen de
       fondo reaparece el background-color de .ga-btn--primary, que es el mismo
       dorado de marca: el botón se queda exactamente como está hoy.

       Sin !important y sin más especificidad: esta regla va DESPUÉS de la de arriba
       y pesa igual, así que gana por orden. */
    @media (prefers-reduced-motion: reduce) {
        .ga-product-single:not(.ga-product-single--eventos) .ga-product__btn-buy-now {
            background-image: none;
            animation: none;
        }
    }
}


/* =============================================================================
   "TAMBIÉN TE PUEDE INTERESAR" · EL BOTÓN DICE SOLO "VER" EN MÓVIL
   =============================================================================
   En pantallas estrechas la tarjeta es tan justa que "Ver producto" se partía en
   dos líneas y descuadraba la altura del botón respecto a los de las tarjetas
   vecinas. En móvil se lee solo "Ver".

   🔴 SE ESCONDE A LA VISTA, PERO NO SE BORRA. Con display: none la palabra
   desaparecería también del árbol de accesibilidad, y en las fichas que NO son de
   eventos este botón no lleva aria-label: quien navegue con lector de pantalla
   oiría seis "Ver" seguidos sin saber a qué producto va cada uno. Con la técnica de
   ocultación visual el botón se VE como "Ver" y se OYE como "Ver producto", que es
   lo mejor de los dos.

   ⚠ NO PUEDE DESBORDAR. La palabra oculta mide 1px y va recortada con clip-path,
     sin desplazarse a ningún sitio: nada de left negativos, que sí pueden empujar
     el ancho. Y el position: absolute la saca del flujo, así que no aporta ni un
     píxel al ancho del botón.

   ⚠ EVENTOS FUERA: allí el botón sigue diciendo "Ver producto" en todos los anchos.
     Su carrusel comparte marcado con el del resto de la tienda —el prefijo
     .ga-eventos-rel- es histórico y hoy sirve a TODA la tienda—, así que el :not()
     no es decorativo: es lo único que separa un caso del otro.
   ============================================================================= */
@media (max-width: 860px) {

    .ga-product-single:not(.ga-product-single--eventos) .ga-eventos-rel__btn-larga {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
    }
}


/* =============================================================================
   GUÍA DE VARIEDADES · CUATRO COLUMNAS EN MÓVIL (SIN "MOMENTO IDEAL")
   =============================================================================
   🔴 600px, QUE ES EL PUNTO DE CORTE QUE ESTA TABLA YA USABA. Su bloque de ajustes
   de móvil —relleno, tamaño de letra, anchos, tamaño de los puntos— vive en un
   @media (max-width: 600px) desde que se hizo. Se respeta ese corte en vez de
   inventarle uno nuevo: por encima, con cinco columnas, la tabla entra bien.

   🔴 SE OCULTA CON CSS, SIN TOCAR LA PLANTILLA. La última columna se puede alcanzar
   sin clase propia —el <th> de "Momento ideal" no la tiene— porque es la última de
   su fila: :last-child en la cabecera y .ga-tcv__fin en el cuerpo. En escritorio no
   cambia ni un carácter del HTML, así que sus cinco columnas siguen intactas.

   ⚠ HAY QUE APAGAR TAMBIÉN SU <col>, Y ESTE ES EL DETALLE QUE SE ESCAPA. La tabla va
     en table-layout: fixed y el <colgroup> declara CINCO columnas: aunque no quede
     ninguna celda en la quinta, el navegador le sigue reservando su ancho y la tabla
     quedaría con una franja vacía a la derecha. Por eso el último <col> se pone a 0
     y los cuatro anchos que quedan suman exactamente 100.
   ============================================================================= */
@media (max-width: 600px) {

    /* ——— FUERA LA QUINTA COLUMNA ——— */
    .ga-product-single:not(.ga-product-single--eventos) .ga-tcv thead th:last-child,
    .ga-product-single:not(.ga-product-single--eventos) .ga-tcv tbody td.ga-tcv__fin {
        display: none;
    }

    /* ——— EL REPARTO, AHORA A CUATRO ———
       El nombre sube de 24 % a 34 %: es texto de varias palabras y con una columna
       menos por fin cabe sin partirse a lo tonto. Los tres datos suben de 19 % a
       22 % cada uno, que es lo que hace que "Intensidad" entre en una sola línea.
       34 + 22 + 22 + 22 = 100 exacto: la tabla no puede desbordar ni dejar hueco. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-tcv__col-nombre { width: 34%; }
    .ga-product-single:not(.ga-product-single--eventos) .ga-tcv__col-dato   { width: 22%; }

    /* El <col> sobrante, a cero. Sin esto la tabla reservaría su ancho igualmente. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-tcv colgroup .ga-tcv__col-dato:last-child {
        width: 0;
    }

    /* ——— CENTRADO Y CUADRE ———
       Todo al centro en horizontal y en vertical. El vertical-align: middle es lo que
       alinea entre sí los puntitos de Intensidad y Picante fila a fila, aunque una
       celda vecina tenga dos líneas de texto. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-tcv th,
    .ga-product-single:not(.ga-product-single--eventos) .ga-tcv td {
        text-align: center;
        vertical-align: middle;
    }

    /* El nombre de la variedad, centrado y con el relleno igual por los dos lados: si
       conservara el sangrado izquierdo de escritorio, "centrado" quedaría corrido
       hacia la derecha. overflow-wrap para que un nombre largo parta por donde deba
       en vez de empujar la columna —nada de min-width, como manda el proyecto—. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-tcv th.ga-tcv__nombre {
        text-align: center;
        padding-inline: var(--ga-tcv-relleno-x);
        overflow-wrap: break-word;
    }

    /* Los puntos, centrados en su celda. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-tcv__puntos {
        justify-content: center;
    }

    /* "Intensidad" es el rótulo más largo de los tres que quedan. Con el 22 % de
       ancho entra en una línea; el nowrap lo garantiza y el clamp le da el margen de
       maniobra para encoger lo justo en las pantallas más estrechas en vez de
       partirse. Los otros dos —"Picante" y "Hueso"— caben de sobra. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-tc.ga-tcv thead th {
        white-space: nowrap;
        font-size: clamp(0.58rem, 2.3vw, var(--ga-text-sm));
    }

    /* ⚠ LA ESQUINA SE QUEDA FUERA DEL nowrap. "Gran Almazara" son dos palabras y en
       su columna necesita poder partirse; con nowrap se saldría de su celda. Es la
       única cabecera que envuelve, y a propósito. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-tc.ga-tcv thead th.ga-tcv__esquina {
        white-space: normal;
    }

    /* ——— EL SALIENTE DE LA FILA DESTACADA, A SU NUEVA ÚLTIMA CELDA ———
       🔴 SIN ESTO SE PERDERÍA. El saliente derecho de la fila verde cuelga de
       td.ga-tcv__fin::after, y esa celda es justo la que se acaba de ocultar: al
       desaparecer se lleva su pseudoelemento y la fila destacada quedaría con
       saliente a la izquierda y nada a la derecha. Se vuelve a declarar sobre la
       cuarta celda, que es la que ahora cierra la fila.

       Los valores son los mismos que los de la regla original —incluido el bottom
       de -1px, que compensa el píxel de la línea separadora—: si allí se cambian,
       hay que cambiarlos aquí. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-tcv tbody tr.is-destacada td:nth-child(4) {
        position: relative;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-tcv tbody tr.is-destacada td:nth-child(4)::after {
        content: '';
        position: absolute;
        top: 0;
        bottom: -1px;
        right: calc(-1 * var(--ga-tcv-saliente));
        width: var(--ga-tcv-saliente);
        background-color: var(--ga-verde-oliva-oscuro);
        border-radius: 0 8px 8px 0;
    }
}


/* =============================================================================
   GUÍA DE VARIEDADES · LAS TRES COLUMNAS DE DATOS, EXACTAMENTE IGUALES (MÓVIL)
   =============================================================================
   🔴 EL REPARTO SE DECLARA DOS VECES A PROPÓSITO, Y ESE ES TODO EL ARREGLO. Los
   anchos ya estaban puestos en el <colgroup>, pero en una tabla con
   table-layout: fixed hay DOS sitios de los que el navegador puede sacar el reparto
   de columnas: los <col> y las celdas de la PRIMERA FILA. Cuál de los dos gana
   depende de si el otro está en `auto`, y aquí conviven la regla base
   (.ga-tcv__col-dato { width: auto }) con la de móvil: basta con que una de las dos
   fuentes se lea en un orden distinto para que las columnas salgan desiguales.

   La forma de no depender de eso es no dejar ninguna de las dos en `auto`: se
   escriben LOS MISMOS NÚMEROS en el <col> y en la celda de cabecera que le
   corresponde. Gane quien gane, el resultado es idéntico, y las tres columnas de
   datos miden lo mismo con total seguridad.

   34 % + 22 % + 22 % + 22 % = 100 exacto. La primera columna se queda con el resto,
   que es lo que se pedía: no tiene por qué medir lo mismo que las otras.

   ⚠ NADA DE min-width, como manda el proyecto: son porcentajes puros y el corte de
     palabra lo hace overflow-wrap. Y como suman 100 sobre una tabla en fixed, no hay
     manera de que el contenido la ensanche ni de que la página desborde.
   ============================================================================= */
@media (max-width: 600px) {

    /* La segunda fuente del reparto: la primera fila. Se cuenta por posición porque
       estas cabeceras no tienen clase propia —solo la esquina la tiene—, y la quinta
       ni se nombra: ya está oculta y su <col> puesto a 0. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-tc.ga-tcv thead th:nth-child(1) {
        width: 34%;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-tc.ga-tcv thead th:nth-child(2),
    .ga-product-single:not(.ga-product-single--eventos) .ga-tc.ga-tcv thead th:nth-child(3),
    .ga-product-single:not(.ga-product-single--eventos) .ga-tc.ga-tcv thead th:nth-child(4) {
        width: 22%;
    }

    /* Y el relleno horizontal, IGUAL EN LAS TRES. Si una llevara un relleno distinto,
       las columnas medirían lo mismo pero el contenido no quedaría centrado en la
       misma posición, y a simple vista se leería como si fueran desiguales. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-tcv thead th:nth-child(n+2),
    .ga-product-single:not(.ga-product-single--eventos) .ga-tcv tbody td {
        padding-inline: var(--ga-tcv-relleno-x);
        text-align: center;
    }
}


/* =============================================================================
   "LOS DEMÁS ALIÑOS" · EL BOTÓN DE CARRITO, DEBAJO DEL NOMBRE EN MÓVIL
   =============================================================================
   El botón se pinta dos veces —.ga-alinos__cart--esc dentro de la capa oscura de la
   foto y .ga-alinos__cart--mov detrás del nombre— y aquí se decide cuál se ve. El
   porqué de las dos copias está en la plantilla, junto al cierre que las genera.

   ⚠ SE OCULTA CON display: none Y NO CON opacidad ni visibilidad: es la única forma
     de que la copia que no toca salga TAMBIÉN del recorrido del tabulador y del
     árbol de accesibilidad. Con un enlace escondido a medias, el teclado seguiría
     parando en él y el lector de pantalla anunciaría dos veces el mismo botón.
   ============================================================================= */

/* ESCRITORIO: solo la de siempre. La de móvil ni existe, así que el bloque se
   comporta exactamente como hasta hoy —capa oscura y círculo sobre la foto al pasar
   el ratón— sin una sola regla nueva que lo toque. */
/* Este bloque ya NO decide visibilidad: lo hacen las cuatro reglas del final del
   archivo, todas juntas. Se deja el comentario para que quede constancia de dónde
   se decide ahora. */

@media (max-width: 860px) {

    /* MÓVIL: se cambian las tornas. En una pantalla táctil no hay hover, así que un
       botón encima de la imagen se toca sin querer y además tapa el producto. */
    /* La celda apila foto → nombre → botón. Es el orden natural del marcado, así que
       no hace falta ni un `order`: basta con que la caja sea una columna y con
       centrar lo que va dentro. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-eventos-combina__celda {
        display: flex;
        flex-direction: column;
        align-items: center;
    }

    .ga-product-single:not(.ga-product-single--eventos) .ga-alinos__cart--mov {

        /* 🔴 44px DE LADO, QUE NO ES UN NÚMERO CUALQUIERA: es el mínimo que las guías
           de accesibilidad dan por cómodo para un dedo. Por debajo de eso el botón
           se ve pero se falla al pulsarlo.

           El `display` NO se declara aquí: lo ponen las cuatro reglas de visibilidad
           del final del archivo. Aquí solo el tamaño y el aspecto. */
        width: 44px;
        height: 44px;

        margin-top: 0.55rem;

        /* El mismo círculo dorado que ya existe sobre la foto: no se estrena nada. */
        background-color: var(--ga-naranja-apagado);
        color: var(--ga-blanco);
        border-radius: var(--ga-radius-full);

        /* ⚠ NI EL HOVER NI EL FOCO PUEDEN MOVERLO. La copia de escritorio se apoya en
           transformaciones que la capa oscura le da al aparecer; aquí no hay nada de
           eso, y no debe haberlo: el botón está siempre a la vista y cualquier cambio
           de tamaño movería el resto de la tarjeta. Solo colores. */
        transform: none;
        opacity: 1;
    }

    /* El icono, al tamaño del círculo. El del tick verde de confirmación lo gobiernan
       las reglas de .ga-home-card__cart, que son las mismas para las dos copias: por
       eso el aviso de "añadido" funciona igual sin escribir nada aquí. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-alinos__cart--mov svg {
        width: 22px;
        height: 22px;
    }
}


/* =============================================================================
   "LOS DEMÁS ALIÑOS" · ICONO CENTRADO Y BOTONES ALINEADOS
   ============================================================================= */

/* ═══════════════════════════════════════════════════════════════════════════
   1 · EL ICONO DESCENTRADO: ERA UN CHOQUE ENTRE GRID Y FLEX
   ═══════════════════════════════════════════════════════════════════════════
   🔴 NO ESTABA MAL COLOCADO: ESTABAN LOS DOS ICONOS EN FILA. El círculo hereda
   `display: inline-flex` de .ga-home-card__cart (main.css), pero sus dos hijos —el
   carrito y el tique de confirmación— se apilan con `grid-area: 1 / 1`, que en un
   contenedor FLEX no significa nada: se descarta y los dos iconos se colocan uno al
   lado del otro.

   El tique va con opacity: 0, o sea INVISIBLE PERO OCUPANDO SU SITIO. Resultado: el
   carrito, que es el que se ve, quedaba empujado hacia la izquierda justo la mitad
   del ancho del otro. Parecía un problema de centrado y era de tipo de contenedor.

   ✅ El círculo pasa a `display: grid` con `place-items: center`. Con eso el
   grid-area de los hijos vuelve a valer: los dos caen en la MISMA celda, apilados y
   centrados en los dos ejes, y el visible queda en el centro exacto del círculo.

   ⚠ ESTRUCTURAL, SIN NI UNA COORDENADA A MANO: ni top, ni left, ni translate. Y no
     hace falta ningún ajuste óptico: la desviación no era visual —el dibujo del
     carrito está bien equilibrado en su lienzo—, era el hueco del segundo icono. Al
     desaparecer ese hueco, el centrado real y el percibido coinciden.

   ⚠ EL FUNDIDO NO SE TOCA: los dos iconos siguen existiendo siempre y cruzándose por
     opacidad, que es lo que permite animar la confirmación. Solo cambia dónde caen.

   ⚠ EN LOS DOS ANCHOS, como se pidió: esta regla va fuera de todo media query.

   🔴 Y AQUÍ YA NO SE DECLARA `display`, QUE ES LA RAÍZ DE TODO EL LÍO DE LAS DOS
   ÚLTIMAS TANDAS. Esta regla llevaba `display: grid` y puntúa 0-4-0, más que las
   reglas que decidían cuál de las dos copias del botón se ve. Resultado: pisaba sus
   `display: none` y las sacaba a las dos a la vez, una vez en móvil y otra en
   escritorio. Se parcheó subiendo la especificidad de las de ocultar, y eso arregla
   el síntoma pero deja la trampa puesta para la próxima.

   El arreglo de verdad es que HAYA UN SOLO SITIO QUE DECIDA `display`: las reglas de
   visibilidad de más abajo, una por copia y por ancho. Aquí se queda únicamente el
   `place-items`, que es lo que centra el icono y no compite con nadie —una propiedad
   de rejilla es inofensiva mientras el elemento no sea rejilla, y lo será en cuanto
   su regla de visibilidad le dé el `display: grid`—.

   Así ya no hay forma de que centrar el icono vuelva a sacar un botón de más. */
.ga-product-single:not(.ga-product-single--eventos) .ga-eventos-combina--alinos .ga-alinos__cart {
    place-items: center;
}

@media (max-width: 860px) {

    /* La copia de móvil nacía con inline-flex en el bloque anterior: se corrige por
       el mismo motivo, y con el mismo mecanismo. */
    /* El centrado ya lo da la regla común de .ga-alinos__cart; el display, las cuatro
       del final. Aquí no queda nada que declarar. */

    /* ═══════════════════════════════════════════════════════════════════════
       2 · LOS BOTONES, TODOS A LA MISMA ALTURA
       ═══════════════════════════════════════════════════════════════════════
       🔴 ANCLADO ABAJO, NO CON UNA ALTURA FIJA PARA EL NOMBRE. Se puede resolver de
       las dos formas, y esta es más limpia: reservarle al nombre la altura del más
       largo obliga a mantener un número a mano que hay que revisar cada vez que
       entra una variedad nueva o cambia el tamaño de letra. Con el botón anclado al
       fondo, la rejilla se ajusta sola pase lo que pase.

       Cómo funciona, que son dos piezas y hacen falta las dos:

         · las celdas de una rejilla se ESTIRAN a la altura de la más alta de su
           fila, así que todas miden ya lo mismo sin pedirlo;
         · `margin-top: auto` en el botón se come todo el espacio sobrante de su
           columna y lo empuja al fondo de la celda.

       Con las dos, el botón cae a la misma altura tanto si el nombre ocupa una línea
       como si ocupa tres. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-alinos__cart--mov {
        margin-top: auto;
    }

    /* ⚠ AQUÍ HABÍA UN margin-bottom PARA SEPARAR EL NOMBRE DEL BOTÓN, Y SE HA IDO CON
       ÉL. Sin botón debajo, ese hueco no separaba nada: solo dejaba las tarjetas más
       altas de lo necesario y la rejilla desahogada sin motivo. */

    /* ═══════════════════════════════════════════════════════════════════════
       3 · QUE NO QUEDE DESPAREJO
       ═══════════════════════════════════════════════════════════════════════
       La foto ocupa el ancho entero de su tarjeta y es cuadrada, así que las ocho se
       escalan igual pase lo que pase con el nombre. Sin min-width: el 100 % se mide
       sobre la celda, que es quien manda. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-eventos-combina--alinos .ga-eventos-combina__foto {
        width: 100%;
    }

    /* El nombre, centrado y partiendo por donde deba en vez de empujar la columna. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-eventos-combina--alinos .ga-alinos__enlace {
        text-align: center;
        overflow-wrap: break-word;
    }
}


/* =============================================================================
   "LOS DEMÁS ALIÑOS" · UNA SOLA COPIA DEL BOTÓN VISIBLE, Y NUNCA LAS DOS
   =============================================================================
   🔴 POR QUÉ VOLVIÓ A SALIR EL BOTÓN SOBRE LA FOTO. No es que se destapara: es que
   el `display: none` que lo escondía dejó de ganar. La regla que centra el icono

       .ga-product-single:not(…) .ga-eventos-combina--alinos .ga-alinos__cart
           { display: grid; place-items: center; }                      → 0-4-0

   nombra el botón con CUATRO clases, mientras que las dos que lo ocultaban tenían

       .ga-alinos__cart--mov                                            → 0-1-0
       .ga-product-single:not(…) .ga-alinos__cart--esc                  → 0-3-0

   Al declarar un `display` con más peso, el de la regla de centrado se impuso sobre
   los dos: `grid` gana a `none` y las DOS copias pasaron a verse a la vez. En móvil
   se notó porque reapareció el círculo sobre la foto; en escritorio estaba pasando
   lo mismo al revés, con el botón de debajo del nombre asomando donde no debía.

   ✅ Las dos reglas de ocultar suben a 0-5-0 —añadiendo la clase del bloque y
   encadenando la del modificador con la base— y vuelven a mandar sobre la de
   centrado, que no se toca porque el centrado sigue siendo correcto.

   ⚠ display: none Y NO opacidad ni visibilidad, que es lo que pedía el encargo: así
     la copia que sobra no se ve, NO SE PUEDE PULSAR, no ocupa sitio y sale también
     del recorrido del tabulador y del árbol de accesibilidad. Tapado no vale.

   ⚠ EL CENTRADO DEL ICONO SIGUE INTACTO en la copia que sí se ve: `display: none`
     solo la retira; en cuanto una es la visible, le vuelve a aplicar el `grid` con
     `place-items: center` de su regla, que es la misma para las dos.
   ============================================================================= */

/* ═══════════════════════════════════════════════════════════════════════════
   LAS CUATRO REGLAS QUE DECIDEN QUÉ SE VE. NO HAY NINGUNA OTRA.
   ═══════════════════════════════════════════════════════════════════════════
   Dos copias × dos anchos = cuatro casos, y los cuatro están escritos aquí, con la
   MISMA especificidad (0-5-0) para que entre ellos mande solo el media query y no
   haya que ir contando clases. Ninguna otra regla del archivo declara `display`
   sobre este botón: es la única forma de que no vuelva a pasar lo de las dos últimas
   tandas, donde una regla de centrado destapaba la copia que tocaba estar escondida.

   ESCRITORIO → círculo sobre la foto (aparece con la capa oscura al pasar el ratón),
                y NADA debajo del nombre.
   MÓVIL      → NINGÚN BOTÓN. Ni sobre la foto ni debajo del nombre: la tarjeta se
                queda con la foto y el nombre, y se compra entrando en la ficha de la
                variedad, que es a donde llevan los dos.

   🔴 EN MÓVIL SE ESCONDEN LAS DOS COPIAS, Y ESO ESTÁ BIEN AUNQUE PAREZCA DESPERDICIO.
   El botón se sigue imprimiendo dos veces en el HTML porque en escritorio hace falta
   una de ellas, y la plantilla no distingue anchos: quien decide es esta hoja. Lo que
   NO se hace es dejar una a medio esconder para "aprovecharla": las dos con
   display: none es lo único que garantiza que en una pantalla táctil no haya nada
   que se pueda tocar sin querer.

   ⚠ `display: none` Y NO opacidad ni visibilidad: la copia que sobra no se ve, no
     ocupa espacio, no se puede pulsar y sale del recorrido del tabulador y del árbol
     de accesibilidad. No queda ni rastro, que es lo que se pedía. */

/* ESCRITORIO */
.ga-product-single:not(.ga-product-single--eventos) .ga-eventos-combina--alinos .ga-alinos__cart.ga-alinos__cart--esc {
    display: grid;
}

.ga-product-single:not(.ga-product-single--eventos) .ga-eventos-combina--alinos .ga-alinos__cart.ga-alinos__cart--mov {
    display: none;
}

@media (max-width: 860px) {

    /* MÓVIL: LAS DOS FUERA. La tarjeta se queda con la foto y el nombre, y los dos
       siguen enlazando a la ficha de la variedad, así que se puede comprar desde su
       propia página igual que antes. */
    .ga-product-single:not(.ga-product-single--eventos) .ga-eventos-combina--alinos .ga-alinos__cart.ga-alinos__cart--esc,
    .ga-product-single:not(.ga-product-single--eventos) .ga-eventos-combina--alinos .ga-alinos__cart.ga-alinos__cart--mov {
        display: none;
    }
}


/* =============================================================================
   PREGUNTAS FRECUENTES · MÁS AIRE ENTRE LAS DOS LÍNEAS DE UNA PREGUNTA
   =============================================================================
   El título de cada pregunta no declaraba `line-height` en ninguna de sus dos reglas
   —ni .ga-accordion__trigger (línea 997) ni .ga-faq__item .ga-accordion__trigger
   (línea 2946)—, así que heredaba el del cuerpo. En escritorio no se nota porque casi
   ninguna pregunta llega a partirse; en una pantalla de 360px se parten casi todas, y
   ahí las dos líneas se leen pegadas.

   🔴 VA SOBRE EL <span> DEL TEXTO Y NO SOBRE EL <button>, y esa es la diferencia
   entre tocar solo el interlineado y tocar la maquetación. El botón es un flex que
   reparte el texto y el chevron con `align-items: center`: cambiarle a él la altura
   de línea le cambia la altura de la caja y con ella la posición vertical del
   chevron. En el span, el chevron ni se entera.

   🔴 UN SOLO SITIO PARA LOS SEIS JUEGOS. Los de aceite, aceituna, packs, mermelada,
   camiseta y apadrina comparten componente —todos son .ga-faq__item—, así que esta
   regla los alcanza a los seis sin enumerarlos y sin que ninguno pueda quedarse
   descolgado si mañana entra un juego nuevo.

   ⚠ SOLO EL INTERLINEADO: ni tamaño de letra, ni color, ni peso, ni nada del
     desplegable. Una sola propiedad.

   ⚠ 1.5 ES DELIBERADAMENTE CORTO. Con dos líneas se separan lo justo para leerse de
     un vistazo; y en las preguntas de UNA sola línea el cambio son unos tres píxeles
     de alto de caja, que al lado del relleno de 1,25rem del botón no se percibe. Por
     eso no quedan desproporcionadas.

   ⚠ EVENTOS FUERA POR PARTIDA DOBLE: lleva su :not(), y además su FAQ ni siquiera usa
     este componente —es un <details>/<summary> con .ga-eventos-faq__pregunta—, así
     que esta regla no tiene allí a quién aplicarse. */
@media (max-width: 860px) {

    .ga-product-single:not(.ga-product-single--eventos) .ga-faq__item .ga-accordion__trigger > span {
        line-height: 1.5;
    }
}


/* =============================================================================
   EL ACEITUNERO · MINIATURAS VISIBLES Y DESCRIPCIÓN CORTA EN LA COLUMNA DE COMPRA
   =============================================================================
   Todo lo de aquí va acotado con .ga-product-single--sku-ga-acc-aceitunero, la clase
   que la plantilla pone en el <main> a partir del SKU. Ningún otro producto la lleva,
   así que ninguna de estas reglas puede alcanzarle: los aceites, los tarros, los
   packs, la mermelada, la camiseta y Apadrina siguen exactamente igual, incluidas sus
   miniaturas ocultas.
   ============================================================================= */

/* ═══════════════════════════════════════════════════════════════════════════
   1 · LAS MINIATURAS, VISIBLES SOLO AQUÍ
   ═══════════════════════════════════════════════════════════════════════════
   🔴 NO HAY QUE CREARLAS: YA ESTÁN EN EL MARCADO. La plantilla las pinta en toda la
   tienda desde siempre y lo que hace la hoja es esconderlas con un display: none, y
   esconderlas —no borrarlas— porque LAS FLECHAS FUNCIONAN PULSÁNDOLAS: son ellas las
   que guardan la URL de cada foto, su texto alternativo y cuál se está viendo.

   De ahí salen dos cosas gratis, y las dos se pedían:

     · flechas y miniaturas quedan SINCRONIZADAS solas. La flecha pulsa la miniatura
       que toca, y esa miniatura es la que cambia la foto y se marca como activa. No
       hay dos estados que mantener a la vez, hay uno: no ha hecho falta tocar el JS.

     · el cambio de foto NO da el pantallazo crema, porque es exactamente el mismo
       camino que ya usaban las flechas y que ya estaba resuelto.

   La regla que las oculta es .ga-product-single:not(…--eventos) .ga-product__gallery-thumbs
   → 0-3-0. Esta suma lo mismo pero va DESPUÉS, así que gana por orden; y conserva el
   :not() de eventos para no destaparlas allí por un descuido. */
.ga-product-single--sku-ga-acc-aceitunero:not(.ga-product-single--eventos) .ga-product__gallery-thumbs {
    display: flex;

    /* Centradas bajo la foto y con aire suficiente para no pegarse a ella. El
       flex-wrap ya lo trae la regla base: si las fotos no caben en una fila, saltan a
       la siguiente en vez de estirar la fila. Es lo que impide que a 360px la fila sea
       más ancha que el viewport. */
    justify-content: center;
    margin-top: var(--ga-space-sm);
}

/* ⚠ A 360px LA MINIATURA ENCOGE ANTES DE PARTIR LA FILA. Con 72px, cuatro miniaturas
     y sus huecos piden unos 318px: entran justo, pero sin margen para una quinta foto.
     A 56px caben cinco cómodas y siguen siendo un objetivo táctil holgado. El
     flex-shrink: 0 de la regla base se mantiene: lo que las adapta es este tamaño y el
     salto de línea, nunca un encogido que las deforme. */
@media (max-width: 400px) {
    .ga-product-single--sku-ga-acc-aceitunero .ga-gallery-thumb {
        width: 56px;
        height: 56px;
    }
}

/* ——— LA MARCA DE LA ACTIVA, EN DORADO ———
   La regla base marca la activa en verde oliva; aquí se pide el dorado de marca. Se
   cambia SOLO el color del borde: el grosor sigue siendo 2px en los tres estados
   —reposo transparente, hover y activa—, así que la miniatura mide siempre lo mismo y
   marcarla no puede mover a sus vecinas. */
.ga-product-single--sku-ga-acc-aceitunero .ga-gallery-thumb.is-active {
    border-color: var(--ga-naranja-apagado);
}

/* 🔴 Y SE LE QUITA EL DESPLAZAMIENTO AL HOVER. La regla base lleva un
   transform: translateY(-1px), que mueve la miniatura al pasar el ratón: eso incumple
   la regla del proyecto de que ningún estado cambie tamaño ni posición. Aquí el hover
   se queda solo con el color del borde.

   El transform se anula con `none` y no quitando la transición: si solo se quitara la
   transición, el salto seguiría ocurriendo, y de golpe. */
.ga-product-single--sku-ga-acc-aceitunero .ga-gallery-thumb:hover,
.ga-product-single--sku-ga-acc-aceitunero .ga-gallery-thumb:focus-visible {
    border-color: var(--ga-naranja-apagado);
    transform: none;
}

/* ═══════════════════════════════════════════════════════════════════════════
   2 · LA DESCRIPCIÓN CORTA, EN LA COLUMNA DE COMPRA
   ═══════════════════════════════════════════════════════════════════════════
   ⚠ EL MODIFICADOR NO TOCA NI LA TIPOGRAFÍA NI EL COLOR. Todo eso lo sigue poniendo
     .ga-product__short-desc, que es la clase que lleva el bloque en cualquier ficha.
     Aquí solo se ajusta la separación con sus dos vecinos —la línea de disponibilidad
     arriba y "Elige la cantidad" abajo— al mismo ritmo que usa el resto de la columna,
     que es --ga-space-sm. Ni recuadro, ni fondo, ni borde, ni icono.

   ⚠ overflow-wrap para que una palabra larga parta en vez de ensanchar la columna, que
     es la vía del proyecto en lugar de cualquier min-width. */
.ga-product-single--sku-ga-acc-aceitunero .ga-product__short-desc--compra {
    margin-top: var(--ga-space-sm);
    margin-bottom: var(--ga-space-sm);
    overflow-wrap: break-word;
}

/* En móvil la ficha se apila con display: contents y `order` (🪤 nº 13), y todo lo que
   no se enumera cae al final por el suelo de seguridad —order: 20—, que para este
   bloque sería el final de la ficha: hay que darle su sitio a mano.

   🔴 EL 10 ES UN HUECO LIBRE, Y ESO ES LO QUE PERMITE HACER ESTO SIN TOCAR NADA MÁS.
   La numeración de la ficha en móvil es: … banda de sellos 9 · descripción corta de la
   columna de la foto 10 · acordeón 11. Ese 10 está VACANTE en este producto, porque su
   descripción corta no es la de la columna de la foto —esa no se imprime aquí— sino la
   de la columna de compra, que es este bloque. Ocupando su sitio queda exactamente
   entre la banda de sellos y los desplegables, que es donde se pide.

   ⚠ NI SE DUPLICA EL MARCADO NI SE RENUMERA NADA. Es un solo <div> en el HTML, el
     mismo que en escritorio se pinta bajo la disponibilidad; aquí solo cambia su turno
     al apilarse. Las once posiciones ya asignadas se quedan como estaban.

   ⚠ Y NO HAY EMPATE QUE DESEMPATAR: antes llevaba un 7, el mismo que .ga-cantidad, y
     dependía del orden del marcado para caer delante. Con el 10 el número es único, así
     que el sitio ya no depende de dónde esté el <div> en la plantilla. */
/* 🔴 POR QUÉ ESTE `order` NO SE APLICABA, QUE ES TODO EL FALLO. No era la estructura:
   los tres bloques —franja de sellos, esta descripción y el acordeón— SÍ son hermanos.
   Con display: contents las dos columnas dejan de generar caja y sus hijos pasan a ser
   celdas del mismo grid, así que `order` sí podía ordenarlos.

   Lo que pasaba es que este `order` PERDÍA contra el suelo de seguridad de la línea
   3481:

       .ga-product-single:not(…--eventos) .ga-product__grid > * > * { order: 20; }

   Ese selector puntúa 0-3-0 —dos clases, el :not() y dos universales, que no suman— y
   el de aquí abajo puntuaba 0-3-0 solo si se contaba mal: eran DOS clases, o sea 0-2-0.
   Perdía, se quedaba con el 20 del suelo y caía al final de la ficha… justo detrás del
   acordeón, que es exactamente lo que se veía.

   Las demás piezas no tenían el problema porque sus reglas siguen el patrón de la casa
   —.ga-product-single:not(…--eventos) .lo-que-sea, o sea 0-3-0—; esta era la única
   escrita con la clase de SKU y una sola clase más.

   ✅ Se le añade el contenedor y el :not() para llegar a 0-4-0, que gana al suelo sin
   necesidad de !important y sin depender del orden de carga.

   ⚠ EL 10 SIGUE SIENDO EL HUECO CORRECTO: banda de sellos 9 · [aquí] 10 · acordeón 11.
     Esa posición 10 es la de .ga-product__short-desc--gal, que en este producto no se
     imprime, así que no hay empate con nadie. */
@media (max-width: 860px) {
    .ga-product-single--sku-ga-acc-aceitunero:not(.ga-product-single--eventos) .ga-product__grid .ga-product__short-desc--compra {
        order: 10;
    }
}


/* =============================================================================
   EL ACEITUNERO · EL VÍDEO DE DEMOSTRACIÓN, BAJO LAS MINIATURAS
   =============================================================================
   Solo existe en esta ficha: el <div> lo imprime la plantilla dentro de un
   if ( $ga_es_aceitunero ), así que estas reglas no tienen a quién aplicarse en
   ninguna otra. Aun así van acotadas con la clase de SKU, que es lo que hace que un
   día que alguien copie el marcado a otro sitio no se lleve por delante su galería.

   🔴 EL MISMO TRATAMIENTO QUE LA FOTO PRINCIPAL, Y CON LOS MISMOS VALORES: cuadrado,
   --ga-radius-md de esquina, el crema de marca de fondo y overflow para que el vídeo
   se recorte a la curva. No se copian números: se usan las mismas variables que
   .ga-product__gallery-main, así que si un día se cambia el radio de la ficha, este
   marco lo sigue solo.
   ============================================================================= */

.ga-product-single--sku-ga-acc-aceitunero .ga-product__video {
    position: relative;

    aspect-ratio: 1 / 1;
    overflow: hidden;
    border-radius: var(--ga-radius-md);
    background: var(--ga-naranja-claro);

    /* La separación con las miniaturas de arriba, la misma que usa la columna entre
       sus bloques. Así no queda pegado. */
    margin-top: var(--ga-space-sm);
}

/* 🔴 width: 100% Y max-width: 100% A LA VEZ, Y NO SOBRA NINGUNO. El primero le dice
   que ocupe el ancho de la columna —el mismo que la foto principal, porque es su
   hermano en la misma caja—; el segundo es el techo que impide que el vídeo, que
   trae su propio tamaño intrínseco de 1080px, empuje la columna y saque la fila
   fuera del viewport. Es la vía del proyecto en lugar de cualquier min-width.

   El height: 100% con object-fit: cover lo encaja en el cuadrado sin deformarlo,
   exactamente como hace la foto principal con su imagen. */
.ga-product-single--sku-ga-acc-aceitunero .ga-product__video-el {
    display: block;
    width: 100%;
    max-width: 100%;
    height: 100%;
    object-fit: cover;

    /* El fondo del propio vídeo mientras carga su primer fotograma: el mismo crema
       del marco, para que no asome un rectángulo negro. */
    background-color: var(--ga-naranja-claro);
}

/* ——— EL BOTÓN DE PLAY ———
   Un círculo dorado centrado sobre el vídeo en reposo. El JS lo retira en cuanto se
   pulsa y a partir de ahí mandan los controles nativos. */
.ga-product-single--sku-ga-acc-aceitunero .ga-product__video-play {
    position: absolute;
    top: 50%;
    left: 50%;

    /* 🔴 EL CENTRADO ES CON transform Y ESO OBLIGA A UNA COSA: el estado activo NO
       puede tocar el transform, porque le quitaría la compensación del 50 % y el
       botón se iría hacia abajo y a la derecha justo la mitad de su tamaño. Es la
       misma trampa que ya mordió en el círculo de "los demás aliños". Aquí no hay
       ningún estado que lo cambie: ver la regla de hover de más abajo. */
    transform: translate(-50%, -50%);

    display: grid;
    place-items: center;

    width: 68px;
    height: 68px;
    padding: 0;

    background-color: var(--ga-naranja-apagado);
    color: var(--ga-blanco);
    border: 0;
    border-radius: var(--ga-radius-full);
    cursor: pointer;

    /* Una sombra cálida de marca para despegarlo del fotograma, sea el que sea. */
    box-shadow: 0 4px 24px rgba(74, 74, 47, 0.35);

    /* Solo cambian color y sombra, nunca tamaño ni posición. */
    transition: background-color var(--ga-transition-fast),
                box-shadow var(--ga-transition-fast),
                opacity var(--ga-transition-fast);
}

.ga-product-single--sku-ga-acc-aceitunero .ga-product__video-play svg {
    width: 30px;
    height: 30px;

    /* El triángulo de play se ve descentrado si se centra geométricamente: su masa
       está a la izquierda del lienzo. Dos píxeles a la derecha lo compensan.
       Va en el SVG, no en el botón: mover el botón sería mover su posición. */
    margin-left: 2px;
}

/* ——— HOVER Y FOCO: VERDE OLIVA DE MARCA, TRIÁNGULO EN BLANCO ———
   El mismo verde principal que el botón de las tarjetas de aceitunas, para que los dos
   estados de esta ficha hablen el mismo idioma.

   🔴 EL `color` VA DECLARADO AUNQUE EN REPOSO YA SEA BLANCO. El triángulo del play es
   un SVG con fill="currentColor", así que toma el color del botón: si el estado no lo
   fija, cualquier regla de hover del tema se lo lleva y el triángulo cambia de tono
   mientras el fondo hace otra cosa. Repetido aquí, se queda blanco siempre.

   ⚠ NI HOVER NI FOCO MUEVEN NADA: solo cambian los colores y se cierra un poco la
     sombra. Y muy en particular NO se toca el transform, porque es el que centra el
     botón con translate(-50%,-50%): pisarlo lo desplazaría media anchura hacia abajo y
     a la derecha. */
.ga-product-single--sku-ga-acc-aceitunero .ga-product__video-play:hover,
.ga-product-single--sku-ga-acc-aceitunero .ga-product__video-play:focus-visible {
    background-color: var(--ga-verde-oliva-oscuro);
    color: var(--ga-blanco);
    box-shadow: 0 2px 14px rgba(74, 74, 47, 0.45);
}

/* Cuando el vídeo ya está en marcha, el botón se va. Se retira del flujo Y del árbol
   de accesibilidad con display: none —no basta con bajarle la opacidad, o seguiría
   pudiéndose pulsar por encima de los controles nativos—. La clase la pone el JS. */
.ga-product-single--sku-ga-acc-aceitunero .ga-product__video.is-reproduciendo .ga-product__video-play {
    display: none;
}

/* Quien ha pedido menos movimiento tampoco recibe la transición del botón. El vídeo
   no se toca: no se reproduce solo, así que no hay movimiento que nadie no haya
   pedido expresamente al pulsar play. */
@media (prefers-reduced-motion: reduce) {
    .ga-product-single--sku-ga-acc-aceitunero .ga-product__video-play {
        transition: none;
    }
}



/* =============================================================================
   EL ACEITUNERO · SU SECCIÓN PROPIA: VÍDEO + PÍLDORAS
   =============================================================================
   Solo existe en esta ficha —la plantilla la imprime dentro de un
   if ( $ga_es_aceitunero )—, así que estas reglas no tienen a quién aplicarse en
   ninguna otra. Aun así el bloque estrena su propio prefijo .ga-ace-, que es lo que
   garantiza que ninguna de ellas pueda alcanzar a otra sección por compartir clase.

   ⚠ EL VÍDEO REUTILIZA .ga-product__video TAL CUAL: su marco cuadrado, su botón de
     play dorado, sus estados y su JS son los mismos que ya se escribieron. Aquí solo
     se le cambia la PROPORCIÓN, porque este vídeo es vertical.
   ============================================================================= */

.ga-ace-bloque {
    /* El aire vertical de las secciones de la ficha.

       ⚠ ARRIBA Y ABAJO EL MISMO VALOR, QUE ES EL DE LAS DEMÁS SECCIONES DE LA
         FICHA. Llegó a llevar un escalón de más arriba para despegarla del acordeón y
         se pasaba: encima ya hay margen de sobra porque el acordeón trae el suyo. Se
         vuelve al valor común, que es lo que hace que esta sección respire igual que
         sus vecinas en vez de destacar por el hueco. */
    padding-block: var(--ga-space-xl);
}

/* El título, centrado sobre las DOS columnas y con aire hasta ellas. El tamaño y el
   color los pone .ga-section__titulo: aquí no se repite ninguno. */
.ga-product-single--sku-ga-acc-aceitunero .ga-ace-bloque__titulo {
    text-align: center;
    margin-top: 0;
    margin-bottom: var(--ga-space-lg);
}

/* ——— LAS DOS COLUMNAS ———
   🔴 minmax(0, …) EN LAS DOS Y NO UN 40/60 PELADO. Un `2fr` a secas vale como mínimo
   el ancho del CONTENIDO de su celda, así que una píldora con una palabra larga
   ensancharía su columna y sacaría la fila fuera de la página. Con el 0 de mínimo,
   las dos pueden estrecharse todo lo que haga falta. Es la vía del proyecto en lugar
   de cualquier min-width. */
.ga-ace-bloque__grid {
    display: grid;
    grid-template-columns: minmax(0, 4fr) minmax(0, 6fr);
    gap: var(--ga-space-md);

    /* 🔴 stretch Y NO start, Y ESE ES TODO EL ARREGLO DEL HUECO BLANCO. Con `start`
       cada columna medía lo suyo y la más corta dejaba un vacío debajo. Con el
       estirado —que es el valor por defecto de un grid— las dos celdas miden lo mismo:
       lo que mida la más alta. A partir de ahí, quien tiene que rellenar ese alto es
       la columna de píldoras, y de eso se encargan las dos reglas de abajo. */
    align-items: stretch;
}

/* ——— EL VÍDEO, VERTICAL ———
   Hereda de .ga-product__video el radio, el fondo crema, el overflow y el botón
   centrado; lo único que cambia es que su marco deja de ser cuadrado.

   ⚠ 4/5 Y NO 9/16. Un vertical completo dejaría la columna izquierda mucho más alta
     que el texto de la derecha y la sección quedaría descompensada. Con 4:5 el vídeo
     se sigue leyendo como vertical y no domina el bloque; el object-fit: cover que ya
     trae .ga-product__video-el lo encaja sin deformarlo.

   ⚠ SE ANULA EL margin-top QUE TRAÍA de cuando vivía bajo las miniaturas: aquí lo
     separa el gap de la rejilla y sumar los dos lo dejaría descolgado. */
.ga-ace-bloque .ga-ace-video {
    aspect-ratio: 4 / 5;
    margin-top: 0;
}

/* ——— LAS SEIS PÍLDORAS: 2 COLUMNAS × 3 FILAS ——— */
.ga-ace-pildoras {
    list-style: none;
    margin: 0;
    padding: 0;

    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--ga-space-sm);
}

.ga-ace-pildora {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;

    padding: 0.9rem 1rem;

    background-color: var(--ga-naranja-claro);
    border-radius: var(--ga-radius-md);

    /* 🔴 EL BORDE EXISTE YA EN REPOSO, TRANSPARENTE. Si naciera sin él y apareciera
       al pasar el ratón, la píldora crecería 1px por lado y empujaría a sus vecinas.
       Declarado desde el principio, el hover solo le cambia el COLOR y la caja mide
       siempre exactamente lo mismo. */
    border: 1px solid transparent;

    transition: background-color var(--ga-transition-fast),
                border-color var(--ga-transition-fast),
                box-shadow var(--ga-transition-fast);
}

/* ⚠ NI TAMAÑO NI POSICIÓN: solo el color del borde y una sombra cálida de marca.
     Sin transform, sin cambio de relleno y sin cambio de grosor de borde. */
.ga-ace-pildora:hover {
    border-color: var(--ga-naranja-apagado);
    box-shadow: 0 4px 24px rgba(74, 74, 47, 0.12);
}

.ga-ace-pildora__dato {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    font-weight: 700;
    line-height: 1.3;
    color: var(--ga-verde-oliva-oscuro);
    overflow-wrap: break-word;
}

.ga-ace-pildora__texto {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    font-weight: 400;
    line-height: 1.45;

    /* 🪤 nº 15: --ga-negro-suave está en la paleta pero NO se declara en el :root, y
       un var() que no resuelve hace que la propiedad HEREDE en vez de caer a su valor
       por defecto —el texto se quedaría con el dorado de los enlaces de Astra—. De
       ahí el respaldo, que es obligatorio mientras la variable no exista. */
    color: var(--ga-negro-suave, #1a1a14);
    overflow-wrap: break-word;
}

/* ═══════════════════════════════════════════════════════════════════════════
   LA FILA DE CERTIFICACIONES: LA QUE MÁS DESTACA
   ═══════════════════════════════════════════════════════════════════════════
   Ocupa el ancho de las dos columnas de píldoras, va sobre el verde oliva de marca y
   su rótulo lleva el brillo del proyecto.

   🔴 EL BRILLO ES EL MECANISMO QUE YA USA LA WEB, NO UNO NUEVO: un linear-gradient
   recortado sobre el texto con background-clip, el fondo estirado al 250 % de ancho y
   la animación moviendo SOLO background-position. Reutiliza los @keyframes
   ga-tienda-titulo-brillo de main.css, que son GLOBALES DEL DOCUMENTO —no pertenecen
   a la hoja donde se escriben—, así que no hay que redeclararlos.

   Es un BARRIDO DE LUZ, no un parpadeo ni un resplandor exterior: nada de opacidades
   que suben y bajan y nada de box-shadow animado. */
.ga-ace-certifica {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;

    margin-top: var(--ga-space-sm);
    padding: 1.15rem 1.25rem;

    background-color: var(--ga-verde-oliva-oscuro);
    border-radius: var(--ga-radius-md);
    text-align: center;
}

/* 🔴 EL COLOR MACIZO SE DECLARA FUERA DEL @supports, Y ESE ES TODO EL RESPALDO. Un
   navegador que no sepa recortar un degradado sobre texto no cruza esa puerta y se
   queda con este dorado: nunca un texto transparente ni invisible. El orden de las
   reglas ES el mecanismo de seguridad, no hay que hacer nada más. */
.ga-ace-certifica__rotulo {
    display: block;
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-lg);
    font-weight: 700;
    letter-spacing: 0.02em;
    line-height: 1.25;
    color: var(--ga-naranja-apagado);
    overflow-wrap: break-word;
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {

    .ga-ace-certifica__rotulo {
        /* La banda es el crema de marca sobre el dorado: dos tonos vecinos, así que
           el destello se lee como un reflejo y no como un cambio de color. */
        background-image: linear-gradient(
            100deg,
            var(--ga-naranja-apagado) 0%,
            var(--ga-naranja-apagado) 45%,
            var(--ga-naranja-claro)   50%,
            var(--ga-naranja-apagado) 55%,
            var(--ga-naranja-apagado) 100%
        );

        background-size: 250% 100%;
        background-repeat: no-repeat;
        background-position: 100% center;

        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;

        animation: ga-tienda-titulo-brillo 6s linear infinite;
    }

    /* Quien ha pedido menos movimiento se queda con el dorado macizo: se deshace el
       recorte y se devuelve el color, porque con background-clip: text y sin
       animación el texto se vería con el degradado congelado a medias. */
    @media (prefers-reduced-motion: reduce) {
        .ga-ace-certifica__rotulo {
            background-image: none;
            -webkit-background-clip: border-box;
            background-clip: border-box;
            color: var(--ga-naranja-apagado);
            animation: none;
        }
    }
}

.ga-ace-certifica__texto {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    line-height: 1.5;
    color: var(--ga-naranja-claro);
    overflow-wrap: break-word;
}

/* ═══════════════════════════════════════════════════════════════════════════
   MÓVIL Y TABLET
   ═══════════════════════════════════════════════════════════════════════════
   Se apila en el punto de corte de la ficha: primero el vídeo, después el titular, la
   frase y las píldoras. Es el orden del marcado, así que no hace falta ningún `order`.

   ⚠ LAS PÍLDORAS PASAN A UNA COLUMNA Y LA FILA DE CERTIFICACIONES SIGUE A TODO EL
     ANCHO, que es lo que se pidió: al ser hermana de la lista y no una celda suya, no
     depende del número de columnas y ocupa el ancho disponible pase lo que pase. */
@media (max-width: 860px) {

    .ga-ace-bloque {
        padding-block: var(--ga-space-lg);
    }

    .ga-ace-bloque__grid {
        grid-template-columns: minmax(0, 1fr);
    }

    /* Apilado, el vídeo dispone del ancho entero y a 4:5 se haría altísimo. Se le
       pone un techo de alto —no de ancho— para que siga entrando en pantalla.
       max-height y no height: si la columna es estrecha, manda la proporción. */
    .ga-ace-bloque .ga-ace-video {
        max-height: 70vh;
        margin-inline: auto;
    }

    /* 🔴 DOS COLUMNAS TAMBIÉN EN MÓVIL, NO UNA. Con solo el título en negrita cada
       píldora es un texto corto, así que a una columna quedaban diez tiras casi vacías
       y la sección se hacía larguísima. En dos, el bloque ocupa la mitad de alto y se
       lee de un vistazo.

       minmax(0, 1fr) y no 1fr a secas: un 1fr pelado vale como mínimo el ancho del
       CONTENIDO, así que "Cierre hermético + base antideslizante" ensancharía su
       columna y sacaría la fila fuera de la página. Con el 0 de mínimo, la columna
       puede estrecharse y el texto parte por donde deba. */
    .ga-ace-pildoras {
        grid-template-columns: repeat(2, minmax(0, 1fr));

        /* 🔴 TODAS LAS PÍLDORAS AL ALTO DE LA MÁS ALTA. Las celdas de una rejilla ya se
           estiran a la altura de su FILA, así que dos píldoras que estén una al lado de
           la otra siempre miden lo mismo; lo que no cuadraba era una fila contra otra,
           porque un título de una línea da una fila más baja que uno de dos. Con las
           cinco filas declaradas en 1fr, todas se igualan a la que más necesita y la
           rejilla queda pareja de arriba abajo.

           ⚠ 1fr NO ES UNA ALTURA FIJA Y NO PUEDE CORTAR NADA: en una rejilla equivale a
             minmax(auto, 1fr), o sea que el suelo sigue siendo el contenido. Si un
             título creciera hasta no caber, su fila crece —y con ella todas las demás,
             que es justo lo que se busca— en vez de recortarlo.

           🔴 EL 5 SON LAS DIEZ PÍLDORAS REPARTIDAS EN DOS COLUMNAS, y por eso se declara
           con grid-template-rows y no con grid-auto-rows: la fila de certificaciones es
           la SEXTA y tiene que quedarse fuera de este reparto. Al no estar declarada,
           cae en las filas implícitas, que se dimensionan solas por su contenido: sigue
           midiendo lo que mide y conserva su texto, exactamente como está hoy. Con
           grid-auto-rows entraría en el 1fr y se estiraría con las demás.

           ⚠ SI ALGÚN DÍA SE AÑADEN O QUITAN PÍLDORAS, HAY QUE ACTUALIZAR ESTE NÚMERO.
             Es la contrapartida de dejar fuera a las certificaciones. Y si se olvida, el
             fallo es benigno: las filas de más no se igualan, pero nada se rompe ni se
             corta. */
        grid-template-rows: repeat(5, 1fr);
    }

    /* ——— SOLO EL TÍTULO ———
       ⚠ SE OCULTA CON display: none, NO SE BORRA DEL HTML: la explicación sigue en la
         página y en escritorio se ve igual que siempre. Solo desaparece aquí.

       ⚠ Y CON ELLA SE VA SU HUECO: el gap de 0,3rem que la separaba del título es de
         la píldora, así que al quedarse un solo hijo no separa nada. No hay que
         tocarlo. */
    .ga-ace-pildora__texto {
        display: none;
    }

    /* Las píldoras de una misma fila miden lo mismo sin pedirlo: las celdas de una
       rejilla se estiran a la altura de la más alta de su fila. Lo que hace falta es
       que el título se CENTRE en esa altura, o el de una línea quedaría arriba junto
       al de dos. El centrado horizontal ya lo trae de su propia regla. */
    .ga-ace-pildora {
        justify-content: center;
    }

    /* ⚠ LA FILA DE CERTIFICACIONES NO ENTRA EN NADA DE ESTO. Sigue a todo el ancho por
         su grid-column: 1 / -1, que ahora abarca las dos columnas en vez de una, y
         conserva su texto porque este NO es un .ga-ace-pildora__texto sino
         .ga-ace-certifica__texto: la regla de arriba no lo alcanza. Se declara aquí de
         todos modos, para que quede a la vista que es la excepción y no un olvido. */
    .ga-ace-certifica__texto {
        display: block;
    }
}


/* ⚠ EL VÍDEO SE PULSA, ASÍ QUE LO PARECE. Sin la barra nativa nada indica que se
   puede interactuar con él; el cursor de mano es la única pista en escritorio. En
   táctil no cambia nada, y el botón de play ya cuenta la historia en reposo.

   No es un estado: es el cursor en reposo, así que no mueve ni redimensiona nada. */
.ga-product-single--sku-ga-acc-aceitunero .ga-product__video-el {
    cursor: pointer;
}


/* =============================================================================
   EL ACEITUNERO · LA COLUMNA DE PÍLDORAS, CON SEPARACIÓN UNIFORME
   =============================================================================
   🔴 NADA DE REPARTIR SOBRANTE. La separación entre cualquier par de filas —y entre la
   última píldora y el bloque verde— es SIEMPRE la misma: el `gap` de la lista y el
   margen de las certificaciones, los dos con el mismo valor de marca. Al no haber nada
   que repartir, no hay dos criterios que puedan discrepar y salir desiguales, que es
   exactamente lo que pasaba antes.

   ⚠ LA COLUMNA MIDE LO QUE MIDE SU CONTENIDO y puede no terminar en el filo de abajo
     del vídeo. Es la contrapartida asumida: vale más una separación uniforme que un
     cuadre milimétrico con filas pegadas entre sí.

   ⚠ SIN NINGUNA ALTURA FIJA, así que aguanta que una explicación ocupe dos líneas: esa
     píldora crece, la separación sigue siendo la misma y el bloque crece hacia abajo.

   La caja sigue siendo flexible en columna porque es lo que ordena sus dos piezas —la
   lista y el bloque verde— una debajo de otra.
   ============================================================================= */

.ga-ace-bloque__texto {
    display: flex;
    flex-direction: column;
}

/* La fila de certificaciones cierra la columna abajo del todo. El margen de arriba
   deja de hacer falta —el reparto de las filas ya la separa— pero se mantiene como
   suelo mínimo, por lo mismo que el gap: garantiza que nunca se pegue a la última
   píldora aunque no sobre ni un píxel de alto. */
.ga-ace-certifica {
    flex: 0 0 auto;
}

/* ⚠ AQUÍ HABÍA UN BLOQUE DE MÓVIL QUE DESHACÍA EL REPARTO VERTICAL, Y SE HA IDO CON
   ÉL. Ya no hay ningún reparto que deshacer: la separación uniforme vale igual
   apilada que en dos columnas, así que el móvil no necesita ninguna regla propia.
   Las diez píldoras pasan a una sola columna en el bloque de más abajo —con
   minmax(0,1fr), sin min-width— y la fila de certificaciones sigue a todo el ancho por
   ser hermana de la lista y no una celda suya. */


/* =============================================================================
   EL ACEITUNERO · DATO CENTRADO Y SIMETRÍA EXACTA CON EL VÍDEO
   ============================================================================= */

/* ——— EL DATO, CENTRADO; LA EXPLICACIÓN, NO ———
   El centrado va SOLO en el <span> del dato: la píldora es una columna flexible cuyos
   hijos ocupan el ancho entero, así que un text-align en el dato no puede alcanzar a
   su hermano de debajo, que conserva la alineación que tenía. */
.ga-product-single--sku-ga-acc-aceitunero .ga-ace-pildora__dato {
    text-align: center;
}

/* ═══════════════════════════════════════════════════════════════════════════
   EL REPARTO VERTICAL: SEPARACIÓN UNIFORME, Y SE ACABÓ
   ═══════════════════════════════════════════════════════════════════════════
   🔴 AQUÍ HABÍA UN MONTAJE PARA QUE LA COLUMNA CUADRARA AL MILÍMETRO CON EL VÍDEO, Y
   SE HA QUITADO ENTERO. Estiraba la columna al alto del vídeo (height: 0 +
   min-height: 100%), pegaba la lista arriba y las certificaciones abajo
   (justify-content: space-between) y repartía las cinco filas dentro de lo que
   quedara (align-content: space-between con el gap a 0).

   El problema es que eran DOS repartos independientes: uno dentro de la lista y otro
   entre la lista y el bloque verde. Cada uno repartía su propio sobrante, y no tenían
   por qué salir iguales. En la práctica la lista se quedaba con casi todo el alto, sus
   filas se separaban mucho… y la última píldora acababa pegada a las certificaciones,
   que es justo lo que se veía.

   ✅ AHORA MANDA UNA SOLA SEPARACIÓN Y ES SIEMPRE LA MISMA: el `gap` de la lista, que
   vale para las filas entre sí, y el mismo valor de margen antes del bloque verde. No
   hay nada que repartir, así que no hay dos criterios que puedan discrepar: la
   distancia entre cualquier par de filas es idéntica por construcción.

   ⚠ LA CONTRAPARTIDA, ASUMIDA Y PEDIDA: la columna deja de terminar exactamente en el
     filo de abajo del vídeo y puede sobrar un poco de aire. Es preferible a filas
     pegadas entre sí, que era el fallo que había que corregir.

   ⚠ Y AGUANTA QUE UNA EXPLICACIÓN OCUPE DOS LÍNEAS: no hay ni una altura fija en todo
     el montaje. Cada píldora mide lo que mida su texto y la separación sigue siendo la
     misma, porque es un gap y no un reparto de sobrante. Si el bloque crece, crece
     hacia abajo y ya está.

   Las reglas base de .ga-ace-pildoras y .ga-ace-certifica ya traen ese gap y ese
   margen, así que no hace falta redeclarar nada: basta con NO deshacerlos. Este
   @media se queda sin contenido y por eso desaparece. */


/* =============================================================================
   EL ACEITUNERO · UN SOLO REPARTO PARA LAS SEIS FILAS
   =============================================================================
   🔴 LA CLAVE ESTÁ EN QUE AHORA HAY UNA SOLA REJILLA. Las certificaciones se han
   metido dentro del <ul> como un <li> más que ocupa las dos columnas, así que la lista
   tiene SEIS filas —cinco de píldoras y la del bloque verde— y un único
   align-content las reparte a todas por igual.

   Antes eran dos repartos independientes, uno dentro de la lista y otro entre la lista
   y el bloque verde, y cada uno repartía su propio sobrante: no tenían por qué salir
   iguales, y de ahí que la última píldora acabara pegada al verde mientras las de
   arriba nadaban en aire. Con un solo reparto ese fallo no puede volver a darse: la
   separación entre cualquier par de filas es la misma por definición.

   ⚠ EL row-gap SE QUEDA COMO SUELO MÍNIMO, NO SE PONE A CERO. `space-between` reparte
     lo que SOBRA por encima del gap, nunca por debajo: si un día el contenido creciera
     hasta llenar el alto del vídeo, las filas conservarían su separación de siempre en
     vez de apelotonarse. Es la red que evita que una explicación de dos líneas rompa
     el reparto.

   ⚠ SIN NINGUNA ALTURA FIJA. Cada píldora mide lo que mida su texto; lo único que se
     reparte es el hueco sobrante. Que una explicación pase a dos líneas solo significa
     que sobra menos aire, no que el reparto deje de ser uniforme.
   ============================================================================= */
@media (min-width: 861px) {

    /* 🔴 LA COLUMNA DEJA DE CONTAR PARA EL ALTO DE LA FILA, y así el único que lo
       decide es el vídeo:

           height: 0        → su contenido ya no suma al calcular la fila
           min-height: 100% → pero después se estira al alto que haya salido

       Es la pareja clásica de "ocupa lo que te den, no pidas nada". Con la fila midiendo
       lo que el vídeo, arriba y abajo coinciden por construcción: no hay ningún número
       ajustado a ojo que revisar si mañana cambia el ancho. */
    .ga-product-single--sku-ga-acc-aceitunero .ga-ace-bloque__texto {
        height: 0;
        min-height: 100%;
    }

    /* La lista se come todo ese alto: es la única pieza de la columna. */
    .ga-product-single--sku-ga-acc-aceitunero .ga-ace-pildoras {
        flex: 1 1 auto;

        /* Las seis filas se reparten el sobrante con separaciones iguales, la primera
           pegada al borde superior del vídeo y la última al inferior. */
        align-content: space-between;
    }

    /* El margen propio del bloque verde sobra: ahora es una fila más de la rejilla y
       quien lo separa de la anterior es el mismo reparto que separa a todas. Dejarlo
       sumaría alto solo en ese hueco y volvería a romper la uniformidad. */
    .ga-product-single--sku-ga-acc-aceitunero .ga-ace-certifica {
        margin-top: 0;
    }
}

/* La fila de certificaciones ocupa las dos columnas de la rejilla, esté donde esté el
   reparto. Va fuera del @media porque también vale apilada: con una sola columna, el
   1 / -1 sigue siendo esa columna y no cambia nada. */
.ga-product-single--sku-ga-acc-aceitunero .ga-ace-certifica {
    grid-column: 1 / -1;
}


/* =============================================================================
   EL ACEITUNERO · "LLÉNALO CON NUESTRAS ACEITUNAS"
   =============================================================================
   La rejilla que ocupa el sitio de la tabla comparativa. Estrena el prefijo .ga-acem-,
   así que ninguna de estas reglas puede alcanzar a otra sección por compartir clase.

   ⚠ EL BOTÓN CONSERVA .ga-alinos__cart PORQUE ES EL SELECTOR QUE EL JS NECESITA, pero
     su aspecto lo decide el modificador --add de aquí abajo. Los dos conviven: la clase
     base trae el círculo dorado pensado para ir sobre una foto, y el modificador la
     reescribe entera para un botón ancho con texto. Todo lo que se sobrescribe va
     declarado, para que no quede nada del círculo asomando.
   ============================================================================= */

.ga-acem {
    padding-block: var(--ga-space-xl);
}

.ga-acem__titulo {
    text-align: center;
    margin-top: 0;
    margin-bottom: var(--ga-space-lg);
}

/* 🔴 CUATRO COLUMNAS CON minmax(0, 1fr) Y NO 1fr A SECAS. Un 1fr pelado vale como
   mínimo el ancho del CONTENIDO de la celda, así que un nombre largo ensancharía su
   columna y sacaría la fila fuera de la página. Con el 0 de mínimo, la columna puede
   estrecharse todo lo que haga falta. Es la vía del proyecto en lugar de min-width. */
.ga-acem__grid {
    list-style: none;
    margin: 0;
    padding: 0;

    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--ga-space-md);
}

/* ⚠ LAS TARJETAS SON COLUMNAS FLEXIBLES CON EL BOTÓN ANCLADO ABAJO (margin-top: auto).
     Las celdas de la rejilla se estiran solas al alto de la más alta de su fila, así
     que con eso los ocho botones quedan alineados aunque un nombre ocupe dos líneas y
     otro una. Sin alturas fijas: si el texto crece, crece la tarjeta. */
.ga-acem-card {
    display: flex;
    flex-direction: column;
    text-align: center;
}

.ga-acem-card__marco {
    aspect-ratio: 1 / 1;
    overflow: hidden;
    border-radius: var(--ga-radius-md);
    background: var(--ga-naranja-claro);
    margin-bottom: var(--ga-space-sm);
}

.ga-acem-card__foto {
    display: block;
    width: 100%;
    max-width: 100%;
    height: 100%;
    object-fit: cover;
}

.ga-acem-card__nombre {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    font-weight: 600;
    line-height: 1.35;
    color: var(--ga-verde-oliva-oscuro);
    margin: 0 0 0.35rem;
    overflow-wrap: break-word;
}

.ga-acem-card__precio {
    font-family: var(--ga-font-body);
    font-size: var(--ga-text-sm);
    font-weight: 700;

    /* 🪤 nº 15: --ga-negro-suave no está declarada en el :root, y un var() que no
       resuelve hace que la propiedad HEREDE en vez de caer a su valor por defecto —el
       texto se quedaría con el dorado de los enlaces de Astra—. De ahí el respaldo. */
    color: var(--ga-negro-suave, #1a1a14);
    margin: 0 0 var(--ga-space-sm);
    overflow-wrap: break-word;
}

/* ——— EL BOTÓN ———
   Reescribe por completo el círculo que trae .ga-alinos__cart: ancho, con texto y
   anclado al fondo de la tarjeta. */
.ga-acem-card__add {
    /* Deshace el círculo: sin tamaño fijo, sin redondeo de bola y en el flujo. */
    position: static;
    width: auto;
    height: auto;
    border-radius: var(--ga-radius-md);

    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;

    /* Lo pega al fondo de la tarjeta: es lo que alinea los ocho botones entre sí. */
    margin-top: auto;

    padding: 0.7rem 0.9rem;

    background-color: var(--ga-naranja-apagado);
    color: var(--ga-blanco);
    text-decoration: none;

    font-family: var(--ga-font-body);
    font-size: var(--ga-text-xs);
    font-weight: 700;
    letter-spacing: 0.02em;
    line-height: 1.2;

    /* 🔴 EL BORDE EXISTE YA EN REPOSO, TRANSPARENTE. Si apareciera al pasar el ratón,
       el botón crecería 1px por lado y movería la tarjeta entera. Declarado desde el
       principio, el hover solo le cambia el COLOR. */
    border: 1px solid transparent;

    transition: background-color var(--ga-transition-fast),
                border-color var(--ga-transition-fast),
                box-shadow var(--ga-transition-fast);
}

/* ——— HOVER Y FOCO: VERDE OLIVA DE MARCA, TEXTO E ICONO EN BLANCO ———
   🔴 EL `color` SE DECLARA AQUÍ TAMBIÉN, Y NO SOBRA. El botón es un <a>, y Astra trae
   su propio `color` para el hover de los enlaces; la regla base de este botón solo lo
   fija en REPOSO, así que al pasar el ratón el color del tema se colaba y el texto y
   el icono —que van en currentColor— se teñían de marrón. Repitiéndolo en el estado,
   el blanco manda en los dos momentos.

   ⚠ VERDE OLIVA OSCURO, EL PRINCIPAL DE MARCA: el mismo que visten los botones oscuros
     de la home. Es una variable, no un valor copiado.

   ⚠ NI TAMAÑO NI POSICIÓN: solo colores y una sombra. Sin transform, sin cambio de
     relleno y sin cambio de grosor de borde —el borde ya existe transparente en
     reposo—, así que la tarjeta no se mueve ni empuja a sus vecinas. */
.ga-acem-card__add:hover,
.ga-acem-card__add:focus-visible {
    background-color: var(--ga-verde-oliva-oscuro);
    border-color: var(--ga-verde-oliva-oscuro);
    color: var(--ga-blanco);
    box-shadow: 0 4px 24px rgba(74, 74, 47, 0.2);
}

/* Los dos iconos apilados en la misma celda, que es lo que permite cruzarlos por
   opacidad cuando el JS confirma. Es el mismo mecanismo del bloque de aliños. */
.ga-acem-card__add .ga-home-card__cart-ico,
.ga-acem-card__add .ga-home-card__cart-ok {
    grid-area: auto;
    display: block;
    width: 18px;
    height: 18px;
    flex-shrink: 0;
}

.ga-acem-card__add .ga-home-card__cart-ok {
    display: none;
}

/* Al confirmarse, el carrito deja paso al tique y el botón se pone verde. La clase
   .is-ok la gobierna gaAlinosCarrito(), la misma que en el bloque de aliños. */
.ga-acem-card__add.is-ok {
    background-color: var(--ga-verde-montanas);
    border-color: var(--ga-verde-montanas);
}

.ga-acem-card__add.is-ok .ga-home-card__cart-ico {
    display: none;
}

.ga-acem-card__add.is-ok .ga-home-card__cart-ok {
    display: block;
}

/* ——— TABLET: DOS POR FILA ——— */
@media (max-width: 1024px) {
    .ga-acem__grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* ——— MÓVIL ———
   Se quedan DOS por fila hasta el final. A 360px el contenedor deja unos 328px, así
   que cada tarjeta ronda los 148px: la foto se lee, el nombre entra en dos líneas y el
   botón sigue siendo un objetivo táctil holgado. Una sola columna dejaría la sección
   larguísima —ocho tarjetas apiladas— para no ganar nada.

   Lo que sí baja es el hueco y el tamaño del texto del botón, que con "Añadir al
   carrito" en 148px se partiría en tres líneas. */
@media (max-width: 600px) {

    .ga-acem {
        padding-block: var(--ga-space-lg);
    }

    .ga-acem__grid {
        gap: var(--ga-space-sm);
    }

    .ga-acem-card__add {
        padding-inline: 0.5rem;
        gap: 0.35rem;
        font-size: 0.65rem;
    }

    .ga-acem-card__add .ga-home-card__cart-ico,
    .ga-acem-card__add .ga-home-card__cart-ok {
        width: 15px;
        height: 15px;
    }
}


/* =============================================================================
   EL ACEITUNERO · SIN MINIATURAS EN MÓVIL
   =============================================================================
   🔴 SOLO EN MÓVIL Y SOLO EN ESTE PRODUCTO. En escritorio y tablet la tira se queda
   como está: esta regla vive dentro del media query y no puede alcanzarles.

   La regla que las destapa —.ga-product-single--sku-ga-acc-aceitunero:not(…--eventos)
   .ga-product__gallery-thumbs { display: flex }— puntúa 0-3-0. Esta suma lo mismo y va
   DESPUÉS, así que gana por orden. Se conserva el :not() de eventos por lo mismo que
   allí: para que el alcance no dependa de que hoy sea imposible que coincidan.

   ⚠ SE OCULTAN, NO SE BORRAN, y aquí eso importa de verdad: LAS FLECHAS FUNCIONAN
     PULSANDO LA MINIATURA QUE TOCA. Son ellas las que guardan la URL de cada foto, su
     texto alternativo y cuál se está viendo. Con display: none siguen en el DOM y el
     JS las encuentra igual, así que las flechas laterales conservan su comportamiento
     completo; borrarlas del HTML las dejaría sin nada que pulsar.

   ⚠ NO SE TOCA NADA DE LAS FLECHAS. Ni su regla, ni su posición, ni su orden en el
     apilado: siguen exactamente como estaban. */
@media (max-width: 860px) {

    .ga-product-single--sku-ga-acc-aceitunero:not(.ga-product-single--eventos) .ga-product__gallery-thumbs {
        display: none;
    }
}


/* =============================================================================
   EL ACEITUNERO · LA DESCRIPCIÓN CORTA, SIN MARCO Y MÁS PEGADA (MÓVIL)
   =============================================================================
   🔴 DE DÓNDE SALEN LAS DOS LÍNEAS: de la propia descripción corta. La regla base
   .ga-product__short-desc (línea 567 de este archivo) le pone un border-top y un
   border-bottom de 1px en --ga-naranja-claro, más un padding-block de 1rem para que el
   texto no se pegue a ellos. No vienen ni de la franja de sellos ni del acordeón.

   ⚠ SE APAGAN CON transparent Y NO CON `border: 0`, que es la diferencia que importa:
     a cero, la caja perdería 1px por arriba y otro por abajo y todo lo que hay debajo
     subiría medio píxel. En transparente ocupa exactamente lo mismo y solo deja de
     verse, que es la regla del proyecto para cualquier ajuste visual.

   ⚠ SI DEBAJO SIGUE VIÉNDOSE UNA LÍNEA, ES DEL ACORDEÓN Y ESTÁ BIEN. Su primer
     apartado lleva su propio border-top (.ga-accordion__item:first-child), que es lo
     que le dibuja el techo en TODAS las fichas. El encargo pedía expresamente no tocar
     los separadores del acordeón, así que se queda.

   ⚠ EL RELLENO BAJA, PERO NO A CERO. Sin bordes, 1rem de relleno más el margen de
     --ga-space-sm por cada lado dejaba la descripción flotando en mitad de un hueco.
     Se queda en 0,35rem de relleno y 0,6rem de margen: separación pequeña, igual
     arriba y abajo, y sin llegar a pegarse ni a la franja de sellos ni al desplegable.
   ============================================================================= */
@media (max-width: 860px) {

    .ga-product-single--sku-ga-acc-aceitunero:not(.ga-product-single--eventos) .ga-product__short-desc--compra {
        border-top-color: transparent;
        border-bottom-color: transparent;

        padding-block: 0.35rem;

        margin-top: 0.6rem;
        margin-bottom: 0.6rem;
    }
}


/* =============================================================================
   EL ACEITUNERO · MENOS HUECO ENTRE LA DESCRIPCIÓN CORTA Y EL ACORDEÓN (MÓVIL)
   =============================================================================
   🔴 ESE HUECO LO SUMABAN TRES COSAS, NO UNA, Y POR ESO TOCAR SOLO UNA NO BASTABA:

     0,6rem  el margin-bottom de la propia descripción corta
     1rem    el row-gap del grid (--ga-space-sm), que separa TODAS las celdas al
             apilarse y no se puede tocar sin descuadrar la ficha entera
     1rem    el margin-top que le da al acordeón la regla de la línea 7009
             ─────
     2,6rem en total

   ⚠ Y LOS TRES SE SUMAN, NO SE COLAPSAN: en un contenedor de rejilla los márgenes de
     hermanos nunca se funden entre sí, así que aquí cada uno aporta lo suyo entero.

   ✅ SE QUITAN DOS DE LOS TRES Y SE DEJA EL DEL MEDIO:

     · el margin-bottom baja a la mitad, 0,3rem;
     · el margin-top del acordeón se va a cero, y NO es un recorte a ojo: esa regla
       existe para pegar el acordeón a la FRANJA DE SELLOS en los productos donde va
       justo detrás de ella. Aquí ya no va detrás de la franja: entre las dos se ha
       metido la descripción corta, así que ese margen sobraba desde que se reordenó.
       Quitarlo es corregir un resto, no apretar el diseño.
     · el row-gap se deja intacto, porque es de la ficha entera.

   Total nuevo: 0,3 + 1 = 1,3rem, o sea la mitad justa de lo que había.

   ⚠ NO SE TOCA NADA MÁS: ni la separación de arriba —los sellos y la descripción
     conservan su margin-top de 0,6rem y su row-gap—, ni los espacios internos del
     acordeón, que los dan el relleno de cada botón y los bordes de cada apartado.
   ============================================================================= */
@media (max-width: 860px) {

    .ga-product-single--sku-ga-acc-aceitunero:not(.ga-product-single--eventos) .ga-product__short-desc--compra {
        margin-bottom: 0.3rem;
    }

    /* 0-4-0, por encima del 0-2-0 de la regla de la línea 7009 que le puso el margen. */
    .ga-product-single--sku-ga-acc-aceitunero:not(.ga-product-single--eventos) .ga-product__trust-band + .ga-product__acordeon-col {
        margin-top: 0;
    }
}


/* =============================================================================
   APADRINA UN OLIVO — LA CUADRÍCULA DE OLIVOS (ordenador y tablet)
   =============================================================================
   110 círculos numerados que sustituyen al desplegable a partir de 769px. Verde =
   libre, rojo = apadrinado.

   🔴 NACE OCULTA Y LA ENCIENDE EL JAVASCRIPT, con la clase .is-rejilla sobre
   .ga-olivo-campo. No es un capricho: la cuadrícula solo sirve si algo conecta los
   círculos con el campo real, y ese algo es gaOlivosRejilla(). Si el JS no corre, la
   clase no se pone, esto sigue en display:none y el cliente ve el desplegable de
   siempre con su required intacto. Es la misma degradación que las tarjetas de
   talla, y por eso el display base va aquí y no dentro del media query.

   🔴 EL DESPLEGABLE SE ESCONDE SOLO DONDE HAY CUADRÍCULA. En móvil el media query
   no aplica, así que el select se ve y la cuadrícula no: a 360px no hay nada nuevo
   en la página y el desplegable se comporta exactamente como hasta ahora.

   ⚠ NINGÚN ESTADO MUEVE NADA. El círculo lleva SIEMPRE un borde de 2px —transparente
     en reposo— y lo único que cambian el hover, el foco y la selección es el color,
     la sombra y la opacidad. Ni un píxel de tamaño ni de posición, así que la
     cuadrícula no baila al pasar el ratón.

   ⚠ SIN min-width, y sin poder desbordar. Las columnas son de ancho fijo con
     auto-fill: el navegador mete las que quepan y no fuerza el contenedor. El
     max-width del 100% es el cinturón.

   ⚠ EL ROJO ES --ga-rojo-teja, la variable que ya usa el punto de "fuera de
     horario" de la página de contacto. No se inventa ningún color: es el rojo que
     esta web ya usa para decir "esto no está disponible".
   ============================================================================= */

/* Oculta mientras el JS no la encienda. */
.ga-product-single .ga-olivos {
    display: none;
}

@media (min-width: 769px) {

    /* Con la cuadrícula montada, el desplegable deja de verse: sigue en el DOM y
       sigue siendo el campo que se envía, pero ya no es lo que se toca. */
    .ga-product-single .ga-olivo-campo.is-rejilla .ga-olivo__select {
        display: none;
    }

    .ga-product-single .ga-olivo-campo.is-rejilla .ga-olivos {
        display: grid;
        grid-template-columns: repeat(auto-fill, 2.25rem);
        justify-content: space-between;
        gap: 0.4rem;
        box-sizing: border-box;
        max-width: 100%;
        margin-top: 0.35rem;
    }
}

/* ——— EL CÍRCULO ——— */
.ga-product-single .ga-olivos__olivo {
    box-sizing: border-box;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
    margin: 0;

    /* El borde existe SIEMPRE, transparente en reposo: es lo que garantiza que
       marcar un olivo no cambie su tamaño ni empuje a los de al lado. */
    border: 2px solid transparent;
    border-radius: 50%;

    background-color: var(--ga-verde-montanas);
    color: var(--ga-blanco);

    font-family: var(--ga-font-body);
    font-size: 0.7rem;
    font-weight: 600;
    line-height: 1;

    display: flex;
    align-items: center;
    justify-content: center;

    cursor: pointer;
    transition: background-color var(--ga-transition-normal),
                border-color var(--ga-transition-normal),
                box-shadow var(--ga-transition-normal),
                opacity var(--ga-transition-normal);
}

/* Hover solo donde hay ratón, y solo en los que se pueden elegir. */
@media (hover: hover) {
    .ga-product-single .ga-olivos__olivo:not(:disabled):hover {
        background-color: var(--ga-verde-oliva-oscuro);
        box-shadow: 0 4px 12px rgba(74, 74, 47, 0.28);
    }
}

/* Foco por teclado: un anillo, que no ocupa sitio en el flujo. */
.ga-product-single .ga-olivos__olivo:focus-visible {
    outline: 2px solid var(--ga-naranja-apagado);
    outline-offset: 2px;
}

/* ——— ELEGIDO ———
   Dorado de marca con el texto en oliva muy oscuro, que es el par que ya usa la web
   para lo seleccionado. Solo color, borde y sombra. */
.ga-product-single .ga-olivos__olivo.is-elegido {
    background-color: var(--ga-naranja-apagado);
    border-color: var(--ga-verde-oliva-oscuro);
    color: var(--ga-negro-suave, #1a1a14);
    box-shadow: 0 4px 14px rgba(199, 168, 98, 0.45);
}

/* ——— OCUPADO ———
   Rojo teja, sin puntero de mano y sin ninguna reacción al ratón. Van además con
   el atributo disabled desde la plantilla, así que tampoco reciben foco: esto es
   solo su aspecto. */
.ga-product-single .ga-olivos__olivo--ocupado,
.ga-product-single .ga-olivos__olivo:disabled {
    background-color: var(--ga-rojo-teja);
    border-color: transparent;
    color: var(--ga-blanco);
    opacity: 0.75;
    cursor: not-allowed;
    box-shadow: none;
}

@media (prefers-reduced-motion: reduce) {
    .ga-product-single .ga-olivos__olivo {
        transition: none;
    }
}
