/* ---- fonts.css ---- */
/**
 * Fuentes auto-alojadas de GS Premium. Handle 'gs-fonts'.
 *
 * Archivo, Inter y Montserrat servidas desde el propio plugin (sin Google CDN):
 * mejor rendimiento, sin dependencia externa y sin implicaciones de privacidad.
 * Son fuentes VARIABLES (un woff2 por familia cubre todo el rango de pesos), por eso
 * cada @font-face declara `font-weight` como rango. Subconjunto latino (cubre español).
 * Licencia SIL Open Font License 1.1 — redistribuibles con el plugin.
 */

@font-face {
	font-family: 'Archivo';
	font-style: normal;
	font-weight: 100 900;
	font-display: swap;
	src: url('../fonts/archivo.woff2') format('woff2');
}

@font-face {
	font-family: 'Inter';
	font-style: normal;
	font-weight: 100 900;
	font-display: swap;
	src: url('../fonts/inter.woff2') format('woff2');
}

@font-face {
	font-family: 'Montserrat';
	font-style: normal;
	font-weight: 100 900;
	font-display: swap;
	src: url('../fonts/montserrat.woff2') format('woff2');
}

/* ---- header-base.css ---- */
/**
 * GS Premium — base compartida de los widgets de header. Handle 'gs-header-base'.
 * Depende de 'gs-tokens' y 'gs-fonts'.
 *
 * DOS trabajos:
 *  1) BLINDAJE anti-hover-leak: neutraliza los artefactos que el tema o Elementor
 *     inyectan en <a>/<button> (sombras, "lift" con transform, subrayados, el clásico
 *     fondo "rosa" de hover). Sin esto los widgets se ven contaminados por el tema.
 *  2) Patrón compartido de botón de ícono `.gs-iconbtn` (sección 6.1 del diseño).
 *
 * Convención de scoping:
 *   - Cada widget de header envuelve su salida en `.gs-hd` (+ clase de componente).
 *   - El cajón del carrito se portaléa a <body> y NO es descendiente de .gs-hd, por eso
 *     todo el blindaje se aplica también a la clase global `.gs-portal`.
 *
 * Técnica clave de la red de seguridad: usar `:where()` (especificidad 0) SIN
 * `!important` para forzar `background: transparent` en hover → mata el fondo del tema
 * pero deja ganar cualquier color propio del widget (que es más específico). Los resets
 * "duros" (sombra/filtro/subrayado) sí usan `!important` porque nunca son deseados.
 */

/* ── Caja y tipografía base ──────────────────────────────────────────────── */
.gs-hd,
.gs-hd *,
.gs-portal,
.gs-portal * {
	box-sizing: border-box;
}

.gs-hd {
	font-family: var(--gs-font-ui);
	-webkit-font-smoothing: antialiased;
}

/* ── Blindaje: reset duro de artefactos del tema en enlaces/botones ──────── */
.gs-hd a,
.gs-hd button,
.gs-portal a,
.gs-portal button,
.gs-hd a:hover,
.gs-hd a:focus,
.gs-hd a:active,
.gs-hd button:hover,
.gs-hd button:focus,
.gs-hd button:active,
.gs-portal a:hover,
.gs-portal a:focus,
.gs-portal a:active,
.gs-portal button:hover,
.gs-portal button:focus,
.gs-portal button:active {
	box-shadow: none !important;
	filter: none !important;
	/* Nota: con este `!important` ningún componente puede usar un subrayado real; por eso
	   .gs-sr__all y .gs-mc__undo-btn lo fingen con `border-bottom`. Se mantiene a
	   propósito: el tema subraya los enlaces con reglas que si no ganarían, y hoy ningún
	   componente necesita `text-decoration`. Si alguna vez hiciera falta, el cambio es
	   acotar este selector, no añadir otro `!important` encima. */
	text-decoration: none !important;
	text-shadow: none !important;
}

/* No permitir el "lift" con transform del tema en hover/focus, pero PRESERVAR el
   :active propio (p. ej. el scale .92 del icon-button). */
.gs-hd a:hover:not(:active),
.gs-hd a:focus:not(:active),
.gs-hd button:hover:not(:active),
.gs-hd button:focus:not(:active),
.gs-portal a:hover:not(:active),
.gs-portal a:focus:not(:active),
.gs-portal button:hover:not(:active),
.gs-portal button:focus:not(:active) {
	transform: none !important;
}

/* Red de seguridad de baja especificidad: elimina el fondo de hover del tema sin pisar
   los fondos propios de cada widget. `:where()` aporta 0, pero `a` + `:hover` dejan la
   regla en 0,1,1 — no en 0 — así que solo ganan las reglas propias de 0,2,0 en adelante
   (todas las actuales lo son: .gs-mc__chip:hover, .gs-sr__row:hover, .gs-nav__sublink:hover…).
   Si alguna vez hace falta un fondo en un <a> SIN pseudoclase, tendrá que subir de 0,1,0. */
:where(.gs-hd, .gs-portal) a:hover,
:where(.gs-hd, .gs-portal) a:focus,
:where(.gs-hd, .gs-portal) a:active,
:where(.gs-hd, .gs-portal) button:hover,
:where(.gs-hd, .gs-portal) button:focus,
:where(.gs-hd, .gs-portal) button:active {
	background-color: transparent;
}

/* ── Neutralizador de HOVER ──────────────────────────────────────────────────
   La red de arriba (0,1,1) basta contra un tema que escriba `a:hover`, pero NO contra el
   Global Kit de Elementor, que emite `.elementor-kit-{ID} a:hover` y `.elementor-kit-{ID}
   button:hover` con 0,2,1. Y como `elementor-kit-{ID}` va en el <body>, portalear a <body>
   no libra de ellas: el cajón del carrito sigue siendo su descendiente. Por eso el rosa del
   kit se colaba en el botón «Deshacer» (texto, borde y fondo).

   Estructura del blindaje, en dos piezas que se complementan:
     1) Esta regla, 0,3,1 con `!important`: mata fondo y color de hover en TODO <a>/<button>
        del header que NO esté en la lista de exclusión.
     2) La lista de exclusión son los componentes que SÍ tienen hover propio. Sus reglas
        viven prefijadas por su raíz (`.gs-portal …:hover` / `.gs-hd …:hover`) para quedar
        en 0,3,0 y ganarle al kit por su cuenta.
   Regla para el futuro: un <a>/<button> nuevo con color propio necesita AMBAS cosas —
   entrar en la lista y declarar su hover prefijado. Si solo entra en la lista, el kit le
   gana; si solo declara el hover sin prefijo (0,2,0), también.

   El `:not()` lleva la lista completa entre paréntesis (y no `:not(.a):not(.b)…`) a
   propósito: así aporta 0,1,0 una sola vez en vez de acumular una clase por cada nombre. */
.gs-hd :is(a, button):not(.gs-iconbtn, .gs-mc__cta, .gs-mc__close, .gs-mc__name, .gs-mc__step, .gs-mc__remove, .gs-mc__chip, .gs-mc__undo-btn, .gs-sr__clear, .gs-sr__all, .gs-sr__row, .gs-account__item, .gs-account__cta, .gs-nav__link, .gs-nav__sublink, .gs-nav__footer):hover,
.gs-portal :is(a, button):not(.gs-iconbtn, .gs-mc__cta, .gs-mc__close, .gs-mc__name, .gs-mc__step, .gs-mc__remove, .gs-mc__chip, .gs-mc__undo-btn, .gs-sr__clear, .gs-sr__all, .gs-sr__row, .gs-account__item, .gs-account__cta, .gs-nav__link, .gs-nav__sublink, .gs-nav__footer):hover {
	background-color: transparent !important;
	color: inherit !important;
}

/* Neutralizador de FOCUS/ACTIVE. El kit de Elementor pinta `a:focus`/`button:focus`
   (fondo y color de marca) con especificidad 0,1,1, que gana a las clases simples de
   nuestros componentes (0,1,0) — por eso el hover propio (0,2,0) sí gana pero el focus
   se colaba (p. ej. el botón de cerrar del cajón, que se auto-enfoca).
   El FONDO se anula con `!important` porque nunca lo queremos. */
.gs-hd :is(a, button):not(.gs-iconbtn):not(.gs-mc__cta):focus:not(:hover),
.gs-hd :is(a, button):not(.gs-iconbtn):not(.gs-mc__cta):active:not(:hover),
.gs-portal :is(a, button):not(.gs-iconbtn):not(.gs-mc__cta):focus:not(:hover),
.gs-portal :is(a, button):not(.gs-iconbtn):not(.gs-mc__cta):active:not(:hover) {
	background-color: transparent !important;
}

/* El COLOR va aparte y con la MISMA lista de exclusión que el neutralizador de hover.
   Antes iba sin lista y confiando en `:where()` para dejarlo «en especificidad 0»; eso era
   falso, y por partida doble:

     · `:where()` solo anula la parte que envuelve. En el selector que había —
       `:where(.gs-hd, .gs-portal) :is(a,button):not(.gs-iconbtn):not(.gs-mc__cta)
       :is(:focus,:active):not(:hover)`— los dos `:not()`, el `:is()` de estado y el
       `:not(:hover)` SÍ cuentan: la especificidad real era 0,4,1, no 0.
     · Y aunque de verdad fuese 0, tampoco serviría: para anular al kit (0,2,1) hay que
       ganarle, y quien le gana le gana también a nuestras clases sueltas (0,1,0). No existe
       una especificidad que cumpla las dos cosas a la vez. La lista de exclusión sí.

   Con 0,4,1 y sin lista, los tres enlaces dorados que el comentario decía proteger se
   apagaban a gris al TABULAR sobre ellos —su color vive en su regla base (0,1,0)—, que es
   justo el fallo que se creía evitado. Ahora quedan fuera del selector y conservan su color.
   Vale la regla del hover: un <a>/<button> nuevo con color propio tiene que entrar en las
   DOS listas. */
.gs-hd :is(a, button):not(.gs-iconbtn, .gs-mc__cta, .gs-mc__close, .gs-mc__name, .gs-mc__step, .gs-mc__remove, .gs-mc__chip, .gs-mc__undo-btn, .gs-sr__clear, .gs-sr__all, .gs-sr__row, .gs-account__item, .gs-account__cta, .gs-nav__link, .gs-nav__sublink, .gs-nav__footer):is(:focus, :active):not(:hover),
.gs-portal :is(a, button):not(.gs-iconbtn, .gs-mc__cta, .gs-mc__close, .gs-mc__name, .gs-mc__step, .gs-mc__remove, .gs-mc__chip, .gs-mc__undo-btn, .gs-sr__clear, .gs-sr__all, .gs-sr__row, .gs-account__item, .gs-account__cta, .gs-nav__link, .gs-nav__sublink, .gs-nav__footer):is(:focus, :active):not(:hover) {
	color: inherit;
}

/* Botón nativo: sin borde/appearance/padding heredados del tema.
   `padding` y los `min-*` NO son opcionales. Nuestros botones circulares fijan
   width/height y centran con grid; con `box-sizing: border-box`, un `padding` del tema
   deja la caja de CONTENIDO en ancho 0 y desplazada, así que el icono se centra ahí
   mientras el fondo redondo se pinta sobre la caja de borde: el icono acaba fuera de su
   propio círculo. Un `min-width` del tema (habitual en WooCommerce) convierte además el
   círculo en óvalo. OJO: este selector es 0,1,1, así que una clase suelta (0,1,0) NO le
   gana. Los botones que necesitan relleno (.gs-mc__cta, .gs-mc__remove) lo recuperan con
   reglas de 0,2,1 en minicarrito.css; cualquier botón nuevo con padding propio tiene que
   hacer lo mismo. */
.gs-hd button,
.gs-portal button {
	margin: 0;
	padding: 0;
	min-width: 0;
	min-height: 0;
	border: 0;
	background: none;
	font: inherit;
	color: inherit;
	line-height: inherit;
	-webkit-appearance: none;
	appearance: none;
	cursor: pointer;
}

/* SVG: siempre en bloque (el tema a veces lo colapsa en flex). NO forzar fill:none
   aquí — mataría los íconos de relleno (el carrito); cada SVG de trazo ya declara su
   propio fill="none". */
.gs-hd svg,
.gs-portal svg {
	display: block;
	flex: 0 0 auto;
}

/* Foco accesible neutro por defecto (cada componente puede reforzarlo en dorado).
   `border-radius: inherit` y no un valor fijo: con 4px este selector (0,2,1) ganaba a
   .gs-iconbtn (0,1,0) y cuadraba las esquinas de todos los botones de icono nada más
   tabular sobre ellos. El contorno debe seguir la forma real del botón. */
.gs-hd a:focus-visible,
.gs-hd button:focus-visible,
.gs-portal a:focus-visible,
.gs-portal button:focus-visible {
	outline: 2px solid var(--gs-oro);
	outline-offset: 2px;
	border-radius: inherit;
}

/* ── Patrón compartido de botón de ícono (§6.1) ─────────────────────────── */
.gs-iconbtn {
	/* Colores como variables: los controles de Elementor las reescriben; las reglas
	   usan !important para ganar SIEMPRE al color de enlace del tema/kit de Elementor
	   (que se colaba en :focus/:active). */
	--gs-ib-fg: var(--gs-tinta);
	--gs-ib-fg-hover: var(--gs-tinta);
	--gs-ib-fg-on: #fff;
	--gs-ib-bg: transparent;
	--gs-ib-bg-hover: var(--gs-hueso);
	--gs-ib-bg-on: var(--gs-tinta);

	width: 40px;
	height: 40px;
	display: grid;
	place-items: center;
	padding: 0;
	border: 0;
	border-radius: var(--gs-r-lg);
	position: relative;
	cursor: pointer;
	color: var(--gs-ib-fg) !important;
	background: var(--gs-ib-bg) !important;
	text-decoration: none !important;
	transition: background .18s var(--gs-e-soft),
		color .18s var(--gs-e-soft),
		transform .12s var(--gs-e-out);
}

/* Neutraliza el color/fondo que el tema o el kit de Elementor aplican en focus/active
   (la fuga del "hover rosa" al hacer clic y soltar). El `:not(:hover)` consulta el estado REAL
   de `:hover` del navegador, y en táctil ese estado se queda pegado tras el toque sin que
   signifique nada: por eso esta distinción foco-con-ratón-encima/foco-solo va dentro de
   `(hover: hover)`, y en táctil hay una rama aparte que no la necesita. */
@media (hover: hover) and (pointer: fine) {
	.gs-iconbtn:focus:not(:hover),
	.gs-iconbtn:active:not(:hover) {
		color: var(--gs-ib-fg) !important;
		background: var(--gs-ib-bg) !important;
	}

	.gs-iconbtn:hover,
	.gs-iconbtn:focus {
		color: var(--gs-ib-fg-hover) !important;
		background: var(--gs-ib-bg-hover) !important;
	}
}

@media (hover: none) {
	/* El `:hover` NO puede quedarse sin regla, aunque en táctil no signifique nada: `.gs-iconbtn`
	   está en la lista de exclusión del neutralizador de arriba, que da por hecho que el
	   componente se defiende solo. Sin esta regla (0,1,0 + pseudoclase, pero con `!important`)
	   el Global Kit gana con su `.elementor-kit-N button:hover` y pinta su rosa en cuanto se
	   toca el botón. Aquí se ancla al aspecto de REPOSO, que es lo que un hover pegado debe
	   valer donde no hay puntero. */
	.gs-iconbtn:hover {
		color: var(--gs-ib-fg) !important;
		background: var(--gs-ib-bg) !important;
	}

	/* Después del `:hover` a propósito: misma especificidad, gana la última, y al tocar
	   coexisten los dos estados. El foco (teclado externo, VoiceOver/TalkBack) sí realza. */
	.gs-iconbtn:focus,
	.gs-iconbtn:active {
		color: var(--gs-ib-fg-hover) !important;
		background: var(--gs-ib-bg-hover) !important;
	}
}

/* Estado "modo activo" (p. ej. buscador abierto): invierte a negro. Va al final para
   ganar aunque el botón esté además en hover/focus. */
.gs-iconbtn.is-on,
.gs-iconbtn.is-on:hover,
.gs-iconbtn.is-on:focus {
	color: var(--gs-ib-fg-on) !important;
	background: var(--gs-ib-bg-on) !important;
}

.gs-iconbtn:active {
	transform: scale(.92);
}

/* Indicador solo abajo, no un anillo completo — mismo lenguaje que
   .gs-sr__field:focus-within (buscador.css). Un anillo en los 4 lados de un botón de 40px se
   percibe como una raya suelta cuando algún vecino tapa parte del contorno; un móvil que da
   foco visible tras un simple toque (habitual en <button>, a diferencia de <a>) lo dejaba
   puesto tras cerrar el dedo.

   Dos blindajes le ganan si no se acota: la regla genérica de más arriba
   (.gs-hd/.gs-portal a/button:focus-visible, un elemento más específica) y sobre todo el reset
   duro de la línea 36 (`.gs-hd button:focus { box-shadow: none !important }`), que SÍ alcanza
   aquí porque `:focus-visible` cumple también `:focus`. Ese reset dice en su propio comentario
   que el arreglo es acotar el selector, no apilar otro `!important` — por eso este prefijado
   con `.gs-hd`/`.gs-portal` (0,3,0) y no `.gs-iconbtn:focus-visible` a secas (0,2,0). */
.gs-hd .gs-iconbtn:focus-visible,
.gs-portal .gs-iconbtn:focus-visible {
	outline: none !important;
	box-shadow: 0 2px 0 0 var(--gs-oro) !important;
}

.gs-iconbtn svg {
	width: 18px;
	height: 18px;
}

/* Soporte para íconos de fuente (Font Awesome, etc.) elegidos desde el control ICONS. */
.gs-iconbtn i {
	font-size: 18px;
	line-height: 1;
	color: inherit;
}

.gs-iconbtn i::before {
	color: inherit;
}

/* Extiende el área táctil en dispositivos sin hover, sin cambiar el hover visible. */
@media (hover: none) {
	.gs-iconbtn::after {
		content: '';
		position: absolute;
		inset: -4px;
	}
}

/* Nota: aquí vivía `.gs-hd--icons` (inline-flex + gap 20px) para agrupar los botones de
   ícono, pero ningún widget la emite nunca: cada uno se registra suelto y la separación la
   pone el contenedor de Elementor donde el usuario los coloca. Regla muerta, retirada. */

/* ── Reduced motion (obligatorio, §6.5; cada widget añade sus selectores) ── */
@media (prefers-reduced-motion: reduce) {
	.gs-iconbtn {
		transition-duration: .01ms;
	}
}

/* ---- nav-menu.css ---- */
/**
 * GS Nav Menu. Handle 'gs-nav-menu' (depende de 'gs-header-base').
 *
 * La barra es Montserrat (mayúsculas, tracking amplio); el panel rompe la herencia a
 * Inter/minúsculas a propósito (§2.1). Estado mobile lo activa el JS con `.is-mobile`.
 */

.gs-nav-root {
	position: relative;
	display: flex;
	align-items: center;
}

/* ── Barra ────────────────────────────────────────────────────────────────── */
/* La separación y la alineación llegan por variable desde los controles del widget. Que
   entren por `var()` y no escritas sobre `.gs-nav` es lo que deja que el reset de acordeón
   y móvil (más abajo) las anule: una regla propia de 0,3,0 le gana a este 0,1,0, mientras
   que a la que emitía Elementor —0,4,0— no le ganaba nada. */
.gs-nav {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	align-items: center;
	justify-content: var(--gs-nav-just, center);
	gap: var(--gs-nav-gap, 34px);
}

.gs-nav__item {
	position: relative;
	margin: 0;
}

.gs-nav__link,
.gs-nav__trigger {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 0.71875rem;
	line-height: 1.6;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--gs-tinta);
	text-decoration: none;
	background: none;
	cursor: pointer;
	transition: color .2s var(--gs-e-soft);
}

/* Prefijados por `.gs-hd` (0,3,0) para ganarle al Global Kit de Elementor (0,2,1). Cada
   hover declara fondo Y color: el que falte lo rellena el kit. Nota en header-base.css. */
.gs-hd .gs-nav__link:hover,
.gs-hd .gs-nav__trigger:hover,
.gs-hd .gs-nav__item.is-open > .gs-nav__trigger,
.gs-hd .gs-nav__link:focus,
.gs-hd .gs-nav__trigger:focus {
	color: var(--gs-oro);
	background: transparent;
}

.gs-nav__item.is-active > .gs-nav__link {
	color: var(--gs-oro);
}

/* Chevron */
.gs-nav__chevron {
	display: inline-flex;
	transition: transform .22s var(--gs-e-soft);
}

.gs-nav__chevron svg {
	width: 9px;
	height: 9px;
}

.gs-nav__item.is-open > .gs-nav__trigger .gs-nav__chevron {
	transform: rotate(180deg);
}

/* ── Panel flotante ─────────────────────────────────────────────────────────── */
.gs-nav__wrap {
	position: absolute;
	top: 100%;
	padding-top: 16px; /* puente de hover invisible: evita el parpadeo */
	z-index: var(--gs-z-panel);
	opacity: 0;
	visibility: hidden;
	transform: translateY(-8px);
	transition: opacity .2s var(--gs-e-soft), transform .2s var(--gs-e-soft), visibility 0s linear .2s;
}

.gs-nav--al-der .gs-nav__wrap { right: 0; left: auto; }
.gs-nav--al-izq .gs-nav__wrap { left: 0; right: auto; }
.gs-nav--al-centro .gs-nav__wrap { left: 50%; transform: translate(-50%, -8px); }

.gs-nav__item.is-open > .gs-nav__wrap {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
	transition: opacity .2s var(--gs-e-soft), transform .2s var(--gs-e-soft);
}

/* La alineación va en :where() (especificidad 0 para el prefijo) para que el reset de
   móvil/acordeón pueda anularla. Antes esta regla pesaba 0,4,0 y le ganaba al reset de
   0,3,0: en móvil, con alineación «Centro», el submenú abierto se iba media anchura a la
   izquierda, fuera de la pantalla. */
:where(.gs-nav--al-centro) .gs-nav__item.is-open > .gs-nav__wrap {
	transform: translate(-50%, 0);
}

/* ── El clon del espaciador del sticky de Elementor Pro ──────────────────────
   Al activarse el sticky, Elementor Pro no reserva el hueco con un div vacío: CLONA el
   contenedor entero —header y widgets incluidos— y oculta la copia con `visibility: hidden`.

   Si el panel estaba abierto en ese momento, el clon se lleva puesta la clase `is-open`. Y
   entonces la regla de aquí arriba, que declara `visibility: visible`, lo VUELVE A MOSTRAR:
   `visibility` es la única propiedad que un descendiente puede reactivar contra un ancestro
   oculto, así que el propio plugin desmontaba el escondite de Elementor.

   El resultado es un segundo panel, fantasma, que además no cierra nunca: el clon no pasa
   por `GSHeader.ready`, así que no tiene ni `__gsInit` ni un solo listener. Se queda abierto
   dentro del espaciador —que sigue en el flujo del documento— mientras el header real ya está
   clavado arriba, así que se desplaza hacia arriba y acaba tapando la barra con sus primeras
   filas cortadas. Al mover el cursor y volver, se abre el panel REAL, que sí está bien puesto:
   de ahí que pareciera que «se arregla solo». Y solo pasa la primera vez que se desplaza desde
   arriba porque el clon se fabrica una sola vez, al activarse el sticky.

   Medido en producción con el sticky activo: dos `.gs-nav-root` en el documento, la del
   contenedor `fixed` cerrada y la del `.elementor-sticky__spacer` abierta en `top: -12`.

   (0,4,0) a propósito: tiene que ganarle a la regla de apertura Y al reset de móvil, las dos
   de 0,3,0, esté donde esté cada una en el archivo. Ocultarlo devuelve además sus enlaces
   fuera del orden de tabulación, que era el otro efecto de haberlo destapado.

   El segundo selector es el mismo agujero en el cajón móvil, que también reafirma
   `visibility: visible` al abrirse (más abajo). Ahí no se ha visto en pantalla, pero el
   mecanismo es idéntico y el cajón es `position: fixed`: un clon abierto taparía la pantalla
   entera. Se cierra por si acaso, que sale gratis. */
.elementor-sticky__spacer .gs-nav-root .gs-nav__item > .gs-nav__wrap,
.elementor-sticky__spacer .gs-nav-root.is-mobile.is-mobile-open .gs-nav {
	visibility: hidden;
}

/* El ancho lo pone el control del widget a través de `--gs-nav-panel-w`, NO con un
   `width` propio. Cuando lo escribía Elementor directamente sobre `.gs-nav__panel`, la
   regla salía con especificidad 0,4,0 (`.elementor-N .elementor-element-X .gs-nav__panel`)
   y le ganaba al `width: 100%` del acordeón (0,3,0): en móvil el panel se quedaba en sus
   266px y se salía de la pantalla. Con la variable no hay pelea — el valor entra por
   herencia y la cascada normal decide.

   El `min()` es la red de seguridad para el desplegable de escritorio: en una tablet
   estrecha, o si alguien sube el slider a 520px, el panel no puede pasar del ancho de la
   ventana menos los márgenes. */
.gs-nav__panel {
	position: relative;
	width: min(var(--gs-nav-panel-w, 266px), calc(100vw - 24px));
	/* Fondo y radio también llegan en variable, y por lo mismo que el ancho: escritos como
	   propiedad, Elementor los emitía a (0,4,0) y el reset de acordeón/móvil (0,3,0) perdía. */
	background: var(--gs-nav-panel-bg, #fff);
	border: 1px solid var(--gs-linea);
	border-radius: var(--gs-nav-panel-r, var(--gs-r-xl));
	box-shadow: var(--gs-sh-dropdown);
	padding: 8px;
	/* reset tipográfico deliberado del panel (§2.5) */
	font-family: var(--gs-font-body);
	font-weight: 400;
	text-transform: none;
	letter-spacing: normal;
	text-align: left;
}

.gs-nav__arrow {
	position: absolute;
	top: -6px;
	right: 28px;
	width: 12px;
	height: 12px;
	background: #fff;
	border-left: 1px solid var(--gs-linea);
	border-top: 1px solid var(--gs-linea);
	transform: rotate(45deg);
}

.gs-nav--al-izq .gs-nav__arrow { right: auto; left: 28px; }
.gs-nav--al-centro .gs-nav__arrow { right: auto; left: 50%; margin-left: -6px; }

.gs-nav__eyebrow {
	display: block;
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 0.5625rem;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--gs-oro);
	padding: 10px 12px 8px;
}

.gs-nav__list {
	list-style: none;
	margin: 0;
	padding: 0;
}

/* El desplegable de la tienda puede traer doce categorías, y el panel flotante no tenía
   tope de altura: una lista larga se salía por abajo de la pantalla y los últimos enlaces
   quedaban fuera de alcance (el panel es `absolute`, así que la página tampoco crecía para
   dejarlos ver).

   El tope se pone sobre el PANEL y el scroll sobre la LISTA, en columna flex. Así el
   eyebrow y el pie —«Ver toda la tienda», a donde va quien no encuentra su categoría— se
   quedan fijos dentro del panel y lo único que se desplaza es la lista. `min-height: 0` es
   obligatorio: sin él un hijo flex no baja de su tamaño de contenido y no habría scroll.

   `--gs-nav-hueco` lo mide el JS al abrir (`medirHueco`), y no se puede deducir del CSS: el
   panel arranca donde caiga la barra, que depende de la plantilla y cambia al desplazar. El
   primer intento lo calculó con `100dvh` menos una reserva fija, y con la barra a 160px del
   borde superior —una cabecera normal— se quedaba 129px corto: el pie acababa fuera de la
   pantalla. El respaldo solo actúa el instante anterior a la primera medida.

   Acotado al panel FLOTANTE: en acordeón y en móvil el cajón entero ya tiene su propio
   scroll (ver `.gs-nav-root.is-mobile .gs-nav`), y un segundo scroll anidado dentro es la
   forma más fácil de dejar al dedo atrapado en la caja interior. */
.gs-nav-root:not(.gs-nav--acordeon):not(.is-mobile) .gs-nav__panel {
	display: flex;
	flex-direction: column;
	max-height: var(--gs-nav-hueco, calc(100dvh - 160px));
}

.gs-nav-root:not(.gs-nav--acordeon):not(.is-mobile) .gs-nav__list {
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
}

.gs-nav__sublink {
	display: block;
	font-family: var(--gs-font-body);
	font-weight: 400;
	font-size: 0.84375rem;
	line-height: 1.6;
	color: #333;
	padding: 10px 12px;
	border-radius: var(--gs-r-md);
	text-decoration: none;
	transition: background .15s var(--gs-e-soft), color .15s var(--gs-e-soft);
}

.gs-hd .gs-nav__sublink:hover,
.gs-hd .gs-nav__sublink:focus {
	background: var(--gs-hueso);
	color: var(--gs-oro);
}

.gs-nav__footer {
	display: flex;
	justify-content: space-between;
	align-items: center;
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 0.6875rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--gs-oro);
	padding: 11px 12px;
	text-decoration: none;
	border-top: 1px solid var(--gs-linea);
	margin-top: 6px;
	transition: color .18s var(--gs-e-soft);
}

/* Este enlace solo movía la flecha en hover y no declaraba color propio, así que era el
   más expuesto del plugin: cualquier `a:hover` del tema o del kit lo teñía. */
.gs-hd .gs-nav__footer:hover,
.gs-hd .gs-nav__footer:focus {
	color: var(--gs-oro-osc);
	background: transparent;
}

.gs-nav__footer-arrow {
	font-size: 15px;
	transition: transform .18s var(--gs-e-out);
}

.gs-nav__footer:hover .gs-nav__footer-arrow {
	transform: translateX(3px);
}

/* Categoría en el panel de LISTA. El enlace pasa a ser una fila con dos partes: el nombre y
   una nota opcional a la derecha (el conteo, o el aviso de que todavía no hay nada). Sin
   nota, `justify-content` no tiene nada que separar y se comporta como el enlace de antes. */
.gs-nav__sublink:has(.gs-nav__sub-nota) {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 12px;
}

.gs-nav__sub-nota {
	flex: 0 0 auto;
	font-family: var(--gs-font-ui);
	font-size: 0.5625rem;
	font-weight: 700;
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--gs-oro);
	opacity: .85;
}

/* Una categoría vacía se atenúa, pero su aviso NO: es lo único que explica por qué está
   apagada, y atenuarlo también lo dejaría ilegible. */
.gs-nav__sublink.is-vacia .gs-nav__sub-nombre { opacity: .5; }

/* ── Panel de tienda en rejilla ─────────────────────────────────────────────
   El desplegable de categorías no es una lista de enlaces sino una parrilla de tarjetas
   con miniatura. La lista simple sigue existiendo (control «Estilo del desplegable»), así
   que todo esto cuelga de `--mega` y no toca al panel de marcas.

   El ancho NO sale de `--gs-nav-panel-w`: esa variable la controla el slider del panel y
   está pensada para una columna de texto. Aquí el ancho lo manda el número de columnas, y
   se acota con `min()` contra la ventana para que no se salga en una tablet. */
.gs-nav__wrap--mega { --gs-nav-mega-col: 132px; }

.gs-nav-root:not(.gs-nav--acordeon):not(.is-mobile) .gs-nav__panel--mega {
	width: min(calc(var(--gs-nav-mega-col) * 4 + 56px), calc(100vw - 24px));
	padding: 10px;
}

.gs-nav__list--mega {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(var(--gs-nav-mega-col), 1fr));
	gap: 4px;
}

/* En acordeón y en móvil el cajón es estrecho: dos columnas, y la tarjeta se aplana a una
   fila (imagen pequeña a la izquierda, texto a la derecha) para no comerse la pantalla. */
.gs-nav-root.gs-nav--acordeon .gs-nav__list--mega,
.gs-nav-root.is-mobile .gs-nav__list--mega {
	grid-template-columns: repeat(2, 1fr);
}

.gs-nav__cat {
	display: flex;
	flex-direction: column;
	gap: 8px;
	padding: 10px;
	border-radius: var(--gs-r-md);
	text-decoration: none;
	transition: background .15s var(--gs-e-soft);
}

/* Prefijado por la raíz (0,3,0) y declarando fondo Y color: el Global Kit de Elementor
   emite `.elementor-kit-N a:hover` con 0,2,1 y alcanza a este enlace. */
.gs-hd .gs-nav__cat:hover,
.gs-hd .gs-nav__cat:focus-visible {
	background: var(--gs-hueso);
	color: inherit;
}

.gs-nav__cat-img {
	display: block;
	position: relative;
	aspect-ratio: 1 / 1;
	border-radius: var(--gs-r-sm, 8px);
	overflow: hidden;
	background: var(--gs-hueso);
}

.gs-nav__cat-img img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	transition: transform .3s var(--gs-e-out);
}

.gs-nav__cat:hover .gs-nav__cat-img img { transform: scale(1.04); }

/* Sin miniatura: la inicial de la categoría, centrada. Es menos ruidoso que el marcador
   de posición de WooCommerce, que es una imagen gris con su logotipo. */
.gs-nav__cat-ini {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 1.5rem;
	color: var(--gs-oro);
	opacity: .55;
}

.gs-nav__cat-txt {
	display: flex;
	flex-direction: column;
	gap: 1px;
	min-width: 0;
}

.gs-nav__cat-nombre {
	font-family: var(--gs-font-body);
	font-size: 0.8125rem;
	line-height: 1.3;
	color: #333;
	overflow-wrap: anywhere;
}

.gs-hd .gs-nav__cat:hover .gs-nav__cat-nombre { color: var(--gs-oro); }

.gs-nav__cat-nota {
	font-family: var(--gs-font-ui);
	font-size: 0.625rem;
	letter-spacing: .04em;
	color: #8A8378;
}

/* Una categoría sin nada que enseñar se atenúa y lo dice. Sigue siendo pulsable a
   propósito: la página existe, y prohibir el clic sin explicar por qué es peor que
   dejar entrar a un archivo que avisa de que está vacío. */
.gs-nav__cat.is-vacia .gs-nav__cat-img,
.gs-nav__cat.is-vacia .gs-nav__cat-nombre { opacity: .5; }

.gs-nav__cat.is-vacia .gs-nav__cat-nota {
	color: var(--gs-oro);
	opacity: .85;
	text-transform: uppercase;
	font-weight: 700;
	font-size: 0.5625rem;
	letter-spacing: .12em;
}

/* Reducción de movimiento: el zoom de la miniatura es decorativo y se apaga entero. */
@media (prefers-reduced-motion: reduce) {
	.gs-nav__cat-img img,
	.gs-nav__cat:hover .gs-nav__cat-img img { transition: none; transform: none; }
}

/* ── Hamburguesa (oculta en escritorio) ─────────────────────────────────────── */
.gs-nav__burger {
	display: none;
}

.gs-nav__burger-bars {
	display: grid;
	gap: 4px;
	width: 18px;
}

.gs-nav__burger-bars span {
	display: block;
	height: 2px;
	background: currentColor;
	border-radius: 2px;
	transition: transform .2s var(--gs-e-out), opacity .2s var(--gs-e-out);
}

.gs-nav-root.is-mobile-open .gs-nav__burger-bars span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.gs-nav-root.is-mobile-open .gs-nav__burger-bars span:nth-child(2) { opacity: 0; }
.gs-nav-root.is-mobile-open .gs-nav__burger-bars span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* ── Acordeón (control) y móvil (JS .is-mobile) comparten comportamiento ───────── */
/* `justify-content: flex-start` no es decorativo: la barra lo trae en `center`, y en una
   columna eso reparte en vertical. Con el cajón limitado en alto y con scroll propio, un
   contenido más largo que la caja se centra desbordando por ARRIBA, y esa parte no se
   puede alcanzar haciendo scroll. */
.gs-nav--acordeon .gs-nav {
	flex-direction: column;
	align-items: stretch;
	justify-content: flex-start;
	gap: 0;
}

.gs-nav-root.is-mobile .gs-nav__burger {
	display: grid;
}

/* El cajón se ancla a la VENTANA, no a la raíz del widget.
   Antes era `position: absolute; left: 0; right: 0` dentro de `.gs-nav-root`, que en móvil
   mide lo que mide la hamburguesa: 40px. El menú entero salía en una cinta de 40px de
   ancho, con los nombres de las categorías desbordando encima de la página. `left`/`right`
   nunca podían arreglarlo — el bloque contenedor era el equivocado.

   Con `fixed` los lados se miden contra la pantalla y el cajón no puede salirse esté donde
   esté la hamburguesa. Lo único que no se deduce del CSS es a qué altura empieza, y eso lo
   escribe el JS en `--gs-hd-top` (GSHeader.anclarBajo). El respaldo de 64px solo actúa el
   instante anterior a la primera medida.

   `max-height` + scroll propio porque un menú con submenús desplegados pasa de largo la
   pantalla de un teléfono; `overscroll-behavior` evita que al llegar al final arrastre la
   página de debajo. */
.gs-nav-root.is-mobile .gs-nav {
	position: fixed;
	top: var(--gs-hd-top, 64px);
	left: 12px;
	right: 12px;
	/* En un teléfono el cajón ocupa el ancho entero; el tope y los márgenes automáticos son
	   para la franja de tablet, donde el mismo cajón medía casi mil píxeles para seis
	   enlaces. Con `left`, `right` y `max-width` a la vez, `margin-inline: auto` centra la
	   caja dentro de la banda en lugar de estirarla. */
	max-width: 420px;
	margin-inline: auto;
	max-height: calc(100vh - var(--gs-hd-top, 64px) - 16px);
	max-height: calc(100dvh - var(--gs-hd-top, 64px) - 16px);
	overflow-y: auto;
	overscroll-behavior: contain;
	flex-direction: column;
	align-items: stretch;
	justify-content: flex-start;
	gap: 0;
	background: #fff;
	border: 1px solid var(--gs-linea);
	border-radius: var(--gs-r-xl);
	box-shadow: var(--gs-sh-dropdown);
	padding: 8px;
	z-index: var(--gs-z-panel);
	/* Cerrado no se oculta con `display: none` —así no había nada que animar y el cajón
	   aparecía de golpe— sino apagado y desplazado. `visibility` lo saca del orden de
	   tabulación, y su transición va retardada hasta el final para no cortar el fundido de
	   salida. Al ser `fixed`, seguir "presente" no ocupa ni un píxel de la página. */
	opacity: 0;
	visibility: hidden;
	transform: translateY(-8px) scale(.985);
	transform-origin: top center;
	transition: opacity .18s var(--gs-e-soft),
		transform .24s var(--gs-e-out),
		visibility 0s linear .24s;
}

.gs-nav-root.is-mobile.is-mobile-open .gs-nav {
	opacity: 1;
	visibility: visible;
	transform: none;
	transition: opacity .18s var(--gs-e-soft), transform .38s var(--gs-e-quint);
}

/* Los ítems entran escalonados detrás del cajón. El retardo se reparte con `nth-child` en vez
   de con una variable por ítem: no hace falta tocar el markup y un menú de header rara vez
   pasa de ocho entradas. A partir de la octava entran todas con el último retardo, que es
   preferible a que las últimas lleguen tardísimo. */
@keyframes gsNavItemIn {
	from { opacity: 0; transform: translateY(-10px); }
	to   { opacity: 1; transform: none; }
}

/* Ojo con el `>`: los <li> de los submenús también llevan `.gs-nav__item`, así que sin acotar
   a los hijos directos de la barra el escalonado se aplicaba igualmente a las marcas de dentro
   del panel. */
.gs-nav-root.is-mobile.is-mobile-open > .gs-nav > .gs-nav__item {
	animation: gsNavItemIn .42s var(--gs-e-quint) both;
	animation-delay: .16s;
}

.gs-nav-root.is-mobile.is-mobile-open > .gs-nav > .gs-nav__item:nth-child(1) { animation-delay: .04s; }
.gs-nav-root.is-mobile.is-mobile-open > .gs-nav > .gs-nav__item:nth-child(2) { animation-delay: .06s; }
.gs-nav-root.is-mobile.is-mobile-open > .gs-nav > .gs-nav__item:nth-child(3) { animation-delay: .08s; }
.gs-nav-root.is-mobile.is-mobile-open > .gs-nav > .gs-nav__item:nth-child(4) { animation-delay: .10s; }
.gs-nav-root.is-mobile.is-mobile-open > .gs-nav > .gs-nav__item:nth-child(5) { animation-delay: .12s; }
.gs-nav-root.is-mobile.is-mobile-open > .gs-nav > .gs-nav__item:nth-child(6) { animation-delay: .14s; }
.gs-nav-root.is-mobile.is-mobile-open > .gs-nav > .gs-nav__item:nth-child(7) { animation-delay: .16s; }

.gs-nav-root.is-mobile .gs-nav__item,
.gs-nav--acordeon .gs-nav__item {
	position: static;
}

/* `min-height: 44px` es el mínimo táctil (§6.5). Con el relleno de 12px y una tipografía
   de 11,5px la fila se quedaba en 42px: dos píxeles de menos que se notan cuando lo que hay
   debajo es otro enlace del menú. */
.gs-nav-root.is-mobile .gs-nav__link,
.gs-nav-root.is-mobile .gs-nav__trigger,
.gs-nav--acordeon .gs-nav__link,
.gs-nav--acordeon .gs-nav__trigger {
	padding: 12px 16px;
	min-height: 44px;
	justify-content: space-between;
	width: 100%;
}

/* Los enlaces del submenú son los más pequeños del sistema (13,5px sobre 10px de relleno).
   En un dedo eso son 42px; se suben al mínimo sin tocar la tipografía. */
.gs-nav-root.is-mobile .gs-nav__sublink,
.gs-nav--acordeon .gs-nav__sublink {
	min-height: 44px;
	display: flex;
	align-items: center;
}

/* Panel → acordeón: técnica grid 0fr→1fr (§2.7), nunca max-height */
.gs-nav-root.is-mobile .gs-nav__wrap,
.gs-nav--acordeon .gs-nav__wrap {
	position: static;
	padding-top: 0;
	opacity: 1;
	visibility: visible;
	transform: none;
	display: grid;
	/* `minmax(0, …)` y no `0fr`/`1fr` a secas: una pista `0fr` es `minmax(auto, 0fr)`, y ese
	   `auto` es el mínimo de contenido de la fila. El panel va con `overflow: hidden`, así
	   que su contenido no contaba… pero su relleno sí: cada submenú PLEGADO dejaba 16px de
	   aire (4px arriba + 12px abajo) bajo su ítem. Con el mínimo en 0 la fila cerrada mide
	   cero de verdad. (Mismo caso que las columnas del mosaico.) */
	grid-template-rows: minmax(0, 0fr);
	transition: grid-template-rows .36s var(--gs-e-quint);
}

.gs-nav-root.is-mobile .gs-nav__item.is-open > .gs-nav__wrap,
.gs-nav--acordeon .gs-nav__item.is-open > .gs-nav__wrap {
	grid-template-rows: minmax(0, 1fr);
}

/* Plegado = fuera del orden de tabulación. El reset de arriba reafirma
   `visibility: visible` para que se vea la animación de altura, pero eso dejaba los
   enlaces de un submenú CERRADO enfocables: tabulando se entraba en enlaces invisibles.
   Se oculta solo mientras está plegado, con la ocultación diferida al final de la
   animación para no cortarla al cerrar. */
.gs-nav-root.is-mobile .gs-nav__item:not(.is-open) > .gs-nav__wrap,
.gs-nav--acordeon .gs-nav__item:not(.is-open) > .gs-nav__wrap {
	visibility: hidden;
	transition: grid-template-rows .36s var(--gs-e-quint), visibility 0s linear .36s;
}

.gs-nav-root.gs-nav--acordeon .gs-nav__panel,
.gs-nav-root.is-mobile .gs-nav__panel {
	overflow: hidden;
	min-height: 0;
	width: 100%;
	background: var(--gs-crema);
	border: 0;
	border-radius: 0;
	box-shadow: none;
	padding: 4px 0 12px;
}

.gs-nav-root.is-mobile .gs-nav__arrow,
.gs-nav--acordeon .gs-nav__arrow {
	display: none;
}

.gs-nav-root.is-mobile .gs-nav__sublink,
.gs-nav--acordeon .gs-nav__sublink {
	padding-left: 28px;
}

@media (prefers-reduced-motion: reduce) {
	.gs-nav__wrap,
	.gs-nav__chevron,
	.gs-nav__footer-arrow,
	.gs-nav-root.is-mobile .gs-nav {
		transition-duration: .01ms;
	}

	/* El escalonado se anula entero, no se acelera: una cascada de siete elementos moviéndose
	   es justo lo que molesta a quien pide menos movimiento. */
	.gs-nav-root.is-mobile.is-mobile-open > .gs-nav > .gs-nav__item {
		animation: none;
	}
}

/* ---- buscador.css ---- */
/**
 * GS Buscador. Handle 'gs-buscador' (depende de 'gs-header-base').
 *
 * Escala paramétrica --k (todo en calc()). Panel de vidrio esmerilado portaleado a
 * <body> (posición fija, ancho completo). Las variables --gs-sr-* llegan inline en el
 * nodo del drop desde el render (los selectors de Elementor no alcanzan lo portaleado).
 */

.gs-sr {
	position: relative;
	display: inline-flex;
}

/* ── Scrim ────────────────────────────────────────────────────────────────── */
/* `pointer-events` es lo que decide si el velo intercepta clics, y NO se delega en
   `visibility`: el patrón «visibility 0s linear <retardo>» no revierte de forma fiable, y
   el velo se quedaba con visibility:visible + opacity:0 cubriendo toda la ventana. Como no
   tenía pointer-events, capturaba TODOS los clics de la página: después de abrir y cerrar
   el buscador una vez, el sitio dejaba de responder al ratón. Con `pointer-events: none`
   en reposo eso es imposible, pase lo que pase con la visibilidad. */
.gs-sr__scrim {
	position: fixed;
	inset: 0;
	z-index: var(--gs-z-scrim);
	background: rgba(10, 10, 10, .34);
	opacity: 0;
	pointer-events: none;
	/* La regla base describe el estado CERRADO, así que su duración es la de la SALIDA; la de
	   `.is-on`, la de la entrada. Estaban al revés (salida .36s, entrada .32s). Al entrar el
	   usuario mira lo que aparece; al salir ya decidió, y esperar se lee como lentitud. */
	transition: opacity .15s var(--gs-e-out);
}

.gs-sr__scrim.is-on {
	opacity: 1;
	pointer-events: auto;
	transition-duration: .2s;
}

/* ── Contenedor desplegable (fixed, ancho completo) ─────────────────────────── */
/* La escala va en px, no en rem: `rem` depende de la raíz del documento y un tema con
   `html { font-size: 62.5% }` —de los más habituales— encogía todo el panel a dos tercios
   sin que el diseño pudiera hacer nada. Los valores son los mismos que antes con una raíz
   de 16px (1.1875rem = 19px…), así que en un sitio normal nada cambia; en uno hostil, deja
   de cambiar. Es la misma razón por la que .gs-iconbtn ya estaba en px. */
.gs-sr__drop {
	--k: .93;
	--t-input: calc(var(--k) * 19px);
	--t-name: calc(var(--k) * 17px);
	--t-meta: calc(var(--k) * 15px);
	--t-price: calc(var(--k) * 20px);
	--ico: calc(var(--k) * 17px);
	--thumb: calc(var(--k) * 52px);
	--field-h: calc(var(--k) * 50px);
	--row-pad: calc(var(--k) * 10px);

	/* `fixed` porque el nodo se portaléa a <body>. `left`/`width` los escribe el JS a
	   partir del ancla (el contenedor del header), así que aquí solo va el valor de
	   partida a ancho de ventana. Sin `right` para no sobre-restringir la caja. */
	position: fixed;
	left: 0;
	width: 100%;
	z-index: var(--gs-z-drop);
	/* `pointer-events: none` frena el ratón pero NO saca del orden de tabulación: con el
	   panel cerrado se podía tabular hasta el campo y la ✕, que además están al final de
	   <body> por el portal, así que el foco saltaba a un sitio invisible. De eso se encarga
	   el atributo `inert`, que pone y quita el JS — es determinista y, a diferencia de
	   `visibility`, no obliga a cuadrar retardos con la animación.

	   Las dos líneas de arriba son AHORA MÁS IMPORTANTES que antes: el contenedor ya no
	   colapsa a altura 0 al cerrarse (ver más abajo), así que su caja ocupa siempre el alto
	   del panel. Sin ellas, un rectángulo invisible taparía la parte alta de la página. */
	pointer-events: none;
}

.gs-sr__drop.is-open {
	pointer-events: auto;
}

/* ── Cómo se despliega ───────────────────────────────────────────────────────
   El panel se DESLIZA dentro de este recorte, en vez de crecer de altura.

   Antes era `grid-template-rows: 0fr → 1fr` en el contenedor. El efecto era el mismo, pero
   `grid-template-rows` es una propiedad de DISEÑO: el navegador recalculaba la maquetación del
   panel entero en cada fotograma, fuera de la GPU, y con una lista de resultados dentro eso es
   justo lo que se percibía como tirón. `transform` y `opacity` se componen sin recalcular nada.

   Lo que hace posible el cambio es que `.gs-sr__drop` es `position: fixed`: que su caja mida
   siempre el alto del panel no descoloca la página, cosa que en flujo normal sí importaría. */
.gs-sr__clip {
	overflow: hidden;
}

.gs-sr__panel {
	display: flow-root;
	background: rgba(255, 255, 255, .94);
	-webkit-backdrop-filter: blur(var(--gs-sr-blur, 28px)) saturate(180%);
	backdrop-filter: blur(var(--gs-sr-blur, 28px)) saturate(180%);
	border-bottom: 1px solid var(--gs-linea);
	box-shadow: var(--gs-sh-panel);
	/* En PORCENTAJE, que es su propia altura: el panel mide lo que midan sus resultados y
	   cualquier valor en px se quedaría corto o largo según la consulta. */
	opacity: 0;
	transform: translateY(-100%);
	/* Salida 150ms / entrada 200ms (`.is-open`), dentro de la banda de 150–250ms de un
	   desplegable. Antes había TRES duraciones en el mismo elemento —.34s opacidad, .5s
	   transform, .34s filtro—: las propiedades terminaban en momentos distintos y eso se lee
	   como descuido. Una sola duración por estado.

	   Se fue también el `filter: blur(8px)` animado: se apilaba sobre el `backdrop-filter` de
	   este mismo nodo, o sea dos desenfoques a la vez y uno de ellos animándose, que es de lo
	   más caro que se le puede pedir a Safari y a cualquier móvil. El vidrio se queda, quieto. */
	transition: opacity .15s var(--gs-e-out), transform .15s var(--gs-e-out);
}

.gs-sr__drop.is-open .gs-sr__panel {
	opacity: 1;
	transform: none;
	transition-duration: .2s;
}

/* Vidrio desactivado desde el widget (o en equipos donde el blur cuesta caro). */
.gs-sr__drop.is-solid .gs-sr__panel {
	background: #fff;
	-webkit-backdrop-filter: none;
	backdrop-filter: none;
}

.gs-sr__inner {
	max-width: var(--gs-sr-maxw, 1280px);
	margin-inline: auto;
	padding-inline: var(--gs-sr-padx, 32px);
}

/* Modo "alinear con el header": la superficie sigue a sangre completa y es el JS quien
   escribe el padding lateral del interior copiando la caja de contenido del header. Aquí
   se sueltan el ancho máximo y el centrado para que ese padding mande. */
.gs-sr__drop.is-anclado .gs-sr__inner {
	max-width: none;
	margin-inline: 0;
}

/* ── Campo ────────────────────────────────────────────────────────────────── */
.gs-sr__field {
	display: flex;
	align-items: center;
	gap: 12px;
	margin: 20px 0;
	height: var(--field-h);
	padding: 0 4px 8px;
	/* `border: 0` ANTES del borde de abajo, y no solo `border-bottom`: el tema deja anchura de
	   borde en los otros tres lados, invisible mientras su color se confunde con el fondo. */
	border: 0;
	border-bottom: 1.5px solid var(--gs-linea);
	transition: border-color .24s, box-shadow .24s;
}

.gs-sr__field:focus-within {
	/* Solo el color del lado de ABAJO. Con `border-color` a secas se tiñen los cuatro lados, y
	   esa anchura ajena del lado izquierdo —invisible en reposo— aparecía como una raya dorada
	   vertical al enfocar el campo: la L que se veía en móvil. */
	border-bottom-color: var(--gs-sr-focus, #9C7A34);
	box-shadow: 0 1px 0 0 var(--gs-sr-focus, #9C7A34);
}

/* No cambia de color al enfocar el campo — el indicador de foco es solo el borde/sombra de
   abajo en `.gs-sr__field:focus-within`. Antes esta lupa también se ponía dorada, y al estar
   pegada al borde izquierdo del campo se leía como una raya dorada suelta a la izquierda. */
.gs-sr__lupa {
	display: flex;
	color: var(--gs-gris-2);
}

.gs-sr__lupa svg {
	width: var(--ico);
	height: var(--ico);
}

/* Variante "línea": el campo NO es una caja. El tema y el kit de Elementor estilan
   `input[type=search]` con borde, radio, fondo y alto propios y ganan por especificidad,
   así que aquí se neutralizan con !important (mismo blindaje que header-base.css aplica a
   <a>/<button>, extendido al único <input> del sistema). Sin esto se pinta un rectángulo
   redondeado alrededor del texto y el diseño de una sola línea se pierde. */
.gs-sr__field .gs-sr__input,
.gs-sr__field .gs-sr__input:hover,
.gs-sr__field .gs-sr__input:focus,
.gs-sr__field .gs-sr__input:focus-visible,
.gs-sr__field .gs-sr__input:active {
	flex: 1;
	min-width: 0;
	width: 100%;
	margin: 0 !important;
	padding: 0 !important;
	height: auto !important;
	min-height: 0 !important;
	line-height: 1.4;
	font-family: var(--gs-font-body);
	font-weight: 400;
	font-size: var(--t-input);
	letter-spacing: -.01em;
	color: var(--gs-tinta);
	-webkit-appearance: none;
	appearance: none;
	background: transparent !important;
	background-image: none !important;
	border: 0 !important;
	border-radius: 0 !important;
	box-shadow: none !important;
	outline: 0 !important;
	text-indent: 0;
}

.gs-sr__input::placeholder {
	color: var(--gs-gris-3);
	font-weight: 300;
	/* Firefox baja la opacidad del placeholder por defecto. */
	opacity: 1;
}

/* La "X" nativa de type=search (Chrome/Safari/Edge e IE) sobra: tenemos la nuestra. */
.gs-sr__input::-webkit-search-cancel-button,
.gs-sr__input::-webkit-search-decoration {
	-webkit-appearance: none;
	appearance: none;
	display: none;
}

.gs-sr__input::-ms-clear,
.gs-sr__input::-ms-reveal {
	display: none;
}

.gs-sr__clear {
	width: 32px;
	height: 32px;
	display: grid;
	place-items: center;
	border-radius: var(--gs-r-pill);
	color: var(--gs-gris-2);
	flex: 0 0 auto;
	transition: background .18s, color .18s, transform .2s var(--gs-e-out);
}

/* Prefijados por `.gs-portal` (0,3,0) para ganarle al Global Kit de Elementor (0,2,1), que
   alcanza al panel aunque esté portaleado a <body>. Ver la nota en header-base.css. */
.gs-portal .gs-sr__clear:focus {
	background: var(--gs-hueso);
	color: var(--gs-tinta);
}

@media (hover: hover) and (pointer: fine) {
	.gs-portal .gs-sr__clear:hover {
		background: var(--gs-hueso);
		color: var(--gs-tinta);
	}
}

/* En táctil el `:hover` se queda pegado tras el toque, pero la regla NO puede desaparecer: este
   botón está en la lista de exclusión del neutralizador de header-base.css, así que sin un
   `:hover` propio a 0,3,0 el que manda es el Global Kit (0,2,1) — y pintaba su rosa sobre la X
   en cuanto se tocaba. Aquí se ancla al aspecto de REPOSO, declarando fondo Y color
   (INSTRUCCIONES.md §3.1). Va después del `:focus` a propósito: misma especificidad, gana la
   última, y al tocar coexisten los dos estados; tabulando con teclado, en cambio, hay `:focus`
   sin `:hover` y el realce sí se ve. */
@media (hover: none) {
	.gs-portal .gs-sr__clear:hover {
		background: transparent;
		color: var(--gs-gris-2);
	}
}

.gs-sr__clear:active {
	transform: scale(.9);
}

.gs-sr__clear svg {
	width: 14px;
	height: 14px;
	stroke-width: 2;
}

/* ── Cuerpo (resultados + vacío + pie) ───────────────────────────────────────
   Truco de altura 0fr → 1fr. Sin esto el panel daría un salto seco al aparecer los
   resultados (el contenedor externo ya terminó su animación al abrir). Así el cuerpo
   "crece desde el campo".

   AQUÍ SÍ se anima una propiedad de diseño, a diferencia del desplegable: la altura la
   decide el contenido —cuántos resultados devolvió la consulta— y no hay forma de expresar
   "crece hasta lo que ocupes" con `transform`, que necesita un valor conocido de antemano.
   Se paga a sabiendas y se acota: ocurre una vez por consulta, no en cada apertura, y baja
   de .5s a .26s para que el recálculo dure la mitad de fotogramas. */
.gs-sr__body {
	display: grid;
	grid-template-rows: 0fr;
	transition: grid-template-rows .26s var(--gs-e-out);
}

.gs-sr__body.is-on {
	grid-template-rows: 1fr;
}

.gs-sr__body-clip {
	overflow: hidden;
	min-height: 0;
}

/* ── Resultados ─────────────────────────────────────────────────────────────── */
.gs-sr__results {
	max-height: min(56vh, 464px);
	overflow: auto;
	overscroll-behavior: contain;
	scrollbar-width: none;
}

.gs-sr__results::-webkit-scrollbar {
	width: 0;
	display: none;
}

.gs-sr__row {
	display: flex;
	align-items: center;
	gap: 20px;
	padding: var(--row-pad) 12px;
	margin-inline: -12px;
	border-radius: 12px;
	text-decoration: none;
}

/* ESCUDO, no realce: la fila ya no pinta fondo propio, pero la regla tiene que existir en TODOS
   los dispositivos. `.gs-sr__row` está en la lista de exclusión del neutralizador de
   header-base.css —esa lista da por hecho que el componente se defiende solo—, así que sin un
   `:hover`/`:focus` propio a 0,3,0 el Global Kit (0,2,1) gana y tiñe la fila con su rosa. Por eso
   NO va dentro de ninguna media query, y declara fondo Y color (INSTRUCCIONES.md §3.1). */
.gs-portal .gs-sr__row:hover,
.gs-portal .gs-sr__row:focus,
.gs-portal .gs-sr__row:active {
	background: transparent;
	color: inherit;
}

/* El realce sí es solo para el nombre y el precio, mismo lenguaje que "ver todos" más abajo en
   este archivo. `.is-active` es el resaltado de teclado (flechas ↑/↓ entre resultados) y también
   lo fija el ratón al entrar en una fila; `buscador.js` lo apaga al salir de la lista, o el
   dorado se quedaría encendido donde ya no está el cursor. */
.gs-portal .gs-sr__row.is-active .gs-sr__name,
.gs-portal .gs-sr__row.is-active .gs-sr__price {
	color: var(--gs-sr-rowhover, #8A6528);
}

@media (hover: hover) and (pointer: fine) {
	.gs-portal .gs-sr__row:hover .gs-sr__name,
	.gs-portal .gs-sr__row:hover .gs-sr__price {
		color: var(--gs-sr-rowhover, #8A6528);
	}
}

@media (hover: none) {
	.gs-portal .gs-sr__row:active .gs-sr__name,
	.gs-portal .gs-sr__row:active .gs-sr__price {
		color: var(--gs-sr-rowhover, #8A6528);
	}
}

.gs-sr__thumb {
	width: var(--thumb);
	height: var(--thumb);
	border-radius: var(--gs-sr-thumb-r, 10px);
	border: 1px solid var(--gs-linea);
	overflow: hidden;
	background: var(--gs-hueso);
	flex: 0 0 auto;
}

.gs-sr__thumb img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.gs-sr__name {
	flex: 1 1 auto;
	min-width: 0;
	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: var(--t-name);
	line-height: 1.3;
	color: var(--gs-tinta);
	transition: color .16s var(--gs-e-soft);
}

.gs-sr__hit {
	color: var(--gs-sr-hit, #8A6528);
	font-weight: 700;
}

.gs-sr__meta {
	flex: 0 0 auto;
	width: 192px;
	font-family: var(--gs-font-body);
	font-size: var(--t-meta);
	color: var(--gs-gris-2);
	text-align: right;
}

.gs-sr__price {
	flex: 0 0 auto;
	font-family: var(--gs-font-display);
	font-weight: 700;
	font-size: var(--t-price);
	line-height: 1;
	color: var(--gs-sr-price, #9C7A34);
	white-space: nowrap;
	text-align: right;
	transition: color .16s var(--gs-e-soft);
}

.gs-sr__price del {
	color: var(--gs-gris-3);
	font-weight: 400;
	font-size: .8em;
	margin-right: 4px;
}

/* ≤900px: cae la columna de meta y la fila queda miniatura · nombre · precio.
   (La fila es flex, no grid: las columnas son opcionales según los switchers del
   widget y flex las reparte sin plantillas que cuadrar.) */
@media (max-width: 900px) {
	.gs-sr__meta {
		display: none;
	}
}

/* ── Animación escalonada (dos keyframes idénticas para re-disparar) ──────────────
   Son keyframes y no transiciones —al revés que todo lo demás de este archivo— porque aquí
   no hay dos estados entre los que ir: la fila nace con cada consulta y solo tiene entrada.
   El truco de las dos clases gemelas `is-a`/`is-b` es lo que re-dispara la animación cuando
   el JS reemplaza la lista sin que el nodo llegue a salir del árbol.

   Se fue el `filter: blur(8px)` de cada fila, que multiplicaba un desenfoque por el número de
   resultados —hasta 12— sobre un panel que YA tiene `backdrop-filter` detrás.

   Y 200ms en vez de 600ms: la fila es lo último que aparece, después del panel (200ms) y del
   cuerpo (260ms). A 600ms la lista seguía acomodándose casi un segundo después del clic. */
@keyframes gsSrRowA {
	from { opacity: 0; transform: translateY(6px); }
	to   { opacity: 1; transform: none; }
}
@keyframes gsSrRowB {
	from { opacity: 0; transform: translateY(6px); }
	to   { opacity: 1; transform: none; }
}

.gs-sr__results.is-a .gs-sr__row,
.gs-sr__results.is-b .gs-sr__row {
	animation-duration: .2s;
	animation-timing-function: var(--gs-e-out);
	animation-fill-mode: both;
}

.gs-sr__results.is-a .gs-sr__row { animation-name: gsSrRowA; }
.gs-sr__results.is-b .gs-sr__row { animation-name: gsSrRowB; }

/* Escalonado de 30ms, y solo en las cinco primeras: el control admite hasta 12 resultados y
   con retardo para todas la última entraría a los 360ms, ya sin relación con el clic. De la
   sexta en adelante comparten el retardo de la quinta, así que el peor caso es 120 + 200 =
   320ms. El escalonado es decorativo: nada espera a que termine. */
.gs-sr__results .gs-sr__row { animation-delay: 120ms; }
.gs-sr__results .gs-sr__row:nth-child(1) { animation-delay: 0ms; }
.gs-sr__results .gs-sr__row:nth-child(2) { animation-delay: 30ms; }
.gs-sr__results .gs-sr__row:nth-child(3) { animation-delay: 60ms; }
.gs-sr__results .gs-sr__row:nth-child(4) { animation-delay: 90ms; }

/* Entrada suave de los bloques que no son filas (estado vacío y pie). */
@keyframes gsSrFadeDown {
	from { opacity: 0; transform: translateY(-6px); }
	to   { opacity: 1; transform: none; }
}

/* ── Estado vacío ─────────────────────────────────────────────────────────────── */
.gs-sr__empty {
	text-align: center;
	padding: 16px 20px 40px;
	animation: gsSrFadeDown .2s var(--gs-e-out) both;
}

.gs-sr__footer:not([hidden]) {
	animation: gsSrFadeDown .2s var(--gs-e-out) .06s both;
}

.gs-sr__empty-ring {
	width: 64px;
	height: 64px;
	border-radius: var(--gs-r-pill);
	border: 1.5px dashed var(--gs-linea);
	display: grid;
	place-items: center;
	color: var(--gs-oro-clr);
	margin: 0 auto 16px;
}

.gs-sr__empty-title {
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 24px;
	line-height: 1.05;
	text-transform: uppercase;
	margin: 0 0 8px;
	color: var(--gs-tinta);
}

.gs-sr__empty-sub {
	font-size: 15px;
	color: #5F5A52;
	margin: 0;
}

/* ── Pie ─────────────────────────────────────────────────────────────────────
   Contiene ÚNICAMENTE el enlace «Ver los N resultados» y solo existe cuando hay más
   resultados de los que caben. El selector [hidden] (0,2,0) gana al display:flex
   (0,1,0), así que el pie desaparece del todo — sin él quedaba una línea separadora
   flotando bajo el campo con el panel vacío. */
.gs-sr__footer {
	display: flex;
	align-items: center;
	padding: 16px 0 24px;
	margin-top: 8px;
	border-top: 1px solid var(--gs-linea);
	font-family: var(--gs-font-body);
	font-size: var(--t-meta);
}

.gs-sr__footer[hidden] {
	display: none;
}

.gs-sr__all {
	margin-left: auto;
	color: var(--gs-oro-osc);
	font-weight: 500;
	text-decoration: none;
	border-bottom: 1px solid rgba(138, 101, 40, .35);
	transition: color .18s var(--gs-e-soft), border-color .18s var(--gs-e-soft);
}

.gs-portal .gs-sr__all:focus {
	color: var(--gs-tinta);
	border-bottom-color: var(--gs-tinta);
	background: transparent;
}

@media (hover: hover) and (pointer: fine) {
	.gs-portal .gs-sr__all:hover {
		color: var(--gs-tinta);
		border-bottom-color: var(--gs-tinta);
		background: transparent;
	}
}

/* En táctil, anclado al aspecto de reposo en vez de quedarse sin regla — mismo motivo que en
   `.gs-sr__clear`: está en la lista de exclusión de header-base.css y sin `:hover` propio le
   gana el rosa del Global Kit. */
@media (hover: none) {
	.gs-portal .gs-sr__all:hover {
		color: var(--gs-oro-osc);
		border-bottom-color: rgba(138, 101, 40, .35);
		background: transparent;
	}
}

/* Reducir no es eliminar: se queda la opacidad —que es lo que evita el parpadeo de aparecer y
   desaparecer de golpe— y se va todo el desplazamiento, en los DOS estados.
   Que se anule también el del panel cerrado es seguro precisamente porque queda la opacidad:
   con `transform: none` el panel se queda en su sitio dentro del recorte, y lo que lo mantiene
   invisible es su `opacity: 0`. Si algún día se quitara esa opacidad, el panel se vería
   permanentemente para quien pida movimiento reducido. */
@media (prefers-reduced-motion: reduce) {
	.gs-sr__body,
	.gs-sr__panel,
	.gs-sr__scrim {
		transition-duration: .01ms;
	}
	.gs-sr__panel,
	.gs-sr__drop.is-open .gs-sr__panel {
		transform: none;
	}
	.gs-sr__results.is-a .gs-sr__row,
	.gs-sr__results.is-b .gs-sr__row,
	.gs-sr__empty,
	.gs-sr__footer:not([hidden]) {
		animation-duration: .01ms;
		animation-delay: 0ms !important;
	}
}

@media (prefers-reduced-transparency: reduce) {
	.gs-sr__panel {
		background: #fff;
		-webkit-backdrop-filter: none;
		backdrop-filter: none;
	}
}

/* ---- cuenta.css ---- */
/**
 * GS Cuenta. Handle 'gs-cuenta' (depende de 'gs-header-base').
 */

.gs-account {
	position: relative;
	display: inline-flex;
}

.gs-account__btn {
	position: relative;
}

/* Punto dorado de sesión iniciada (§4.2). El borde lo separa del ícono. */
.gs-account__dot {
	position: absolute;
	top: 6px;
	right: 5px;
	width: 6px;
	height: 6px;
	border-radius: var(--gs-r-pill);
	background: var(--gs-oro);
	border: 1.5px solid var(--gs-crema);
	pointer-events: none;
}

/* ── Dropdown ────────────────────────────────────────────────────────────── */
.gs-account__wrap {
	position: absolute;
	top: 100%;
	right: 0;
	z-index: var(--gs-z-panel);
	padding-top: 12px; /* puente de hover / separación del botón */
	display: none;
}

.gs-account--dd.is-open .gs-account__wrap {
	display: block;
}

.gs-account__panel {
	position: relative;
	width: min(266px, calc(100vw - 24px));
	background: #fff;
	border: 1px solid var(--gs-linea);
	border-radius: var(--gs-r-xl);
	box-shadow: var(--gs-sh-dropdown);
	padding: 8px;
	text-align: left;
	font-family: var(--gs-font-body);
	animation: gsAccIn .2s var(--gs-e-soft);
}

.gs-account__arrow {
	position: absolute;
	top: -6px;
	right: 28px;
	width: 12px;
	height: 12px;
	background: #fff;
	border-left: 1px solid var(--gs-linea);
	border-top: 1px solid var(--gs-linea);
	transform: rotate(45deg);
}

.gs-account__head {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 8px 10px 10px;
}

.gs-account__avatar {
	--gs-av-1: #8A6528;
	--gs-av-2: #C2A370;
	width: 36px;
	height: 36px;
	flex: 0 0 auto;
	display: grid;
	place-items: center;
	border-radius: var(--gs-r-pill);
	background: linear-gradient(135deg, var(--gs-av-1), var(--gs-av-2));
	color: #fff;
	font-family: var(--gs-font-display);
	font-weight: 700;
	font-size: 0.8125rem;
}

.gs-account__hi {
	font-size: 0.875rem;
	font-weight: 600;
	color: var(--gs-tinta);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.gs-account__eyebrow {
	display: block;
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 0.5625rem;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--gs-oro);
	padding: 10px 12px 8px;
}

.gs-account__item {
	display: flex;
	align-items: center;
	/* Mínimo táctil (§6.5): con 13,5px de texto y 10px de relleno la fila medía 42px, y
	   estos enlaces van pegados unos a otros. */
	min-height: 44px;
	font-family: var(--gs-font-body);
	font-weight: 400;
	font-size: 0.84375rem;
	line-height: 1.6;
	color: #333;
	padding: 10px 12px;
	border-radius: var(--gs-r-md);
	text-decoration: none;
	transition: background .15s var(--gs-e-soft), color .15s var(--gs-e-soft);
}

/* Prefijados por `.gs-hd` (0,3,0) para ganarle al Global Kit de Elementor (0,2,1). Cada
   hover declara fondo Y color: el que falte lo rellena el kit. Nota en header-base.css. */
.gs-hd .gs-account__item:hover,
.gs-hd .gs-account__item:focus {
	background: var(--gs-hueso);
	color: var(--gs-oro);
}

.gs-account__divider {
	display: block;
	height: 1px;
	background: var(--gs-linea);
	margin: 6px 8px;
}

/* El color base lo pone el control «Color de "Cerrar sesión"», que escribe `--gs-logout-fg`
   sobre este elemento. Aquí se consume, para que exista también sin Elementor delante. */
.gs-account__logout {
	color: var(--gs-logout-fg, var(--gs-rojo));
}

.gs-hd .gs-account__logout:hover,
.gs-hd .gs-account__logout:focus {
	background: var(--gs-rojo-bg);
	color: var(--gs-logout-fg, var(--gs-rojo));
}

.gs-account__cta {
	display: block;
	text-align: center;
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 0.6875rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: #fff;
	background: var(--gs-tinta);
	padding: 12px;
	margin: 4px;
	border-radius: var(--gs-r-md);
	text-decoration: none;
	transition: background .2s var(--gs-e-soft);
}

.gs-hd .gs-account__cta:hover,
.gs-hd .gs-account__cta:focus {
	background: var(--gs-tinta-hover);
	color: #fff;
}

/* ── Móvil ───────────────────────────────────────────────────────────────────
   El desplegable deja de colgar del botón y se ancla a la VENTANA. El botón mide 44px, y
   con `right: 0` el panel crecía hacia la izquierda desde ahí: con el icono en el centro
   del header, sus 266px empezaban en x negativo y la mitad quedaba fuera de la pantalla.
   Aquí `left`/`right` se miden contra la ventana, así que no puede salirse esté donde
   esté el icono. La altura a la que empieza la escribe el JS en `--gs-hd-top`
   (GSHeader.anclarBajo); el respaldo de 64px solo actúa antes de la primera medida.
   La flecha se retira porque ya no apunta a nada: el panel no está bajo el botón. */
@media (max-width: 767px) {

	.gs-account--dd .gs-account__wrap {
		position: fixed;
		top: var(--gs-hd-top, 64px);
		left: 12px;
		right: 12px;
		padding-top: 0;
	}

	.gs-account--dd .gs-account__panel {
		width: 100%;
	}

	.gs-account--dd .gs-account__arrow {
		display: none;
	}
}

@keyframes gsAccIn {
	from { opacity: 0; transform: translateY(-8px); }
	to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
	.gs-account__panel { animation-duration: .01ms; }
}

/* ---- minicarrito.css ---- */
/**
 * GS Minicarrito. Handle 'gs-minicarrito' (depende de 'gs-header-base').
 *
 * Badge en el header (usa .gs-hd, hereda el blindaje). Cajón portaleado a <body> con
 * clase .gs-portal (para recibir el reset anti-hover). Colores del cajón vía variables
 * --gs-mc-* inline en el nodo (los selectors de Elementor no alcanzan el portal).
 */

/* ── Botón + badge (en el header) ─────────────────────────────────────────── */
.gs-minicart {
	position: relative;
	display: inline-flex;
}

.gs-minicart__btn {
	position: relative;
}

/* Centrado REAL con flex, como el resto de piezas circulares del sistema (.gs-iconbtn,
   .gs-mc__close, .gs-mc__step…). Antes el dígito se centraba con el truco de
   `line-height == height`, que no es centrado: basta con que el tema toque `line-height`
   en spans para que la caja de línea encoja, se apoye contra el borde superior y todo el
   sobrante quede debajo — el número aparecía pegado arriba.
   `font-size` en px y no en rem: un tema con `html { font-size: 62.5% }` (muy común)
   encogía el dígito dentro de un círculo que sigue midiendo 15px. */
.gs-minicart__badge {
	position: absolute;
	top: 3px;
	right: 2px;
	min-width: 15px;
	height: 15px;
	padding: 0 3px;
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--gs-oro);
	color: #fff;
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 9px;
	line-height: 1;
	border-radius: var(--gs-r-pill);
	pointer-events: none;
}

/* [hidden] (0,2,0) tiene que ganarle al `display: flex` de arriba (0,1,0). */
.gs-minicart__badge[hidden] {
	display: none;
}

@keyframes gsBadgePop {
	0%   { transform: scale(1); }
	38%  { transform: scale(1.42); }
	100% { transform: scale(1); }
}

.gs-minicart__badge.is-bump {
	animation: gsBadgePop .45s var(--gs-e-out);
}

/* ── Cajón (portal) ─────────────────────────────────────────────────────────── */
.gs-mc {
	position: fixed;
	inset: 0;
	z-index: var(--gs-z-drawer);
	visibility: hidden;
	pointer-events: none;
	transition: visibility 0s linear .44s;
}

.gs-mc.is-open {
	visibility: visible;
	pointer-events: auto;
	transition: visibility 0s;
}

.gs-mc__scrim {
	position: absolute;
	inset: 0;
	z-index: 300;
	background: var(--gs-mc-scrim, rgba(10, 10, 10, .45));
	opacity: 0;
	transition: opacity .3s var(--gs-e-soft);
}

.gs-mc.is-open .gs-mc__scrim {
	opacity: 1;
}

.gs-mc__panel {
	position: absolute;
	top: 0;
	bottom: 0;
	z-index: 301;
	width: min(var(--gs-mc-w, 420px), 100vw);
	background: var(--gs-mc-bg, #fff);
	box-shadow: var(--gs-sh-drawer);
	display: flex;
	flex-direction: column;
	transition: transform .36s var(--gs-e-out);
}

.gs-mc--der .gs-mc__panel { right: 0; transform: translateX(102%); }
.gs-mc--izq .gs-mc__panel { left: 0; transform: translateX(-102%); }

.gs-mc.is-open .gs-mc__panel {
	transform: none;
	transition: transform .44s var(--gs-e-out);
}

/* ── Ancho en móvil ──────────────────────────────────────────────────────────
   Por qué hay DOS variables y no una: el ancho de escritorio lo emite PHP como estilo EN LÍNEA
   sobre el nodo del cajón, y un estilo en línea no puede llevar media query. Reutilizando la
   misma variable no habría forma de darle dos valores; con dos, la media query elige cuál
   consume.

   Esta regla arregla algo que se veía como una inconsistencia entre teléfonos: con
   `min(420px, 100vw)`, un móvil de 390px resolvía a 390 —cajón a pantalla completa— y uno de
   430px a 420, dejando una franja de 10px. Mismo ajuste, dos resultados distintos, sin que nadie
   hubiera configurado nada. De fábrica el móvil va al 100%, así que el ancho ya no depende del
   tamaño del dispositivo.

   El `min(…, 100vw)` se conserva: con 100% es redundante, pero el control admite px y ahí vuelve
   a ser lo que impide que un valor mayor que la pantalla saque el cajón fuera de cuadro.

   560px es el corte de móvil que ya usan tarjetas.css y producto-related.css: no se estrena un
   punto de ruptura nuevo. */
@media (max-width: 560px) {
	.gs-mc__panel {
		width: min(var(--gs-mc-w-movil, 100%), 100vw);
	}
}

/* El panel se enfoca por programa al abrir el cajón (tiene tabindex="-1"), así que este
   contorno sí llega a verse; sin el tabindex era una regla muerta. */
.gs-mc__panel:focus-visible {
	outline: 2px solid var(--gs-oro);
	outline-offset: 2px;
}

/* ── Cabecera ──────────────────────────────────────────────────────────────── */
.gs-mc__head {
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 12px;
	padding: 22px 24px 18px;
	border-bottom: 1px solid var(--gs-linea);
}

.gs-mc__title {
	font-family: var(--gs-font-display);
	font-weight: 700;
	font-size: 1.4375rem;
	line-height: 1;
	text-transform: uppercase;
	margin: 0;
	color: var(--gs-tinta);
}

.gs-mc__count-line { margin-top: 1px; }

.gs-minicart__count {
	font-family: var(--gs-font-body);
	font-size: 0.71875rem;
	color: var(--gs-gris);
}

.gs-mc__close {
	width: 38px;
	height: 38px;
	border-radius: 9px;
	color: var(--gs-gris);
	display: grid;
	place-items: center;
	flex: 0 0 auto;
	transition: background .18s, color .18s;
}

/* Los `:hover` propios van prefijados por `.gs-portal` (0,3,0) para ganarle al Global Kit
   de Elementor, que emite `.elementor-kit-N button:hover` a 0,2,1 y alcanza al cajón aunque
   esté portaleado a <body>. Cada uno declara fondo Y color: si deja uno sin declarar, es
   justo ese el que el kit rellena. Ver la nota larga en header-base.css. */
.gs-portal .gs-mc__close:hover,
.gs-portal .gs-mc__close:focus { background: var(--gs-hueso); color: var(--gs-tinta); }
.gs-mc__close svg { width: 15px; height: 15px; stroke-width: 1.7; }

/* ── Barra de envío gratis ────────────────────────────────────────────────────── */
/* El JS oculta la barra cuando la tienda no tiene envío gratuito configurado o el carrito
   no se envía. Se declara explícito para que ningún `display` del tema resucite el nodo. */
.gs-mc__ship[hidden] { display: none; }

.gs-mc__ship {
	padding: 14px 24px;
	background: var(--gs-hueso);
	border-bottom: 1px solid var(--gs-linea);
}

.gs-mc__ship-row {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: 8px;
}

.gs-mc__ship-msg {
	font-family: var(--gs-font-body);
	font-size: 0.75rem;
	font-weight: 500;
	color: var(--gs-oro-osc);
}

.gs-mc__ship.is-ok .gs-mc__ship-msg { color: var(--gs-verde); }

.gs-mc__ship-meta {
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 0.5625rem;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--gs-gris);
	white-space: nowrap;
}

.gs-mc__ship-track {
	height: 5px;
	border-radius: var(--gs-r-pill);
	background: var(--gs-track);
	overflow: hidden;
	margin-top: 9px;
}

.gs-mc__ship-fill {
	display: block;
	height: 100%;
	background: linear-gradient(90deg, var(--gs-mc-m1, #8A6528), var(--gs-mc-m2, #C2A370));
	clip-path: inset(0 100% 0 0);
	transition: clip-path .55s var(--gs-e-out), background .3s var(--gs-e-soft);
}

.gs-mc__ship.is-ok .gs-mc__ship-fill {
	background: var(--gs-mc-ok, #3A7D44);
}

/* ── Cuerpo / filas ─────────────────────────────────────────────────────────── */
.gs-mc__body {
	flex: 1 1 auto;
	overflow-y: auto;
	overscroll-behavior: contain;
	padding: 20px 24px;
	scrollbar-width: thin;
	scrollbar-color: #D6CDBB #fff;
}

.gs-minicart__items {
	display: flex;
	flex-direction: column;
}

.gs-mc__row {
	display: flex;
	gap: 13px;
	align-items: flex-start;
	padding: 16px 0;
	border-bottom: 1px solid var(--gs-linea);
}

.gs-mc__row:first-child { padding-top: 0; }
.gs-mc__row:last-child { border-bottom: 0; }

.gs-mc__thumb {
	width: 70px;
	height: 70px;
	border-radius: 10px;
	object-fit: cover;
	border: 1px solid var(--gs-linea);
	background: var(--gs-hueso);
	flex: 0 0 auto;
}

.gs-mc__info {
	flex: 1 1 auto;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 2px;
}

.gs-mc__name {
	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: 0.8125rem;
	line-height: 1.35;
	color: var(--gs-tinta);
	text-decoration: none;
}

.gs-portal .gs-mc__name:hover,
.gs-portal .gs-mc__name:focus { color: var(--gs-oro); background: transparent; }

.gs-mc__variant {
	font-family: var(--gs-font-body);
	font-size: 0.71875rem;
	color: var(--gs-gris);
}

.gs-mc__controls {
	display: flex;
	align-items: center;
	gap: 8px;
	margin-top: 6px;
}

.gs-mc__stepper {
	display: inline-flex;
	align-items: center;
	border: 1px solid var(--gs-linea);
	border-radius: 8px;
	overflow: hidden;
	background: #fff;
}

.gs-mc__step {
	width: 29px;
	height: 29px;
	display: grid;
	place-items: center;
	color: var(--gs-gris);
	font-size: 15px;
	line-height: 1;
	transition: background .15s, color .15s;
}

.gs-portal .gs-mc__step:hover,
.gs-portal .gs-mc__step:focus { background: var(--gs-hueso); color: var(--gs-tinta); }

.gs-mc__qty {
	min-width: 32px;
	text-align: center;
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 0.78125rem;
}

.gs-mc__remove {
	padding: 4px;
	border-radius: 6px;
	color: #988C79;
	display: grid;
	place-items: center;
	transition: color .18s, background .18s;
}

.gs-portal .gs-mc__remove:hover,
.gs-portal .gs-mc__remove:focus { color: var(--gs-rojo); background: var(--gs-rojo-bg); }
.gs-mc__remove svg { width: 14px; height: 14px; }

.gs-mc__prices {
	flex: 0 0 auto;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	text-align: right;
}

.gs-mc__lineprice {
	font-family: var(--gs-font-display);
	font-weight: 700;
	font-size: 1.1875rem;
	letter-spacing: .01em;
	color: var(--gs-oro);
}

.gs-mc__unit {
	font-family: var(--gs-font-body);
	font-size: 0.65625rem;
	color: var(--gs-gris);
	margin-top: -2px;
}

@keyframes gsRowIn {
	from { opacity: 0; transform: translateY(9px); }
	to   { opacity: 1; transform: none; }
}

.gs-mc.is-animating .gs-mc__row {
	animation: gsRowIn .34s var(--gs-e-out) both;
}

/* Aquí vivía `gsRowFlash`: un destello dorado sobre la fila entera al cambiar la cantidad
   o restaurar un producto. Retirado a petición del cliente (se veía como un hover amarillo
   perdido). La fila ya no se tiñe; la animación de entrada `gsRowIn` se conserva. */

/* ── Barra de deshacer ────────────────────────────────────────────────────────── */
/* Es hermana de .gs-mc__body, no hija (si no, `is-empty` la ocultaba justo al borrar el
   último producto). Por eso el margen lateral replica el `padding: 20px 24px` del cuerpo,
   y `flex: 0 0 auto` evita que la columna flex la estire. */
.gs-mc__undo {
	flex: 0 0 auto;
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 12px;
	padding: 11px 13px;
	border: 1px dashed var(--gs-linea);
	border-radius: 10px;
	background: var(--gs-hueso);
	margin: 0 24px 16px;
	animation: gsRowIn .26s var(--gs-e-out) both;
}

.gs-mc__undo[hidden] { display: none; }

.gs-mc__undo-text {
	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: 0.71875rem;
	color: var(--gs-gris);
}

.gs-mc__undo-btn {
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 0.65625rem;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--gs-oro-osc);
	border-bottom: 1px solid rgba(156, 122, 52, .4);
	flex: 0 0 auto;
	transition: color .18s var(--gs-e-soft), border-color .18s var(--gs-e-soft);
}

/* El subrayado es fingido con `border-bottom` (header-base.css impone
   `text-decoration: none !important`), así que el hover tiene que moverlo a mano: si no,
   el texto pasaba a negro y el subrayado se quedaba dorado. Mismo patrón que .gs-sr__all. */
.gs-portal .gs-mc__undo-btn:hover,
.gs-portal .gs-mc__undo-btn:focus {
	color: var(--gs-tinta);
	border-bottom-color: var(--gs-tinta);
	background: transparent;
}

/* ── Footer ──────────────────────────────────────────────────────────────────── */
.gs-mc__foot {
	padding: 18px 24px 22px;
	border-top: 1px solid var(--gs-linea);
	background: var(--gs-crema);
}

.gs-mc__line {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	font-family: var(--gs-font-body);
	font-size: 0.8125rem;
	color: var(--gs-gris);
	margin-bottom: 7px;
}

.gs-minicart__subtotal,
.gs-mc__ship-val {
	color: var(--gs-tinta);
	font-weight: 600;
}

.gs-mc__ship-val.is-free { color: var(--gs-verde); }

.gs-mc__divider {
	height: 1px;
	background: var(--gs-linea);
	margin: 12px 0 13px;
}

.gs-mc__total-line {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	margin-bottom: 16px;
}

.gs-mc__total-label {
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 0.625rem;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--gs-tinta);
}

.gs-minicart__total {
	font-family: var(--gs-font-display);
	font-weight: 700;
	font-size: 1.875rem;
	line-height: 1;
	color: var(--gs-mc-total, #9C7A34);
}

.gs-minicart__mxn {
	font-family: var(--gs-font-body);
	font-weight: 400;
	font-size: 0.75rem;
	color: var(--gs-gris);
	margin-left: 2px;
}

.gs-mc__cta {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	width: 100%;
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 0.78125rem;
	letter-spacing: .1em;
	text-transform: uppercase;
	padding: 15px;
	border-radius: 9px;
	text-decoration: none;
	cursor: pointer;
	transition: transform .16s var(--gs-e-out), background .2s, border-color .2s, color .2s;
}

.gs-mc__cta:active { transform: scale(.985); }

/* El reset de <button> de header-base.css (`.gs-portal button`, 0,1,1) le gana al relleno
   declarado arriba (`.gs-mc__cta`, 0,1,0). Se notaba solo en el estado vacío: su CTA es un
   <button> y salía aplastado, mientras el del footer, que es un <a>, conservaba el suyo.
   Estas dos reglas suben a 0,2,1 para devolverles su relleno. */
.gs-portal button.gs-mc__cta { padding: 15px; }
.gs-portal button.gs-mc__remove { padding: 4px; }

.gs-mc__pay,
.gs-mc__pay:focus {
	background: var(--gs-tinta) !important;
	color: #fff !important;
	margin-bottom: 9px;
}

.gs-portal .gs-mc__pay:hover,
.gs-portal .gs-mc__pay:focus { background: var(--gs-tinta-hover) !important; color: #fff !important; }

.gs-mc__view,
.gs-mc__view:focus {
	background: transparent !important;
	border: 1.5px solid var(--gs-linea);
	color: var(--gs-gris) !important;
	font-weight: 600;
	font-size: 0.71875rem;
	padding: 12px;
}

.gs-portal .gs-mc__view:hover,
.gs-portal .gs-mc__view:focus { border-color: var(--gs-oro); background: transparent !important; color: var(--gs-oro-osc) !important; }

/* ── Estado vacío ─────────────────────────────────────────────────────────────── */
.gs-mc__empty {
	display: none;
	flex: 1 1 auto;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	text-align: center;
	padding: 44px 26px;
}

.gs-mc.is-empty .gs-mc__empty { display: flex; }
.gs-mc.is-empty .gs-mc__body,
.gs-mc.is-empty .gs-mc__foot,
.gs-mc.is-empty .gs-mc__ship { display: none; }

.gs-mc__empty-ring {
	width: 76px;
	height: 76px;
	border-radius: var(--gs-r-pill);
	border: 1.5px dashed var(--gs-linea);
	display: grid;
	place-items: center;
	color: var(--gs-oro-clr);
	margin-bottom: 20px;
}

.gs-mc__empty-ring svg { width: 30px; height: 30px; }

.gs-mc__empty-title {
	font-family: var(--gs-font-display);
	font-weight: 700;
	font-size: 1.375rem;
	line-height: 1;
	text-transform: uppercase;
	margin: 0 0 8px;
	color: var(--gs-tinta);
}

.gs-mc__empty-text {
	font-family: var(--gs-font-body);
	font-size: 0.8125rem;
	color: var(--gs-gris);
	max-width: 270px;
	margin: 0 0 22px;
}

.gs-mc__chips {
	display: flex;
	gap: 8px;
	flex-wrap: wrap;
	justify-content: center;
	margin-bottom: 22px;
}

.gs-mc__chip {
	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: 0.6875rem;
	letter-spacing: .09em;
	text-transform: uppercase;
	padding: 8px 14px;
	border: 1px solid var(--gs-linea);
	border-radius: var(--gs-r-pill);
	color: var(--gs-gris);
	text-decoration: none;
	transition: border-color .18s, color .18s, background .18s;
}

.gs-portal .gs-mc__chip:hover,
.gs-portal .gs-mc__chip:focus { border-color: var(--gs-oro); color: var(--gs-oro-osc); background: #fff; }

.gs-mc__empty .gs-mc__cta { max-width: 250px; }

@media (prefers-reduced-motion: reduce) {
	.gs-mc,
	.gs-mc__panel,
	.gs-mc__scrim,
	.gs-mc__ship-fill,
	.gs-minicart__badge,
	.gs-mc__row,
	.gs-mc__undo {
		transition-duration: .01ms;
		animation-duration: .01ms;
	}
}

/* ---- tarjetas.css ---- */
/**
 * GS Tarjetas de Producto. Handle 'gs-tarjetas' (deps: gs-tokens, gs-fonts).
 *
 * Parrilla de tarjetas de producto. Prefijo propio `.gsp-` para no colisionar con los
 * widgets de header (`.gs-`). Las reglas se escriben con doble clase
 * (`.gsp-cards .gsp-card__x`) para ganar por especificidad a los temas, que suelen
 * estilar `a`, `button`, `img` y `h3` de forma agresiva dentro del contenido.
 *
 * El widget NO pinta encabezado ni padding de sección: solo el grid. El ancho máximo de
 * 80rem es de maquetación, para alinear con el header y el resto de secciones del sitio.
 *
 * ── Por qué todo pasa por variables ──────────────────────────────────────────
 * Esta hoja tenía los colores y las familias tipográficas escritos como literales, a
 * diferencia de `mosaico.css` o `videos.css` (deuda registrada en `PENDIENTES.md`). Ahora
 * cada valor sale de un token en `tokens.css`, y además se expone como variable propia
 * `--gsp-c-*` sobre la raíz del componente para que los controles de Elementor puedan
 * escribirla — que es lo que exige `INSTRUCCIONES.md` §3.3 en cuanto una propiedad tiene
 * control Y el CSS la reescribe en algún estado (aquí: `.is-sale`, los tres de stock y el
 * `[disabled]:hover` del botón).
 *
 * Los defaults se declaran **en `.gsp-cards`, no en `:root`**: son del componente, no del
 * sistema, y `tokens.css` se sirve en TODA la web (está fuera del bundle), así que meter ahí
 * veinte variables de tarjeta las mandaría a la portada y al carrito.
 *
 * Cada `var()` lleva además el literal de siempre como respaldo. Es red doble a coste cero:
 * si el bloque de defaults no llegara —una hoja a medias, un orden inesperado del bundle— la
 * tarjeta se ve exactamente igual que antes de este cambio.
 *
 * ── Lo que esta hoja NO decide ───────────────────────────────────────────────
 * El `gap` y las columnas son suyos solo cuando la parrilla va suelta. Dentro del archivo de
 * categoría manda `.gsa .gsp-cards` y en relacionados `.gsp-p .gsp-rel__grid`, los dos a
 * (0,2,0) y por tanto por encima de lo que se declare aquí. No es accidente ni orden de
 * hojas: es especificidad, y es el motivo de que el control de separación solo exista en el
 * widget de parrilla suelta.
 */

.gsp-cards {
	/* ── Contenedor ──────────────────────────────────────────────────── */
	--gsp-c-gap: 18px;

	/* ── Tarjeta ─────────────────────────────────────────────────────── */
	--gsp-c-bg: #fff;
	--gsp-c-radio: var(--gs-r-xl, 14px);
	--gsp-c-borde: var(--gs-linea, #E8E2D9);
	--gsp-c-borde-on: var(--gs-oro, #9C7A34);

	/* ── Zona de imagen ──────────────────────────────────────────────── */
	--gsp-c-media-h: 220px;
	--gsp-c-media-bg: #fff;
	--gsp-c-badge-bg: var(--gs-oferta, #E8534A);
	--gsp-c-badge-txt: #fff;

	/* ── Textos ──────────────────────────────────────────────────────── */
	--gsp-c-cat: var(--gs-txt-3, #888);
	--gsp-c-nombre: var(--gs-tinta, #0A0A0A);
	--gsp-c-precio: var(--gs-tinta-precio, #111);
	--gsp-c-precio-oferta: var(--gs-oferta, #E8534A);
	/* La única MEDIDA de texto que sale por variable, y no por capricho: la container query
	   del carrusel necesita poder ponerle techo, y para eso el control no puede escribir
	   `font-size` (§3.3). Las demás tipografías sí escriben la propiedad. */
	--gsp-c-precio-tam: 26px;
	--gsp-c-divisa: var(--gs-txt-3, #888);
	--gsp-c-regular: var(--gs-tachado, #C7C7C7);

	/* ── Stock ───────────────────────────────────────────────────────── */
	--gsp-c-stock-alto: var(--gs-verde, #3A7D44);
	--gsp-c-stock-bajo: var(--gs-ambar, #D4820A);
	--gsp-c-stock-agotado: var(--gs-agotado, #B0B0B0);

	/* ── Botón ───────────────────────────────────────────────────────── */
	--gsp-c-btn-bg: var(--gs-tinta, #0A0A0A);
	--gsp-c-btn-txt: #fff;
	--gsp-c-btn-bg-on: var(--gs-oro, #9C7A34);
	--gsp-c-btn-txt-on: var(--gs-tinta, #0A0A0A);
	--gsp-c-btn-r: 8px;

	display: grid;
	grid-template-columns: repeat(var(--gsp-cols, 4), 1fr);
	gap: var(--gsp-c-gap, 18px);
	width: 100%;
	max-width: 80rem;
	margin-inline: auto;
	/* El tema no debe meter viñetas ni sangrías si envuelve esto en una lista. */
	padding: 0;
	list-style: none;
}

/* Bajada de columnas. Los valores llegan calculados desde PHP: una parrilla de 2 nunca
   sube a 3 en tablet, porque `repeat()` no admite min()/calc(). */
@media (max-width: 1200px) {
	.gsp-cards {
		grid-template-columns: repeat(var(--gsp-cols-lg, 3), 1fr);
	}
}

@media (max-width: 900px) {
	.gsp-cards {
		grid-template-columns: repeat(var(--gsp-cols-md, 2), 1fr);
	}
}

@media (max-width: 560px) {
	.gsp-cards {
		grid-template-columns: repeat(var(--gsp-cols-sm, 1), 1fr);
	}
}

/* ── Carrusel ─────────────────────────────────────────────────────────────────
   TODO lo de aquí abajo cuelga de `.gsp-cards--carrusel`, y esa acotación no es
   estilo: es lo que impide romper otros dos widgets.

   `.gsp-cards` la comparten `gs_tarjetas_producto`, `gs_product_related` y
   `gs_archivo_categoria`. Los dos últimos redeclaran `grid-template-columns` y
   `gap` con más especificidad, así que de eso están a salvo — pero **ninguno
   redeclara `display`**. Tocar el `display: grid` de la regla base los convertiría
   a los tres en carrusel a la vez, y en el archivo además rompería su modo lista.

   El motor es el scroll nativo, no un arrastre propio. `overflow-x` + `scroll-snap`
   ya traen seguimiento 1:1 del dedo, inercia, rebote en los extremos y la
   posibilidad de agarrar el riel a media animación. Un arrastre escrito a mano
   imita esas cuatro cosas y casi siempre las imita peor. Es lo mismo que ya hacen
   el riel de volumen de la vista rápida y el carrusel de vídeos. */

.gsp-cards--carrusel {
	display: flex;
	grid-template-columns: none;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	/* Que arrastrar el riel hasta el tope no arrastre además la página detrás. Es
	   también lo que evita que el carrusel siga moviéndose con la ventana de vista
	   rápida abierta: el bloqueo de scroll pone `overflow: hidden` en el <html>, y
	   eso detiene el documento, no a un contenedor hijo que puede desplazarse. */
	overscroll-behavior-x: contain;
	/* La barra horizontal debajo de las tarjetas ensucia y en táctil no aporta: el
	   recorte de la siguiente tarjeta ya comunica que hay más a la derecha. */
	scrollbar-width: none;
	-ms-overflow-style: none;
}

.gsp-cards--carrusel::-webkit-scrollbar {
	display: none;
}

/* Cuántas se ven. Se resuelve en una variable propia para que el ancho de la tarjeta
   sea UNA sola regla y no tres repetidas por breakpoint.

   El respaldo encadenado de `var()` es lo que da la herencia que se espera del panel:
   un tamaño que el operador deja sin tocar no vale cero, vale «lo mismo que el de
   arriba». Elementor no guarda nada en ese caso y la variable ni se emite. */

.gsp-cards--carrusel {
	--gsp-por-vista: var(--gsp-cols, 4);
}

/* 1024 y 767 son los cortes de Elementor, que son los que usan los controles
   responsive de este widget (`card_gap`, `card_media_alto` y ahora `columns`). NO son
   los de la parrilla (1200/900/560), que se calculan en PHP y se quedan como están
   porque esa hoja la comparten otros widgets. */
@media (max-width: 1024px) {
	.gsp-cards--carrusel {
		--gsp-por-vista: var(--gsp-cols-t, var(--gsp-cols, 3));
	}
}

@media (max-width: 767px) {
	.gsp-cards--carrusel {
		--gsp-por-vista: var(--gsp-cols-m, var(--gsp-cols-t, var(--gsp-cols, 2)));
	}
}

/* El ancho exacto para que entren N justas: se reparte el ancho visible menos los
   N-1 huecos. Sin asomo de la siguiente, que es lo pedido.

   `min-width: 0` porque un hijo de flex no baja de su contenido por defecto, y el
   nombre del producto puede ser larguísimo («[PUMA] Puma negros con tigre blanco…»):
   sin esto una tarjeta se ensancharía y descuadraría el paso del carrusel. */

.gsp-cards--carrusel > .gsp-card {
	flex: 0 0 calc(
		(100% - (var(--gsp-por-vista) - 1) * var(--gsp-c-gap, 18px)) / var(--gsp-por-vista)
	);
	min-width: 0;
	scroll-snap-align: start;

	/* PRIMERA container query del plugin (INSTRUCCIONES.md §1.3: el primer ejemplo de un
	   patrón se declara como tal). La tarjeta se declara contenedor de consulta para que
	   su interior se adapte a SU PROPIO ancho.

	   Y tiene que ser el ancho de la tarjeta, no el de la pantalla: con 2 por vista en un
	   móvil de 390px la tarjeta mide 176px y necesita compactarse, pero con 1 por vista
	   en esa misma pantalla mediría 360px y compactarla sería estropearla. Una media query
	   no puede distinguir esos dos casos porque el ancho de pantalla es el mismo. */
	container: gsp-card / inline-size;
}

/* ── El interior a lo ancho de la tarjeta ─────────────────────────────────────
   El problema real, medido: la fila de precio necesita ~168px —«$800» a 26px con
   `nowrap`, «MXN», y «● En stock» también con `nowrap`— y una tarjeta de 176px
   ofrece 140px de interior tras sus 18px de padding a cada lado. Nada podía
   encoger, así que se desbordaba y el `overflow: hidden` de la tarjeta lo
   recortaba: el precio se comía el stock y el botón salía como «AÑADIR AL CARRIT».

   Este primer arreglo va FUERA de la container query a propósito: es la red de
   seguridad. Aunque un navegador no soporte `@container`, el precio y el stock
   dejan de pisarse porque el stock se va a su propia línea en cuanto no quepa. */

.gsp-cards.gsp-cards--carrusel .gsp-card__row {
	flex-wrap: wrap;
	row-gap: 6px;
}

@container gsp-card (max-width: 250px) {

	/* (0,3,0) porque las reglas base son (0,2,0) y una container query NO añade
	   especificidad: sin subirla, nada de esto se aplicaría. */

	/* El stock ocupa su propia línea entera en vez de disputarle el sitio al precio. */
	.gsp-cards.gsp-cards--carrusel .gsp-card__stock {
		flex: 1 0 100%;
	}

	/* Deja bajar de línea al precio TACHADO cuando hay oferta. Ojo con lo que este
	   `flex-wrap` NO hace, porque el comentario anterior lo daba por hecho y era falso:
	   la divisa «MXN» va dentro del `.gsp-card__price` y no es un ítem flex, así que
	   aquí no se la alcanza — de ella se ocupa el tope de tamaño de más abajo. */
	.gsp-cards.gsp-cards--carrusel .gsp-card__prices {
		flex-wrap: wrap;
		row-gap: 2px;
	}

	/* Un TECHO al tamaño del precio, no una imposición.

	   Durante un tiempo esto no se pudo escribir: el control `card_precio_tipo` emitía
	   `font-size` sobre `.gsp-card__price` y Elementor lo saca a (0,4,0), que se come
	   cualquier regla de esta hoja —incluida una de (0,3,0) dentro de una container query,
	   porque una container query NO añade especificidad—. Un intento de bajarlo a 20px
	   quedó de código muerto: la regla existía y no aplicaba nunca.

	   Ya no: ese control emite `--gsp-c-precio-tam` sobre `.gsp-cards` (INSTRUCCIONES.md §3.3),
	   la regla base consume la variable y esta de aquí, que es (0,3,0), gana.

	   `min()` y no un valor a secas porque el tamaño sigue siendo de quien monta la página:
	   si ya lo bajó a 18px en móvil, `min(18px, …)` respeta sus 18px — un `font-size` fijo
	   se los SUBIRÍA. Esto solo recorta por arriba.

	   ── De dónde sale el 11, medido y no estimado ─────────────────────────────
	   Lo que hay que hacer caber no es el importe: es el importe MÁS la divisa, porque
	   `CardRenderer` mete el `<span class="gsp-card__cur">MXN</span>` DENTRO del propio
	   `.gsp-card__price`, y ese span lleva `white-space: nowrap`. La divisa no es un ítem
	   flex, así que el `flex-wrap` de arriba no la alcanza y NO puede bajar de línea.

	   Y la divisa no escala con el precio: son 12px fijos. Así que el ancho no es
	   proporcional al tamaño, es `5,342 × tamaño + 32`. De ahí los 171px a 26px que ya
	   estaban medidos en PENDIENTES §8 bis — no eran del importe solo.

	   Interior real de la tarjeta a 360px con 2 por vista: la tarjeta mide 159px, menos
	   1px de borde a cada lado y 14px de padding a cada lado = **129px**.

	   Medido con «$1,234,567 MXN» en las dos anchuras que importan:

	     tope     tarjeta 159px            tarjeta 174px
	     20px     139px → se sale 10px     145px → cabe justo
	     11cqi    124px → cabe, 5px libres 133px → cabe
	     12cqi    133px → se sale 4px      143px → cabe

	   `11cqi` es el mayor que entra en las dos. Un tope FIJO no serviría igual de bien:
	   recortaría también las tarjetas de ~240px, donde 26px entra de sobra. Con `11cqi`
	   el tope se desactiva solo a partir de 238px de tarjeta.

	   Sin suelo (`max(16px, …)`) a propósito: por debajo de ~135px de tarjeta el suelo
	   forzaría un tamaño MAYOR del que cabe, o sea desbordaría a cambio de nada. A esos
	   anchos la tarjeta ya está rota por el nombre y el botón, no por el precio. */
	.gsp-cards.gsp-cards--carrusel .gsp-card__price {
		font-size: min(var(--gsp-c-precio-tam, 26px), 11cqi);
	}

	/* El icono del carrito se retira: cuesta 23px entre él y su hueco, que es justo lo
	   que le falta a la etiqueta para caber en una línea. Entre enseñar el dibujo de un
	   carrito y poder leer «AÑADIR AL CARRITO» entero, gana el texto — el botón ya está
	   dentro de una tarjeta de producto y nadie duda de para qué sirve. */
	.gsp-cards.gsp-cards--carrusel .gsp-card__ico {
		display: none;
	}

	.gsp-cards.gsp-cards--carrusel .gsp-card__btn {
		letter-spacing: .04em;
		padding-inline: 8px;
	}

	/* Menos padding: 18px a cada lado se llevan el 20% del ancho de una tarjeta de 176px. */
	.gsp-cards.gsp-cards--carrusel .gsp-card__body {
		padding: 14px 14px 16px;
	}
}

/* ── Puntos ───────────────────────────────────────────────────────────────────
   Los pinta el JS, porque cuántos hay depende del ancho y eso PHP no lo sabe. */

.gsp-cards__dots {
	display: flex;
	justify-content: center;
	align-items: center;
	gap: 8px;
	margin-top: 18px;
	padding: 0;
}

.gsp-cards__dot {
	width: 8px;
	height: 8px;
	padding: 0;
	border: 0;
	border-radius: var(--gs-r-pill, 999px);
	background-color: var(--gs-linea, #E8E2D9);
	cursor: pointer;
	/* El área de pulsación real es de 24px aunque el punto mida 8: un objetivo de 8px
	   es imposible de acertar con el pulgar. Se agranda con un pseudo-elemento para
	   no separar los puntos entre sí. */
	position: relative;
	transition: background-color .2s var(--gs-e-soft, ease);
}

.gsp-cards__dot::after {
	content: '';
	position: absolute;
	inset: -8px;
}

/* El estado vive en el atributo ARIA y en ningún otro sitio: no hay una clase
   `is-activo` que pueda desincronizarse de lo que anuncia el lector de pantalla.
   Es como lo hace el carrusel de banners.

   Mismo punto que los demás, solo que dorado. Llegó a alargarse a 22px para dar una
   segunda señal además del color —quien no distingue el dorado del beige se queda
   sin indicador—, pero en pantalla parecía una píldora entre puntos y desentonaba.
   La accesibilidad la sigue cubriendo `aria-current`, que es lo que lee un lector
   de pantalla; para quien ve, el contraste entre #9C7A34 y #E8E2D9 es suficiente. */

.gsp-cards__dot[aria-current="true"] {
	background-color: var(--gs-oro, #9C7A34);
}

/* (0,3,0) y declarando fondo Y color, aunque aquí solo cambie el fondo: lo que se
   deje sin declarar es exactamente lo que rellena el Global Kit de Elementor, que
   emite sus estados de `button` con (0,2,1) desde el <body> (INSTRUCCIONES §3.1). */

.gsp-cards--carrusel ~ .gsp-cards__dots .gsp-cards__dot:hover,
.gsp-cards--carrusel ~ .gsp-cards__dots .gsp-cards__dot:focus,
.gsp-cards--carrusel ~ .gsp-cards__dots .gsp-cards__dot:focus-visible {
	background-color: var(--gs-oro-clr, #C2A370);
	color: inherit;
}

.gsp-cards--carrusel ~ .gsp-cards__dots .gsp-cards__dot[aria-current="true"]:hover,
.gsp-cards--carrusel ~ .gsp-cards__dots .gsp-cards__dot[aria-current="true"]:focus,
.gsp-cards--carrusel ~ .gsp-cards__dots .gsp-cards__dot[aria-current="true"]:focus-visible {
	background-color: var(--gs-oro, #9C7A34);
	color: inherit;
}

.gsp-cards__dot:focus-visible {
	outline: 2px solid var(--gs-oro, #9C7A34);
	outline-offset: 4px;
}

/* ── Tarjeta ─────────────────────────────────────────────────────────────── */

.gsp-cards .gsp-card {
	display: block;
	border: 1px solid var(--gsp-c-borde, #E8E2D9);
	border-radius: var(--gsp-c-radio, 14px);
	overflow: hidden;
	background-color: var(--gsp-c-bg, #fff);
	transition: border-color .2s ease;
	/* Anti-tema: nada de subrayados ni colores heredados del enlace. */
	text-decoration: none;
	color: inherit;
	box-shadow: none;
}

/* Fondo y color repetidos aunque no cambien: la tarjeta es un `<a>` y el Global Kit emite
   `.elementor-kit-N a:focus`/`a:hover` con (0,2,1). Esta regla es (0,3,0) y le gana, pero solo en
   lo que declara: lo que se dejara fuera lo rellenaba el Kit, y aquí eso significa el color de
   marca pintado sobre la tarjeta ENTERA. */
.gsp-cards .gsp-card:focus-visible,
.gsp-cards .gsp-card:focus {
	border-color: var(--gsp-c-borde-on, #9C7A34);
	background-color: var(--gsp-c-bg, #fff);
	color: inherit;
	text-decoration: none;
	outline: 2px solid var(--gsp-c-borde-on, #9C7A34);
	outline-offset: 2px;
}

/* El realce del ratón se acota a puntero fino. En táctil `:hover` se queda PEGADO tras el
   toque: la tarjeta se quedaba con el borde dorado y la imagen ampliada hasta que tocabas
   otra cosa, y al volver atrás en el historial seguía así. Es la MISMA trampa que ya
   documenta y cierra `mosaico.css` (§ "En táctil el feedback es el estado activo"); aquí
   no se había cerrado, y la parrilla es la superficie que más se toca del sitio.
   `:focus-visible` se queda fuera a propósito: el teclado sí debe realzar en cualquier
   dispositivo. */
@media (hover: hover) and (pointer: fine) {

	.gsp-cards .gsp-card:hover {
		border-color: var(--gsp-c-borde-on, #9C7A34);
		background-color: var(--gsp-c-bg, #fff);
		color: inherit;
		text-decoration: none;
	}

	.gsp-cards .gsp-card:hover .gsp-card__img {
		transform: scale(1.08);
	}
}

/* ── Zona de imagen ──────────────────────────────────────────────────────── */

.gsp-cards .gsp-card__media {
	position: relative;
	height: var(--gsp-c-media-h, 220px);
	background-color: var(--gsp-c-media-bg, #fff);
	border-bottom: 1px solid var(--gsp-c-borde, #E8E2D9);
	overflow: hidden;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 16px;
}

.gsp-cards .gsp-card__img {
	max-width: 100%;
	max-height: 100%;
	width: auto;
	height: auto;
	object-fit: contain;
	display: block;
	transition: transform .35s ease;
}

.gsp-cards .gsp-card__badge {
	position: absolute;
	top: 12px;
	left: 12px;
	z-index: 2;
	background-color: var(--gsp-c-badge-bg, #E8534A);
	color: var(--gsp-c-badge-txt, #fff);
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 700;
	font-size: 10px;
	line-height: 1;
	letter-spacing: .1em;
	text-transform: uppercase;
	padding: 4px 10px;
	border-radius: 4px;
}

/* ── Cuerpo ──────────────────────────────────────────────────────────────── */

.gsp-cards .gsp-card__body {
	padding: 18px 18px 22px;
}

.gsp-cards .gsp-card__cat {
	display: block;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 600;
	font-size: 9.5px;
	line-height: 1.2;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--gsp-c-cat, #888);
}

.gsp-cards .gsp-card__name {
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 600;
	font-size: 14px;
	line-height: 1.35;
	margin: 8px 0 8px;
	color: var(--gsp-c-nombre, #0A0A0A);
	/* Dos líneas SIEMPRE: máximo y mínimo. El recorte ya estaba, el suelo no, y sin él la
	   promesa quedaba a medias — «Dandy» ocupaba una línea y «[PUMA] Puma negros con tigre
	   blanco» dos, así que el precio, el stock y el botón de tarjetas vecinas caían a
	   alturas distintas. Reservar el hueco de la segunda línea aunque no se use es lo que
	   hace que todo lo que va debajo coincida.

	   `2lh` y no un número de píxeles porque el interlineado lo manda `card_nombre_tipo`
	   desde el panel (0,4,0): `lh` es la altura de línea REAL, así que el hueco sigue al
	   control en vez de quedarse desfasado en cuanto alguien lo toque.

	   La declaración en `em` va delante como respaldo para los navegadores sin `lh`
	   (Safari 16.0-16.3 ya tenía container queries y aún no tenía `lh`): 2 × 1,35 = 2,7em,
	   correcto mientras nadie cambie el interlineado, que es el caso normal. */
	min-height: 2.7em;
	min-height: 2lh;

	display: -webkit-box;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	/* Anti-tema: los h3 suelen traer tamaño, peso y padding propios. */
	padding: 0;
	text-transform: none;
	letter-spacing: 0;
}

.gsp-cards .gsp-card__row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
}

.gsp-cards .gsp-card__prices {
	display: flex;
	align-items: baseline;
	gap: 8px;
	min-width: 0;
}

/* El precio normal va en NEGRO, no en dorado: el oro queda reservado para acentos, y en una
   parrilla de tarjetas un precio dorado en cada una competía con el badge de oferta y con el
   propio nombre del producto. El default de `--gsp-c-precio` es `--gs-tinta-precio` (#111, un
   pelo más claro que la tinta), que es el mismo token que usa el precio de la ficha de
   producto: el mismo importe se lee del mismo color en la parrilla y al abrir el producto. */
.gsp-cards .gsp-card__price {
	font-family: var(--gs-font-display, 'Archivo', 'Arial Narrow', system-ui, sans-serif);
	font-weight: 700;
	/* Variable y no literal porque el tamaño lo escribe `card_precio_tipo` como
	   `--gsp-c-precio-tam` — así esta regla se queda en (0,2,0) y la container query del
	   carrusel puede ponerle techo. El 26px de respaldo es el default del control. */
	font-size: var(--gsp-c-precio-tam, 26px);
	line-height: 1.1;
	color: var(--gsp-c-precio, #111);
	white-space: nowrap;
}

/* El estado escribe la PROPIEDAD y el control escribe la VARIABLE: si el control de color de
   precio emitiera `color` directamente (0,4,0) se comería también al producto en oferta. */
.gsp-cards .gsp-card__price.is-sale {
	color: var(--gsp-c-precio-oferta, #E8534A);
}

.gsp-cards .gsp-card__cur {
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-size: 12px;
	font-weight: 400;
	color: var(--gsp-c-divisa, #888);
	letter-spacing: 0;
}

.gsp-cards .gsp-card__regular {
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-size: 13px;
	font-weight: 400;
	color: var(--gsp-c-regular, #C7C7C7);
	text-decoration: line-through;
	white-space: nowrap;
}

/* ── Stock ───────────────────────────────────────────────────────────────── */

.gsp-cards .gsp-card__stock {
	display: flex;
	align-items: center;
	gap: 5px;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 600;
	font-size: 10px;
	line-height: 1.2;
	white-space: nowrap;
	color: var(--gsp-c-stock-alto, #3A7D44);
}

.gsp-cards .gsp-card__dot {
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background-color: currentColor;
	flex: 0 0 7px;
}

/* Tres estados, tres variables. Misma razón que en el precio de oferta: la propiedad la pone
   el estado y el control solo mueve la variable. */
.gsp-cards .gsp-card__stock.is-alto {
	color: var(--gsp-c-stock-alto, #3A7D44);
}

.gsp-cards .gsp-card__stock.is-bajo {
	color: var(--gsp-c-stock-bajo, #D4820A);
}

.gsp-cards .gsp-card__stock.is-agotado {
	color: var(--gsp-c-stock-agotado, #B0B0B0);
}

/* ── Botón ───────────────────────────────────────────────────────────────── */

.gsp-cards .gsp-card__btn {
	width: 100%;
	margin-top: 14px;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 700;
	font-size: 11px;
	line-height: 1;
	letter-spacing: .1em;
	text-transform: uppercase;
	padding: 12px;
	border: 1px solid var(--gsp-c-btn-bg, #0A0A0A);
	border-radius: var(--gsp-c-btn-r, 8px);
	background-color: var(--gsp-c-btn-bg, #0A0A0A);
	color: var(--gsp-c-btn-txt, #fff);
	cursor: pointer;
	transition: background-color .2s, border-color .2s, color .2s;
	/* Anti-tema: los botones de tema traen sombras, min-height y text-shadow. */
	box-shadow: none;
	text-shadow: none;
	min-height: 0;
	appearance: none;
	-webkit-appearance: none;
}

/* ── Estados del botón, y el ORDEN entre ellos es el mecanismo ──────────────
   Esto era UNA sola regla —`:hover, :focus-visible, :focus` con el dorado— y de ahí salía un
   bug que se veía a simple vista: `cerrar()` de la vista rápida DEVUELVE el foco al botón que
   la abrió (lo exige INSTRUCCIONES §6, y está bien hecho), así que al cerrar el modal el botón
   se quedaba pintado de dorado, como si siguiera pulsado, hasta que tocaras otra cosa.
   Medido: tras cerrar, `document.activeElement` es ese botón.

   En táctil había un segundo camino al mismo sitio: el `:hover` se queda PEGADO tras el toque
   —hasta que tocas en otro lado— y el hover de este botón no estaba acotado a dispositivos con
   puntero.

   El reparto que arregla los dos:
     :hover          → dorado, pero solo donde el hover existe de verdad.
     :active         → dorado mientras se mantiene pulsado, en cualquier dispositivo.
     :focus          → NUNCA rellena: se ancla al reposo.
     :focus-visible  → aro dorado, sin relleno.

   Por qué `(hover: hover)` a secas y NO `and (pointer: fine)`, que es lo que usa
   `header-base.css`: las dos ramas tienen que ser EXHAUSTIVAS o queda un hueco sin escudo. Un
   táctil que declare `hover: hover` con `pointer: coarse` no entraría en ninguna de las dos, y
   un elemento con color propio y sin regla que lo defienda es justo por donde se cuela el
   Global Kit (§3.1 regla 2). `hover` solo puede valer `hover` o `none`: así no hay hueco. */

@media (hover: hover) {

	.gsp-cards .gsp-card__btn:hover {
		background-color: var(--gsp-c-btn-bg-on, #9C7A34);
		border-color: var(--gsp-c-btn-bg-on, #9C7A34);
		color: var(--gsp-c-btn-txt-on, #0A0A0A);
	}

	/* Foco SIN el ratón encima: es el clic que ya soltaste, y el foco que le devuelve la vista
	   rápida al cerrarse. Vuelve al reposo. Va a (0,4,0) porque con (0,3,0) empataría con el
	   `:hover` de arriba y ganaría por orden también cuando SÍ hay ratón encima, que es cuando
	   el dorado debe verse. El `:not()` puntúa (§3.1 regla 7). */
	.gsp-cards .gsp-card__btn:focus:not(:hover) {
		background-color: var(--gsp-c-btn-bg, #0A0A0A);
		border-color: var(--gsp-c-btn-bg, #0A0A0A);
		color: var(--gsp-c-btn-txt, #fff);
	}
}

/* El ESCUDO del táctil, y no es decorativo: aquí el `:hover` se queda pegado tras el toque y el
   foco vuelve al botón al cerrar la vista rápida. Los dos anclados al reposo, declarando fondo
   Y color —el que dejes sin declarar es exactamente el que el Kit rellena (§3.1 regla 2)—. */

@media (hover: none) {

	.gsp-cards .gsp-card__btn:hover,
	.gsp-cards .gsp-card__btn:focus {
		background-color: var(--gsp-c-btn-bg, #0A0A0A);
		border-color: var(--gsp-c-btn-bg, #0A0A0A);
		color: var(--gsp-c-btn-txt, #fff);
	}
}

/* La pulsación. Sustituye al `transform: scale(.985)` que había aquí: se pidió color y no
   hundimiento. Es la única señal en táctil de que el botón recibió el toque, y sirve porque un
   `:active` NO se queda pegado — se suelta al levantar el dedo, que es justo lo que le faltaba
   al `:hover`.

   Va la última y fuera de las dos ramas, a propósito. El `:not([disabled])` hace dos cosas: la
   sube a (0,4,0) para que le gane al ancla de `:focus:not(:hover)` —si no, pulsar con el
   teclado no se vería— y deja fuera al agotado sin necesitar una regla aparte. */
.gsp-cards .gsp-card__btn:not([disabled]):active {
	background-color: var(--gsp-c-btn-bg-on, #9C7A34);
	border-color: var(--gsp-c-btn-bg-on, #9C7A34);
	color: var(--gsp-c-btn-txt-on, #0A0A0A);
}

/* El aro del teclado, sin relleno. Usa `--gs-oro` y NO `--gsp-c-btn-bg-on`: ese local es un
   control de Elementor y la tienda puede ponerlo negro —en la página de pruebas lo está—, y
   entonces el aro sería invisible sobre un botón negro. Mismo criterio que
   `.gsp-cards__dot:focus-visible`. */
.gsp-cards .gsp-card__btn:focus-visible {
	outline: 2px solid var(--gs-oro, #9C7A34);
	outline-offset: 2px;
}

.gsp-cards .gsp-card__btn[disabled] {
	opacity: .5;
	cursor: not-allowed;
}

/* Un agotado no debe cambiar de color al pasar por encima: sigue sin poder comprarse. Declara
   fondo Y color, que es lo que impide que el Global Kit rellene el que se deje sin declarar. */
.gsp-cards .gsp-card__btn[disabled]:hover,
.gsp-cards .gsp-card__btn[disabled]:focus {
	background-color: var(--gsp-c-btn-bg, #0A0A0A);
	border-color: var(--gsp-c-btn-bg, #0A0A0A);
	color: var(--gsp-c-btn-txt, #fff);
}

.gsp-cards .gsp-card__ico {
	width: 15px;
	height: 15px;
	flex: 0 0 15px;
	fill: currentColor;
	display: block;
}

/* Estado transitorio tras añadir por AJAX: el ícono estorba al tick. */
.gsp-cards .gsp-card__btn.is-added .gsp-card__ico,
.gsp-cards .gsp-card__btn.is-adding .gsp-card__ico {
	display: none;
}

/* Red de seguridad: el enlace "Ver carrito" que WooCommerce (o cualquier plugin que
   escuche `added_to_cart`) inserta detrás del botón. La tarjeta ya lleva su propio CTA y
   ese enlace hereda los estilos del tema, así que no debe verse. El JS de este widget ya
   evita que Woo lo genere; esto cubre a terceros. */
.gsp-cards .gsp-card .added_to_cart,
.gsp-cards .gsp-card .wc-forward {
	display: none !important;
}

@media (prefers-reduced-motion: reduce) {

	.gsp-cards .gsp-card,
	.gsp-cards .gsp-card__img,
	.gsp-cards .gsp-card__btn {
		transition: none;
	}

	.gsp-cards .gsp-card:hover .gsp-card__img {
		transform: none;
	}

	/* El punto solo transiciona su COLOR, que no es desplazamiento y no marea: se acorta
	   en vez de anularse, porque es la única señal de en qué grupo estás y quitarla
	   dejaría el carrusel sin indicador. No hay nada más que anular aquí — el activo
	   llegó a ensancharse y eso sí habría que haberlo cortado, pero ya no lo hace. */
	.gsp-cards__dot {
		transition-duration: .01ms;
	}
}

/* El `:active` del botón NO se anula aquí, y es deliberado. «Movimiento reducido» pide menos
   movimiento, y ese `:active` ya no mueve nada: era un `transform: scale(.985)` y ahora es un
   cambio de color, que no desplaza ni marea. La regla de arriba le quita su transición, así
   que el color entra seco. Quitarlo dejaría al botón de compra sin ninguna señal de que
   recibió la pulsación, y en táctil es la única que tiene. Lo que sí se va es el zoom del 8 %
   de la imagen, que es movimiento de verdad. */

/* ── El Kit tiñe el `:focus` a secas ─────────────────────────────────────────
   `:focus-visible` NO casa al pulsar con el ratón, y `.elementor-kit-N a:focus` /
   `button:focus` sí, con (0,2,1): al hacer clic, el elemento se quedaba con el color del
   Kit hasta perder el foco. Este gemelo va APARTE de la regla de hover de la tarjeta porque
   aquélla vive dentro de un `@media (hover: hover) and (pointer: fine)`: aquí solo se repite
   el color, así que el táctil no se queda sin cubrir.

   El BOTÓN ya no necesita gemelo aquí: sus cuatro estados se reparten arriba, y las dos ramas
   de `(hover: hover)` / `(hover: none)` declaran fondo y color en `:hover` y en `:focus`, que
   es lo que le cierra la puerta al Kit por los dos lados. */
.gsp-cards .gsp-card:focus {
	background-color: var(--gsp-c-bg, #fff);
	color: inherit;
}

/* ---- vista-rapida.css ---- */
/**
 * GS Vista Rápida. Handle 'gs-vista-rapida' (deps: gs-tokens, gs-fonts).
 *
 * La ventana de selección de variantes que se abre desde el botón de una tarjeta del catálogo.
 * Prefijo propio `.gsp-vr`.
 *
 * ── Este archivo está SOLO, y eso cambia cómo se escribe ─────────────────────
 * No depende de `producto-base.css` ni de `header-base.css`, a propósito: la ventana se abre
 * desde el catálogo, y arrastrar la hoja de la ficha de producto a una página de parrilla sería
 * peso puro. El precio de esa decisión es que aquí NO llega el neutralizador del Global Kit
 * (`.gsp-i`) ni el reset de `<button>` del header, así que las dos cosas se hacen aquí:
 *
 *   1. **Toda regla de estado va a (0,3,0)** —raíz + clase + pseudoclase— y declara **fondo Y
 *      color**, aunque solo cambie uno. El Kit emite `.elementor-kit-N button:hover` con (0,2,1)
 *      y `elementor-kit-N` vive en el `<body>`: portalear la ventana ahí NO libra de él, al
 *      contrario. El que se deje sin declarar es justo el que el Kit rellena.
 *   2. **Los `<button>` se resetean a (0,1,1)** (`.gsp-vr button`), y sus medidas se escriben a
 *      (0,2,1) (`.gsp-vr button.gsp-vr__cta`), porque un reset de elemento le gana a una clase
 *      suelta —es la cicatriz de `INSTRUCCIONES.md` §3.2, donde el CTA del carrito vacío salía
 *      aplastado—.
 *
 * ── Los colores vienen de VARIABLES, no de literales ─────────────────────────
 * Los controles de Elementor escriben `--gsp-vr-*` sobre `.gsp-vr[data-dueno="{{ID}}"]`. `{{ID}}`
 * y no `{{WRAPPER}}` porque el nodo está portaleado al `<body>` y ya no cuelga del widget; es el
 * mismo recurso que usa el widget de vídeo de Elementor para su lightbox. Los defaults se
 * declaran aquí sobre `.gsp-vr` y cada `var()` lleva además su literal de respaldo.
 *
 * ── El corte de móvil es 900px ───────────────────────────────────────────────
 * El mismo que usa `producto-tabs.css` para pasar la ventana de reseñas a panel inferior, y el
 * mismo al que la parrilla de tarjetas baja a dos columnas. Dos ventanas modales de la misma
 * tienda que cambian de forma a anchos distintos se leen como un fallo. NO se usan los
 * breakpoints de Elementor para la conmutación de forma: los controles responsive solo emiten
 * variables, la forma la decide esta hoja.
 */

.gsp-vr {
	/* ── Superficie ──────────────────────────────────────────────────── */
	--gsp-vr-velo: rgba(10, 10, 10, .5);
	--gsp-vr-bg: #fff;
	--gsp-vr-r: var(--gs-r-2xl, 16px);
	--gsp-vr-w: 880px;
	--gsp-vr-linea: var(--gs-linea, #E8E2D9);
	--gsp-vr-alterno: var(--gs-crema, #FAFAF7);

	/* ── Galería ─────────────────────────────────────────────────────── */
	--gsp-vr-gal-bg: var(--gs-crema, #FAFAF7);
	--gsp-vr-gal-w: 376px;

	/* ── Textos ──────────────────────────────────────────────────────── */
	--gsp-vr-oro: var(--gs-oro, #9C7A34);
	--gsp-vr-tinta: var(--gs-tinta, #0A0A0A);
	--gsp-vr-precio: var(--gs-tinta-precio, #111);
	--gsp-vr-sec: var(--gs-gris, #6B6B6B);
	--gsp-vr-tenue: var(--gs-txt-5, #A8A8A8);
	--gsp-vr-tachado: var(--gs-tachado, #C7C7C7);

	/* ── Opciones ────────────────────────────────────────────────────── */
	--gsp-vr-activo: var(--gs-oro, #9C7A34);
	--gsp-vr-muestra-borde: #E0DAD0;
	--gsp-vr-chip-borde: var(--gs-linea, #E8E2D9);
	--gsp-vr-chip-r: var(--gs-r-md, 9px);
	--gsp-vr-chip-hover: #FBF8F2;
	--gsp-vr-chip-on-bg: var(--gs-tinta, #0A0A0A);
	--gsp-vr-chip-on-txt: #fff;

	/* ── Disponibilidad ──────────────────────────────────────────────── */
	--gsp-vr-stock-alto: var(--gs-verde, #3A7D44);
	--gsp-vr-stock-bajo: var(--gs-oro, #9C7A34);
	--gsp-vr-stock-agotado: var(--gs-agotado, #B0B0B0);

	/* ── Volumen ─────────────────────────────────────────────────────── */
	--gsp-vr-vol-bg: rgba(17, 17, 17, .04);
	--gsp-vr-vol-borde: rgba(17, 17, 17, .08);
	--gsp-vr-vol-on-bg: var(--gs-tinta, #0A0A0A);
	--gsp-vr-vol-on-precio: var(--gs-oro-clr, #C2A370);
	--gsp-vr-vol-on-txt: #fff;

	/* ── Pie ─────────────────────────────────────────────────────────── */
	--gsp-vr-pie-bg: var(--gs-crema, #FAFAF7);
	/* Selector de cantidad: mismos colores que el del widget de mayoreo, para que la misma
	   pieza no cambie de aspecto entre la ficha y esta ventana. */
	--gsp-vr-step-fg: var(--gs-txt-3, #888);
	--gsp-vr-step-on-bg: var(--gs-hueso, #F5F1E8);
	--gsp-vr-step-on-fg: var(--gs-tinta, #0A0A0A);
	--gsp-vr-cta-bg: var(--gs-tinta, #0A0A0A);
	--gsp-vr-cta-txt: #fff;
	--gsp-vr-cta-bg-on: var(--gs-tinta-hover, #242424);
	--gsp-vr-cta-txt-on: #fff;
	--gsp-vr-cta-r: var(--gs-r-md, 9px);
	--gsp-vr-ok: var(--gs-verde, #3A7D44);

	position: fixed;
	inset: 0;
	z-index: var(--gs-z-modal, 380);
}

/* Un componente que llegue con su clase de abierto se normaliza a cerrado al iniciar
   (INSTRUCCIONES.md §3.4.5). El `hidden` lo pone PHP; esto es la red por si un estilo de tema
   pisara el `display` de `[hidden]`. */
.gsp-vr[hidden] {
	display: none;
}

/* ── Reset de los <button> ───────────────────────────────────────────────────
   (0,1,1). Sin él, los botones del tema traen padding, borde, sombra y min-height propios, y
   una clase suelta (0,1,0) NO les gana. Las medidas de cada botón concreto se escriben después
   a (0,2,1). */

.gsp-vr button {
	margin: 0;
	padding: 0;
	border: 0;
	border-radius: 0;
	background: none;
	box-shadow: none;
	text-shadow: none;
	min-height: 0;
	min-width: 0;
	line-height: 1;
	letter-spacing: normal;
	text-transform: none;
	font-family: inherit;
	color: inherit;
	cursor: pointer;
	appearance: none;
	-webkit-appearance: none;
}

/* ── Reset de los <input> ────────────────────────────────────────────────────
   Mismo motivo que el de `<button>`, y se olvidó: aquí no llega `producto-base.css`, que es
   quien neutraliza los campos en la ficha. El tema del sitio declara

       input[type="number"] { border: 1px solid #666; border-radius: 3px; padding: .5rem 1rem;
                              transition: .3s; width: 100% }
       input[type="number"]:focus { border-color: #333 }

   a (0,1,1) y (0,2,1). Sin este reset, el campo de cantidad heredaba esa transición de .3s
   sobre TODAS las propiedades —de ahí que «se pusiera raro» al tocarlo— y el borde del foco del
   tema. Va a (0,1,1) para ganarle al selector de elemento, igual que el de los botones. */

.gsp-vr input {
	margin: 0;
	border: 0;
	border-radius: 0;
	padding: 0;
	background: none;
	box-shadow: none;
	font: inherit;
	color: inherit;
	transition: none;
	appearance: none;
	-webkit-appearance: none;
}

.gsp-vr :focus-visible {
	outline: 2px solid var(--gsp-vr-activo, #9C7A34);
	outline-offset: 2px;
}

/* ── El foco del selector de cantidad va al GRUPO, no a la pieza ─────────────
   Portado tal cual del widget de mayoreo, que ya se peleó con esto. El grupo lleva
   `overflow: hidden` y sus piezas miden lo mismo de alto que él, así que un `outline` con
   desplazamiento se recortaba contra ese overflow y dejaba dos medias lunas doradas a los lados
   del campo. Y se veía al hacer CLIC, no solo al tabular, porque los navegadores casan
   `:focus-visible` con cualquier foco en un campo de texto.

   El BORDE que el grupo ya tiene es por definición su misma caja: no puede desalinearse, y marca
   la pieza entera —`−`, el número y `+`— en vez de un trozo. Va en gris y no en el oro del resto
   de la ventana: `--gs-txt-3` da ~3.5:1 contra el blanco del grupo, por encima del 3:1 que pide
   WCAG 1.4.11 para un indicador no textual, y es ya el color en reposo de los glifos.

   `:focus-within` y no `:has(:focus-visible)`: hace lo mismo sin necesitar `:has()`. La única
   diferencia es que pulsar `−`/`+` con el ratón también tiñe el borde, y con un gris discreto eso
   es realimentación correcta. */

.gsp-vr .gsp-vr__qty :is(.gsp-vr__qty-input, .gsp-vr__qty-btn):focus,
.gsp-vr .gsp-vr__qty :is(.gsp-vr__qty-input, .gsp-vr__qty-btn):focus-visible {
	outline: none;
}

.gsp-vr .gsp-vr__qty:focus-within {
	border-color: var(--gsp-vr-step-fg, #888);
}

/* Y nada de resaltado propio del navegador al tocarlo: en una hoja que sube desde abajo, el
   recuadro azul de selección táctil sobre un campo de dos cifras se lee como un error. */
.gsp-vr input.gsp-vr__qty-input {
	-webkit-tap-highlight-color: transparent;
}

/* ── Velo y caja ─────────────────────────────────────────────────────────────
   Solo `opacity` y `transform`, que son las dos que el navegador compone sin recalcular
   diseño. Transiciones y no keyframes: una transición se interrumpe y se retoma; un keyframe
   reinicia desde cero, y esta ventana se abre y se cierra deprisa. La salida es más rápida que
   la entrada, que es el vocabulario de motion ya establecido en el plugin. */

/* El desenfoque va como propiedad aparte y NO tocando `--gsp-vr-velo`: esa variable es un
   control de Elementor y la tienda elige su color. El esmerilado nació de un problema de móvil
   —el velo es lo único que separa la hoja de la página, y con el teclado abierto llegaba a verse
   por los bordes: desenfocado se lee como cristal y no como página suelta asomando—, pero se
   aplica en los dos tamaños. Es el mismo componente, y la hoja de reseñas (`.gsp-rev__velo`, en
   `producto-tabs.css`) ya usaba `backdrop-filter` sin distinguir tamaño: darle dos aspectos al
   mismo velo según el ancho solo obligaría a aprender dos.

   `-webkit-backdrop-filter` NO es opcional: en iOS —que es justo donde ocurre el problema del
   teclado— es la única de las dos que se aplica.

   `touch-action` y `overscroll-behavior` son la mitad CSS de lo que hace `onTouchMove` en el JS:
   ni el velo se arrastra, ni el gesto que muera aquí se propaga a la página de detrás. */

.gsp-vr__velo {
	position: absolute;
	inset: 0;
	background-color: var(--gsp-vr-velo, rgba(10, 10, 10, .5));
	/* Cristal, no niebla. El desenfoque baja de 6px a 3: lo justo para que la página de detrás
	   no se lea, conservando sus formas y sus bordes. Y la saturación sube de 120% a 180%, que
	   es lo que hace la diferencia entre «espejo» y «gris»: un desenfoque a secas apaga el color
	   y el fondo se apelmaza; devolviéndole saturación, lo que se ve detrás sigue teniendo color
	   propio y el velo se lee como un vidrio delante, no como una capa de humo. Es la misma
	   receta de los materiales del sistema en iOS — poco radio, mucha saturación. */
	-webkit-backdrop-filter: blur(3px) saturate(180%);
	backdrop-filter: blur(3px) saturate(180%);
	touch-action: none;
	overscroll-behavior: none;
	opacity: 0;
	transition: opacity 180ms var(--gs-e-out);
}

.gsp-vr.is-abierto .gsp-vr__velo {
	opacity: 1;
	transition-duration: 240ms;
}

.gsp-vr__caja {
	position: absolute;
	top: 50%;
	left: 50%;
	z-index: var(--gs-z-modal-caja, 381);
	display: flex;
	width: min(var(--gsp-vr-w, 880px), 100vw - 48px);
	max-height: min(660px, 92vh);
	overflow: hidden;
	background-color: var(--gsp-vr-bg, #fff);
	border-radius: var(--gsp-vr-r, 16px);
	box-shadow: 0 28px 70px rgba(10, 10, 10, .4);
	/* Se entra desde .96 y nunca desde 0: una ventana que crece de un punto se lee como un
	   truco; desde .96 parece que ya estaba ahí. El translate se repite porque es lo que la
	   centra — perderlo aquí la manda a la esquina. */
	opacity: 0;
	transform: translate(-50%, -50%) scale(.96);
	transition: opacity 160ms var(--gs-e-out), transform 160ms var(--gs-e-out);
}

.gsp-vr.is-abierto .gsp-vr__caja {
	opacity: 1;
	transform: translate(-50%, -50%) scale(1);
	transition-duration: 220ms;
}

/* La manija solo existe en el panel inferior. */
.gsp-vr__manija {
	display: none;
	position: absolute;
	top: 10px;
	left: 50%;
	transform: translateX(-50%);
	width: 40px;
	height: 4px;
	border-radius: var(--gs-r-pill, 99px);
	background-color: var(--gs-manija, #DDD8CE);
}

/* ── Cerrar ──────────────────────────────────────────────────────────────────
   Flota sobre la caja para no ocupar una fila propia en el encabezado. */

.gsp-vr button.gsp-vr__cerrar {
	position: absolute;
	top: 14px;
	right: 14px;
	z-index: 3;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 34px;
	height: 34px;
	border-radius: var(--gs-r-sm, 6px);
	background-color: transparent;
	color: var(--gsp-vr-tenue, #A8A8A8);
	transition: background-color .18s var(--gs-e-soft), color .18s var(--gs-e-soft);
}

/* (0,3,0), con los tres estados juntos y declarando fondo Y color. */
.gsp-vr .gsp-vr__cerrar:hover,
.gsp-vr .gsp-vr__cerrar:focus,
.gsp-vr .gsp-vr__cerrar:active {
	background-color: var(--gsp-vr-alterno, #FAFAF7);
	color: var(--gsp-vr-tinta, #0A0A0A);
}

.gsp-vr__cerrar-ico {
	width: 15px;
	height: 15px;
	display: block;
	stroke: currentColor;
	fill: none;
}

/* ── Cuerpo ──────────────────────────────────────────────────────────────── */

.gsp-vr__cuerpo {
	display: flex;
	width: 100%;
	min-width: 0;
	/* Sin esto el scroll interno encadena con el documento al llegar al final, y en iOS el
	   bloqueo por `overflow: hidden` del <body> no frena el gesto táctil. */
	overscroll-behavior: contain;
}

/* ── Columna de la galería ───────────────────────────────────────────────────
   Ancho FIJO con `flex: 0 0`, no `width`: con `width` el contenedor flex la comprime en cuanto
   la columna de la derecha pide sitio, y el `contain` de la foto la deja diminuta. */

.gsp-vr__gal {
	flex: 0 0 var(--gsp-vr-gal-w, 376px);
	padding: 20px;
	background-color: var(--gsp-vr-gal-bg, #FAFAF7);
	border-right: 1px solid var(--gsp-vr-linea, #E8E2D9);
}

/* El fondo de esta caja es el TINTE del color elegido, y lo escribe el JS en `backgroundColor`.
   El anillo interior va SIEMPRE: con un color muy claro —o con blanco— el tinte queda a un par
   de puntos del fondo de la columna y la caja se perdería sin él. */
.gsp-vr__foto {
	display: flex;
	align-items: center;
	justify-content: center;
	height: 286px;
	border-radius: var(--gs-r-lg, 10px);
	overflow: hidden;
	box-shadow: inset 0 0 0 1px var(--gsp-vr-linea, #E8E2D9);
	transition: background-color 300ms var(--gs-e-soft);
}

.gsp-vr__img {
	width: 82%;
	height: 82%;
	object-fit: contain;
	display: block;
}

.gsp-vr__thumbs {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 8px;
	margin-top: 12px;
}

.gsp-vr button.gsp-vr__thumb {
	position: relative;
	aspect-ratio: 1;
	border-radius: var(--gs-r-sm, 6px);
	overflow: hidden;
	background-color: #fff;
	box-shadow: inset 0 0 0 1px var(--gsp-vr-linea, #E8E2D9);
	transition: box-shadow .18s var(--gs-e-soft);
}

.gsp-vr .gsp-vr__thumb:hover,
.gsp-vr .gsp-vr__thumb:focus,
.gsp-vr .gsp-vr__thumb.is-activa {
	background-color: #fff;
	color: inherit;
	box-shadow: inset 0 0 0 1.5px var(--gsp-vr-activo, #9C7A34);
}

.gsp-vr__thumb img {
	width: 100%;
	height: 100%;
	object-fit: contain;
	display: block;
}

/* ── Columna de opciones ─────────────────────────────────────────────────────
   `min-width: 0` NO es opcional: sin él, el riel del carrusel —que tiene tarjetas de ancho
   fijo— impone su ancho mínimo al elemento flex y la ventana se desborda por la derecha. */

.gsp-vr__ops {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	overflow-y: auto;
	overscroll-behavior: contain;
}

/* Encabezado y pie quedan fijos y el cuerpo scrollea entre ellos. `sticky` y no `fixed`: dentro
   de un contenedor con scroll propio es lo que funciona sin sacar el nodo del flujo. */
.gsp-vr__head {
	position: sticky;
	top: 0;
	z-index: 2;
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 20px 56px 14px 24px;
	background-color: var(--gsp-vr-bg, #fff);
}

.gsp-vr__head-txt {
	min-width: 0;
}

.gsp-vr__cat {
	display: block;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 600;
	font-size: 9.5px;
	line-height: 1.2;
	letter-spacing: .2em;
	text-transform: uppercase;
	color: var(--gsp-vr-oro, #9C7A34);
}

.gsp-vr__titulo {
	margin: 5px 0 0;
	padding: 0;
	font-family: var(--gs-font-display, 'Archivo', 'Arial Narrow', system-ui, sans-serif);
	font-weight: 600;
	font-size: 25px;
	line-height: 1.15;
	text-transform: uppercase;
	color: var(--gsp-vr-tinta, #0A0A0A);
}

/* La miniatura solo existe cuando la galería se oculta (bajo 900px). */
.gsp-vr__mini {
	display: none;
	flex: 0 0 54px;
	width: 54px;
	height: 54px;
	border-radius: var(--gs-r-sm, 6px);
	overflow: hidden;
	box-shadow: inset 0 0 0 1px var(--gsp-vr-linea, #E8E2D9);
	transition: background-color 300ms var(--gs-e-soft);
}

.gsp-vr__mini img {
	width: 100%;
	height: 100%;
	object-fit: contain;
	display: block;
}

/* ── Precio ──────────────────────────────────────────────────────────────── */

.gsp-vr__precio-fila {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: 8px;
	padding: 0 24px 16px;
	border-bottom: 1px solid var(--gsp-vr-linea, #E8E2D9);
}

.gsp-vr__precio {
	font-family: var(--gs-font-display, 'Archivo', 'Arial Narrow', system-ui, sans-serif);
	font-weight: 700;
	font-size: 29px;
	line-height: 1;
	color: var(--gsp-vr-precio, #111);
}

.gsp-vr__divisa {
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-size: 12px;
	color: var(--gsp-vr-tenue, #A8A8A8);
}

/* Aparece al elegir una variación rebajada, así que no puede cambiar la altura de la fila. Con el
   `line-height` que hereda del tema, por encima de ~1,4 su caja baja de la línea base más que la
   del precio (que va a 1) y la fila crece: por cálculo con las métricas de Archivo e Inter, medio
   píxel con 1,5 y más de uno con 1,6. A 1 cabe entera dentro de la del precio. */
.gsp-vr__regular {
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-size: 14px;
	line-height: 1;
	color: var(--gsp-vr-tachado, #C7C7C7);
	text-decoration: line-through;
}

.gsp-vr__pastilla {
	margin-left: auto;
	padding: 4px 9px;
	border-radius: var(--gs-r-pill, 99px);
	background-color: var(--gs-oro-pale, #FBF6EE);
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 700;
	font-size: 9.5px;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--gsp-vr-oro, #9C7A34);
	white-space: nowrap;
}

.gsp-vr__pastilla[hidden],
.gsp-vr__regular[hidden] {
	display: none;
}

/* ── Bloques de atributo ─────────────────────────────────────────────────── */

/* El aire que separa del pie va ABAJO de cada bloque de contenido, no arriba del siguiente: la
   caja de volumen se oculta cuando el producto no tiene tramos, y con la separación puesta en su
   `margin-top` el último bloque de pastillas se quedaba pegado al pie. */
.gsp-vr__bloques {
	padding: 0 24px 18px;
}

.gsp-vr__bloque {
	padding: 18px 0 0;
}

.gsp-vr__bloque-head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 12px;
	margin-bottom: 11px;
}

.gsp-vr__label {
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 600;
	font-size: 10.5px;
	letter-spacing: .16em;
	text-transform: uppercase;
	color: var(--gsp-vr-tinta, #0A0A0A);
}

.gsp-vr__elegido {
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-size: 12.5px;
	color: var(--gsp-vr-sec, #6B6B6B);
}

/* Vacío, el hueco del valor elegido ocupa SU LÍNEA igual que lleno. Un `<span>` sin texto no
   genera caja de línea, así que la cabecera medía lo que la etiqueta (10,5px); al elegir entraba
   «Negro» (12,5px), la estiraba y la alineación por línea base bajaba la etiqueta. Como la caja
   va centrada con `translate(-50%, -50%)`, se movía la ventana entera: en las capturas del dueño,
   450 → 454px físicos a 125%, con «COLOR» 3px más abajo.

   Un espacio de no separación y no un `min-height`: con la MISMA fuente y el MISMO `line-height`
   que el nombre que vendrá, la caja de línea y la línea base son las de «Negro», herede el tema el
   `line-height` que herede. Un `min-height` en píxeles acertaría con un solo tema, y un bloque
   vacío no tiene línea base: `baseline` lo alinearía por su borde inferior y la etiqueta seguiría
   saltando. */
.gsp-vr__elegido:empty::before {
	content: '\00a0';
}

.gsp-vr a.gsp-vr__guia {
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-size: 12px;
	color: var(--gsp-vr-oro, #9C7A34);
	text-decoration: underline;
	text-underline-offset: 2px;
	background-color: transparent;
}

/* (0,3,0) y declarando fondo Y color: es el enlace más expuesto de la ventana, porque el Kit
   emite `.elementor-kit-N a:hover` con (0,2,1) y alcanza a un nodo portaleado al <body>. */
.gsp-vr .gsp-vr__guia:hover,
.gsp-vr .gsp-vr__guia:focus,
.gsp-vr .gsp-vr__guia:active {
	background-color: transparent;
	color: var(--gsp-vr-tinta, #0A0A0A);
	text-decoration: underline;
}

/* Radios ocultos pero ENFOCABLES: recorte por `clip`, nunca `display:none` ni `visibility`, que
   los sacarían del recorrido con teclado. Es la convención del plugin para swatches. */
.gsp-vr__radio {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
	border: 0;
}

.gsp-vr__opciones {
	display: flex;
	flex-wrap: wrap;
	gap: 11px;
}

.gsp-vr__bloque.is-button .gsp-vr__opciones {
	display: grid;
	grid-template-columns: repeat(5, 1fr);
	gap: 8px;
}

/* ── Muestras de color ───────────────────────────────────────────────────────
   El anillo de selección es un `border` que pasa de 1 a 2px, y no mueve a nadie porque la muestra
   es `border-box`: el borde se come el círculo por dentro en vez de sumarse por fuera. Se declara
   AQUÍ porque esta hoja no carga `producto-base.css`, que es quien lo pone en la ficha. Hasta ahora
   lo ponía una regla global ajena al plugin —en las capturas del dueño el relleno mide 30px, o sea
   `border-box`—, y en un sitio sin ella la elegida crecía 2px: fila más alta y vecinas desplazadas.
   El halo es sombra, que no ocupa sitio. */

.gsp-vr .gsp-vr__muestra {
	position: relative;
	box-sizing: border-box;
	width: 32px;
	height: 32px;
	border-radius: 50%;
	border: 1px solid var(--gsp-vr-muestra-borde, #E0DAD0);
	background-color: var(--gsp-vr-muestra-color, transparent);
	cursor: pointer;
	transition: border-color .18s var(--gs-e-soft), box-shadow .18s var(--gs-e-soft);
}

/* El círculo mide 32px porque lo pide el diseño, pero 32 es poco para un dedo. Esta caja
   invisible lo lleva a 44×44 sin cambiar nada de lo que se ve, que es la forma estándar de
   cumplir el mínimo táctil sin rehacer la fila. El gap entre muestras es de 11px, así que las
   áreas ampliadas se tocan pero no se solapan. */
.gsp-vr .gsp-vr__muestra::before {
	content: '';
	position: absolute;
	top: 50%;
	left: 50%;
	width: 44px;
	height: 44px;
	transform: translate(-50%, -50%);
}

.gsp-vr .gsp-vr__muestra:hover {
	border-color: var(--gsp-vr-activo, #9C7A34);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--gsp-vr-activo, #9C7A34) 18%, transparent);
}

.gsp-vr .gsp-vr__radio:checked + .gsp-vr__muestra {
	border: 2px solid var(--gsp-vr-activo, #9C7A34);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--gsp-vr-activo, #9C7A34) 22%, transparent);
}

/* Respaldo para navegadores sin `color-mix()`: sin él el halo desaparecería del todo. */
@supports not (color: color-mix(in srgb, red 20%, transparent)) {

	.gsp-vr .gsp-vr__muestra:hover,
	.gsp-vr .gsp-vr__radio:checked + .gsp-vr__muestra {
		box-shadow: 0 0 0 3px var(--gs-oro-halo, rgba(156, 122, 52, .2));
	}
}

.gsp-vr .gsp-vr__radio:focus-visible + .gsp-vr__muestra {
	outline: 2px solid var(--gsp-vr-activo, #9C7A34);
	outline-offset: 3px;
}

/* ── Pastillas de talla ─────────────────────────────────────────────────────
   ORDEN IMPORTANTE: «agotada» va DESPUÉS de «elegida», y a propósito no redeclara fondo ni
   color. Si lo hiciera al revés, una talla agotada que estaba elegida quedaría blanca sobre
   blanco. Aquí solo baja la opacidad y tacha, así que se lee sea cual sea el estado de debajo. */

.gsp-vr .gsp-vr__chip {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 2px;
	min-height: 52px;
	padding: 6px 4px;
	border: 1.5px solid var(--gsp-vr-chip-borde, #E8E2D9);
	border-radius: var(--gsp-vr-chip-r, 9px);
	background-color: transparent;
	color: var(--gsp-vr-tinta, #0A0A0A);
	cursor: pointer;
	text-align: center;
	transition: border-color .18s var(--gs-e-soft), background-color .18s var(--gs-e-soft), color .18s var(--gs-e-soft);
}

.gsp-vr .gsp-vr__chip:hover {
	border-color: var(--gsp-vr-activo, #9C7A34);
	background-color: var(--gsp-vr-chip-hover, #FBF8F2);
	color: var(--gsp-vr-tinta, #0A0A0A);
}

.gsp-vr .gsp-vr__radio:checked + .gsp-vr__chip {
	border-color: var(--gsp-vr-chip-on-bg, #0A0A0A);
	background-color: var(--gsp-vr-chip-on-bg, #0A0A0A);
	color: var(--gsp-vr-chip-on-txt, #fff);
}

.gsp-vr .gsp-vr__radio:focus-visible + .gsp-vr__chip {
	outline: 2px solid var(--gsp-vr-activo, #9C7A34);
	outline-offset: 2px;
}

/* ── Estados de disponibilidad ───────────────────────────────────────────────
   Mismo tratamiento que el widget de atributos de la ficha, para que una talla agotada se lea
   igual en los dos sitios: la pastilla NO se desvanece —se queda a opacidad 1 y es el TEXTO el
   que va en gris y tachado, que es mucho más legible que atenuar la caja entera— y el círculo de
   color lleva una diagonal.

   `agotado` e `imposible` se ven igual pero NO se comportan igual (ver más abajo).

   Nunca con el atributo `disabled`: eso saca la opción del orden de tabulación y el lector de
   pantalla deja de poder anunciar por qué no se puede elegir (INSTRUCCIONES.md §6). El JS pone
   `aria-disabled` en el radio. */

.gsp-vr .gsp-vr__chip.is-agotada,
.gsp-vr .gsp-vr__chip.is-imposible {
	opacity: 1;
	color: var(--gs-agotado-2, #CFCFCF);
	text-decoration: line-through;
	cursor: not-allowed;
}

/* La talla elegida que además está agotada conserva su fondo negro: si «agotada» redeclarara el
   color se quedaría gris sobre negro y no se leería. Por eso este bloque va DESPUÉS del de
   `:checked` y solo toca lo que tiene que tocar. */
.gsp-vr .gsp-vr__radio:checked + .gsp-vr__chip.is-agotada,
.gsp-vr .gsp-vr__radio:checked + .gsp-vr__chip.is-imposible {
	color: var(--gsp-vr-chip-on-txt, #fff);
	opacity: .55;
}

.gsp-vr .gsp-vr__muestra.is-agotada,
.gsp-vr .gsp-vr__muestra.is-imposible {
	cursor: not-allowed;
}

/* Diagonal sobre el círculo. `::after` y no un nodo en el markup: es decoración pura y no debe
   existir para un lector de pantalla. Se dibuja con un degradado de paradas duras para que
   escale con el tamaño del círculo sin recalcular nada. */
.gsp-vr .gsp-vr__muestra.is-agotada::after,
.gsp-vr .gsp-vr__muestra.is-imposible::after {
	content: '';
	position: absolute;
	inset: 0;
	border-radius: 50%;
	pointer-events: none;
	background: linear-gradient(
		to top right,
		transparent calc(50% - 1px),
		var(--gs-agotado, #B0B0B0) calc(50% - 1px),
		var(--gs-agotado, #B0B0B0) calc(50% + 1px),
		transparent calc(50% + 1px)
	);
}

/* ── Y aquí está la diferencia entre los dos ─────────────────────────────────
   Una AGOTADA existe en el catálogo y sigue siendo elegible: se puede pulsar a propósito, para
   que la línea de disponibilidad diga que está agotada. Es lo mismo que hace WooCommerce.

   Una IMPOSIBLE no existe —esa combinación de color y talla no está en la tienda—, así que no
   hay nada que explicar al pulsarla y no se deja elegir. La opacidad baja además del tachado,
   para que se distinga de la agotada de un vistazo. */

.gsp-vr .gsp-vr__chip.is-imposible,
.gsp-vr .gsp-vr__muestra.is-imposible {
	opacity: .35;
	pointer-events: none;
}

.gsp-vr__chip-val {
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 700;
	font-size: 13px;
	line-height: 1;
}

.gsp-vr__chip-stock {
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-size: 9.5px;
	line-height: 1.1;
	opacity: .75;
}

/* ── Línea de disponibilidad ─────────────────────────────────────────────── */

.gsp-vr__disp {
	margin: 10px 0 0;
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-size: 12px;
	line-height: 1.35;
	color: var(--gsp-vr-tenue, #A8A8A8);
}

.gsp-vr__disp.is-alto {
	color: var(--gsp-vr-stock-alto, #3A7D44);
}

.gsp-vr__disp.is-bajo {
	color: var(--gsp-vr-stock-bajo, #9C7A34);
}

.gsp-vr__disp.is-agotado {
	color: var(--gsp-vr-stock-agotado, #B0B0B0);
}

/* ── Precio por volumen ──────────────────────────────────────────────────── */

.gsp-vr__vol {
	margin: 0 24px 20px;
	padding: 12px;
	border: 1px solid var(--gsp-vr-vol-borde, rgba(17, 17, 17, .08));
	border-radius: var(--gs-r-lg, 10px);
	background-color: var(--gsp-vr-vol-bg, rgba(17, 17, 17, .04));
}

.gsp-vr__vol[hidden] {
	display: none;
}

.gsp-vr__vol-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	margin-bottom: 10px;
}

.gsp-vr__vol-titulo {
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 600;
	font-size: 10px;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--gsp-vr-sec, #6B6B6B);
}

.gsp-vr__vol-flechas {
	display: flex;
	gap: 6px;
}

.gsp-vr button.gsp-vr__vol-flecha {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 24px;
	height: 24px;
	border: 1px solid #DDD6CA;
	border-radius: var(--gs-r-sm, 6px);
	background-color: transparent;
	color: var(--gsp-vr-tinta, #0A0A0A);
	transition: background-color .18s var(--gs-e-soft), color .18s var(--gs-e-soft), opacity .18s var(--gs-e-soft);
}

.gsp-vr .gsp-vr__vol-flecha:hover,
.gsp-vr .gsp-vr__vol-flecha:focus,
.gsp-vr .gsp-vr__vol-flecha:active {
	background-color: var(--gsp-vr-tinta, #0A0A0A);
	color: #fff;
}

.gsp-vr .gsp-vr__vol-flecha.is-tope {
	opacity: .3;
	pointer-events: none;
}

.gsp-vr__vol-ico {
	width: 10px;
	height: 10px;
	display: block;
	stroke: currentColor;
	fill: none;
}

.gsp-vr__vol-flecha.is-izq .gsp-vr__vol-ico {
	transform: rotate(90deg);
}

.gsp-vr__vol-flecha.is-der .gsp-vr__vol-ico {
	transform: rotate(-90deg);
}

.gsp-vr__vol-marco {
	position: relative;
	min-width: 0;
}

.gsp-vr__vol-riel {
	display: flex;
	gap: 8px;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	overscroll-behavior-x: contain;
	scrollbar-width: none;
	min-width: 0;
}

.gsp-vr__vol-riel::-webkit-scrollbar {
	display: none;
}

/* Ancho FIJO —todas iguales— y es lo que hace que la última tarjeta salga recortada contra el
   borde interior de la caja de volumen: ese recorte es lo que comunica que hay más a la derecha.
   Con `flex: 1` cabrían todas y no habría nada que deslizar. */
.gsp-vr button.gsp-vr__tier {
	flex: 0 0 122px;
	scroll-snap-align: start;
	display: flex;
	flex-direction: column;
	gap: 3px;
	padding: 9px 10px;
	border: 1px solid var(--gsp-vr-vol-borde, rgba(17, 17, 17, .08));
	border-radius: var(--gs-r-sm, 6px);
	background-color: #fff;
	color: var(--gsp-vr-tinta, #0A0A0A);
	text-align: left;
	transition: background-color .18s var(--gs-e-soft), color .18s var(--gs-e-soft), border-color .18s var(--gs-e-soft);
}

.gsp-vr .gsp-vr__tier:hover,
.gsp-vr .gsp-vr__tier:focus {
	background-color: #fff;
	color: var(--gsp-vr-tinta, #0A0A0A);
	border-color: var(--gsp-vr-activo, #9C7A34);
}

.gsp-vr .gsp-vr__tier.is-activo {
	background-color: var(--gsp-vr-vol-on-bg, #0A0A0A);
	border-color: var(--gsp-vr-vol-on-bg, #0A0A0A);
	color: var(--gsp-vr-vol-on-txt, #fff);
}

.gsp-vr .gsp-vr__tier.is-activo:hover,
.gsp-vr .gsp-vr__tier.is-activo:focus {
	background-color: var(--gsp-vr-vol-on-bg, #0A0A0A);
	color: var(--gsp-vr-vol-on-txt, #fff);
}

.gsp-vr__tier-min {
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 700;
	font-size: 10px;
	letter-spacing: .06em;
	text-transform: uppercase;
	opacity: .7;
}

.gsp-vr__tier-precio {
	font-family: var(--gs-font-display, 'Archivo', 'Arial Narrow', system-ui, sans-serif);
	font-weight: 700;
	font-size: 15px;
	line-height: 1;
}

.gsp-vr .gsp-vr__tier.is-activo .gsp-vr__tier-precio {
	color: var(--gsp-vr-vol-on-precio, #C2A370);
}

.gsp-vr__tier-chip {
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-size: 10px;
	line-height: 1.1;
	opacity: .8;
}

/* Degradado del borde derecho. `pointer-events: none` o se comería los clics de la última
   tarjeta. Se desvanece al llegar al final. */
.gsp-vr__vol-fade {
	position: absolute;
	top: 0;
	right: 0;
	width: 32px;
	height: 100%;
	pointer-events: none;
	background: linear-gradient(to right, rgba(250, 250, 247, 0), var(--gsp-vr-vol-fade, #F5F5F2));
	opacity: 1;
	transition: opacity .2s var(--gs-e-soft);
}

.gsp-vr__vol.is-fin .gsp-vr__vol-fade {
	opacity: 0;
}

/* ── Pie de acción ───────────────────────────────────────────────────────── */

.gsp-vr__pie {
	position: sticky;
	bottom: 0;
	z-index: 2;
	margin-top: auto;
	padding: 14px 24px 16px;
	background-color: var(--gsp-vr-pie-bg, #FAFAF7);
	border-top: 1px solid var(--gsp-vr-linea, #E8E2D9);
}

.gsp-vr__pie-fila {
	display: flex;
	align-items: stretch;
	gap: 12px;
}

.gsp-vr__qty {
	display: flex;
	align-items: stretch;
	flex: 0 0 auto;
	border: 1px solid var(--gsp-vr-linea, #E8E2D9);
	border-radius: var(--gsp-vr-cta-r, 9px);
	overflow: hidden;
	background-color: #fff;
	/* El borde es el indicador de foco (más abajo): sin transición el cambio de color salta. */
	transition: border-color .15s var(--gs-e-soft);
}

.gsp-vr button.gsp-vr__qty-btn {
	width: 38px;
	min-height: 48px;
	display: flex;
	align-items: center;
	justify-content: center;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-size: 17px;
	background-color: transparent;
	color: var(--gsp-vr-step-fg, #888);
	transition: background-color .15s var(--gs-e-soft), color .15s var(--gs-e-soft);
}

/* Los tres estados a (0,3,0) y declarando fondo Y color, que es lo que le gana al
   `.elementor-kit-N button:hover` del Global Kit. El glifo pasa de gris a NEGRO sobre hueso:
   es exactamente el mismo hover que el selector de cantidad del widget de mayoreo, para que la
   misma pieza no cambie de aspecto entre la ficha y esta ventana. */
.gsp-vr .gsp-vr__qty-btn:hover,
.gsp-vr .gsp-vr__qty-btn:focus,
.gsp-vr .gsp-vr__qty-btn:active {
	background-color: var(--gsp-vr-step-on-bg, #F5F1E8);
	color: var(--gsp-vr-step-on-fg, #0A0A0A);
}

.gsp-vr input.gsp-vr__qty-input {
	width: 46px;
	min-height: 48px;
	padding: 0;
	border: 0;
	border-left: 1px solid var(--gsp-vr-linea, #E8E2D9);
	border-right: 1px solid var(--gsp-vr-linea, #E8E2D9);
	border-radius: 0;
	background-color: #fff;
	text-align: center;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 700;
	font-size: 14px;
	color: var(--gsp-vr-tinta, #0A0A0A);
	appearance: textfield;
	-moz-appearance: textfield;
}

/* Los controles nativos de incremento sobran: ya hay dos botones grandes al lado. */
.gsp-vr .gsp-vr__qty-input::-webkit-outer-spin-button,
.gsp-vr .gsp-vr__qty-input::-webkit-inner-spin-button {
	appearance: none;
	-webkit-appearance: none;
	margin: 0;
}

.gsp-vr button.gsp-vr__cta {
	flex: 1;
	min-height: 52px;
	padding: 0 16px;
	border-radius: var(--gsp-vr-cta-r, 9px);
	background-color: var(--gsp-vr-cta-bg, #0A0A0A);
	color: var(--gsp-vr-cta-txt, #fff);
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 700;
	font-size: 12.5px;
	letter-spacing: .1em;
	text-transform: uppercase;
	transition: background-color .18s var(--gs-e-soft), color .18s var(--gs-e-soft), opacity .18s var(--gs-e-soft);
}

.gsp-vr .gsp-vr__cta:hover,
.gsp-vr .gsp-vr__cta:focus,
.gsp-vr .gsp-vr__cta:active {
	background-color: var(--gsp-vr-cta-bg-on, #242424);
	color: var(--gsp-vr-cta-txt-on, #fff);
}

/* Atenuado pero NO deshabilitado: tiene que poder recibir el clic para explicar qué falta. */
.gsp-vr .gsp-vr__cta[aria-disabled="true"] {
	opacity: .35;
}

.gsp-vr .gsp-vr__cta.is-ok,
.gsp-vr .gsp-vr__cta.is-ok:hover,
.gsp-vr .gsp-vr__cta.is-ok:focus {
	background-color: var(--gsp-vr-ok, #3A7D44);
	color: #fff;
	opacity: 1;
}

.gsp-vr__pie-sub {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 12px;
	margin-top: 10px;
}

.gsp-vr a.gsp-vr__ficha {
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-size: 12px;
	color: var(--gsp-vr-sec, #6B6B6B);
	text-decoration: underline;
	text-underline-offset: 2px;
	background-color: transparent;
}

.gsp-vr .gsp-vr__ficha:hover,
.gsp-vr .gsp-vr__ficha:focus,
.gsp-vr .gsp-vr__ficha:active {
	background-color: transparent;
	color: var(--gsp-vr-tinta, #0A0A0A);
	text-decoration: underline;
}

.gsp-vr__total {
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 700;
	font-size: 12.5px;
	color: var(--gsp-vr-tinta, #0A0A0A);
	white-space: nowrap;
}

/* Utilidad de lectores de pantalla: los temas suelen traerla, pero no todos. */
.gsp-vr .screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
	border: 0;
}

/* ── Esqueleto de carga ──────────────────────────────────────────────────── */

.gsp-vr__cargando {
	display: flex;
	gap: 24px;
	width: 100%;
	padding: 20px;
}

.gsp-vr__ph-col {
	display: flex;
	flex-direction: column;
	gap: 14px;
	flex: 1;
	min-width: 0;
	padding: 12px 4px;
}

.gsp-vr__ph {
	display: block;
	border-radius: var(--gs-r-lg, 10px);
	background-color: var(--gsp-vr-alterno, #FAFAF7);
	animation: gsp-vr-latido 1.4s ease-in-out infinite;
}

.gsp-vr__ph--media {
	flex: 0 0 var(--gsp-vr-gal-w, 376px);
	height: 286px;
}

.gsp-vr__ph--linea {
	width: 35%;
	height: 10px;
}

.gsp-vr__ph--titulo {
	width: 75%;
	height: 26px;
}

.gsp-vr__ph--precio {
	width: 45%;
	height: 30px;
}

.gsp-vr__ph--bloque {
	width: 100%;
	height: 52px;
}

@keyframes gsp-vr-latido {

	0%,
	100% {
		opacity: 1;
	}

	50% {
		opacity: .55;
	}
}

/* ── Región de anuncios ──────────────────────────────────────────────────────
   Visible solo para lectores de pantalla. Recorte por `clip` y no `display:none`, que la
   sacaría del árbol de accesibilidad y no anunciaría nada. */

.gsp-vr__live {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
	border: 0;
}

/* ── Panel inferior en pantallas estrechas ─────────────────────────────────── */

@media (max-width: 900px) {

	/* ── El teclado: el VELO tapa todo, y solo la HOJA se sube ────────────
	   `position: fixed; inset: 0` cubre el layout viewport, y en iOS el teclado en pantalla no
	   lo toca: lo que encoge y desplaza es el visual viewport. Con la raíz clavada al layout,
	   la hoja —anclada con `bottom: 0`— se quedaba DEBAJO del teclado.

	   El primer intento fue encoger la RAÍZ al visual viewport. Arreglaba la hoja y estropeaba
	   el velo: `.gsp-vr__velo` es `absolute; inset: 0` dentro de esa raíz, así que encogía con
	   ella y dejaba de cubrir la franja del teclado. En iOS el teclado es TRANSLÚCIDO, y por ahí
	   se seguía viendo la página de detrás.

	   El reparto correcto son dos anclajes distintos, no uno:
	     · la raíz —y con ella el velo— se queda cubriendo el layout viewport ENTERO;
	     · la hoja se apoya en `--gs-vv-fondo`, que es justo lo que ocupa el teclado.

	   Las variables las publica `GSHeader.seguirViewport()` en `<html>` mientras la ventana está
	   abierta. Si el navegador no trae `visualViewport` no llegan a declararse y mandan los
	   respaldos: `bottom: 0` y `94vh`, que es el comportamiento de siempre. */

	.gsp-vr__caja {
		top: auto;
		bottom: var(--gs-vv-fondo, 0px);
		left: 0;
		width: 100%;
		max-width: none;
		/* Sobre `--gs-vv-alto` y no sobre `vh`: `vh` es justo la unidad que NO encoge cuando
		   sale el teclado, y la hoja se pasaría de largo. El respaldo `100vh` reproduce el
		   `94vh` de antes allí donde no hay `visualViewport`. */
		max-height: calc(var(--gs-vv-alto, 100vh) * .94);
		border-radius: 22px 22px 0 0;
		/* Entra deslizando desde abajo. La curva es `--gs-e-sheet`, que existe justo para esto:
		   sale disparada y frena largo, que es lo que da la sensación de ir agarrada al dedo.

		   `bottom` y `max-height` también transicionan, y no es adorno: son las dos propiedades
		   que cambian cuando el teclado entra y sale. Sin transición, al bajar el teclado la
		   hoja recuperaba su tamaño de golpe, en un solo fotograma, y se veía seco.

		   240ms y no los 380 de la entrada: aquí la hoja no está apareciendo, está acompañando
		   a un teclado que ya se está yendo. Más largo y va por detrás de él. */
		transform: translateY(14%);
		transition:
			opacity 200ms var(--gs-e-out),
			transform 380ms var(--gs-e-sheet),
			bottom 240ms var(--gs-e-sheet),
			max-height 240ms var(--gs-e-sheet);
	}

	.gsp-vr.is-abierto .gsp-vr__caja {
		transform: translateY(0);
		/* Las cuatro, en el mismo orden que arriba: con menos valores la lista se recicla y a
		   `bottom` le tocaría la duración de `opacity`. */
		transition-duration: 260ms, 380ms, 240ms, 240ms;
	}

	.gsp-vr__manija {
		display: block;
	}

	.gsp-vr__cargando {
		flex-direction: column;
	}

	/* La galería se oculta: en vertical el espacio vale más que la foto grande. */
	.gsp-vr__ph--media,
	.gsp-vr__gal {
		display: none;
	}

	/* Y en su sitio, la miniatura junto al título, con el mismo tinte. */
	.gsp-vr__mini {
		display: block;
	}

	.gsp-vr__head {
		padding: 18px 52px 12px 20px;
	}

	.gsp-vr__titulo {
		font-size: 21px;
	}

	.gsp-vr__precio-fila {
		padding: 0 20px 14px;
	}

	.gsp-vr__bloques {
		padding: 0 20px 16px;
	}

	.gsp-vr__vol {
		margin: 0 20px 20px;
	}

	.gsp-vr__pie {
		padding: 12px 20px 18px;
	}

	/* ── Objetivos táctiles ──────────────────────────────────────────────
	   Nada por debajo de 44px. Las pastillas suben a 56 y el selector de cantidad a 42×52. */

	.gsp-vr .gsp-vr__chip {
		min-height: 56px;
	}

	/* 44 y no los 42 del diseño: por debajo de 44px un objetivo táctil deja de ser cómodo, y
	   entre dos píxeles de maquetación y que el botón se pueda pulsar, gana lo segundo. */
	.gsp-vr button.gsp-vr__qty-btn {
		width: 44px;
		min-height: 52px;
	}

	/* Los 16px NO son decorativos: por debajo de 16, iOS hace zoom al enfocar el campo, y en una
	   hoja que sube desde abajo eso reencuadra la pantalla entera y deja la ventana descolocada.
	   Es la única forma de evitarlo sin tocar el `viewport` del sitio, que no es nuestro. */
	.gsp-vr input.gsp-vr__qty-input {
		width: 52px;
		min-height: 52px;
		font-size: 16px;
	}

	.gsp-vr button.gsp-vr__cta {
		min-height: 52px;
	}

	.gsp-vr button.gsp-vr__cerrar {
		width: 44px;
		height: 44px;
		top: 10px;
		right: 8px;
	}

	/* ── Carrusel ────────────────────────────────────────────────────────
	   Las flechas se van: en táctil se desliza con el dedo. Las tarjetas bajan a 112px, de modo
	   que la siguiente asoma cortada contra el borde INTERIOR de la caja de volumen — que es lo
	   único que comunica que hay más.

	   Aquí hubo un sangrado —`.gsp-vr__vol-marco { margin: 0 -32px }` con el padding equivalente
	   en el riel— para que el carril llegara a los bordes de la hoja. La idea era buena y el
	   efecto secundario no se vio: `.gsp-vr__vol` no declara `overflow`, así que la caja de
	   pintado del riel se salía 32 − 12 de padding − 1 de borde = 19px POR FUERA del borde de la
	   caja gris a cada lado. Con cuatro escalones o más eso se leía como «asoma la siguiente»;
	   con tres exactos (3×112 + 2×8 de hueco + 64 de sangrado = 416px, más que cualquier móvil)
	   la tercera aterrizaba justo en esa franja y se leía como una tarjeta escapada del recuadro.
	   El degradado, anclado al `right: 0` del marco sangrado, se iba fuera con ella.

	   Ahora el riel vive dentro del padding de la caja y no se pinta nada fuera de su borde. */

	.gsp-vr__vol-flechas {
		display: none;
	}

	.gsp-vr button.gsp-vr__tier {
		flex: 0 0 112px;
	}
}

/* ── Movimiento reducido ─────────────────────────────────────────────────────
   Acotado a `.gsp-vr` y con el universal DENTRO: es la única forma de alcanzar las quince
   transiciones de esta hoja sin tener que listarlas —y sin que olvidarse de una al añadir un
   bloque nuevo pase desapercibido—. Fuera de la ventana no toca nada de la página.

   `.01ms` y no `0s`: con duración cero algunos navegadores no emiten `transitionend`, y el
   cierre de la ventana lo usa para poner el `hidden`. Se quedaría esperando al temporizador de
   respaldo, que son 600 ms de ventana invisible capturando clics. */
@media (prefers-reduced-motion: reduce) {

	.gsp-vr,
	.gsp-vr *,
	.gsp-vr *::before,
	.gsp-vr *::after {
		transition-duration: .01ms !important;
		animation-duration: .01ms !important;
		animation-iteration-count: 1 !important;
		scroll-behavior: auto !important;
	}
}

/* ---- mosaico.css ---- */
/**
 * GS Mosaico de Categorías. Handle 'gs-mosaico' (deps: gs-tokens, gs-fonts).
 *
 * Mosaico de tarjetas con imagen a sangre, degradado de legibilidad y una tarjeta
 * destacada que ocupa dos filas. Los colores salen de los tokens del plugin con el valor
 * literal como respaldo, de modo que el mosaico siga el sistema de diseño si algún día
 * se retoca la paleta.
 *
 * Las reglas van con el contenedor por delante (`.gspc-wrap .gspc-card`) para ganar por
 * especificidad a los temas. Los `!important` puntuales están donde los temas casi
 * siempre pelean: dimensiones de <img>, subrayado del enlace y color del texto.
 */

.gspc-wrap {
	width: 100%;
	max-width: none;
	margin: 0;
	padding: 0;
}

.gspc-wrap,
.gspc-wrap * {
	box-sizing: border-box;
}

/* Las tres variables de esta regla (`--gspc-cols`, `--gspc-alto`, `--gspc-gap`) las escribe
   Elementor desde los controles responsive del widget, con SUS cortes (1024 y 767). Aquí no
   hay ninguna @media de columnas: si la hubiera competiría con esa hoja y ganaría una u otra
   según el orden de carga. El valor de respaldo de cada `var()` es la única red de seguridad,
   y solo entra en juego si la hoja de Elementor aún no se ha regenerado.

   `minmax(0, 1fr)` y no `1fr`: `1fr` equivale a `minmax(auto, 1fr)`, y con `auto` una tarjeta
   cuyo contenido no quepa —un nombre de categoría largo sin espacios— ensancha su columna y
   descuadra la fila entera. Con el mínimo en 0 la columna nunca crece por encima de su parte. */
.gspc-wrap .gspc-grid {
	display: grid;
	width: 100%;
	grid-template-columns: repeat(var(--gspc-cols, 3), minmax(0, 1fr));
	grid-auto-rows: var(--gspc-alto, 340px);
	gap: var(--gspc-gap, 18px);
	/* Por si el tema envuelve esto en una lista. */
	padding: 0;
	margin: 0;
	list-style: none;
}

/* ── Tarjeta ─────────────────────────────────────────────────────────────── */

/* El relleno escala con la pantalla: 24px dentro de una tarjeta de 150px de ancho —lo que
   mide a dos columnas en un móvil— se come un tercio del espacio y deja el texto sin sitio.
   `min-height` es un seguro: si alguien vacía el slider de alto, `--gspc-alto` llega vacío y
   la fila colapsaría a cero. */
.gspc-wrap .gspc-card {
	position: relative;
	display: flex !important;
	align-items: flex-end;
	min-height: 140px;
	padding: clamp(14px, 4vw, 24px);
	border: 1px solid var(--gs-linea, #E8E2D9);
	border-radius: var(--gspc-radio, 14px);
	overflow: hidden;
	text-decoration: none !important;
	box-shadow: 0 2px 12px rgba(0, 0, 0, .06);
	background: linear-gradient(160deg, var(--gs-hueso, #F5F1E8) 0%, #EDE8DE 90%);
	transition: transform .25s ease, border-color .25s ease, box-shadow .25s ease;
}

/* La destacada ocupa dos filas SIEMPRE, también en el móvil. Antes volvía a una sola fila por
   debajo de 640px y se quedaba en «una tarjeta un poco más alta»: perdía la jerarquía, que es
   justo lo único que la hace destacada. Con dos columnas en móvil el span de dos filas vuelve
   a leerse como lo que es. */
.gspc-wrap .gspc-card--feat {
	grid-row: span 2;
	background: linear-gradient(160deg, #F0EDE6 0%, var(--gs-linea, #E8E2D9) 90%);
}

/* El hover se limita a los punteros que de verdad pueden pasar por encima. En una pantalla
   táctil `:hover` se queda PEGADO tras el toque: la tarjeta se quedaba levantada 6px y con el
   borde dorado hasta que tocabas otra cosa, y al volver atrás en el historial seguía así. */
@media (hover: hover) and (pointer: fine) {

	/* `background` va repetido porque la tarjeta es un `<a>` y el Kit emite
	   `.elementor-kit-N a:hover` con (0,2,1): esta regla es (0,3,0) y le gana solo en lo que
	   declara. Sin la línea, el degradado de la tarjeta se sustituía por el color del Kit. */
	.gspc-wrap .gspc-card:hover {
		transform: translateY(-6px);
		border-color: var(--gspc-hover, #C2A370);
		background: linear-gradient(160deg, var(--gs-hueso, #F5F1E8) 0%, #EDE8DE 90%);
		color: inherit;
		box-shadow: 0 8px 32px rgba(156, 122, 52, .15);
	}

	.gspc-wrap .gspc-card:hover .gspc-img {
		transform: scale(1.06);
	}
}

/* En táctil el feedback es el estado activo: inmediato y no se queda pegado. */
@media (hover: none) {

	.gspc-wrap .gspc-card:active {
		transform: scale(.985);
		border-color: var(--gspc-hover, #C2A370);
	}
}

.gspc-wrap .gspc-card:focus-visible,
.gspc-wrap .gspc-card:focus {
	outline: 2px solid var(--gspc-hover, #C2A370);
	outline-offset: 2px;
	background: linear-gradient(160deg, var(--gs-hueso, #F5F1E8) 0%, #EDE8DE 90%);
}

/* ── Imagen y capas ──────────────────────────────────────────────────────── */

.gspc-wrap .gspc-card .gspc-img {
	position: absolute;
	inset: 0;
	width: 100% !important;
	height: 100% !important;
	max-width: none !important;
	object-fit: cover;
	display: block;
	border-radius: 0 !important;
	transition: transform .5s ease;
}

.gspc-wrap .gspc-shade {
	position: absolute;
	inset: 0;
	background: linear-gradient(to top,
			rgba(10, 10, 10, var(--gspc-shade, .72)) 0%,
			rgba(10, 10, 10, calc(var(--gspc-shade, .72) * .21)) 55%,
			transparent 100%);
}

.gspc-wrap .gspc-glow {
	position: absolute;
	inset: 0;
	background: radial-gradient(circle at 50% 30%, rgba(194, 163, 112, .2), transparent 60%);
}

.gspc-wrap .gspc-card--feat .gspc-glow {
	background: radial-gradient(circle at 50% 30%, rgba(194, 163, 112, .3), transparent 60%);
}

/* ── Texto ───────────────────────────────────────────────────────────────── */

/* `min-width: 0` sobre el texto: es hijo de un flex, y sin él una palabra larga se niega a
   partirse y empuja la tarjeta. El `letter-spacing` también escala — .16em sobre 14px son
   más de 2px por letra, y en una tarjeta de 150px «PERFUMES» se sale de su propia caja. */
.gspc-wrap .gspc-card .gspc-txt {
	position: relative;
	z-index: 2;
	display: block;
	min-width: 0;
	font-family: 'Montserrat', 'Helvetica Neue', Arial, sans-serif;
	font-weight: 700;
	font-size: clamp(12px, 3.2vw, 14px);
	line-height: 1.2;
	letter-spacing: clamp(.08em, 1vw, .16em);
	text-transform: uppercase;
	color: #fff !important;
	text-shadow: 0 1px 2px rgba(10, 10, 10, .35);
	overflow-wrap: anywhere;
}

/* El subtítulo se corta a dos líneas. En escritorio nunca llega a tanto, pero a dos columnas
   en un móvil «Playeras · Camisas · Sudaderas» ocupa tres o cuatro renglones y empuja al
   título fuera de la zona oscurecida, que es donde se lee. */
.gspc-wrap .gspc-card .gspc-txt small {
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	overflow: hidden;
	font-family: 'Inter', 'Helvetica Neue', Arial, sans-serif;
	font-weight: 400;
	font-size: clamp(11px, 2.8vw, 12px);
	line-height: 1.35;
	letter-spacing: 0;
	text-transform: none;
	color: var(--gs-linea, #E8E2D9) !important;
	margin-top: 6px;
}

/* ── Responsive ──────────────────────────────────────────────────────────────
   Este bloque ya no existe. Las columnas, el alto de fila y la separación son controles
   responsive del widget y los escribe Elementor en sus propios cortes (1024 y 767), así que
   se editan y se previsualizan desde el panel en vez de estar clavados aquí.

   Lo que sí se queda en CSS es todo lo que NO es una medida elegible: el relleno y la
   tipografía escalan con `clamp()` (arriba, en sus reglas), y el hover se separa por
   capacidad del puntero, no por ancho de pantalla. */

@media (prefers-reduced-motion: reduce) {

	.gspc-wrap .gspc-card,
	.gspc-wrap .gspc-card .gspc-img {
		transition: none;
	}

	.gspc-wrap .gspc-card:hover,
	.gspc-wrap .gspc-card:active,
	.gspc-wrap .gspc-card:hover .gspc-img {
		transform: none;
	}
}

/* ── El Kit tiñe el `:focus` a secas ─────────────────────────────────────────
   `:focus-visible` NO casa al pulsar con el ratón, y `.elementor-kit-N a:focus` /
   `button:focus` sí, con (0,2,1): al hacer clic, el elemento se quedaba con el color del
   Kit hasta perder el foco. Estos gemelos van APARTE de sus reglas de hover porque
   aquéllas mueven la caja (`transform`) o viven dentro de un `@media (hover)`: aquí solo
   se repite el color, así que ni se levanta nada al hacer clic ni se queda el táctil
   sin cubrir. */
.gspc-wrap .gspc-card:focus {
	background: linear-gradient(160deg, var(--gs-hueso, #F5F1E8) 0%, #EDE8DE 90%);
	color: inherit;
}

/* ---- videos.css ---- */
/**
 * GS Videos. Handle 'gs-videos' (deps: gs-tokens, gs-fonts).
 *
 * Sección de videos verticales: encabezado centrado y parrilla de tarjetas 9:16 con
 * portada a sangre, degradado de legibilidad, botón de play y texto sobreimpreso.
 *
 * Los valores que el panel de Elementor controla llegan como variables CSS escritas por
 * sus `selectors` sobre `.gsv` (sección) y `.gsv__grid` (tarjetas). Aquí solo están los
 * valores por defecto del diseño; no dupliques reglas de color ni de tamaño que ya tenga
 * un control.
 *
 * Las reglas van con el contenedor por delante (`.gsv .gsv-card__x`) para ganar por
 * especificidad a los temas, que estilan `img`, `video`, `button`, `h3` y `a` dentro del
 * contenido de forma agresiva. Los `!important` puntuales están donde los temas casi
 * siempre pelean: dimensiones de medios y decoración del enlace.
 *
 * ── El rival no es el tema, es el Global Kit ─────────────────────────────
 * Esta hoja no depende de `header-base.css`, así que aquí NO llega su neutralizador del Kit. El
 * Kit emite `.elementor-kit-N button:hover` con (0,2,1), que le gana a un `.gsv .gsv-x` (0,2,0):
 * **toda regla de estado va a (0,3,0) y declara fondo Y color**, aunque solo cambie uno, porque
 * el que se deje sin declarar es justo el que el Kit rellena. Importa el doble en esta hoja: el
 * botón de play cubre la tarjeta entera, así que un fondo suyo tapa el vídeo.
 *
 * La ventana emergente se portalea al `<body>` y por eso cuelga de `.gsv-modal`, no de `.gsv`.
 * Portalear no libra del Kit —`elementor-kit-N` vive en el propio `<body>`—, así que la ventana
 * se blinda sola escribiendo su raíz por delante, igual que `vista-rapida.css`.
 */

.gsv {
	width: 100%;
	padding: 100px 0;
	background-color: #FAFAF7;
	border-top: 1px solid #EEE8DD;
	/* 80rem es el ancho de columna del sitio (el mismo de GS Tarjetas de Producto): la
	   primera tarjeta tiene que empezar en esa línea para cuadrar con el header y con el
	   resto de secciones. */
	--gsv-max: 80rem;
	--gsv-pad-x: 32px;
}

.gsv,
.gsv * {
	box-sizing: border-box;
}

/* El relleno lateral se SUMA al ancho máximo en vez de comérselo. Con `max-width: 80rem`
   a secas, el padding quedaba por dentro y el contenido medía 80rem − 64px: la sección se
   veía metida hacia dentro respecto a las demás. Así la columna mide 80rem exactos en
   pantallas anchas, y en móvil el relleno sigue separando las tarjetas del borde. */
.gsv__inner {
	width: 100%;
	max-width: calc(var(--gsv-max, 80rem) + var(--gsv-pad-x, 32px) * 2);
	margin: 0 auto;
	padding-inline: var(--gsv-pad-x, 32px);
}

/* ── Encabezado ──────────────────────────────────────────────────────────── */

.gsv .gsv__head {
	text-align: center;
}

.gsv .gsv__eyebrow {
	margin: 0 0 12px;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 600;
	font-size: 11px;
	line-height: 1.2;
	letter-spacing: .3em;
	text-transform: uppercase;
	color: var(--gs-oro, #9C7A34);
}

.gsv .gsv__title {
	margin: 0;
	padding: 0;
	font-family: var(--gs-font-display, 'Archivo', 'Arial Narrow', system-ui, sans-serif);
	font-weight: 700;
	/* clamp() en vez de media queries: el título escala de forma continua entre 30 y 46px. */
	font-size: clamp(30px, 5vw, 46px);
	line-height: 1.06;
	letter-spacing: -.01em;
	text-transform: uppercase;
	color: var(--gs-tinta, #0A0A0A);
}

.gsv .gsv__sub {
	max-width: 520px;
	margin: 16px auto 0;
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-weight: 400;
	font-size: 14.5px;
	line-height: 1.55;
	color: var(--gs-gris, #6B6B6B);
}

/* ── Parrilla ────────────────────────────────────────────────────────────── */

.gsv .gsv__grid {
	display: grid;
	grid-template-columns: repeat(var(--gsv-cols, 3), minmax(0, 1fr));
	gap: var(--gsv-gap, 22px);
	margin-top: 44px;
	/* Por si el tema envuelve esto en una lista. */
	padding: 0;
	list-style: none;
}

/* ── Tarjeta ─────────────────────────────────────────────────────────────── */

.gsv .gsv-card {
	position: relative;
	display: block;
	aspect-ratio: var(--gsv-ar, 9 / 16);
	border-radius: var(--gsv-radio, 16px);
	overflow: hidden;
	background: var(--gsv-card-bg, #0A0A0A);
	border: 1px solid var(--gsv-borde, #1F1F1F);
	cursor: pointer;
	transition: transform .25s ease, border-color .25s ease, box-shadow .25s ease;
	/* Anti-tema cuando la raíz es un <a>. */
	text-decoration: none !important;
	color: inherit;
}

.gsv .gsv-card:hover,
.gsv .gsv-card:focus-within {
	transform: translateY(var(--gsv-lift, -6px));
	border-color: var(--gsv-borde-hover, #C2A370);
	box-shadow: 0 14px 38px rgba(10, 10, 10, .18);
}

/* La tarjeta es un `<a>` y la regla de arriba solo mueve la caja: fondo y color quedaban sin
   declarar y los rellenaba el Kit —(0,2,1)— pintando su color de marca sobre el vídeo entero.
   Se repiten aparte para no duplicar el `transform` ni la sombra, y con `:focus` a secas porque
   `:focus-visible` no casa al pulsar con el ratón. */
.gsv .gsv-card:hover,
.gsv .gsv-card:focus,
.gsv .gsv-card:focus-within {
	background: var(--gsv-card-bg, #0A0A0A);
	color: inherit;
}

/* ── Medios ──────────────────────────────────────────────────────────────── */

.gsv .gsv-card__media {
	position: absolute;
	inset: 0;
}

.gsv .gsv-card__video,
.gsv .gsv-card__poster,
.gsv .gsv-card__frame {
	position: absolute;
	inset: 0;
	width: 100% !important;
	height: 100% !important;
	max-width: none !important;
	display: block;
	border: 0;
	border-radius: 0 !important;
	object-fit: cover;
}

/* La portada vive por encima del <video> y se retira cuando este empieza a reproducir:
   un <video> sin `src` (aún no cargado) no pinta su atributo `poster` en todos los
   navegadores, así que la imagen es la que garantiza que nunca se vea un hueco negro. */
.gsv .gsv-card__poster {
	z-index: 1;
	transition: opacity .3s ease;
}

/* `is-previa` la pone el JS solo cuando el hover ha CONSEGUIDO reproducir; si se retirase
   la portada al entrar el cursor, un navegador que bloquee la reproducción dejaría la
   tarjeta en negro. */
.gsv .gsv-card.is-playing .gsv-card__poster,
.gsv .gsv-card.is-previa .gsv-card__poster {
	opacity: 0;
	pointer-events: none;
}

.gsv .gsv-card__frame {
	z-index: 3;
}

/* ── Degradado ───────────────────────────────────────────────────────────── */

.gsv .gsv-card__shade {
	position: absolute;
	inset: 0;
	z-index: 2;
	pointer-events: none;
	background: linear-gradient(to top,
			rgba(10, 10, 10, var(--gsv-shade, .82)) 0%,
			transparent 42%,
			rgba(10, 10, 10, calc(var(--gsv-shade, .82) * .3)) 100%);
	transition: opacity .3s ease;
}

/* Reproduciendo, el degradado y el texto estorban. */
.gsv .gsv-card.is-playing .gsv-card__shade,
.gsv .gsv-card.is-playing .gsv-card__txt {
	opacity: 0;
	pointer-events: none;
}

/* ── Botón de play ───────────────────────────────────────────────────────── */

.gsv .gsv-card__play {
	position: absolute;
	inset: 0;
	z-index: 4;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	height: 100%;
	padding: 0;
	margin: 0;
	background: none;
	border: 0;
	cursor: pointer;
	/* Anti-tema: los botones traen sombras, mínimos y fondos propios. */
	box-shadow: none;
	text-shadow: none;
	min-height: 0;
	appearance: none;
	-webkit-appearance: none;
}

/* El botón cubre la tarjeta ENTERA, así que un fondo suyo tapa el vídeo. El Global Kit emite
   `.elementor-kit-N button:hover` con (0,2,1) y la regla de arriba es (0,2,0): sin esto, al pasar
   el ratón el color del Kit se pintaba sobre toda la portada. Va a (0,3,0) y declara fondo Y color
   —aunque aquí ninguno de los dos cambie— porque el que se deje sin declarar es justo el que el Kit
   rellena (INSTRUCCIONES §3.1). `:focus` sin `-visible` porque el Kit también tiñe ese. */
.gsv .gsv-card__play:hover,
.gsv .gsv-card__play:focus,
.gsv .gsv-card__play:focus-visible,
.gsv .gsv-card__play:active {
	background: none;
	color: inherit;
	box-shadow: none;
}

/* El círculo es un pseudo-elemento, no el botón: así el área de clic ocupa la tarjeta
   entera (spec: `cursor: pointer` en toda ella) mientras solo se ve el disco de 62px. */
.gsv .gsv-card__play::before {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	width: var(--gsv-play, 62px);
	height: var(--gsv-play, 62px);
	transform: translate(-50%, -50%);
	border-radius: 50%;
	background: rgba(255, 255, 255, .12);
	border: 1.5px solid rgba(255, 255, 255, .55);
	-webkit-backdrop-filter: blur(6px);
	backdrop-filter: blur(6px);
	transition: background .2s ease, border-color .2s ease, transform .2s ease;
}

.gsv .gsv-card__play-ico {
	position: relative;
	z-index: 1;
	width: 22px;
	height: 22px;
	color: var(--gsv-play-fg, #fff);
	fill: currentColor;
	transition: transform .2s ease;
}

.gsv .gsv-card:hover .gsv-card__play::before,
.gsv .gsv-card__play:focus-visible::before {
	background: rgba(255, 255, 255, .22);
	border-color: rgba(255, 255, 255, .85);
	transform: translate(-50%, -50%) scale(1.06);
}

.gsv .gsv-card__play:focus-visible {
	outline: 2px solid var(--gsv-borde-hover, #C2A370);
	outline-offset: -4px;
	border-radius: var(--gsv-radio, 16px);
}

/* «Mostrar botón de play» apagado: se va el disco, no el control. El botón sigue en el
   DOM porque es el único elemento enfocable de la tarjeta. */
.gsv .gsv-card__play.is-oculto::before,
.gsv .gsv-card__play.is-oculto .gsv-card__play-ico {
	opacity: 0;
}

/* Con enlace el play es un <span> decorativo: los clics deben llegar al <a> de debajo. */
.gsv .gsv-card--link .gsv-card__play {
	pointer-events: none;
}

.gsv .gsv-card.is-playing .gsv-card__play {
	opacity: 0;
	pointer-events: none;
}

/* ── Texto ───────────────────────────────────────────────────────────────── */

.gsv .gsv-card__txt {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 3;
	padding: 20px 20px 22px;
	pointer-events: none;
	transition: opacity .3s ease;
}

.gsv .gsv-card__cat {
	display: block;
	margin-bottom: 6px;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 700;
	font-size: 9px;
	line-height: 1.2;
	letter-spacing: .16em;
	text-transform: uppercase;
	color: var(--gs-oro-clr, #C2A370);
}

.gsv .gsv-card__name {
	margin: 0;
	padding: 0;
	font-family: var(--gs-font-display, 'Archivo', 'Arial Narrow', system-ui, sans-serif);
	font-weight: 700;
	font-size: 19px;
	line-height: 1.05;
	letter-spacing: 0;
	text-transform: uppercase;
	color: #fff;
	text-shadow: 0 1px 3px rgba(10, 10, 10, .45);
}

/* ── Carrusel en móvil ───────────────────────────────────────────────────── */

/* 767px es el corte de móvil de Elementor: así el carrusel entra exactamente cuando el
   control «Columnas» aplica su valor de móvil. */
@media (max-width: 767px) {

	.gsv .gsv__grid--carrusel {
		display: flex;
		overflow-x: auto;
		scroll-snap-type: x mandatory;
		/* Sangra hasta los bordes de la pantalla: la tarjeta cortada indica que hay más. */
		margin-inline: calc(var(--gsv-pad-x, 32px) * -1);
		padding-inline: var(--gsv-pad-x, 32px);
		scrollbar-width: none;
	}

	.gsv .gsv__grid--carrusel::-webkit-scrollbar {
		display: none;
	}

	.gsv .gsv__grid--carrusel .gsv-card {
		flex: 0 0 78%;
		scroll-snap-align: center;
	}
}

/* ── Ventana emergente ───────────────────────────────────────────────────── */

/* Se porta a <body> (fuera del widget), así que NO puede colgar de `.gsv`. */
.gsv-modal {
	position: fixed;
	inset: 0;
	z-index: 320;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 4vh 4vw;
	background: rgba(10, 10, 10, .88);
	-webkit-backdrop-filter: blur(4px);
	backdrop-filter: blur(4px);
	opacity: 0;
	visibility: hidden;
	transition: opacity .25s ease, visibility .25s ease;
}

.gsv-modal.is-open {
	opacity: 1;
	visibility: visible;
}

.gsv-modal__box {
	position: relative;
	/* Alto primero: en un 9:16 lo que limita es la altura de la ventana, no su ancho. */
	height: min(92vh, 1200px);
	max-width: 100%;
	aspect-ratio: var(--gsv-modal-ar, 9 / 16);
	background: #000;
	border-radius: 14px;
	overflow: hidden;
	box-shadow: 0 30px 80px rgba(0, 0, 0, .55);
}

.gsv-modal__box > video,
.gsv-modal__box > iframe {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border: 0;
	display: block;
	object-fit: contain;
	background: #000;
}

/* La ✕ cuelga de `.gsv-modal` y no de `.gsv` —la ventana se portalea al `<body>`—, así que aquí no
   llega ninguna raíz que suba la especificidad sola. Se escribe con la raíz de la ventana por
   delante para que la base sea (0,2,0) y el estado (0,3,0): `elementor-kit-N` vive en el `<body>`,
   o sea que portalear NO libra del Kit, al contrario. Es el mismo blindaje que ya hace
   `vista-rapida.css`, que también se abre portaleada. */
.gsv-modal .gsv-modal__close {
	position: absolute;
	top: 10px;
	right: 10px;
	z-index: 2;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	padding: 0;
	border-radius: 50%;
	background: rgba(10, 10, 10, .55);
	border: 1px solid rgba(255, 255, 255, .35);
	color: #fff;
	cursor: pointer;
	appearance: none;
	-webkit-appearance: none;
	box-shadow: none;
	min-height: 0;
	transition: background .2s ease, border-color .2s ease;
}

/* `color` va declarado aunque no cambie: sin él el Kit lo rellenaba con su color de hover y el
   glifo blanco sobre negro se volvía ilegible. `:focus` sin `-visible` porque el Kit tiñe los dos. */
.gsv-modal .gsv-modal__close:hover,
.gsv-modal .gsv-modal__close:focus,
.gsv-modal .gsv-modal__close:focus-visible {
	background: rgba(10, 10, 10, .85);
	border-color: #C2A370;
	color: #fff;
}

.gsv-modal .gsv-modal__close svg {
	width: 16px;
	height: 16px;
}

/* ── Movimiento reducido ─────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {

	.gsv .gsv-card,
	.gsv .gsv-card__play::before,
	.gsv .gsv-card__play-ico,
	.gsv .gsv-card__poster,
	.gsv .gsv-card__shade,
	.gsv .gsv-card__txt,
	.gsv-modal,
	.gsv-modal .gsv-modal__close {
		transition: none;
	}

	.gsv .gsv-card:hover,
	.gsv .gsv-card:focus-within {
		transform: none;
	}

	.gsv .gsv-card:hover .gsv-card__play::before,
	.gsv .gsv-card__play:focus-visible::before {
		transform: translate(-50%, -50%);
	}
}

/* ---- banners.css ---- */
/**
 * Carrusel de banners de portada. Handle 'gs-banners' (deps: gs-tokens, gs-fonts).
 *
 * Familia de prefijo `.gsb-`. NO depende de 'gs-header-base': no es un widget de header, y el
 * `text-decoration: none !important` de esa hoja se comería el subrayado del botón «underline».
 *
 * ── El reparto de trabajo con PHP ────────────────────────────────────────────
 * `Banners\Renderer` aporta los VALORES como custom properties y esta hoja aporta los SELECTORES.
 * Está así por dos motivos que no son de gusto: un `:hover` no se puede escribir en un atributo
 * `style`, y desde PHP no se puede emitir una media query. Casi todo el banner tiene versión de
 * escritorio y de móvil, así que casi todo pasa por aquí.
 *
 * ── El contrato anti-fugas ───────────────────────────────────────────────────
 * El Global Kit de Elementor emite `.elementor-kit-N a:hover` con especificidad (0,2,1). Todas las
 * reglas de hover de este archivo van prefijadas por `.gsb` y declaran fondo Y color, así que
 * ganan por especificidad y no por orden de aparición — que es lo que exige la regla 2 de
 * CLAUDE.md. Ver el comentario de las animaciones, que es el único punto con matiz.
 *
 * Corte de móvil en 767px, el mismo que usa Elementor por defecto.
 */

/* ── Cascarón ────────────────────────────────────────────────────────────── */

.gsb {
	position: relative;
	width: 100%;
}

/* ── A sangre ────────────────────────────────────────────────────────────── */

/* Un banner de portada tiene que llegar a los bordes de la pantalla aunque esté dentro de un
   contenedor con ancho de contenido. Va por opción («Ancho completo» en el panel) y no siempre,
   porque el mismo carrusel se puede colocar en una columna.

   Las dos variables las escribe `banners.js` midiendo de verdad, y los valores de reserva de aquí
   son los que se usan sin JavaScript. Por qué no basta con la reserva:

   - `100vw` **incluye la barra de desplazamiento**. En Windows, con barras clásicas, deja ~15 px de
     scroll horizontal en toda la portada. `document.documentElement.clientWidth` no la incluye.
   - `calc(50% - 50vw)` solo centra si el contenedor está centrado. Con un contenedor con padding
     asimétrico el banner se va de lado; medir el `left` real acierta siempre.

   Es lo mismo que hace Elementor con sus secciones estiradas, y por lo mismo lo hace con JS. */
.gsb--full {
	width: var(--gsb-vw, 100vw);
	max-width: var(--gsb-vw, 100vw);
	margin-left: var(--gsb-ml, calc(50% - 50vw));
}

/* El recorte vive aquí y no en `.gsb`: con la paginación «fuera» los puntos caen por debajo del
   viewport y `.gsb` con overflow oculto se los comería. */
.gsb-viewport {
	position: relative;
	overflow: hidden;

	/* Dos formas de decir cuánto mide el banner, y solo una viaja: `Renderer` emite la variable que
	   toca y pone la otra en `auto`.

	   Con una MEDIDA (`80vh`, `600px`) el alto no depende del ancho, así que la caja cambia de forma
	   según la pantalla y `object-fit: cover` recorta la foto por otro sitio en cada una. Eso es lo
	   que hace que el editor de Elementor —cuyo lienzo siempre es más bajo que la pantalla real— no
	   enseñe el mismo encuadre que la página publicada.

	   Con una PROPORCIÓN (`21/9`) el alto sale del ancho, la caja tiene la misma forma en todas
	   partes y la foto se recorta igual en el editor, en un portátil y en un monitor 4K. */
	height: var(--gsb-h-pc, 80vh);
	aspect-ratio: var(--gsb-ar-pc);
}

.gsb-track {
	display: flex;
	height: 100%;
	transition: transform .6s var(--gs-e-quint);
	will-change: transform;
}

.gsb-slide {
	position: relative;
	flex: 0 0 100%;
	width: 100%;
	height: 100%;
	overflow: hidden;

	/* Las inactivas se ocultan para sacarlas del orden de tabulación y del árbol de
	   accesibilidad — `aria-hidden` solo no basta para lo primero. El retardo iguala la duración
	   del desplazamiento: sin él, la que sale desaparecería de golpe a mitad de transición. */
	visibility: hidden;
	transition: visibility 0s linear .6s;
}

.gsb-slide.is-active {
	visibility: visible;
	transition-delay: 0s;
}

/* ── Medio ───────────────────────────────────────────────────────────────── */

.gsb-media {
	position: absolute;
	inset: 0;
}

/* Prefijadas por la raíz (0,2,0) y con `!important`, igual que `videos.css` y `mosaico.css`, y por
   la misma razón que documenta INSTRUCCIONES §3.2: un reset de tipo con una clase ancestro gana a
   una clase suelta. Elementor emite `.elementor img { height:auto; max-width:100% }` con (0,2,0)…
   perdón, con (0,1,1), y esta hoja declaraba `.gsb-media-el` con (0,1,0). Dentro de una página
   construida con Elementor —o sea, la portada— la imagen caía a `height:auto`, se dimensionaba por
   su proporción natural y `object-fit: cover` dejaba de recortar nada porque la caja ya coincidía
   con la imagen: un banner de 80vh con una foto apaisada dejaba el hueco vacío debajo. Medido:
   356 px de imagen dentro de 814 px de banner. El `!important` no hace falta contra Elementor —la
   raíz ya le gana— pero sí contra los temas que escriben `img { height:auto !important }`, que es
   de donde viene el patrón de los otros dos archivos.

   El `<picture>` entra en la misma regla porque es solo un envoltorio: sin alto propio, su `<img>`
   no tendría contra qué calcular el 100% y el recorte no funcionaría. */
.gsb .gsb-media-pic,
.gsb .gsb-media-el {
	display: block;
	width: 100% !important;
	height: 100% !important;
	max-width: none !important;
}

/* El encuadre del recorte, que es el equivalente exacto de «posición del fondo» de un container.
   Lo elige quien configura cada diapositiva; el valor viaja en la custom property. */
.gsb .gsb-media-el {
	object-fit: cover;
	object-position: var(--gsb-op-pc, 50% 50%);
}

/* Solo para el camino con vídeo: cuando los dos medios son imágenes van en un `<picture>` y es el
   `<source media>` quien elige, sin que ninguna de las dos llegue a descargarse de más.

   Prefijada por la raíz, y no por gusto: la regla del blindaje de arriba declara `display: block`
   con (0,2,0), así que escrita como `.gsb-media--mv` (0,1,0) PERDÍA y los dos vídeos —el de
   escritorio y el de móvil— se pintaban uno encima del otro y sonaban los dos. Empata en
   especificidad y gana por orden, que es lo que hay que mirar cada vez que se sube la de una regla
   base: lo que dependía de ella hay que subirlo también. */
.gsb .gsb-media--mv {
	display: none;
}

/* ── Velo ────────────────────────────────────────────────────────────────── */

/* Lo que hace que un titular se lea sobre una foto cualquiera. Sin él, el contraste depende de por
   dónde quede el cielo, y eso no se arregla con una sombra.

   Sin `z-index` a propósito: va después del medio en el DOM y antes del enlace, así que el orden de
   pintado lo coloca solo —encima de la foto, debajo del enlace (z-index 1) y del contenido (2)—.
   Y `pointer-events: none` porque cubre la diapositiva entera: sin eso se comería los clics del
   enlace del banner, que es justo lo que está debajo. */
.gsb-velo {
	position: absolute;
	inset: 0;
	background: var(--gsb-velo, #000);

	/* La variable viaja de 0 a 100 —el mismo número que se escribe en el panel— y la división vive
	   aquí. Es lo que permite que la vista previa escriba el valor del campo tal cual mientras se
	   arrastra el control, sin tener que convertirlo en JavaScript. */
	opacity: calc(var(--gsb-velo-op, 0) / 100);
	pointer-events: none;
}

/* ── Enlace de la diapositiva entera ─────────────────────────────────────── */

/* Va DEBAJO del contenido (z-index 1 frente a 2) para no tapar los botones, que tienen su propio
   destino. El cuerpo no recibe punteros salvo en sus elementos interactivos, así que el clic en
   cualquier zona muerta del banner cae aquí. */
.gsb-link {
	position: absolute;
	inset: 0;
	z-index: 1;
	display: block;
}

.gsb-link--mv {
	display: none;
}

/* (0,4,0), fondo Y color, aunque el enlace no tenga ni una cosa ni la otra.
   No es un trámite: `.gsb-link` es un <a> vacío que cubre la diapositiva ENTERA con
   `position:absolute; inset:0`, así que el `.elementor-kit-N a:hover` del Global Kit —que llega
   con (0,2,1) y suele traer `background-color`— pintaría un rectángulo de color sobre todo el
   banner con solo pasar el ratón. Es el peor caso posible de la fuga que documenta la regla 2. */
.gsb .gsb-slide .gsb-link:hover,
.gsb .gsb-slide .gsb-link:focus,
.gsb .gsb-slide .gsb-link:active {
	background: transparent;
	color: inherit;
	text-decoration: none;
}

/* ── Contenido ───────────────────────────────────────────────────────────── */

.gsb-body {
	position: absolute;
	inset: 0;
	z-index: 2;
	display: flex;
	flex-direction: column;
	justify-content: var(--gsb-jc-pc, center);
	align-items: var(--gsb-ai-pc, center);
	padding: var(--gsb-pad-pc, 60px);
	text-align: var(--gsb-ta-pc, center);
	pointer-events: none;
}

.gsb-titulo {
	max-width: 100%;
	margin: 0;
	color: var(--gsb-fg, #fff);
	font-family: var(--gsb-ff, var(--gs-font-display));
	font-size: var(--gsb-fs, 50px);
	font-weight: 700;
	line-height: 1.1;

	/* La traía el snippet y aquí se había perdido. No es decoración: el título va SOBRE una foto
	   que quien configura elige después, y no hay forma de garantizar contraste contra una imagen
	   cualquiera. La sombra es lo que hace legible un texto claro sobre un cielo blanco. */
	text-shadow: 0 2px 15px rgba(0, 0, 0, .3);
}

.gsb-titulo--mv {
	display: none;
}

/* Hereda color y familia del título —son las mismas variables— y solo cambia de tamaño y peso. Es
   deliberado: un subtítulo con otra tipografía y otro color casi siempre empeora el banner, y darle
   los suyos costaría siete campos más por diapositiva que el presupuesto no da. */
.gsb-subtitulo {
	max-width: 100%;
	margin: 12px 0 0;
	color: var(--gsb-fg, #fff);
	font-family: var(--gsb-ff, var(--gs-font-display));
	font-size: var(--gsb-sub-fs, 20px);
	font-weight: 400;
	line-height: 1.4;
	text-shadow: 0 2px 15px rgba(0, 0, 0, .3);
}

.gsb-subtitulo--mv {
	display: none;
}

.gsb-botones {
	display: flex;
	flex-direction: var(--gsb-btn-fd-pc, row);
	flex-wrap: wrap;
	gap: 14px;
	margin-top: 24px;
}

/* La columna hereda la alineación horizontal del cuerpo para que «botones apilados a la derecha»
   quede a la derecha y no centrado. */
.gsb-body .gsb-botones {
	align-items: var(--gsb-ai-pc, center);
}

/* Apilados, los dos del mismo ancho, como en el snippet. `max-content` deja la columna del ancho
   del botón más largo y `stretch` estira el corto hasta ahí. El snippet necesitaba un igualador de
   anchos en JavaScript para esto; con la clase que pone `Renderer::botones()` sale del CSS. */
.gsb-body .gsb-botones--stack-pc {
	width: max-content;
	max-width: 100%;
	align-items: stretch;
}

.gsb .gsb-slide .gsb-botones--stack-pc .gsb-btn {
	width: 100%;
}

/* ── Botones ─────────────────────────────────────────────────────────────── */

/* Prefijada por la raíz igual que las de hover, y por el mismo motivo. El Global Kit emite
   `.elementor-kit-N a` con (0,2,1) y eso también alcanza al ESTADO NORMAL: con la regla escrita
   como `.gsb-btn` (0,1,0) los botones salían subrayados y con el color de enlace del tema. Se vio
   en pantalla, no se dedujo. */
.gsb .gsb-slide .gsb-btn {
	display: inline-block;
	padding: var(--gsb-btn-pv, 15px) var(--gsb-btn-ph, 40px);
	border: var(--gsb-btn-bw, 0) solid var(--gsb-btn-bd, transparent);
	border-radius: var(--gsb-btn-r, 0);
	background: var(--gsb-btn-bg, #fff);
	color: var(--gsb-btn-fg, #000);
	font-family: var(--gsb-btn-ff, var(--gs-font-ui));
	font-size: var(--gsb-btn-fs, 14px);
	font-weight: 600;
	line-height: 1.2;
	text-align: center;
	text-decoration: none;
	text-transform: var(--gsb-btn-tt, uppercase);
	cursor: pointer;

	/* El cuerpo no recibe punteros; los botones sí. */
	pointer-events: auto;

	transition:
		background-color .25s var(--gs-e-soft),
		color .25s var(--gs-e-soft),
		border-color .25s var(--gs-e-soft),
		transform .25s var(--gs-e-out),
		box-shadow .25s var(--gs-e-out);
}

/* Un botón sin destino se pinta como <span>: no navega, así que tampoco debe parecer pulsable.
   La especificidad tiene que superar a la regla base de arriba —(0,3,0)— o el `cursor: pointer` de
   allí gana y el <span> sigue pareciendo pulsable. Escrita como `.gsb span.gsb-btn` era (0,2,1) y
   perdía. */
.gsb .gsb-slide span.gsb-btn {
	cursor: default;
}

/* (0,4,0) contando la pseudoclase: por encima del (0,2,1) del Global Kit. Declara fondo Y color,
   como manda el contrato. `:focus` va en la MISMA declaración a propósito — el `:hover` no se
   puede comprobar conduciendo Chrome, y así verificar el foco verifica esta cascada. */
.gsb .gsb-slide .gsb-btn:hover,
.gsb .gsb-slide .gsb-btn:focus,
.gsb .gsb-slide .gsb-btn:active {
	background: var(--gsb-btn-bg-h, #000);
	color: var(--gsb-btn-fg-h, #fff);
	border-color: var(--gsb-btn-bd-h, transparent);

	/* También aquí: el Kit subraya los enlaces al pasar por encima. Va ANTES que las animaciones
	   para que la de «se subraya», que empata en especificidad, gane por orden. */
	text-decoration: none;
}

/* Las animaciones NO repiten fondo ni color a propósito: la regla de arriba ya los fija con la
   misma especificidad (0,4,0) para todos los `.gsb-btn`, y el Kit pierde igual. Repetir aquí los
   dos colores obligaría a mantenerlos en siete sitios. */
.gsb .gsb-slide .gsb-btn--lift:hover,
.gsb .gsb-slide .gsb-btn--lift:focus,
.gsb .gsb-slide .gsb-btn--lift:active {
	transform: translateY(-3px);
}

.gsb .gsb-slide .gsb-btn--scale:hover,
.gsb .gsb-slide .gsb-btn--scale:focus,
.gsb .gsb-slide .gsb-btn--scale:active {
	transform: scale(1.05);
}

.gsb .gsb-slide .gsb-btn--shadow:hover,
.gsb .gsb-slide .gsb-btn--shadow:focus,
.gsb .gsb-slide .gsb-btn--shadow:active {
	box-shadow: 0 12px 28px rgba(0, 0, 0, .28);
}

.gsb .gsb-slide .gsb-btn--lift-shadow:hover,
.gsb .gsb-slide .gsb-btn--lift-shadow:focus,
.gsb .gsb-slide .gsb-btn--lift-shadow:active {
	transform: translateY(-3px);
	box-shadow: 0 12px 28px rgba(0, 0, 0, .28);
}

.gsb .gsb-slide .gsb-btn--glow:hover,
.gsb .gsb-slide .gsb-btn--glow:focus,
.gsb .gsb-slide .gsb-btn--glow:active {
	box-shadow: 0 0 0 3px var(--gsb-btn-bg-h, rgba(255, 255, 255, .35));
}

.gsb .gsb-slide .gsb-btn--underline:hover,
.gsb .gsb-slide .gsb-btn--underline:focus,
.gsb .gsb-slide .gsb-btn--underline:active {
	text-decoration: underline;
	text-underline-offset: 4px;
}

/* ── Flechas ─────────────────────────────────────────────────────────────── */

.gsb-nav {
	position: absolute;
	top: 50%;
	z-index: 3;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	transform: translateY(-50%);
	border: 0;
	border-radius: var(--gs-r-pill);
	background: transparent;
	color: var(--gsb-nav, #fff);
	cursor: pointer;
	transition: background-color .2s var(--gs-e-soft), color .2s var(--gs-e-soft);
}

.gsb-nav svg {
	width: 24px;
	height: 24px;
}

.gsb-nav--prev {
	left: 12px;
}

.gsb-nav--next {
	right: 12px;
}

/* (0,3,0): por encima del Global Kit, con fondo Y color declarados. */
.gsb .gsb-nav:hover,
.gsb .gsb-nav:focus,
.gsb .gsb-nav:active {
	background: rgba(0, 0, 0, .32);
	color: var(--gsb-nav, #fff);
}

/* ── Paginación ──────────────────────────────────────────────────────────── */

.gsb-dots {
	display: flex;
	justify-content: center;
	gap: var(--gsb-dot-gap, 6px);
}

.gsb-dots--inside {
	position: absolute;
	right: 0;
	bottom: 18px;
	left: 0;
	z-index: 3;
}

.gsb-dots--outside {
	margin-top: 14px;
}

.gsb-dot {
	width: var(--gsb-dot-size, 12px);
	height: var(--gsb-dot-size, 12px);
	padding: 0;
	border: 0;
	background: var(--gsb-dot-off, #fff);
	cursor: pointer;
	opacity: .55;
	transition: opacity .2s var(--gs-e-soft), background-color .2s var(--gs-e-soft);
}

.gsb-dots--circle .gsb-dot {
	border-radius: var(--gs-r-pill);
}

.gsb-dots--rounded .gsb-dot {
	border-radius: var(--gs-r-sm);
}

.gsb-dot[aria-current="true"] {
	background: var(--gsb-dot-on, #2271b1);
	opacity: 1;
}

/* (0,3,0), fondo Y color. El color no se ve (el punto no tiene texto) pero se declara igual: el
   contrato es que ninguna regla de hover propia deje uno de los dos al azar del Kit. */
.gsb .gsb-dot:hover,
.gsb .gsb-dot:focus,
.gsb .gsb-dot:active {
	background: var(--gsb-dot-on, #2271b1);
	color: var(--gsb-dot-on, #2271b1);
	opacity: 1;
}

/* ── Foco visible ────────────────────────────────────────────────────────── */

.gsb .gsb-btn:focus-visible,
.gsb .gsb-nav:focus-visible,
.gsb .gsb-dot:focus-visible,
.gsb .gsb-link:focus-visible {
	outline: 3px solid var(--gs-oro);
	outline-offset: 3px;
}

/* ── Texto solo para lectores de pantalla ────────────────────────────────── */

/* Propio y no heredado del tema: el plugin no puede dar por hecho que exista. Mismo bloque que
   `archivo.css`, `perfil.css` y `producto-base.css`. */
.gsb .screen-reader-text {
	position: absolute !important;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	border: 0;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
}

/* ── Móvil ───────────────────────────────────────────────────────────────── */

@media (max-width: 767px) {

	.gsb-viewport {
		height: var(--gsb-h-mv, 70vh);
		aspect-ratio: var(--gsb-ar-mv);
	}

	/* Con raíz por lo mismo que su gemela de escritorio: el blindaje del medio declara
	   `display: block` con (0,2,0) y una clase suelta no le gana ni dentro de una media query. */
	.gsb .gsb-media--pc {
		display: none;
	}

	.gsb .gsb-media--mv {
		display: block;
	}

	.gsb-link--pc {
		display: none;
	}

	.gsb-link--mv {
		display: block;
	}

	.gsb-body {
		justify-content: var(--gsb-jc-mv, center);
		align-items: var(--gsb-ai-mv, center);
		padding: var(--gsb-pad-mv, 24px);
		text-align: var(--gsb-ta-mv, center);
	}

	.gsb .gsb-media-el {
		object-position: var(--gsb-op-mv, 50% 50%);
	}

	/* El apilado se decide por dispositivo, así que lo de escritorio se deshace antes de aplicar lo
	   de móvil: si no, un banner apilado solo en escritorio arrastraría aquí el `max-content`. */
	.gsb-body .gsb-botones {
		flex-direction: var(--gsb-btn-fd-mv, row);
		align-items: var(--gsb-ai-mv, center);
		width: auto;
	}

	.gsb .gsb-slide .gsb-botones .gsb-btn {
		width: auto;
	}

	.gsb-body .gsb-botones--stack-mv {
		width: max-content;
		max-width: 100%;
		align-items: stretch;
	}

	.gsb .gsb-slide .gsb-botones--stack-mv .gsb-btn {
		width: 100%;
	}

	.gsb-titulo--pc {
		display: none;
	}

	.gsb-titulo--mv {
		display: block;
	}

	.gsb-subtitulo--pc {
		display: none;
	}

	.gsb-subtitulo--mv {
		display: block;
	}

	/* Mismo trato que el título: el modelo guarda un tamaño pensado para escritorio y aquí se le
	   pone tope para que no se coma la pantalla del teléfono. */
	.gsb-subtitulo {
		margin-top: 8px;
		font-size: min(var(--gsb-sub-fs, 20px), 4.5vw);
	}

	/* El modelo guarda UN tamaño de título, pensado para escritorio. El snippet lo bajaba al 60% en
	   el móvil, y así estaba calibrada la portada que hay que reproducir; el `min()` con 11vw se
	   conserva encima porque el 60% de un titular de 120px sigue sin caber en un teléfono. Sin el
	   factor, un tamaño de 50px salía a ~43px en un móvil de 390px donde antes salía a 30. */
	.gsb-titulo {
		font-size: min(calc(var(--gsb-fs, 50px) * .6), 11vw);
	}

	.gsb-nav {
		width: 38px;
		height: 38px;
	}

	.gsb-nav--prev {
		left: 6px;
	}

	.gsb-nav--next {
		right: 6px;
	}
}

/* ── Sin ratón: las flechas estorban más de lo que ayudan ────────────────── */

@media (hover: none) and (pointer: coarse) {

	.gsb-nav {
		display: none;
	}
}

/* ── Movimiento reducido ─────────────────────────────────────────────────── */

/* Aquí no es un trámite: el autoplay lo apaga `banners.js` leyendo la misma consulta, y esto se
   ocupa de que el cambio manual tampoco desplace nada. La diapositiva se sustituye, no viaja. */
@media (prefers-reduced-motion: reduce) {

	.gsb-track {
		transition: none;
	}

	.gsb-slide {
		transition: none;
	}

	.gsb-btn {
		transition: none;
	}

	.gsb .gsb-slide .gsb-btn--lift:hover,
	.gsb .gsb-slide .gsb-btn--lift:focus,
	.gsb .gsb-slide .gsb-btn--lift:active,
	.gsb .gsb-slide .gsb-btn--scale:hover,
	.gsb .gsb-slide .gsb-btn--scale:focus,
	.gsb .gsb-slide .gsb-btn--scale:active,
	.gsb .gsb-slide .gsb-btn--lift-shadow:hover,
	.gsb .gsb-slide .gsb-btn--lift-shadow:focus,
	.gsb .gsb-slide .gsb-btn--lift-shadow:active {
		transform: none;
	}

	.gsb-nav,
	.gsb-dot {
		transition: none;
	}
}

/* ---- archivo.css ---- */
/**
 * GS Archivo de Categoría. Handle 'gs-archivo' (deps: gs-tarjetas → gs-tokens, gs-fonts).
 *
 * Prefijo propio `.gsa-`. Las tarjetas NO se estilan aquí: vienen de tarjetas.css, del que
 * este archivo depende. Lo único que se toca de ellas es el contenedor (`.gsa .gsp-cards`),
 * porque dentro del archivo manda su parrilla y no el ancho de maquetación que la parrilla
 * suelta usa cuando va sola en una sección.
 *
 * Los filtros no ocupan columna: viven en un panel que entra desde la derecha, de modo que
 * la parrilla dispone del ancho completo para sus cuatro columnas.
 *
 * Los colores y medidas llegan como variables desde los controles de Elementor
 * (`selectors`); los valores que hay aquí son los de partida del diseño.
 *
 * Tipografías: el sistema del plugin trae Archivo, Inter y Montserrat autoalojadas. Donde el
 * boceto pedía Anton se deja esa familia PRIMERO en la cadena, de modo que si el sitio llega
 * a cargarla se usa, y si no se cae con naturalidad a Archivo. No se declara ningún
 * @font-face nuevo.
 */

.gsa {
	width: 100%;
	background-color: var(--gsa-fondo, #FAFAF7);
	padding-bottom: var(--gsa-pad-b, 80px);

	/* Contenedor */
	--gsa-max: 80rem;
	--gsa-pad-x: 32px;

	/* Parrilla */
	--gsa-cols: 4;
	--gsa-gap: 20px;

	/* Panel de filtros */
	--gsa-panel-w: 400px;

	/* Paleta */
	--gsa-tinta: #0A0A0A;
	--gsa-linea: #E8E2D9;
	--gsa-oro: #9C7A34;
	--gsa-oro-pale: #FBF6EE;
	--gsa-gris: #888888;
}

.gsa,
.gsa * {
	box-sizing: border-box;
}

/* Los temas suelen traer esta clase, pero no todos: aquí se define para no depender de ello
   (sin la regla, las etiquetas de los lectores de pantalla se verían en pantalla). */
.gsa .screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* El padding se SUMA al ancho de contenido en vez de restarlo: así la primera tarjeta
   arranca justo en la línea de 80rem, alineada con el resto de secciones del sitio. */
.gsa__crumbs-in,
.gsa__hero-in,
.gsa__tabs-in,
.gsa__inner {
	width: 100%;
	max-width: calc(var(--gsa-max, 80rem) + var(--gsa-pad-x, 32px) * 2);
	margin-inline: auto;
	padding-inline: var(--gsa-pad-x, 32px);
}

/* ── Ruta de navegación ──────────────────────────────────────────────────── */

.gsa .gsa__crumbs {
	padding-block: 14px 0;
}

.gsa .gsa__crumbs-in {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 6px;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-size: 11px;
	line-height: 1.4;
	letter-spacing: .08em;
}

.gsa .gsa__crumb {
	color: var(--gsa-crumb, #888888);
	text-decoration: none;
	transition: color .18s ease;
}

.gsa a.gsa__crumb:hover,
.gsa a.gsa__crumb:focus-visible,
.gsa a.gsa__crumb:focus {
	background: transparent;
	color: var(--gsa-crumb-act, #0A0A0A);
	text-decoration: none;
}

.gsa .gsa__crumb.is-actual {
	color: var(--gsa-crumb-act, #0A0A0A);
}

.gsa .gsa__sep {
	color: var(--gsa-crumb-sep, #C8C2B8);
}

/* ── Encabezado ──────────────────────────────────────────────────────────── */

/* Sin franja oscura: el título va en negro sobre el fondo de la sección. El color de fondo
   sigue siendo un control del panel, por si algún día se quiere la versión en negativo. */
.gsa .gsa__hero {
	background: var(--gsa-hero-bg, transparent);
	padding-block: 30px 44px;
}

.gsa .gsa__hero-in {
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	gap: 24px;
	flex-wrap: wrap;
}

.gsa .gsa__eyebrow {
	display: block;
	font-family: 'Bebas Neue', var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 600;
	font-size: 13px;
	line-height: 1;
	letter-spacing: .3em;
	text-transform: uppercase;
	color: var(--gsa-eyebrow, #9C7A34);
	margin-bottom: 12px;
}

.gsa .gsa__titulo {
	font-family: 'Anton', var(--gs-font-display, 'Archivo', 'Arial Narrow', sans-serif);
	font-weight: 700;
	font-size: clamp(28px, 4.2vw, 44px);
	line-height: 1;
	letter-spacing: -.01em;
	text-transform: uppercase;
	color: var(--gsa-titulo, #0A0A0A);
	/* Anti-tema: los h1 llegan con márgenes y tamaños propios. */
	margin: 0;
	padding: 0;
}

.gsa .gsa__hero-num {
	display: flex;
	align-items: baseline;
	gap: 8px;
}

.gsa .gsa__num {
	font-family: 'Anton', var(--gs-font-display, 'Archivo', 'Arial Narrow', sans-serif);
	font-weight: 700;
	font-size: 36px;
	line-height: 1;
	color: var(--gsa-num, #9C7A34);
}

.gsa .gsa__num-lbl {
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 600;
	font-size: 11px;
	line-height: 1;
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--gsa-num-lbl, #6B6B6B);
}

/* ── Pestañas de subcategoría (apagadas por defecto) ─────────────────────── */

.gsa .gsa__tabs {
	border-bottom: 1px solid var(--gsa-linea, #E8E2D9);
}

.gsa .gsa__tabs-in {
	display: flex;
	align-items: stretch;
	/* En móvil la fila se desliza en vez de romperse en varias líneas. */
	overflow-x: auto;
	scrollbar-width: none;
}

.gsa .gsa__tabs-in::-webkit-scrollbar {
	display: none;
}

.gsa .gsa__tab {
	flex: 0 0 auto;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 600;
	font-size: 11px;
	line-height: 1;
	letter-spacing: .14em;
	text-transform: uppercase;
	padding: 14px 20px;
	color: var(--gsa-tab, #888888);
	text-decoration: none;
	white-space: nowrap;
	border-bottom: 2px solid transparent;
	transition: color .18s ease, border-color .18s ease;
}

.gsa a.gsa__tab:hover,
.gsa a.gsa__tab:focus-visible,
.gsa a.gsa__tab:focus {
	background: transparent;
	color: var(--gsa-tab-hover, #0A0A0A);
	text-decoration: none;
}

.gsa .gsa__tab.is-activo {
	font-weight: 700;
	color: var(--gsa-tab-act, #0A0A0A);
	border-bottom-color: var(--gsa-tab-linea, #9C7A34);
}

/* ── Barra de filtros y orden ────────────────────────────────────────────── */

/* Dos reglas horizontales encierran la barra, como en el boceto. Sin cajas ni bordes en los
   controles: el peso visual lo llevan las tarjetas, no la barra. */
.gsa .gsa__barra {
	border-top: 1px solid var(--gsa-linea, #E8E2D9);
	border-bottom: 1px solid var(--gsa-linea, #E8E2D9);
	padding-block: 13px;
	display: flex;
	flex-direction: column;
	gap: 7px;
}

.gsa .gsa__barra-fila {
	display: flex;
	align-items: center;
	gap: 26px;
	flex-wrap: wrap;
}

.gsa .gsa__barra-fila.is-meta {
	gap: 10px;
}

.gsa .gsa__filtrar {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 0;
	border: 0;
	background: transparent;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 700;
	font-size: 11px;
	line-height: 1;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--gsa-tinta, #0A0A0A);
	cursor: pointer;
	transition: color .18s ease, transform .16s var(--gs-e-out, cubic-bezier(.22, 1, .36, 1));
	/* Anti-tema: los botones del tema traen alto mínimo, sombra y relleno. */
	box-shadow: none;
	min-height: 0;
	appearance: none;
	-webkit-appearance: none;
}

.gsa .gsa__filtrar:hover,
.gsa .gsa__filtrar:focus-visible,
.gsa .gsa__filtrar:focus {
	background: transparent;
	color: var(--gsa-oro, #9C7A34);
}

.gsa .gsa__filtrar-n {
	color: var(--gsa-oro, #9C7A34);
	font-weight: 700;
}

.gsa .gsa__ico {
	width: 15px;
	height: 15px;
	display: block;
	flex: 0 0 15px;
}

/* Selector de orden */

.gsa .gsa__orden {
	position: relative;
	display: inline-flex;
	align-items: center;
}

.gsa .gsa__orden-sel {
	appearance: none;
	-webkit-appearance: none;
	min-width: 200px;
	padding: 0 24px 0 0;
	border: 0;
	border-radius: 0;
	background: transparent;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 600;
	font-size: 11px;
	line-height: 1;
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--gsa-tinta, #0A0A0A);
	cursor: pointer;
	/* Anti-tema: los select del tema traen alto mínimo, borde y sombra. */
	box-shadow: none;
	min-height: 0;
	height: auto;
}

.gsa .gsa__orden-ico {
	position: absolute;
	right: 4px;
	width: 11px;
	height: 11px;
	pointer-events: none;
	color: var(--gsa-tinta, #0A0A0A);
}

/* Cuadrícula / lista (apagado por defecto) */

.gsa .gsa__vista {
	display: inline-flex;
	border: 1px solid var(--gsa-linea, #E8E2D9);
	border-radius: 6px;
	overflow: hidden;
	margin-left: auto;
}

.gsa .gsa__vista-btn {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 34px;
	height: 30px;
	padding: 0;
	border: 0;
	background: transparent;
	color: var(--gsa-gris, #888888);
	cursor: pointer;
	transition: background-color .15s ease, color .15s ease,
		transform .16s var(--gs-e-out, cubic-bezier(.22, 1, .36, 1));
}

.gsa .gsa__vista-btn + .gsa__vista-btn {
	border-left: 1px solid var(--gsa-linea, #E8E2D9);
}

.gsa .gsa__vista-btn.is-activo {
	background: var(--gsa-oro-pale, #FBF6EE);
	color: var(--gsa-oro, #9C7A34);
}

/* Fila inferior: total, chips y limpiar */

.gsa .gsa__conteo {
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-size: 12px;
	line-height: 1.2;
	color: var(--gsa-conteo, #888888);
}

.gsa .gsa__chip {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	padding: 5px 9px;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 600;
	font-size: 10px;
	line-height: 1;
	letter-spacing: .08em;
	text-transform: uppercase;
	background: var(--gsa-chip-bg, #FBF6EE);
	border: 1px solid var(--gsa-chip-borde, rgba(156, 122, 52, .3));
	border-radius: 99px;
	color: var(--gsa-chip-txt, #9C7A34);
	text-decoration: none;
}

.gsa a.gsa__chip:hover,
.gsa a.gsa__chip:focus-visible,
.gsa a.gsa__chip:focus {
	border-color: var(--gsa-oro, #9C7A34);
	background: var(--gsa-chip-bg, #FBF6EE);
	color: var(--gsa-chip-txt, #9C7A34);
	text-decoration: none;
}

.gsa .gsa__chip-x {
	font-size: 13px;
	line-height: 1;
	opacity: .75;
}

.gsa .gsa__limpiar-mini {
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 600;
	font-size: 10px;
	line-height: 1;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--gsa-gris, #888888);
	text-decoration: underline;
	text-underline-offset: 3px;
	transition: color .18s ease;
}

.gsa a.gsa__limpiar-mini:hover,
.gsa a.gsa__limpiar-mini:focus-visible,
.gsa a.gsa__limpiar-mini:focus {
	background: transparent;
	color: var(--gsa-oro, #9C7A34);
}

/* ── Resultados ──────────────────────────────────────────────────────────── */

.gsa .gsa__resultados {
	margin-top: 22px;
	/* Mientras llega la respuesta AJAX el bloque se atenúa: se ve que algo pasa sin que la
	   página dé un salto (la altura se conserva hasta que llega el reemplazo). */
	transition: opacity .18s ease;
}

.gsa.is-cargando .gsa__resultados {
	opacity: .45;
	pointer-events: none;
}

/* Dentro del archivo manda su parrilla: la de tarjetas.css lleva su propio ancho máximo de
   maquetación, que aquí sobra porque el contenedor ya lo aplica. */
.gsa .gsp-cards {
	grid-template-columns: repeat(var(--gsa-cols, 4), 1fr);
	gap: var(--gsa-gap, 20px);
	max-width: none;
	margin-inline: 0;
}

.gsa .gsa__vacio {
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-size: 14px;
	color: var(--gsa-gris, #888888);
	padding: 48px 0;
	margin: 0;
}

/* Vista de lista: cambia la disposición, no la tarjeta. No hay segunda plantilla ni segunda
   consulta; es la misma parrilla con una columna y la tarjeta puesta en horizontal. */
.gsa .gsa__resultados.is-lista .gsp-cards {
	grid-template-columns: 1fr;
}

@media (min-width: 561px) {

	.gsa .gsa__resultados.is-lista .gsp-card {
		display: grid;
		grid-template-columns: 220px 1fr;
		align-items: center;
	}

	.gsa .gsa__resultados.is-lista .gsp-card__media {
		height: 100%;
		min-height: 200px;
		border-bottom: 0;
		border-right: 1px solid var(--gsa-linea, #E8E2D9);
	}
}

/* ── Paginación ──────────────────────────────────────────────────────────── */

.gsa .gsa__pag {
	display: flex;
	align-items: center;
	justify-content: center;
	flex-wrap: wrap;
	gap: 6px;
	margin-top: 40px;
}

.gsa .gsa__pag-num,
.gsa .gsa__pag-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 32px;
	height: 32px;
	padding: 0 8px;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 600;
	font-size: 12px;
	line-height: 1;
	border: 1px solid var(--gsa-linea, #E8E2D9);
	border-radius: 6px;
	color: var(--gsa-tinta, #0A0A0A);
	text-decoration: none;
	transition: border-color .18s ease, color .18s ease,
		transform .16s var(--gs-e-out, cubic-bezier(.22, 1, .36, 1));
}

.gsa a.gsa__pag-num:hover,
.gsa a.gsa__pag-btn:hover,
.gsa a.gsa__pag-num:focus-visible,
.gsa a.gsa__pag-btn:focus-visible,
.gsa a.gsa__pag-num:focus,
.gsa a.gsa__pag-btn:focus {
	border-color: var(--gsa-oro, #9C7A34);
	background: transparent;
	color: var(--gsa-oro, #9C7A34);
	text-decoration: none;
}

.gsa .gsa__pag-num.is-activo {
	border-color: var(--gsa-oro, #9C7A34);
	color: var(--gsa-oro, #9C7A34);
	font-weight: 700;
}

.gsa .gsa__pag-btn.is-off {
	opacity: .35;
}

.gsa .gsa__pag-gap {
	color: var(--gsa-gris, #888888);
	padding: 0 4px;
}

/* ── Panel de filtros ────────────────────────────────────────────────────── */

.gsa .gsa__velo {
	position: fixed;
	inset: 0;
	z-index: 295;
	background: rgba(10, 10, 10, .5);
	opacity: 0;
	transition: opacity .28s ease;
}

.gsa.is-filtros .gsa__velo {
	opacity: 1;
}

/* `hidden` lo pone y lo quita el JS al terminar la transición, para que el velo no siga
   capturando clics cuando ya no se ve. */
.gsa .gsa__velo[hidden] {
	display: none;
}

.gsa .gsa__panel {
	position: fixed;
	top: 0;
	right: 0;
	bottom: 0;
	z-index: 300;
	width: min(var(--gsa-panel-w, 400px), 92vw);
	display: flex;
	flex-direction: column;
	background: #FFFFFF;
	/* Copia literal de `--gs-sh-drawer`: es el mismo cajón lateral que el minicarrito y el
	   buscador, y con el valor escrito a mano cambiar la sombra del sitio dejaba este panel
	   fuera. El literal se queda como respaldo por si la hoja se sirve sin tokens. */
	box-shadow: var(--gs-sh-drawer, -12px 0 54px rgba(10, 10, 10, .2));
	transform: translateX(100%);
	visibility: hidden;
	transition: transform .3s var(--gs-e-out, cubic-bezier(.22, 1, .36, 1)), visibility .3s;
}

.gsa.is-filtros .gsa__panel {
	transform: translateX(0);
	visibility: visible;
}

.gsa .gsa__panel-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	flex: 0 0 auto;
	padding: 18px 22px;
	background: var(--gsa-panel-bg, #0A0A0A);
}

.gsa .gsa__panel-tit {
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 700;
	font-size: 12px;
	line-height: 1;
	letter-spacing: .16em;
	text-transform: uppercase;
	color: var(--gsa-panel-txt, #FFFFFF);
}

.gsa .gsa__panel-x {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 30px;
	height: 30px;
	padding: 0;
	border: 0;
	background: transparent;
	color: var(--gsa-panel-x, #C2A370);
	cursor: pointer;
	transition: color .18s ease, transform .18s ease;
}

.gsa .gsa__panel-x:hover,
.gsa .gsa__panel-x:focus-visible {
	background: transparent;
	color: #FFFFFF;
	transform: rotate(90deg);
}

.gsa .gsa__panel-body {
	flex: 1 1 auto;
	overflow-y: auto;
	padding: 0 22px 20px;
	-webkit-overflow-scrolling: touch;
}

/* ── Bloques del panel ───────────────────────────────────────────────────── */

.gsa .gsa__bloque {
	border-bottom: 1px solid var(--gsa-linea, #E8E2D9);
	padding-block: 20px;
}

.gsa .gsa__bloque:last-child {
	border-bottom: 0;
}

.gsa .gsa__bloque-tit {
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 700;
	font-size: 11px;
	line-height: 1.2;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--gsa-bloque-tit, #0A0A0A);
	margin: 0 0 14px;
	padding: 0;
}

/* Precio */

.gsa .gsa__range {
	width: 100%;
	margin: 0;
	accent-color: var(--gsa-oro, #9C7A34);
	cursor: pointer;
}

.gsa .gsa__range-vals {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	margin-top: 8px;
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-size: 12px;
	color: var(--gsa-gris, #888888);
}

.gsa .gsa__range-max {
	font-weight: 700;
	color: var(--gsa-oro, #9C7A34);
}

.gsa .gsa__range-form {
	display: flex;
	gap: 6px;
	margin-top: 10px;
}

/* Pastillas (talla y demás atributos) */

.gsa .gsa__pills {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

.gsa .gsa__pill {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 42px;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 600;
	font-size: 11px;
	line-height: 1;
	letter-spacing: .04em;
	padding: 9px 12px;
	border: 1px solid var(--gsa-linea, #E8E2D9);
	border-radius: 7px;
	background: transparent;
	color: var(--gsa-tinta, #0A0A0A);
	text-decoration: none;
	transition: border-color .18s ease, background-color .18s ease, color .18s ease;
}

.gsa a.gsa__pill:hover,
.gsa a.gsa__pill:focus-visible,
.gsa a.gsa__pill:focus {
	border-color: var(--gsa-oro, #9C7A34);
	background: var(--gsa-pill-bg, transparent);
	color: var(--gsa-pill-fg, var(--gsa-tinta, #0A0A0A));
	text-decoration: none;
}

/* El borde activo pasa de 1px a 2px. Se compensa con el padding para que la pastilla no dé
   un salto de 1px al seleccionarla y arrastre a las vecinas. */
.gsa .gsa__pill.is-activo {
	--gsa-pill-bg: var(--gsa-oro-pale, #FBF6EE);
	--gsa-pill-fg: var(--gsa-oro, #9C7A34);
	border: 2px solid var(--gsa-oro, #9C7A34);
	background: var(--gsa-pill-bg);
	color: var(--gsa-pill-fg);
	padding: 8px 11px;
}

/* Un valor que no existe en el resultado actual sigue ahí (para poder volver a él) pero
   apagado: pulsarlo llevaría a una parrilla vacía. */
.gsa .gsa__pill.is-vacio,
.gsa .gsa__color.is-vacio,
.gsa .gsa__check.is-vacio {
	opacity: .35;
}

/* Colores */

.gsa .gsa__colores {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
}

.gsa .gsa__color {
	position: relative;
	display: block;
	width: 26px;
	height: 26px;
	border-radius: 50%;
	border: 1px solid var(--gsa-linea, #E8E2D9);
	background: var(--gsa-swatch, #FFFFFF);
	text-decoration: none;
	transition: border-color .18s ease, box-shadow .18s ease;
}

.gsa .gsa__color.is-activo {
	border: 2px solid var(--gsa-oro, #9C7A34);
	box-shadow: 0 0 0 2px rgba(156, 122, 52, .25);
}

/* Sin color conocido: se marca con una diagonal en vez de fingir un tono que no es. */
.gsa .gsa__color.is-sin-color {
	background:
		linear-gradient(135deg, transparent 46%, var(--gsa-linea, #E8E2D9) 46%, var(--gsa-linea, #E8E2D9) 54%, transparent 54%),
		#FFFFFF;
}

/* Casillas (disponibilidad y tipo) */

.gsa .gsa__checks {
	display: flex;
	flex-direction: column;
	gap: 11px;
}

.gsa .gsa__check {
	display: flex;
	align-items: center;
	gap: 10px;
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-size: 13px;
	line-height: 1.2;
	color: var(--gs-txt-2, #555555);
	text-decoration: none;
}

.gsa a.gsa__check:hover,
.gsa a.gsa__check:focus-visible,
.gsa a.gsa__check:focus {
	background: transparent;
	color: var(--gsa-tinta, #0A0A0A);
	text-decoration: none;
}

/* Casilla dibujada: la fila es un enlace (para que funcione sin JS) y un <input> real dentro
   de un <a> no sería activable. El aspecto es el de un checkbox con accent-color. */
.gsa .gsa__check-box {
	position: relative;
	width: 16px;
	height: 16px;
	flex: 0 0 16px;
	border: 1px solid #B8B2A8;
	border-radius: 3px;
	background: #FFFFFF;
	transition: background-color .15s ease, border-color .15s ease;
}

.gsa .gsa__check.is-activo .gsa__check-box {
	background: var(--gsa-oro, #9C7A34);
	border-color: var(--gsa-oro, #9C7A34);
}

.gsa .gsa__check.is-activo .gsa__check-box::after {
	content: '';
	position: absolute;
	left: 5px;
	top: 1.5px;
	width: 4px;
	height: 8px;
	border: solid #FFFFFF;
	border-width: 0 2px 2px 0;
	transform: rotate(45deg);
}

.gsa .gsa__check-txt {
	flex: 1 1 auto;
}

.gsa .gsa__check-n {
	color: var(--gsa-gris, #888888);
	font-size: 12px;
}

/* ── Pie del panel ───────────────────────────────────────────────────────── */

/* Fijo al fondo: los filtros de arriba se recorren, pero «Ver N productos» tiene que estar
   siempre a un toque de distancia. */
.gsa .gsa__panel-pie {
	flex: 0 0 auto;
	display: grid;
	grid-template-columns: 1fr 1.4fr;
	gap: 10px;
	padding: 16px 22px;
	background: #FFFFFF;
	border-top: 1px solid var(--gsa-linea, #E8E2D9);
}

.gsa .gsa__btn-limpiar,
.gsa .gsa__btn-ver {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 13px 14px;
	font-family: var(--gs-font-ui, 'Montserrat', system-ui, sans-serif);
	font-weight: 700;
	font-size: 11px;
	line-height: 1;
	letter-spacing: .12em;
	text-transform: uppercase;
	border-radius: 8px;
	text-decoration: none;
	cursor: pointer;
	transition: background-color .2s ease, border-color .2s ease, color .2s ease,
		transform .16s var(--gs-e-out, cubic-bezier(.22, 1, .36, 1));
	/* Anti-tema. */
	box-shadow: none;
	text-shadow: none;
	min-height: 0;
	appearance: none;
	-webkit-appearance: none;
}

.gsa .gsa__btn-limpiar {
	border: 1px solid var(--gsa-linea, #E8E2D9);
	background: transparent;
	color: var(--gsa-gris, #888888);
}

.gsa a.gsa__btn-limpiar:hover,
.gsa a.gsa__btn-limpiar:focus-visible,
.gsa a.gsa__btn-limpiar:focus {
	border-color: var(--gsa-oro, #9C7A34);
	background: transparent;
	color: var(--gsa-oro, #9C7A34);
	text-decoration: none;
}

/* Sin filtros puestos no hay nada que limpiar: se apaga en vez de dejar un botón que no
   hace nada. No se oculta, porque desaparecer movería el otro botón de sitio. */
.gsa .gsa__btn-limpiar.is-off {
	opacity: .4;
	pointer-events: none;
}

.gsa .gsa__btn-ver {
	border: 1px solid var(--gsa-tinta, #0A0A0A);
	background: var(--gsa-tinta, #0A0A0A);
	color: #FFFFFF;
}

.gsa .gsa__btn-ver:hover,
.gsa .gsa__btn-ver:focus-visible,
.gsa .gsa__btn-ver:focus {
	background: var(--gsa-oro, #9C7A34);
	border-color: var(--gsa-oro, #9C7A34);
	color: var(--gsa-tinta, #0A0A0A);
}

/* ── Realimentación de pulsación ─────────────────────────────────────────────
   Escala de la casa: control grande `.985`, botón de ícono `.92`. Los valores salen de
   `.gs-mc__cta` (minicarrito) y `.gs-iconbtn` (header), que son los que ya la tenían; aquí
   no se inventa ninguno.

   Sólo entran los controles que actúan SIN recargar la página —el archivo pagina y filtra
   por AJAX—, porque son justo aquellos en los que el usuario pulsa y la página tarda en
   contestar: el acuse de recibo tapa esa espera. Los enlaces que navegan de verdad (migas,
   pestañas de categoría) se quedan fuera a propósito: allí la respuesta es el cambio de
   página, y no hace falta anunciarla dos veces.

   Sin acotar a puntero fino: un `:active` se suelta con el dedo, no se queda pegado como el
   `:hover`, y en táctil es la única señal que hay. */
.gsa .gsa__btn-limpiar:active,
.gsa .gsa__btn-ver:active,
.gsa .gsa__filtrar:active,
.gsa a.gsa__pag-btn:active {
	transform: scale(.985);
}

/* Botón de ícono: mismo `.92` que `.gs-iconbtn` en el header, y mide casi lo mismo (34×30). */
.gsa .gsa__vista-btn:active {
	transform: scale(.92);
}

/* Quedan fuera dos que parecían candidatos:
   · `.gsa__chip-x` es un `<span>` DENTRO del `<a class="gsa__chip">`, así que sólo recibiría
     `:active` al pulsar exactamente sobre la «×» y no al pulsar el resto de la pastilla — un
     feedback que aparece o no según dónde caiga el dedo es peor que ninguno.
   · `.gsa__panel-x` ya acusa la interacción girando 90°, y una escala encima le ganaría por
     orden y le desharía el giro justo al pulsar. */

/* La paginación se acota a `a.` por el mismo motivo que su `:hover` unas líneas más arriba:
   los extremos sin destino se imprimen como `<span class="gsa__pag-btn is-off">`
   (`ArchiveRenderer`), y un `<span>` SÍ recibe `:active` — sin el `a.` la flecha muerta se
   hundiría al pulsarla y prometería una página que no existe. `.gsa__btn-limpiar.is-off` no
   necesita el mismo cuidado porque además lleva `pointer-events: none`. */

/* ── Foco visible ────────────────────────────────────────────────────────── */

.gsa a:focus-visible,
.gsa button:focus-visible,
.gsa select:focus-visible,
.gsa input:focus-visible {
	outline: 2px solid var(--gsa-oro, #9C7A34);
	outline-offset: 2px;
}

/* ── Responsive ──────────────────────────────────────────────────────────── */

@media (max-width: 767px) {

	.gsa .gsa__barra-fila {
		gap: 18px;
	}

	.gsa .gsa__orden-sel {
		min-width: 0;
	}

	.gsa .gsa__vista {
		margin-left: 0;
	}
}

@media (prefers-reduced-motion: reduce) {

	.gsa .gsa__panel,
	.gsa .gsa__velo,
	.gsa .gsa__resultados,
	.gsa .gsa__pill,
	.gsa .gsa__color,
	.gsa .gsa__tab,
	.gsa .gsa__panel-x,
	.gsa .gsa__filtrar,
	.gsa .gsa__vista-btn,
	.gsa .gsa__pag-btn,
	.gsa .gsa__btn-limpiar,
	.gsa .gsa__btn-ver {
		transition: none;
	}

	.gsa .gsa__panel-x:hover {
		transform: none;
	}

	/* Los `:active` de pulsación NO se anulan: sin transición son un acuse instantáneo, no un
	   desplazamiento. «Movimiento reducido» pide menos movimiento, no dejar los controles sin
	   respuesta — y en este widget la respuesta tarda, porque pagina y filtra por AJAX. */
}

/* ── El Kit tiñe el `:focus` a secas ─────────────────────────────────────────
   `:focus-visible` NO casa al pulsar con el ratón, y `.elementor-kit-N a:focus` /
   `button:focus` sí, con (0,2,1): al hacer clic, el elemento se quedaba con el color del
   Kit hasta perder el foco. Estos gemelos van APARTE de sus reglas de hover porque
   aquéllas mueven la caja (`transform`) o viven dentro de un `@media (hover)`: aquí solo
   se repite el color, así que ni se levanta nada al hacer clic ni se queda el táctil
   sin cubrir. */
.gsa .gsa__panel-x:focus {
	background: transparent;
	color: #FFFFFF;
}

/* ---- perfil.css ---- */
/**
 * GS Mi Perfil. Handle 'gs-perfil' (deps: gs-tokens, gs-fonts).
 *
 * Prefijo propio `.gsp-perfil-`. Todas las reglas se cuelgan de `.gsp-perfil` y nombran
 * también la clase del elemento, de modo que la especificidad (0,2,0) gana a las reglas
 * genéricas de `input`, `button` o `a` que traiga el tema sin necesidad de `!important`.
 *
 * ── (0,2,0) basta contra el tema, NO contra el Global Kit ────────────────
 * Esta hoja no depende de `header-base.css` y aquí no llega su neutralizador. El Kit de Elementor
 * emite `.elementor-kit-N a:hover` y `button:hover` con (0,2,1), que **le gana a (0,2,0)**. Por eso:
 *
 *   1. **Toda regla de estado va a (0,3,0)** —raíz + clase + pseudoclase— y **declara fondo Y
 *      color**, aunque solo cambie uno: el que se deje sin declarar es justo el que el Kit rellena.
 *   2. Cuando el color depende de una **variante** cuya regla es (0,2,0) —las acciones de dirección,
 *      los botones de confirmar—, la variante publica su color en una **variable** (`--gsp-dir-fg`,
 *      `--gsp-cf-bg`/`--gsp-cf-fg`) y la regla de estado la lee. Las variables heredan y no compiten
 *      por especificidad, así que una sola regla de estado sirve para todas las variantes.
 *
 * Archivo, Montserrat e Inter ya vienen auto-alojadas por el plugin (handle 'gs-fonts'); aquí
 * no se declara ningún @font-face ni se carga nada de Google.
 *
 * Los colores y medidas llegan como variables desde los controles de Elementor
 * (`selectors`); los valores escritos aquí son los de partida del diseño.
 *
 * La ventana de dirección es `position: fixed` y vive dentro del widget: si se le aplica una
 * animación o un `transform` de Elementor al widget o a su contenedor, el navegador la
 * anclará a ese contenedor en vez de a la pantalla. Es la misma advertencia que el archivo
 * de categoría.
 */

.gsp-perfil {
	width: 100%;
	background-color: var(--gsp-fondo, #FAFAF7);

	/* Contenedor */
	--gsp-max: 1280px;
	--gsp-pad-x: 32px;
	--gsp-pad-b: 80px;
	--gsp-side-w: 240px;
	--gsp-gap: 32px;

	/* Paleta */
	--gsp-tinta: #0A0A0A;
	--gsp-linea: #E8E2D9;
	--gsp-oro: #9C7A34;
	--gsp-oro-pale: #FBF6EE;
	--gsp-gris: #888888;
	--gsp-gris-2: #555555;
	--gsp-rojo: #B23B32;
	--gsp-caja-bg: #FFFFFF;
	--gsp-panel-bg: #FFFFFF;
	--gsp-panel-r: 16px;

	/* Avatar */
	--gsp-av-1: #8A6528;
	--gsp-av-2: #C2A370;

	/* Pantalla de acceso */
	--gsp-acc-w: 460px;
	--gsp-acc-aire: 64px;
	--gsp-acc-cta-bg: #0A0A0A;
	--gsp-acc-cta-txt: #FFFFFF;
	--gsp-acc-cta-hover: #9C7A34;
	--gsp-acc-cta-r: 10px;
}

.gsp-perfil,
.gsp-perfil *,
.gsp-perfil *::before,
.gsp-perfil *::after {
	box-sizing: border-box;
}

/* No todos los temas la traen; sin ella los textos de lector de pantalla se verían. */
.gsp-perfil .screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* ── Rejilla general ─────────────────────────────────────────────────────── */

.gsp-perfil .gsp-perfil__grid {
	max-width: var(--gsp-max, 1280px);
	margin: 0 auto;
	padding: var(--gsp-pad-x, 32px);
	padding-bottom: var(--gsp-pad-b, 80px);
	display: grid;
	grid-template-columns: var(--gsp-side-w, 240px) 1fr;
	gap: var(--gsp-gap, 32px);
	align-items: start;
}

/* ── Columna lateral ─────────────────────────────────────────────────────── */

.gsp-perfil .gsp-perfil__side {
	position: sticky;
	top: 90px;
}

/* Tarjeta de usuario */

.gsp-perfil .gsp-perfil__user {
	background: var(--gsp-caja-bg, #fff);
	border: 1px solid var(--gsp-linea, #E8E2D9);
	border-radius: 16px;
	padding: 22px;
	margin-bottom: 8px;
	text-align: center;
}

.gsp-perfil .gsp-perfil__avatar {
	position: relative;
	display: block;
	width: 64px;
	height: 64px;
	margin: 0 auto 12px;
	border-radius: 50%;
	overflow: hidden;
	background: linear-gradient(135deg, var(--gsp-av-1, #8A6528), var(--gsp-av-2, #C2A370));
}

.gsp-perfil .gsp-perfil__iniciales {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	font-family: var(--gs-font-display, 'Archivo', sans-serif);
	font-weight: 700;
	font-size: 24px;
	line-height: 1;
	color: #fff;
	letter-spacing: .02em;
}

/* Va encima de las iniciales: si la foto no existe, el JS la retira y quedan a la vista. */
.gsp-perfil .gsp-perfil__foto {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	border-radius: 50%;
}

.gsp-perfil .gsp-perfil__nombre {
	margin: 0 0 3px;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 15px;
	line-height: 1.3;
	color: var(--gsp-tinta, #0A0A0A);
}

.gsp-perfil .gsp-perfil__email {
	margin: 0;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 12px;
	line-height: 1.4;
	color: var(--gsp-gris, #888);
	word-break: break-word;
}

.gsp-perfil .gsp-perfil__badge {
	display: inline-block;
	margin-top: 12px;
	background: var(--gsp-badge-bg, #FBF6EE);
	border: 1px solid var(--gsp-badge-bd, rgba(156, 122, 52, .25));
	border-radius: 20px;
	padding: 4px 12px;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 600;
	font-size: 9.5px;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--gsp-badge-txt, #9C7A34);
}

/* Menú de cuenta */

.gsp-perfil .gsp-perfil__menu {
	background: var(--gsp-caja-bg, #fff);
	border: 1px solid var(--gsp-linea, #E8E2D9);
	border-radius: 14px;
	overflow: hidden;
}

.gsp-perfil .gsp-perfil__item {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 14px 18px;
	border-left: 3px solid transparent;
	border-bottom: 1px solid var(--gsp-item-sep, #F5F1E8);
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 12px;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--gsp-item, #888);
	text-decoration: none;
	transition: color .18s var(--gs-e-soft, ease), border-color .18s var(--gs-e-soft, ease), background-color .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-perfil__item:last-child {
	border-bottom: 0;
}

/* `background` va declarado aunque el diseño no lo cambie: es un `<a>`, y el Global Kit emite
   `.elementor-kit-N a:hover` con (0,2,1) rellenando el fondo. Sin esta línea, pasar el ratón por el
   menú lateral lo pintaba del color del Kit. La regla del elemento activo, que sí trae fondo, es
   (0,3,0) igual que esta y va después, así que le sigue ganando. */
.gsp-perfil .gsp-perfil__item:hover,
.gsp-perfil .gsp-perfil__item:focus-visible,
.gsp-perfil .gsp-perfil__item:focus {
	background: transparent;
	color: var(--gsp-item-hover, #9C7A34);
	border-left-color: var(--gsp-item-hover, #9C7A34);
}

.gsp-perfil .gsp-perfil__item.is-activo {
	border-left-color: var(--gsp-oro, #9C7A34);
	background: var(--gsp-item-act-bg, #FBF6EE);
	color: var(--gsp-item-act, #9C7A34);
}

.gsp-perfil .gsp-perfil__item-ico {
	display: inline-flex;
	flex: 0 0 auto;
}

.gsp-perfil .gsp-perfil__item-ico svg {
	width: 16px;
	height: 16px;
	display: block;
}

.gsp-perfil .gsp-perfil__item-txt {
	font: inherit;
	letter-spacing: inherit;
}

/* ── Encabezado ──────────────────────────────────────────────────────────── */

.gsp-perfil .gsp-perfil__head {
	margin-bottom: 22px;
}

.gsp-perfil .gsp-perfil__titulo {
	margin: 0 0 6px;
	font-family: var(--gs-font-display, 'Archivo', sans-serif);
	font-weight: 700;
	font-size: 32px;
	line-height: 1;
	text-transform: uppercase;
	color: var(--gsp-titulo, #0A0A0A);
}

.gsp-perfil .gsp-perfil__sub {
	margin: 0;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 14px;
	line-height: 1.5;
	color: var(--gsp-sub, #888);
}

/* ── Paneles ─────────────────────────────────────────────────────────────── */

.gsp-perfil .gsp-perfil__panel {
	background: var(--gsp-panel-bg, #fff);
	border: 1px solid var(--gsp-linea, #E8E2D9);
	border-radius: var(--gsp-panel-r, 16px);
	padding: 28px;
	margin-bottom: 20px;
}

.gsp-perfil .gsp-perfil__panel:last-child {
	margin-bottom: 0;
}

.gsp-perfil .gsp-perfil__panel-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	margin-bottom: 22px;
}

.gsp-perfil .gsp-perfil__panel-tit {
	margin: 0;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 13px;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--gsp-panel-tit, #0A0A0A);
}

/* Botón Editar / Guardar */

.gsp-perfil .gsp-perfil__btn-edit {
	flex: 0 0 auto;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 10px;
	letter-spacing: .12em;
	text-transform: uppercase;
	padding: 8px 16px;
	border: 1px solid var(--gsp-oro, #9C7A34);
	border-radius: 6px;
	background: transparent;
	color: var(--gsp-oro, #9C7A34);
	cursor: pointer;
	transition: background-color .18s var(--gs-e-soft, ease), color .18s var(--gs-e-soft, ease), opacity .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-perfil__panel.is-editando .gsp-perfil__btn-edit {
	background: var(--gsp-oro, #9C7A34);
	color: #fff;
}

.gsp-perfil .gsp-perfil__btn-edit[disabled] {
	opacity: .55;
	cursor: default;
}

/* Una sola caja con las dos etiquetas dentro: se enseña la que corresponde al modo. */
.gsp-perfil .gsp-perfil__lbl--edit,
.gsp-perfil .gsp-perfil__panel.is-editando .gsp-perfil__lbl--ver {
	display: none;
}

.gsp-perfil .gsp-perfil__panel.is-editando .gsp-perfil__lbl--edit {
	display: inline;
}

/* ── Campos ──────────────────────────────────────────────────────────────── */

.gsp-perfil .gsp-perfil__campos {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 20px 24px;
	margin: 0;
}

.gsp-perfil .gsp-perfil__campo {
	min-width: 0;
}

.gsp-perfil .gsp-perfil__campo-lbl {
	display: block;
	margin-bottom: 7px;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 600;
	font-size: 10px;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--gsp-gris, #888);
}

.gsp-perfil .gsp-perfil__campo-opt {
	font-weight: 600;
	letter-spacing: .06em;
	text-transform: none;
	opacity: .75;
}

.gsp-perfil .gsp-perfil__input {
	width: 100%;
	padding: 12px 14px;
	border: 1.5px solid var(--gsp-linea, #E8E2D9);
	border-radius: 8px;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 14px;
	line-height: 1.35;
	outline: none;
	background: var(--gsp-input-bg, #FAFAF7);
	color: var(--gsp-input-txt, #0A0A0A);
	transition: border-color .18s var(--gs-e-soft, ease), background-color .18s var(--gs-e-soft, ease);
}

/* Los navegadores atenúan los deshabilitados; aquí el campo en reposo debe LEERSE bien:
   lo que comunica «no editable» es el fondo crema y la ausencia de borde dorado. */
.gsp-perfil .gsp-perfil__input:disabled {
	opacity: 1;
	-webkit-text-fill-color: var(--gsp-input-txt, #0A0A0A);
	cursor: default;
}

.gsp-perfil .gsp-perfil__panel.is-editando .gsp-perfil__input,
.gsp-perfil .gsp-perfil__input.is-editable {
	border-color: var(--gsp-oro, #9C7A34);
	background: #fff;
}

.gsp-perfil .gsp-perfil__input:focus {
	border-color: var(--gsp-oro, #9C7A34);
	box-shadow: 0 0 0 3px rgba(156, 122, 52, .14);
}

/* ── Avisos ──────────────────────────────────────────────────────────────── */

.gsp-perfil .gsp-perfil__aviso {
	margin: 16px 0 0;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 13px;
	line-height: 1.5;
	color: var(--gsp-gris-2, #555);
}

.gsp-perfil .gsp-perfil__aviso.is-error {
	color: var(--gsp-rojo, #B23B32);
}

.gsp-perfil .gsp-perfil__aviso.is-ok {
	color: var(--gsp-oro, #9C7A34);
}

/* ── Direcciones ─────────────────────────────────────────────────────────── */

.gsp-perfil .gsp-perfil__btn-add {
	flex: 0 0 auto;
	padding: 8px 16px;
	border: none;
	border-radius: 6px;
	background: var(--gsp-add-bg, #0A0A0A);
	color: var(--gsp-add-txt, #fff);
	cursor: pointer;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 10px;
	letter-spacing: .12em;
	text-transform: uppercase;
	transition: background-color .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-perfil__btn-add:hover,
.gsp-perfil .gsp-perfil__btn-add:focus-visible,
.gsp-perfil .gsp-perfil__btn-add:focus {
	background: var(--gsp-add-hover, #9C7A34);
	/* El fondo cambia y el texto no, pero se repite igualmente: el Kit rellena con (0,2,1) todo lo
	   que esta regla deje sin declarar, y el blanco sobre oro se perdía. */
	color: var(--gsp-add-txt, #fff);
}

.gsp-perfil .gsp-perfil__dirs {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 14px;
}

.gsp-perfil .gsp-perfil__vacio {
	margin: 0;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 13px;
	line-height: 1.6;
	color: var(--gsp-gris, #888);
}

.gsp-perfil .gsp-perfil__dir {
	position: relative;
	border: 1.5px solid var(--gsp-linea, #E8E2D9);
	border-radius: 12px;
	padding: 18px 20px;
}

.gsp-perfil .gsp-perfil__dir.is-principal {
	border-color: var(--gsp-dir-pri-bd, #9C7A34);
	background: var(--gsp-dir-pri-bg, #FBF6EE);
}

.gsp-perfil .gsp-perfil__dir-badge {
	position: absolute;
	top: 16px;
	right: 18px;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 8.5px;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--gsp-oro, #9C7A34);
	background: #fff;
	border: 1px solid rgba(156, 122, 52, .3);
	border-radius: 20px;
	padding: 3px 10px;
}

.gsp-perfil .gsp-perfil__dir-lbl {
	margin: 0 0 8px;
	/* Deja sitio al distintivo para que una etiqueta larga no se le meta debajo. */
	padding-right: 84px;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 12px;
	letter-spacing: .06em;
	text-transform: uppercase;
	color: var(--gsp-tinta, #0A0A0A);
}

.gsp-perfil .gsp-perfil__dir-txt {
	margin: 0;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 13px;
	line-height: 1.6;
	color: var(--gsp-gris-2, #555);
}

.gsp-perfil .gsp-perfil__dir-acciones {
	display: flex;
	flex-wrap: wrap;
	gap: 16px;
	margin-top: 14px;
}

.gsp-perfil .gsp-perfil__dir-accion {
	padding: 0 0 1px;
	border: 0;
	border-bottom: 1px solid transparent;
	background: none;
	cursor: pointer;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 600;
	font-size: 11px;
	transition: opacity .18s var(--gs-e-soft, ease);
}

/* El color no se puede repetir aquí porque cada variante trae el suyo, y esas reglas son (0,2,0):
   el `color` de `.elementor-kit-N button:hover` (0,2,1) les ganaba y «Eliminar» perdía su rojo al
   pasar el ratón. Cada variante publica su color en `--gsp-dir-fg` y esta regla —(0,3,0), por
   encima del Kit— lo devuelve. Las variables no compiten por especificidad: heredan. */
.gsp-perfil .gsp-perfil__dir-accion:hover,
.gsp-perfil .gsp-perfil__dir-accion:focus-visible,
.gsp-perfil .gsp-perfil__dir-accion:focus {
	opacity: .72;
	background: none;
	color: var(--gsp-dir-fg, inherit);
}

.gsp-perfil .gsp-perfil__dir-principal {
	--gsp-dir-fg: var(--gsp-gris, #888);
	color: var(--gsp-dir-fg);
	border-bottom-color: var(--gsp-linea, #E8E2D9);
}

.gsp-perfil .gsp-perfil__dir-edit {
	--gsp-dir-fg: var(--gsp-oro, #9C7A34);
	color: var(--gsp-dir-fg);
	border-bottom-color: rgba(156, 122, 52, .3);
}

.gsp-perfil .gsp-perfil__dir-del {
	--gsp-dir-fg: var(--gsp-rojo, #B23B32);
	color: var(--gsp-dir-fg);
	border-bottom-color: rgba(178, 59, 50, .3);
}

/* Confirmación de borrado, dentro de la propia tarjeta. */

.gsp-perfil .gsp-perfil__confirm {
	margin-top: 14px;
	padding-top: 12px;
	border-top: 1px solid var(--gsp-linea, #E8E2D9);
}

.gsp-perfil .gsp-perfil__confirm[hidden] {
	display: none;
}

.gsp-perfil .gsp-perfil__confirm-txt {
	margin: 0 0 10px;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 13px;
	color: var(--gsp-gris-2, #555);
}

.gsp-perfil .gsp-perfil__confirm-btns {
	display: flex;
	gap: 10px;
}

.gsp-perfil .gsp-perfil__confirm-si,
.gsp-perfil .gsp-perfil__confirm-no {
	padding: 7px 14px;
	border-radius: 6px;
	cursor: pointer;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 10px;
	letter-spacing: .1em;
	text-transform: uppercase;
	transition: opacity .18s var(--gs-e-soft, ease);
}

/* Mismo recurso que en las acciones de dirección: dos variantes con colores distintos y un solo
   `:hover` que solo toca la opacidad. Publican fondo y texto en variables para que la regla de
   estado pueda repetirlos sin duplicarse por variante. */
.gsp-perfil .gsp-perfil__confirm-si {
	--gsp-cf-bg: var(--gsp-rojo, #B23B32);
	--gsp-cf-fg: #fff;
	border: 1px solid var(--gsp-rojo, #B23B32);
	background: var(--gsp-cf-bg);
	color: var(--gsp-cf-fg);
}

.gsp-perfil .gsp-perfil__confirm-no {
	--gsp-cf-bg: transparent;
	--gsp-cf-fg: var(--gsp-gris, #888);
	border: 1px solid var(--gsp-linea, #E8E2D9);
	background: var(--gsp-cf-bg);
	color: var(--gsp-cf-fg);
}

/* Sin repetir fondo y color, el «Sí, eliminar» perdía su rojo bajo el ratón justo cuando más
   importa que se lea como una acción destructiva. */
.gsp-perfil .gsp-perfil__confirm-si:hover,
.gsp-perfil .gsp-perfil__confirm-si:focus-visible,
.gsp-perfil .gsp-perfil__confirm-no:hover,
.gsp-perfil .gsp-perfil__confirm-no:focus-visible,
.gsp-perfil .gsp-perfil__confirm-si:focus,
.gsp-perfil .gsp-perfil__confirm-no:focus {
	opacity: .8;
	background: var(--gsp-cf-bg);
	color: var(--gsp-cf-fg);
}

/* Mientras una operación está en vuelo. */
.gsp-perfil .gsp-perfil__dir.is-ocupada,
.gsp-perfil.is-guardando .gsp-perfil__campos {
	opacity: .6;
	pointer-events: none;
}

/* ── Ventana de dirección ────────────────────────────────────────────────── */

.gsp-perfil .gsp-perfil__velo {
	position: fixed;
	inset: 0;
	z-index: 300;
	background: rgba(10, 10, 10, .5);
	opacity: 0;
	transition: opacity .28s var(--gs-e-out, ease);
}

.gsp-perfil .gsp-perfil__velo[hidden] {
	display: none;
}

.gsp-perfil.is-modal .gsp-perfil__velo {
	opacity: 1;
}

.gsp-perfil .gsp-perfil__modal {
	position: fixed;
	inset: 0;
	z-index: 310;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 24px;
	overflow-y: auto;
}

.gsp-perfil .gsp-perfil__modal[hidden] {
	display: none;
}

.gsp-perfil .gsp-perfil__modal-caja {
	width: 100%;
	max-width: 520px;
	max-height: calc(100vh - 48px);
	display: flex;
	flex-direction: column;
	background: #fff;
	border-radius: 16px;
	box-shadow: var(--gs-sh-panel, 0 20px 48px rgba(10, 10, 10, .18));
	transform: translateY(12px);
	opacity: 0;
	transition: transform .28s var(--gs-e-out, ease), opacity .28s var(--gs-e-out, ease);
}

.gsp-perfil.is-modal .gsp-perfil__modal-caja {
	transform: none;
	opacity: 1;
}

.gsp-perfil .gsp-perfil__modal-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	padding: 20px 24px;
	border-bottom: 1px solid var(--gsp-linea, #E8E2D9);
}

.gsp-perfil .gsp-perfil__modal-tit {
	margin: 0;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 13px;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--gsp-tinta, #0A0A0A);
}

/* Título doble: «Nueva dirección» o «Editar dirección» según cómo se abrió. */
.gsp-perfil .gsp-perfil__lbl--editar,
.gsp-perfil.is-editando-dir .gsp-perfil__lbl--nueva {
	display: none;
}

.gsp-perfil.is-editando-dir .gsp-perfil__lbl--editar {
	display: inline;
}

.gsp-perfil .gsp-perfil__modal-x {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 32px;
	padding: 0;
	border: 0;
	border-radius: 8px;
	background: none;
	color: var(--gsp-oro, #9C7A34);
	cursor: pointer;
	transition: background-color .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-perfil__modal-x:hover,
.gsp-perfil .gsp-perfil__modal-x:focus-visible,
.gsp-perfil .gsp-perfil__modal-x:focus {
	background: var(--gsp-oro-pale, #FBF6EE);
	color: var(--gsp-oro, #9C7A34);
}

.gsp-perfil .gsp-perfil__modal-x svg {
	width: 16px;
	height: 16px;
	display: block;
}

.gsp-perfil .gsp-perfil__modal-body {
	flex: 1 1 auto;
	overflow-y: auto;
	padding: 22px 24px;
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 16px 20px;
}

.gsp-perfil .gsp-perfil__campo--ancho {
	grid-column: 1 / -1;
}

.gsp-perfil .gsp-perfil__modal-body .gsp-perfil__aviso {
	grid-column: 1 / -1;
	margin-top: 0;
}

.gsp-perfil .gsp-perfil__modal-pie {
	flex: 0 0 auto;
	display: flex;
	justify-content: flex-end;
	gap: 12px;
	padding: 18px 24px;
	border-top: 1px solid var(--gsp-linea, #E8E2D9);
}

.gsp-perfil .gsp-perfil__btn-cancelar,
.gsp-perfil .gsp-perfil__btn-guardar {
	padding: 11px 22px;
	border-radius: 8px;
	cursor: pointer;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 11px;
	letter-spacing: .1em;
	text-transform: uppercase;
	transition: background-color .18s var(--gs-e-soft, ease), color .18s var(--gs-e-soft, ease), opacity .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-perfil__btn-cancelar {
	border: 1px solid var(--gsp-linea, #E8E2D9);
	background: transparent;
	color: var(--gsp-gris, #888);
}

.gsp-perfil .gsp-perfil__btn-cancelar:hover,
.gsp-perfil .gsp-perfil__btn-cancelar:focus-visible,
.gsp-perfil .gsp-perfil__btn-cancelar:focus {
	border-color: var(--gsp-oro, #9C7A34);
	background: transparent;
	color: var(--gsp-oro, #9C7A34);
}

.gsp-perfil .gsp-perfil__btn-guardar {
	border: 1px solid var(--gsp-add-bg, #0A0A0A);
	background: var(--gsp-add-bg, #0A0A0A);
	color: var(--gsp-add-txt, #fff);
}

.gsp-perfil .gsp-perfil__btn-guardar:hover,
.gsp-perfil .gsp-perfil__btn-guardar:focus-visible,
.gsp-perfil .gsp-perfil__btn-guardar:focus {
	border-color: var(--gsp-add-hover, #9C7A34);
	background: var(--gsp-add-hover, #9C7A34);
	color: var(--gsp-add-txt, #fff);
}

.gsp-perfil .gsp-perfil__btn-guardar[disabled],
.gsp-perfil .gsp-perfil__btn-cancelar[disabled] {
	opacity: .55;
	cursor: default;
}

/* ── Pantalla de acceso ──────────────────────────────────────────────────── */

.gsp-perfil .gsp-acc {
	display: flex;
	justify-content: center;
	padding: var(--gsp-acc-aire, 64px) var(--gsp-pad-x, 32px);
}

.gsp-perfil .gsp-acc__caja {
	width: 100%;
	max-width: var(--gsp-acc-w, 460px);
	padding: 40px 36px;
	background: var(--gsp-panel-bg, #fff);
	border: 1px solid var(--gsp-linea, #E8E2D9);
	border-radius: var(--gsp-panel-r, 16px);
}

/* Las tres caras están siempre en el HTML y solo una se ve. Se explicita porque hay temas
   que redefinen `display` en elementos con [hidden] y dejarían las tres a la vista. */
.gsp-perfil .gsp-acc__cara[hidden] {
	display: none;
}

.gsp-perfil .gsp-acc__titulo {
	margin: 0 0 6px;
	font-family: var(--gs-font-display, 'Archivo', sans-serif);
	font-weight: 700;
	font-size: 30px;
	line-height: 1.15;
	color: var(--gsp-titulo, #0A0A0A);
}

.gsp-perfil .gsp-acc__lema {
	margin: 0 0 22px;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 15px;
	line-height: 1.5;
	color: var(--gsp-sub, #888);
}

/* El puente entre las tres caras: «¿Eres nuevo? Crear cuenta». */
.gsp-perfil .gsp-acc__cambio {
	margin: 0 0 26px;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 14px;
	line-height: 1.5;
	color: var(--gsp-gris-2, #555);
}

.gsp-perfil .gsp-acc__cambio-a {
	color: var(--gsp-tinta, #0A0A0A);
	font-weight: 700;
	text-decoration: underline;
	text-underline-offset: 3px;
	transition: color .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-acc__cambio-a:hover,
.gsp-perfil .gsp-acc__cambio-a:focus-visible,
.gsp-perfil .gsp-acc__cambio-a:focus {
	background: transparent;
	color: var(--gsp-oro, #9C7A34);
}

.gsp-perfil .gsp-acc__form {
	display: grid;
	gap: 18px;
}

.gsp-perfil .gsp-acc__campo {
	display: grid;
	gap: 8px;
}

.gsp-perfil .gsp-acc__etq {
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 11px;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--gsp-gris, #888);
}

.gsp-perfil .gsp-acc__input {
	width: 100%;
	padding: 14px 16px;
	border: 1.5px solid var(--gsp-linea, #E8E2D9);
	border-radius: 10px;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 15px;
	line-height: 1.35;
	outline: none;
	background: var(--gsp-input-bg, #FAFAF7);
	color: var(--gsp-input-txt, #0A0A0A);
	transition: border-color .18s var(--gs-e-soft, ease), background-color .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-acc__input:focus {
	border-color: var(--gsp-oro, #9C7A34);
	background: var(--gsp-panel-bg, #fff);
}

/* Ancla del ojo, que va superpuesto dentro del campo. */
.gsp-perfil .gsp-acc__secreto {
	position: relative;
	display: block;
}

/* Hueco a la derecha para que el texto tecleado no pase por debajo del ojo. */
.gsp-perfil .gsp-acc__secreto .gsp-acc__input {
	padding-right: 50px;
}

.gsp-perfil .gsp-acc__ojo {
	position: absolute;
	top: 50%;
	right: 8px;
	transform: translateY(-50%);
	display: flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	padding: 0;
	border: 0;
	border-radius: 8px;
	background: transparent;
	color: var(--gsp-gris, #888);
	cursor: pointer;
	transition: color .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-acc__ojo:hover,
.gsp-perfil .gsp-acc__ojo:focus-visible,
.gsp-perfil .gsp-acc__ojo:focus {
	background: transparent;
	color: var(--gsp-tinta, #0A0A0A);
}

.gsp-perfil .gsp-acc__ojo-ico {
	width: 20px;
	height: 20px;
}

/* La tacha solo aparece con la contraseña a la vista: el icono dice qué está pasando
   ahora, no qué pasará al pulsarlo. */
.gsp-perfil .gsp-acc__ojo-tacha {
	opacity: 0;
	transition: opacity .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-acc__ojo[aria-pressed="true"] .gsp-acc__ojo-tacha {
	opacity: 1;
}

.gsp-perfil .gsp-acc__fila {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	margin-top: -4px;
}

.gsp-perfil .gsp-acc__check {
	display: flex;
	align-items: center;
	gap: 9px;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 14px;
	color: var(--gsp-gris-2, #555);
	cursor: pointer;
}

.gsp-perfil .gsp-acc__check input {
	width: 17px;
	height: 17px;
	margin: 0;
	accent-color: var(--gsp-oro, #9C7A34);
	cursor: pointer;
}

.gsp-perfil .gsp-acc__enlace {
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 14px;
	color: var(--gsp-gris-2, #555);
	text-decoration: none;
	transition: color .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-acc__enlace:hover,
.gsp-perfil .gsp-acc__enlace:focus-visible,
.gsp-perfil .gsp-acc__enlace:focus {
	background: transparent;
	color: var(--gsp-oro, #9C7A34);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.gsp-perfil .gsp-acc__cta {
	width: 100%;
	padding: 16px 24px;
	border: 0;
	border-radius: var(--gsp-acc-cta-r, 10px);
	background: var(--gsp-acc-cta-bg, #0A0A0A);
	color: var(--gsp-acc-cta-txt, #fff);
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 15px;
	line-height: 1.2;
	cursor: pointer;
	transition: background-color .18s var(--gs-e-soft, ease), opacity .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-acc__cta:hover,
.gsp-perfil .gsp-acc__cta:focus-visible,
.gsp-perfil .gsp-acc__cta:focus {
	background: var(--gsp-acc-cta-hover, #9C7A34);
	color: var(--gsp-acc-cta-txt, #fff);
}

.gsp-perfil .gsp-acc__cta[disabled] {
	opacity: .55;
	cursor: default;
}

/* ── Requisitos de la contraseña ─────────────────────────────────────────── */

.gsp-perfil .gsp-acc__reglas {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 7px 14px;
	margin: -4px 0 0;
	padding: 0;
	list-style: none;
}

.gsp-perfil .gsp-acc__regla {
	display: flex;
	align-items: center;
	gap: 7px;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 13px;
	line-height: 1.4;
	color: var(--gsp-gris, #888);
	transition: color .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-acc__regla.is-ok {
	color: var(--gsp-oro, #9C7A34);
}

.gsp-perfil .gsp-acc__regla-ico {
	flex: 0 0 auto;
	width: 16px;
	height: 16px;
}

/* La palomita solo aparece cuando el requisito está cumplido; hasta entonces se ve el
   círculo vacío, que ya dice «esto te falta» sin necesidad de texto en rojo. */
.gsp-perfil .gsp-acc__regla-check {
	opacity: 0;
	transition: opacity .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-acc__regla.is-ok .gsp-acc__regla-check {
	opacity: 1;
}

/* Nombre y apellido, uno al lado del otro. */
.gsp-perfil .gsp-acc__par {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 14px;
}

.gsp-perfil .gsp-acc__legal {
	margin: 0;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 13px;
	line-height: 1.55;
	color: var(--gsp-gris, #888);
}

.gsp-perfil .gsp-acc__legal p {
	margin: 0;
}

.gsp-perfil .gsp-acc__legal a {
	color: var(--gsp-oro, #9C7A34);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.gsp-perfil .gsp-acc__aviso {
	margin: 0;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 14px;
	line-height: 1.5;
	color: var(--gsp-gris-2, #555);
}

.gsp-perfil .gsp-acc__aviso.is-error {
	color: var(--gsp-rojo, #B23B32);
}

.gsp-perfil .gsp-acc__aviso.is-ok {
	color: var(--gsp-oro, #9C7A34);
}

/* ── Pedidos ─────────────────────────────────────────────────────────────── */

.gsp-perfil .gsp-ped__cuenta {
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 600;
	font-size: 12px;
	color: var(--gsp-gris, #888);
}

.gsp-perfil .gsp-ped__lista {
	display: grid;
	gap: 14px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.gsp-perfil .gsp-ped__item {
	padding: 18px 20px;
	border: 1px solid var(--gsp-linea, #E8E2D9);
	border-radius: 12px;
	transition: border-color .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-ped__item:hover {
	border-color: var(--gsp-oro, #9C7A34);
}

.gsp-perfil .gsp-ped__item-top {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	margin-bottom: 6px;
}

.gsp-perfil .gsp-ped__num {
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 15px;
	color: var(--gsp-tinta, #0A0A0A);
}

.gsp-perfil .gsp-ped__meta {
	margin: 0;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 14px;
	line-height: 1.5;
	color: var(--gsp-gris-2, #555);
}

.gsp-perfil .gsp-ped__punto {
	margin: 0 7px;
	color: var(--gsp-linea, #E8E2D9);
}

.gsp-perfil .gsp-ped__total {
	color: var(--gsp-tinta, #0A0A0A);
}

/* ── Distintivo de estado ────────────────────────────────────────────────── */

/* Cada estado lleva su color, y el que no esté contemplado hereda el gris de aquí: una
   extensión puede añadir estados que este plugin no conoce. */
.gsp-perfil .gsp-ped__estado {
	display: inline-block;
	padding: 5px 11px;
	border: 1px solid var(--gsp-linea, #E8E2D9);
	border-radius: 999px;
	background: transparent;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 10px;
	letter-spacing: .08em;
	text-transform: uppercase;
	white-space: nowrap;
	color: var(--gsp-gris-2, #555);
}

.gsp-perfil .gsp-ped__estado--completed {
	border-color: rgba(47, 122, 76, .3);
	background: rgba(47, 122, 76, .08);
	color: #2F7A4C;
}

.gsp-perfil .gsp-ped__estado--processing {
	border-color: var(--gsp-badge-bd, rgba(156, 122, 52, .25));
	background: var(--gsp-badge-bg, #FBF6EE);
	color: var(--gsp-oro, #9C7A34);
}

.gsp-perfil .gsp-ped__estado--pending,
.gsp-perfil .gsp-ped__estado--on-hold {
	border-color: rgba(176, 128, 30, .3);
	background: rgba(176, 128, 30, .08);
	color: #8A6528;
}

.gsp-perfil .gsp-ped__estado--cancelled,
.gsp-perfil .gsp-ped__estado--failed,
.gsp-perfil .gsp-ped__estado--refunded {
	border-color: rgba(178, 59, 50, .28);
	background: rgba(178, 59, 50, .07);
	color: var(--gsp-rojo, #B23B32);
}

/* ── Tira de fotos del listado ───────────────────────────────────────────── */

.gsp-perfil .gsp-ped__minis {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin-top: 14px;
}

.gsp-perfil .gsp-ped__mini {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 48px;
	height: 48px;
	overflow: hidden;
	border: 1px solid var(--gsp-linea, #E8E2D9);
	border-radius: 8px;
	background: var(--gsp-input-bg, #FAFAF7);
}

.gsp-perfil .gsp-ped__mini-img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.gsp-perfil .gsp-ped__mini--mas {
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 12px;
	color: var(--gsp-gris, #888);
}

/* ── Botones ─────────────────────────────────────────────────────────────── */

.gsp-perfil .gsp-ped__acciones {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	margin-top: 16px;
}

.gsp-perfil .gsp-ped__acciones--detalle {
	margin-top: 24px;
}

.gsp-perfil .gsp-ped__ver,
.gsp-perfil .gsp-ped__pagar,
.gsp-perfil .gsp-ped__ficha {
	display: inline-block;
	padding: 11px 20px;
	border: 1.5px solid var(--gsp-tinta, #0A0A0A);
	border-radius: 8px;
	text-decoration: none;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 11px;
	letter-spacing: .08em;
	text-transform: uppercase;
	transition: border-color .18s var(--gs-e-soft, ease), background-color .18s var(--gs-e-soft, ease), color .18s var(--gs-e-soft, ease);
}

/* «Ver detalle» es la acción de todos los días y va en segundo plano; «Pagar» solo aparece
   cuando hay algo pendiente y ahí sí conviene que grite. */
.gsp-perfil .gsp-ped__ver {
	background: transparent;
	color: var(--gsp-tinta, #0A0A0A);
}

.gsp-perfil .gsp-ped__ver:hover,
.gsp-perfil .gsp-ped__ver:focus-visible,
.gsp-perfil .gsp-ped__ver:focus {
	border-color: var(--gsp-oro, #9C7A34);
	background: transparent;
	color: var(--gsp-oro, #9C7A34);
}

.gsp-perfil .gsp-ped__pagar {
	background: var(--gsp-tinta, #0A0A0A);
	color: #fff;
}

.gsp-perfil .gsp-ped__pagar:hover,
.gsp-perfil .gsp-ped__pagar:focus-visible,
.gsp-perfil .gsp-ped__pagar:focus {
	border-color: var(--gsp-oro, #9C7A34);
	background: var(--gsp-oro, #9C7A34);
	color: #fff;
}

/* «Ver mi ficha de pago». Cuando existe, SUSTITUYE a «Pagar» —el cliente vuelve aquí a
   recuperar su comprobante, no a pagar otra vez— así que hereda su aspecto sólido. No conviven:
   ver `PedidosRenderer::acciones()`. */
.gsp-perfil .gsp-ped__ficha {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	background: var(--gsp-tinta, #0A0A0A);
	color: #fff;
}

.gsp-perfil .gsp-ped__ficha:hover,
.gsp-perfil .gsp-ped__ficha:focus-visible,
.gsp-perfil .gsp-ped__ficha:focus {
	border-color: var(--gsp-oro, #9C7A34);
	background: var(--gsp-oro, #9C7A34);
	color: #fff;
}

.gsp-perfil .gsp-ped__ext {
	width: 12px;
	height: 12px;
	flex: 0 0 auto;
}


/* ── Paginación ──────────────────────────────────────────────────────────── */

.gsp-perfil .gsp-ped__paginas {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 16px;
	margin-top: 22px;
	padding-top: 18px;
	border-top: 1px solid var(--gsp-item-sep, #F5F1E8);
}

.gsp-perfil .gsp-ped__pagina {
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 11px;
	letter-spacing: .08em;
	text-transform: uppercase;
	text-decoration: none;
	color: var(--gsp-tinta, #0A0A0A);
	transition: color .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-ped__pagina:hover,
.gsp-perfil .gsp-ped__pagina:focus-visible,
.gsp-perfil .gsp-ped__pagina:focus {
	background: transparent;
	color: var(--gsp-oro, #9C7A34);
}

.gsp-perfil .gsp-ped__pagina-de {
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 13px;
	color: var(--gsp-gris, #888);
}

/* ── Detalle ─────────────────────────────────────────────────────────────── */

.gsp-perfil .gsp-ped__volver {
	display: inline-block;
	margin-bottom: 14px;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 14px;
	text-decoration: none;
	color: var(--gsp-gris-2, #555);
	transition: color .18s var(--gs-e-soft, ease);
}

.gsp-perfil .gsp-ped__volver:hover,
.gsp-perfil .gsp-ped__volver:focus-visible,
.gsp-perfil .gsp-ped__volver:focus {
	background: transparent;
	color: var(--gsp-oro, #9C7A34);
}

.gsp-perfil .gsp-ped__cab-detalle {
	margin-bottom: 4px;
}

.gsp-perfil .gsp-ped__lineas {
	display: grid;
	gap: 0;
	margin: 22px 0 0;
	padding: 0;
	list-style: none;
}

.gsp-perfil .gsp-ped__linea {
	display: flex;
	align-items: center;
	gap: 14px;
	padding: 14px 0;
	border-bottom: 1px solid var(--gsp-item-sep, #F5F1E8);
}

.gsp-perfil .gsp-ped__linea-foto {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 60px;
	height: 60px;
	overflow: hidden;
	border: 1px solid var(--gsp-linea, #E8E2D9);
	border-radius: 8px;
	background: var(--gsp-input-bg, #FAFAF7);
}

.gsp-perfil .gsp-ped__linea-img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.gsp-perfil .gsp-ped__linea-txt {
	flex: 1 1 auto;
	display: grid;
	gap: 3px;
	min-width: 0;
}

.gsp-perfil .gsp-ped__linea-nom {
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-weight: 600;
	font-size: 15px;
	line-height: 1.35;
	text-decoration: none;
	color: var(--gsp-tinta, #0A0A0A);
	transition: color .18s var(--gs-e-soft, ease);
}

.gsp-perfil a.gsp-ped__linea-nom:hover,
.gsp-perfil a.gsp-ped__linea-nom:focus-visible,
.gsp-perfil a.gsp-ped__linea-nom:focus {
	background: transparent;
	color: var(--gsp-oro, #9C7A34);
}

.gsp-perfil .gsp-ped__linea-cant {
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 13px;
	color: var(--gsp-gris, #888);
}

.gsp-perfil .gsp-ped__linea-precio {
	flex: 0 0 auto;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 14px;
	white-space: nowrap;
	color: var(--gsp-tinta, #0A0A0A);
}

.gsp-perfil .gsp-ped__totales {
	display: grid;
	gap: 9px;
	margin-top: 20px;
	margin-left: auto;
	max-width: 320px;
}

.gsp-perfil .gsp-ped__total-fila {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 20px;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-size: 14px;
	color: var(--gsp-gris-2, #555);
}

.gsp-perfil .gsp-ped__total-fila--final {
	margin-top: 5px;
	padding-top: 12px;
	border-top: 1px solid var(--gsp-linea, #E8E2D9);
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 17px;
	color: var(--gsp-tinta, #0A0A0A);
}

.gsp-perfil .gsp-ped__dirs {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
	gap: 20px;
	margin-top: 26px;
	padding-top: 22px;
	border-top: 1px solid var(--gsp-item-sep, #F5F1E8);
}

.gsp-perfil .gsp-ped__dir-tit {
	margin: 0 0 7px;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 11px;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--gsp-gris, #888);
}

.gsp-perfil .gsp-ped__dir-txt {
	margin: 0;
	font-family: var(--gs-font-body, 'Inter', sans-serif);
	font-style: normal;
	font-size: 14px;
	line-height: 1.6;
	color: var(--gsp-tinta, #0A0A0A);
}

/* ── Adaptación a pantallas ──────────────────────────────────────────────── */

@media (max-width: 900px) {

	.gsp-perfil .gsp-perfil__grid {
		grid-template-columns: 1fr;
	}

	/* Arriba y a todo lo ancho: pegada dejaría la tarjeta flotando sobre el contenido. */
	.gsp-perfil .gsp-perfil__side {
		position: static;
		top: auto;
	}
}

@media (max-width: 600px) {

	.gsp-perfil .gsp-perfil__grid {
		padding-inline: 18px;
	}

	.gsp-perfil .gsp-perfil__panel {
		padding: 20px;
	}

	.gsp-perfil .gsp-perfil__titulo {
		font-size: 26px;
	}

	/* La tarjeta de acceso pierde el aire lateral: a 360 px cada píxel de ancho cuenta. */
	.gsp-perfil .gsp-acc {
		padding-inline: 18px;
	}

	.gsp-perfil .gsp-acc__caja {
		padding: 30px 22px;
	}

	/* Dos campos en fila a 360 px dejan cajas donde no cabe ni un apellido corto. */
	.gsp-perfil .gsp-acc__par {
		grid-template-columns: 1fr;
	}

	.gsp-perfil .gsp-acc__reglas {
		grid-template-columns: 1fr;
	}

	.gsp-perfil .gsp-acc__titulo {
		font-size: 25px;
	}

	/* El importe baja a su propia línea, alineado con el texto: en fila con el nombre
	   estrujaría los dos hasta partir palabras. */
	.gsp-perfil .gsp-ped__linea {
		flex-wrap: wrap;
	}

	.gsp-perfil .gsp-ped__linea-precio {
		width: 100%;
		padding-left: 74px;
	}

	.gsp-perfil .gsp-ped__totales {
		max-width: none;
	}

	.gsp-perfil .gsp-perfil__campos,
	.gsp-perfil .gsp-perfil__dirs,
	.gsp-perfil .gsp-perfil__modal-body {
		grid-template-columns: 1fr;
	}

	/* ── El teclado ───────────────────────────────────────────────────────
	   Aquí el modal se convierte en hoja inferior, y la caja se apoya en el fondo por
	   `align-items: flex-end`. Por eso sube con un `padding-bottom` y no con un `bottom`: lo
	   que empuja la caja hacia arriba es el hueco que deja el padding del contenedor flex.

	   El velo es un elemento aparte (`.gsp-perfil__velo`) y NO lleva este padding: tiene que
	   seguir cubriendo la pantalla entera, incluida la franja del teclado, que en iOS es
	   translúcida y deja ver la página de detrás si se descubre.

	   Las variables las publica `GSHeader.seguirViewport()` mientras el modal está abierto;
	   sin `visualViewport` mandan los respaldos y queda el comportamiento de siempre. */

	.gsp-perfil .gsp-perfil__modal {
		padding: 0;
		padding-bottom: var(--gs-vv-fondo, 0px);
		align-items: flex-end;
	}

	.gsp-perfil .gsp-perfil__modal-caja {
		max-width: none;
		max-height: calc(var(--gs-vv-alto, 100vh) * .92);
		border-radius: 16px 16px 0 0;
	}

	/* ── 16px CLAVADOS, y no es decisión tipográfica ──────────────────────
	   Safari en iOS AMPLÍA la página al enfocar cualquier campo cuya letra baje de 16px, y NO
	   deshace el zoom al salir: te quedas con el formulario de dirección ampliado y medio fuera
	   de pantalla, en mitad de un alta de dirección. Los campos estaban a 14px, y este era el
	   ÚNICO sitio del plugin con campos enfocables que se había quedado sin la regla — la vista
	   rápida, el checkout, las reseñas y los escalones ya la tenían.

	   Va solo en móvil para no engordar el formulario de escritorio, donde 14px es lo que pide
	   el diseño y el zoom de iOS no existe. */
	.gsp-perfil .gsp-perfil__input {
		font-size: 16px;
	}
}

@media (prefers-reduced-motion: reduce) {

	.gsp-perfil .gsp-perfil__velo,
	.gsp-perfil .gsp-perfil__modal-caja,
	.gsp-perfil .gsp-perfil__item,
	.gsp-perfil .gsp-perfil__input,
	.gsp-perfil .gsp-perfil__btn-edit,
	.gsp-perfil .gsp-perfil__btn-add,
	.gsp-perfil .gsp-perfil__btn-guardar,
	.gsp-perfil .gsp-perfil__btn-cancelar,
	/* Los cuatro botones de pedidos comparten `transition` en su regla base. `ver` y `pagar`
	   faltaban aquí desde que se escribieron: se añaden ahora que se toca el archivo. */
	.gsp-perfil .gsp-ped__ver,
	.gsp-perfil .gsp-ped__pagar,
	.gsp-perfil .gsp-ped__ficha {
		transition: none;
	}

	.gsp-perfil .gsp-perfil__modal-caja {
		transform: none;
	}
}

/* ---- checkout.css ---- */
/**
 * GS Checkout. Handle 'gs-checkout' (depende de 'gs-tokens' y 'gs-fonts').
 *
 * NO depende de 'gs-header-base': ese archivo neutraliza los `<button>` nativos con
 * `.gs-hd button, .gs-portal button { padding: 0; border: 0 }` y mete un
 * `text-decoration: none !important` que aquí estorba. Este widget no es de header y se
 * viste solo.
 *
 * Todo el color entra por variables locales `--gsc-*` que por defecto valen el token del
 * sistema. Los controles de Elementor reescriben ESAS VARIABLES sobre `.gsc`, nunca la
 * propiedad: un `selectors` se emite con 0,4,0 y le ganaría a los estados y al móvil
 * (INSTRUCCIONES.md §3.3).
 *
 * Todos los `:hover` van prefijados por `.gsc` —que con la pseudoclase suma 0,3,0— y
 * declaran FONDO Y COLOR, aunque solo cambie uno: el que se deje sin declarar es
 * exactamente el que rellena el Global Kit de Elementor (§3.1).
 */

.gsc {
	--gsc-max: 1280px;
	--gsc-pad: 32px;
	/* Aire vertical propio. El widget ocupa la página entera entre el header y el pie, y sin
	   esto quedaba a 10px de cada uno —los del contenedor de Elementor—, pegado a los dos.
	   Es padding y no margin para que no colapse con los márgenes de lo que tenga al lado. */
	--gsc-pad-y: 48px;
	--gsc-lado: 360px;
	--gsc-gap: 32px;

	--gsc-tinta: var(--gs-tinta, #0A0A0A);
	--gsc-tinta-h: var(--gs-tinta-hover, #242424);
	--gsc-oro: var(--gs-oro, #9C7A34);
	--gsc-oro-clr: var(--gs-oro-clr, #C2A370);
	--gsc-oro-pale: var(--gs-oro-pale, #FBF6EE);
	--gsc-linea: var(--gs-linea, #E8E2D9);
	--gsc-hueso: var(--gs-hueso, #F5F1E8);
	--gsc-verde: var(--gs-verde, #3A7D44);
	--gsc-gris: var(--gs-txt-3, #888888);
	/* Gris del marcador de los campos. Propio y no `--gs-txt-4`: ver la nota de
	   `.gsc__input::placeholder`. No sale de tokens.css porque allí no hay ningún gris
	   entre #888 y #555, y añadir uno para un solo uso es peor que tenerlo aquí. */
	--gsc-marcador: #757575;

	box-sizing: border-box;
	max-width: var(--gsc-max);
	margin-inline: auto;
	padding-block: var(--gsc-pad-y);
	padding-inline: var(--gsc-pad);
	color: var(--gsc-tinta);
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
}

.gsc *,
.gsc *::before,
.gsc *::after {
	box-sizing: border-box;
}

/* ── Indicador de pasos ───────────────────────────────────────────────────── */

.gsc__pasos {
	display: flex;
	align-items: center;
	gap: 0;
	margin: 0 0 40px;
	padding: 0;
	list-style: none;
}

/* Cada estado PUBLICA sus colores en variables y la bola los consume.

   Es la regla 5 del blindaje anti-Kit (INSTRUCCIONES.md §3.1): si el color lo trae una
   variante, la variante escribe una variable y las reglas de estado la leen. Las variables
   heredan y no compiten por especificidad, así que UNA sola regla de `:hover`/`:focus` a
   (0,3,1) sirve para los tres estados. Redeclarando colores por estado harían falta tres
   reglas de hover, y la que se olvidara la rellenaría el Kit. */
.gsc__paso {
	display: flex;
	align-items: center;
	gap: 12px;
	flex: 0 0 auto;

	--gsc-bola-bg: #fff;
	--gsc-bola-borde: var(--gsc-linea);
	--gsc-bola-tinta: var(--gsc-gris);
	--gsc-bola-grosor: 1.5px;
}

.gsc__paso.is-activo {
	--gsc-bola-bg: var(--gsc-tinta);
	--gsc-bola-borde: var(--gsc-tinta);
	--gsc-bola-tinta: #fff;
	--gsc-bola-grosor: 2px;
}

.gsc__paso.is-hecho {
	--gsc-bola-bg: var(--gsc-oro-pale);
	--gsc-bola-borde: var(--gsc-oro);
	--gsc-bola-tinta: var(--gsc-oro);
}

/* La línea que une los círculos. Es un pseudo-elemento del propio paso y no un nodo
   aparte: así el markup queda limpio y la línea se estira con `flex: 1`. */
.gsc__paso:not(:last-child)::after {
	content: '';
	flex: 1 1 auto;
	height: 1px;
	min-width: 24px;
	background: var(--gsc-linea);
	margin: 0 16px;
}

.gsc__paso:not(:last-child) {
	flex: 1 1 auto;
}

/* La bola es un `<button>` desde que el indicador navega. Lleva su propio reset porque
   esta hoja NO depende de `gs-header-base` (a propósito: allí los `<button>` se aplastan
   y se les mete un `text-decoration: none !important` que aquí estorba), así que lo que
   hay que apagar son los estilos nativos del navegador. */
.gsc button.gsc__bola {
	position: relative;
	display: grid;
	place-items: center;
	width: 32px;
	height: 32px;
	flex: 0 0 32px;
	margin: 0;
	padding: 0;
	appearance: none;
	-webkit-appearance: none;
	border-radius: var(--gs-r-pill, 999px);
	background: var(--gsc-bola-bg);
	border: var(--gsc-bola-grosor) solid var(--gsc-bola-borde);
	color: var(--gsc-bola-tinta);
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 0.75rem;
	line-height: 1;
	cursor: pointer;
	transition: background .25s var(--gs-e-soft, ease), border-color .25s var(--gs-e-soft, ease), color .25s var(--gs-e-soft, ease);
}

/* Un paso al que aún no se ha llegado no se puede pulsar, y el cursor lo dice antes de
   intentarlo. Es `aria-disabled` y no `disabled` para que siga siendo tabulable y el
   lector pueda anunciar de qué paso se trata (INSTRUCCIONES.md §6). */
.gsc button.gsc__bola[aria-disabled='true'] {
	cursor: default;
}

/* El par fondo+color de los estados, en UNA regla y a (0,3,1).

   Declara las dos propiedades aunque el diseño no cambie ninguna: el Kit de Elementor
   emite `.elementor-kit-N button:hover { background-color; color }` a (0,2,1), y la que
   se dejara sin declarar la rellenaría él. Los valores salen de las variables del estado,
   así que «no cambia nada al pasar el ratón» es aquí una decisión escrita, no un olvido.
   Cubre `:focus` además de `:focus-visible` porque el Kit también emite `button:focus`. */
.gsc button.gsc__bola:hover,
.gsc button.gsc__bola:focus,
.gsc button.gsc__bola:focus-visible {
	background: var(--gsc-bola-bg);
	color: var(--gsc-bola-tinta);
}

.gsc button.gsc__bola:focus-visible {
	outline: 2px solid var(--gsc-oro);
	outline-offset: 2px;
}

/* La etiqueta que lee el lector de pantalla. El botón necesita un nombre y un número
   suelto no lo es; la etiqueta visible de al lado va `aria-hidden` para no leerla dos
   veces. No se usa `display: none` porque eso también la esconde del lector. */
.gsc__bola-sr {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.gsc__bola-ok {
	display: none;
	width: 14px;
	height: 14px;
}

.gsc__bola-ok svg {
	width: 100%;
	height: 100%;
	display: block;
}

.gsc__paso.is-hecho .gsc__bola-n {
	display: none;
}

.gsc__paso.is-hecho .gsc__bola-ok {
	display: block;
}

.gsc__paso-txt {
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 600;
	font-size: 0.6875rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--gsc-gris);
	white-space: nowrap;
}

.gsc__paso.is-activo .gsc__paso-txt {
	color: var(--gsc-tinta);
}

.gsc__paso.is-hecho .gsc__paso-txt {
	color: var(--gsc-oro);
}

/* ── Vistas ───────────────────────────────────────────────────────────────── */

.gsc__vista {
	outline: none;
}

/* La animación va en la vista visible, no en un `.is-entrando` con temporizador: el
   navegador la dispara al dejar de estar `hidden` y no hay estado que limpiar si el
   usuario cambia de paso a media animación. */
.gsc__vista.is-visible {
	animation: gscEntra .3s var(--gs-e-out, cubic-bezier(.22, 1, .36, 1)) both;
}

@keyframes gscEntra {
	from { opacity: 0; transform: translateY(12px); }
	to   { opacity: 1; transform: none; }
}

/* ── Lo que se esconde SIN dejar de poder medirse ──────────────────────────── */

/* Dos sitios, un mismo problema: dentro vive el paso de pago, y las pasarelas montan su
   SDK sobre `payment_fields()` midiendo los campos. Un contenedor en `display: none` mide
   cero y el formulario de la tarjeta nace roto o no se monta. La fila de grid a `0fr` deja
   el contenedor sin alto pero conserva la caja de lo que lleva dentro, que es exactamente
   la técnica que ya usaba `.gsc__pasarela-campos`; y `visibility: hidden` lo saca del orden
   de tabulación, que es lo que daba el `hidden` de los demás pasos.

   El envoltorio se esconde preguntando por el ESTADO del DOM y no por el número de paso.
   Un selector `[data-paso="1"]` es justo lo que dejó al checkout de Fanor —de donde viene
   esta organización— con su paso «Confirmar» dentro de un `display: none`: insertaron un
   paso, PHP renumeró y el CSS se quedó apuntando al número viejo. Sin número no hay nada
   que mantener sincronizado.

   `grid-auto-rows: 0` además de la primera fila: así no hace falta envolver el contenido
   en un div de más. Cada hijo directo cae a alto cero y su contenido se desborda —y un
   contenido desbordado conserva su caja, que es lo único que los SDK necesitan—. */
.gsc .gsc__medio:not(:has(.gsc__vista.is-visible)),
.gsc .gsc__vista--medible:not(.is-visible) {
	display: grid;
	grid-template-rows: minmax(0, 0fr);
	grid-auto-rows: 0;
	overflow: hidden;
	visibility: hidden;
	margin: 0;
}

.gsc__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr) var(--gsc-lado);
	gap: var(--gsc-gap);
	align-items: start;
}

.gsc__principal {
	min-width: 0;
}

.gsc__sticky {
	position: sticky;
	top: 24px;
}

/* ── Cabeceras ────────────────────────────────────────────────────────────── */

.gsc__cab {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 16px;
	margin-bottom: 24px;
}

.gsc__cab--col {
	flex-direction: column;
	align-items: flex-start;
	gap: 8px;
}

.gsc__h2 {
	margin: 0;
	font-family: var(--gs-font-display, 'Archivo', sans-serif);
	font-weight: 700;
	font-size: 2rem;
	line-height: 1.1;
	letter-spacing: -0.01em;
	text-transform: uppercase;
	color: var(--gsc-tinta);
}

.gsc__sub {
	margin: 0;
	font-size: 0.9375rem;
	color: var(--gsc-gris);
}

.gsc__mas {
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 600;
	font-size: 0.6875rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--gsc-oro);
	text-decoration: none;
	border-bottom: 1px solid var(--gsc-linea);
	padding-bottom: 3px;
	transition: color .2s var(--gs-e-soft, ease), border-color .2s var(--gs-e-soft, ease);
}

/* 0,3,0 y declara fondo Y color: ver la cabecera del archivo. */
.gsc .gsc__mas:hover,
.gsc .gsc__mas:focus-visible,
.gsc .gsc__mas:focus {
	background: transparent;
	color: var(--gsc-tinta);
	border-color: var(--gsc-oro);
}

/* ── Paso 1: líneas ───────────────────────────────────────────────────────── */

.gsc__lineas {
	margin: 0;
	padding: 0;
	list-style: none;
	display: flex;
	flex-direction: column;
	gap: 16px;
}

.gsc__linea {
	display: flex;
	align-items: flex-start;
	gap: 20px;
	padding: 20px;
	background: #fff;
	border: 1px solid var(--gsc-linea);
	border-radius: var(--gs-r-xl, 14px);
	transition: opacity .2s var(--gs-e-soft, ease);
}

.gsc__linea.is-cargando {
	opacity: .5;
	pointer-events: none;
}

.gsc__foto {
	flex: 0 0 90px;
	width: 90px;
	height: 90px;
	border-radius: var(--gs-r-md, 8px);
	overflow: hidden;
	background: var(--gsc-hueso);
	display: block;
}

.gsc__foto img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.gsc__datos {
	flex: 1 1 auto;
	min-width: 0;
}

.gsc__cat {
	margin: 0 0 6px;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 600;
	font-size: 0.5625rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--gsc-gris);
}

.gsc__nombre {
	margin: 0 0 10px;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 0.9375rem;
	line-height: 1.3;
}

.gsc__nombre a {
	color: var(--gsc-tinta);
	text-decoration: none;
}

.gsc .gsc__nombre a:hover,
.gsc .gsc__nombre a:focus-visible,
.gsc .gsc__nombre a:focus {
	background: transparent;
	color: var(--gsc-oro);
}

.gsc__chips {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.gsc__chip {
	font-size: 0.75rem;
	color: var(--gs-txt-2, #555);
	background: var(--gsc-hueso);
	border-radius: var(--gs-r-sm, 6px);
	padding: 4px 10px;
}

.gsc__acciones {
	flex: 0 0 auto;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 10px;
}

.gsc__precio {
	margin: 0;
	font-family: var(--gs-font-display, 'Archivo', sans-serif);
	font-weight: 500;
	font-size: 1.5rem;
	line-height: 1.1;
	color: var(--gsc-tinta);
	white-space: nowrap;
}

/* Stepper de cantidad */
.gsc__stepper {
	display: flex;
	align-items: center;
	border: 1px solid var(--gsc-linea);
	border-radius: var(--gs-r-md, 8px);
	overflow: hidden;
	background: #fff;
}

/* 0,2,1: los resets de `button` de otras hojas son 0,1,1 y ganarían a una clase suelta
   (INSTRUCCIONES.md §3.2). Mínimo táctil de 40px en el botón. */
.gsc button.gsc__paso-btn {
	display: grid;
	place-items: center;
	width: 36px;
	height: 40px;
	padding: 0;
	border: 0;
	background: #fff;
	color: var(--gsc-tinta);
	cursor: pointer;
	transition: background .15s var(--gs-e-soft, ease), color .15s var(--gs-e-soft, ease);
}

.gsc button.gsc__paso-btn svg {
	width: 14px;
	height: 14px;
	display: block;
}

.gsc button.gsc__paso-btn:hover,
.gsc button.gsc__paso-btn:focus-visible,
.gsc button.gsc__paso-btn:focus {
	background: var(--gsc-hueso);
	color: var(--gsc-oro);
}

/* 0,2,1, por la MISMA razón que los botones de aquí arriba y con la misma trampa detrás. El
   reset del tema trae `input[type="number"] { border: 1px solid #666; width: 100%; border-radius:
   3px }`, que es (0,1,1): empata en clases con `.gsc__qty` (0,1,0) y desempata por el elemento.
   Perdiendo se perdía TODO lo de esta regla a la vez —borde, ancho y apariencia—, así que el
   contador salía como una caja gris de 98,8px con su propio recuadro y esquinas de 3px dentro del
   stepper, en vez de los 44px sin borde con solo las dos líneas laterales. Medido en pantalla. */

.gsc input.gsc__qty {
	width: 44px;
	height: 40px;
	border: 0;
	border-inline: 1px solid var(--gsc-linea);
	/* Explícito aunque el valor sea el neutro: el reset del tema pone `border-radius: 3px` y
	   aquí no había NADA que lo pisara, así que se colaba. Se veía poco —sin borde arriba ni
	   abajo, lo único que curvaba eran los extremos de las dos líneas laterales—, pero deja el
	   aspecto del contador a merced de una hoja ajena. La esquina la decide esta regla. */
	border-radius: 0;
	/* Y el relleno, por lo mismo y con peor consecuencia. De fuera venía `padding: 8px 16px`,
	   que con esta caja de 44px deja 10px para el número: un «14» mide 17px y se cortaba. No se
	   notaba mientras el campo heredaba los 98,8px del tema —ahí sobraba sitio—, así que el
	   síntoma apareció justo al devolverle su ancho de diseño. Sin relleno caben cuatro cifras
	   (40px de texto en 42px de hueco) y el `text-align: center` de abajo hace el resto. */
	padding: 0;
	text-align: center;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 600;
	font-size: 0.875rem;
	color: var(--gsc-tinta);
	background: #fff;
	-moz-appearance: textfield;
	appearance: textfield;
}

.gsc input.gsc__qty::-webkit-outer-spin-button,
.gsc input.gsc__qty::-webkit-inner-spin-button {
	-webkit-appearance: none;
	margin: 0;
}

.gsc button.gsc__quitar {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	min-height: 32px;
	padding: 0;
	border: 0;
	background: transparent;
	color: var(--gsc-gris);
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 500;
	font-size: 0.75rem;
	letter-spacing: 0.04em;
	cursor: pointer;
	transition: color .15s var(--gs-e-soft, ease);
}

.gsc button.gsc__quitar svg {
	width: 11px;
	height: 11px;
	display: block;
}

.gsc button.gsc__quitar:hover,
.gsc button.gsc__quitar:focus-visible,
.gsc button.gsc__quitar:focus {
	background: transparent;
	color: var(--gs-rojo, #B23B32);
}

.gsc__vacio {
	margin: 0;
	padding: 40px 20px;
	text-align: center;
	color: var(--gsc-gris);
	background: #fff;
	border: 1px solid var(--gsc-linea);
	border-radius: var(--gs-r-xl, 14px);
}

/* ── Paso 1: cupón ────────────────────────────────────────────────────────── */

.gsc__cupon {
	display: flex;
	align-items: center;
	gap: 12px;
	flex-wrap: wrap;
	margin-top: 16px;
	padding: 18px 20px;
	background: #fff;
	border: 1px dashed var(--gsc-linea);
	border-radius: var(--gs-r-xl, 14px);
	transition: opacity .2s var(--gs-e-soft, ease);
}

.gsc__cupon.is-cargando {
	opacity: .5;
	pointer-events: none;
}

.gsc__cupon-lbl {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	flex: 0 0 auto;
	font-size: 0.875rem;
	color: var(--gsc-gris);
	cursor: pointer;
}

.gsc__cupon-ico svg {
	width: 16px;
	height: 16px;
	display: block;
	color: var(--gsc-oro-clr);
}

/* 0,2,1: mismo reset del tema, aquí con `input[type="text"]`. Sin esto el campo del cupón salía
   con el borde gris de 1px y esquinas de 3px en vez de los 1.5px de la línea de la casa. */

.gsc input.gsc__cupon-input {
	flex: 1 1 140px;
	min-width: 0;
	height: 40px;
	padding: 0 14px;
	border: 1.5px solid var(--gsc-linea);
	border-radius: var(--gs-r-md, 8px);
	font-family: inherit;
	font-size: 0.875rem;
	color: var(--gsc-tinta);
	background: #fff;
	transition: border-color .18s var(--gs-e-soft, ease);
}

.gsc input.gsc__cupon-input:focus {
	outline: none;
	border-color: var(--gsc-oro);
}

.gsc button.gsc__cupon-btn {
	flex: 0 0 auto;
	min-height: 40px;
	padding: 0 22px;
	border: 1px solid var(--gsc-oro);
	border-radius: var(--gs-r-md, 8px);
	background: #fff;
	color: var(--gsc-oro);
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 0.6875rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	cursor: pointer;
	transition: background .18s var(--gs-e-soft, ease), color .18s var(--gs-e-soft, ease);
}

.gsc button.gsc__cupon-btn:hover,
.gsc button.gsc__cupon-btn:focus-visible,
.gsc button.gsc__cupon-btn:focus {
	background: var(--gsc-oro-pale);
	color: var(--gsc-oro);
}

/* ── Paso 1: resumen ──────────────────────────────────────────────────────── */

.gsc__resumen {
	background: #fff;
	border: 1px solid var(--gsc-linea);
	border-radius: var(--gs-r-2xl, 16px);
	padding: 28px;
}

.gsc__resumen-h {
	margin: 0 0 20px;
	font-family: var(--gs-font-display, 'Archivo', sans-serif);
	font-weight: 700;
	font-size: 1.125rem;
	letter-spacing: 0.02em;
	text-transform: uppercase;
}

/* La LISTA DE IMPORTES: Subtotal, Descuento, Envío. Es un `<dl>`, y no lleva caja
   propia —vive dentro de `.gsc__resumen` o de `.gsc__mini`, que ya tienen la suya—:
   solo una línea abajo que la separa del TOTAL.

   No reutilices este nombre. Lo hizo el grupo de radios del método de pago y, con la
   misma especificidad, su `border` shorthand borraba este `border-bottom` y encajonaba
   los importes contra sus propios bordes. Ese componente se llama `.gsc__opciones`. */

.gsc__filas {
	margin: 0 0 20px;
	padding: 0 0 20px;
	border-bottom: 1px solid var(--gsc-linea);
	display: flex;
	flex-direction: column;
	gap: 12px;
}

.gsc__fila {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 12px;
}

.gsc__fila dt {
	margin: 0;
	font-size: 0.875rem;
	color: var(--gs-txt-2, #555);
}

.gsc__fila dd {
	margin: 0;
	font-size: 0.875rem;
	font-weight: 600;
	color: var(--gsc-tinta);
	white-space: nowrap;
}

.gsc__free {
	color: var(--gsc-verde);
}

/* La promesa del umbral («Envío gratis a partir de $2,000»). Es una fila de la lista, pero SIN
   columna de importe: su `<dd>` va vacío a propósito, porque el ahorro real no se conoce y la
   columna del dinero significa «lo que se cobra en este pedido». Ver el comentario largo de
   `CheckoutRenderer`, que cuenta por qué esa celda no puede llevar cifra.

   Antes era un `<p>` fuera del `<dl>`, y por eso caía debajo de la separadora, pegado al TOTAL.

   `flex: 1` en el `<dt>` para que ocupe el ancho entero: el `justify-content: space-between` de
   `.gsc__fila` la dejaría alineada a la izquierda igual, pero un texto largo se partiría contra
   un `<dd>` vacío que sigue reservando su hueco de `gap`. */

.gsc__fila--promo dt {
	flex: 1;
	color: var(--gsc-verde);
}

.gsc__fila--promo dd {
	display: none;
}

.gsc__calc {
	color: var(--gsc-verde);
	font-weight: 600;
}

.gsc__total {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 12px;
	margin-bottom: 20px;
}

.gsc__total-lbl {
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 0.75rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

/* 1.875rem (30px) y no 2.25 (36px), que es lo que había. Medido en la tarjeta del resumen: a 36px
   el total salía MÁS GRANDE que el «Tu Carrito» de la propia página (32px) y era metro y medio el
   precio de cada línea (24px). No era falta de sitio —le sobraban 68px de los 304 de la tarjeta—,
   era jerarquía: el importe pesaba más que el título y la pantalla se leía desequilibrada.

   A 30px queda justo por debajo del título y bien por encima del precio de línea, así que sigue
   siendo sin discusión el número que manda en la tarjeta. El corte de móvil lo baja a 1.75rem
   aparte, por sitio y no por peso. */

.gsc__total-n {
	font-family: var(--gs-font-display, 'Archivo', sans-serif);
	font-weight: 500;
	font-size: 1.875rem;
	line-height: 1;
	letter-spacing: -0.02em;
	color: var(--gsc-tinta);
}

/* CTA principal. 0,2,1 por el mismo motivo que el stepper. */
.gsc button.gsc__cta,
.gsc a.gsc__cta--a {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	width: 100%;
	min-height: 56px;
	padding: 0 24px;
	border: 0;
	border-radius: var(--gs-r-md, 8px);
	background: var(--gsc-tinta);
	color: #fff;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 0.8125rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	text-decoration: none;
	cursor: pointer;
	transition: background .2s var(--gs-e-soft, ease);
}

.gsc button.gsc__cta svg {
	width: 18px;
	height: 18px;
	display: block;
}

.gsc button.gsc__cta:hover,
.gsc button.gsc__cta:focus-visible,
.gsc a.gsc__cta--a:hover,
.gsc a.gsc__cta--a:focus-visible,
.gsc button.gsc__cta:focus,
.gsc a.gsc__cta--a:focus {
	background: var(--gsc-tinta-h);
	color: #fff;
}

.gsc button.gsc__cta[disabled] {
	opacity: .45;
	cursor: not-allowed;
}

.gsc button.gsc__cta.is-cargando {
	opacity: .6;
	cursor: progress;
}

.gsc__nota {
	margin: 12px 0 0;
	text-align: center;
	font-size: 0.75rem;
	color: var(--gsc-gris);
}

.gsc__seguir {
	display: block;
	margin-top: 20px;
	text-align: center;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 600;
	font-size: 0.6875rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--gsc-gris);
	text-decoration: none;
	transition: color .2s var(--gs-e-soft, ease);
}

.gsc .gsc__seguir:hover,
.gsc .gsc__seguir:focus-visible,
.gsc .gsc__seguir:focus {
	background: transparent;
	color: var(--gsc-tinta);
}

/* ── Pasos 2 a 5: la tarjeta de cada paso ─────────────────────────────────── */

/* La tarjeta es cada PASO. La caja se ha ido moviendo con la unidad de trabajo: primero
   la llevaba el formulario entero, luego cada sección del acordeón, y ahora el paso, que
   es lo que el cliente resuelve de una vez. Sigue siendo un <form> de verdad —un solo
   POST, una sola validación del navegador—, solo que sin vestido propio: si lo tuviera,
   la tarjeta del paso quedaría dentro de otra caja, y una caja dentro de otra duplica
   bordes y radios sin añadir información. */

.gsc__form {
	background: transparent;
	border: 0;
	padding: 0;
}

.gsc__form .gsc__vista {
	background: #fff;
	border: 1px solid var(--gsc-linea);
	border-radius: var(--gs-r-xl, 14px);
	padding: 22px;
}

/* El relleno y el borde viven FUERA de las filas de la rejilla, así que un paso
   colapsado a `0fr` seguiría midiendo 45px de alto si no se apagaran aquí. Es la misma
   trampa por la que el colapso lleva `margin: 0`. */
.gsc .gsc__vista--medible:not(.is-visible) {
	padding: 0;
	border-width: 0;
}

/* El título de cada paso, visible y no solo para lectores de pantalla.

   Con tres pasos el indicador bastaba para saber dónde estabas y un <h2> repetía lo que
   ya decía la bola. Con cinco no: por debajo de 1024px las etiquetas del indicador se
   esconden —cinco palabras en mayúsculas con letter-spacing no caben en un iPad en
   vertical— y sin este título la pantalla no dice de qué paso es el formulario. */
.gsc__h3 {
	margin: 0 0 4px;
	font-family: var(--gs-font-display, 'Archivo', sans-serif);
	font-weight: 700;
	font-size: 1.25rem;
	line-height: 1.15;
	letter-spacing: -0.01em;
	color: var(--gsc-tinta);
}

/* El subtítulo separa del primer campo; los pasos que no lo llevan no arrastran hueco. */
.gsc__vista .gsc__sub {
	margin-bottom: 22px;
}

/* ── Paso 4: el repaso ────────────────────────────────────────────────────── */

.gsc__rev {
	display: grid;
	gap: 1px;
	background: var(--gsc-linea);
	border: 1px solid var(--gsc-linea);
	border-radius: var(--gs-r-md, 9px);
	overflow: hidden;
}

/* El separador es el `gap` sobre un fondo de línea y no un `border-bottom` por bloque:
   así no hay que acordarse de quitárselo al último, que es de donde salen los bordes
   dobles cuando alguien añade un bloque más. */
.gsc__rev-b {
	background: #fff;
	padding: 16px 18px;
}

.gsc__rev-cab {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 12px;
	margin-bottom: 8px;
}

.gsc__rev-tit {
	margin: 0;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 600;
	font-size: 0.6875rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--gsc-gris);
}

.gsc__rev-l {
	margin: 0 0 2px;
	font-size: 0.875rem;
	line-height: 1.45;
	color: var(--gsc-tinta);
}

.gsc__rev-l:last-child {
	margin-bottom: 0;
}

/* Un hueco del repaso sin nada que contar se esconde: la dirección con recogida en
   tienda, o el envío antes de que haya código postal. */
.gsc__rev-l[hidden] {
	display: none;
}

/* «Cambiar»: un <button> con pinta de enlace. Reset propio porque esta hoja no depende
   de `gs-header-base` y lo que hay que apagar son los estilos nativos del navegador. */
.gsc button.gsc__cambiar {
	margin: 0;
	padding: 0;
	appearance: none;
	-webkit-appearance: none;
	background: transparent;
	border: 0;
	border-bottom: 1px solid var(--gsc-oro-clr);
	border-radius: 0;
	color: var(--gsc-oro);
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 600;
	font-size: 0.6875rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	line-height: 1.2;
	cursor: pointer;
	flex: 0 0 auto;
	transition: color .2s var(--gs-e-soft, ease), border-color .2s var(--gs-e-soft, ease);
}

/* Fondo Y color, aunque aquí solo se quiera cambiar el color: el que se deje sin
   declarar lo rellena `.elementor-kit-N button:hover` (0,2,1). Y el `border-bottom`
   dorado se redeclara también — no hacerlo fue exactamente el bug del botón «Deshacer»
   del minicarrito, que se volvía rosa. `:focus` además de `:focus-visible` porque el Kit
   emite los dos. */
.gsc button.gsc__cambiar:hover,
.gsc button.gsc__cambiar:focus,
.gsc button.gsc__cambiar:focus-visible {
	background: transparent;
	color: var(--gsc-tinta);
	border-bottom-color: var(--gsc-tinta);
}

.gsc button.gsc__cambiar:focus-visible {
	outline: 2px solid var(--gsc-oro);
	outline-offset: 3px;
}
.gsc__campos {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 18px 20px;
}

.gsc__campo--ancho {
	grid-column: 1 / -1;
}

.gsc__campo[hidden] {
	display: none;
}

/* «Notas adicionales» ya no cuelga del formulario: vive dentro de la rejilla de la
   sección de entrega, que es de donde son las instrucciones para quien entrega. Con
   eso desaparece la regla que le daba margen a los hijos directos del <form> —el
   `gap` de la rejilla ya lo separa— y con ella el hueco de más que aquel margen le
   sumaba a cualquier campo que cambiara de sitio. */

.gsc__campos--sep {
	margin-top: 22px;
}

.gsc__lbl {
	display: block;
	margin-bottom: 8px;
	padding: 0;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 600;
	font-size: 0.6875rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--gs-txt-2, #555);
}

.gsc__req {
	color: var(--gsc-oro);
}

/* 0,2,0 y SIN calificar por etiqueta: esta clase la llevan el <input>, el <select> y el
   <textarea>, así que un `input.gsc__input` dejaría fuera a los otros dos. Dos clases bastan —el
   reset del tema es (0,1,1) y el recuento de clases se compara antes que el de elementos—, y así
   los tres campos siguen compartiendo una sola regla, que es lo que los mantiene idénticos. */

.gsc .gsc__input {
	display: block;
	width: 100%;
	padding: 13px 16px;
	border: 1.5px solid var(--gsc-linea);
	border-radius: var(--gs-r-md, 8px);
	background: #fff;
	font-family: inherit;
	font-size: 0.9375rem;
	color: var(--gsc-tinta);
	transition: border-color .18s var(--gs-e-soft, ease);
}

/* NO usa `--gs-txt-4` (#9A9A9A), que es el gris de metadatos: sobre blanco da 2,9:1 y
   el mínimo para texto es 4,5:1. Un marcador no es decoración —dice con qué formato se
   espera el dato, «Ej. Calle San Fabián 24»— y en un formulario de compra es justo lo
   que mira quien duda. `--gsc-marcador` sale a 4,6:1 y sigue leyéndose como pista, no
   como valor escrito. */

.gsc .gsc__input::placeholder {
	color: var(--gsc-marcador);
}

.gsc .gsc__input:focus {
	outline: none;
	border-color: var(--gsc-oro);
}

/* ── Un campo que no pasa ─────────────────────────────────────────────────────
   El aviso que se acordó con el dueño (10-09-2026): borde rojo y un toast con los motivos,
   SIN texto bajo el campo. El motivo, para quien no ve el rojo, va en un hueco oculto a la
   vista y enlazado por `aria-describedby` (`CheckoutRenderer::hueco_motivo()`).

   Con `[aria-invalid]` y NO con `:invalid` ni `:user-invalid`. `:invalid` se pinta al cargar
   la página —un `required` vacío ya es inválido antes de que nadie lo toque— y `:user-invalid`
   decide él cuándo regañar. `aria-invalid` lo pone el JS al pulsar «Continuar», que es el
   momento que se acordó, y lo quita en cuanto el campo queda bien.

   (0,3,0), la misma que la regla de `:focus` de arriba: por eso va DESPUÉS de ella. */

.gsc .gsc__input[aria-invalid="true"] {
	border-color: var(--gs-rojo, #B23B32);
}

/* Enfocado Y en rojo: el rojo se queda —el dorado del foco escondería el error justo cuando
   el cliente va a corregirlo— y el foco se ve por el anillo, del mismo rojo. (0,4,0). */

.gsc .gsc__input[aria-invalid="true"]:focus {
	border-color: var(--gs-rojo, #B23B32);
	box-shadow: 0 0 0 1px var(--gs-rojo, #B23B32);
}

/* Los grupos de opciones —entrega, envío, pago— no tienen caja de campo propia: el rojo va al
   borde del contenedor que las agrupa. */

.gsc .gsc__grupo.is-invalido .gsc__opciones,
.gsc .gsc__grupo.is-invalido .gsc__seg {
	border-color: var(--gs-rojo, #B23B32);
}

/* A domicilio sin ninguna tarifa no hay opciones que enmarcar: se tiñe la pista que lo dice. */

.gsc .gsc-frg-envio.is-invalido .gsc__pista {
	color: var(--gs-rojo, #B23B32);
}

/* La flecha del select se dibuja aquí porque `appearance: none` quita la nativa; va como
   data-URI para no pedir un archivo (y porque el CSP del sitio bloquea externos). */
/* También a (0,2,0), y no por el reset del tema sino por la regla de arriba: `.gsc .gsc__input`
   fija `padding: 13px 16px`, y con una clase suelta aquí ese atajo le ganaría al `padding-right`
   que reserva el hueco de la flecha. La flecha acabaría encima del texto del estado. */

.gsc .gsc__select {
	appearance: none;
	-webkit-appearance: none;
	padding-right: 40px;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%230A0A0A' stroke-width='1.6'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 16px center;
	background-size: 12px 8px;
	cursor: pointer;
}

/* Idem: modifica a `.gsc .gsc__input`, así que tiene que pesar al menos lo mismo. */

.gsc .gsc__area {
	resize: vertical;
	min-height: 96px;
	line-height: 1.6;
}

.gsc__grupo {
	margin: 24px 0 0;
	padding: 0;
	border: 0;
}

.gsc__grupo .gsc__lbl {
	margin-bottom: 10px;
}

/* ── Tipo de entrega: un control SEGMENTADO ───────────────────────────────────
   Dos opciones excluyentes que se comparan de un vistazo. Antes eran dos tarjetas,
   y una tarjeta por opción dentro de la tarjeta de la sección es la caja dentro de
   la caja que este rediseño vino a quitar. Un segmentado dice «elige una de estas
   dos» con la forma, sin necesidad de bordes por opción. */

.gsc__seg {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	border: 1px solid var(--gsc-linea);
	border-radius: var(--gs-r-md, 8px);
	background: #fff;
	overflow: hidden;
}

.gsc__seg-op {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding: 12px 16px;
	cursor: pointer;
	transition: background .18s var(--gs-e-soft, ease), color .18s var(--gs-e-soft, ease);
}

.gsc__seg-op + .gsc__seg-op {
	border-left: 1px solid var(--gsc-linea);
}

/* El ícono, traído del checkout de Fanor. Va en línea con el título y no encima: en un
   segmentado de dos mitades el alto lo marca la opción más alta, y una fila de ícono
   propia le sumaría 26px a las dos para decorar. A 16px la silueta de Phosphor —caja o
   local— todavía se distingue, que es lo único que se le pide: reconocer la opción antes
   de leerla. Hereda `currentColor`, así que se tiñe con el estado sin una regla más. */
.gsc__seg-ico {
	display: inline-flex;
	width: 16px;
	height: 16px;
	margin-right: 7px;
	vertical-align: -3px;
}

.gsc__seg-ico svg {
	width: 100%;
	height: 100%;
	display: block;
}

.gsc__seg-txt strong {
	display: block;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 600;
	font-size: 0.875rem;
}

.gsc__seg-txt em {
	font-style: normal;
	font-size: 0.75rem;
	color: var(--gsc-gris);
}

.gsc__seg-op:has(.gsc__radio:checked) {
	background: var(--gsc-tinta);
	color: #fff;
}

.gsc__seg-op:has(.gsc__radio:checked) .gsc__seg-txt em {
	color: rgba(255, 255, 255, .68);
}

/* Foco POR DENTRO. Un `outline` se dibuja fuera de la pieza y aquí lo recortaría el
   `overflow: hidden` que redondea las esquinas del segmentado. */

.gsc__seg-op:has(.gsc__radio:focus-visible) {
	box-shadow: inset 0 0 0 2px var(--gsc-oro);
}

/* Hover a (0,3,0) y declarando FONDO Y COLOR, aunque solo cambie el fondo: el Global
   Kit de Elementor emite sus estados con (0,2,1) y rellena justo lo que aquí se deje
   sin declarar (INSTRUCCIONES.md §3.1). */

.gsc .gsc__seg-op:hover,
.gsc .gsc__seg-op:focus {
	background: var(--gsc-hueso);
	color: var(--gsc-tinta);
}

/* La elegida no debe reaccionar al ratón: ya está en negro, y teñirla de hueso al
   pasar por encima haría dudar de si sigue elegida. */

.gsc .gsc__seg-op:has(.gsc__radio:checked):hover,
.gsc .gsc__seg-op:has(.gsc__radio:checked):focus {
	background: var(--gsc-tinta);
	color: #fff;
}

/* ── La sucursal donde se recoge ──────────────────────────────────────────────
   Ocupa el hueco que dejan los campos de dirección al elegir «Tienda», y por eso reusa la
   caja de `.gsc__resumen`: misma familia visual que el resto del paso, sin estrenar una
   tarjeta nueva. El JS la muestra y la esconde por `data-gsc-solo`, igual que a los campos.

   La regla `[hidden]` es explícita a propósito. La hoja del navegador ya trae
   `[hidden] { display: none }`, pero cualquier declaración de autor sobre este nodo le
   ganaría, y entonces la tarjeta se vería también a domicilio. Es el mismo motivo por el que
   `.gsc__campo[hidden]` existe (línea 1006). */

.gsc__tienda {
	margin-top: 22px;
	padding: 20px;
	/* Blanca y con el borde en oro: sobre el fondo hueso del paso, el blanco la separa sola y
	   el filete dorado la señala sin necesidad de rellenarla de color. */
	border: 1px solid var(--gsc-oro);
	border-radius: var(--gs-r-md, 8px);
	background: #fff;
}

.gsc__tienda[hidden] {
	display: none;
}

.gsc__tienda-h {
	margin-bottom: 12px;
}

/* El nombre en la tipografía de interfaz, como los títulos del segmentado: es un rótulo,
   no prosa. */
.gsc__tienda-nombre {
	margin: 0 0 8px;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 1rem;
	line-height: 1.35;
	color: var(--gsc-tinta);
}

/* La dirección SÍ es prosa y va en la de texto. `flex` y no un `inline` suelto para que las
   direcciones que ocupan dos líneas sangren bajo sí mismas y no bajo el pin. */
.gsc__tienda-dir {
	display: flex;
	align-items: flex-start;
	gap: 8px;
	margin: 0;
	font-family: var(--gs-font-body, 'Inter', system-ui, sans-serif);
	font-size: 0.9375rem;
	line-height: 1.5;
	color: var(--gsc-tinta);
}

.gsc__tienda-pin {
	display: inline-flex;
	flex: 0 0 auto;
	width: 17px;
	height: 17px;
	margin-top: 2px;
	color: var(--gsc-oro);
}

.gsc__tienda-pin svg {
	width: 100%;
	height: 100%;
	display: block;
}

/* Mismo botón que el de la ficha de pago del acuse: es la misma clase de acción —abrir algo
   fuera— y merecía leerse igual. */
.gsc__tienda-mapa {
	display: inline-flex;
	align-items: center;
	gap: 9px;
	margin-top: 16px;
	min-height: 44px;
	padding: 0 20px;
	border: 0;
	border-radius: var(--gs-r-md, 8px);
	background: var(--gsc-tinta);
	color: #fff;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 0.75rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	text-decoration: none;
	transition: background .2s var(--gs-e-soft, ease);
}

.gsc__tienda-ext {
	width: 14px;
	height: 14px;
	flex: 0 0 auto;
}

/* (0,3,0) y declarando FONDO Y COLOR, con los tres estados juntos: el Global Kit emite
   `a:hover` a (0,2,1) y rellenaría justo el que dejáramos sin declarar. */
.gsc .gsc__tienda-mapa:hover,
.gsc .gsc__tienda-mapa:focus,
.gsc .gsc__tienda-mapa:focus-visible {
	background: var(--gsc-tinta-h);
	color: #fff;
}

/* El fragmento de tarifas también recibe `hidden` desde el JS y no tenía regla propia:
   funcionaba por la hoja del navegador, o sea por accidente. */
.gsc-frg-envio[hidden] {
	display: none;
}

/* ── Método de pago: FILAS de un solo grupo ───────────────────────────────────
   Cuatro opciones son demasiadas para un segmentado y eran cuatro tarjetas en una
   rejilla de dos columnas. Como filas de una única caja se leen en vertical, que es
   como se comparan cuatro cosas, y vuelve a haber un solo borde en pantalla.

   Se llamaba `.gsc__filas`, y ese nombre YA ESTABA COGIDO por la lista de importes
   (línea 672). Misma especificidad (0,1,0), así que ganaba esta por orden y le metía
   al `<dl>` de Subtotal/Envío un `border` completo —el shorthand borra el
   `border-bottom` de allí—, fondo blanco y radio, conservando su `padding: 0 0 20px`:
   cero arriba y cero a los lados. El texto tocaba el borde por tres caras.
   El nombre nuevo es `.gsc__opciones` porque este es el componente más joven y el más
   estrecho: «elige una de estas», que es lo que son las pasarelas y las tarifas de
   envío. La lista de importes se queda con `.gsc__filas`, que es lo que siempre fue. */

.gsc__opciones {
	border: 1px solid var(--gsc-linea);
	border-radius: var(--gs-r-md, 8px);
	background: #fff;
	overflow: hidden;
}

.gsc__fila-op {
	position: relative;
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 13px 16px;
	cursor: pointer;
	transition: background .18s var(--gs-e-soft, ease);
}

.gsc__fila-op + .gsc__fila-op {
	border-top: 1px solid var(--gsc-linea);
}

.gsc__fila-tit {
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 600;
	font-size: 0.875rem;
	color: var(--gsc-tinta);
}

.gsc__fila-nota {
	margin-left: auto;
	font-style: normal;
	font-size: 0.8125rem;
	color: var(--gsc-gris);
	text-align: right;
}

.gsc__fila-op:has(.gsc__radio:checked) {
	background: var(--gsc-oro-pale);
}

.gsc__fila-op:has(.gsc__radio:focus-visible) .gsc__marca {
	box-shadow: 0 0 0 3px var(--gs-oro-halo, rgba(156, 122, 52, .2));
}

.gsc .gsc__fila-op:hover,
.gsc .gsc__fila-op:focus {
	background: var(--gsc-hueso);
	color: var(--gsc-tinta);
}

.gsc .gsc__fila-op:has(.gsc__radio:checked):hover,
.gsc .gsc__fila-op:has(.gsc__radio:checked):focus {
	background: var(--gsc-oro-pale);
	color: var(--gsc-tinta);
}

/* El <input> real se mantiene en el DOM y solo se oculta visualmente: así la
   semántica de teclado (flechas entre opciones del grupo) sale gratis y correcta, que
   es lo que pide INSTRUCCIONES.md §6. Nada de `display: none`, que lo sacaría del
   foco. Lo comparten el segmentado y las filas. */

.gsc__radio {
	position: absolute;
	width: 1px;
	height: 1px;
	opacity: 0;
	margin: 0;
	pointer-events: none;
}

.gsc__marca {
	flex: 0 0 18px;
	width: 18px;
	height: 18px;
	border-radius: var(--gs-r-pill, 999px);
	border: 1.5px solid var(--gsc-linea);
	background: #fff;
	display: grid;
	place-items: center;
	transition: border-color .18s var(--gs-e-soft, ease);
}

.gsc__marca::after {
	content: '';
	width: 9px;
	height: 9px;
	border-radius: var(--gs-r-pill, 999px);
	background: var(--gsc-oro);
	transform: scale(0);
	transition: transform .18s var(--gs-e-out, ease);
}

.gsc__fila-op:has(.gsc__radio:checked) .gsc__marca {
	border-color: var(--gsc-oro);
}

.gsc__fila-op:has(.gsc__radio:checked) .gsc__marca::after {
	transform: scale(1);
}

/* ── Envío ────────────────────────────────────────────────────────────────────
   Las tarifas reales de las zonas de WooCommerce. Reutiliza `.gsc__opciones`, que es
   el mismo control que las formas de pago: son la misma pregunta —«elige una de
   estas»— y darles dos aspectos distintos solo obligaría a aprender dos. */

.gsc__envio {
	margin-top: 22px;
}

.gsc-frg-envio.is-cargando {
	opacity: .5;
	pointer-events: none;
	transition: opacity .18s var(--gs-e-soft, ease);
}

/* ── Pasarelas ────────────────────────────────────────────────────────────────
   Cada pasarela es una fila que puede traer su propio formulario debajo. */

/* El separador, solo entre pasarelas VISIBLES. Era `.gsc__pasarela + .gsc__pasarela`, y con
   una plegada en medio la raya quedaba suelta —encima de la primera visible, o doble—. Así
   cada visible que tiene otra visible antes lleva su raya, y la primera no. */

.gsc__pasarela:not(.is-fuera) ~ .gsc__pasarela:not(.is-fuera) {
	border-top: 1px solid var(--gsc-linea);
}

/* Una pasarela que no vale con la entrega elegida (contra entrega solo al recoger, por
   ejemplo). Plegada y NO con `display: none`: la pasarela mide sus campos al montar su SDK, y
   sin caja mide cero. `visibility` la saca del tabulador y del lector de pantalla. La conmuta
   `ajustarPasarelas()` en checkout.js. */

.gsc .gsc__pasarela.is-fuera {
	height: 0;
	overflow: hidden;
	visibility: hidden;
}

.gsc__fila-ico {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	margin-left: 10px;
}

/* Los iconos los emite la pasarela y vienen con el tamaño que ella decida: sin
   tope, un logo de 200px rompe la fila. `max-height` y no `height` para no
   estirar los pequeños. */

.gsc__fila-ico img {
	display: block;
	max-height: 22px;
	width: auto;
	max-width: 60px;
}

.gsc__fila-op:has(.gsc__radio:checked) {
	background: var(--gsc-oro-pale);
}

/* El formulario propio de la pasarela: en el DOM siempre, visible solo el de la
   elegida.

   Se conmuta con altura y no con `display: none` a propósito. Varias pasarelas
   —Mercado Pago entre ellas— montan su SDK sobre estos nodos al cargar la página
   y necesitan que existan y que se puedan medir; un `display: none` les da altura
   cero al inicializar y el formulario nace roto. */

.gsc__pasarela-campos {
	display: grid;
	grid-template-rows: minmax(0, 0fr);
	visibility: hidden;
	transition:
		grid-template-rows .17s var(--gs-e-quint, ease),
		visibility 0s linear .17s;
}

.gsc__pasarela.is-elegida .gsc__pasarela-campos {
	grid-template-rows: minmax(0, 1fr);
	visibility: visible;
	transition: grid-template-rows .22s var(--gs-e-quint, ease);
}

/* El hijo que recorta. `min-height: 0` es obligatorio o la pista nunca encoge. */

.gsc__pasarela-campos > * {
	overflow: hidden;
	min-height: 0;
	padding: 0 16px 16px;
	font-size: 0.875rem;
	line-height: 1.55;
	color: var(--gs-txt-2, #555);
}

/* Lo que pinte la pasarela dentro es HTML ajeno: se le da el aspecto de los campos
   de este formulario para que no parezca pegado de otra web, pero sin tocar su
   estructura, que es suya. */

.gsc .gsc__pasarela-campos input[type="text"],
.gsc .gsc__pasarela-campos input[type="tel"],
.gsc .gsc__pasarela-campos input[type="email"],
.gsc .gsc__pasarela-campos input[type="number"],
.gsc .gsc__pasarela-campos select {
	width: 100%;
	padding: 11px 13px;
	border: 1px solid var(--gsc-linea);
	border-radius: var(--gs-r-md, 8px);
	background: #fff;
	font-family: inherit;
	font-size: 0.9375rem;
	color: var(--gsc-tinta);
}

/* Aviso cuando no hay ninguna forma de pago. No es un error del cliente, así que
   va en el gris de apoyo y no en el rojo de fallo. */

.gsc__aviso {
	margin: 0;
	padding: 14px 16px;
	border: 1px solid var(--gsc-linea);
	border-radius: var(--gs-r-md, 8px);
	background: var(--gsc-hueso);
	color: var(--gs-txt-2, #555);
	font-size: 0.875rem;
	line-height: 1.5;
}

.gsc__filas--mini {
	margin-top: 14px;
}

/* Aviso al pie de un campo o de una sección. Texto de apoyo, no un importe ni una
   promesa. */

.gsc__pista {
	margin: 14px 0 0;
	font-size: 0.8125rem;
	line-height: 1.5;
	color: var(--gs-txt-2, #555);
}

.gsc__error {
	margin: 20px 0 0;
	padding: 12px 16px;
	border-radius: var(--gs-r-md, 8px);
	background: var(--gs-rojo-bg, #FBEFEE);
	color: var(--gs-rojo, #B23B32);
	font-size: 0.875rem;
}

.gsc__error[hidden] {
	display: none;
}

.gsc__botones {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	gap: 16px;
	margin-top: 24px;
}

/* La botonera de un paso intermedio no es la del acuse. Aquí «Continuar» no debe
   estirarse a todo el ancho: es un paso intermedio, no el final del recorrido, y un
   botón enorme en cada uno de los cuatro anuncia cuatro veces un final que solo ocurre
   una. «Regresar» se va al otro extremo con `margin-right: auto`, que en el primer paso
   se queda solo y deja el CTA a la derecha igualmente.

   El modificador se llamaba `--sec`, de «sección», cuando el paso 2 era un acordeón.
   Las secciones ya no existen y el nombre habría quedado apuntando a algo que no está. */

.gsc__botones--paso {
	display: flex;
	flex-wrap: wrap;
	justify-content: flex-end;
	gap: 12px;
}

.gsc__botones--paso .gsc__volver {
	margin-right: auto;
}

/* (0,3,0) para ganarle al `width: 100%` de `.gsc button.gsc__cta`, que pesa (0,2,1). */

.gsc .gsc__botones--paso .gsc__cta {
	width: auto;
}

.gsc button.gsc__volver,
.gsc a.gsc__volver--a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 56px;
	padding: 0 32px;
	border: 1px solid var(--gsc-linea);
	border-radius: var(--gs-r-md, 8px);
	background: #fff;
	color: var(--gsc-gris);
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 0.75rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	text-decoration: none;
	cursor: pointer;
	transition: background .2s var(--gs-e-soft, ease), color .2s var(--gs-e-soft, ease), border-color .2s var(--gs-e-soft, ease);
}

.gsc button.gsc__volver:hover,
.gsc button.gsc__volver:focus-visible,
.gsc a.gsc__volver--a:hover,
.gsc a.gsc__volver--a:focus-visible,
.gsc button.gsc__volver:focus,
.gsc a.gsc__volver--a:focus {
	background: var(--gsc-hueso);
	color: var(--gsc-tinta);
	border-color: var(--gsc-oro-clr);
}

/* ── Paso 2: mini resumen ─────────────────────────────────────────────────── */

.gsc__mini {
	background: #fff;
	border: 1px solid var(--gsc-linea);
	border-radius: var(--gs-r-2xl, 16px);
	padding: 28px;
}

.gsc__mini-h {
	margin: 0 0 18px;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 0.6875rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--gsc-oro);
}

.gsc__mini-lista {
	margin: 0 0 20px;
	padding: 0 0 20px;
	border-bottom: 1px solid var(--gsc-linea);
	list-style: none;
	display: flex;
	flex-direction: column;
	gap: 12px;
}

.gsc__mini-fila {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 12px;
	font-size: 0.875rem;
}

.gsc__mini-nom {
	color: var(--gs-txt-2, #555);
	min-width: 0;
}

.gsc__mini-x {
	color: var(--gsc-gris);
	white-space: nowrap;
}

.gsc__mini-p {
	font-weight: 600;
	white-space: nowrap;
}

.gsc__total--mini {
	margin-bottom: 0;
}

.gsc__total--mini .gsc__total-n {
	font-size: 1.75rem;
}

/* ── Paso 3: gracias ──────────────────────────────────────────────────────── */

.gsc__gracias {
	max-width: 720px;
	margin-inline: auto;
	text-align: center;
}

.gsc__check {
	display: grid;
	place-items: center;
	width: 72px;
	height: 72px;
	margin: 0 auto 24px;
	border-radius: var(--gs-r-pill, 999px);
	background: #E7F3E9;
	color: var(--gsc-verde);
}

.gsc__check svg {
	width: 32px;
	height: 32px;
	display: block;
}

.gsc__h1 {
	margin: 0 0 14px;
	font-family: var(--gs-font-display, 'Archivo', sans-serif);
	font-weight: 700;
	font-size: 2.125rem;
	line-height: 1.15;
	text-transform: uppercase;
	letter-spacing: -0.01em;
}

.gsc__lead {
	margin: 0 auto 36px;
	max-width: 46ch;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--gsc-gris);
}

.gsc__meta {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: 20px;
	text-align: left;
	padding: 22px 26px;
	background: #fff;
	border: 1px solid var(--gsc-linea);
	border-radius: var(--gs-r-xl, 14px);
	margin-bottom: 16px;
}

.gsc__meta-c {
	min-width: 0;
}

.gsc__meta-k {
	display: block;
	margin-bottom: 6px;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 600;
	font-size: 0.5625rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--gsc-gris);
}

.gsc__meta-v {
	display: block;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 0.875rem;
	color: var(--gsc-tinta);
	word-break: break-word;
}

/* ── La ficha de pago de la pasarela ──────────────────────────────────────────
   Misma tarjeta que `.gsc__detalle`, con un filete de oro arriba: es lo único de esta
   pantalla que el cliente tiene que HACER, y va antes que el resumen por eso.

   Dentro conviven dos cosas de dueños distintos: lo nuestro (`.gsc__ficha-h`, `-lead`,
   `-cta`) y lo que pinta la pasarela (`.gsc__ficha-pasarela`), que llega con su markup, sus
   clases genéricas y sus estilos EN LÍNEA. Todo lo que hay aquí para domarlo va acotado a
   `.gsc__ficha-pasarela` y no sale de esta tarjeta. */

.gsc__ficha {
	text-align: left;
	padding: 26px;
	background: #fff;
	border: 1px solid var(--gsc-linea);
	border-top: 3px solid var(--gsc-oro);
	border-radius: var(--gs-r-xl, 14px);
	margin-bottom: 16px;

	/* Alto del marco del comprobante. En variable porque la reescribe el móvil, y en
	   `clamp` porque un ticket es un documento vertical: por debajo de ~420px se lee a
	   trozos, y por encima de 700 se come la pantalla entera. */
	--gsc-ficha-alto: clamp(420px, 72vh, 700px);
}

.gsc__ficha-h {
	margin: 0 0 10px;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 0.6875rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--gsc-oro);
}

.gsc__ficha-lead {
	margin: 0 0 18px;
	font-size: 0.9375rem;
	line-height: 1.55;
	color: var(--gsc-tinta);
}

/* Va al final de la tarjeta, donde la pasarela ponía su «Print ticket». */
.gsc__ficha-acciones {
	margin: 18px 0 0;
}

/* Mismo botón que `.gsc__cta--a` pero al ancho de su texto: aquí no es el CTA de un paso,
   es una acción dentro de una tarjeta. */
.gsc__ficha-cta {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	min-height: 48px;
	padding: 0 22px;
	border: 0;
	border-radius: var(--gs-r-md, 8px);
	background: var(--gsc-tinta);
	color: #fff;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 0.8125rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	text-decoration: none;
	transition: background .2s var(--gs-e-soft, ease);
}

.gsc__ficha-ext {
	width: 15px;
	height: 15px;
	flex: 0 0 auto;
}

.gsc .gsc__ficha-cta:hover,
.gsc .gsc__ficha-cta:focus,
.gsc .gsc__ficha-cta:focus-visible {
	background: var(--gsc-tinta-h);
	color: #fff;
}

.gsc__ficha-pasarela {
	display: grid;
	gap: 14px;
}

/* La plantilla de Mercado Pago anida `<p>` dentro de `<p>`; el navegador los cierra solos y
   deja párrafos vacíos con el margen del tema puesto. */
.gsc__ficha-pasarela p {
	margin: 0;
}

.gsc__ficha-pasarela p:empty {
	display: none;
}

/* El `height: 1000px` del marco viene EN LÍNEA en la plantilla de la pasarela
   (`woocommerce-mercadopago/templates/public/order/ticket-order-received.php`), y una
   declaración en línea gana a cualquier clase: `!important` es la ÚNICA forma de vencerla.
   Es el único de esta hoja, va sobre UNA propiedad y no sale de esta tarjeta. Si algún día
   la pasarela deja de escribir ese `style`, la regla sigue siendo correcta.
   El comprobante hace su propio scroll dentro del marco: es un documento de otro origen y
   ahí la barra interna es lo que se espera. */
.gsc .gsc__ficha-pasarela iframe {
	display: block;
	width: 100%;
	height: var(--gsc-ficha-alto) !important;
	border: 1px solid var(--gsc-linea);
	border-radius: var(--gs-r-md, 8px);
	background: #fff;
}

/* Con `--mudo` se apagan los enlaces de la pasarela: van al mismo sitio que nuestro botón, que
   está justo debajo. El modificador solo lo pone PHP cuando ese botón existe —ver
   `CheckoutRenderer::ficha()`—, así que sin él esta regla no casa con nada y el enlace ajeno
   sigue siendo la única salida, que es lo correcto.

   `display: none` y no una ocultación visual: no debe quedar en el orden de tabulación ni
   anunciarse, porque no es que esté escondido, es que sobra.

   Va a (0,3,1) —con `.gsc__ficha` delante— a propósito. La regla que viste esos mismos enlaces
   unas líneas más abajo es (0,2,1) y declara `display: inline-flex`: con la misma especificidad
   ganaría por orden de aparición, y esta regla dejaría de hacer nada en cuanto alguien moviera
   un bloque de sitio. Contando la especificidad, el orden deja de importar. */
.gsc .gsc__ficha .gsc__ficha-pasarela--mudo a {
	display: none;
}

/* Los enlaces que pinta la pasarela cuando NO hay botón propio. No se selecciona `.button` ni
   el `id` que pone Mercado Pago —serían selectores genéricos y un acoplamiento a su markup
   (INSTRUCCIONES §2)—: se viste TODO enlace que aparezca dentro de su bloque, que es lo que de
   verdad se quiere. */
.gsc .gsc__ficha-pasarela a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* El bloque de la pasarela es una rejilla y sus hijos se estiran a la columna entera:
	   sin esto el enlace sale a 665px al lado de nuestro botón de 275px, que es lo mismo
	   que decirle al cliente que el importante es el de la pasarela. */
	justify-self: start;
	min-height: 44px;
	padding: 0 20px;
	border: 1.5px solid var(--gsc-tinta);
	border-radius: var(--gs-r-md, 8px);
	background: transparent;
	color: var(--gsc-tinta);
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	text-decoration: none;
	transition: border-color .18s var(--gs-e-soft, ease), background-color .18s var(--gs-e-soft, ease), color .18s var(--gs-e-soft, ease);

	/* Las tres que la plantilla escribe en línea. Van enumeradas a propósito: cada una
	   corresponde a una declaración real y suya, así que el día que sobre una se borra.

	   El ancho sale de una VARIABLE y no de un valor fijo: `!important` gana también a las
	   reglas de móvil de más abajo, así que si aquí pusiera `auto` a secas el botón se
	   quedaría estrecho en un teléfono y no habría forma de reescribirlo. La variable entra
	   por herencia y deja que la cascada normal siga decidiendo (INSTRUCCIONES §3.3). */
	width: var(--gsc-ficha-btn-w, auto) !important;
	height: auto !important;
	font-size: 0.75rem !important;
}

/* 0,3,1: le gana al `.elementor-kit-N a:hover` (0,2,1) del Global Kit, que si no rellenaría
   justo la propiedad que dejáramos sin declarar. Fondo Y color, y los tres estados juntos
   porque `:focus-visible` no casa al pulsar con el ratón (INSTRUCCIONES §3.1). */
.gsc .gsc__ficha-pasarela a:hover,
.gsc .gsc__ficha-pasarela a:focus,
.gsc .gsc__ficha-pasarela a:focus-visible {
	border-color: var(--gsc-oro);
	background: transparent;
	color: var(--gsc-oro);
}

.gsc__detalle {
	text-align: left;
	padding: 26px;
	background: #fff;
	border: 1px solid var(--gsc-linea);
	border-radius: var(--gs-r-xl, 14px);
	margin-bottom: 16px;
}

.gsc__detalle-h {
	margin: 0 0 18px;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 0.6875rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

.gsc__detalle-lista {
	margin: 0 0 18px;
	padding: 0 0 18px;
	border-bottom: 1px solid var(--gsc-linea);
	list-style: none;
	display: flex;
	flex-direction: column;
	gap: 12px;
}

.gsc__detalle-fila {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 16px;
	font-size: 0.9375rem;
	color: #333;
}

.gsc__detalle-p {
	font-weight: 600;
	white-space: nowrap;
	color: var(--gsc-tinta);
}

.gsc__filas--fin {
	border-bottom: 0;
	margin-bottom: 12px;
	padding-bottom: 0;
}

/* Vive en el bloque del acuse por historia, pero NO es solo suya: el resumen del paso 1 usa la
   misma clase para el mismo hecho. Un único tratamiento del envío gratis en toda la compra. */

.gsc__fila--envio.is-gratis dt,
.gsc__fila--envio.is-gratis dd {
	color: var(--gsc-verde);
}

.gsc__fila--envio[hidden] {
	display: none;
}

.gsc__total--fin {
	margin-bottom: 0;
	padding-top: 14px;
	border-top: 1px solid var(--gsc-linea);
}

.gsc__entrega {
	text-align: left;
	padding: 24px 26px;
	background: var(--gsc-hueso);
	border-radius: var(--gs-r-xl, 14px);
	margin-bottom: 28px;
}

.gsc__entrega[hidden] {
	display: none;
}

.gsc__entrega-h {
	margin: 0 0 14px;
	font-family: var(--gs-font-ui, 'Montserrat', sans-serif);
	font-weight: 700;
	font-size: 0.6875rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--gsc-oro);
}

.gsc__entrega-l {
	margin: 0 0 6px;
	font-size: 0.9375rem;
	color: #333;
}

.gsc__entrega-l:empty {
	display: none;
}

.gsc__botones--fin {
	grid-template-columns: repeat(2, minmax(0, 1fr));
	margin-top: 0;
}

.gsc__botones--fin [hidden] {
	display: none;
}

/* Región de estado para lectores de pantalla. Fuera de la vista pero NO `display: none`,
   que la haría muda. */
.gsc__aria {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* ── Móvil ────────────────────────────────────────────────────────────────── */

@media (max-width: 1024px) {

	.gsc__grid {
		grid-template-columns: minmax(0, 1fr);
	}

	/* El resumen pasa DEBAJO de la lista y deja de ser pegajoso: en una sola columna,
	   `sticky` lo dejaría flotando sobre el contenido que le sigue. */
	.gsc__sticky {
		position: static;
	}

	.gsc__lado {
		order: 2;
	}

	/* 16px CLAVADOS en todo lo que se pueda enfocar, y no por gusto tipográfico: Safari en iOS
	   hace zoom automático sobre cualquier campo cuya letra baje de 16px, y NO deshace el zoom al
	   salir. El cliente se queda con la página ampliada y el resto del checkout fuera de pantalla,
	   teniendo que apartar con dos dedos en mitad de la compra. Medido: los siete campos salían a
	   15px y el contador a 14px, así que picaban todos.

	   Va en el corte de 1024 y no en el de 767 porque el iPad hace exactamente lo mismo y cae por
	   encima del corte de móvil. En escritorio la tipografía fina se queda como está. */

	.gsc .gsc__input,
	.gsc input.gsc__cupon-input,
	.gsc input.gsc__qty {
		font-size: 1rem;
	}
}

@media (max-width: 767px) {

	/* OJO con `--gsc-pad` aquí: esta regla es solo un respaldo y NO manda.
	   El control «Margen lateral» del widget escribe la misma variable con el selector que
	   emite Elementor —`.elementor-N .elementor-element-X .gsc`, que es (0,3,0)— y le gana a
	   este `.gsc` (0,1,0) sin despeinarse. Estuvo escrito aquí desde el principio y no llegó a
	   aplicarse nunca: medido en la tienda, el móvil calculaba 32px, no estos 16.

	   El truco de escribir variables en vez de propiedades (ver la cabecera de CheckoutWidget)
	   salva a las PROPIEDADES que las consumen, no a la variable misma. Así que el valor por
	   breakpoint tiene que salir del propio control, y por eso `padding_lat` lleva ahora
	   `tablet_default` y `mobile_default`. Esto se queda por si el widget se pinta sin el CSS
	   de Elementor delante. */

	.gsc {
		--gsc-pad: 16px;
		--gsc-gap: 20px;
	}

	/* El indicador se queda en una fila con los círculos y sin etiquetas: tres etiquetas en
	   mayúsculas no caben en 320px y partirlas en dos líneas descuadra la fila entera. El
	   nombre del paso sigue en el DOM para el lector de pantalla. */
	.gsc__paso-txt {
		position: absolute;
		width: 1px;
		height: 1px;
		margin: -1px;
		overflow: hidden;
		clip-path: inset(50%);
		white-space: nowrap;
	}

	.gsc__paso {
		gap: 0;
	}

	.gsc__paso:not(:last-child)::after {
		margin: 0 8px;
	}

	.gsc__pasos {
		margin-bottom: 28px;
	}

	/* La cabecera del carrito se parte en dos filas. En 390px no hay forma de que «Tu Carrito (2)»
	   y «+ Agregar más» quepan en la misma línea sin dejar el título en letra de nota al pie, y lo
	   que pasaba sin esto era lo peor de ambos mundos: los DOS se partían por la mitad, con un
	   «(2)» y un «MÁS» sueltos en su propia línea. Ahora el título ocupa su fila entera y el enlace
	   baja debajo, pegado a la derecha, que es donde el ojo ya lo busca. */

	.gsc__cab {
		flex-wrap: wrap;
		gap: 8px 12px;
	}

	.gsc__cab .gsc__h2 {
		flex: 1 1 100%;
	}

	.gsc__cab .gsc__mas {
		margin-left: auto;
		white-space: nowrap;
	}

	.gsc__h2 {
		font-size: 1.5rem;
	}

	.gsc__h1 {
		font-size: 1.625rem;
	}

	/* El total también envuelve. Medido en 320px: «TOTAL» (52px) más «$13,553.00» a 1.75rem
	   (~190px) más el hueco de 12 pedían 254px para 248 de tarjeta, y el importe se salía 18px.
	   Bajarle más el cuerpo sería castigar la cifra que más mira el cliente por un caso de
	   pantalla estrecha, así que se deja envolver: la etiqueta arriba y el número entero debajo.
	   Y se arregla solo para totales largos, que es cuando de verdad hace falta. */

	.gsc__total {
		flex-wrap: wrap;
	}

	.gsc__total-n {
		font-size: 1.75rem;
		min-width: 0;
	}

	/* La línea del carrito pasa a dos filas: foto + datos arriba, precio y controles abajo.
	   Con 90px de foto y el stepper en la misma fila no quedaban ni 120px para el nombre. */
	.gsc__linea {
		flex-wrap: wrap;
		gap: 14px;
		padding: 16px;
	}

	.gsc__foto {
		flex-basis: 72px;
		width: 72px;
		height: 72px;
	}

	/* `wrap` y no una segunda fila fija: en 390px esta fila pedía 304px (precio 90 + stepper 118
	   + «Eliminar» 72, más dos huecos de 12) para 259px de hueco real, y como ninguna de las tres
	   piezas encoge, «Eliminar» se salía 45px de la tarjeta y se veía cortado. Medido en pantalla.

	   Envolviendo, «Eliminar» baja solo cuando no cabe y el `margin-left: auto` de más abajo lo
	   pega a la derecha. La ventaja de dejarlo al flexbox y no partir la fila a mano es que se
	   arregla también con precios más largos: si un día precio + stepper tampoco caben, el
	   stepper baja por su cuenta en vez de desbordar otra vez. */

	.gsc__acciones {
		flex: 1 1 100%;
		flex-direction: row;
		flex-wrap: wrap;
		align-items: center;
		justify-content: space-between;
		gap: 12px;
		padding-top: 12px;
		border-top: 1px solid var(--gsc-linea);
	}

	.gsc__precio {
		font-size: 1.25rem;
		order: 1;
	}

	.gsc__stepper {
		order: 2;
	}

	/* `margin-left: auto` porque al bajar de fila se queda solo, y el `space-between` del padre
	   no separa nada cuando hay un único elemento: sin esto quedaría pegado a la izquierda,
	   justo debajo del precio, como si fuera parte de él. */

	.gsc button.gsc__quitar {
		order: 3;
		margin-left: auto;
	}

	.gsc__form .gsc__vista {
		padding: 18px;
	}

	.gsc__rev-b {
		padding: 14px 16px;
	}

	.gsc__campos {
		grid-template-columns: minmax(0, 1fr);
	}

	/* El segmentado se apila. En horizontal, dos columnas de 160px cortan las notas
	   («Envío a tu…») y la elección se hace justo por esa nota. */
	.gsc__seg {
		grid-template-columns: minmax(0, 1fr);
	}

	.gsc__seg-op + .gsc__seg-op {
		border-left: 0;
		border-top: 1px solid var(--gsc-linea);
	}

	/* La nota del método de pago baja bajo su título: alineada a la derecha en un
	   móvil, se pega al título y se leen como una sola frase. */
	.gsc__fila-op {
		flex-wrap: wrap;
	}

	.gsc__fila-nota {
		flex: 1 0 100%;
		margin-left: 29px;
		text-align: left;
	}

	.gsc__resumen,
	.gsc__mini {
		padding: 20px;
	}

	.gsc__meta {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		padding: 18px 20px;
	}

	/* El botón de mapa al ancho completo: su etiqueta en mayúsculas no cabe al lado de nada. */
	.gsc__tienda-mapa {
		width: 100%;
		justify-content: center;
	}

	.gsc__ficha {
		padding: 20px;
		/* En un teléfono el 72vh del escritorio deja el resto del acuse fuera de la
		   pantalla; con esto el comprobante sigue siendo legible y se ve que hay algo
		   debajo. */
		--gsc-ficha-alto: clamp(340px, 58vh, 520px);
		/* La consume la regla del enlace de la pasarela, que va con `!important` y no se
		   puede reescribir de otra forma. */
		--gsc-ficha-btn-w: 100%;
	}

	/* Los botones de la ficha al ancho completo: uno junto a otro no caben sin partir sus
	   etiquetas en mayúsculas. */
	.gsc__ficha-cta {
		width: 100%;
		justify-content: center;
	}

	.gsc .gsc__ficha-pasarela a {
		justify-self: stretch;
	}

	.gsc__botones,
	.gsc__botones--fin {
		grid-template-columns: minmax(0, 1fr);
	}

	/* La botonera de paso NO es grid —`--paso` la pasa a flex— así que la regla de
	   arriba nunca la tocó: `grid-template-columns` sobre un contenedor flex no hace
	   nada. Y a 390px el par no cabe en una línea («← Volver al carrito» del paso 2
	   mide ~230px con sus 64px de padding), de modo que el `flex-wrap` los repartía en
	   dos filas y cada uno se quedaba anclado a un extremo distinto: «Regresar» a la
	   izquierda por su `margin-right: auto`, «Continuar» a la derecha por el
	   `justify-content: flex-end`. Se apilan a todo el ancho.

	   En el ORDEN DEL DOM, no al revés: «Regresar» va primero en el markup, y ponerlo
	   debajo con `column-reverse` dejaría el recorrido del tabulador contradiciendo lo
	   que se ve. */

	.gsc__botones--paso {
		flex-direction: column;
	}

	.gsc__botones--paso .gsc__volver {
		margin-right: 0;
	}

	/* (0,3,0) para empatar con `.gsc .gsc__botones--paso .gsc__cta { width: auto }` y
	   ganarle por orden. Con (0,2,1) perdería y el CTA seguiría midiendo su texto. */

	.gsc .gsc__botones--paso .gsc__cta,
	.gsc .gsc__botones--paso .gsc__volver {
		width: 100%;
	}

	.gsc__cupon {
		padding: 16px;
	}

	.gsc__cupon-lbl {
		flex: 1 1 100%;
	}
}

/* ── Movimiento reducido ──────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {

	/* La entrada del paso se ANULA, no se acelera: un bloque entero deslizándose es justo
	   lo que molesta a quien pide menos movimiento. Las transiciones de color sí se
	   conservan acortadas, que no marean y ayudan a ver qué cambió. */
	.gsc__vista.is-visible {
		animation: none;
	}

	/* El plegado del formulario de la pasarela va con DOS entradas: `.is-elegida`
	   redeclara su propio `transition` con más especificidad (0,2,0 frente a 0,1,0), así
	   que sin nombrarlo aquí seguiría animando los 220ms enteros. */
	.gsc__pasarela-campos,
	.gsc__pasarela.is-elegida .gsc__pasarela-campos,
	.gsc button.gsc__cambiar,
	.gsc__seg-op,
	.gsc__fila-op,
	.gsc__linea,
	.gsc__marca,
	.gsc__marca::after,
	/* Estos dos suben con sus reglas base: si se quedaran en una clase suelta, el
	   `transition` de aquellas les ganaría y quien pide menos movimiento seguiría viéndolo. */
	.gsc .gsc__input,
	.gsc input.gsc__cupon-input,
	.gsc button.gsc__bola,
	.gsc button.gsc__cta,
	.gsc button.gsc__volver,
	.gsc button.gsc__cupon-btn,
	.gsc button.gsc__paso-btn,
	/* Los dos de la ficha. El de la pasarela va prefijado por `.gsc` para igualar la
	   especificidad de su regla base, que es 0,2,1. */
	.gsc__ficha-cta,
	.gsc .gsc__ficha-pasarela a,
	.gsc__tienda-mapa {
		transition-duration: .01ms;
	}
}

/* ---- producto-base.css ---- */
/**
 * GS Premium — base compartida de los widgets de la ficha de producto.
 * Handle 'gs-producto-base' (deps: gs-tokens, gs-fonts).
 *
 * Los 12 widgets de la categoría «GS Premium — Producto» envuelven su salida en `.gsp-p`
 * (más su clase de componente) y dependen de este archivo.
 *
 * DELIBERADAMENTE NO reutiliza 'gs-header-base'. Aquel archivo declara
 * `text-decoration: none !important` sobre todo <a>/<button>, y la ficha SÍ necesita
 * subrayados reales: el enlace auxiliar de los atributos («Guía de tallas»), los enlaces de
 * categoría del widget de meta y el «Ver todos» de relacionados. Heredarlo obligaría a
 * fingir cada subrayado con `border-bottom`, que es exactamente la deuda que ya arrastra el
 * header.
 *
 * ── La diferencia importante con header-base ─────────────────────────────────
 * El neutralizador de hover de header-base lleva una LISTA de 15 clases exentas dentro de
 * un `:not(...)`, y hay que ampliarla a mano cada vez que nace un componente con hover
 * propio. Con 12 widgets por delante eso se rompe el primer día que alguien lo olvide (y el
 * síntoma es el peor posible: un hover rosa del Global Kit en producción).
 *
 * Aquí se invierte: el neutralizador exime a `.gsp-i` («interactivo propio»), y es CADA
 * elemento el que se declara exento poniéndose la clase. Añadir un widget nuevo no toca
 * este archivo nunca.
 *
 *   CONTRATO para todo <a>/<button> con color o fondo propio:
 *     1) lleva la clase `gsp-i` además de su clase de componente, y
 *     2) declara sus TRES estados prefijados por la raíz (`.gsp-p .gsp-x:hover`, `:focus`,
 *        `:active`), que quedan en 0,3,0 y le ganan al Kit sin ningún !important.
 *   Cumplir solo (1) deja que el Kit le gane; cumplir solo (2) también, porque este
 *   neutralizador es 0,3,1 con !important y se lo comería.
 */

/* ── Caja y tipografía ───────────────────────────────────────────────────── */

.gsp-p,
.gsp-p * {
	box-sizing: border-box;
}

.gsp-p {
	font-family: var(--gs-font-body);
	color: var(--gs-tinta);
	-webkit-font-smoothing: antialiased;
}

/* ── Blindaje: artefactos que nunca queremos ─────────────────────────────────
   `text-decoration` NO entra en esta lista (ver cabecera). Tampoco `transform` a secas:
   se acota a hover/focus para no matar el :active propio de los botones. */

.gsp-p a,
.gsp-p button,
.gsp-p a:hover,
.gsp-p a:focus,
.gsp-p a:active,
.gsp-p button:hover,
.gsp-p button:focus,
.gsp-p button:active {
	box-shadow: none !important;
	filter: none !important;
	text-shadow: none !important;
}

.gsp-p a:hover:not(:active),
.gsp-p a:focus:not(:active),
.gsp-p button:hover:not(:active),
.gsp-p button:focus:not(:active) {
	transform: none !important;
}

/* ── Neutralizador del Global Kit ────────────────────────────────────────────
   El Kit emite `.elementor-kit-{ID} a:hover` y `... button:hover` con 0,2,1, y la clase
   `elementor-kit-{ID}` va en el <body>: portalear un nodo (el visor de la galería) tampoco
   libra de ella. Esta regla es 0,3,1 con !important y gana; los componentes exentos
   (`.gsp-i`) recuperan el mando con sus propias reglas de 0,3,0.

   Se declaran fondo Y color aunque solo se quiera uno: el que se deja sin declarar es
   justo el que el Kit rellena (INSTRUCCIONES.md §3.1). */

.gsp-p :is(a, button):not(.gsp-i):hover,
.gsp-p :is(a, button):not(.gsp-i):focus,
.gsp-p :is(a, button):not(.gsp-i):active {
	background-color: transparent !important;
	color: inherit !important;
}

/* Y NO hay un segundo neutralizador para los exentos.
 *
 * El header sí lo tiene, y aquí sería un error. Una regla como
 *   `.gsp-p :is(a,button).gsp-i:focus:not(:hover) { background: transparent !important }`
 * es 0,4,1 con !important, así que le gana también a los componentes propios: el botón
 * «Agregar al Carrito» (fondo negro, declarado en 0,2,0) se quedaría transparente en cuanto
 * alguien tabulara sobre él. En el header eso se parchea listando `.gs-iconbtn` y
 * `.gs-mc__cta` dentro del `:not()`, que es volver a la lista que este archivo evita.
 *
 * A cambio, el contrato de `.gsp-i` incluye los TRES estados: quien se declara exento se
 * ocupa de su :hover, su :focus y su :active. Sus reglas de 0,3,0 le ganan al Kit (0,2,1)
 * por su cuenta, sin necesidad de ningún !important. */

/* ── Botón nativo ────────────────────────────────────────────────────────────
   Reset a 0,1,1. Incluye `padding: 0` porque los temas (y WooCommerce) rellenan los
   <button> y eso descuadra los steppers y los CTA de alto fijo. La consecuencia, que ya
   costó un bug en el minicarrito: una clase suelta (0,1,0) NO le gana.

   Aquí no hace falta el truco de `button.clase` (0,2,1) que usa el header: la convención
   de esta familia es que TODA regla de componente va prefijada por `.gsp-p`, lo que da
   0,2,0 y ya gana. `padding` se declara con la clase, no con el elemento. */

.gsp-p button {
	margin: 0;
	padding: 0;
	min-width: 0;
	min-height: 0;
	border: 0;
	background: none;
	font: inherit;
	color: inherit;
	line-height: inherit;
	text-align: inherit;
	-webkit-appearance: none;
	appearance: none;
	cursor: pointer;
}

/* Los temas de bloques (el sitio de pruebas usa twentytwentyfive) estilan `input` con
   bordes y alturas propias; el campo de cantidad del stepper los necesita neutros. */

.gsp-p input[type="number"],
.gsp-p input[type="text"] {
	margin: 0;
	border-radius: 0;
	background: none;
	font: inherit;
	color: inherit;
	-webkit-appearance: none;
	appearance: none;
}

/* Spinners nativos fuera: el stepper trae sus propios − / +. */

.gsp-p input[type="number"]::-webkit-outer-spin-button,
.gsp-p input[type="number"]::-webkit-inner-spin-button {
	-webkit-appearance: none;
	margin: 0;
}

.gsp-p input[type="number"] {
	-moz-appearance: textfield;
	appearance: textfield;
}

/* ── Media ───────────────────────────────────────────────────────────────────
   No se fuerza `fill: none` en los SVG: mataría los de relleno (estrella, carrito, play).
   Cada SVG de trazo ya declara su propio fill="none" desde Support\Icons. */

.gsp-p svg {
	display: block;
	flex: 0 0 auto;
}

.gsp-p img {
	max-width: 100%;
	height: auto;
}

/* ── Foco accesible ─────────────────────────────────────────────────────────
   `border-radius: inherit` y no un valor fijo: con un valor propio esta regla (0,1,1)
   ganaría al radio del componente (0,2,0) y le cuadraría las esquinas al tabular. */

.gsp-p a:focus-visible,
.gsp-p button:focus-visible,
.gsp-p input:focus-visible,
.gsp-p [tabindex]:focus-visible {
	outline: 2px solid var(--gs-oro);
	outline-offset: 2px;
	border-radius: inherit;
}

/* Los radios se dibujan ocultos y el foco tiene que verse en su etiqueta: los swatches y
   las pastillas de atributo son <input type="radio"> visualmente escondidos para heredar
   gratis la semántica de teclado (INSTRUCCIONES.md §6). */

.gsp-p .gsp-radio {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

.gsp-p .gsp-radio:focus-visible + * {
	outline: 2px solid var(--gs-oro);
	outline-offset: 2px;
}

/* ── Utilidades ─────────────────────────────────────────────────────────────
   Se define aquí y no se da por hecha: la trae la mayoría de temas, pero no todos, y sin
   ella las etiquetas para lectores de pantalla se ven en pantalla. */

.gsp-p .screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
	word-wrap: normal;
}

/* Región de anuncios para lectores de pantalla (cambio de precio, resultado de añadir al
   carrito). Ocupa sitio cero pero DEBE seguir en el árbol de accesibilidad, así que nada
   de `display:none` ni `visibility:hidden`. */

.gsp-p .gsp-live {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
}

/* Aviso visible solo dentro del editor de Elementor (widget sin producto que mostrar). */

.gsp-p-aviso {
	padding: 12px 16px;
	border: 1px dashed var(--gs-linea);
	border-radius: var(--gs-r-lg);
	color: var(--gs-gris-2);
	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: 12px;
	line-height: 1.4;
}

/* ── Reduced motion (obligatorio; cada widget añade sus propios selectores) ── */

@media (prefers-reduced-motion: reduce) {
	.gsp-p *,
	.gsp-p *::before,
	.gsp-p *::after {
		transition-duration: .01ms !important;
		animation-duration: .01ms !important;
		animation-iteration-count: 1 !important;
	}
}

/* ---- producto-crumb.css ---- */
/**
 * GS Product Breadcrumb. Handle 'gs-producto-crumb' (dep: gs-producto-base).
 *
 * Prefijo `.gsp-crumb`. Los colores llegan como variables desde los controles de Elementor;
 * los valores que hay aquí son los de partida del diseño.
 *
 * Toda regla va prefijada por `.gsp-p` (la raíz de la familia), lo que da 0,2,0 y le gana a
 * los `.woocommerce ol` y `.entry-content a` con los que los temas estilan el contenido.
 */

.gsp-p.gsp-crumb {
	--gsp-crumb-link: var(--gs-txt-3);
	--gsp-crumb-link-hover: var(--gs-oro);
	--gsp-crumb-actual: var(--gs-tinta);
	--gsp-crumb-sep: var(--gs-sep);

	font-family: var(--gs-font-ui);
	font-size: 11px;
	font-weight: 500;
	line-height: 1.4;
	letter-spacing: .08em;
}

/* ── Lista ───────────────────────────────────────────────────────────────────
   Es un <ol> porque un breadcrumb es una lista ordenada: el orden ES la información. Aquí se
   le quitan los estilos de lista, que si no el tema pinta números y sangría. */

.gsp-p .gsp-crumb__list {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 8px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.gsp-p .gsp-crumb__item {
	display: flex;
	align-items: center;
	gap: 8px;
	margin: 0;
	padding: 0;
	list-style: none;
	/* Los temas de bloques suelen meter `::marker` incluso con list-style:none. */
	min-width: 0;
}

.gsp-p .gsp-crumb__item::marker,
.gsp-p .gsp-crumb__item::before {
	content: none;
}

/* ── Enlaces ─────────────────────────────────────────────────────────────────
   Llevan `.gsp-i` en el markup (quedan exentos del neutralizador de producto-base.css) y a
   cambio declaran sus TRES estados, cada uno prefijado por la raíz → 0,3,0, que le gana al
   `.elementor-kit-N a:hover` del Global Kit (0,2,1). Se declara fondo Y color en los tres: el
   que se deja sin declarar es justo el que el Kit rellena. */

.gsp-p .gsp-crumb__link {
	color: var(--gsp-crumb-link);
	background-color: transparent;
	text-decoration: none;
	transition: color .18s var(--gs-e-soft);
}

.gsp-p .gsp-crumb__link:hover,
.gsp-p .gsp-crumb__link:focus,
.gsp-p .gsp-crumb__link:active {
	color: var(--gsp-crumb-link-hover);
	background-color: transparent;
	text-decoration: none;
}

.gsp-p .gsp-crumb__actual {
	color: var(--gsp-crumb-actual);
	/* El nombre del producto puede ser largo; en móvil no debe romper la fila entera. */
	overflow-wrap: anywhere;
}

.gsp-p .gsp-crumb__sep {
	color: var(--gsp-crumb-sep);
	/* `flex: none` para que el separador no se comprima cuando el nombre del producto es
	   largo: sin esto la flecha se aplasta hasta desaparecer. */
	flex: 0 0 auto;
	user-select: none;
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
	.gsp-p .gsp-crumb__link {
		transition-duration: .01ms;
	}
}

/* ---- producto-cat.css ---- */
/**
 * GS Product Category. Handle 'gs-producto-cat' (dep: gs-producto-base).
 *
 * El eyebrow que corona la columna de datos: una línea corta en mayúsculas, dorada.
 *
 * Va SUELTO, con su propio margen inferior. No arma fila de dos columnas: en la v1 de la
 * especificación compartía renglón con un widget de valoración que la v2 eliminó, y montar
 * aquí una fila dejaría un hueco esperando algo que ya no existe.
 */

.gsp-p.gsp-cat {
	--gsp-cat-color: var(--gs-oro);
	--gsp-cat-hover: var(--gs-tinta);

	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: 10px;
	line-height: 1.4;
	letter-spacing: .2em;
	text-transform: uppercase;
	color: var(--gsp-cat-color);
	margin-bottom: 12px;
}

/* ── Enlace ──────────────────────────────────────────────────────────────────
   Lleva `.gsp-i` en el markup (exento del neutralizador de producto-base.css) y declara sus
   tres estados prefijados por la raíz → 0,3,0, que le gana al `.elementor-kit-N a:hover` del
   Global Kit (0,2,1). Fondo Y color en los tres: el que se deja sin declarar es el que el Kit
   rellena.

   Hereda el color en reposo en vez de repetirlo: así basta cambiar `--gsp-cat-color` desde el
   control para que el texto y el enlace vayan a una. */

.gsp-p .gsp-cat__link {
	color: inherit;
	background-color: transparent;
	text-decoration: none;
	transition: color .18s var(--gs-e-soft);
}

.gsp-p .gsp-cat__link:hover,
.gsp-p .gsp-cat__link:focus,
.gsp-p .gsp-cat__link:active {
	color: var(--gsp-cat-hover);
	background-color: transparent;
	text-decoration: none;
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
	.gsp-p .gsp-cat__link {
		transition-duration: .01ms;
	}
}

/* ---- producto-titulo.css ---- */
/**
 * GS Product Title. Handle 'gs-producto-titulo' (dep: gs-producto-base).
 *
 * El nombre del producto en Archivo 500, mayúsculas y 42px, bajando a 36 en tablet y 30 en
 * móvil. Los tres tamaños llegan como defaults responsive desde los controles; los de aquí son
 * el respaldo por si alguien borra el control de tipografía.
 *
 * El selector lleva la etiqueta además de las clases (`h1.gsp-title`, y su equivalente para el
 * resto) porque los temas estilan los encabezados con reglas agresivas —`.entry-content h1`,
 * `.woocommerce h1`— y una clase suelta no siempre gana.
 */

.gsp-p.gsp-title {
	--gsp-title-color: var(--gs-tinta);
	--gsp-title-hover: var(--gs-oro);

	font-family: var(--gs-font-display);
	font-weight: 500;
	font-size: 42px;
	line-height: 1.05;
	letter-spacing: -.01em;
	text-transform: uppercase;
	color: var(--gsp-title-color);
	margin: 0 0 10px;
	/* Los temas suelen dar padding a los encabezados dentro del contenido. */
	padding: 0;
	/* Un nombre largo sin espacios (un SKU, una referencia) desbordaría la columna. */
	overflow-wrap: break-word;
}

/* ── Enlace opcional ─────────────────────────────────────────────────────────
   Lleva `.gsp-i` en el markup y declara sus tres estados prefijados por la raíz (0,3,0), que
   le gana al Global Kit (0,2,1). Fondo Y color en los tres. */

.gsp-p .gsp-title__link {
	color: inherit;
	background-color: transparent;
	text-decoration: none;
	transition: color .18s var(--gs-e-soft);
}

.gsp-p .gsp-title__link:hover,
.gsp-p .gsp-title__link:focus,
.gsp-p .gsp-title__link:active {
	color: var(--gsp-title-hover);
	background-color: transparent;
	text-decoration: none;
}

/* ── Responsive ──────────────────────────────────────────────────────────────
   Los mismos cortes que los defaults responsive de los controles. Están aquí también para que
   el respaldo del párrafo de arriba no deje 42px en un móvil si el control se vacía. */

@media (max-width: 1200px) {
	.gsp-p.gsp-title {
		font-size: 36px;
	}
}

@media (max-width: 900px) {
	.gsp-p.gsp-title {
		font-size: 30px;
	}
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
	.gsp-p .gsp-title__link {
		transition-duration: .01ms;
	}
}

/* ---- producto-precio.css ---- */
/**
 * GS Product Price. Handle 'gs-producto-precio' (dep: gs-producto-base).
 *
 * Precio grande en Archivo, con el código de divisa, el importe tachado y el porcentaje de
 * descuento en la misma línea. En la v2 del diseño este widget cierra el bloque de precio con
 * su divisor inferior; hasta entonces lo ponía un widget de nota de IVA que se eliminó.
 */

.gsp-p.gsp-price {
	--gsp-price-color: var(--gs-tinta-precio);
	--gsp-price-cur: var(--gs-txt-5);
	--gsp-price-old: var(--gs-tachado);
	--gsp-price-off: var(--gs-oro);
	--gsp-price-note: var(--gs-txt-4);
	--gsp-price-line: var(--gs-linea);
	--gsp-price-gap: 24px;

	margin-top: 6px;
	margin-bottom: var(--gsp-price-gap);
}

/* El divisor cierra el bloque. Va por clase y no por control directo para que el padding
   inferior y el borde aparezcan y desaparezcan juntos: con el borde apagado, el padding solo
   dejaría un hueco inexplicable. */

.gsp-p.gsp-price.has-divider {
	padding-bottom: var(--gsp-price-gap);
	border-bottom: 1px solid var(--gsp-price-line);
}

/* ── Fila ────────────────────────────────────────────────────────────────────
   `baseline` y no `center`: el precio mide 34px y la divisa 11px, y alinearlos por el centro
   dejaría el código de moneda flotando a media altura del número en vez de asentado sobre su
   línea base. */

.gsp-p .gsp-price__row {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: 12px;
}

.gsp-p .gsp-price__now {
	font-family: var(--gs-font-display);
	font-weight: 600;
	font-size: 34px;
	line-height: 1;
	letter-spacing: -.01em;
	color: var(--gsp-price-color);
	/* Un rango («$450 – $620») no debe partirse en dos líneas por el guion. */
	white-space: nowrap;
}

.gsp-p .gsp-price__cur {
	font-family: var(--gs-font-body);
	font-weight: 500;
	font-size: 11px;
	line-height: 1;
	letter-spacing: .14em;
	color: var(--gsp-price-cur);
}

.gsp-p .gsp-price__old {
	font-family: var(--gs-font-body);
	font-weight: 400;
	font-size: 13px;
	line-height: 1;
	color: var(--gsp-price-old);
	text-decoration: line-through;
	white-space: nowrap;
}

.gsp-p .gsp-price__off {
	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: 10px;
	line-height: 1;
	letter-spacing: .08em;
	color: var(--gsp-price-off);
	white-space: nowrap;
}

.gsp-p .gsp-price__none {
	font-family: var(--gs-font-body);
	font-size: 15px;
	line-height: 1.4;
	color: var(--gsp-price-note);
}

.gsp-p .gsp-price__note {
	font-family: var(--gs-font-body);
	font-size: 12px;
	line-height: 1.5;
	letter-spacing: .01em;
	color: var(--gsp-price-note);
	margin: 10px 0 0;
	padding: 0;
}

/* `hidden` necesita ayuda: los temas declaran `span { display: inline-block }` y esa regla gana
   al comportamiento por defecto del atributo, con lo que un tachado vacío seguiría ocupando su
   hueco en el `gap` de la fila. */

.gsp-p .gsp-price__old[hidden],
.gsp-p .gsp-price__off[hidden] {
	display: none;
}

/* ── Móvil ───────────────────────────────────────────────────────────────── */

@media (max-width: 560px) {
	.gsp-p .gsp-price__now {
		font-size: 28px;
	}

	.gsp-p .gsp-price__row {
		gap: 8px;
	}
}

/* ---- producto-badges.css ---- */
/**
 * GS Product Trust Badges. Handle 'gs-producto-badges' (dep: gs-producto-base).
 *
 * Línea de garantías: ícono + texto, separados por divisores verticales.
 */

.gsp-p.gsp-trust {
	--gsp-trust-txt: var(--gs-txt-3);
	--gsp-trust-ico: var(--gs-oro);
	--gsp-trust-ico-tam: 12px;
	--gsp-trust-sep: var(--gs-linea);
	--gsp-trust-gap: 10px;
	--gsp-trust-pad: 24px;

	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--gsp-trust-gap);

	font-family: var(--gs-font-body);
	font-weight: 400;
	font-size: 11.5px;
	line-height: 1.4;
	color: var(--gsp-trust-txt);

	margin-bottom: var(--gsp-trust-pad);
}

.gsp-p.gsp-trust.has-divider {
	padding-bottom: var(--gsp-trust-pad);
	border-bottom: 1px solid var(--gsp-trust-sep);
}

/* ── Item ────────────────────────────────────────────────────────────────── */

.gsp-p .gsp-trust__item {
	display: flex;
	align-items: center;
	gap: 6px;
	color: inherit;
	background-color: transparent;
	text-decoration: none;
}

/* Solo los items ENLAZADOS tienen hover, y llevan `.gsp-i` en el markup para quedar exentos del
   neutralizador de producto-base.css. Se declaran los tres estados prefijados por la raíz
   (0,3,0) con fondo Y color, que es lo que gana al Global Kit. */

.gsp-p a.gsp-trust__item:hover,
.gsp-p a.gsp-trust__item:focus,
.gsp-p a.gsp-trust__item:active {
	color: var(--gsp-trust-ico);
	background-color: transparent;
	text-decoration: none;
}

/* ── Ícono ───────────────────────────────────────────────────────────────────
   Se dimensionan `svg` e `i` por separado: el control de Elementor admite librerías de fuente y
   en ese caso emite un <i>, al que `width`/`height` no le hacen nada. */

.gsp-p .gsp-trust__ico {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	color: var(--gsp-trust-ico);
}

.gsp-p .gsp-trust__ico svg {
	width: var(--gsp-trust-ico-tam);
	height: var(--gsp-trust-ico-tam);
	display: block;
}

.gsp-p .gsp-trust__ico i {
	font-size: var(--gsp-trust-ico-tam);
	line-height: 1;
	color: inherit;
}

/* ── Divisor ─────────────────────────────────────────────────────────────────
   Un <span> con `align-self: stretch` y NO un `border-left` en el item siguiente. El borde se
   dibuja a la altura de su propia caja; el span estirado toma la altura real de la fila, que es
   lo que hace que el divisor case con el texto tenga el tamaño que tenga.

   `flex: 0 0 1px` además de `width`: sin fijar el `flex-basis`, un contenedor estrecho comprime
   el divisor hasta hacerlo desaparecer. */

.gsp-p .gsp-trust__sep {
	width: 1px;
	flex: 0 0 1px;
	align-self: stretch;
	/* Mínimo para que se vea aunque la fila colapse a la altura del texto. */
	min-height: 1em;
	background-color: var(--gsp-trust-sep);
}

/* En una fila que ha hecho wrap, un divisor al principio de la línea nueva queda huérfano. No se
   puede detectar el salto por CSS, así que en móvil se ocultan todos: con los items apilados el
   divisor vertical no aporta nada. */

@media (max-width: 480px) {
	.gsp-p .gsp-trust__sep {
		display: none;
	}
}

/* ---- producto-meta.css ---- */
/**
 * GS Product Meta. Handle 'gs-producto-meta' (dep: gs-producto-base).
 *
 * SKU, categorías y disponibilidad, una línea cada uno. La etiqueta en un gris más oscuro que
 * el valor, y la disponibilidad con color según el estado real del inventario.
 */

.gsp-p.gsp-meta {
	--gsp-meta-label: var(--gs-txt-2);
	--gsp-meta-value: var(--gs-txt-3);
	--gsp-meta-link: var(--gs-oro);
	--gsp-meta-alto: var(--gs-verde);
	--gsp-meta-bajo: var(--gs-ambar);
	--gsp-meta-agotado: var(--gs-agotado);

	display: flex;
	flex-direction: column;
	gap: 8px;

	font-family: var(--gs-font-body);
	font-weight: 400;
	font-size: 12px;
	line-height: 1.5;
	color: var(--gsp-meta-value);
}

/* ── Fila ────────────────────────────────────────────────────────────────────
   `flex-wrap` para que un producto con muchas categorías baje de línea en vez de desbordar la
   columna, y `gap` en vez de un espacio en el markup para no depender de espacios en blanco. */

.gsp-p .gsp-meta__row {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: 5px;
}

/* La compañera de `[hidden]`, que faltaba. `producto-meta.js` esconde así la fila del SKU cuando
   una variación no tiene uno propio, y el `[hidden]` de la hoja de usuario es (0,1,0): pierde
   contra el `display: flex` de arriba, que es (0,2,0). Hoy la rama que lo pone es difícil de
   alcanzar —con `hide_empty` apagado el SKU cae a «—» y nunca queda vacío—, así que el arreglo
   es preventivo; pero es exactamente la trampa de INSTRUCCIONES.md §3.2 y el resto de hojas de
   producto ya llevan su regla. */

.gsp-p .gsp-meta__row[hidden] {
	display: none;
}

.gsp-p .gsp-meta__label {
	color: var(--gsp-meta-label);
	font-weight: 500;
	/* La etiqueta nunca se parte: «Disponibilidad:» debe quedar entera. */
	flex: 0 0 auto;
}

.gsp-p .gsp-meta__val {
	color: var(--gsp-meta-value);
	overflow-wrap: anywhere;
}

/* Estados de disponibilidad. Van sobre `.gsp-meta__val` con doble clase, así que ganan a la
   regla de color de arriba sin necesidad de !important. */

.gsp-p .gsp-meta__val.is-alto {
	color: var(--gsp-meta-alto);
	font-weight: 500;
}

.gsp-p .gsp-meta__val.is-bajo {
	color: var(--gsp-meta-bajo);
	font-weight: 500;
}

.gsp-p .gsp-meta__val.is-agotado {
	color: var(--gsp-meta-agotado);
	font-weight: 500;
}

/* ── Enlaces de categoría ────────────────────────────────────────────────────
   Llevan `.gsp-i` en el markup y declaran los tres estados prefijados por la raíz (0,3,0), con
   fondo Y color, que es lo que le gana al Global Kit (0,2,1).

   El subrayado en hover es un `text-decoration` de verdad, no un `border-bottom` fingido: por
   esto la familia de producto NO hereda de `gs-header-base`, cuyo
   `text-decoration: none !important` lo haría imposible. */

.gsp-p .gsp-meta__link {
	color: var(--gsp-meta-link);
	background-color: transparent;
	text-decoration: none;
	transition: color .18s var(--gs-e-soft);
}

.gsp-p .gsp-meta__link:hover,
.gsp-p .gsp-meta__link:focus,
.gsp-p .gsp-meta__link:active {
	color: var(--gsp-meta-link);
	background-color: transparent;
	text-decoration: underline;
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
	.gsp-p .gsp-meta__link {
		transition-duration: .01ms;
	}
}

/* ---- producto-galeria.css ---- */
/**
 * GS Product Gallery. Handle 'gs-producto-galeria' (dep: gs-producto-base).
 *
 * Rail vertical de miniaturas a la izquierda e imagen principal grande a la derecha.
 */

/* Blindaje de ancho. TODO el CSS de este widget es porcentual —la imagen es `width:100%`—, así que
   no tiene ancho intrínseco. Dentro de un contenedor de Elementor en `flex-direction: row` el
   widget es un ítem flexible con `flex-grow: 0`, su ancho se calcula por contenido y resuelve a
   CERO: contenedor de 500px, widget de 0px, imagen cargada y en el DOM pero invisible, sin error
   ni hueco que delate el motivo. Los demás widgets de la ficha llevan texto y sobreviven; este no.
   El `min-width` de la principal es el suelo por si aun así queda sin ancho: mejor descuadrado y
   visible que perfecto e invisible. */

.elementor-widget-gs_product_gallery {
	width: 100%;
}

.gsp-p.gsp-gal {
	--gsp-gal-alto: 560px;
	--gsp-gal-radio: 8px;
	--gsp-gal-bg: var(--gs-hueso);
	--gsp-gal-fit: cover;
	--gsp-gal-rail: 78px;
	--gsp-gal-thumb-gap: 8px;
	--gsp-gal-activo: var(--gs-oro);
	--gsp-gal-thumb-on: var(--gs-hueso-2);
	--gsp-gal-sticky: 100px;

	display: grid;
	gap: 12px;
	align-items: start;
}

/* Rail a la izquierda: dos columnas. */

.gsp-p.gsp-gal.has-rail.is-left {
	grid-template-columns: var(--gsp-gal-rail) 1fr;
}

/* Rail debajo: una columna, y el rail pasa a fila con las miniaturas repartidas. */

.gsp-p.gsp-gal.has-rail.is-bottom {
	grid-template-columns: 1fr;
}

.gsp-p.gsp-gal.has-rail.is-bottom .gsp-gal__rail {
	flex-direction: row;
	order: 2;
}

/* Sticky. Se apaga por debajo de 900px: en un móvil fijar la galería dejaría el precio y los
   botones fuera de la pantalla. */

@media (min-width: 901px) {
	.gsp-p.gsp-gal.is-sticky {
		position: sticky;
		top: var(--gsp-gal-sticky);
	}
}

/* ── Rail ────────────────────────────────────────────────────────────────── */

.gsp-p .gsp-gal__rail {
	display: flex;
	flex-direction: column;
	gap: var(--gsp-gal-thumb-gap);
}

/* `button.gsp-gal__thumb` con la etiqueta: el reset de producto-base.css es 0,1,1 y le quita el
   padding y el fondo a todo <button>; una clase suelta (0,1,0) no lo recupera. */

.gsp-p button.gsp-gal__thumb {
	position: relative;
	aspect-ratio: 1;
	width: 100%;
	padding: 0;
	border: 0;
	border-radius: 6px;
	overflow: hidden;
	cursor: pointer;
	background-color: var(--gsp-gal-bg);
	/* El anillo se dibuja con `box-shadow` interior y NO con `border`: un borde suma a la caja y
	   al activarse movería la miniatura y, con ella, toda la columna. */
	box-shadow: inset 0 0 0 1px transparent;
	transition: box-shadow .18s var(--gs-e-soft), background-color .18s var(--gs-e-soft);
}

.gsp-p .gsp-gal__thumb img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.gsp-p button.gsp-gal__thumb:hover,
.gsp-p button.gsp-gal__thumb:focus {
	box-shadow: inset 0 0 0 1.5px var(--gs-oro-clr);
	background-color: var(--gsp-gal-bg);
}

/* La activa se marca por `aria-selected`, que es el estado REAL del tab: así el atributo de
   accesibilidad y el aspecto no pueden desincronizarse. */

.gsp-p button.gsp-gal__thumb[aria-selected="true"],
.gsp-p button.gsp-gal__thumb[aria-selected="true"]:hover,
.gsp-p button.gsp-gal__thumb[aria-selected="true"]:focus {
	box-shadow: inset 0 0 0 1.5px var(--gsp-gal-activo);
	background-color: var(--gsp-gal-thumb-on);
}

/* ── Principal ───────────────────────────────────────────────────────────── */

.gsp-p .gsp-gal__main {
	position: relative;
	min-width: 180px;
	height: var(--gsp-gal-alto);
	border-radius: var(--gsp-gal-radio);
	overflow: hidden;
	background-color: var(--gsp-gal-bg);
}

.gsp-p .gsp-gal__img {
	width: 100%;
	height: 100%;
	object-fit: var(--gsp-gal-fit);
	display: block;
	/* El origen se mueve con el cursor desde el JS. La transición SOLO está aquí, en reposo:
	   mientras el cursor se mueve el JS la quita, porque si no la imagen «arrastra» detrás del
	   puntero en vez de seguirlo. */
	transform: scale(1);
	transform-origin: 50% 50%;
	transition: transform .35s var(--gs-e-out), opacity .18s var(--gs-e-soft);
}

/* Cambio de imagen: se atenúa y vuelve. La clase la pone el JS un instante. */

.gsp-p .gsp-gal__img.is-cambiando {
	opacity: 0;
}

/* `.gsp-p.gsp-gal` y no `.gsp-p .gsp-gal`: las dos clases van en el MISMO elemento, así que el
   descendiente no casaba nunca y el cursor no se aplicaba. */

.gsp-p.gsp-gal.has-zoom .gsp-gal__main {
	cursor: zoom-in;
}

.gsp-p .gsp-gal__main.is-zoom {
	cursor: zoom-out;
}

/* En pantallas táctiles no hay cursor que seguir: el zoom hover se desactiva y el clic queda
   para el visor. */

@media (pointer: coarse) {
	.gsp-p.gsp-gal.has-zoom .gsp-gal__main,
	.gsp-p .gsp-gal__main.is-zoom {
		cursor: default;
	}
}

/* ── Flechas ─────────────────────────────────────────────────────────────── */

.gsp-p .gsp-gal__flechas {
	position: absolute;
	right: 20px;
	bottom: 20px;
	z-index: 2;
	display: flex;
	gap: 10px;
}

.gsp-p button.gsp-gal__flecha {
	width: 42px;
	height: 42px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	display: grid;
	place-items: center;
	background-color: #fff;
	color: var(--gs-tinta);
	cursor: pointer;
	box-shadow: 0 2px 10px rgba(10, 10, 10, .1);
	transition: background-color .18s var(--gs-e-soft), color .18s var(--gs-e-soft);
	user-select: none;
}

.gsp-p button.gsp-gal__flecha:hover,
.gsp-p button.gsp-gal__flecha:focus,
.gsp-p button.gsp-gal__flecha:active {
	background-color: var(--gs-tinta);
	color: #fff;
}

.gsp-p .gsp-gal__flecha svg {
	width: 16px;
	height: 16px;
}

/* ── Móvil ───────────────────────────────────────────────────────────────────
   El rail pasa debajo y en fila: una columna de miniaturas a la izquierda en una pantalla de
   360px dejaría la principal en poco más de 270. */

@media (max-width: 900px) {
	.gsp-p.gsp-gal.has-rail.is-left {
		grid-template-columns: 1fr;
	}

	.gsp-p.gsp-gal.has-rail .gsp-gal__rail {
		flex-direction: row;
		order: 2;
		/* Con muchas imágenes, la fila se desplaza en lugar de encogerlas hasta que no se vean. */
		overflow-x: auto;
		scrollbar-width: thin;
	}

	.gsp-p.gsp-gal.has-rail .gsp-gal__thumb {
		flex: 0 0 var(--gsp-gal-rail);
	}
}

/* ── Reduced motion ──────────────────────────────────────────────────────────
   Sin zoom ni transiciones: el zoom es un `transform` continuo siguiendo el cursor, que es justo
   lo que molesta a quien pide movimiento reducido. */

@media (prefers-reduced-motion: reduce) {
	.gsp-p .gsp-gal__img {
		transition-duration: .01ms;
		transform: none !important;
	}

	.gsp-p button.gsp-gal__thumb,
	.gsp-p button.gsp-gal__flecha {
		transition-duration: .01ms;
	}
}

/* ---- producto-attrs.css ---- */
/**
 * GS Product Attributes. Handle 'gs-producto-attrs' (dep: gs-producto-base).
 *
 * Cada opción es un `<input type="radio">` oculto (`.gsp-radio`, en producto-base.css) con su
 * `<label>` visible. El estado se dibuja con `:checked + label`, no con una clase que ponga el
 * JS: así el marcado sigue al radio de verdad y no hay dos fuentes de verdad que se puedan
 * desincronizar.
 *
 * Los estados de disponibilidad llegan como atributos `data-estado` desde el JS:
 *   disponible → normal
 *   agotado    → tachado y apagado, pero SIGUE siendo elegible (como en WooCommerce)
 *   imposible  → apagado; al pulsarlo el bus libera los atributos que estorban
 */

.gsp-p.gsp-attrs {
	--gsp-at-label: var(--gs-txt-2);
	--gsp-at-valor: var(--gs-oro);
	--gsp-at-aux: var(--gs-oro);
	--gsp-at-aux-ico: 14px;
	--gsp-at-activo: var(--gs-oro);
	--gsp-at-borde: var(--gs-linea);
	--gsp-at-pill-on: var(--gs-tinta);
	--gsp-at-swatch: 32px;
	--gsp-at-pill: 40px;
	--gsp-at-gap: 24px;
	/* Halo del círculo elegido. El respaldo es el token en oro; la regla de abajo lo sustituye
	   por una mezcla del color REAL del activo. Escrito a mano —que es como estaba—, cambiar
	   «Color del activo» en Elementor teñía el anillo y dejaba el halo dorado. */
	--gsp-at-halo: var(--gs-oro-halo);
}

/* Por qué `@supports` y no dos declaraciones seguidas: una propiedad personalizada NO se valida
   al parsear, así que un navegador sin `color-mix()` se traga la declaración igual y el fallo
   aparece más tarde, al sustituir `var(--gsp-at-halo)`. Ahí ya no se cae en la declaración
   anterior: la propiedad se queda en su valor inicial y el halo no se pinta. La puerta decide
   antes, que es el único momento en que se puede decidir.

   `producto-related.css` rechazó `color-mix()` en su día por eso mismo —«el borde desaparecería
   del todo, no se degradaría»—, y aquel razonamiento sigue siendo bueno. Aquí se puede usar
   porque ese modo de fallo está cerrado dos veces: la puerta deja el token estático y, aunque
   fallara, el anillo es un `border` aparte y sobrevive solo. */

@supports (color: color-mix(in srgb, red 20%, transparent)) {
	.gsp-p.gsp-attrs {
		--gsp-at-halo: color-mix(in srgb, var(--gsp-at-activo) 20%, transparent);
	}
}

/* ── Bloque ──────────────────────────────────────────────────────────────────
   20px entre bloques y 24 en el último, que es lo que pide el diseño para separar el grupo de
   atributos de los botones de compra. */

.gsp-p .gsp-attrs__bloque {
	margin-bottom: 20px;
}

.gsp-p .gsp-attrs__bloque:last-of-type {
	margin-bottom: var(--gsp-at-gap);
}

.gsp-p .gsp-attrs__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	margin-bottom: 12px;
}

.gsp-p .gsp-attrs__label {
	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: 11px;
	line-height: 1.4;
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--gsp-at-label);
}

.gsp-p .gsp-attrs__valor {
	font-family: var(--gs-font-body);
	font-size: 12px;
	line-height: 1.4;
	color: var(--gsp-at-valor);
	text-align: right;
}

/* ── Enlace auxiliar («Guía de tallas») ──────────────────────────────────────
   Ya no vive en la fila de la etiqueta: es una LÍNEA PROPIA bajo el selector, con el ícono a la
   izquierda del texto. De ahí que pase de texto en línea a caja flex, y de ahí que pierda el
   `white-space: nowrap` que tenía: arriba evitaba que partiera la cabecera en dos; aquí, en una
   columna estrecha, lo único que provocaría es desbordamiento horizontal.

   `width: fit-content` para que el área clicable sea la del texto y no la fila entera: un enlace
   con 600px de ancho invisible se pulsa sin querer.

   EL SUBRAYADO VA EN EL SPAN DEL TEXTO, NO EN EL <a>. `text-decoration` se PROPAGA a los
   descendientes y no se puede apagar desde dentro: declarado en el enlace, pintaría también una
   raya bajo el ícono.

   Es el caso concreto por el que esta familia no hereda de `gs-header-base`, cuyo
   `text-decoration: none !important` haría imposible cualquier subrayado real. Lleva `.gsp-i` en
   el markup y declara sus tres estados prefijados por la raíz (0,3,0) con fondo Y color —y aquí
   además `text-decoration`, porque el Kit también la emite en `a:hover` (0,2,1). */

.gsp-p .gsp-attrs__aux {
	display: flex;
	align-items: center;
	gap: 6px;
	width: fit-content;
	margin-top: 10px;
	font-family: var(--gs-font-body);
	font-size: 11px;
	line-height: 1.4;
	color: var(--gsp-at-aux);
	background-color: transparent;
	text-decoration: none;
}

.gsp-p .gsp-attrs__aux:hover,
.gsp-p .gsp-attrs__aux:focus,
.gsp-p .gsp-attrs__aux:active {
	color: var(--gs-tinta);
	background-color: transparent;
	text-decoration: none;
}

.gsp-p .gsp-attrs__aux-txt {
	text-decoration: underline;
}

/* Ícono. Se dimensionan `svg` e `i` por separado: el control ICONS admite librerías de fuente y
   en ese caso Elementor emite un <i>, al que `width`/`height` no le hacen nada. Mismo trato que
   `.gsp-trust__ico` en producto-badges.css.

   ── El color, y por qué el control tiene una condición ────────────────────────
   El SVG del plugin sale con `stroke="currentColor"` desde Support\Icons y un <i> de fuente usa
   `color`, así que por defecto los dos siguen al del enlace. Eso NO es un descuido: es lo que
   hace que al pasar el ratón se oscurezca el conjunto entero y no el texto por un lado y el
   dibujo por otro.

   El control «Color del ícono» escribe `--gsp-at-aux-ico-clr`, y el respaldo `inherit` conserva
   ese comportamiento cuando está vacío. Pero en `:hover`, `:focus` y `:active` se fuerza `inherit`
   otra vez, pase lo que pase: un color propio manda en REPOSO, y en el hover el ícono vuelve a
   acompañar al enlace. La alternativa —dejar que se quede quieto mientras el texto cambia— es un
   enlace que se oscurece a medias, y eso es peor que no poder elegir el color.

   `:empty` cubre el caso de un SVG subido cuyo adjunto se borró: Elementor no imprime nada y sin
   esto quedaría el `gap` de 6px colgando delante del texto. El PHP escribe el <span> sin espacios
   dentro justo para que `:empty` acierte. */

.gsp-p .gsp-attrs__aux-ico {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	color: var(--gsp-at-aux-ico-clr, inherit);
}

.gsp-p .gsp-attrs__aux:hover .gsp-attrs__aux-ico,
.gsp-p .gsp-attrs__aux:focus .gsp-attrs__aux-ico,
.gsp-p .gsp-attrs__aux:active .gsp-attrs__aux-ico {
	color: inherit;
}

.gsp-p .gsp-attrs__aux-ico:empty {
	display: none;
}

.gsp-p .gsp-attrs__aux-ico svg {
	width: var(--gsp-at-aux-ico);
	height: var(--gsp-at-aux-ico);
	display: block;
}

.gsp-p .gsp-attrs__aux-ico i {
	font-size: var(--gsp-at-aux-ico);
	line-height: 1;
	color: inherit;
}

/* ── Círculos de color e imágenes ────────────────────────────────────────── */

.gsp-p .is-color .gsp-attrs__ops,
.gsp-p .is-image .gsp-attrs__ops {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

.gsp-p .is-color .gsp-attrs__op,
.gsp-p .is-image .gsp-attrs__op {
	position: relative;
	width: var(--gsp-at-swatch);
	height: var(--gsp-at-swatch);
	border-radius: 50%;
	overflow: hidden;
	cursor: pointer;
	display: block;
	/* El borde de 1px pasa a 2 al seleccionarse, y es un `border` de verdad.

	   Antes se dibujaba con `box-shadow: inset` para que el círculo no cambiara de tamaño, pero
	   así NO SE VEÍA NINGUNO DE LOS DOS: una sombra interior se pinta dentro de la caja de
	   relleno, y `.gsp-attrs__punto` —que es quien lleva el color— se dimensiona contra esa
	   misma caja con `inset: 0` y se pinta después, por ser un descendiente posicionado. El
	   punto tapaba el anillo entero. Se notaba en dos sitios: al seleccionar solo quedaba el
	   halo traslúcido de fuera, y un color claro perdía su contorno y se fundía con el fondo.

	   Con `border` no puede pasar: la caja de relleno EXCLUYE el borde, así que el punto ya no
	   llega a taparlo y queda pegado justo por dentro —el «borde pegado al relleno, sin aro
	   blanco intermedio» que pide el diseño—. Y sigue sin mover a los vecinos porque
	   `producto-base.css` declara `box-sizing: border-box` para toda la familia: el borde se
	   come el ancho por dentro en vez de sumarlo. El halo se queda en `box-shadow` (sin
	   `inset`), que no participa del layout. */
	border: 1px solid var(--gsp-at-borde);
	transition: border-color .18s var(--gs-e-soft), box-shadow .18s var(--gs-e-soft);
}

.gsp-p .gsp-attrs__punto {
	position: absolute;
	inset: 0;
	display: block;
	border-radius: 50%;
}

.gsp-p .gsp-attrs__img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	border-radius: 50%;
}

/* Fondo y color se redeclaran aunque aquí solo cambie el borde: es el contrato de la casa para
   todo `:hover` propio (INSTRUCCIONES.md §3.1). El relleno lo pinta `.gsp-attrs__punto`, así que
   dejarlos transparente y heredado no cambia nada de lo que se ve. */

.gsp-p .is-color .gsp-attrs__op:hover,
.gsp-p .is-image .gsp-attrs__op:hover {
	background-color: transparent;
	color: inherit;
	border-color: var(--gsp-at-activo);
}

/* Seleccionado: anillo de 2px más un halo exterior, que es lo que pide el diseño PARA LOS
   CÍRCULOS. El prefijo `.is-color`/`.is-image` no es decorativo: sin él esta regla alcanzaba
   también a las pastillas de talla, que no llevan anillo en el diseño —solo fondo negro y texto
   blanco—. Ahí se veía como tres trazos dorados encima de una caja que ya tiene su propio borde:
   el anillo de 2px sobre el negro, el halo de 3px (un `spread` sin blur, o sea una banda sólida)
   comiéndose los 4px de padding del grupo y los 4px de hueco hacia las vecinas, y encima el
   `outline` del foco. De ahí que se leyera como una línea dorada ancha y no como un contorno. */

.gsp-p .is-color .gsp-attrs__radio:checked + .gsp-attrs__op,
.gsp-p .is-image .gsp-attrs__radio:checked + .gsp-attrs__op {
	border-width: 2px;
	border-color: var(--gsp-at-activo);
	box-shadow: 0 0 0 3px var(--gsp-at-halo);
}

/* ── Pastillas ───────────────────────────────────────────────────────────────
   El grupo es una caja con borde y las pastillas viven dentro, como en el diseño. */

.gsp-p .is-button .gsp-attrs__ops {
	display: inline-flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 4px;
	padding: 4px;
	border: 1px solid var(--gsp-at-borde);
	border-radius: 8px;
	background: #fff;
}

.gsp-p .is-button .gsp-attrs__op {
	font-family: var(--gs-font-ui);
	font-weight: 600;
	/* El tamaño de la pastilla lo hacen TRES cosas y no una: el mínimo de ancho, la tipografía y el
	   relleno vertical. Con solo `min-width` —que era lo único que tenía control— la pastilla se
	   ensanchaba pero no crecía, que es justo lo que se pedía y no se podía hacer.

	   Con el valor de siempre como respaldo: sin tocar el control, nada cambia de aspecto. */
	font-size: var(--gsp-at-pill-fs, 12px);
	line-height: 1;
	min-width: var(--gsp-at-pill);
	text-align: center;
	/* El relleno lateral crece si el texto es largo, sin romper el mínimo. El vertical es el que da
	   el alto, junto con la tipografía de arriba. */
	padding: var(--gsp-at-pill-py, 10px) 8px;
	border-radius: 7px;
	color: var(--gs-txt-4);
	background-color: transparent;
	cursor: pointer;
	transition: background-color .18s var(--gs-e-soft), color .18s var(--gs-e-soft);
	/* Sin esto, un valor largo parte en dos líneas y descuadra la fila entera. */
	white-space: nowrap;
}

.gsp-p .is-button .gsp-attrs__op:hover {
	background-color: var(--gs-hueso);
	color: var(--gs-tinta);
}

/* La activa NO cambia con el hover: pasar el ratón por encima de lo ya elegido no debe
   sugerir que va a ocurrir algo. Va después de la regla de hover para ganarle. */

.gsp-p .is-button .gsp-attrs__radio:checked + .gsp-attrs__op,
.gsp-p .is-button .gsp-attrs__radio:checked + .gsp-attrs__op:hover {
	background-color: var(--gsp-at-pill-on);
	color: #fff;
	font-weight: 700;
}

/* ── Estados de disponibilidad ───────────────────────────────────────────────
   Se marcan con `data-estado` en la etiqueta y `aria-disabled` en el radio. NUNCA con el
   atributo `disabled`: eso saca la opción del orden de tabulación y el lector de pantalla ya no
   puede anunciar por qué no se puede elegir (INSTRUCCIONES.md §6). Y una agotada sigue siendo
   clicable a propósito, igual que en WooCommerce, para que el cliente llegue a ella y lo vea. */

.gsp-p .gsp-attrs__op[data-estado="agotado"],
.gsp-p .gsp-attrs__op[data-estado="imposible"] {
	opacity: .35;
	cursor: not-allowed;
}

.gsp-p .is-button .gsp-attrs__op[data-estado="agotado"],
.gsp-p .is-button .gsp-attrs__op[data-estado="imposible"] {
	opacity: 1;
	color: var(--gs-agotado-2);
	text-decoration: line-through;
}

/* Diagonal tachada sobre el círculo agotado. `::after` sobre la etiqueta y no un elemento en el
   markup: es decoración pura y no debe existir para un lector de pantalla. */

.gsp-p .is-color .gsp-attrs__op[data-estado="agotado"]::after,
.gsp-p .is-color .gsp-attrs__op[data-estado="imposible"]::after,
.gsp-p .is-image .gsp-attrs__op[data-estado="agotado"]::after,
.gsp-p .is-image .gsp-attrs__op[data-estado="imposible"]::after {
	content: '';
	position: absolute;
	inset: 0;
	/* La diagonal se dibuja con un degradado de paradas duras: así escala con el tamaño del
	   círculo sin necesidad de recalcular nada. */
	background: linear-gradient(
		to top right,
		transparent calc(50% - 1px),
		var(--gs-agotado) calc(50% - 1px),
		var(--gs-agotado) calc(50% + 1px),
		transparent calc(50% + 1px)
	);
	border-radius: 50%;
	pointer-events: none;
}

/* Opciones ocultas por el control «ocultar agotadas». */

.gsp-p .gsp-attrs__radio[hidden] + .gsp-attrs__op,
.gsp-p .gsp-attrs__op[hidden] {
	display: none;
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
	.gsp-p .gsp-attrs__op {
		transition-duration: .01ms;
	}
}

/* ---- producto-cart.css ---- */
/**
 * GS Product Add To Cart. Handle 'gs-producto-cart' (dep: gs-producto-base).
 *
 * Botón negro de añadir, a todo el ancho de la fila. Dos piezas vienen APAGADAS de fábrica —el
 * selector de cantidad (lo quitó la v2) y «Comprar ahora» (lo quitaron los ajustes posteriores)—
 * pero su estilo se conserva entero por si se reactivan desde el panel.
 *
 * La separación entre la fila y «Comprar ahora» es un `gap` de `.gsp-cart__acciones` y NO un
 * `margin-bottom` de la fila: solo debe existir cuando existan los dos. Con el margen en la fila,
 * apagar el botón dejaba 14px colgando bajo el de añadir, sumados a los 24 de `--gsp-cart-gap` de
 * la raíz. Un `gap` no existe si no hay un segundo hermano, y esa es la diferencia entre una
 * invariante estructural y una regla que alguien tiene que acordarse de mantener.
 */

.gsp-p.gsp-cart {
	--gsp-cart-alto: 52px;
	--gsp-cart-radio: 8px;
	--gsp-cart-gap: 24px;

	--gsp-cart-add-bg: var(--gs-tinta);
	--gsp-cart-add-fg: #fff;
	--gsp-cart-add-bg-on: var(--gs-oro);
	--gsp-cart-add-fg-on: var(--gs-tinta);

	--gsp-cart-buy: var(--gs-oro);
	--gsp-cart-buy-bg-on: var(--gs-oro-pale);

	margin-bottom: var(--gsp-cart-gap);
}

.gsp-p .gsp-cart__acciones {
	display: flex;
	flex-direction: column;
	gap: 14px;
}

.gsp-p .gsp-cart__fila {
	display: flex;
	gap: 12px;
}

/* Red de seguridad: el enlace «Ver carrito» que WooCommerce —o cualquier plugin que escuche
   `added_to_cart`— inserta detrás del botón con `$button.after()`. Aquí caería dentro de la fila
   flex, o sea pegado a la derecha del botón negro, con los estilos de enlace del tema y el texto
   sin traducir. El JS de este widget ya evita que Woo lo genere (no le pasa el botón al `trigger`);
   esto cubre a terceros. Mismo criterio que en tarjetas.css. */

.gsp-p.gsp-cart .added_to_cart,
.gsp-p.gsp-cart .wc-forward {
	display: none !important;
}

/* ── Botones ─────────────────────────────────────────────────────────────────
   Llevan `.gsp-i` en el markup (exentos del neutralizador de producto-base.css) y declaran sus
   tres estados prefijados por la raíz → 0,3,0, que le gana al Global Kit (0,2,1).

   El selector incluye la etiqueta (`button.gsp-cart__btn`, `a.gsp-cart__btn`) porque el reset de
   `button` de producto-base.css es 0,1,1 y anula el padding: una clase suelta no le gana. */

.gsp-p .gsp-cart__btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	height: var(--gsp-cart-alto);
	padding: 0 20px;
	border: none;
	border-radius: var(--gsp-cart-radio);
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 13px;
	line-height: 1;
	letter-spacing: .1em;
	text-transform: uppercase;
	text-decoration: none;
	cursor: pointer;
	transition: background-color .2s var(--gs-e-soft), color .2s var(--gs-e-soft), border-color .2s var(--gs-e-soft),
		transform .16s var(--gs-e-out);
}

/* Realimentación de pulsación, misma escala que el resto de controles grandes del sistema
   (`.gs-mc__cta` del minicarrito, la tarjeta del mosaico, el botón de la tarjeta de producto).
   Estos dos declaraban `:active` sólo para el COLOR —blindaje contra el Global Kit, ver la
   cabecera de `producto-base.css`—, así que el botón de compra principal de la ficha no
   acusaba la pulsación por ningún lado.

   No hace falta escaparse de nada: el neutralizador de `producto-base.css` mata `transform`
   en `:hover` y `:focus` pero se excluye a sí mismo del `:active` (`:hover:not(:active)`)
   justamente para dejar sitio a esto. El hueco estaba hecho y sin usar.

   Se aplica también al botón en `aria-disabled`, y a diferencia de la tarjeta eso es
   correcto: aquí pulsar SÍ hace algo —sale el aviso con el motivo por el que no se puede
   comprar—, así que el acuse de recibo es justo lo que hace falta para que el aviso no
   parezca salido de la nada. */
.gsp-p .gsp-cart__btn:active {
	transform: scale(.985);
}

/* Añadir al carrito: ocupa el ancho que quede libre junto al stepper. */

/* `flex: 1 1 auto` es lo que evita el salto al cambiar el texto por «Agregando…» y «✓
   Agregado»: el ancho lo reparte el contenedor, no lo decide el contenido. Por eso NO hace
   falta un `min-width`. */

.gsp-p .gsp-cart__add {
	flex: 1 1 auto;
	background-color: var(--gsp-cart-add-bg);
	color: var(--gsp-cart-add-fg);
}

.gsp-p .gsp-cart__add:hover,
.gsp-p .gsp-cart__add:focus,
.gsp-p .gsp-cart__add:active {
	background-color: var(--gsp-cart-add-bg-on);
	color: var(--gsp-cart-add-fg-on);
}

/* Comprar ahora: contorno dorado a todo el ancho. */

.gsp-p .gsp-cart__buy {
	width: 100%;
	background-color: transparent;
	color: var(--gsp-cart-buy);
	border: 1.5px solid var(--gsp-cart-buy);
}

.gsp-p .gsp-cart__buy:hover,
.gsp-p .gsp-cart__buy:focus,
.gsp-p .gsp-cart__buy:active {
	background-color: var(--gsp-cart-buy-bg-on);
	color: var(--gsp-cart-buy);
	border-color: var(--gsp-cart-buy);
}

/* ── Deshabilitado ───────────────────────────────────────────────────────────
   El estado lo marca `aria-disabled`, NO el atributo `disabled`, y aquí decía lo contrario: «un
   botón de compra sin variación elegida no tiene ninguna acción que ofrecer». Sí la tiene —
   explicar por qué no se puede comprar—, y con `disabled` era imposible: ese atributo impide que
   el botón emita `click`, así que el cliente pulsaba y no pasaba absolutamente nada. Ver el
   comentario largo de `refrescarBotones()` en producto-cart.js.

   El selector de `[disabled]` se conserva por si algún camino externo lo pone (un plugin de
   terceros sobre el mismo markup): el aspecto debe ser el mismo venga de donde venga. */

.gsp-p .gsp-cart__btn[disabled],
.gsp-p .gsp-cart__btn[aria-disabled="true"] {
	opacity: .5;
	cursor: not-allowed;
}

.gsp-p .gsp-cart__btn[disabled]:hover,
.gsp-p .gsp-cart__btn[aria-disabled="true"]:hover,
.gsp-p .gsp-cart__btn[disabled]:focus,
.gsp-p .gsp-cart__btn[aria-disabled="true"]:focus {
	background-color: var(--gsp-cart-add-bg);
	color: var(--gsp-cart-add-fg);
}

.gsp-p .gsp-cart__buy[disabled]:hover,
.gsp-p .gsp-cart__buy[aria-disabled="true"]:hover,
.gsp-p .gsp-cart__buy[disabled]:focus,
.gsp-p .gsp-cart__buy[aria-disabled="true"]:focus {
	background-color: transparent;
	color: var(--gsp-cart-buy);
}

/* ── Agotado ─────────────────────────────────────────────────────────────────
   Mismo alto que los botones: si midiera menos, el contenido de debajo daría un salto al
   cambiar de variación. */

.gsp-p .gsp-cart__agotado {
	display: flex;
	align-items: center;
	justify-content: center;
	height: var(--gsp-cart-alto);
	border-radius: var(--gsp-cart-radio);
	background-color: var(--gs-hueso);
	color: var(--gs-agotado);
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 13px;
	line-height: 1;
	letter-spacing: .1em;
	text-transform: uppercase;
}

.gsp-p .gsp-cart__agotado[hidden],
.gsp-p .gsp-cart__acciones[hidden] {
	display: none;
}

/* ── Selector de cantidad ────────────────────────────────────────────────── */

.gsp-p .gsp-cart__stepper {
	display: flex;
	align-items: center;
	flex: 0 0 auto;
	border: 1px solid var(--gs-linea);
	border-radius: var(--gsp-cart-radio);
	overflow: hidden;
	background: #fff;
	/* El borde es el indicador de foco (más abajo): sin transición el cambio de color salta. */
	transition: border-color .15s var(--gs-e-soft);
}

/* ── Foco: el mismo trato que el stepper de mayoreo ──────────────────────────
   Este contenedor tiene el mismo `overflow: hidden` que el de `producto-tiers.css`, así que el
   `outline: 2px solid var(--gs-oro)` que `producto-base.css` pinta sobre cualquier campo o botón
   enfocado (0,2,1) salía aquí igual de mal: el campo mide lo mismo de alto que la pieza, el contorno
   se iba 2px por arriba y por abajo y el recorte lo dejaba en dos medias lunas doradas a los lados.
   Era el defecto gemelo que PENDIENTES.md tenía anotado sin tocar.

   El indicador es el BORDE que la pieza ya tiene —la misma caja que el control, así que no se
   desalinea ni asoma sobre la fila vecina como hacía el `outline`— y en gris `--gs-txt-3`, que da
   ~3.5:1 contra el blanco y es ya el color en reposo de los `−`/`+`. Razonado en `producto-tiers.css`.

   La exención de las piezas (0,4,0) NO es opcional: sin ella vuelven las medias lunas. */

.gsp-p .gsp-cart__stepper :is(.gsp-cart__qty, .gsp-cart__step):focus-visible {
	outline: none;
}

.gsp-p .gsp-cart__stepper:focus-within {
	border-color: var(--gs-txt-3);
}

/* `button.gsp-cart__step` con la etiqueta: el reset de producto-base.css es 0,1,1 y le quita el
   padding a todo <button>, así que una clase suelta (0,1,0) no recupera el tamaño. */

.gsp-p button.gsp-cart__step {
	width: 44px;
	height: var(--gsp-cart-alto);
	display: grid;
	place-items: center;
	background-color: transparent;
	color: var(--gs-txt-3);
	border: 0;
	cursor: pointer;
	transition: background-color .18s var(--gs-e-soft), color .18s var(--gs-e-soft);
}

.gsp-p button.gsp-cart__step:hover,
.gsp-p button.gsp-cart__step:focus,
.gsp-p button.gsp-cart__step:active {
	background-color: var(--gs-hueso);
	color: var(--gs-tinta);
}

.gsp-p .gsp-cart__step svg {
	width: 14px;
	height: 14px;
}

/* Tres clases, y hacen falta — la misma trampa que `producto-tiers.css` documenta para su gemelo.
   Con dos (`.gsp-p .gsp-cart__qty`, 0,2,0) el campo perdía la pelea y sus bordes laterales salían en
   #333 en vez de `--gs-linea`. No se notaba en reposo, pero al enfocar `producto-base.css` le pone
   `border-radius: inherit` y esos dos filos oscuros se curvaban dibujando un recuadro negro alrededor
   del número, dentro de la pieza. Con `.gsp-cart__stepper` en medio se llega a 0,3,0 y gana sin
   `!important`. Medido en pantalla. Es la trampa de INSTRUCCIONES.md §3.2. */

.gsp-p .gsp-cart__stepper .gsp-cart__qty {
	width: 48px;
	height: var(--gsp-cart-alto);
	padding: 0;
	text-align: center;
	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: 15px;
	color: var(--gs-tinta);
	border: 0;
	border-left: 1px solid var(--gs-linea);
	border-right: 1px solid var(--gs-linea);
	background: transparent;
}

/* Los spinners nativos ya se ocultan en producto-base.css, que además pone `appearance` a
   textfield para que Firefox tampoco los pinte. */

/* ── Móvil ───────────────────────────────────────────────────────────────── */

@media (max-width: 480px) {
	.gsp-p .gsp-cart__btn {
		font-size: 12px;
		padding: 0 14px;
	}
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
	.gsp-p .gsp-cart__btn,
	.gsp-p button.gsp-cart__step {
		transition-duration: .01ms;
	}
}

/* ---- producto-mayoreo.css ---- */
/**
 * GS Product Wholesale CTA. Handle 'gs-producto-mayoreo' (dep: gs-producto-base).
 *
 * Caja gris con el gancho de mayoreo a la izquierda y el botón de cotizar a la derecha.
 */

.gsp-p.gsp-may {
	--gsp-may-bg: rgba(17, 17, 17, .04);
	--gsp-may-borde: rgba(17, 17, 17, .08);
	--gsp-may-titulo: var(--gs-tinta-precio);
	--gsp-may-sub: var(--gs-gris);
	--gsp-may-btn-bg: var(--gs-tinta-precio);
	--gsp-may-btn-on: var(--gs-oro);
	--gsp-may-radio: 10px;
	--gsp-may-gap: 24px;

	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	padding: 16px 20px;
	border: 1px solid var(--gsp-may-borde);
	border-radius: var(--gsp-may-radio);
	background-color: var(--gsp-may-bg);
	margin-bottom: var(--gsp-may-gap);
}

/* `min-width: 0` en la columna de texto: sin él, un título largo impide que el flex se encoja y
   empuja el botón fuera de la caja. */

.gsp-p .gsp-may__texto {
	min-width: 0;
}

.gsp-p .gsp-may__titulo {
	font-family: var(--gs-font-display);
	font-weight: 700;
	font-size: 15px;
	line-height: 1.3;
	letter-spacing: .04em;
	text-transform: uppercase;
	color: var(--gsp-may-titulo);
	margin: 0 0 5px;
	padding: 0;
}

.gsp-p .gsp-may__sub {
	font-family: var(--gs-font-body);
	font-weight: 400;
	font-size: 12.5px;
	line-height: 1.5;
	color: var(--gsp-may-sub);
	margin: 0;
	padding: 0;
}

/* El precio dentro de la frase, más oscuro y en negrita. */

.gsp-p .gsp-may__sub strong {
	color: var(--gsp-may-titulo);
	font-weight: 600;
}

/* ── Botón ───────────────────────────────────────────────────────────────────
   Lleva `.gsp-i` y declara sus tres estados prefijados por la raíz (0,3,0), con fondo Y color,
   que es lo que gana al Global Kit (0,2,1).

   `white-space: nowrap` y `flex: 0 0 auto`: el botón no debe partirse ni encogerse cuando el
   texto de al lado es largo. */

.gsp-p .gsp-may__btn {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 10px 18px;
	border: 1px solid var(--gsp-may-btn-bg);
	border-radius: 5px;
	background-color: var(--gsp-may-btn-bg);
	color: #fff;
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 10px;
	line-height: 1;
	letter-spacing: .1em;
	text-transform: uppercase;
	text-decoration: none;
	white-space: nowrap;
	transition: background-color .18s var(--gs-e-soft), border-color .18s var(--gs-e-soft), color .18s var(--gs-e-soft);
}

.gsp-p .gsp-may__btn:hover,
.gsp-p .gsp-may__btn:focus,
.gsp-p .gsp-may__btn:active {
	background-color: var(--gsp-may-btn-on);
	border-color: var(--gsp-may-btn-on);
	color: #fff;
	text-decoration: none;
}

/* ── Móvil ───────────────────────────────────────────────────────────────────
   En columna y con el botón a todo el ancho: a 360px, el texto y el botón en la misma fila
   dejan al botón con sitio para tres letras. */

@media (max-width: 560px) {
	.gsp-p.gsp-may {
		flex-direction: column;
		align-items: stretch;
		gap: 14px;
	}

	.gsp-p .gsp-may__btn {
		width: 100%;
	}
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
	.gsp-p .gsp-may__btn {
		transition-duration: .01ms;
	}
}

/* ---- producto-tiers.css ---- */
/**
 * GS Product Wholesale Tiers. Handle 'gs-producto-tiers' (dep: gs-producto-base).
 *
 * Lista de escalones de precio por volumen: una fila por escalón, más la de cantidad libre. Los
 * escalones que sobran de los tres primeros y la fila libre viven detrás de «Ver más».
 *
 * ── El único elemento dorado del widget es el toggle ─────────────────────────
 * Está escrito en la especificación y conviene que se note aquí: las pastillas son negras o beige,
 * nunca oro. Si mañana alguien «unifica el acento» y lo mete en los chips, el bloque pierde el
 * único punto de color que dirige la mirada al desplegable.
 *
 * ── Por qué el corte de móvil es 767 y no 560 ────────────────────────────────
 * El resto de la familia rompe en 560px, pero este widget trae `mobile_default` en sus controles de
 * tipografía, y esos los aplica Elementor en SU breakpoint móvil, que es 767. Con la hoja en 560 el
 * tamaño de letra y el relleno de las filas cambiarían a anchos distintos, y entre 560 y 767 la fila
 * quedaría con la letra pequeña y el relleno grande. Se igualan a propósito.
 */

.gsp-p.gsp-wt {
	/* Caja */
	--gsp-wt-bg: rgba(17, 17, 17, .04);
	--gsp-wt-borde: rgba(17, 17, 17, .08);
	--gsp-wt-radio: 10px;
	--gsp-wt-gap: 24px;

	/* Filas */
	--gsp-wt-fila-on: rgba(10, 10, 10, .05);
	--gsp-wt-fila-hover: rgba(10, 10, 10, .028);
	--gsp-wt-anillo: rgba(10, 10, 10, .25);
	--gsp-wt-dot-off: var(--gs-sep);
	--gsp-wt-dot-on: var(--gs-tinta);

	/* Texto */
	--gsp-wt-label: var(--gs-tinta-precio);
	--gsp-wt-precio: var(--gs-tinta-precio);
	--gsp-wt-resumen: var(--gs-gris);

	/* Pastillas */
	--gsp-wt-chip-off-bg: var(--gs-hueso-3);
	--gsp-wt-chip-off-txt: var(--gs-txt-4);
	--gsp-wt-chip-on-bg: var(--gs-tinta);
	--gsp-wt-chip-on-txt: #fff;

	/* Desplegable */
	--gsp-wt-toggle: var(--gs-oro);
	--gsp-wt-toggle-on: var(--gs-tinta-precio);

	/* Medidas que cambian en móvil. Viven en variables porque el control de tipografía de
	   Elementor escribe `font-size` con 0,4,0 y ganaría a cualquier regla de esta hoja; los
	   rellenos, que NO tienen control, se resuelven aquí. */
	--gsp-wt-pad: 12px 14px;
	--gsp-wt-fila-pad: 10px 12px;
	--gsp-wt-fila-alto: auto;
	--gsp-wt-precio-min: 78px;
	--gsp-wt-chip-size: 9.5px;
	--gsp-wt-chip-pad: 3px 7px;

	padding: var(--gsp-wt-pad);
	border: 1px solid var(--gsp-wt-borde);
	border-radius: var(--gsp-wt-radio);
	background-color: var(--gsp-wt-bg);
	margin-bottom: var(--gsp-wt-gap);
}

/* ── Lista ──────────────────────────────────────────────────────────────── */

.gsp-p .gsp-wt-list {
	display: flex;
	flex-direction: column;
	gap: 2px;
}

/* ── Fila ────────────────────────────────────────────────────────────────────
   El anillo de selección es un `box-shadow: inset` y no un `border`: un borde cambiaría el tamaño
   de la caja y las filas darían un salto de 2px al elegirlas. Aquí sí vale (al revés que en el
   swatch de atributos, donde el punto de color tapaba la sombra interior) porque dentro de la fila
   no hay ningún hijo posicionado que se pinte encima. */

.gsp-p .gsp-wt-row {
	display: flex;
	align-items: center;
	gap: 12px;
	min-height: var(--gsp-wt-fila-alto);
	padding: var(--gsp-wt-fila-pad);
	border-radius: 8px;
	background-color: transparent;
	box-shadow: inset 0 0 0 1px transparent;
	cursor: pointer;
	transition: background-color .15s var(--gs-e-soft), box-shadow .15s var(--gs-e-soft);
	-webkit-tap-highlight-color: transparent;
}

.gsp-p .gsp-wt-row.is-selected {
	background-color: var(--gsp-wt-fila-on);
	box-shadow: inset 0 0 0 1px var(--gsp-wt-anillo);
}

/* Un escalón que pide más piezas de las que hay se ve, pero no se elige. Sigue siendo alcanzable
   por teclado (`aria-disabled`, nunca `disabled`) para que el lector pueda anunciar por qué. */

.gsp-p .gsp-wt-row.is-agotado {
	opacity: .45;
	cursor: not-allowed;
}

/* ── El radio y su foco ──────────────────────────────────────────────────────
   NO se reutiliza `.gsp-radio` de `producto-base.css`, y merece explicación: aquella trae consigo
   `.gsp-p .gsp-radio:focus-visible + *`, que pinta el anillo de foco sobre el HERMANO siguiente —
   aquí, el círculo de 15px—. El diseño pide el foco sobre la fila entera, y las dos reglas
   convivirían dando dos anillos. Ocultar el input son seis líneas; pelearse con esa regla, más. */

.gsp-p .gsp-wt-input {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* `:has()` para llevar el foco a la fila. Va tras un `@supports` EXCLUYENTE porque el respaldo
   (anillo sobre el círculo) tiene que desaparecer donde `:has()` funciona: conviviendo se pintan
   los dos. Es el mismo patrón que usan las estrellas del formulario de reseña. */

@supports selector(:has(*)) {
	.gsp-p .gsp-wt-row:has(.gsp-wt-input:focus-visible) {
		outline: 2px solid var(--gs-tinta);
		outline-offset: 2px;
	}
}

/* El respaldo alcanza al hermano siguiente, que en las filas de escalón es el círculo y en la de
   cantidad libre es la etiqueta envolvente (ahí el círculo va dentro, ver `.gsp-wt-toque`). */

@supports not selector(:has(*)) {
	.gsp-p .gsp-wt-input:focus-visible + .gsp-wt-dot,
	.gsp-p .gsp-wt-input:focus-visible + .gsp-wt-toque {
		outline: 2px solid var(--gs-tinta);
		outline-offset: 2px;
	}
}

/* ── La zona etiquetada de la fila de cantidad libre ─────────────────────────
   Esa fila NO puede ser un `<label>` —lleva dos botones y un segundo campo dentro—, así que el
   label envuelve solo lo que de verdad etiqueta: el círculo y el texto. Hereda el reparto que antes
   hacía la fila, para que el aspecto no cambie. */

.gsp-p .gsp-wt-toque {
	display: flex;
	flex: 1 1 auto;
	align-items: center;
	gap: 12px;
	min-width: 0;
	cursor: pointer;
	margin: 0;
}

/* El círculo se dibuja con `border` y no con un pseudo-elemento: al seleccionarlo el borde engorda
   a 4.5px y el fondo blanco que queda ES el anillo interior, sin un solo nodo extra. */

.gsp-p .gsp-wt-dot {
	flex: 0 0 auto;
	width: 15px;
	height: 15px;
	border: 1.5px solid var(--gsp-wt-dot-off);
	border-radius: 50%;
	background-color: #fff;
	transition: border-color .15s var(--gs-e-soft), border-width .15s var(--gs-e-soft);
}

.gsp-p .gsp-wt-row.is-selected .gsp-wt-dot {
	border: 4.5px solid var(--gsp-wt-dot-on);
}

/* ── Etiqueta ────────────────────────────────────────────────────────────────
   `min-width: 0` + `overflow: hidden`: cuando falta ancho es la etiqueta la que se recorta, nunca
   la pastilla ni el precio (que son los datos). */

.gsp-p .gsp-wt-label {
	flex: 1 1 auto;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: 13.5px;
	line-height: 1.3;
	color: var(--gsp-wt-label);
}

/* Las dos versiones de la etiqueta de la fila libre se imprimen y aquí se elige: cambiar el texto
   desde JS obligaría a escuchar el `resize` y metería una cadena traducible en el JavaScript. */

.gsp-p .gsp-wt-label__corto {
	display: none;
}

/* ── Pastilla ────────────────────────────────────────────────────────────── */

.gsp-p .gsp-wt-chip {
	flex: 0 0 auto;
	padding: var(--gsp-wt-chip-pad);
	border-radius: 4px;
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: var(--gsp-wt-chip-size);
	line-height: 1.2;
	letter-spacing: .1em;
	text-transform: uppercase;
	white-space: nowrap;
	background-color: var(--gsp-wt-chip-off-bg);
	color: var(--gsp-wt-chip-off-txt);
}

.gsp-p .gsp-wt-chip.is-off {
	background-color: var(--gsp-wt-chip-on-bg);
	color: var(--gsp-wt-chip-on-txt);
}

/* ── Precio ──────────────────────────────────────────────────────────────────
   `tabular-nums` para que el importe no baile al cambiar de escalón: sin él cada dígito tiene un
   ancho distinto y la columna se mueve con cada clic. */

.gsp-p .gsp-wt-price {
	flex: 0 0 auto;
	min-width: var(--gsp-wt-precio-min);
	font-family: var(--gs-font-display);
	font-weight: 700;
	font-size: 15px;
	line-height: 1.2;
	color: var(--gsp-wt-precio);
	font-variant-numeric: tabular-nums;
	text-align: right;
	white-space: nowrap;
}

/* ── Stepper de la fila libre ────────────────────────────────────────────────
   Los spinners nativos del `input[type=number]` ya los quita `producto-base.css` para toda la
   familia, y el reset de `<button>` también es suyo: aquí solo va lo propio. */

.gsp-p .gsp-wt-stepper {
	display: flex;
	flex: 0 0 auto;
	align-items: center;
	overflow: hidden;
	border: 1px solid var(--gs-linea);
	border-radius: 7px;
	background-color: #fff;
	/* Sin esto, en táctil el doble toque sobre el stepper hace zoom a la página y añade el retardo
	   de 300 ms antes de que el «+» responda. */
	touch-action: manipulation;
	/* El borde es el indicador de foco (más abajo): sin transición el cambio de color salta. */
	transition: border-color .15s var(--gs-e-soft);
}

/* ── El foco va al STEPPER, y se marca con su BORDE ──────────────────────────
   `producto-base.css` pinta `outline: 2px solid var(--gs-oro)` con `outline-offset: 2px` y
   `border-radius: inherit` sobre cualquier `input` o `button` enfocado (0,2,1). Dentro de este
   contenedor eso salía fatal: el campo mide lo mismo de alto que el stepper, así que el contorno se
   iba 2px por arriba y por abajo, el `overflow: hidden` de aquí lo recortaba, y solo quedaban dos
   medias lunas doradas a los lados del campo. Se ve además al hacer CLIC, no solo al tabular, porque
   los navegadores casan `:focus-visible` con cualquier foco en los campos de texto.

   De ahí que el indicador pasara al stepper, que es lo que el cliente ve como una sola pieza. Pero
   pintarlo con `outline` era el error: un `outline` con `outline-offset` es una caja dibujada FUERA
   del elemento, que no participa del layout y se pinta sobre lo que tenga al lado. En pantalla se
   leía despegado y por encima del control en vez de rodearlo. El BORDE que el stepper ya tiene es por
   definición la misma caja que el control: no puede desalinearse, y marca la pieza entera —`−`, el
   número y `+`— en vez de un trozo de ella.

   Va en gris y no en negro. `--gs-txt-3` da ~3.5:1 contra el blanco del stepper, por encima del 3:1
   que pide WCAG 1.4.11 para un indicador no textual, y es ya el color en reposo de los glifos `−`/`+`,
   así que no entra un tono nuevo en el widget. El negro de `--gs-tinta` a 2px se leía como un
   artefacto y no como un foco.

   `:focus-within` en vez de `:has(:focus-visible)`: hace lo mismo sin necesitar `:has()`, así que cae
   la bifurcación `@supports` que dejaba dos aspectos distintos según el navegador —y con ella el
   anillo cuadrado hacia dentro del campo, que era el peor de los dos. La única diferencia es que
   pulsar `−`/`+` con el ratón también tiñe el borde (un `<button>` no casa `:focus-visible` al hacer
   clic, pero sí `:focus-within`), y con un gris discreto eso es realimentación correcta.

   La exención de las piezas (0,4,0) NO es opcional: sin ella vuelven las medias lunas doradas. */

.gsp-p .gsp-wt-stepper :is(.gsp-wt-qty, .gsp-wt-step):focus-visible {
	outline: none;
}

.gsp-p .gsp-wt-stepper:focus-within {
	border-color: var(--gs-txt-3);
}

.gsp-p .gsp-wt-step {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 29px;
	height: 32px;
	background-color: transparent;
	color: var(--gs-txt-3);
	font-family: var(--gs-font-ui);
	font-size: 17px;
	line-height: 1;
	transition: background-color .15s var(--gs-e-soft), color .15s var(--gs-e-soft);
}

/* Los tres estados prefijados por la raíz (0,3,0) y declarando fondo Y color: es lo que le gana al
   `.elementor-kit-N button:hover` del Global Kit (0,2,1), que va en el <body>. El botón lleva
   además `.gsp-i` para quedar exento del neutralizador de `producto-base.css`. Cumplir solo una de
   las dos cosas deja que el Kit gane. */

.gsp-p .gsp-wt-step:hover,
.gsp-p .gsp-wt-step:focus,
.gsp-p .gsp-wt-step:active {
	background-color: var(--gs-hueso);
	color: var(--gs-tinta);
}

/* Tres clases, y hacen falta. `producto-base.css` neutraliza los campos del formulario con
   `.gsp-p input[type="number"] { font: inherit; color: inherit }`, que es (0,2,1): una clase, un
   elemento y un atributo. Una regla de dos clases (0,2,0) PIERDE, y el campo se quedaba con la
   tipografía del tema a 16px en vez de Montserrat 600 a 13. Medido en pantalla. El recuento de
   clases se compara antes que el de elementos, así que con `.gsp-wt-stepper` en medio se llega a
   (0,3,0) y gana sin `!important`. Es la trampa de INSTRUCCIONES.md §3.2. */

.gsp-p .gsp-wt-stepper .gsp-wt-qty {
	width: 48px;
	height: 32px;
	padding: 0;
	border: 0;
	border-left: 1px solid var(--gs-linea);
	border-right: 1px solid var(--gs-linea);
	background-color: transparent;
	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: 13px;
	color: var(--gs-tinta);
	text-align: center;
}

/* ── Bloque plegable ─────────────────────────────────────────────────────────
   Técnica grid 0fr→1fr, nunca max-height medido en JS (mismo mecanismo que el acordeón de
   nav-menu.css): sin medición no hay momento en que el número fijado por JS pueda no coincidir
   con el layout final, que es justo la clase de salto que se veía al revelar la fila de cantidad
   libre. */

.gsp-p .gsp-wt-hidden {
	display: grid;
	grid-template-rows: minmax(0, 0fr);
	visibility: hidden;
	transition: grid-template-rows .22s var(--gs-e-quint), visibility 0s linear .22s;
}

.gsp-p .gsp-wt-hidden.is-open {
	grid-template-rows: minmax(0, 1fr);
	visibility: visible;
	/* Sin el retardo de `visibility`: al abrir se revela al instante, solo al cerrar se retrasa
	   hasta que termina de encogerse (si no, el teclado se pierde dentro de algo invisible). */
	transition: grid-template-rows .22s var(--gs-e-quint);
}

/* Corta la transición para los cierres forzados sin animación (cambio de variación con el panel
   ya vacío). Hace falta esta clase y no basta con quitar `.is-open`: sin ella, quitarla dispara
   igualmente la transición de `grid-template-rows`/`visibility` de la regla base. */

.gsp-p .gsp-wt-hidden.gsp-wt-hidden--instant {
	transition: none;
}

/* El panel real: aquí vive el recorte y la MISMA separación que la lista (el bloque es un hijo
   más de `.gsp-wt-list`, así que sus filas respiran igual que las de fuera). `min-height: 0` es
   obligatorio: un hijo de grid nunca encoge por debajo de la altura de su contenido
   (min-height:auto por defecto), y la pista de arriba no tendría nada que recortar por mucho que
   `grid-template-rows` baje a 0fr. Mismo caso que `.gs-nav__panel` en nav-menu.css. */

.gsp-p .gsp-wt-hidden__panel {
	display: flex;
	flex-direction: column;
	gap: 2px;
	overflow: hidden;
	min-height: 0;
}

/* ── El `[hidden]` del pie y del toggle ───────────────────────────────────────
   Las dos reglas de abajo declaran `display`, que es (0,2,0), y el `[hidden] { display: none }`
   de la hoja de usuario es (0,1,0): pierde. Sin sus compañeras, el `hidden` que ponen
   `pintar()` (PHP) y `sincronizarToggle()` (JS) era INERTE, y se veía:

     · con la fila de cantidad libre apagada y tres escalones o menos, un botón «Ver más» que no
       despliega nada — y que al pulsarlo pone `aria-expanded="true"` sobre una región vacía;
     · con el resumen del pie también apagado, una línea divisoria suelta con nada debajo, que es
       justo lo que el comentario de `producto-tiers.js` dice estar evitando.

   La compañera de `.gsp-wt-hidden` sí estaba (arriba), y por eso el bloque plegable funcionaba y
   estas dos no. Es la trampa de INSTRUCCIONES.md §3.2 aplicada al selector de atributo. */

.gsp-p .gsp-wt-foot[hidden],
.gsp-p .gsp-wt-toggle[hidden] {
	display: none;
}

/* ── Pie ─────────────────────────────────────────────────────────────────── */

.gsp-p .gsp-wt-foot {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	margin-top: 11px;
	padding: 10px 2px 0;
	border-top: 1px solid var(--gsp-wt-borde);
}

.gsp-p .gsp-wt-summary {
	margin: 0;
	padding: 0;
	font-family: var(--gs-font-body);
	font-weight: 400;
	font-size: 12.5px;
	line-height: 1.4;
	color: var(--gsp-wt-resumen);
}

/* El total, más oscuro dentro de la frase. */

.gsp-p .gsp-wt-summary strong {
	color: var(--gsp-wt-label);
	font-weight: 600;
}

.gsp-p .gsp-wt-foot__hueco {
	flex: 1 1 auto;
}

/* ── «Elige Color para ver el precio por cantidad» ───────────────────────────
   Solo aparece cuando el precio de este producto depende de un atributo y todavía no hay variación
   elegida: ahí las filas van sin importe a propósito, porque el del padre es el del color más
   barato (ver `filas_pendientes()` en el widget).

   Se usa `--gsp-wt-label` y no el gris del resumen: no es un cálculo secundario, es lo único que
   hay que hacer para que la caja empiece a decir números. Con el gris se leía como una nota al pie
   y la caja parecía rota en vez de a la espera. */

.gsp-p .gsp-wt-elige {
	margin: 0 0 6px;
	padding: 0;
	font-family: var(--gs-font-body);
	font-weight: 500;
	font-size: 12.5px;
	line-height: 1.4;
	color: var(--gsp-wt-label);
}

/* La pastilla de un escalón cuyo precio aún no se sabe (`is-pendiente`) NO lleva regla propia, y
   es deliberado: se queda con el aspecto neutro de `.gsp-wt-chip`, que es el mismo que usan
   «Menudeo» y «Sin stock». El énfasis oscuro es de `.is-off`, y esa clase significa además otra
   cosa —el JS publica el escalón al widget de precio solo cuando la ve—, así que ponérsela a una
   fila sin importe haría que la ficha anunciara un precio que no existe. */

/* ── Toggle ──────────────────────────────────────────────────────────────────
   Único elemento dorado del widget. Lleva `.gsp-i` y sus tres estados prefijados por la raíz. */

.gsp-p .gsp-wt-toggle {
	display: inline-flex;
	flex: 0 0 auto;
	align-items: center;
	gap: 6px;
	background-color: transparent;
	color: var(--gsp-wt-toggle);
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 10px;
	line-height: 1;
	letter-spacing: .1em;
	text-transform: uppercase;
	transition: color .15s var(--gs-e-soft);
}

.gsp-p .gsp-wt-toggle:hover,
.gsp-p .gsp-wt-toggle:focus,
.gsp-p .gsp-wt-toggle:active {
	background-color: transparent;
	color: var(--gsp-wt-toggle-on);
}

/* Chevron dibujado con dos bordes, no con un glifo (`⌄`, `▾`): cada familia tipográfica los
   centra a una altura distinta y quedan descolgados del texto. */

.gsp-p .gsp-wt-chevron {
	width: 6px;
	height: 6px;
	margin-bottom: 2px;
	border-right: 1.6px solid currentColor;
	border-bottom: 1.6px solid currentColor;
	transform: rotate(45deg);
	transition: transform .22s var(--gs-e-soft);
}

.gsp-p .gsp-wt-toggle[aria-expanded="true"] .gsp-wt-chevron {
	transform: rotate(-135deg);
}

/* ── Móvil ───────────────────────────────────────────────────────────────────
   767px: el breakpoint móvil de Elementor, que es donde entran los `mobile_default` de los
   controles de tipografía (ver la cabecera). */

@media (max-width: 767px) {
	.gsp-p.gsp-wt {
		--gsp-wt-pad: 11px 12px;
		--gsp-wt-fila-pad: 11px 10px;
		/* 44px de alto mínimo: el objetivo táctil que pide la especificación. */
		--gsp-wt-fila-alto: 44px;
		--gsp-wt-precio-min: 0;
		--gsp-wt-chip-size: 9px;
		--gsp-wt-chip-pad: 3px 6px;
	}

	.gsp-p .gsp-wt-row,
	.gsp-p .gsp-wt-toque {
		gap: 10px;
	}

	.gsp-p .gsp-wt-label {
		font-size: 12.5px;
	}

	.gsp-p .gsp-wt-price {
		font-size: 14px;
	}

	/* La fila libre acorta su etiqueta: con el stepper al lado, «Otra cantidad» no cabe. */

	.gsp-p .gsp-wt-label__largo {
		display: none;
	}

	.gsp-p .gsp-wt-label__corto {
		display: inline;
	}

	/* Botones del stepper a 34×40 y campo a 44×40: los dos por encima del objetivo táctil. */

	.gsp-p .gsp-wt-step {
		width: 34px;
		height: 40px;
	}

	.gsp-p .gsp-wt-stepper .gsp-wt-qty {
		width: 44px;
		height: 40px;
	}
}

/* Por debajo de 360px el resumen y el toggle no caben en la misma línea. */

@media (max-width: 359px) {
	.gsp-p .gsp-wt-foot {
		flex-wrap: wrap;
	}

	.gsp-p .gsp-wt-summary {
		flex: 1 1 100%;
	}

	.gsp-p .gsp-wt-toggle {
		margin-left: auto;
	}
}

/* ── Táctil ──────────────────────────────────────────────────────────────────
   Dos problemas distintos y los dos hay que resolverlos, aunque suenen al mismo. */

/* 1. El zoom de iOS. Safari amplía la página al enfocar CUALQUIER campo con `font-size` menor de
      16px, y luego no vuelve. No hay forma de desactivarlo desde el CSS ni con `user-scalable=no`
      (ignorado desde iOS 10): la única cura es que el campo mida 16px. En su caja de 44×40 se ve
      igual de bien. */

@media (pointer: coarse) {
	.gsp-p .gsp-wt-stepper .gsp-wt-qty {
		font-size: 16px;
	}
}

/* 2. El hover pegado. En una pantalla táctil el `:hover` se queda puesto tras el toque hasta que se
      toca en otro sitio, así que una fila cualquiera acababa pareciendo la elegida. Donde no hay
      ratón, el único feedback es el estado seleccionado y un `:active` mientras se pulsa. */

@media (hover: none) {
	.gsp-p .gsp-wt-row:hover {
		background-color: transparent;
	}

	.gsp-p .gsp-wt-row.is-selected:hover {
		background-color: var(--gsp-wt-fila-on);
	}

	.gsp-p .gsp-wt-row:active {
		background-color: rgba(10, 10, 10, .06);
	}

	.gsp-p .gsp-wt-step:hover {
		background-color: transparent;
		color: var(--gs-txt-3);
	}

	.gsp-p .gsp-wt-step:active {
		background-color: var(--gs-hueso);
		color: var(--gs-tinta);
	}
}

/* El hover de la fila va DESPUÉS del bloque táctil para que dentro de él la regla de arriba pueda
   anularlo; con ratón, esta es la que manda. */

@media (hover: hover) {
	.gsp-p .gsp-wt-row:hover {
		background-color: var(--gsp-wt-fila-hover);
	}

	.gsp-p .gsp-wt-row.is-selected:hover {
		background-color: var(--gsp-wt-fila-on);
	}

	.gsp-p .gsp-wt-row.is-agotado:hover {
		background-color: transparent;
	}
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
	/* `.is-open` va listado aparte porque redeclara su propio `transition` (para quitar el
	   retardo de `visibility` al abrir) con más especificidad (0,3,0) que la regla base (0,2,0):
	   sin listarlo aquí, este reset perdería contra él mientras el panel estuviera abierto y
	   dejaría de respetar «reducir movimiento» justo en ese estado. */
	.gsp-p .gsp-wt-row,
	.gsp-p .gsp-wt-dot,
	.gsp-p .gsp-wt-step,
	.gsp-p .gsp-wt-toggle,
	.gsp-p .gsp-wt-chevron,
	.gsp-p .gsp-wt-hidden,
	.gsp-p .gsp-wt-hidden.is-open {
		transition-duration: .01ms;
	}
}

/* ---- producto-related.css ---- */
/**
 * GS Product Related. Handle 'gs-producto-related' (deps: gs-tarjetas → gs-tokens, gs-fonts).
 *
 * Encabezado propio y parrilla. La TARJETA no se estila aquí: viene de tarjetas.css, del que
 * este archivo depende. Lo único que se toca de ella es el contenedor, porque dentro de este
 * bloque manda su parrilla y no el ancho de maquetación que la parrilla suelta usa cuando va
 * sola en una sección. Mismo criterio que `archivo.css` con `.gsa .gsp-cards`.
 *
 * El widget hereda de `Base\ProductoWidget`, así que `gs-producto-base` viaja igualmente por
 * `get_style_depends()`: la raíz `.gsp-p` y su blindaje anti-Global-Kit están disponibles.
 */

.gsp-p.gsp-rel {
	--gsp-rel-titulo: var(--gs-tinta);
	--gsp-rel-ver: var(--gs-oro);
	/* El borde del enlace es más tenue que su texto. Va como variable propia y no con
	   `color-mix()` sobre el color del texto: aquella función no está en navegadores algo
	   antiguos y el borde desaparecería del todo, no se degradaría. */
	--gsp-rel-ver-borde: rgba(156, 122, 52, .4);
	--gsp-rel-gap: 18px;
	--gsp-rel-head-gap: 40px;
}

/* ── Encabezado ──────────────────────────────────────────────────────────────
   `baseline` y no `center`: el título mide 34px y el enlace 11, y centrarlos dejaría el «Ver
   todos» flotando a media altura en vez de asentado sobre la misma línea base. */

.gsp-p .gsp-rel__head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 24px;
	margin-bottom: var(--gsp-rel-head-gap);
}

/* El selector incluye la clase del componente además de la raíz porque los temas estilan los
   encabezados dentro del contenido con reglas agresivas (`.entry-content h2`). */

.gsp-p .gsp-rel__titulo {
	font-family: var(--gs-font-display);
	font-weight: 700;
	font-size: 34px;
	line-height: 1.1;
	text-transform: uppercase;
	color: var(--gsp-rel-titulo);
	margin: 0;
	padding: 0;
}

/* «Ver todos» lleva `.gsp-i` y declara sus tres estados prefijados por la raíz (0,3,0), con
   fondo Y color, que es lo que le gana al Global Kit (0,2,1).

   El subrayado es un `border-bottom` y no un `text-decoration` porque el diseño lo quiere
   separado del texto (2px por debajo) y con su propia opacidad, cosa que `text-underline-offset`
   no consigue de forma consistente entre navegadores. */

.gsp-p .gsp-rel__ver {
	flex: 0 0 auto;
	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: 11px;
	line-height: 1.4;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--gsp-rel-ver);
	background-color: transparent;
	text-decoration: none;
	border-bottom: 1px solid var(--gsp-rel-ver-borde);
	padding-bottom: 2px;
	white-space: nowrap;
	transition: color .18s var(--gs-e-soft), border-color .18s var(--gs-e-soft);
}

.gsp-p .gsp-rel__ver:hover,
.gsp-p .gsp-rel__ver:focus,
.gsp-p .gsp-rel__ver:active {
	color: var(--gs-tinta);
	background-color: transparent;
	text-decoration: none;
	border-bottom-color: var(--gs-tinta);
}

/* ── Parrilla ────────────────────────────────────────────────────────────────
   La tarjeta suelta se centra con `max-width: 80rem; margin-inline: auto` porque cuando va sola
   en una sección necesita ese ancho de maquetación. Aquí NO: el contenedor de Elementor donde se
   coloca el widget ya define el ancho, y dejar el de la parrilla la centraría dentro de él,
   desalineándola del resto de la ficha. */

.gsp-p .gsp-rel__grid {
	max-width: none;
	margin-inline: 0;
	gap: var(--gsp-rel-gap);
}

/* ── Móvil ───────────────────────────────────────────────────────────────────
   El encabezado pasa a columna: a 360px, un título de 26px y el «Ver todos» en la misma fila
   dejan al enlace sin sitio. */

@media (max-width: 560px) {
	.gsp-p .gsp-rel__head {
		flex-direction: column;
		align-items: flex-start;
		gap: 12px;
	}

	.gsp-p .gsp-rel__titulo {
		font-size: 26px;
	}
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
	.gsp-p .gsp-rel__ver {
		transition-duration: .01ms;
	}
}

/* ---- producto-tabs.css ---- */
/**
 * GS Product Tabs. Handle 'gs-producto-tabs' (dep: gs-producto-base → gs-tokens, gs-fonts).
 *
 * Tres bloques en un archivo, porque son un solo widget: la barra de pestañas, la tabla de
 * especificaciones (compartida por los paneles 1 y 2) y el panel de reseñas.
 *
 * Dos cosas que conviene tener presentes al leerlo:
 *
 * · **El estado activo vive en los atributos ARIA**, no en una clase paralela: los selectores son
 *   `[aria-selected="true"]` y `[hidden]`. Así el CSS no puede quedarse describiendo un estado que
 *   el árbol de accesibilidad ya no tiene — si el JS se olvidara de una clase, la pestaña se vería
 *   activa sin serlo.
 * · **El acordeón de móvil cambia de roles, no solo de pinta.** El JS pone `role="region"` y
 *   reapunta el `aria-labelledby` al disparador; aquí solo se decide qué se ve. Ver la cabecera de
 *   producto-tabs.js.
 *
 * Los botones llevan `.gsp-i` en el markup (exentos del neutralizador de producto-base.css) y
 * declaran sus tres estados prefijados por la raíz → 0,3,0, con fondo Y color, que es lo que le
 * gana al Global Kit (0,2,1).
 */

.gsp-p.gsp-tabs {
	--gsp-tb-linea: var(--gs-linea);
	--gsp-tb-tab: var(--gs-txt-3);
	--gsp-tb-tab-hover: var(--gs-txt-2);
	--gsp-tb-tab-on: var(--gs-tinta);
	--gsp-tb-borde-on: var(--gs-oro);
	--gsp-tb-head-gap: 40px;

	--gsp-tb-subtitulo: var(--gs-tinta);
	--gsp-tb-cuerpo: var(--gs-txt-2);
	--gsp-tb-specs-label: var(--gs-txt-3);
	--gsp-tb-specs-valor: var(--gs-tinta);
	--gsp-tb-texto-max: 640px;

	--gsp-tb-promedio: var(--gs-txt-2);
	--gsp-tb-estrella: var(--gs-tinta);
	--gsp-tb-rev-gap: 28px;

	--gsp-tb-cierre-gap: 80px;
	--gsp-tb-cierre-linea: var(--gs-linea);
}

/* ── Cierre del widget ───────────────────────────────────────────────────────
   El espacio va suelto y la línea detrás de `has-divider`, y NO juntos como en el widget de
   precio: allí el relleno es el respiro de la divisoria y sin ella sobra, aquí el respiro cierra
   el bloque de pestañas exista línea o no. Quien tenga ya un borde en el contenedor de abajo
   apaga la divisoria y se queda con el espacio, que es justo el caso que motiva separarlos. */

.gsp-p.gsp-tabs {
	padding-bottom: var(--gsp-tb-cierre-gap);
}

.gsp-p.gsp-tabs.has-divider {
	border-bottom: 1px solid var(--gsp-tb-cierre-linea);
}

/* ── Barra de pestañas ───────────────────────────────────────────────────────
   `gap: 0` es del diseño: las pestañas se separan por su propio relleno, no por hueco, para que
   el subrayado de la activa llegue hasta el borde de su zona pulsable. */

.gsp-p .gsp-tabs__barra {
	display: flex;
	gap: 0;
	border-bottom: 1px solid var(--gsp-tb-linea);
	margin-bottom: var(--gsp-tb-head-gap);
}

/* El selector incluye la etiqueta (`button.gsp-tabs__tab`) porque el reset de `button` de
   producto-base.css es 0,1,1 y una clase suelta no le gana el padding. */

.gsp-p button.gsp-tabs__tab {
	flex: 0 0 auto;
	padding: 16px 28px;
	background-color: transparent;
	border: 0;
	/* El subrayado de la activa se dibuja en este borde, que existe siempre en transparente: si
	   apareciera solo al activarse, la pestaña crecería 2px y la fila daría un salto. */
	border-bottom: 2px solid transparent;
	/* Sube 1px para que ese borde tape la línea de la barra en vez de apilarse debajo. */
	margin-bottom: -1px;
	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: 11.5px;
	line-height: 1;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--gsp-tb-tab);
	cursor: pointer;
	transition: color .2s var(--gs-e-soft), border-color .2s var(--gs-e-soft);
}

.gsp-p .gsp-tabs__tab:hover,
.gsp-p .gsp-tabs__tab:focus,
.gsp-p .gsp-tabs__tab:active {
	background-color: transparent;
	color: var(--gsp-tb-tab-hover);
}

/* La activa gana a las reglas de hover por el atributo (0,4,0): pasar el ratón por la pestaña en
   la que ya estás no debe aclarar su texto. */

.gsp-p .gsp-tabs__tab[aria-selected="true"],
.gsp-p .gsp-tabs__tab[aria-selected="true"]:hover,
.gsp-p .gsp-tabs__tab[aria-selected="true"]:focus,
.gsp-p .gsp-tabs__tab[aria-selected="true"]:active {
	background-color: transparent;
	font-weight: 700;
	color: var(--gsp-tb-tab-on);
	border-bottom-color: var(--gsp-tb-borde-on);
}

/* `[hidden]` no se deja al navegador: su `display: none` de hoja de usuario lo pisa cualquier
   `display` que herede el panel de un contenedor de Elementor. */

.gsp-p .gsp-tabs__panel[hidden] {
	display: none;
}

/* Y la barra, por lo mismo. `aplicarModo()` le pone `hidden` al entrar en modo acordeón, pero el
   `display: flex` de `.gsp-p .gsp-tabs__barra` es (0,2,0) y el `[hidden]` de la hoja de usuario
   (0,1,0) pierde.

   Comprobado: hoy no se ve, porque el acordeón solo se activa por debajo de los 900px
   (`aplicarModo(modoAcordeon && mq.matches)`) y ahí ya lo esconde
   `.is-acordeon .gsp-tabs__barra`, que es (0,3,0). Pero eso deja el estado dependiendo del ANCHO
   de la ventana en vez del atributo que el JS acaba de poner: el día que el acordeón se pueda
   forzar desde el panel —o que cambie el corte—, la barra reaparece. Con su regla propia el
   `hidden` significa lo que dice, que es lo que ya hacen las otras cuatro hojas de producto. */

.gsp-p .gsp-tabs__barra[hidden] {
	display: none;
}

/* ── Disparador del acordeón ─────────────────────────────────────────────────
   Fuera de móvil no existe: la barra hace su trabajo. */

.gsp-p .gsp-tabs__acordeon {
	display: none;
}

/* ── Panel 1 · Descripción ──────────────────────────────────────────────────── */

.gsp-p .gsp-tabs__subtitulo {
	font-family: var(--gs-font-display);
	font-weight: 700;
	font-size: 26px;
	line-height: 1.15;
	text-transform: uppercase;
	color: var(--gsp-tb-subtitulo);
	margin: 0 0 16px;
	padding: 0;
}

/* El tope de ancho va en el texto y no en el panel: el panel lo comparten los tres, y acotarlo
   ahí encogería también la tabla de especificaciones y la lista de reseñas, que tienen su propia
   medida. El blanco a la derecha es del diseño, no un contenedor sin cerrar. */

.gsp-p .gsp-tabs__texto {
	max-width: var(--gsp-tb-texto-max);
	font-family: var(--gs-font-body);
	font-size: 14.5px;
	line-height: 1.75;
	color: var(--gsp-tb-cuerpo);
}

/* Los párrafos son los que escribió la tienda: se respeta su separación y se le quita el margen
   al último, que si no deja un hueco muerto al final del panel. */

.gsp-p .gsp-tabs__texto p {
	margin: 0 0 16px;
}

.gsp-p .gsp-tabs__texto p:last-child {
	margin-bottom: 0;
}

.gsp-p .gsp-tabs__texto ul,
.gsp-p .gsp-tabs__texto ol {
	margin: 0 0 16px;
	padding-left: 1.25em;
}

.gsp-p .gsp-tabs__texto li {
	margin-bottom: 6px;
}

/* ── Panel sin datos ─────────────────────────────────────────────────────────
   Misma tipografía que el cuerpo —familia, tamaño y altura de línea— y solo cambia el color, al
   gris de los metadatos: se lee como una nota al margen, no como contenido del producto. Con esto
   las tres pestañas se ven siempre; antes, un producto sin descripción ni atributos perdía dos de
   las tres y la barra entera, y la ficha caía directa en Reseñas. */

.gsp-p .gsp-tabs__vacio {
	margin: 0;
	font-family: var(--gs-font-body);
	font-size: 14.5px;
	line-height: 1.75;
	color: var(--gs-txt-3);
}

/* ── Tabla de especificaciones (paneles 1 y 2) ───────────────────────────────
   Es una `<dl>`: pares término/definición. El `display: flex` en la fila y no en la lista es lo
   que permite que el `<dt>` y el `<dd>` se repartan la línea sin tocar su semántica. */

.gsp-p .gsp-specs {
	display: flex;
	flex-direction: column;
	gap: 0;
	margin: 0;
	font-family: var(--gs-font-body);
	font-size: 13.5px;
	line-height: 1.5;
}

.gsp-p .gsp-specs.is-acotada {
	max-width: 640px;
}

.gsp-p .gsp-specs__fila {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 24px;
	padding: 14px 0;
	border-bottom: 1px solid var(--gsp-tb-linea);
}

/* La última fila no lleva línea: cerraría la tabla con un borde suelto que el diseño no tiene. */

.gsp-p .gsp-specs__fila:last-child {
	border-bottom: 0;
}

.gsp-p .gsp-specs__label {
	flex: 0 0 auto;
	color: var(--gsp-tb-specs-label);
	margin: 0;
}

.gsp-p .gsp-specs__valor {
	/* `min-width: 0` para que un valor largo pueda partirse en vez de desbordar la fila. */
	min-width: 0;
	margin: 0;
	text-align: right;
	color: var(--gsp-tb-specs-valor);
}

.gsp-p .gsp-specs__sep {
	color: var(--gsp-tb-specs-label);
}

.gsp-p .gsp-specs__link {
	color: var(--gs-oro);
	text-decoration: none;
	border-bottom: 1px solid transparent;
}

.gsp-p .gsp-specs__link:hover,
.gsp-p .gsp-specs__link:focus,
.gsp-p .gsp-specs__link:active {
	background-color: transparent;
	color: var(--gs-oro-osc);
	border-bottom-color: currentColor;
}

/* ── Guía de tallas ──────────────────────────────────────────────────────────
   Esta SÍ es una `<table>` y la de especificaciones es una `<dl>`, y no es una incoherencia: allí
   cada término nombra a su propio valor, y aquí las cabeceras nombran COLUMNAS enteras. El
   razonamiento largo está en `Woo\TallasRenderer`.

   No estrena ni un token ni un control: consume las MISMAS variables que la tabla de
   especificaciones —`--gsp-tb-specs-label`, `--gsp-tb-specs-valor`, `--gsp-tb-linea`—, que se
   escriben sobre `{{WRAPPER}} .gsp-tabs` y heredan hasta aquí. Es el rédito de la regla de
   INSTRUCCIONES §3.3: color por variable y nunca por propiedad. La tipografía la hereda por el
   selector ampliado del control `specs_tipo`. */

.gsp-p .gsp-tallas__caja {
	/* Red de seguridad para un título largo —«Contorno de pecho (cm)»— en una pantalla estrecha.
	   Sin `tabindex` en el markup: con la tabla al ancho del panel esto no desborda en la
	   práctica, y un contenedor que nunca desplaza pero sí recibe el foco es una parada de
	   tabulación muerta para quien navega con teclado. */
	overflow-x: auto;
}

.gsp-p .gsp-tallas {
	/* ── La MISMA medida que «Información adicional» ──────────────────────
	   640px, que es exactamente el `max-width` de `.gsp-specs.is-acotada` —el panel se lo pasa
	   como `max_width` al pintarla— así que las dos tablas de la pestaña terminan en la misma
	   vertical. No es un número elegido: es el suyo.

	   Estuvo acotada a 360 y quedaba diminuta al lado de su vecina. En una captura a 1,25× de
	   escala esos 640 se ven como 800, que es lo que confundió la primera medida.

	   Y con `width: 100%` por debajo del tope, en móvil ocupa lo que haya sin desbordar: dos
	   columnas de dos cifras caben en cualquier pantalla, y el `overflow-x` de la caja queda de
	   red por si algún día un título es larguísimo. */
	width: 100%;
	max-width: 640px;
	border-collapse: collapse;
	font-family: var(--gs-font-body);
	font-size: 13.5px;
	line-height: 1.5;

	/* Cifras de ancho fijo: en una columna de tallas, `11` y `44` tienen que ocupar lo mismo o la
	   columna se ve temblorosa al recorrerla. */
	font-variant-numeric: tabular-nums;
}

/* ── Apagar TODOS los bordes antes de poner el nuestro ───────────────────────
   Esto es lo que de verdad estaba mal, y no se podía deducir leyendo esta hoja: **el tema pinta
   bordes en `table`, `th` y `td`**, y aquí solo se declaraba el de abajo. Resultado en pantalla:
   líneas verticales entre las columnas y a los lados, y la tabla dibujada como una hoja de
   cálculo justo al lado de una `.gsp-specs` que no tiene ni una raya vertical.

   La `<dl>` de especificaciones nunca tuvo el problema porque no es una tabla. Esta es la primera
   `<table>` propia del panel, así que es la primera que hereda ese estilo — y por eso hay que
   apagarlo explícitamente en los tres niveles, no solo en las celdas. */

.gsp-p .gsp-tallas,
.gsp-p .gsp-tallas thead,
.gsp-p .gsp-tallas tbody,
.gsp-p .gsp-tallas tr,
.gsp-p .gsp-tallas th,
.gsp-p .gsp-tallas td {
	border: 0;
	background-color: transparent;
}

/* ── Y ahora, la única línea que sí queremos ─────────────────────────────────
   `padding` y filete calcados de `.gsp-specs__fila`, para que las dos tablas de la pestaña se
   lean como el mismo objeto sin tener que acordarse de mantenerlas a mano.

   `font-style: normal` sigue siendo necesario: la hoja de WooCommerce pone en cursiva los valores
   de cualquier tabla del contenido. */

.gsp-p .gsp-tallas th,
.gsp-p .gsp-tallas td {
	padding: 14px 0;
	border-bottom: 1px solid var(--gsp-tb-linea);
	font-style: normal;
	text-align: left;
}

/* ── La cabecera no parece una fila: parece un rótulo ────────────────────────
   Es la opción que eligió la tienda. Los nombres de las columnas se leen como una etiqueta
   pequeña por encima de la tabla, y lo que queda debajo es exactamente `.gsp-specs`: pares de
   dato y valor separados por un filete, sin ninguna fila que se distinga de las demás.

   Se consigue estilando el `<thead>`, NO sacándolo del markup a un `<p>`. Visualmente da lo
   mismo; semánticamente no: unos `<th scope="col">` de verdad son lo que hace que un lector de
   pantalla anuncie «Centímetros, 23» al pararse en la celda, y un párrafo suelto encima de la
   tabla no ata nada con nada. Además el rótulo así se alinea con el borde REAL de cada columna y
   no con los extremos de la caja.

   Sin filete propio: la línea que hay bajo él es la de la primera fila del cuerpo, que es la que
   ya existía. Dos líneas seguidas volverían a dibujar una cabecera de tabla, que es justo lo que
   esta opción no quiere. */

.gsp-p .gsp-tallas thead th {
	padding: 0 0 6px;
	border-bottom: 0;
	color: var(--gsp-tb-specs-label);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: .09em;
	text-transform: uppercase;
}

/* Y el cuerpo, calcado de `.gsp-specs`: la talla en el gris de etiqueta a la izquierda y la
   medida en la tinta del dato a la derecha. Los dos colores salen de las variables del panel, así
   que recolorear la tabla de especificaciones desde Elementor cambia esta a juego. */

.gsp-p .gsp-tallas tbody td:first-child {
	color: var(--gsp-tb-specs-label);
	font-weight: 400;
}

.gsp-p .gsp-tallas tbody td:last-child {
	color: var(--gsp-tb-specs-valor);
	font-weight: 400;
}

/* La segunda columna a la derecha, igual que el valor de `.gsp-specs` y el de la tabla nativa de
   Woo: es lo que ata cada dato a su cabecera en vez de dejarlo flotando a media anchura. */

.gsp-p .gsp-tallas th:last-child,
.gsp-p .gsp-tallas td:last-child {
	text-align: right;
}

/* La última fila no lleva línea: cerraría la tabla con un borde suelto que el diseño no tiene.
   Misma decisión que en `.gsp-specs__fila`. Solo `td`: el `tbody` no emite cabeceras de fila. */

.gsp-p .gsp-tallas tbody tr:last-child td {
	border-bottom: 0;
}

/* Salida NATIVA de Woo (control `info_source`). Se estiliza su tabla para que se parezca a la
   nuestra, sin sobrescribir la plantilla: el tema puede tenerla ya sobrescrita y pelearse con él
   solo traería sorpresas. Es una `<table>` de verdad, así que aquí sí hay celdas. */

.gsp-p .gsp-tabs__woo table {
	width: 100%;
	max-width: 640px;
	border-collapse: collapse;
	font-family: var(--gs-font-body);
	font-size: 13.5px;
	line-height: 1.5;
}

/* `font-style` y `background-color` se declaran explícitamente porque la hoja de WooCommerce pone
   los valores en cursiva y pinta las filas alternas en gris. Verificado en pantalla: sin esto la
   misma tabla se veía en cursiva y a rayas en el panel nativo, y recta y limpia en el propio. */

.gsp-p .gsp-tabs__woo th,
.gsp-p .gsp-tabs__woo td {
	padding: 14px 0;
	background-color: transparent;
	border-bottom: 1px solid var(--gsp-tb-linea);
	text-align: left;
	font-weight: 400;
	font-style: normal;
}

.gsp-p .gsp-tabs__woo tr {
	background-color: transparent;
}

.gsp-p .gsp-tabs__woo th {
	color: var(--gsp-tb-specs-label);
}

.gsp-p .gsp-tabs__woo td {
	color: var(--gsp-tb-specs-valor);
	text-align: right;
}

.gsp-p .gsp-tabs__woo tr:last-child th,
.gsp-p .gsp-tabs__woo tr:last-child td {
	border-bottom: 0;
}

.gsp-p .gsp-tabs__woo p {
	margin: 0;
}

/* ── Panel 3 · Reseñas ───────────────────────────────────────────────────────
   Minimalista: una cabecera de una línea —estrellas en tinta, «4.7 estrellas» y el botón
   enfrentado— y debajo la lista, plana y separada por filetes.

   Ni tarjeta de resumen con el promedio a 64px, ni barras por estrella, ni reseñas en cajas con
   fondo, borde y radio. Las tres se construyeron y el diseño las descartó; si vuelven, están en el
   historial. La única línea horizontal del panel es la que separa cada reseña de la anterior. */

/* Estrellas. El tamaño se da en `width`/`height` y no con `font-size` porque son SVG sin
   dimensiones propias (Support\Icons no las escribe, para que el CSS decida). `gap` en vez del
   `letter-spacing` del diseño: no hay glifos que espaciar. */

.gsp-p .gsp-estrellas {
	display: inline-flex;
	align-items: center;
	gap: 2px;
	color: var(--gsp-tb-estrella);
}

.gsp-p .gsp-estrella {
	width: 1em;
	height: 1em;
}

.gsp-p .gsp-rev__estrellas-grandes {
	font-size: 15px;
}

/* ── Cabecera: valoración y botón ────────────────────────────────────────────
   `space-between` y no `flex-end`: son los dos extremos de la misma fila. `flex-wrap` porque con el
   texto traducido a un idioma largo los dos no caben en pantallas estrechas.

   Sin `border-bottom`: la línea que separa la cabecera de la lista es el `border-top` de la primera
   reseña. Declarando las dos salían dos filetes con el hueco de por medio. */

.gsp-p .gsp-rev__cabecera {
	display: flex;
	align-items: center;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: 16px;
	margin-bottom: var(--gsp-tb-rev-gap);
}

.gsp-p .gsp-rev__valoracion {
	display: inline-flex;
	align-items: center;
	gap: 10px;
}

.gsp-p .gsp-rev__promedio {
	margin: 0;
	font-family: var(--gs-font-body);
	font-size: 13px;
	line-height: 1.4;
	color: var(--gsp-tb-promedio);
}

/* Sin reseñas, apagada. Se llegó a ocultar del todo y quedaba peor: el botón suelto a la derecha
   con un hueco al lado, que se lee como que algo no ha cargado. Se pinta igual —cinco estrellas
   vacías y el promedio a cero— y solo cambia el tono.

   Las estrellas vacías son un CONTORNO que hereda el color del contenedor, así que sin esto
   saldrían las cinco en el color de una valoración real y el «0.0» al lado parecería una
   puntuación de cero en vez de la ausencia de puntuación.

   No se usa `--gs-estrella-off` —el de la estrella sin elegir del formulario— aunque el significado
   sea parecido: allí son glifos macizos de 32px y aquí contornos de 15 con un trazo de 1px, y ese
   tono se perdía contra el fondo. Verificado en pantalla. */

.gsp-p .gsp-rev__valoracion.is-vacio .gsp-rev__promedio,
.gsp-p .gsp-rev__valoracion.is-vacio .gsp-estrellas {
	color: var(--gs-txt-4);
}

/* El botón se mantiene a la derecha aunque la valoración faltara por cualquier otro motivo: con
   `space-between` y un solo hijo se iría a la izquierda. */

.gsp-p .gsp-rev__cabecera .gsp-rev__abrir {
	margin-left: auto;
}

/* Lista de reseñas */

.gsp-p .gsp-rev__col {
	/* `min-width: 0` para que una palabra larga en una reseña no desborde el panel. */
	min-width: 0;
}

/* Sin `gap`: la separación la da el relleno de cada reseña, y el filete tiene que quedar pegado
   entre dos, no flotando en un hueco. El de abajo cierra la lista igual que el `border-top` de la
   primera la abre.

   Se cierra con `border-bottom` en la lista y no con un `<div>` vacío al final: un nodo sin
   contenido es ruido para un lector de pantalla, y además así el cierre sigue en su sitio solo
   cuando «Ver más» añade tarjetas por AJAX. */

.gsp-p .gsp-rev__lista {
	display: flex;
	flex-direction: column;
	border-bottom: 1px solid var(--gsp-tb-linea);
}

/* Plana: ni fondo, ni borde de caja, ni radio, ni relleno lateral. El texto arranca en el mismo
   margen que la cabecera y que el resto de la página. */

.gsp-p .gsp-rev__card {
	padding: 20px 0;
	border-top: 1px solid var(--gsp-tb-linea);
}

.gsp-p .gsp-rev__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	margin-bottom: 8px;
}

.gsp-p .gsp-rev__quien {
	display: flex;
	align-items: center;
	gap: 12px;
	min-width: 0;
}

.gsp-p .gsp-rev__avatar {
	width: 36px;
	height: 36px;
	border-radius: 50%;
	flex: 0 0 auto;
}

.gsp-p .gsp-rev__autor {
	display: flex;
	flex-direction: column;
	gap: 3px;
	min-width: 0;
}

.gsp-p .gsp-rev__nombre {
	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: 13px;
	line-height: 1.2;
	color: var(--gs-tinta);
}

/* Las estrellas de una reseña ocupan su propia línea, entre la cabecera y el texto. */

.gsp-p .gsp-rev__estrellas {
	font-size: 12px;
	margin-bottom: 8px;
}

.gsp-p .gsp-rev__meta {
	flex: 0 0 auto;
	font-family: var(--gs-font-body);
	font-size: 11px;
	line-height: 1.3;
	color: var(--gs-txt-3);
	text-align: right;
}

.gsp-p .gsp-rev__texto {
	font-family: var(--gs-font-body);
	font-size: 13.5px;
	line-height: 1.65;
	color: var(--gs-txt-2);
	/* Una reseña puede traer una URL sin espacios: se parte antes que desbordar la tarjeta. */
	overflow-wrap: break-word;
}

.gsp-p .gsp-rev__texto p {
	margin: 0 0 10px;
}

.gsp-p .gsp-rev__texto p:last-child {
	margin-bottom: 0;
}

.gsp-p .gsp-rev__vacio {
	font-family: var(--gs-font-body);
	font-size: 13.5px;
	color: var(--gs-txt-3);
	margin: 0;
}

/* ── Paginación ──────────────────────────────────────────────────────────────
   «Ver más» repite el tratamiento del botón de escribir —contorno en tinta— pero algo más alto y
   centrado bajo la lista. Estuvo en dorado; el diseño dejó el oro fuera de este panel. */

.gsp-p button.gsp-rev__mas {
	display: flex;
	align-items: center;
	justify-content: center;
	height: 44px;
	margin: 16px auto 0;
	padding: 0 24px;
	background-color: transparent;
	color: var(--gs-tinta);
	border: 1.5px solid var(--gs-tinta);
	border-radius: 8px;
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 12px;
	line-height: 1;
	letter-spacing: .1em;
	text-transform: uppercase;
	cursor: pointer;
	transition: background-color .2s var(--gs-e-soft), color .2s var(--gs-e-soft);
}

.gsp-p .gsp-rev__mas:hover,
.gsp-p .gsp-rev__mas:focus,
.gsp-p .gsp-rev__mas:active {
	background-color: var(--gs-hueso);
	color: var(--gs-tinta);
}

/* Mientras carga: `aria-disabled` y NO el atributo `disabled` (INSTRUCCIONES.md §6). Un botón
   deshabilitado de verdad pierde el foco, y quien lo hubiera pulsado con el teclado se quedaría
   sin punto de referencia justo cuando llega el contenido nuevo. */

.gsp-p .gsp-rev__mas[aria-disabled="true"] {
	opacity: .55;
	cursor: progress;
}

.gsp-p .gsp-rev__paginas {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	margin-top: 16px;
}

.gsp-p button.gsp-rev__pagina {
	min-width: 34px;
	height: 34px;
	padding: 0 8px;
	background-color: transparent;
	color: var(--gs-txt-2);
	border: 1px solid var(--gsp-tb-linea);
	border-radius: var(--gs-r-sm);
	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: 11.5px;
	line-height: 1;
	cursor: pointer;
	transition: background-color .2s var(--gs-e-soft), color .2s var(--gs-e-soft), border-color .2s var(--gs-e-soft);
}

.gsp-p .gsp-rev__pagina:hover,
.gsp-p .gsp-rev__pagina:focus,
.gsp-p .gsp-rev__pagina:active {
	background-color: var(--gs-hueso);
	color: var(--gs-tinta);
	border-color: var(--gsp-tb-linea);
}

/* La página en curso se marca por `aria-current`, que es el estado real, no por una clase. */

.gsp-p .gsp-rev__pagina[aria-current="true"],
.gsp-p .gsp-rev__pagina[aria-current="true"]:hover,
.gsp-p .gsp-rev__pagina[aria-current="true"]:focus {
	background-color: var(--gs-tinta);
	color: #fff;
	border-color: var(--gs-tinta);
	cursor: default;
}

/* ── Ventana del formulario ──────────────────────────────────────────────────
   El JS PORTALEA `.gsp-rev__modal` a <body>, así que el nodo lleva su propia clase `gsp-p` y estas
   reglas siguen casando fuera del widget. Por el mismo motivo aquí se usan los tokens globales
   `--gs-*` (viven en `:root` y sobreviven al traslado) en vez de las `--gsp-tb-*`, que se declaran
   en `.gsp-tabs` y se quedarían atrás. Las dos que sí se pueden configurar desde Elementor
   (`--gsp-tb-badge` y `--gsp-tb-estrella-on`) se escriben también en `:root` desde el widget. */

.gsp-p.gsp-rev__modal {
	position: fixed;
	inset: 0;
	z-index: var(--gs-z-modal);
}

/* ── Entrada y salida ────────────────────────────────────────────────────────
   La ventana aparecía de golpe: `abrir()` quitaba el `hidden` y ya. Ahora entra con transición,
   y hay tres decisiones detrás que conviene no deshacer:

   · **Transiciones y no `@keyframes`.** Una transición se puede interrumpir y retomar desde donde
     esté; un keyframe reinicia desde cero. Abrir y cerrar rápido dos veces seguidas con keyframes
     da un salto, y este modal se abre desde un botón que invita a probarlo.
   · **Solo `transform` y `opacity`.** Son las dos que el navegador compone en la GPU sin recalcular
     diseño ni repintar (INSTRUCCIONES.md §8).
   · **La salida es más rápida que la entrada.** Al entrar el usuario está mirando y la animación
     explica de dónde sale la ventana; al salir ya ha decidido, y cualquier espera se lee como
     lentitud.

   El estado lo lleva `.is-abierto`, que pone el JS DESPUÉS de quitar el `hidden`: desde
   `display: none` no transiciona nada. */

.gsp-p .gsp-rev__velo {
	position: absolute;
	inset: 0;
	background-color: rgba(10, 10, 10, .55);
	backdrop-filter: blur(3px);
	opacity: 0;
	transition: opacity 180ms var(--gs-e-out);
}

.gsp-p.gsp-rev__modal.is-abierto .gsp-rev__velo {
	opacity: 1;
	transition-duration: 240ms;
}

.gsp-p .gsp-rev__caja {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	z-index: var(--gs-z-modal-caja);
	width: 480px;
	max-width: calc(100vw - 40px);
	padding: 28px;
	background-color: #fff;
	border-radius: var(--gs-r-2xl);
	/* Sin `max-height` ni scroll: la ventana se dimensiona a su contenido, que es corto y conocido
	   (puntuación y un textarea). El panel inferior de móvil sí lo lleva, porque ahí el teclado
	   virtual se come media pantalla. */
	box-shadow: 0 24px 64px rgba(10, 10, 10, .22);
	/* Se entra desde 0.96 y NUNCA desde 0: nada en el mundo real aparece de la nada, y una
	   ventana que crece desde un punto se lee como un truco. Desde 0.96 parece que ya estaba
	   ahí y solo se ha acercado. El `translate(-50%,-50%)` se repite porque es lo que la
	   centra: perderlo aquí la mandaría a la esquina. */
	opacity: 0;
	transform: translate(-50%, -50%) scale(.96);
	transition: opacity 160ms var(--gs-e-out), transform 160ms var(--gs-e-out);
}

.gsp-p.gsp-rev__modal.is-abierto .gsp-rev__caja {
	opacity: 1;
	transform: translate(-50%, -50%) scale(1);
	transition-duration: 220ms;
}

/* La manija solo existe en el panel inferior. */

.gsp-p .gsp-rev__manija {
	display: none;
	width: 36px;
	height: 4px;
	margin: 0 auto 14px;
	border-radius: var(--gs-r-pill);
	background-color: var(--gs-manija);
}

.gsp-p .gsp-rev__caja-head {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 16px;
}

.gsp-p .gsp-rev__caja-titulo {
	margin: 0;
	font-family: var(--gs-font-display);
	font-weight: 700;
	font-size: 21px;
	line-height: 1.2;
	letter-spacing: .01em;
	text-transform: uppercase;
	color: var(--gs-tinta);
}

.gsp-p button.gsp-rev__cerrar {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 28px;
	height: 28px;
	padding: 0;
	border: 0;
	background-color: transparent;
	color: var(--gs-txt-3);
	cursor: pointer;
	transition: color .18s var(--gs-e-soft);
}

.gsp-p .gsp-rev__cerrar:hover,
.gsp-p .gsp-rev__cerrar:focus,
.gsp-p .gsp-rev__cerrar:active {
	background-color: transparent;
	color: var(--gs-tinta);
}

.gsp-p .gsp-rev__cerrar svg {
	width: 15px;
	height: 15px;
}

.gsp-p .gsp-rev__caja-sub {
	margin: 4px 0 0;
	padding-bottom: 18px;
	border-bottom: 1px solid var(--gs-linea);
	font-family: var(--gs-font-body);
	font-size: 12.5px;
	line-height: 1.4;
	color: var(--gs-txt-3);
}

/* ── Panel inferior (móvil, o forzado con `review_form_style`) ────────────────
   Mismo formulario, otro contenedor: solo cambian el anclaje y las alturas de toque.

   El anclaje va sobre `--gs-vv-fondo` y la altura sobre `--gs-vv-alto`, que publica
   `GSHeader.seguirViewport()` mientras la hoja está abierta. Aquí importa más que en ningún
   otro sitio: una reseña se escribe con el teclado abierto TODO el rato, y sin esto la hoja se
   quedaba debajo del teclado —el `vh` es justo la unidad que no encoge cuando sale— con la
   página de detrás asomando por la franja. Sin `visualViewport` mandan los respaldos, que son
   el `bottom: 0` y el `82vh` de siempre. */

.gsp-p.gsp-rev__modal.is-sheet .gsp-rev__caja {
	top: auto;
	bottom: var(--gs-vv-fondo, 0px);
	left: 0;
	width: 100%;
	max-width: none;
	max-height: calc(var(--gs-vv-alto, 100vh) * .82);
	overflow-y: auto;
	border-radius: 20px 20px 0 0;
	/* En PORCENTAJE, nunca en píxeles: el panel mide lo que mida su contenido, y un valor fijo
	   dejaría un panel bajo asomando por debajo o uno alto arrancando fuera de pantalla.
	   `translateY(100%)` es exactamente su propia altura, sea cual sea. */
	opacity: 1;
	transform: translateY(100%);
	transition: transform 220ms var(--gs-e-sheet);
}

.gsp-p.gsp-rev__modal.is-sheet.is-abierto .gsp-rev__caja {
	transform: translateY(0);
	transition-duration: 320ms;
}

.gsp-p.gsp-rev__modal.is-sheet .gsp-rev__manija {
	display: block;
}

/* Contorno en tinta y de ancho automático, a la derecha de la cabecera. Vive fuera del nodo de la
   valoración —aunque estén en la misma fila— porque ese nodo lo reemplaza el JS al publicar y este
   botón es a quien el modal le devuelve el foco al cerrarse. */

.gsp-p button.gsp-rev__abrir {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	height: 40px;
	padding: 0 20px;
	border: 1.5px solid var(--gs-tinta);
	border-radius: 8px;
	background-color: transparent;
	color: var(--gs-tinta);
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 11px;
	line-height: 1;
	letter-spacing: .1em;
	text-transform: uppercase;
	white-space: nowrap;
	cursor: pointer;
	transition: background-color .2s var(--gs-e-soft), color .2s var(--gs-e-soft);
}

/* Hover suave y NO inversión a fondo negro: el diseño lo quiere discreto, y en negro competía con
   el botón de comprar de la ficha. El color se redeclara aunque no cambie, que es el contrato de
   la casa para todo `:hover` propio. */

.gsp-p .gsp-rev__abrir:hover,
.gsp-p .gsp-rev__abrir:focus,
.gsp-p .gsp-rev__abrir:active {
	background-color: var(--gs-hueso);
	color: var(--gs-tinta);
}

/* ── Formulario ────────────────────────────────────────────────────────────── */

.gsp-p .gsp-rev__form {
	margin-top: 18px;
}

.gsp-p .gsp-rev__nota {
	display: flex;
	align-items: center;
	gap: 8px;
	font-family: var(--gs-font-body);
	font-size: 12.5px;
	line-height: 1.5;
	color: var(--gs-txt-3);
	margin: 0 0 14px;
}

.gsp-p .gsp-rev__nota-ico {
	width: 14px;
	height: 14px;
	color: var(--gs-verde);
}

.gsp-p .gsp-rev__login {
	color: var(--gs-oro);
	text-decoration: none;
	border-bottom: 1px solid currentColor;
}

.gsp-p .gsp-rev__login:hover,
.gsp-p .gsp-rev__login:focus,
.gsp-p .gsp-rev__login:active {
	background-color: transparent;
	color: var(--gs-oro-osc);
	border-bottom-color: currentColor;
}

.gsp-p .gsp-rev__estrellas-campo {
	border: 0;
	padding: 0;
	margin: 0 0 14px;
}

.gsp-p .gsp-rev__label {
	display: block;
	font-family: var(--gs-font-ui);
	font-weight: 600;
	font-size: 11px;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--gs-txt-2);
	margin-bottom: 8px;
	padding: 0;
}

/* Las estrellas del formulario son radios ocultos con su etiqueta. El orden en el DOM es de 5 a 1
   —lo que permite pintar «todas las de la izquierda» con el combinador `~` sin JS— y `row-reverse`
   las devuelve a su orden visual. */

/* ── Ni `gap` ni ancho de sobra: el contenedor no puede tener zonas muertas ──
   La previsualización de abajo funciona apagando las cinco al entrar en el contenedor y
   reencendiendo las que tocan al entrar en una etiqueta. Eso obliga a que TODO punto dentro del
   contenedor caiga sobre una etiqueta; donde no, quedan las cinco apagadas y parece que la
   puntuación elegida se ha perdido.

   Había dos huecos así, y el segundo era el estado normal, no un caso raro:
     · los 4px de `gap`, que hacían parpadear al cruzar de una estrella a otra;
     · y sobre todo, que este `<div>` es de bloque y ocupaba TODO el ancho del formulario. Las
       cinco estrellas miden ~136px; los cientos de píxeles restantes seguían disparando `:hover`,
       así que mover el ratón hacia el textarea apagaba la puntuación recién elegida.

   `width: fit-content` quita el sobrante y la separación pasa a ser relleno DENTRO de cada
   etiqueta, con lo que sigue viéndose igual pero ya no hay superficie huérfana. */

.gsp-p .gsp-rev__radios {
	display: flex;
	flex-direction: row-reverse;
	justify-content: flex-end;
	width: fit-content;
}

.gsp-p .gsp-rev__estrella-btn {
	display: inline-flex;
	padding: 0 3px;
	font-size: 32px;
	color: var(--gs-estrella-off);
	cursor: pointer;
	transition: color .15s var(--gs-e-soft);
}

/* Elegida y todas las anteriores. Funciona por el orden invertido del DOM: el `~` alcanza a los
   hermanos que van DESPUÉS, que visualmente son los de la izquierda. */

.gsp-p .gsp-rev__radio:checked ~ .gsp-rev__estrella-btn {
	color: var(--gsp-tb-estrella-on, var(--gs-tinta));
}

/* Al pasar el ratón se previsualiza igual. `:hover` sobre el contenedor apaga las de más a la
   derecha para que la previsualización no se sume a lo ya elegido.

   Dentro de `@media (hover: hover)` y no del corte de 900px: lo que decide si hay previsualización
   es tener un puntero de verdad, no el ancho de la pantalla. En táctil el `:hover` se queda pegado
   después del toque y dejaría encendidas estrellas que nadie eligió; en una tableta apaisada de
   1200px con dedo pasaría exactamente igual, y un `max-width` no lo vería. */

/* Los selectores de encendido van prefijados por `.gsp-rev__radios` en los dos bloques de abajo, y
   eso arregla un bug real, no es simetría cosmética. El de apagar es (0,4,0); cuando el de encender
   era `.gsp-p .gsp-rev__estrella-btn:hover` se quedaba en (0,3,0) y PERDÍA, mientras que el del `~`
   sí llegaba a (0,4,0) —el combinador no suma, pero la segunda clase sí— y ganaba por orden. Al
   señalar una estrella se encendían las de su izquierda y justo la señalada se quedaba apagada, que
   se leía como que el hover no funcionaba. Verificado en pantalla antes y después.

   El bloque está duplicado por `@supports` porque hay un SEGUNDO fallo, independiente: el
   contenedor es más alto que sus iconos —32px de estrella en una caja de 54, y ni `align-self`
   ni tocar `line-height` lo cambian— así que por debajo de las estrellas queda una franja que
   dispara el `:hover` del grupo sin que ninguna etiqueta lo reciba. Ahí se apagaban las cinco, y
   mover el ratón hacia el textarea borraba la puntuación recién elegida. `width: fit-content` ya
   resolvía lo mismo en horizontal; en vertical se había pasado por alto.

   Con `:has()` el apagado sólo ocurre si el cursor está DE VERDAD sobre una estrella, y el alto
   sobrante deja de importar. Los dos bloques son excluyentes —`not selector(:has(*))` frente a
   `selector(:has(*))`— porque conviviendo se pisan: la regla clásica seguiría apagando en la franja.
   Y dentro del bloque con `:has()` TODOS los selectores lo llevan, para que las especificidades
   sigan ordenadas: apagado (0,5,0), encendidos (0,6,0). */

@media (hover: hover) {
	@supports not selector(:has(*)) {
		.gsp-p .gsp-rev__radios:hover .gsp-rev__estrella-btn {
			color: var(--gs-estrella-off);
		}

		.gsp-p .gsp-rev__radios .gsp-rev__estrella-btn:hover,
		.gsp-p .gsp-rev__radios .gsp-rev__estrella-btn:hover ~ .gsp-rev__estrella-btn {
			color: var(--gsp-tb-estrella-on, var(--gs-tinta));
		}
	}

	@supports selector(:has(*)) {
		.gsp-p .gsp-rev__radios:has(.gsp-rev__estrella-btn:hover) .gsp-rev__estrella-btn {
			color: var(--gs-estrella-off);
		}

		.gsp-p .gsp-rev__radios:has(.gsp-rev__estrella-btn:hover) .gsp-rev__estrella-btn:hover,
		.gsp-p .gsp-rev__radios:has(.gsp-rev__estrella-btn:hover) .gsp-rev__estrella-btn:hover ~ .gsp-rev__estrella-btn {
			color: var(--gsp-tb-estrella-on, var(--gs-tinta));
		}
	}
}

/* El foco del teclado se ve en la ETIQUETA porque el radio está recortado a 1px: sin esto, tabular
   por las estrellas no marcaría nada en pantalla. */

.gsp-p .gsp-rev__radio:focus-visible ~ .gsp-rev__estrella-btn:first-of-type,
.gsp-p .gsp-rev__radio:focus-visible + .gsp-rev__estrella-btn {
	outline: 2px solid var(--gs-oro);
	outline-offset: 2px;
	border-radius: 2px;
}

/* Las estrellas y su etiqueta, en una fila: el texto va a la DERECHA, no debajo.
   `align-items: center` lo asienta con los iconos. */

.gsp-p .gsp-rev__estrellas-fila {
	display: flex;
	align-items: center;
	gap: 12px;
}

/* El texto aparece y desaparece según se elija o se previsualice una puntuación, así que reserva
   su alto: sin `min-height` el formulario daría un salto cada vez que el ratón entra y sale del
   grupo. `min-width` no hace falta —está al final de la fila y sólo crece hacia la derecha—. */

.gsp-p .gsp-rev__rating-txt {
	min-height: 1.2em;
	font-family: var(--gs-font-body);
	font-size: 12.5px;
	line-height: 1.2;
	color: var(--gs-oro);
}

.gsp-p .gsp-rev__textarea {
	display: block;
	width: 100%;
	min-height: 88px;
	padding: 12px 14px;
	background-color: #fff;
	border: 1px solid var(--gs-linea);
	border-radius: 8px;
	font-family: var(--gs-font-body);
	font-size: 13.5px;
	line-height: 1.6;
	color: var(--gs-tinta);
	resize: vertical;
}

.gsp-p .gsp-rev__textarea:focus {
	border-color: var(--gs-oro);
	outline: none;
}

.gsp-p .gsp-rev__textarea[aria-invalid="true"] {
	border-color: var(--gs-rojo);
}

/* Botones apilados: publicar arriba, cancelar debajo. En una ventana estrecha ponerlos en fila
   dejaría dos botones de 200px que se leen como igual de importantes. */

.gsp-p .gsp-rev__acciones {
	display: flex;
	flex-direction: column;
	gap: 8px;
	margin-top: 18px;
}

.gsp-p button.gsp-rev__enviar,
.gsp-p button.gsp-rev__cancelar {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	padding: 0 24px;
	border-radius: 8px;
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 12px;
	line-height: 1;
	letter-spacing: .1em;
	text-transform: uppercase;
	cursor: pointer;
	transition: background-color .2s var(--gs-e-soft), color .2s var(--gs-e-soft), border-color .2s var(--gs-e-soft);
}

.gsp-p button.gsp-rev__enviar {
	height: 48px;
	border: none;
	background-color: var(--gs-tinta);
	color: #fff;
}

.gsp-p .gsp-rev__enviar:hover,
.gsp-p .gsp-rev__enviar:focus,
.gsp-p .gsp-rev__enviar:active {
	background-color: var(--gs-oro);
	color: #fff;
}

/* Apagado mientras falta puntuación o texto, y mientras se envía. Va DESPUÉS de las reglas de
   `:hover` y las repite, porque el puntero puede seguir encima de un botón que acaba de apagarse y
   si no se vería el oro del hover sobre un botón que no acepta nada. */

.gsp-p .gsp-rev__enviar[aria-disabled="true"],
.gsp-p .gsp-rev__enviar[aria-disabled="true"]:hover,
.gsp-p .gsp-rev__enviar[aria-disabled="true"]:focus,
.gsp-p .gsp-rev__enviar[aria-disabled="true"]:active {
	background-color: var(--gs-tinta);
	color: #fff;
	opacity: .35;
	cursor: not-allowed;
}

.gsp-p button.gsp-rev__cancelar {
	height: 44px;
	border: 1.5px solid var(--gs-linea);
	background-color: transparent;
	color: var(--gs-txt-3);
}

.gsp-p .gsp-rev__cancelar:hover,
.gsp-p .gsp-rev__cancelar:focus,
.gsp-p .gsp-rev__cancelar:active {
	background-color: transparent;
	color: var(--gs-tinta);
	border-color: var(--gs-txt-3);
}

/* ── Distintivo de la reseña recién publicada ────────────────────────────────
   Lo pone el JS sobre la tarjeta que devuelve el servidor. */

.gsp-p .gsp-rev__pill {
	display: inline-block;
	margin-top: 4px;
	padding: 3px 8px;
	border-radius: var(--gs-r-pill);
	background-color: var(--gs-oro-pale);
	font-family: var(--gs-font-ui);
	font-weight: 700;
	font-size: 9px;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--gsp-tb-badge, var(--gs-oro));
}

/* ── Responsive ──────────────────────────────────────────────────────────────
   900px es el corte del diseño para toda la ficha. */

@media (max-width: 900px) {
	/* ── La ventana pasa a panel inferior ────────────────────────────────────
	   Solo en `is-auto`: quien haya elegido «siempre ventana centrada» la mantiene, y `is-sheet`
	   ya lo es en todos los tamaños por su regla de arriba. */

	.gsp-p.gsp-rev__modal.is-auto .gsp-rev__caja {
		top: auto;
		/* Sobre el teclado, igual que `.is-sheet`; el porqué está en su regla. */
		bottom: var(--gs-vv-fondo, 0px);
		left: 0;
		width: 100%;
		max-width: none;
		max-height: calc(var(--gs-vv-alto, 100vh) * .82);
		overflow-y: auto;
		border-radius: 20px 20px 0 0;
		/* Mismo movimiento que `.is-sheet`; ver el porqué del porcentaje allí. */
		opacity: 1;
		transform: translateY(100%);
		transition: transform 220ms var(--gs-e-sheet);
	}

	.gsp-p.gsp-rev__modal.is-auto.is-abierto .gsp-rev__caja {
		transform: translateY(0);
		transition-duration: 320ms;
	}

	.gsp-p.gsp-rev__modal.is-auto .gsp-rev__manija {
		display: block;
	}

	/* El botón que abre ocupa el ancho: en móvil es la acción principal del panel. */

	.gsp-p .gsp-rev__cabecera {
		margin-bottom: 20px;
	}

	.gsp-p button.gsp-rev__abrir {
		width: 100%;
	}

	/* ── 16px en el campo, y NO es una decisión tipográfica ──────────────────────
	   Safari en iOS AMPLÍA el viewport al enfocar cualquier campo cuyo texto mida menos de 16px.
	   Con los 13.5px del diseño, tocar el textarea para escribir la reseña daba un salto de zoom:
	   el panel se salía de la pantalla y había que pellizcar para volver. No es un fallo del CSS,
	   es una regla del sistema, y el único modo de evitarla es no bajar de ese suelo en móvil.

	   Se hace aquí y no en la regla general para no engordar el texto de la ventana centrada de
	   escritorio, donde 13.5px es lo que pide el diseño y el zoom de iOS no existe.

	   Lo que NO se hace: `<meta viewport maximum-scale=1>`. Quitaría el pellizco para ampliar en
	   TODO el sitio, que es un fallo de accesibilidad de manual (WCAG 1.4.4). El problema se
	   arregla en el campo, no capando el navegador. */

	.gsp-p .gsp-rev__textarea {
		font-size: 16px;
	}

	/* Zona de toque de 44px por estrella con el glifo a 28px: el dedo no acierta un objetivo de
	   32px con 6px de separación, y en táctil no hay hover que ayude a corregir. */

	.gsp-p .gsp-rev__estrella-btn {
		min-width: 44px;
		min-height: 44px;
		align-items: center;
		justify-content: center;
		padding: 0;
		font-size: 28px;
	}

	.gsp-p button.gsp-rev__enviar {
		height: 50px;
	}

	.gsp-p button.gsp-rev__cancelar {
		height: 46px;
	}

	/* Modo «pestañas con desplazamiento»: la barra se desliza en horizontal en vez de apretar
	   las pestañas. `-webkit-overflow-scrolling` para que el gesto tenga inercia en iOS. */

	.gsp-p.gsp-tabs[data-movil="scroll"] .gsp-tabs__barra {
		flex-wrap: nowrap;
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
	}

	.gsp-p.gsp-tabs[data-movil="scroll"] .gsp-tabs__barra::-webkit-scrollbar {
		display: none;
	}

	.gsp-p.gsp-tabs[data-movil="scroll"] button.gsp-tabs__tab {
		padding: 14px 18px;
	}

	/* Modo acordeón: la barra desaparece y cada panel estrena su propio disparador. La clase la
	   pone el JS al aplicar el modo, no el ancho por sí solo: así el CSS y los roles ARIA cambian
	   a la vez y no puede verse un acordeón que para el lector de pantalla sigue siendo pestañas. */

	.gsp-p.gsp-tabs.is-acordeon .gsp-tabs__barra {
		display: none;
	}

	.gsp-p.gsp-tabs.is-acordeon button.gsp-tabs__acordeon {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: 12px;
		width: 100%;
		padding: 18px 0;
		background-color: transparent;
		border: 0;
		border-bottom: 1px solid var(--gsp-tb-linea);
		font-family: var(--gs-font-ui);
		font-weight: 600;
		font-size: 11.5px;
		line-height: 1;
		letter-spacing: .14em;
		text-transform: uppercase;
		color: var(--gsp-tb-tab);
		text-align: left;
		cursor: pointer;
	}

	.gsp-p.gsp-tabs.is-acordeon .gsp-tabs__acordeon:hover,
	.gsp-p.gsp-tabs.is-acordeon .gsp-tabs__acordeon:focus,
	.gsp-p.gsp-tabs.is-acordeon .gsp-tabs__acordeon:active {
		background-color: transparent;
		color: var(--gsp-tb-tab-hover);
	}

	.gsp-p.gsp-tabs.is-acordeon .gsp-tabs__acordeon[aria-expanded="true"] {
		color: var(--gsp-tb-tab-on);
		font-weight: 700;
		border-bottom-color: transparent;
	}

	.gsp-p.gsp-tabs.is-acordeon .gsp-tabs__chevron {
		width: 14px;
		height: 14px;
		transition: transform .25s var(--gs-e-out);
	}

	.gsp-p.gsp-tabs.is-acordeon .gsp-tabs__acordeon[aria-expanded="true"] .gsp-tabs__chevron {
		transform: rotate(180deg);
	}

	.gsp-p.gsp-tabs.is-acordeon .gsp-tabs__panel {
		padding: 20px 0 24px;
		border-bottom: 1px solid var(--gsp-tb-linea);
	}

	/* En acordeón cada apartado ya cierra con su propia línea —la del disparador si está
	   plegado, la del panel si está abierto, que por eso el disparador abierto pone la suya en
	   transparente—, así que la del widget saldría pegada debajo de esa, separada solo por el
	   respiro. Se apaga la del widget y no la del último apartado: quitársela a ese obligaría a
	   saber cuál es el último VISIBLE, y con paneles que desaparecen por no tener contenido eso
	   cambia de un producto a otro. El espacio inferior sí se conserva. */

	.gsp-p.gsp-tabs.is-acordeon.has-divider {
		border-bottom: 0;
	}

	.gsp-p .gsp-rev__head {
		/* Con la tarjeta estrecha el nombre y la fecha no caben en la misma línea. */
		flex-direction: column;
		align-items: flex-start;
		gap: 6px;
	}

	.gsp-p .gsp-rev__meta {
		text-align: left;
	}
}

@media (max-width: 560px) {
	/* La reseña NO entra aquí: es plana y su relleno lateral ya es cero, así que reducirlo no
	   tendría efecto. Solo el formulario, que sí es una caja con relleno. */

	.gsp-p .gsp-rev__form {
		padding: 20px;
	}

	.gsp-p .gsp-specs__fila {
		/* Etiqueta y valor uno debajo del otro: con 24px de hueco mínimo y un valor largo, la
		   fila de dos columnas se convertía en dos líneas rotas a media palabra. */
		flex-direction: column;
		gap: 2px;
	}

	.gsp-p .gsp-specs__valor {
		text-align: left;
	}

	/* ── La guía de tallas NO se apila, a diferencia de la de arriba ──────
	   `.gsp-specs` apila porque su valor es texto —«Malla y sintético»— y en dos columnas se
	   partía a media palabra. Aquí las dos celdas son dos cifras: apilarlas rompería la
	   correspondencia, que es justo lo único que esta tabla tiene que comunicar. Una talla y su
	   medida caben en cualquier pantalla en una sola línea.

	   Lo que sí baja es el relleno de fila. En un móvil, quince tallas a 14px arriba y abajo son
	   una columna interminable de desplazamiento; a 11 se recorre de un gesto y sigue sin
	   apretar. */

	.gsp-p .gsp-tallas th,
	.gsp-p .gsp-tallas td {
		padding: 11px 0;
	}

	.gsp-p .gsp-tallas thead th {
		padding: 0 0 6px;
	}

	/* El rótulo puede necesitar dos líneas —«CONTORNO DE PECHO (CM)» no cabe en media pantalla—
	   y tiene que poder partirse sin desalinear su columna. */

	.gsp-p .gsp-tallas thead th:last-child {
		padding-left: 12px;
	}
}

/* ── Movimiento reducido ─────────────────────────────────────────────────────
   Obligatorio en esta familia (INSTRUCCIONES.md §4): quien pide menos movimiento no recibe
   ninguna transición, pero sí todos los cambios de color y de estado. */

@media (prefers-reduced-motion: reduce) {
	.gsp-p .gsp-tabs__tab,
	.gsp-p .gsp-tabs__chevron,
	.gsp-p .gsp-rev__mas,
	.gsp-p .gsp-rev__pagina,
	.gsp-p .gsp-rev__enviar,
	.gsp-p .gsp-rev__estrella-btn {
		transition: none;
	}

	/* La ventana pierde el DESPLAZAMIENTO, no la aparición: reducir movimiento no es quitar toda
	   la animación, es quitar la que mueve cosas por la pantalla. Se queda un fundido corto, que
	   sigue explicando que ha aparecido una capa encima sin desplazar nada.

	   La transición NO se pone a `none`: `cerrar()` espera al `transitionend` para volver a poner
	   el `hidden`, y sin ningún evento se apoyaría siempre en el temporizador de respaldo. Con
	   una duración mínima el camino es el mismo para todo el mundo. */
	/* OJO con el `transform` de la ventana centrada: NO puede irse a `none`. Ahí el
	   `translate(-50%,-50%)` no es animación, es lo que la centra —`top:50%; left:50%` la deja en
	   la esquina y el translate la recoloca—, así que quitarlo la manda a la esquina inferior
	   derecha. Se le quita solo el `scale`. El panel inferior sí puede ir a `none`, porque allí el
	   translate era únicamente el desplazamiento. */
	.gsp-p .gsp-rev__caja {
		transform: translate(-50%, -50%);
		opacity: 0;
		transition: opacity 120ms linear;
	}

	.gsp-p.gsp-rev__modal.is-abierto .gsp-rev__caja {
		transform: translate(-50%, -50%);
		opacity: 1;
	}

	.gsp-p.gsp-rev__modal.is-sheet .gsp-rev__caja,
	.gsp-p.gsp-rev__modal.is-auto .gsp-rev__caja,
	.gsp-p.gsp-rev__modal.is-sheet.is-abierto .gsp-rev__caja,
	.gsp-p.gsp-rev__modal.is-auto.is-abierto .gsp-rev__caja {
		transform: none;
	}
}

