/* assets/css/tokens.css */
/*
 * Tokens de marca — extraídos con pipeta directo del archivo real del logo
 * (Downloads/cohasa-logo.png, RGB exacto vía PIL): navy #051a2d (estructura:
 * header, hero, texto) y verde #00f647 (acento: CTA, badges de marca) son
 * literalmente los dos colores del isotipo. Nada inventado.
 * Dirección "Vivo y animado" (elegida por el usuario sobre las otras 4).
 *
 * Los valores editables desde Apariencia > Editor > Estilos (paleta de
 * theme.json: bg, surface, ink, ink-soft, accent, accent-ink, hero-bg,
 * oferta) se leen vía var(--wp--preset--color--<slug>, <hex de fábrica>) —
 * el hex de respaldo es el mismo que el default de theme.json, así que si
 * nadie tocó Estilos globales el resultado es idéntico a antes. Reemplaza
 * al ajuste "Cohasa > Apariencia > Colores" (Cohasa_Customizer), eliminado
 * el 2026-09-24 por duplicar Estilos globales sin vista previa real.
 *
 * El verde de marca es MUY brillante (luminancia alta): sobre blanco da
 * apenas 1,47:1 de contraste — falla WCAG feo si se usa como texto sobre
 * fondo claro. Regla dura en todo el CSS: el verde solo se usa como FONDO
 * (con --color-accent-ink oscuro encima) o como acento sobre fondos oscuros
 * (navy), nunca como color de texto sobre superficie clara.
 */
:root {
	--color-bg: var(--wp--preset--color--bg, #f4f6f8);
	--color-surface: var(--wp--preset--color--surface, #ffffff);
	--color-ink: var(--wp--preset--color--ink, #0d1117);
	--color-ink-soft: var(--wp--preset--color--ink-soft, #47536b); /* #64748b (token real de cohasa.cl) da 4.39:1 sobre --color-bg,
		bajo el mínimo AA de 4.5:1 para texto normal — se oscureció a 7.1:1 (AAA), mismo matiz azulado */
	--color-line: var(--wp--preset--color--line, #d8dde5);
	/* Borde de controles que solo se distinguen por su caja (chips): WCAG 1.4.11 pide 3:1.
	   --color-line da 1.24:1 sobre --color-bg. #7f8a9b = 3.22:1 sobre --color-bg y 3.08:1
	   sobre --color-field (el peor caso, fondo del chip). */
	--color-line-strong: var(--wp--preset--color--line-strong, #7f8a9b);
	--color-field: var(--wp--preset--color--field, #eef1f4);
	/* Fondo de inputs de texto/select — token propio, NO --color-bg ni
	   --color-field (ver el porqué en assets/css/forms.css): mismo valor de
	   fábrica que --color-bg hoy, pero editable aparte para que cambiar
	   "Fondo" en Estilos globales no mueva sin querer todos los inputs del
	   sitio. */
	--color-input-bg: var(--wp--preset--color--input-bg, #f4f6f8);

	/* Acento = verde real del isotipo. Contraste verificado:
	   #052d00 sobre #00f647 = 10,33:1 (AAA). El navy sigue siendo --color-ink
	   y el fondo directo de header/hero (ver main.css, no es "accent"). */
	--color-accent: var(--wp--preset--color--accent, #00f647);
	--color-accent-ink: var(--wp--preset--color--accent-ink, #052d00);

	/* Verde oscurecido para texto/ícono de acento sobre superficie clara
	   (ej. estrellas de valoración) — mismo matiz que --color-accent pero
	   con luminosidad baja. #0a6b2e sobre #ffffff = 6,65:1 (AAA). En modo
	   oscuro el verde de marca ya es legible como texto, así que aquí
	   apunta directo a --color-accent (ver bloque prefers-color-scheme).
	   Editable desde Estilos globales (preset "accent-text") — si se cambia
	   --color-accent, este valor NO se ajusta solo (probado con color-mix(),
	   no preserva contraste de forma confiable — ver design.md), hay que
	   revisarlo a mano tras cualquier cambio de acento. */
	--color-accent-text: var(--wp--preset--color--accent-text, #0a6b2e);

	/* Oferta/descuento en terracota, deliberadamente distinto del verde de
	   CTA — el verde significa "acción", el terracota "alerta de precio".
	   Contraste #ffffff sobre #c1440e = 5,12:1 (AA). */
	--color-oferta-bg: var(--wp--preset--color--oferta, #c1440e);
	--color-oferta-ink: var(--wp--preset--color--oferta-ink, #ffffff);
	/* Terracota como TEXTO (ícono/porcentaje de bento-card, no fondo): en claro
	   el mismo --color-oferta-bg ya pasa AA sobre superficie clara. En oscuro
	   #c1440e da solo 3,34:1 sobre --color-surface — bajo el mínimo. Aclarado
	   a #e8703f: 5,56:1 sobre surface, 6,01:1 sobre bg, 5,26:1 sobre field.
	   Editable en claro (preset "oferta-text"); en oscuro usa "oferta-text-dark". */
	--color-oferta-text: var(--wp--preset--color--oferta-text, var(--color-oferta-bg));
	/* #15803d/#b3261e (valores previos) dan 3.50:1 y 4.31:1 sobre el fondo tenue
	   de badges (ej. --color-ok/--color-error 18% + --color-field, .cuenta-badge)
	   — bajo AA. Oscurecidos: #166534 = 4.81:1, #9b1c16 = 5.26:1 sobre ese mismo
	   fondo (margen sobre 4.5 por la brecha cálculo-vs-vivo, ver verificacion.md).
	   Editables desde Estilos globales (presets "ok"/"error"). */
	--color-ok: var(--wp--preset--color--ok, #166534);
	--color-error: var(--wp--preset--color--error, #9b1c16);
	/* Texto/ícono sólido sobre --color-ok o --color-error como FONDO (botones,
	   íconos de aviso WC): blanco en claro (7.13:1 sobre ok, 8.17:1 sobre error),
	   --color-bg oscuro en modo oscuro — ver bloques de abajo. */
	--color-on-status: var(--wp--preset--color--on-status, #ffffff);

	--font-display: var(--wp--preset--font-family--display, "Sora", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif);
	--font-body: var(--wp--preset--font-family--body, "Inter Variable", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif);
	--font-mono: var(--wp--preset--font-family--mono, "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace);

	--radius: 10px;
	--radius-lg: 20px;
	--gutter: 16px;
	--maxw: 1280px;

	--focus-ring: 0 0 0 3px var(--color-bg), 0 0 0 5px var(--color-ink);
	/* Color suelto del aro de foco, para outline con offset negativo dentro de
	   contenedores con overflow (tarjetas del carrusel): box-shadow ahí se recorta. */
	--color-focus: var(--color-ink);
	/* Sombra de elementos flotantes (flechas del carrusel): negro puro, sirve en
	   claro y oscuro — una sombra hecha con --color-ink brilla en modo oscuro. */
	--shadow-float: 0 4px 14px -6px rgb(0 0 0 / 0.35);
	/* Elevación en reposo de la tarjeta de producto (antes solo tenía borde,
	   sin sombra hasta el :hover — invisible en touch, que no tiene hover).
	   Negro puro fijo, mismo motivo que --shadow-float. */
	--shadow-card: 0 1px 2px -1px rgb(0 0 0 / 0.12), 0 2px 6px -2px rgb(0 0 0 / 0.10);
	/* Sombra corta de chips/badges flotantes sobre una tarjeta (variantes de
	   producto, botones del quick view): mismo criterio que --shadow-float
	   (fijo, no --color-ink, para no aclararse en modo oscuro). Antes
	   repetido literal en 3 archivos sin token — consolidado acá. */
	--shadow-sm: 0 4px 10px -6px rgb(13 17 23 / 0.35);

	/* Velo de las cards de categoría (imagen + texto encima): oscuro fijo en
	   los dos temas, igual que --color-focus/--shadow-float — no se invierte
	   en modo oscuro porque el texto siempre va en blanco sobre la foto.
	   Peor caso de contraste (foto blanca pura bajo el velo): compuesto
	   ≈ #6e6e6e (L≈0.152), blanco encima = 5,2:1 (AA, incluso para el
	   conteo de 12.5px). */
	--color-scrim: rgb(13 17 23 / 0.6);
	--color-scrim-ink: #ffffff;

	/* Fondo del hero: siempre navy de marca, en los dos temas — no usa
	   --color-ink (que se invierte en modo oscuro; el hero quedaría claro
	   sobre una página oscura, al revés de la intención). */
	--color-hero-bg: var(--wp--preset--color--hero-bg, #051a2d);
	--color-hero-ink: #ffffff;
	/* Borde de los bloques navy flotantes (.cta-banner/.campana-banner/
	   .promo-banner): en claro --color-hero-bg contrasta 16.3:1 contra
	   --color-bg, no necesita borde (transparent). En oscuro cae a 1.05:1 —
	   el bloque se funde con la página, "vibración visual" sin límite
	   visible (bug real, reportado 2026-09-24). Sin valor acá: solo se
	   define en los bloques de abajo (oscuro). */
	--color-hero-border: transparent;
	/* Texto secundario sobre --color-hero-bg (footer, en dos lugares): antes
	   #c3d4e3 hardcodeado y repetido. Igual que --color-hero-bg/-ink, fijo
	   en los dos temas — el footer navy no se invierte. */
	--color-hero-ink-soft: #c3d4e3;

	/* Duraciones/curvas para la capa de animación (assets/css/motion.css) —
	   centralizadas para no repetir "ease" mágicos por todo el CSS. */
	--ease-out: cubic-bezier(.16,1,.3,1);
	--dur-fast: .18s;
	--dur-base: .32s;
	--dur-slow: .5s;
}

@media (prefers-color-scheme: dark) {
	:root:not([data-cohasa-theme="light"]) {
		--color-bg: var(--wp--preset--color--bg-dark, #0f1419);
		--color-surface: var(--wp--preset--color--surface-dark, #161c24);
		--color-ink: var(--wp--preset--color--ink-dark, #e2e8f0);
		--color-ink-soft: var(--wp--preset--color--ink-soft-dark, #94a3b8);
		--color-line: var(--wp--preset--color--line-dark, #253040);
		--color-line-strong: var(--wp--preset--color--line-strong-dark, #64748b); /* 3.89:1 sobre --color-bg, 3.40:1 sobre --color-field */
		--color-field: var(--wp--preset--color--field-dark, #1a212b);
		--color-input-bg: var(--wp--preset--color--input-bg-dark, #0f1419);
		--color-accent: var(--wp--preset--color--accent-dark, #4af835);
		--color-accent-ink: var(--wp--preset--color--accent-ink, #052d00);
		--color-accent-text: var(--color-accent);
		--color-oferta-text: var(--wp--preset--color--oferta-text-dark, #e8703f);
		--focus-ring: 0 0 0 3px var(--color-bg), 0 0 0 5px var(--color-accent);
		--color-focus: var(--color-accent);

		/* --color-ok/--color-error de modo claro dan 3.41:1 y 2.62:1 sobre el fondo
		   oscuro — bajo el mínimo AA. Variantes claras equivalentes. --color-error
		   #f87171 (valor previo) daba 4.46:1 sobre el fondo tenue de badges — bajo
		   AA; #fca5a5 = 5.84:1 (margen sobre 4.5). */
		--color-ok: var(--wp--preset--color--ok-dark, #4ade80);
		--color-error: var(--wp--preset--color--error-dark, #fca5a5);
		--color-on-status: var(--wp--preset--color--on-status-dark, #0f1419);
		/* 35% de --color-hero-ink sobre --color-hero-bg: 3.18:1 contra el
		   propio bloque, 3.34:1 contra --color-bg de la página — visible
		   contra los dos lados del borde (AA no-textual). */
		--color-hero-border: color-mix(in srgb, var(--color-hero-ink) 35%, transparent);
	}
}

/* Elección explícita del toggle (data-cohasa-theme, ver assets/js/
   theme-toggle.js + functions.php anti-flash): mismos valores que el bloque
   de arriba, pero SIN el @media — si el sistema operativo está en claro y
   la persona fuerza oscuro con el botón (o viceversa), el bloque de arriba
   nunca se activa porque el @media de prefers-color-scheme no matchea, así
   que la elección explícita quedaba ignorada. Ver design.md, "Temas: los
   tres estados". */
:root[data-cohasa-theme="dark"] {
	--color-bg: var(--wp--preset--color--bg-dark, #0f1419);
	--color-surface: var(--wp--preset--color--surface-dark, #161c24);
	--color-ink: var(--wp--preset--color--ink-dark, #e2e8f0);
	--color-ink-soft: var(--wp--preset--color--ink-soft-dark, #94a3b8);
	--color-line: var(--wp--preset--color--line-dark, #253040);
	--color-line-strong: var(--wp--preset--color--line-strong-dark, #64748b);
	--color-field: var(--wp--preset--color--field-dark, #1a212b);
	--color-input-bg: var(--wp--preset--color--input-bg-dark, #0f1419);
	--color-accent: var(--wp--preset--color--accent-dark, #4af835);
	--color-accent-ink: var(--wp--preset--color--accent-ink, #052d00);
	--color-accent-text: var(--color-accent);
	--color-oferta-text: var(--wp--preset--color--oferta-text-dark, #e8703f);
	--focus-ring: 0 0 0 3px var(--color-bg), 0 0 0 5px var(--color-accent);
	--color-focus: var(--color-accent);
	--color-ok: var(--wp--preset--color--ok-dark, #4ade80);
	--color-error: var(--wp--preset--color--error-dark, #fca5a5);
	--color-on-status: var(--wp--preset--color--on-status-dark, #0f1419);
	--color-hero-border: color-mix(in srgb, var(--color-hero-ink) 35%, transparent);
}

/* color-scheme nativo: sin esto, el navegador dibuja el fondo antes de que
   nuestro CSS cargue (scrollbars, inputs nativos, el "flash" blanco entre
   navegaciones en modo oscuro reportado en Recordatorios). Misma cascada que
   los bloques de arriba: preferencia del sistema, salvo elección explícita
   del toggle (data-cohasa-theme). El script anti-parpadeo en functions.php
   ajusta esto mismo en el `style` inline de <html>, antes del primer paint. */
:root { color-scheme: light; }
@media (prefers-color-scheme: dark) {
	:root:not([data-cohasa-theme="light"]) { color-scheme: dark; }
}
:root[data-cohasa-theme="dark"] { color-scheme: dark; }

/* assets/css/main.css */
/* Cohasa — CSS base. Mobile-first: todo se escribe para 390px primero,
   los @media (min-width) agregan lo que el escritorio necesita de más. */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

/* El UA stylesheet solo oculta [hidden] en elementos HTML — la excepción
   del spec deja <svg hidden> visible en todos los navegadores. Se usa para
   alternar íconos (ver hero-slider.js, data-hero-pause-icon). */
svg[hidden] { display: none; }

body {
	margin: 0;
	background: var(--color-bg);
	color: var(--color-ink);
	font-family: var(--font-body);
	font-size: 16px;
	line-height: 1.5;
}

img, svg { max-width: 100%; display: block; }
img { height: auto; }

/* Selección de texto de marca — sin esto queda el azul default del
   navegador, el único control nativo que faltaba (ver design.md, "UI
   personalizada siempre"). Mismo par que --color-accent-ink/--color-accent
   ya usan botones/badges (10.3:1 en claro, 10.7:1 en oscuro), consistente
   en los dos temas. */
::selection {
	background: var(--color-accent);
	color: var(--color-accent-ink);
}

h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 800; line-height: 1.15; margin: 0 0 .5em; text-wrap: balance; }
p { margin: 0 0 1em; }

/* Sin subrayado en ningún link del sitio, por defecto (design.md, "Sin
   redundancia ni texto subrayado"): antes cada componente lo pisaba caso a
   caso (breadcrumb, avisos, footer, etc.) y siempre quedaba alguno sin
   cubrir con el subrayado nativo del navegador — reset acá, una sola vez,
   en vez de seguir agregando `text-decoration: none` componente por
   componente. Un link se distingue por color/peso o por vivir dentro de un
   componente con su propia caja (.btn, tarjetas, pastillas), no por el
   subrayado. `:hover`/`:focus-visible` sí pueden agregarlo puntualmente
   donde ya estaba pensado como refuerzo (ver .site-footer a:hover). */
a { color: inherit; text-decoration: none; }
/* Link suelto dentro de contenido de página/patrón (ej. "¿Olvidaste tu
   contraseña?"): sin subrayado (regla de arriba) ni color propio (hereda
   --color-ink, ya con contraste suficiente), un link ahí es indistinguible
   del texto que lo rodea — WCAG 1.4.1 exige un segundo indicador además del
   color. Peso de fuente como distintivo, ya documentado en design.md
   ("Texto subrayado: no"). No aplica a listas de navegación (nav/menú, ya
   con su propio componente), solo a párrafos/listas de contenido real. */
.wp-block-post-content p a,
.wp-block-post-content li a {
	font-weight: 600;
}

/* --- Foco: nunca se oculta, en ningún control ---
   [tabindex="-1"] queda afuera a propósito: WooCommerce le hace foco por
   script a los avisos ("Xxx se ha añadido a tu carrito") con tabindex="-1"
   para que el lector de pantalla los anuncie — no es navegación real de
   teclado, y el anillo de foco ahí se veía como un recuadro verde brillante
   envolviendo todo el aviso (bug real, reportado por captura). */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:not([tabindex="-1"]):focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
	border-radius: 4px;
}
/* El foco por script en tabindex="-1" (avisos de WooCommerce) no necesita
   anillo visual — quien lo necesita es el lector de pantalla, que ya lo
   anuncia igual sin el contorno azul por defecto del navegador. */
[tabindex="-1"]:focus-visible {
	outline: none;
}
@media (prefers-reduced-motion: no-preference) {
	:focus-visible { transition: box-shadow .12s ease; }
}

/* --- Texto solo para lectores de pantalla (estándar WordPress) --- */
.screen-reader-text {
	position: absolute !important;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* --- Skip link --- */
.skip-link {
	position: absolute;
	left: -999px;
	top: 0;
	background: var(--color-ink);
	color: var(--color-bg);
	padding: 12px 18px;
	z-index: 1000;
	font-weight: 700;
	border-radius: 0 0 8px 0;
}
.skip-link:focus {
	left: 0;
}

/* Único contenedor de ancho del sitio (design.md: "Espaciado: gutter en
   TODO ancho, no solo centrado"). `margin-inline: auto` solo centra — da 0
   de margen mientras el viewport sea más angosto que --maxw, dejando el
   bloque pegado al borde en mobile. max() conserva el gutter siempre y pasa
   a centrar recién cuando el viewport supera --maxw. Los hijos de un
   `.container` NO deben volver a aplicar max-width/margin/padding-inline
   propios — lo hacían en varios componentes (ver historial) y sumaba un
   segundo gutter, desalineando el contenido respecto del header. */
.container {
	max-width: var(--maxw);
	margin-inline: max(var(--gutter), calc((100% - var(--maxw)) / 2));
	padding-inline: 0;
}

/* --- Botones: objetivo táctil ≥44px siempre (AAA gratis) ---
   El bloque nativo "Botones" de Gutenberg pone la clase en el <div>
   envoltorio (.wp-block-button), no en el <a> real (.wp-block-button__link)
   — así que estas reglas se aplican tanto a un <a class="btn"> directo
   (markup PHP clásico) como a ".wp-block-button.btn .wp-block-button__link"
   (patrones de bloques, ej. cohasa/hero), y se anula el estilo por defecto
   del bloque en el envoltorio para que no se dupliquen fondo/borde. */
.btn,
.wp-block-button.btn .wp-block-button__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	min-height: 44px;
	padding: 10px 20px;
	border-radius: var(--radius);
	border: 1px solid transparent;
	font-family: var(--font-body);
	font-weight: 700;
	font-size: 15px;
	text-decoration: none;
	cursor: pointer;
}
.wp-block-button.btn {
	background: none;
	border: none;
	padding: 0;
	min-height: 0;
	display: inline-block;
}
.btn--primary,
.wp-block-button.btn--primary .wp-block-button__link {
	background: var(--color-accent);
	color: var(--color-accent-ink);
}
.btn--primary:hover,
.wp-block-button.btn--primary .wp-block-button__link:hover { opacity: .9; }
.btn--secondary,
.wp-block-button.btn--secondary .wp-block-button__link {
	background: transparent;
	border-color: var(--color-ink);
	color: var(--color-ink);
}
.btn--block { display: flex; width: 100%; }
/* Ghost: enlace "ver todo" de encabezado de sección — pill discreto, mismo
   objetivo táctil que .btn pero más compacto (13px, menos padding). */
.btn--ghost {
	background: transparent;
	border-color: var(--color-line);
	color: var(--color-ink);
	font-size: 13px;
	padding: 8px 16px;
}
.btn--ghost:hover,
.btn--ghost:focus-visible {
	background: var(--color-field);
	border-color: var(--color-ink);
}
.btn--ghost svg { transition: transform var(--dur-fast) var(--ease-out); }
.btn--ghost:hover svg { transform: translateX(2px); }
@media (prefers-reduced-motion: reduce) {
	.btn--ghost svg { transition: none; }
	.btn--ghost:hover svg { transform: none; }
}

/* --- Barra promocional (despacho gratis, etc.) --- */
.site-topbar {
	margin: 0;
	background: var(--color-hero-bg);
	color: var(--color-hero-ink);
	font-size: 12.5px;
	font-weight: 600;
	text-align: center;
	padding: 6px var(--gutter);
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
}

/* --- Header: fila única (design.md) ---
   Una sola fila de 64px: logo, botón "Categorías" (dropdown, escritorio) +
   buscador (flex, escritorio) + acciones — y hamburguesa a la derecha en
   móvil, donde Categorías y el buscador se ocultan (ambos viven dentro del
   drawer de la hamburguesa, ver .site-menu-drawer más abajo e
   inc/menu-drawer.php). Reemplaza a la dirección anterior de dos filas
   (barra + franja de categorías siempre visible). */
.site-header {
	border-bottom: 1px solid var(--color-line);
	background: var(--color-surface);
	position: sticky;
	top: 0;
	z-index: 50;
}
.site-header__bar {
	display: flex;
	align-items: center;
	flex-wrap: nowrap;
	gap: 8px 14px;
	min-height: 64px;
	padding-block: 10px;
}
/* Sin esto, el blockGap global de theme.json (16px) le mete margin-top a
   cada hijo directo del wp:group "default" (bug real, con captura: el botón
   Categorías y las acciones quedaban 8px más abajo que el logo y el
   buscador, porque .site-search ya se defendía con su propio margin:0 y el
   resto no). align-items:center ya centra todo — el blockGap sobra acá. */
.site-header__bar > * {
	margin-block: 0;
}
.site-header__logo { order: 1; flex-shrink: 0; }
/* Categorías: solo escritorio (900px) — ver el reset de abajo. En móvil el
   botón no se renderiza en el flujo visible (display:none) porque el mismo
   menú ya está disponible en el drawer de la hamburguesa. */
.site-header__categorias { order: 2; display: none; position: relative; flex-shrink: 0; }
/* Link "Tienda" — mismo criterio de visibilidad que .site-header__categorias
   (oculto en móvil, ya disponible en el drawer), mismo order para que quede
   justo al lado del dropdown en el flujo. */
.site-header__tienda { order: 2; display: none; flex-shrink: 0; }
.site-header .site-search--header { order: 3; flex-shrink: 0; }
/* Buscador oculto en móvil: vive dentro del drawer de la hamburguesa
   (variante "inline" sin lupa/overlay, inc/menu-drawer.php) — evita
   duplicar el mismo campo visible dos veces en pantallas chicas. */
@media (max-width: 899.98px) {
	.site-header .site-search--header { display: none; }
}
.site-header .site-header__actions { order: 4; margin-left: auto; flex-shrink: 0; }
.nav-toggle { order: 5; flex-shrink: 0; }
/* Editor de sitio: cohasa/primary-nav y cohasa/site-search son bloques
   dinámicos, y ServerSideRender (assets/js/editor-blocks.js) los envuelve en
   un div propio (clase wp-block-cohasa-*) — ese div, no .site-header__categorias
   ni .site-search--header, es el hijo directo real de .site-header__bar en el
   lienzo. Las reglas de order/flex de arriba (y las de @media min-width:900px
   más abajo) nunca llegan a aplicarse ahí, así que se repiten acá apuntando
   al wrapper. En el front no existe este wrapper (el render_callback no lo
   imprime) — cero efecto fuera del editor. */
.site-header__bar > .wp-block-cohasa-primary-nav { order: 2; flex-shrink: 0; }
.site-header__bar > .wp-block-cohasa-site-search { order: 3; flex: 1 1 auto; max-width: 720px; }
.site-header__logo {
	display: flex;
	align-items: center;
	text-decoration: none;
	flex-shrink: 0;
}
.site-header__logo img,
.site-header__logo .custom-logo,
/* Logo a color (sin margen transparente): 30px. */
.site-header__logo .site-logo-img {
	height: 30px;
	width: auto;
	display: block;
}
/* En tema oscuro se muestra el negativo (blanco) del logo monocromático
   negro, invertido por CSS. Ese PNG trae ~33% de margen transparente
   vertical, por eso 44px: la marca visible mide ~29px. Ver
   cohasa_block_site_logo() en inc/blocks.php. */
.site-header__logo .site-logo-img--dark {
	display: none;
	height: 44px;
	filter: invert(1);
}
/* Logo oscuro subido a mano (atributo logoOscuroId, cohasa_block_site_logo()):
   sin el invert del PNG de respaldo (le cambiaría los colores a un logo
   real) ni el alto de 44px (ese margen transparente del 33% es propio del
   PNG de respaldo, no de una imagen subida por el usuario). */
.site-header__logo .site-logo-img--dark-custom {
	height: 30px;
	filter: none;
}
@media (prefers-color-scheme: dark) {
	:root:not([data-cohasa-theme="light"]) .site-header__logo .site-logo-img--light { display: none; }
	:root:not([data-cohasa-theme="light"]) .site-header__logo .site-logo-img--dark { display: block; }
}
:root[data-cohasa-theme="dark"] .site-header__logo .site-logo-img--light { display: none; }
:root[data-cohasa-theme="dark"] .site-header__logo .site-logo-img--dark { display: block; }
.site-header__actions {
	display: flex;
	align-items: center;
	gap: 8px;
	flex-shrink: 0;
	margin-left: auto;
}
/* Mismo blockGap de theme.json que .site-header__bar > * — acá pega sobre
   los tres bloques del wp:group (theme-toggle/cuenta/carrito): el primero no
   lo recibe (nada antes de él) pero los otros dos sí, quedaban 8px más
   abajo (bug real, con captura). */
.site-header__actions > * {
	margin-block: 0;
}
/* Los <svg> de inc/icons.php ya traen width/height como atributos —
   inline-block solo para que el ícono se alinee con el texto vecino
   (un elemento inline normal queda pegado a la línea base). */
.cohasa-icon {
	display: inline-block;
	vertical-align: middle;
}
.icon-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border-radius: var(--radius);
	background: none;
	border: none;
	color: var(--color-ink);
	cursor: pointer;
	position: relative;
}
.icon-btn:hover { background: var(--color-field); }

/* Toggle de tema: muestra el sol en modo claro (invita a pasar a oscuro) y
   la luna en modo oscuro — el ícono representa a dónde se puede ir, no
   dónde se está. */
.theme-toggle-icon--moon { display: none; }
@media (prefers-color-scheme: dark) {
	:root:not([data-cohasa-theme="light"]) .theme-toggle-icon--sun { display: none; }
	:root:not([data-cohasa-theme="light"]) .theme-toggle-icon--moon { display: block; }
}
:root[data-cohasa-theme="dark"] .theme-toggle-icon--sun { display: none; }
:root[data-cohasa-theme="dark"] .theme-toggle-icon--moon { display: block; }
.icon-btn .cart-count {
	position: absolute;
	top: 4px;
	right: 4px;
	background: var(--color-accent);
	color: var(--color-accent-ink);
	font-size: 10px;
	line-height: 1;
	padding: 3px 5px;
	border-radius: 999px;
	font-weight: 700;
}

.nav-toggle { display: inline-flex; }
/* Nav de categorías (contenido de cohasa_block_primary_nav(), inc/blocks.php):
   base común a las dos superficies donde aparece — el panel dropdown de
   escritorio (dentro de .dropdown__panel) y el drawer de la hamburguesa
   (.site-menu-drawer__nav). Cada superficie define su propio contenedor. */
.site-nav ul,
.site-menu-drawer__nav ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 2px;
}
.site-nav a,
.site-menu-drawer__nav a {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 12px 10px;
	border-radius: var(--radius);
	text-decoration: none;
	font-weight: 600;
	min-height: 44px;
}
.site-nav a .cohasa-icon,
.site-menu-drawer__nav a .cohasa-icon {
	flex-shrink: 0;
}
.site-nav a:hover,
.site-nav a[aria-current="page"],
.site-menu-drawer__nav a:hover,
.site-menu-drawer__nav a[aria-current="page"] {
	color: var(--color-accent-text);
	background: var(--color-field);
}
.site-nav a[aria-current="page"],
.site-menu-drawer__nav a[aria-current="page"] { font-weight: 700; }

/* Subcategorías (hijas de un padre, cohasa_imprimir_categorias_nav()) — en
   escritorio, flyout lateral que se abre al pasar el mouse o llegar con
   teclado al <li> del padre (":hover"/"focus-within", sin JS); en el drawer
   móvil, acordeón que abre/cierra el botón .site-nav__toggle
   (menu-drawer.js). ".site-nav__flecha" (chevron-right) es solo la pista
   visual de escritorio; ".site-nav__toggle" (chevron-down) es el control
   real en móvil — cada uno oculto en la superficie que no le corresponde. */
.site-nav li.site-nav__padre,
.site-menu-drawer__nav li.site-nav__padre {
	position: relative;
	display: flex;
	align-items: center;
	flex-wrap: wrap; /* el link+flecha+botón ocupan la fila; ".site-nav__sub"
	                    (flex-basis:100%, más abajo) cae a la línea siguiente
	                    en el drawer — en escritorio es position:absolute, así
	                    que el wrap no le afecta (queda fuera del flujo). */
}
.site-nav li.site-nav__padre > a,
.site-menu-drawer__nav li.site-nav__padre > a {
	flex: 1;
}
.site-nav__toggle {
	display: none;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	width: 44px;
	height: 44px;
	border: none;
	background: none;
	color: inherit;
	cursor: pointer;
}
.site-nav__toggle svg { transition: transform var(--dur-fast) var(--ease-out); }
.site-nav__toggle[aria-expanded="true"] svg { transform: rotate(180deg); }

/* --- Flyout de escritorio --- */
.site-nav__flecha { flex-shrink: 0; margin-right: 10px; color: var(--color-ink-muted); }
.site-nav .site-nav__sub {
	display: block; /* pisa el "display:flex" de ".site-nav ul" (l.365) —
	                    "columns" no tiene efecto dentro de un flex container */
	position: absolute;
	top: calc(-1 * 6px);
	left: 100%;
	z-index: 1;
	width: 420px;
	max-height: 70vh;
	overflow-y: auto;
	columns: 2;
	column-gap: 4px;
	background: var(--color-surface);
	border: 1px solid var(--color-line-strong);
	border-radius: var(--radius);
	box-shadow: var(--shadow-float);
	padding: 6px;
	opacity: 0;
	visibility: hidden;
	transform: translateX(-4px);
	transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out), visibility var(--dur-fast);
}
/* Puente invisible entre el <li> y el flyout: sin esto el cursor pierde el
   hover al cruzar el hueco (6px de separación visual) y el panel se cierra
   antes de llegar. */
.site-nav .site-nav__sub::before {
	content: "";
	position: absolute;
	top: 0;
	left: -12px;
	width: 12px;
	height: 100%;
}
.site-nav .site-nav__sub li { break-inside: avoid; }
.site-nav li.site-nav__padre:hover > .site-nav__sub,
.site-nav li.site-nav__padre:focus-within > .site-nav__sub {
	opacity: 1;
	visibility: visible;
	transform: none;
}
@media (prefers-reduced-motion: reduce) {
	.site-nav__toggle svg,
	.site-nav .site-nav__sub { transition: none; }
}

/* --- Acordeón del drawer móvil --- */
.site-menu-drawer__nav .site-nav__flecha { display: none; }
.site-menu-drawer__nav .site-nav__toggle { display: inline-flex; }
.site-menu-drawer__nav .site-nav__sub {
	flex-basis: 100%; /* cae bajo el link+botón (li padre en flex-wrap, l.406) */
	width: 100%;
	max-height: 0;
	overflow: hidden;
	visibility: hidden; /* "max-height:0" solo lo recorta visualmente — sin esto
	                       los links colapsados seguían enfocables por teclado y
	                       expuestos al lector de pantalla. "visibility" en una
	                       transición conmuta a "visible" al inicio y a "hidden"
	                       recién al terminar, así no corta la animación. */
	padding-left: 20px;
	transition: max-height var(--dur-base) var(--ease-out), visibility var(--dur-base);
}
.site-menu-drawer__nav .site-nav__toggle[aria-expanded="true"] + .site-nav__sub {
	max-height: 1000px;
	visibility: visible;
}
@media (prefers-reduced-motion: reduce) {
	.site-menu-drawer__nav .site-nav__sub { transition: none; }
}

/* Botón "Categorías" (escritorio) — reusa el mismo formato de pill que
   .cat-chip para no inventar un tercer tipo de botón secundario. */
.site-header__categorias-trigger {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	min-height: 44px;
	padding: 0 14px;
	border-radius: var(--radius);
	border: none;
	background: none;
	color: var(--color-ink);
	font-family: inherit;
	font-weight: 600;
	font-size: 13.5px;
	cursor: pointer;
	white-space: nowrap;
}
.site-header__categorias-trigger:hover { background: var(--color-field); }
.site-header__categorias-trigger svg:last-child { transition: transform var(--dur-fast) var(--ease-out); }
/* :has(:popover-open) en vez de un aria-expanded que ya no escribimos a
   mano: el botón con popovertarget lo gestiona el navegador solo. */
.site-header__categorias:has(.dropdown__panel:popover-open) .site-header__categorias-trigger svg:last-child { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
	.site-header__categorias-trigger svg:last-child { transition: none; }
}

/* Link "Tienda" — mismo formato de pill que .site-header__categorias-trigger,
   siempre visible al lado del dropdown (no es una categoría). */
.site-header__tienda {
	align-items: center;
	gap: 8px;
	min-height: 44px;
	padding: 0 14px;
	border-radius: var(--radius);
	border: none;
	color: var(--color-ink);
	font-weight: 600;
	font-size: 13.5px;
	text-decoration: none;
	white-space: nowrap;
}
.site-header__tienda:hover,
.site-header__tienda[aria-current="page"] { background: var(--color-field); }

/* Panel del dropdown "Categorías" — misma fórmula visual que
   .cohasa-select__panel (forms.css): superficie + borde + sombra flotante,
   nunca la franja de ancho completo que usaba la dirección anterior.
   [popover] + anchor positioning (position-anchor en el HTML, inc/blocks.php)
   reemplazan el JS: el navegador gestiona apertura/cierre (Esc, clic afuera),
   foco y capa superior solos. */
.site-header__categorias .dropdown__panel {
	position: fixed;
	position-area: block-end span-inline-start;
	margin-top: 6px;
	inset: auto;
	z-index: 60;
	min-width: 240px;
	background: var(--color-surface);
	border: 1px solid var(--color-line-strong);
	border-radius: var(--radius);
	box-shadow: var(--shadow-float);
	padding: 6px;
	/* El navegador le pone overflow:auto y color:CanvasText a todo [popover]:
	   lo primero recorta el flyout de .site-nav__sub (position:absolute;
	   left:100%, fuera de la caja del panel) y lo segundo deja el texto
	   negro en modo oscuro. */
	overflow: visible;
	color: var(--color-ink);
	opacity: 0;
	transform: translateY(-4px);
	transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out), display var(--dur-fast) allow-discrete, overlay var(--dur-fast) allow-discrete;
}
.site-header__categorias .dropdown__panel:popover-open {
	opacity: 1;
	transform: none;
}
@starting-style {
	.site-header__categorias .dropdown__panel:popover-open {
		opacity: 0;
		transform: translateY(-4px);
	}
}
@media (prefers-reduced-motion: reduce) {
	.site-header__categorias .dropdown__panel { transition: none; }
}
/* Sin CSS anchor positioning (navegador viejo), el panel [popover] se
   promueve a la capa superior y position:relative del wrapper deja de
   aplicarle — quedaría centrado en el viewport, no bajo el botón. No hay
   forma correcta de arreglarlo solo con CSS (haría falta JS con
   getBoundingClientRect, justo lo que este cambio evita); queda pendiente
   verificar soporte real de anchor positioning en Firefox/Safari antes de
   dar esto por terminado (ver plan).*/

/* --- Menú móvil a pantalla completa (inc/menu-drawer.php) ---
   Mismo patrón que el overlay del buscador standalone
   (.site-search--header.is-abierto .site-search__box, site-search.css):
   position:fixed; inset:0, sin scrim ni ancho máximo — pedido explícito de
   que ocupe toda la pantalla, no un panel lateral angosto. */
.site-menu-drawer {
	position: fixed;
	inset: 0;
	z-index: 100;
	display: flex;
	flex-direction: column;
	background: var(--color-surface);
	overflow-y: auto;
	overscroll-behavior: contain;
}
.site-menu-drawer[hidden] { display: none; }
body.has-menu-open { overflow: hidden; }
.site-menu-drawer:focus-visible,
.site-menu-drawer:focus { outline: none; }
.site-menu-drawer__header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding: 14px var(--gutter);
	border-bottom: 1px solid var(--color-line);
	flex-shrink: 0;
}
.site-menu-drawer__title {
	font-family: var(--font-display);
	font-size: 19px;
	margin: 0;
}
.site-menu-drawer__body {
	padding: var(--gutter);
	display: flex;
	flex-direction: column;
	gap: 20px;
}
.site-menu-drawer .site-search--inline {
	margin: 0;
	max-width: none;
}
@media (min-width: 900px) {
	/* El drawer es exclusivo de móvil: a 900px el menú vuelve al dropdown
	   "Categorías" del header y el buscador a su campo en la barra. Sin este
	   reset, pasar a escritorio con el drawer abierto (o con foco perdido)
	   lo dejaba visible encima del header de escritorio. */
	.site-menu-drawer { display: none !important; }
}

/* Buscador — rehecho desde cero: antes tenía un borde verde grueso (2px)
   SIEMPRE encendido, no solo al enfocar, y quedaba visualmente ruidoso y
   desconectado del resto de los inputs del sitio (que usan --color-line,
   1px). Ahora usa el mismo lenguaje visual que cualquier input del tema:
   borde sutil en reposo, fondo --color-field (no --color-surface, así se
   distingue del header blanco), y el anillo de foco estándar del sitio al
   enfocar — nada de verde permanente. */
.site-search {
	margin: 0 0 14px;
}
.site-search__field {
	display: flex;
	align-items: center;
	gap: 10px;
	background: var(--input-bg);
	border: 1px solid var(--input-border);
	border-radius: var(--input-radius);
	padding: var(--input-py) var(--input-px);
	min-height: var(--input-h);
	transition: border-color var(--dur-fast) var(--ease-out);
}
.site-search__field:hover { border-color: var(--input-border-hover); }
.site-search__field svg { color: var(--color-ink-soft); flex-shrink: 0; }
.site-search input {
	border: none;
	background: none;
	font-size: 16px;
	color: var(--color-ink);
	width: 100%;
	min-height: 24px;
}
/* El botón "borrar" propio (site-search.css) reemplaza a la X nativa. */
.site-search input[type="search"]::-webkit-search-cancel-button { display: none; }
/* outline Y box-shadow: la regla global input:focus-visible (arriba) le
   pone su propio box-shadow (--focus-ring, verde en modo oscuro) directo al
   input — sin anularlo acá quedaban DOS aros superpuestos (el del input,
   verde y ajustado; el de .site-search__field:focus-within, neutro y más
   ancho). El indicador de foco lo da el wrapper; el input no necesita el
   suyo propio. */
.site-search input:focus { outline: none; box-shadow: none; }
/* Anillo de foco propio del buscador — a propósito NO usa --focus-ring ni
   el verde de marca: en modo oscuro --color-accent-text apunta al verde
   brillante (#4af835), y ese verde a todo el borde de un input tan ancho
   se veía como un rectángulo verde duro (reporte real, con captura). Se usa
   un anillo neutro (--color-ink, el mismo tono del texto en cada tema) en
   vez del acento de marca — visible y con contraste suficiente sin gritar. */
.site-search__field:focus-within {
	border-color: var(--input-border-hover);
	box-shadow: 0 0 0 3px var(--input-ring);
}

@media (min-width: 900px) {
	.nav-toggle { display: none; }
	.site-header__bar { padding-block: 12px; }
	.site-header__categorias { display: inline-flex; }
	.site-header__tienda { display: inline-flex; }
	.site-header .site-search--header {
		flex: 1 1 auto;
		max-width: 720px;
		margin: 0;
	}
	.site-search { max-width: none; margin: 0; }
}

/* --- Eyebrow (usado por templates/404.html) --- */
.hero__eyebrow {
	font-size: 12px;
	letter-spacing: .1em;
	text-transform: uppercase;
	opacity: .8;
	margin: 0 0 10px;
	font-weight: 700;
}

/* --- Categorías --- */
.cat-scroll {
	display: flex;
	gap: 8px;
	overflow-x: auto;
	padding: 0 0 20px;
	scrollbar-width: thin;
}
.cat-chip {
	flex: 0 0 auto;
	font-weight: 700;
	font-size: 13px;
	padding: 10px 16px;
	min-height: 44px;
	display: inline-flex;
	align-items: center;
	border-radius: 999px;
	background: var(--color-field);
	border: 1px solid var(--color-line-strong); /* 3:1 (WCAG 1.4.11): el borde es lo único que lo marca como control */
	color: var(--color-ink);
	text-decoration: none;
	white-space: nowrap;
}

/* --- Tarjetas de categoría (bloque cohasa/categorias-destacadas) --- */
/* auto-fit, no repeat(2|4,1fr) fijo: con 3 categorías (sin +X) un conteo fijo de
   columnas deja la 4ª celda en blanco. auto-fit colapsa la columna sin ítem y
   reparte el ancho entre las que sí hay, para cualquier cantidad de 1 a 4. */
.cat-grid {
	list-style: none;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
	gap: 14px;
	padding: 0 0 30px;
}
@media (min-width: 900px) {
	.cat-grid { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
}
@media (min-width: 1180px) {
	.cat-grid { gap: 20px; }
}
/* El bloque contenedor cohasa/categorias-destacadas (InnerBlocks reales,
   ver inc/blocks.php) pasa su propio wrapper (.wp-block-cohasa-categorias-destacadas,
   generado por useBlockProps.save() en editor-blocks.js) dentro del $content
   que WordPress le entrega al render_callback — ese wrapper queda como
   ÚNICO hijo de <ul class="cat-grid">, rompiendo el grid (una sola celda
   con todas las tarjetas apiladas adentro en vez de una celda por tarjeta).
   display:contents lo saca del árbol de layout sin sacarlo del DOM: sus
   hijos (los <li class="cat-card">) pasan a ser hijos directos del grid. */
.cat-grid > .wp-block-cohasa-categorias-destacadas {
	display: contents;
}
.cat-card {
	position: relative;
	background: var(--color-surface);
	border: 1px solid var(--color-line);
	border-radius: var(--radius);
	overflow: hidden;
}
.cat-card__link {
	display: flex;
	flex-direction: column;
	height: 100%;
	color: inherit;
	text-decoration: none;
}
/* Foco hacia adentro: con overflow:hidden el box-shadow de --focus-ring se recorta. */
.cat-card__link:focus-visible {
	outline: 3px solid var(--color-focus);
	outline-offset: -3px;
}
/* Cuadrada: la imagen ocupa toda la card, el texto va encima con un velo
   (excepción a "las imágenes nunca se recortan" — no es foto de producto en
   contexto de compra, es ilustrativa de la categoría; ver design.md). */
.cat-card__media {
	position: relative;
	aspect-ratio: 1 / 1;
	background: var(--color-field);
}
.cat-card__media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Velo oscuro fijo (--color-scrim, ver tokens.css) para que el texto blanco
   tenga contraste sobre cualquier foto. */
.cat-card .cat-card__media::after {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--color-scrim);
}
@media (prefers-contrast: more) {
	.cat-card .cat-card__media::after { background: rgb(13 17 23 / 0.75); }
}
.cat-card__placeholder {
	position: absolute;
	inset: 0;
	display: grid;
	place-items: center;
	color: var(--color-scrim-ink);
	opacity: .7;
}
.cat-card__body {
	position: absolute;
	inset: 0;
	display: grid;
	place-content: center;
	gap: 2px;
	padding: 12px 14px;
	text-align: center;
}
.cat-card__name {
	font-size: 14px;
	font-weight: 700;
	color: var(--color-scrim-ink);
}
.cat-card__count {
	font-size: 12.5px;
	color: var(--color-scrim-ink);
	/* Sin opacity: el peor caso de contraste del velo (--color-scrim, 5.2:1 AA)
	   ya asume blanco a opacidad plena — el .85 anterior bajaba el ratio real
	   a 4.21:1 sobre foto blanca, bajo AA. */
}

/* --- Grilla de productos --- */
.section-title {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 0 0 14px;
}
.section-title h2 { font-size: 19px; margin: 0; }
.section-title__link { margin-left: auto; }

/* Sin max-width/margin/padding-inline propios: su único uso hoy
   (inc/favoritos.php) siempre cuelga de un <main class="site-main
   container"> que ya trae ese gutter — duplicarlo aquí sumaba un segundo
   gutter en mobile (el `.container` ya aporta margen, esta grilla volvía a
   aportar padding encima). */
.product-grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 14px;
	padding-bottom: 30px;
}
@media (min-width: 640px) {
	.product-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 1180px) {
	.product-grid { grid-template-columns: repeat(4, 1fr); gap: 20px; }
}

.product-card {
	background: var(--color-surface);
	border: 1px solid var(--color-line);
	border-radius: var(--radius);
	box-shadow: var(--shadow-card);
	overflow: hidden;
	display: flex;
	flex-direction: column;
}
.product-card a.product-card__link {
	text-decoration: none;
	color: inherit;
	display: flex;
	flex-direction: column;
	flex: 1;
}
.product-card a.product-card__link:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
}
.product-card__media {
	aspect-ratio: 1 / 1;
	background: var(--color-field);
	position: relative;
}
.product-card__media img { width: 100%; height: 100%; object-fit: contain; }
.product-card__placeholder { position: absolute; inset: 0; display: grid; place-items: center; color: var(--color-ink-soft); }
/* Wrapper: apila badge (Oferta/Kit) e ícono de variantes con un gap fijo,
   sin calcular a mano el alto del badge para separarlos (ver commit previo,
   el offset en px quedaba desalineado — círculo vs. rectángulo, gap dispar). */
.product-card__badges {
	position: absolute;
	top: 8px;
	left: 8px;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 6px;
}
.product-card__badge {
	background: var(--color-oferta-bg);
	color: var(--color-oferta-ink);
	font-size: 11px;
	font-weight: 700;
	padding: 4px 8px;
	border-radius: 5px;
}
/* Mismo patrón bg tenue + texto fuerte que .cuenta ya usa para error
   (assets/css/cuenta.css) — nunca el bg sólido de oferta, para no leerse
   como una promoción. */
.product-card__badge--sin-stock {
	background: color-mix(in srgb, var(--color-error) 18%, var(--color-surface));
	color: var(--color-error);
}
.product-card__badge--reserva {
	background: color-mix(in srgb, var(--color-ink-soft) 18%, var(--color-surface));
	color: var(--color-ink-soft);
}
/* Misma forma/alto que el badge (rectángulo redondeado, no círculo) para
   que la pila se lea como un solo sistema de etiquetas. */
.product-card__variantes {
	display: grid;
	place-items: center;
	width: 26px;
	height: 26px;
	background: var(--color-surface);
	color: var(--color-ink);
	border-radius: 5px;
	box-shadow: var(--shadow-sm);
}
.product-card__body { padding: 8px 10px 10px; display: flex; flex-direction: column; gap: 3px; flex: 1; }
.product-card__name { font-size: 13.5px; font-weight: 600; line-height: 1.3; }

/* Rating: SVG propios (no wc_get_rating_html(), ver comentario en
   cohasa_product_rating_html(), inc/template-tags.php) + conteo real de
   reseñas. --color-accent-text es el verde de marca ya oscurecido para
   cumplir contraste como texto/ícono (ver tokens.css). */
.product-card__rating { display: flex; align-items: center; gap: 5px; font-size: 11.5px; color: var(--color-ink-soft); min-height: 16px; }
.product-card__rating--empty { font-style: italic; }
.product-card__stars { display: inline-flex; gap: 1px; color: var(--color-accent-text); }
.product-card__star { width: 13px; height: 13px; }
/* --color-line (borde sutil, ~1.3:1) es invisible para un gráfico con
   significado (estrella vacía vs. llena) — WCAG 1.4.11 pide 3:1 no-textual.
   --color-line-strong ya está calculado para eso (3.08-3.89:1 según fondo,
   ver tokens.css); en oscuro --color-line es casi negro sobre el panel
   translúcido del carrusel, quedaba invisible (bug real, reportado 2026-09-24). */
.product-card__star:not(.product-card__star--full) { color: var(--color-line-strong); }
.product-card__rating-count { color: var(--color-ink-soft); }

/* order:-1 en <ins> lo pone primero visualmente sin tocar el orden del DOM
   — WooCommerce genera <del> antes que <ins>, y ese orden se mantiene para
   lectores de pantalla ("antes $X, ahora $Y"). Sin oferta no hay <del>: un
   solo hijo, sin efecto visible. A diferencia de flex-direction: row-reverse
   (usado antes acá), order:-1 no invierte el rango mín–máx de productos
   agrupados/variables (ese span no tiene <ins>/<del>, queda intacto) —
   sin esto el precio quedaba pegado al borde derecho en vez de al izquierdo
   (el span se estira a todo el ancho por el stretch de .product-card__body). */
.product-card__price { display: flex; align-items: baseline; gap: 6px; font-family: var(--font-mono); font-size: 15px; font-weight: 700; margin-top: auto; }
.product-card__price del { color: var(--color-ink-soft); font-weight: 500; font-size: 12.5px; text-decoration: line-through; }
.product-card__price ins { order: -1; text-decoration: none; }

.product-card__stock { font-size: 11.5px; color: var(--color-ok); display: flex; align-items: center; gap: 5px; }
.product-card__stock--out { color: var(--color-error); }
.product-card__stock--reserva { color: var(--color-ink-soft); }

/* ---------------------------------------------------------------- */
/* Tarjeta "vitrina": imagen 4/5 recortada, panel compacto con datos  */
/* encima, botón que aparece al pasar el mouse. Es la tarjeta de todo */
/* el sitio (carrusel de home/relacionados y grilla de tienda/        */
/* categoría/búsqueda) — mismo CSS acá, sin overrides por contexto,   */
/* para que hablen igual. Vive en main.css (no en carousel.css) por   */
/* eso mismo: no es privativa del carrusel. */
/* ---------------------------------------------------------------- */
.product-card--vitrina .product-card__media { aspect-ratio: 4 / 5; }
.product-card--vitrina .product-card__media img { object-fit: cover; }
.product-card--vitrina a.product-card__link:focus-visible { box-shadow: none; }
/* La sombra de foco se recorta con overflow:hidden; un outline hacia adentro no. */
.product-card--vitrina:has(:focus-visible) {
	outline: 3px solid var(--color-focus);
	outline-offset: -3px;
}

.product-card--vitrina .product-card__body {
	position: absolute;
	inset: auto 0 0 0;
	flex: none;
	/* Alto fijo, no por contenido (bug real, visto 2026-09-23: sin esto el panel
	   medía distinto según hubiera o no reseñas — tapaba distinta porción de la
	   foto según la tarjeta). 80px alcanza el peor caso ya compactado (nombre a
	   1 línea + estrellas + precio + paddings, con un gap de 6px entre cada uno
	   para que no queden pegados); el chip de oferta ya no vive acá, flota sobre
	   la foto (ver .oferta-aviso más abajo). justify-content ancla el contenido
	   abajo para que el precio quede a la misma altura tenga o no reseñas. */
	height: 80px;
	justify-content: flex-end;
	gap: 6px;
	padding: 8px 12px 8px;
	/* border-radius propio (no solo el overflow:hidden del .product-card padre):
	   con backdrop-filter, Chromium no recorta bien el blur cuando el redondeo
	   viene solo del ancestro — se veía un sangrado de la foto (amarillo/naranja)
	   asomando en las esquinas inferiores del panel, visto en /tienda/ con fotos
	   de colores brillantes. Solo abajo: las esquinas de arriba del panel son
	   internas a la tarjeta, no coinciden con el radio de .product-card. */
	border-radius: 0 0 var(--radius) var(--radius);
	background: color-mix(in srgb, var(--color-surface) 88%, transparent);
	-webkit-backdrop-filter: blur(10px);
	backdrop-filter: blur(10px);
	transition: height var(--dur-base) var(--ease-out), padding-bottom var(--dur-base) var(--ease-out);
}
.product-card--vitrina .product-card__name {
	/* Una sola línea con "…", no -webkit-line-clamp: dentro de un flex column
	   compacto esa combinación recortaba el tope de las letras (bug real, visto
	   2026-09-24) en vez de truncar limpio. */
	font-size: 13px;
	line-height: 1.4;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.product-card--vitrina .product-card__price {
	margin-top: 0;
	font-family: var(--font-display);
	font-size: 1.125rem;
	line-height: 1.15;
	letter-spacing: -.02em;
}
.product-card--vitrina .product-card__price del { font-family: var(--font-body); font-size: .75rem; }
/* El panel se mantiene corto: cuotas y stock viven en la ficha. "Sin stock"
   sí se conserva, porque cambia lo que hace el botón. */
.product-card--vitrina .product-card__stock:not(.product-card__stock--out):not(.product-card__stock--reserva) { display: none; }
/* Estrellas al mínimo para que el panel compacto alcance sin desbordar; el
   conteo de reseñas ("4,5 (12)") se oculta solo visualmente — mismo patrón
   que .screen-reader-text — porque el panel ya no tiene alto para mostrarlo,
   pero el dato sigue disponible para lectores de pantalla.
   !important necesario: cohasa_icon_html() (inc/icons.php) fija el tamaño del
   ícono con `style` inline a propósito (reserva espacio mientras Lucide carga,
   evita salto de layout) — un `style` inline le gana a cualquier selector de
   clase, así que sin !important esta regla no tiene efecto (bug real, visto
   2026-09-24: la estrella seguía renderizando a 20px pese a esta regla, y el
   panel recortaba el nombre por calcular mal el alto disponible). */
.product-card--vitrina .product-card__rating { font-size: 10px; min-height: 11px; }
.product-card--vitrina .product-card__star { width: 9px !important; height: 9px !important; }
.product-card--vitrina .product-card__rating-count {
	position: absolute !important;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}
/* Chip de oferta ("Termina en...") fuera del panel: flota sobre la foto, pegado
   arriba del panel translúcido. Antes vivía dentro de .product-card__body, pero
   ahí obligaba a un alto fijo mayor para el caso poco frecuente de oferta +
   reseñas a la vez — la mayoría de las tarjetas quedaban con espacio vacío.
   .oferta-aviso ya trae fondo sólido propio (--color-oferta-bg), legible sobre
   la foto sin blur. El panel es position:absolute, así que sirve de contenedor
   de referencia. */
.product-card--vitrina .oferta-aviso {
	position: absolute;
	left: 12px;
	bottom: calc(100% + 8px);
	margin: 0;
	padding: 2px 8px;
	font-size: 10.5px;
}

.product-card__add { display: none; }
.product-card--vitrina .product-card__add {
	display: inline-flex;
	position: absolute;
	left: 12px;
	right: 12px;
	bottom: 12px;
	z-index: 1;
	align-items: center;
	justify-content: center;
	gap: 8px;
	min-height: 44px;
	padding: 0 16px;
	border-radius: var(--radius);
	background: var(--color-accent);
	color: var(--color-accent-ink);
	font: 700 15px/1 var(--font-body);
	text-decoration: none;
	opacity: 0;
	pointer-events: none;
	transition: opacity var(--dur-fast) var(--ease-out);
}
/* Sin stock: mismo lugar/tamaño, pero neutro y sin la promesa de "Agregar"
   — el link ya no suma al carro, lleva a la ficha (ver cohasa_render_product_card()). */
.product-card--vitrina .product-card__add[aria-disabled="true"] {
	background: var(--color-field);
	color: var(--color-ink-soft);
}
/* +56px de alto (80→136px), igual al +56px de padding-bottom (8→64px, =
   12px bottom + 44px botón + 8px separación): el mismo espacio disponible
   para nombre/estrellas/precio se mantiene en ambos estados, solo cambia
   cuánto de ese espacio queda arriba (contenido) vs abajo (botón). Medido en
   navegador real (Chrome DevTools) contra el alto de contenido sin recortar
   — con menos que esto el nombre se comprimía ~2px por el algoritmo de
   flexbox (bug real, visto 2026-09-24). */
.product-card--vitrina:hover .product-card__body,
.product-card--vitrina:focus-within .product-card__body { height: 136px; padding-bottom: 64px; }
.product-card--vitrina:hover .product-card__add,
.product-card--vitrina:focus-within .product-card__add { opacity: 1; pointer-events: auto; }
/* Sin hover (táctil): el panel ya está expandido y el botón siempre visible. */
@media (hover: none) {
	.product-card--vitrina .product-card__body { height: 136px; padding-bottom: 64px; }
	.product-card--vitrina .product-card__add { opacity: 1; pointer-events: auto; }
}

@media (prefers-reduced-motion: reduce) {
	.product-card--vitrina .product-card__body,
	.product-card--vitrina .product-card__add { transition: none; }
}

/* --- Banner angosto (mensajes tipo despacho/promo) --- */
.info-banner {
	background: var(--color-field);
	border-block: 1px solid var(--color-line-strong); /* 3:1 WCAG 1.4.11: franja full-bleed, --color-line (1.24:1) no separa del fondo */
	color: var(--color-ink);
	text-align: center;
	font-size: 13px;
	font-weight: 700;
	padding: 10px var(--gutter);
	margin: 0;
}

/* --- Ficha de producto (templates/single-product.html, bloques nativos +
   cohasa/*) ---
   Sin .pdp en <main>: esa clase traía un display:grid propio (ver historial)
   pensado para hijos directos de una estructura vieja de un solo <img> —
   ahora los hijos reales de <main> son bloques distintos (breadcrumb,
   columnas, tabs, relacionados) y ese grid los rompía a todos. El layout de
   dos columnas vive en .pdp__layout (core/columns), no en <main>.
   La galería (cohasa/product-gallery) no necesita CSS acá: adentro
   renderiza nuestro override (woocommerce/single-product/product-image.php)
   con su propio sistema completo en producto.css. */
.pdp__layout { padding-top: 8px; padding-bottom: 24px; }
.pdp__gallery-col { min-width: 0; }
.pdp__summary-col { min-width: 0; }
.pdp__title { margin-top: 4px; }
/* cohasa/product-price (antes wp:woocommerce/product-price, que no acepta
   className en su bloque raíz): se apunta a la clase estable que emite el
   wrapper del bloque. font-family la pone .woocommerce-Price-amount
   (woocommerce.css); acá solo tamaño/peso/espaciado propios de la ficha. */
.wp-block-cohasa-product-price {
	font-size: 24px;
	font-weight: 800;
	margin: 6px 0 18px;
}
.wp-block-cohasa-product-price del { font-size: 15px; color: var(--color-ink-soft); font-weight: 500; margin-right: 10px; }
.pdp__excerpt { color: var(--color-ink-soft); margin-bottom: 16px; }

/* core/columns apila bajo 782px por defecto (breakpoint propio del bloque,
   fuera de nuestra tabla) — se alinea al corte "md" (900px) de design.md
   para que la ficha cambie de layout en el mismo punto que el resto del
   sitio, no en un valor distinto sin relación. */
@media (max-width: 899px) {
	.pdp__layout.wp-block-columns { flex-wrap: wrap; }
	.pdp__gallery-col,
	.pdp__summary-col { flex-basis: 100% !important; }
}
@media (min-width: 900px) {
	.pdp__gallery-col { flex-basis: 50% !important; }
	.pdp__summary-col { flex-basis: 50% !important; }
}

/* --- Breadcrumb --- */
/* Único componente de breadcrumb del sitio (cohasa_breadcrumb(),
   inc/template-tags.php) — ficha de producto, listados de tienda, Mi cuenta,
   páginas y entradas. Sin max-width/margin/padding-inline: siempre se usa
   dentro de un <main class="site-main container"> (o del shop-archive
   equivalente), que ya trae el gutter. */
.breadcrumb {
	font-size: 12px;
	color: var(--color-ink-soft);
	padding: 14px 0 4px;
}
.breadcrumb__list {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	margin: 0;
	padding: 0;
	list-style: none;
}
.breadcrumb__item { display: flex; align-items: center; gap: 4px; }
/* Sin subrayado (reset global de arriba): se distingue por peso de fuente,
   sobre --color-ink-soft ya con contraste AA. */
.breadcrumb__item a { font-weight: 600; }
.breadcrumb__item .cohasa-icon { flex-shrink: 0; opacity: .6; }
.breadcrumb__item:last-child .cohasa-icon { display: none; }
.breadcrumb__volver { display: none; align-items: center; gap: 4px; font-weight: 600; }

/* Móvil: la lista completa ocupa demasiado ancho con 3+ niveles — se
   reemplaza por un único «‹ Volver a {nivel anterior}», sin JS. */
@media (max-width: 639px) {
	.breadcrumb__list { display: none; }
	.breadcrumb__volver { display: inline-flex; }
}

/* --- Aviso de oferta (inc/ofertas.php) --- */
/* "En oferta" (más de X horas) o cuenta regresiva (menos), configurable en
   Cohasa > Ofertas. Semántico: --color-oferta-bg/-ink, nunca el verde de
   marca (el color nunca es el único portador de significado: el texto ya
   lo dice). El número de la cuenta va en JetBrains Mono, igual que
   cualquier otro precio/cifra del sitio (ver design.md). */
.oferta-aviso {
	display: inline-flex;
	align-items: center;
	align-self: flex-start; /* dentro de .product-card__body (flex column) no se estira al ancho completo */
	gap: 6px;
	margin: 4px 0 0;
	padding: 4px 10px;
	font-size: 12px;
	font-weight: 600;
	color: var(--color-oferta-ink);
	background: var(--color-oferta-bg);
	border-radius: 999px;
}
.oferta-aviso__contador { font-family: var(--font-mono); }

/* --- Franja de cupón (cohasa/cupon-banner, inc/blocks.php) ---
   Ancho completo, mismo esquema semántico que .oferta-aviso (--color-oferta-bg/-ink:
   "esto es un descuento", nunca el verde de marca) — se apila en mobile. El
   chip (.cohasa-cupon-chip) se reutiliza tal cual dentro de un slide del hero
   (cohasa_cupon_chip_html()), ahí SIN el fondo propio del banner: hereda el
   fondo oscuro semitransparente que ya trae .hero-slide__body. */
.cohasa-cupon-banner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 8px 20px;
	padding: 12px 20px;
	background: var(--color-oferta-bg);
	color: var(--color-oferta-ink);
	text-align: center;
}
.cohasa-cupon-banner--vacio {
	/* Solo en el editor (cohasa_editor_preview()) — nunca en el front. */
	background: var(--color-line);
	color: var(--color-ink-soft);
	padding: 12px 20px;
	margin: 0;
	font-size: 13px;
}
.cohasa-cupon-banner__eyebrow {
	font-size: 12px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: .04em;
	opacity: .85;
}

.cohasa-cupon-chip {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 6px 14px;
}
.cohasa-cupon-chip__codigo {
	padding: 3px 10px;
	font-family: var(--font-mono);
	font-weight: 700;
	letter-spacing: .03em;
	background: color-mix(in srgb, currentColor 18%, transparent);
	border: 1px dashed currentColor;
	border-radius: var(--radius);
}
.cohasa-cupon-chip__desc {
	font-weight: 600;
}
.cohasa-cupon-chip__cuenta {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	font-size: 13px;
	opacity: .9;
}
.cohasa-cupon-chip__contador {
	font-family: var(--font-mono);
}
.cohasa-cupon-chip__copiar {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 6px 14px;
	font-size: 13px;
	font-weight: 700;
	color: inherit;
	background: transparent;
	border: 1px solid currentColor;
	border-radius: 999px;
	cursor: pointer;
	transition: background-color .15s ease;
}
.cohasa-cupon-chip__copiar:hover {
	background: color-mix(in srgb, currentColor 15%, transparent);
}
.cohasa-cupon-chip__copiar.is-copiado {
	background: color-mix(in srgb, currentColor 25%, transparent);
}

/* Dentro del hero: mismo chip, pero sobre la franja oscura semitransparente
   de .hero-slide__body (main.css, más abajo) en vez de su propio fondo. */
.hero-slide__body .cohasa-cupon-chip {
	justify-content: flex-start;
	margin: 4px 0 12px;
}

/* --- Footer: denso, navy, tipo marketplace ---
   --color-hero-ink-soft cubre el texto secundario repetido acá (antes
   #c3d4e3 hardcodeado dos veces). #9fb4c8 (un solo uso) y el rgba blanco del
   borde quedan literales — son específicos de este footer y no se repiten
   en otro lado del sitio, así que no ganan nada con un token propio. */
.site-footer {
	background: var(--color-hero-bg);
	color: var(--color-hero-ink-soft);
	margin-top: 40px;
	font-size: 13px;
}
.site-footer a { color: var(--color-hero-ink-soft); text-decoration: none; }
.site-footer a:hover { color: var(--color-accent); text-decoration: underline; }

/* Mobile-first: marca arriba y columnas como acordeón (<details>, ver
   cohasa_footer_col_html()); desde 760px, grilla de 4 con las columnas
   siempre abiertas. Los hijos directos llevan margin 0 para anular el
   margin-block que el layout "flow" del grupo les pone entre bloques. */
.site-footer__top { padding: 26px var(--gutter) 12px; display: grid; }
.site-footer__top > *,
.site-footer__bottom > * { margin: 0; }
.footer-marca { display: grid; gap: 14px; padding-bottom: 14px; justify-items: start; }
.footer-marca__logo img { height: 44px; width: auto; filter: invert(1); } /* mismo PNG monocromático + invert que el logo oscuro del header */
.footer-marca__desc { margin: 0; max-width: 36ch; }
.footer-redes { display: flex; gap: 8px; list-style: none; margin: 0; padding: 0; }
.footer-redes a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border-radius: var(--radius);
	border: 1px solid color-mix(in srgb, var(--color-hero-ink) 22%, transparent);
}
.footer-redes a:hover { background: color-mix(in srgb, var(--color-hero-ink) 10%, transparent); text-decoration: none; }
.footer-col { border-top: 1px solid color-mix(in srgb, var(--color-hero-ink) 12%, transparent); }
.footer-col__titulo {
	display: flex;
	align-items: center;
	justify-content: space-between;
	min-height: 48px;
	cursor: pointer;
	list-style: none;
	color: var(--color-hero-ink);
	font-family: var(--font-display);
	font-size: 14px;
	font-weight: 600;
}
.footer-col__titulo::-webkit-details-marker { display: none; }
.footer-col__titulo .cohasa-icon { transition: transform var(--dur-fast) var(--ease-out); }
.footer-col[open] .footer-col__titulo .cohasa-icon { transform: rotate(180deg); }
.footer-col__cuerpo { padding-bottom: 14px; }
.footer-col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.footer-contacto li { display: flex; gap: 10px; align-items: flex-start; }
.footer-contacto li .cohasa-icon { flex-shrink: 0; margin-top: 1px; color: var(--color-accent); }
.site-footer__bottom {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 10px 24px;
	border-top: 1px solid color-mix(in srgb, var(--color-hero-ink) 12%, transparent);
	padding: 14px var(--gutter) calc(14px + env(safe-area-inset-bottom));
	font-size: 12px;
	color: #9fb4c8;
}
.footer-pagos { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; margin: 0; padding: 0; }
.footer-pagos li {
	border: 1px solid color-mix(in srgb, var(--color-hero-ink) 22%, transparent);
	border-radius: 6px;
	padding: 4px 9px;
	font-size: 11.5px;
	font-weight: 600;
	color: var(--color-hero-ink);
	display: inline-flex;
	align-items: center;
	gap: 6px;
}
/* Logo de marca: fondo blanco fijo en los dos temas (el footer es navy fijo). */
.footer-pagos li.footer-pagos__logo { background: #fff; border-color: #fff; padding: 4px 8px; }
.footer-pagos__logo img { display: block; height: 20px; width: auto; }
@media (min-width: 760px) {
	.site-footer__top { grid-template-columns: 1.3fr 1fr 1fr 1.2fr; gap: 32px; padding-block: 32px 26px; }
	.footer-marca { padding-bottom: 0; }
	.footer-col { border-top: 0; }
}
/* Columnas abiertas y sin interacción en desktop: `::details-content` deja
   ver el cuerpo aunque el <details> esté cerrado. Sin soporte del
   pseudo-elemento el acordeón sigue funcionando también en desktop. */
@supports selector(::details-content) {
	@media (min-width: 760px) {
		.footer-col::details-content { content-visibility: visible; }
		.footer-col__titulo {
			pointer-events: none;
			min-height: 0;
			margin-bottom: 12px;
			font-size: 13px;
			letter-spacing: .04em;
			text-transform: uppercase;
		}
		.footer-col__titulo .cohasa-icon { display: none; }
	}
}
@media (prefers-reduced-motion: reduce) { .footer-col__titulo .cohasa-icon { transition: none; } }

/* La navegación mobile (Inicio/Tienda/Carrito/Cuenta) vivía en una tabbar
   fija redundante con el header de fila única: éste ya cubre las mismas
   cuatro acciones (logo, dropdown Categorías dentro del drawer de la
   hamburguesa, carrito, cuenta) sin duplicar nada abajo. El bloque
   cohasa/mobile-tabbar, su render y su CSS se eliminaron por completo en
   la auditoría de 2026-09-22 (confirmado sin uso en ningún template/part
   ni en el editor). Si se retoma esta dirección, hay que rehacerlo. */

/* ==========================================================================
   Home "Marketplace funcional" — banner promo Cyber Ferretero + franja de
   confianza restyleada. Ver propuestas-html/direccion-4-marketplace-funcional/.
   Sección agregada al final a propósito para minimizar choque con el resto
   del archivo (otro proceso edita secciones de header/footer más arriba).
   ========================================================================== */

/* --- Hero de portada (bloque cohasa/hero-slider + cohasa/hero-slide) ---
   Fade entre slides (no transform/scroll: cada slide ocupa toda la caja,
   position:absolute, y solo el activo es opaco/interactivo — ver hero-slider.js).
   .hero-slider__track hereda el mismo margin-inline con max() que .hero
   (ver más abajo) para quedar a ancho de container, no del viewport. */
.hero-slider {
	position: relative;
	margin-block: var(--gutter);
	margin-inline: max(var(--gutter), calc((100% - var(--maxw)) / 2));
	max-width: var(--maxw);
	border-radius: var(--radius-lg);
	overflow: hidden;
}
.hero-slider__track {
	position: relative;
	height: 360px;
}
/* Mismo bug/arreglo que .cat-grid > .wp-block-cohasa-categorias-destacadas
   (ver ahí el porqué): el $content que WordPress le pasa al render_callback
   incluye el propio wrapper del bloque contenedor (ContenedorSave,
   editor-blocks.js), que queda como único hijo de .hero-slider__track. */
.hero-slider__track > .wp-block-cohasa-hero-slider {
	display: contents;
}
/* Solo dentro del iframe del editor: .wp-block-cohasa-hero-slide es el
   wrapper que useBlockProps() le pone a cada cohasa/hero-slide (ver
   EditorHeroSlide, editor-blocks.js) — el front no lo tiene, ahí
   cohasa_block_hero_slide() imprime .hero-slide directo. Se ve un solo
   slide a la vez (el seleccionado, o el primero si ninguno lo está) igual
   que en el front, en vez de los 3 superpuestos con opacity:0 apilada
   (.hero-slide sola ya es position:absolute+opacity:0 por defecto).
   Selector con el padre directo (0,2,0), no genérico: en el editor
   .hero-slider__track es hijo de .wp-block-cohasa-hero-slider (al revés
   que en el front, ver la regla de arriba) y cada slide cuelga directo de
   .hero-slider__track. Necesita esa especificidad extra porque el core
   trae `.block-editor-block-list__layout .block-editor-block-list__block
   { position:relative }` (también 0,2,0) — con un solo `.wp-block-cohasa-
   hero-slide` (0,1,0) esa regla del core ganaba y el slide quedaba
   position:relative con altura 0 (inset:0 no tiene nada que "estirar" en
   un padre no-absoluto), invisible aunque el HTML sí tenía el contenido
   (bug real, visto en el Editor del sitio). */
.hero-slider__track > .wp-block-cohasa-hero-slide {
	position: absolute;
	inset: 0;
	display: none;
}
.hero-slider__track > .wp-block-cohasa-hero-slide.is-editor-activo {
	display: block;
}
.wp-block-cohasa-hero-slide.is-editor-activo .hero-slide {
	opacity: 1;
	visibility: visible;
}
.hero-slide {
	position: absolute;
	inset: 0;
	opacity: 0;
	visibility: hidden;
	transition: opacity var(--dur-slow, .5s) var(--ease-out, ease);
	display: flex;
	align-items: flex-end;
}
.hero-slide.is-activo {
	opacity: 1;
	visibility: visible;
	z-index: 1;
}
.hero-slide__media {
	position: absolute;
	inset: 0;
	background: var(--color-hero-bg);
}
.hero-slide__media img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover; /* excepción ilustrativa, mismo criterio que .cat-card__media (design.md) */
	transform: scale(1);
}
/* animation, no transition: una transition sigue corriendo hasta terminar
   aunque el usuario pause el slider (animation-play-state no existe para
   transitions) — el botón de pausa quedaba sin efecto sobre el zoom, solo
   sobre el cambio de slide (bug real, reportado). */
.hero-slide.is-activo .hero-slide__media img { animation: hero-kenburns 8s linear forwards; }
.hero-slider.is-pausado .hero-slide__media img { animation-play-state: paused; }
@keyframes hero-kenburns {
	from { transform: scale(1); }
	to { transform: scale(1.08); }
}
/* Velo lateral (no plano completo, para no tapar la foto) con el mismo
   token que el resto del sitio usa para texto blanco sobre foto. */
.hero-slide__media::after {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(90deg, var(--color-scrim) 0%, transparent 65%);
}
.hero-slide__body {
	position: relative;
	z-index: 1;
	color: var(--color-scrim-ink);
	/* bottom 64px = 16px de .hero-slider__controls + 36px de sus botones + 12px
	   de aire, para que el CTA no quede debajo de la fila de controles en mobile. */
	padding: 28px var(--gutter) 64px;
	max-width: 34ch;
}
.hero-slide__eyebrow {
	display: inline-flex;
	align-items: center;
	background: var(--color-accent);
	color: var(--color-accent-ink);
	font-size: 12px;
	font-weight: 800;
	text-transform: uppercase;
	letter-spacing: .04em;
	padding: 5px 12px;
	border-radius: 999px;
	margin: 0 0 10px;
}
.hero-slide__title { font-size: clamp(24px, 4vw, 36px); margin: 0 0 8px; color: inherit; }
.hero-slide__text { margin: 0 0 16px; opacity: .9; }
.hero-slide.is-activo .hero-slide__eyebrow,
.hero-slide.is-activo .hero-slide__title,
.hero-slide.is-activo .hero-slide__text,
.hero-slide.is-activo .hero-slide__cta {
	animation: hero-slide-in .5s var(--ease-out, ease) both;
}
.hero-slide.is-activo .hero-slide__title { animation-delay: .06s; }
.hero-slide.is-activo .hero-slide__text { animation-delay: .12s; }
.hero-slide.is-activo .hero-slide__cta { animation-delay: .18s; }
@keyframes hero-slide-in {
	from { opacity: 0; transform: translateY(10px); }
}
.hero-slider__controls {
	position: absolute;
	z-index: 2;
	inset-inline: var(--gutter);
	bottom: 16px;
	display: flex;
	align-items: center;
	gap: 10px;
}
/* appearance:none + padding:0 + box-sizing: los 3 son <button> nativos —
   sin resetear esto el padding/box-model por defecto del navegador infla
   width/height (un botón de 8x8 quedaba como una píldora de ~20px, no un
   punto redondo — bug real, visto en pantalla). Mismo criterio que el resto
   de controles nativos del tema (design.md, "UI personalizada siempre"). */
.hero-slider__arrow,
.hero-slider__pause,
.hero-slider__dot {
	appearance: none;
	-webkit-appearance: none;
	box-sizing: border-box;
	padding: 0;
	margin: 0;
	font: inherit;
	cursor: pointer;
}
.hero-slider__arrow,
.hero-slider__pause {
	background: color-mix(in srgb, var(--color-hero-bg) 55%, transparent);
	color: var(--color-scrim-ink);
	border: 1px solid color-mix(in srgb, white 25%, transparent);
	border-radius: 999px;
	width: 36px;
	height: 36px;
	display: grid;
	place-items: center;
	flex: 0 0 auto;
}
.hero-slider__arrow:hover,
.hero-slider__pause:hover { background: color-mix(in srgb, var(--color-hero-bg) 80%, transparent); }
.hero-slider__dots {
	display: flex;
	align-items: center;
	gap: 8px;
	margin-inline-end: auto;
}
/* Botón real 24x24 (WCAG 2.5.8 / Lighthouse target-size, que mide la caja
   del elemento, no un ::before posicionado encima — un pseudo-elemento
   absoluto más grande no cuenta para el audit). El punto visual (8px,
   22px activo) sigue siendo intencionalmente chico: vive en ::before,
   centrado por flex, sin position:absolute. */
.hero-slider__dot {
	width: 24px;
	height: 24px;
	display: flex;
	align-items: center;
	justify-content: center;
	border: none;
	background: transparent;
	flex: 0 0 auto;
}
.hero-slider__dot::before {
	content: "";
	width: 8px;
	height: 8px;
	border-radius: 999px;
	background: color-mix(in srgb, white 45%, transparent);
	transition: width var(--dur-fast, .18s) var(--ease-out, ease);
}
.hero-slider__dot.is-activo::before { background: var(--color-scrim-ink); width: 22px; }
@media (prefers-reduced-motion: reduce) {
	.hero-slider__dot::before { transition: none; }
	.hero-slide { transition: none; }
	.hero-slide.is-activo .hero-slide__media img { animation: none; transform: none; }
	.hero-slide.is-activo .hero-slide__eyebrow,
	.hero-slide.is-activo .hero-slide__title,
	.hero-slide.is-activo .hero-slide__text,
	.hero-slide.is-activo .hero-slide__cta { animation: none; }
}
@media (min-width: 640px) {
	.hero-slider__track { height: 440px; }
	.hero-slide__body { padding: 48px 48px 64px; max-width: 40ch; } /* 64px abajo: mismo aire que en mobile para los controles del carrusel */
}

/* --- Bento de ofertas (patrón cohasa/bento-ofertas) --- */
/* Igual estrategia que .trust-row: el grupo usa layout:"default" (flow) para
   que WP no imprima su propio is-layout-flex/grid, y el grid real lo pone
   este CSS. Mobile-first: 2 columnas; en desktop, los 4 tiles en una fila
   (antes había un 5º tile grande, que pasó a ser el hero-slider). */
.bento-grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 12px;
	margin-block: 0 var(--gutter);
}
/* Mismo bug/arreglo que .trust-row__item: "flow" (layout:"default") trae su
   propio CSS core (.is-layout-flow > * + *) con margin-block-start en todo
   hijo salvo el primero. En un grid con align-items:stretch (default), ese
   margen no se ve como separación — se resta de la altura de la CAJA del
   ítem (el alto de fila ya lo fija el grid), así que las 3 tarjetas no-
   primeras quedaban más bajas que la primera (bug real, visto en pantalla:
   67px vs 83px). Se anula explícito, igual que en .trust-row__item. */
.bento-grid > .bento-card { margin-block: 0; }
/* Fila: texto (pct + label, .bento-card__text) a la izquierda, ícono a la
   derecha — justify-content:space-between separa los dos grupos sin
   necesitar margin-inline-start:auto en el ícono. */
.bento-card {
	border-radius: var(--radius);
	padding: 12px 14px;
	min-height: 0;
	flex-direction: row !important;
	align-items: center !important;
	justify-content: space-between !important;
	gap: 8px !important;
	background: var(--color-surface);
	border: 1px solid var(--color-line);
	transition: transform var(--dur-fast, .15s) var(--ease-out, ease);
}
.bento-card:hover { transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) {
	.bento-card:hover { transform: none; }
}
.bento-card--accent {
	background: color-mix(in srgb, var(--color-accent) 12%, var(--color-surface));
	border-color: color-mix(in srgb, var(--color-accent) 30%, transparent);
}
.bento-card__text {
	gap: 1px !important;
	min-width: 0;
}
/* El ícono (cohasa_svg_patron(), inc/patterns.php) es el segundo hijo del
   grupo. */
.bento-card > .cohasa-icon {
	color: var(--color-oferta-text);
	flex: 0 0 auto;
}
.bento-card--accent > .cohasa-icon { color: var(--color-accent-text); }
.bento-card__pct { color: var(--color-oferta-text); font-weight: 800; font-size: 18px; margin: 0; line-height: 1.2; }
.bento-card--accent .bento-card__pct { color: var(--color-accent-text); }
.bento-card__label {
	font-size: 12.5px;
	margin: 0;
	color: var(--color-ink-soft);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.bento-card__label a { color: inherit; text-decoration: none; }
.bento-card__label a:hover { text-decoration: underline; }

@media (min-width: 640px) {
	.bento-grid { grid-template-columns: repeat(4, 1fr); }
}

/* --- Franja de confianza (patrón cohasa/bloque-confianza), 4 ítems --- */
.trust-row {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 12px;
	padding: 0 0 24px;
}
/* El grupo usa layout:"default" (flow) para que WP no le sume su propio
   is-layout-flex (un display:flex de WP gana en cascada al display:grid propio) — pero "flow"
   trae su propio CSS core (.is-layout-flow > * + *) pensado para apilado
   VERTICAL: margin-block-start en todo hijo salvo el primero. Al convertir
   el grupo en grid horizontal ese margen no desaparece, solo empuja las 3
   tarjetas no-primeras hacia abajo — mismas columnas, pero item 1 quedaba
   455px de alto vs 439px del resto y las 3 últimas nacían 16px más abajo
   (bug real, visto en el navegador). Se anula explícito. */
.trust-row__item {
	margin-block: 0;
	background: var(--color-surface);
	border: 1px solid var(--color-line);
	border-radius: var(--radius);
	padding: 16px;
	display: flex;
	align-items: flex-start;
	gap: 12px;
}
.trust-row__item svg { flex: 0 0 auto; color: var(--color-accent-text); margin-top: 2px; }
.trust-row__title { margin: 0 0 2px; font-size: 13.5px; }
.trust-row__subtitle { margin: 0; font-size: 12.5px; color: var(--color-ink-soft); }
@media (max-width: 399px) {
	/* 2 columnas con ícono + 2 líneas de texto no caben bajo ~400px. */
	.trust-row { grid-template-columns: 1fr; }
}
@media (min-width: 640px) {
	.trust-row { grid-template-columns: repeat(4, 1fr); }
}

/* --- Patrones editables (inc/patterns.php) ---
   Todos reusan tokens de tokens.css, ningún color/ancho literal nuevo —
   ver "Patrones editables" en design.md. */

/* Banner de campaña: core/columns navy (texto + imagen), mismo criterio visual que hero-slide. */
.campana-banner {
	background: var(--color-hero-bg);
	color: var(--color-hero-ink);
	border-radius: var(--radius-lg);
	align-items: center;
	border: 1px solid var(--color-hero-border); /* --color-hero-bg es fijo: sin borde se funde con el fondo oscuro */
}
.campana-banner > .wp-block-column:not(.campana-banner__media) { padding: 28px var(--gutter); }
/* Columna de imagen (también la reusa .nosotros-intro): llena la altura de la fila. */
.campana-banner__media { align-self: stretch; }
.campana-banner__media .wp-block-image { margin: 0; }
.campana-banner__media img {
	width: 100%;
	height: auto;
	aspect-ratio: 4 / 3;
	object-fit: cover; /* excepción ilustrativa, mismo criterio que .cat-card__media (design.md) */
	border-radius: var(--radius-lg);
}
.campana-banner__eyebrow {
	display: inline-flex;
	background: var(--color-accent);
	color: var(--color-accent-ink);
	font-size: 12px;
	font-weight: 800;
	text-transform: uppercase;
	letter-spacing: .04em;
	padding: 5px 12px;
	border-radius: 999px;
	margin: 0 0 14px;
}
.campana-banner__title { font-size: clamp(22px, 3vw, 30px); margin: 0 0 10px; }
.campana-banner__text { color: color-mix(in srgb, var(--color-hero-ink) 85%, var(--color-hero-bg)); margin: 0 0 18px; }
.cohasa-placeholder-img { width: 100%; height: 100%; object-fit: cover; }

/* "Nosotros": mismo layout de columnas que .campana-banner, sin fondo navy
   (contenido institucional, no promocional). */
.nosotros-intro { align-items: center; }

/* Dos banners promocionales lado a lado: imagen a fondo completo con velo
   (mismo criterio que .cat-card__media) y el texto encima. */
.banners-duo { gap: 16px; }
.banners-duo__item {
	position: relative;
	flex: 1 1 calc(50% - 8px);
	border-radius: var(--radius-lg);
	overflow: hidden;
	background: var(--color-field);
}
.banners-duo__media { margin: 0; }
/* aspect-ratio en la <img> (no en el <figure>): en el editor la imagen va envuelta y height:100% no resuelve. */
.banners-duo__media img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
.banners-duo__media::after {
	content: "";
	pointer-events: none;
	position: absolute;
	inset: 0;
	background: var(--color-scrim);
}
.banners-duo .banners-duo__item .banners-duo__body { /* especificidad extra: el editor fuerza position:relative en cada bloque */
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	gap: 12px;
	padding: 20px var(--gutter);
}
.banners-duo__title { margin: 0; font-size: clamp(18px, 2.4vw, 24px); color: var(--color-scrim-ink); }
@media (max-width: 639px) {
	.banners-duo__item { flex-basis: 100%; }
}

/* Franja de marcas. */
.brand-row-section { padding: 28px 0; }
.brand-row-section__title { font-size: 19px; text-align: center; margin: 0 0 20px; }
.brand-row { gap: 32px 24px; align-items: center; }
.brand-row__logo img { display: block; filter: grayscale(1); opacity: .7; transition: filter var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out); }
.brand-row__logo img:hover { filter: none; opacity: 1; }
@media (prefers-reduced-motion: reduce) {
	.brand-row__logo img { transition: none; }
}

/* Cifras de "Nosotros" — mismo grid que .trust-row, tipografía de cifra
   más grande (no reusa .trust-row__title: ese token es para títulos
   cortos de 13.5px, no para un número protagonista). */
.stat-row { display: grid; grid-template-columns: 1fr; gap: 12px; padding: 0; }
.stat-item {
	background: var(--color-surface);
	border: 1px solid var(--color-line);
	border-radius: var(--radius);
	padding: 20px 16px;
	text-align: center;
	margin-block: 0;
}
.stat-item__value { font-size: 28px; color: var(--color-accent-text); margin: 0 0 4px; }
.stat-item__label { font-size: 13px; color: var(--color-ink-soft); margin: 0; }
@media (min-width: 640px) {
	.stat-row { grid-template-columns: repeat(3, 1fr); }
}

/* Sucursales: mismo item que .trust-row pero con 3 líneas de texto. */
.store-item { align-items: flex-start; }

/* Preguntas frecuentes: core/details reestilado, sin JS propio (acordeón
   nativo del navegador). */
.faq-section { max-width: 760px; }
.faq-item {
	border: 1px solid var(--color-line);
	border-radius: var(--radius);
	padding: 14px var(--gutter);
	margin-block: 8px;
}
.faq-item summary {
	cursor: pointer;
	font-weight: 700;
	list-style: none;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
	content: "+";
	float: right;
	font-weight: 400;
}
.faq-item[open] summary::after { content: "–"; }
.faq-item p { margin: 10px 0 0; color: var(--color-ink-soft); }

/* Contacto: mismos .trust-row__item de siempre, en fila. */
.contact-row { gap: 12px; }
/* nowrap: el is-layout-flex de WP trae flex-wrap:wrap y un texto largo (horario)
   caía bajo el ícono, dejando esa tarjeta más alta que las demás. */
.contact-row { align-items: stretch; }
.contact-row .trust-row__item { flex: 1 1 220px; flex-wrap: nowrap; align-items: center; }
.contact-row .trust-row__item p { margin: 0; min-width: 0; }
/* Aviso de derecho a retracto (Cohasa_Retracto, plugin cohasa-core). Borde
   completo, nunca de un solo lado. En la variante "sin retracto" el título va
   al tamaño del precio (24px/800, ver .wp-block-cohasa-product-price): el
   Decreto 52/2024 pide que la advertencia sea de tamaño equivalente al precio. */
.cohasa-retracto {
	display: flex;
	gap: 12px;
	align-items: flex-start;
	margin: 12px 0 14px;
	padding: 12px 14px;
	background: var(--color-field);
	border: 1px solid var(--color-line);
	border-radius: var(--radius);
}
.cohasa-retracto__icono { flex: 0 0 auto; }
.cohasa-retracto__icono svg { margin-top: 2px; color: var(--color-accent-text); }
.cohasa-retracto__cuerpo { min-width: 0; }
.cohasa-retracto__titulo { margin: 0 0 2px; font-size: 14px; font-weight: 700; }
.cohasa-retracto__texto { margin: 0; font-size: 13px; color: var(--color-ink-soft); }
.cohasa-retracto__texto a { font-weight: 600; }
.cohasa-retracto--excluido {
	background: color-mix(in srgb, var(--color-error) 18%, var(--color-field));
	border-color: var(--color-error);
}
.cohasa-retracto--excluido .cohasa-retracto__icono svg { color: var(--color-error); }
.cohasa-retracto--excluido .cohasa-retracto__titulo { font-size: 24px; font-weight: 800; line-height: 1.2; color: var(--color-ink); }
.cohasa-retracto--excluido .cohasa-retracto__texto { font-size: 14px; color: var(--color-ink); }
.order-recibo__desc .cohasa-retracto,
.cart-line__body .cohasa-retracto { margin: 8px 0 0; padding: 8px 10px; }
/* En las líneas del pedido el precio es de ~15px: el título va a ese tamaño (equivalente al precio de esa misma línea). */
.order-recibo__desc .cohasa-retracto--excluido .cohasa-retracto__titulo,
.cart-line__body .cohasa-retracto--excluido .cohasa-retracto__titulo { font-size: 16px; }
.order-recibo__desc .cohasa-retracto--excluido .cohasa-retracto__texto,
.cart-line__body .cohasa-retracto--excluido .cohasa-retracto__texto { font-size: 12.5px; }
.order-recibo__desc .cohasa-retracto,
.cart-line__body .cohasa-retracto { width: 100%; box-sizing: border-box; }
.cohasa-retracto-acuse { margin: 0 0 14px; }

.contact-row a { font-weight: 600; text-decoration: none; }

/* CTA de cierre. */
.cta-banner {
	background: var(--color-hero-bg);
	color: var(--color-hero-ink);
	border-radius: var(--radius-lg);
	border: 1px solid var(--color-hero-border); /* --color-hero-bg es fijo: sin borde se funde con el fondo oscuro */
	padding: 40px var(--gutter);
	text-align: center;
}
.cta-banner__title { font-size: clamp(22px, 3vw, 30px); margin: 0 0 10px; }
.cta-banner__text { color: color-mix(in srgb, var(--color-hero-ink) 85%, var(--color-hero-bg)); margin: 0 0 20px; }
.cta-banner .wp-block-buttons { justify-content: center; }

/* .btn--secondary usa --color-ink (se invierte con el tema), pero estos
   fondos navy son fijos en los dos temas (ver --color-hero-bg en tokens.css)
   — en tema claro el botón queda ilegible (oscuro sobre navy). Se fuerza a
   --color-hero-ink, igual que el resto del texto de estos bloques. */
.cta-banner .btn--secondary,
.cta-banner .wp-block-button.btn--secondary .wp-block-button__link,
.banners-duo .btn--secondary,
.banners-duo .wp-block-button.btn--secondary .wp-block-button__link,
.campana-banner .btn--secondary,
.campana-banner .wp-block-button.btn--secondary .wp-block-button__link {
	border-color: var(--color-hero-ink);
	color: var(--color-hero-ink);
}

/* Newsletter: mismo criterio de "Banner angosto" que .info-banner, pero
   con título/texto/botón en vez de una sola línea. */
.newsletter-banner {
	background: var(--color-field);
	border-block: 1px solid var(--color-line-strong); /* 3:1 WCAG 1.4.11, mismo criterio que .info-banner */
	padding: 20px var(--gutter);
	gap: 16px;
	align-items: center;
}
.newsletter-banner__title { font-size: 17px; margin: 0 0 4px; }
.newsletter-banner__text { font-size: 13.5px; color: var(--color-ink-soft); margin: 0; }

/* assets/css/forms.css */
/*
 * Kit de controles de formulario propios — primera entrada de este tipo en
 * el sistema de diseño (ver design.md, "Controles de formulario"). El select
 * es el único con JS (assets/js/select.js); checkbox/radio se resuelven
 * re-estilando el elemento nativo (appearance: none), sin wrapper ni ARIA
 * extra — regla núcleo de accesibilidad: elemento nativo antes que ARIA.
 */

/* --- Campo de texto/select unificado ---
   Un único componente visual para inputs de texto, textarea y el trigger del
   select (y select2), vía props redefinibles (mismo patrón que --pg-* en
   pagination.css y --field-* de checkbox/radio más abajo: cero reglas
   duplicadas, una variante = redefinir props, nunca clonar el bloque).
   Fondo --color-input-bg (no --color-surface ni --color-field): ninguno de
   los dos se distinguía bien del resto de superficies de la página; el valor
   de fábrica de --color-input-bg (igual al de --color-bg) da 3.22:1 (claro) /
   3.89:1 (oscuro) de borde sobre sí mismo, sobre AA 1.4.11 (ver tokens.css,
   --color-line-strong). Decisión 2026-09-28, reemplaza la de 2026-09-24
   (--color-surface) y la de checkout (--color-field). Token propio (no
   --color-bg directo) agregado el mismo día: que cambiar "Fondo" en Estilos
   globales no mueva sin querer todos los inputs del sitio — mismo valor por
   defecto, editable aparte (preset "input-bg"/"input-bg-dark"). */
:root {
	--input-bg: var(--color-input-bg);
	--input-border: var(--color-line-strong);
	--input-border-hover: var(--color-ink-soft);
	--input-ring: color-mix(in srgb, var(--color-ink) 15%, transparent);
	--input-h: 44px;
	--input-px: 14px;
	--input-py: 10px;
	--input-fs: 15px;
	--input-radius: var(--radius);
}
/* Variante compacta: toolbar de orden de la tienda, filtro de precio. */
.cohasa-input--sm {
	--input-h: 36px;
	--input-px: 10px;
	--input-py: 6px;
	--input-fs: 13px;
}

/* --- Select personalizado (`.cohasa-select`) --- */
.cohasa-select {
	position: relative;
	display: inline-block;
	min-width: 220px;
}
.cohasa-select__trigger {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	width: 100%;
	min-height: var(--input-h);
	padding: var(--input-py) var(--input-px);
	background: var(--input-bg);
	color: var(--color-ink);
	border: 1px solid var(--input-border);
	border-radius: var(--input-radius);
	font: inherit;
	font-size: var(--input-fs);
	cursor: pointer;
	transition: border-color var(--dur-fast) var(--ease-out);
}
.cohasa-select__trigger:hover { border-color: var(--input-border-hover); }
/* Anillo neutro en el wrapper (patrón .site-search__field, main.css): el
   doble aro de --focus-ring se ve pesado en un control ancho, y en modo
   oscuro pinta un rectángulo verde duro (design.md, "Foco visible"). */
.cohasa-select:focus-within .cohasa-select__trigger {
	border-color: var(--input-border-hover);
	box-shadow: 0 0 0 3px var(--input-ring);
}
.cohasa-select__trigger:focus-visible { outline: none; box-shadow: none; }
.cohasa-select__trigger svg {
	flex-shrink: 0;
	color: var(--color-ink-soft);
	transition: transform var(--dur-fast) var(--ease-out);
}
.cohasa-select__trigger[aria-expanded="true"] svg { transform: rotate(180deg); }

.cohasa-select__panel {
	position: absolute;
	z-index: 20;
	top: calc(100% + 6px);
	left: 0;
	min-width: 100%;
	max-height: 320px;
	overflow-y: auto;
	background: var(--color-surface);
	border: 1px solid var(--color-line-strong);
	border-radius: var(--radius);
	box-shadow: var(--shadow-float);
	padding: 6px;
}
.cohasa-select__group-label {
	margin: 6px 8px 2px;
	font-size: 11px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: .04em;
	color: var(--color-ink-soft);
}
.cohasa-select__option {
	display: flex;
	align-items: center;
	gap: 8px;
	width: 100%;
	min-height: 40px;
	padding: 8px 10px;
	border: 0;
	border-radius: calc(var(--radius) - 4px);
	background: none;
	color: var(--color-ink);
	font: inherit;
	font-size: 14px;
	text-align: left;
	cursor: pointer;
}
.cohasa-select__option:hover:not(:disabled) { background: var(--color-field); }
.cohasa-select__option.is-selected { background: var(--color-field); color: var(--color-accent-text); font-weight: 600; }
.cohasa-select__option:disabled { color: var(--color-ink-soft); cursor: not-allowed; opacity: .6; }
.cohasa-select__check { flex-shrink: 0; width: 16px; height: 16px; }

/* El Select2 de fábrica de WooCommerce (checkout/mi cuenta, select2.css) mete
   su propio <span class="select2 select2-container"> junto al <select> que
   assets/js/checkout-select.js envuelve — con display:inline-block de un
   stylesheet de autor, que le gana a `[hidden]{display:none}` (origen
   user-agent) aunque la especificidad empate. Sin este !important queda un
   segundo control visible y sin estilo propio al lado del trigger. */
.cohasa-select > .select2 { display: none !important; }

/* Sin flash del select nativo en checkout/mi cuenta: checkout-select.js
   (defer) lo envuelve recién después del primer pintado, y hasta entonces se
   veía el <select> del navegador (medido 2026-09-29: 7 visibles en el FCP).
   visibility (no display) mantiene la caja, así el trigger no empuja el
   layout al aparecer. Solo con `.woocommerce-js` (lo pone el JS de WooCommerce):
   sin JS el campo sigue visible y usable. Mismos selectores que SELECTOR en
   checkout-select.js. */
body.woocommerce-js:is(.woocommerce-checkout, .woocommerce-account) :is(.state_select, #billing_city, #shipping_city, #billing_country, #shipping_country, #billing_tipo_documento):not(.cohasa-select__native),
body.woocommerce-js:is(.woocommerce-checkout, .woocommerce-account) .state_select:not(.cohasa-select__native) + .select2 {
	visibility: hidden;
}

/* --- Checkbox / radio nativos, re-estilados ---
   Componente por variante (mismo patrón que --pg-* en pagination.css: props
   redefinibles, cero reglas duplicadas). Variante por defecto = --color-ink
   (neutro, como hasta ahora); ".cohasa-field--accent" en un ancestro
   redefine las props al verde de marca sin tocar el resto del sitio. */
input[type="checkbox"],
input[type="radio"] {
	--field-border: var(--color-line-strong);
	--field-checked-bg: var(--color-ink);
	--field-checked-border: var(--color-ink);
	--field-mark: var(--color-bg);

	appearance: none;
	-webkit-appearance: none;
	width: 20px;
	height: 20px;
	min-width: 20px;
	margin: 0;
	border: 1.5px solid var(--field-border);
	background: var(--color-surface);
	display: inline-grid;
	place-content: center;
	cursor: pointer;
	flex-shrink: 0;
}
.cohasa-field--accent input[type="checkbox"],
.cohasa-field--accent input[type="radio"],
input[type="checkbox"].cohasa-field--accent,
input[type="radio"].cohasa-field--accent {
	--field-checked-bg: var(--color-accent);
	--field-checked-border: var(--color-accent);
	--field-mark: var(--color-accent-ink);
}
input[type="checkbox"] { border-radius: 5px; }
input[type="radio"] { border-radius: 999px; }
input[type="checkbox"]:checked,
input[type="radio"]:checked {
	border-color: var(--field-checked-border);
	background: var(--field-checked-bg);
}
input[type="checkbox"]:checked::after {
	content: "";
	width: 11px;
	height: 11px;
	/* Tick dibujado con clip-path en vez de SVG: es un pseudo-elemento, no
	   puede llevar un <svg> propio sin volverlo elemento real. */
	clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
	background: var(--field-mark);
}
input[type="radio"]:checked::after {
	content: "";
	width: 9px;
	height: 9px;
	border-radius: 999px;
	background: var(--field-mark);
}
input[type="checkbox"]:focus-visible,
input[type="radio"]:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
	border-radius: 999px; /* el aro redondo evita que se vea cuadrado sobre el radio */
}
input[type="checkbox"]:focus-visible { border-radius: 5px; }
input[type="checkbox"]:disabled,
input[type="radio"]:disabled {
	opacity: .5;
	cursor: not-allowed;
}

/* assets/css/motion.css */
/*
 * Capa de animación y microinteracciones — dirección "Vivo y animado".
 * Usa exclusivamente los tokens de wp-content/themes/cohasa-base/assets/css/tokens.css
 * (--ease-out, --dur-fast, --dur-base, --dur-slow). No se inventan timings nuevos.
 *
 * Principio de robustez: las animaciones de entrada dejan el elemento visible
 * por defecto (estado final del keyframe = opacity:1, sin transform) y usan
 * animation-fill-mode: both solo para sostener el frame 0% antes de que la
 * animación arranque. Si este CSS no llegara a cargar, el navegador nunca
 * aplica `animation`, así que el contenido queda en su estado natural
 * (visible) — no depende de JS para "revelar" nada.
 */

@keyframes cohasa-fade-rise {
	from {
		opacity: 0;
		transform: translateY(14px);
	}
	to {
		opacity: 1;
		transform: translateY(0);
	}
}

/* --- Entrada del eyebrow (404): fade+rise --- */
.hero__eyebrow {
	animation: cohasa-fade-rise var(--dur-slow) var(--ease-out) both;
}

/* NOTA: se probó una entrada fade+rise escalonada para .product-card (como
   la del hero), pero medida con Lighthouse bajaba el LCP de la tienda de
   2,5s a 4,5s (Performance 96→76) — con una grilla grande, animar la
   opacidad de muchas tarjetas retrasa el momento en que Chrome considera
   "pintado" el contenido más grande de la página, aunque el texto ya esté
   listo. Es un problema real y documentado de Core Web Vitals con
   animaciones de entrada en listas, no algo cosmético a ignorar — se
   descartó. El "vivo" de esta dirección queda en las microinteracciones de
   abajo (hover, pulso de badge), que no tocan el primer pintado.

   El hero SÍ anima su entrada arriba: son 4 elementos fijos, no una lista
   que crece con el catálogo, y se verificó que no afecta el LCP (preload
   de fuentes + fondo inline se encargan de eso). */

/* --- Hover de tarjeta: elevación leve + sombra sutil --- */
.product-card {
	transition: transform var(--dur-fast) var(--ease-out),
		box-shadow var(--dur-fast) var(--ease-out);
}
.cat-card {
	transition: transform var(--dur-fast) var(--ease-out),
		box-shadow var(--dur-fast) var(--ease-out);
}
.product-card:hover,
.cat-card:hover {
	transform: translateY(-3px);
	/* Negro puro, no --color-ink: mismo motivo que --shadow-float (tokens.css)
	   — una sombra con --color-ink se ve clara/brillante en modo oscuro. */
	box-shadow: 0 8px 20px -12px rgb(0 0 0 / 0.35);
}
/* Feedback táctil: sin :hover en touch, :active es la única señal de que el
   tap registró antes de navegar a la ficha. */
.product-card:active {
	transform: scale(.98);
	box-shadow: var(--shadow-card);
}
/* Zoom sutil de la foto en hover: la card cuadrada ahora es toda imagen. */
.cat-card__media img {
	transition: transform var(--dur-base) var(--ease-out);
}
.cat-card:hover .cat-card__media img {
	transform: scale(1.05);
}
/* El foco nunca se anima: aparece/desaparece instantáneo (accesibilidad). */
.product-card a.product-card__link:focus-visible {
	transition: none;
}

/* --- Badge de oferta: pulso muy sutil, lento, no distrae del precio --- */
@keyframes cohasa-badge-pulse {
	0%, 100% { transform: scale(1); }
	50%      { transform: scale(1.04); }
}
.product-card__badge {
	animation: cohasa-badge-pulse 2.6s var(--ease-out) infinite;
}

/* --- Botones: transición de escala/sombra al hover, sin rebote --- */
.btn {
	transition: transform var(--dur-fast) var(--ease-out),
		box-shadow var(--dur-fast) var(--ease-out),
		opacity var(--dur-fast) var(--ease-out);
}
.btn--primary:hover:not(:disabled) {
	transform: scale(1.03);
	box-shadow: 0 6px 16px -8px color-mix(in srgb, var(--color-accent) 55%, transparent);
}
.btn--secondary:hover:not(:disabled) {
	transform: scale(1.03);
}

/* --- Chips de categoría: elevación leve, más sutil que las tarjetas --- */
.cat-chip {
	transition: transform var(--dur-fast) var(--ease-out),
		box-shadow var(--dur-fast) var(--ease-out);
}
.cat-chip:hover {
	transform: translateY(-1px);
	box-shadow: 0 4px 10px -6px rgb(13 17 23 / 0.2);
}

/* --- prefers-reduced-motion: cero animación de entrada, cero movimiento --- */
@media (prefers-reduced-motion: reduce) {
	.hero__eyebrow,
	.product-card {
		animation: none;
		opacity: 1;
		transform: none;
	}
	.product-card__badge {
		animation: none;
	}
	.product-card,
	.cat-card,
	.btn,
	.cat-chip {
		transition-property: color, background-color, border-color, box-shadow;
	}
	.product-card:hover,
	.product-card:active,
	.cat-card:hover,
	.btn--primary:hover,
	.btn--secondary:hover,
	.cat-chip:hover {
		transform: none;
	}
	.cat-card__media img {
		transition: none;
	}
	.cat-card:hover .cat-card__media img {
		transform: none;
	}
}

/* assets/css/carousel.css */
/*
 * Carrusel horizontal de productos — scroll-snap nativo, sin librerías.
 * Dirección "Vitrina con peek" (elegida entre 3 propuestas, ver design.md).
 * Shell agnóstico del contenido: la tarjeta que va adentro la decide el
 * llamador (ver cohasa_render_product_carousel(), inc/template-tags.php).
 * Se usa en la home (cohasa/product-carousel) y en "También te puede
 * interesar" (woocommerce/single-product/related.php).
 */

.carousel {
	position: relative;
	padding: 0 0 20px;
	/* Las columnas del track dependen del ancho del carrusel, no del viewport. */
	container-type: inline-size;
}
.carousel__body { position: relative; }

/* --cols entero: se abandonó el "peek" (asomar una fracción de la tarjeta
   siguiente, ver design.md) porque esa tarjeta parcial quedaba con precio y
   botón legibles y luego cortados de golpe contra el borde — el degradado
   que lo disimulaba (--fade, más abajo) se sacó junto con esto: ya no hay
   ninguna tarjeta cortada que tapar. Las flechas (.carousel__nav) siguen
   siendo la señal de que hay más contenido. */
.carousel__track {
	--gap: 14px;
	/* min() con --n (cantidad real de slides, seteado inline por PHP): con menos
	   productos que columnas, --cols baja al número real y las tarjetas ocupan
	   todo el ancho en vez de quedar angostas con la mitad del carrusel vacía. */
	--cols: min(1, var(--n, 999));
	/* Tope de 320px (mismo orden que .product-grid a 4 columnas en desktop):
	   sin esto, con 1 solo producto (--cols:1) la tarjeta ocupa el 100% del
	   carrusel — imagen cuadrada gigante, rota visualmente con el resto del
	   home (bug real, visto con un solo producto "destacado"). */
	--card-w: min(320px, calc((100% - (var(--cols) - 1) * var(--gap)) / var(--cols)));
	display: flex;
	gap: var(--gap);
	overflow-x: auto;
	overscroll-behavior-x: contain;
	scroll-snap-type: x mandatory;
	/* Peek deliberado hacia el borde de pantalla: el margen negativo compensa
	   el padding para que la última tarjeta siga alcanzando el borde real del
	   viewport en vez de quedar 16px adentro (ver "Sistema único de ancho",
	   design.md — .carousel__nav de abajo ya usa var(--gutter) sin compensar,
	   coincide con este mismo borde).
	   scroll-padding-inline TIENE que ser var(--gutter), no 0: el snapport de
	   scroll-snap se mide sobre el padding-box del propio track, así que con
	   scroll-padding-inline:0 el snap-point de la 1ª tarjeta (scroll-snap-align:
	   start, desplazada var(--gutter) por el padding del track) cae en
	   scrollLeft = var(--gutter), no en 0. El navegador auto-corrige ahí en la
	   carga (mandatory), is-scrolled se activa sin que el usuario haya scrolleado
	   y el fade izquierdo (--fade-start) tapa la primera tarjeta desde el inicio. */
	scroll-padding-inline: var(--gutter);
	padding: 4px var(--gutter) 10px;
	margin-inline: calc(-1 * var(--gutter));
	scrollbar-width: none;
}
@container (min-width: 480px)  { .carousel__track { --cols: min(2, var(--n, 999)); } }
@container (min-width: 720px)  { .carousel__track { --cols: min(3, var(--n, 999)); } }
@container (min-width: 1000px) { .carousel__track { --cols: min(4, var(--n, 999)); } }

.carousel__track > *,
.carousel__track > .wp-block-cohasa-product-carousel > * {
	flex: 0 0 var(--card-w);
	min-width: 0;
	scroll-snap-align: start;
	scroll-snap-stop: always;
}
/* El bloque contenedor cohasa/product-carousel (InnerBlocks reales, ver
   inc/blocks.php) pasa su propio wrapper (.wp-block-cohasa-product-carousel,
   generado por useBlockProps.save() en editor-blocks.js) dentro del
   $content que WordPress le entrega al render_callback — ese wrapper queda
   como ÚNICO hijo de .carousel__track. display:contents lo saca del árbol de
   LAYOUT (sus hijos participan del flex del track como si fueran hermanos),
   pero NO lo saca del árbol DOM: ".carousel__track > *" solo matchea el
   wrapper, nunca las tarjetas de adentro — por eso el selector de arriba
   necesita también la variante "> .wp-block-cohasa-product-carousel > *". */
.carousel__track > .wp-block-cohasa-product-carousel {
	display: contents;
}
/* scroll-snap-stop: always frena los saltos programáticos en el primer punto
   de snap; carousel.js lo suspende mientras dura el salto de una flecha. */
.carousel.is-paging .carousel__track > *,
.carousel.is-paging .carousel__track > .wp-block-cohasa-product-carousel > * { scroll-snap-stop: normal; }

.carousel__track:focus-visible {
	outline: 2px solid var(--color-focus);
	outline-offset: -2px;
}

/* Contador: solo lectores de pantalla (.screen-reader-text, main.css). */

/* --- Flechas: flotan sobre el track; en móvil el swipe ya cubre --- */
.carousel__nav {
	display: none;
	position: absolute;
	top: 40%;
	z-index: 2;
	width: 48px;
	height: 48px;
	padding: 0;
	place-items: center;
	border: 1px solid var(--color-line);
	border-radius: 50%;
	background: var(--color-surface);
	color: var(--color-ink);
	box-shadow: var(--shadow-float);
	cursor: pointer;
	transform: translateY(-50%);
	transition: background var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out);
}
.carousel__nav--prev { left: calc(var(--gutter) + 8px); }
.carousel__nav--next { right: calc(var(--gutter) + 8px); }
@container (min-width: 640px) {
	.carousel__nav { display: grid; }
}
.carousel__nav:hover { background: var(--color-field); }
.carousel__nav:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* aria-disabled y no `disabled`: un botón que se deshabilita con el foco lo pierde. */
.carousel__nav[aria-disabled="true"] { opacity: .38; cursor: default; }
.carousel__nav[aria-disabled="true"]:hover { background: var(--color-surface); }
.carousel.is-static .carousel__nav { display: none; }

/* Flechas ocultas desde el primer frame cuando hay menos tarjetas que
   columnas visibles (data-n, inc/template-tags.php) — mismos cortes que
   --cols arriba, así no se ven un instante antes de que carousel.js las
   oculte con is-static tras el primer cálculo de scroll (bug real, flash
   reportado 2026-09-25). Solo cubre data-n de 1 a 4 (el máximo de columnas):
   con más tarjetas que eso siempre hay overflow, así que ningún selector
   matchea y las flechas quedan visibles. carousel.js sigue corrigiendo con
   is-static los casos límite que dependen del ancho real del contenedor
   (tarjetas topadas en 320px dentro de un carrusel muy ancho). */
@container (min-width: 640px) {
	.carousel[data-n="1"] .carousel__nav,
	.carousel[data-n="2"] .carousel__nav {
		display: none;
	}
}
@container (min-width: 720px) {
	.carousel[data-n="3"] .carousel__nav {
		display: none;
	}
}
@container (min-width: 1000px) {
	.carousel[data-n="4"] .carousel__nav {
		display: none;
	}
}

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

/* assets/css/site-search.css */
/* Buscador (bloque cohasa/site-search): botón lupa + campo a pantalla
   completa en móvil, campo ancho con panel desplegable en escritorio. El
   campo en sí (borde, foco) vive en main.css; acá el contenedor, el overlay
   móvil y el panel de sugerencias. Solo tokens — ver assets/css/tokens.css. */

.site-search__box {
	position: relative;
}

.site-search__field { position: relative; }
.site-search__icon { display: inline-flex; color: var(--color-ink-soft); flex-shrink: 0; }
.site-search__close { display: none; margin-left: -8px; }

.site-search__clear {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	width: 32px;
	height: 32px;
	margin: -6px -8px -6px 0;
	border: none;
	border-radius: 999px;
	background: none;
	color: var(--color-ink-soft);
	cursor: pointer;
}
.site-search__clear:hover { background: var(--color-line); color: var(--color-ink); }
.site-search__clear[hidden] { display: none; }

/* --- Móvil: solo la lupa; el campo abre como overlay --------------------- */
.site-search__toggle { display: inline-flex; }
.site-search--header .site-search__box { display: none; }

.site-search--header.is-abierto .site-search__box {
	display: flex;
	flex-direction: column;
	gap: 12px;
	position: fixed;
	inset: 0;
	z-index: 100;
	padding: var(--gutter);
	background: var(--color-surface);
	overflow-y: auto;
	overscroll-behavior: contain;
}
.site-search--header.is-abierto .site-search__close { display: inline-flex; }
.site-search--header.is-abierto .site-search__icon { display: none; }
.site-search--header.is-abierto .site-search__field { padding-left: 8px; }
body.has-search-open { overflow: hidden; }

@media (min-width: 900px) {
	.site-search__toggle,
	.site-search--header .site-search__close { display: none !important; }
	.site-search--header .site-search__box { display: block; }
}

/* --- Panel de sugerencias ------------------------------------------------ */
.site-search__panel {
	background: var(--color-surface);
	padding: 6px;
}
.site-search__panel[hidden] { display: none; }

/* En el overlay móvil el panel es la propia pantalla: sin caja ni sombra. */
.site-search--header.is-abierto .site-search__panel { padding: 0; flex: 1; }

@media (min-width: 900px) {
	.site-search__panel {
		position: absolute;
		top: calc(100% + 6px);
		left: 0;
		right: 0;
		z-index: 60;
		border: 1px solid var(--color-line);
		border-radius: var(--radius);
		box-shadow: 0 12px 28px rgb(0 0 0 / 0.18);
		max-height: min(70vh, 560px);
		overflow-y: auto;
		animation: site-search-in var(--dur-fast) var(--ease-out);
	}
}
@keyframes site-search-in {
	from { opacity: 0; transform: translateY(-4px); }
	to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
	.site-search__panel { animation: none; }
}

.site-search__group + .site-search__group {
	margin-top: 6px;
	padding-top: 6px;
	border-top: 1px solid var(--color-line);
}
.site-search__group-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 6px 8px 2px;
	font-size: 13px;
	font-weight: 600;
	color: var(--color-ink-soft);
}
.site-search__option--accion {
	width: 100%;
	border: none;
	background: none;
	font: inherit;
	font-size: 13px;
	color: var(--color-ink-soft);
	text-align: left;
	cursor: pointer;
}

.site-search__option {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 8px;
	min-height: 44px;
	border-radius: var(--radius);
	text-decoration: none;
	color: var(--color-ink);
}
.site-search__option:hover,
.site-search__option.is-activo {
	background: var(--color-field);
}
/* Opción activa por teclado: fondo + anillo completo (no solo color). */
.site-search__option.is-activo {
	outline: 2px solid var(--color-ink-soft);
	outline-offset: -2px;
}

.site-search__option-media {
	flex: 0 0 48px;
	width: 48px;
	height: 48px;
	border-radius: calc(var(--radius) - 2px);
	overflow: hidden;
	background: var(--color-field);
}
.site-search__option-media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.site-search__option-body {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
	flex: 1;
}
.site-search__option-name {
	font-size: 14px;
	font-weight: 600;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
/* El match es el único énfasis del panel: fondo neutro, nunca el verde de marca. */
.site-search__option mark {
	background: var(--color-line);
	color: inherit;
	border-radius: 3px;
	padding: 0 1px;
}
.site-search__option-meta {
	font-size: 12.5px;
	color: var(--color-ink-soft);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.site-search__option-price {
	flex-shrink: 0;
	font-size: 14px;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
}
.site-search__option-price del { font-weight: 400; color: var(--color-ink-soft); }
.site-search__option-price ins { text-decoration: none; }

.site-search__state {
	margin: 0;
	padding: 18px 12px;
	font-size: 14px;
	text-align: center;
	color: var(--color-ink-soft);
}

.site-search__see-all {
	justify-content: center;
	font-size: 14px;
	font-weight: 600;
	color: var(--color-accent-text);
}
.site-search__see-all:hover { text-decoration: underline; }

/* 404: el campo va centrado en el cuerpo, no en el header. */
.site-search--inline { max-width: 560px; margin: 24px auto; text-align: left; }

/* Estado vacío de resultados: chips alineados con el texto, sin el sangrado del carrusel de categorías. */
.search-empty { margin-top: 20px; }
.search-empty .cat-scroll { padding-inline: 0; }
.search-empty__similares-titulo,
.cohasa-sugerencias-404__titulo { font-weight: 600; margin: 20px 0 12px; }

/* 404: mismo bloque de "sin resultados", ancho completo del contenedor. */
.cohasa-sugerencias-404 { text-align: left; }

/* assets/css/pagination.css */
/* Cohasa — componente de paginación, compartido por los dos markups que
   genera el sitio: core/query-pagination (bloques FSE, ej. /tienda/) y la
   paginación clásica de WooCommerce (paginate_links(), .woocommerce-pagination,
   ej. categorías y búsqueda vía woocommerce/legacy-template). Un solo lugar
   para no duplicar/desalinear el estilo entre los dos.

   Antes .woocommerce-pagination tenía el "pill" completo pero ese prefijo no
   matchea el markup de core/query-pagination (quedaba texto plano sin caja);
   y lo que sí aplicaba a /tienda (.shop-archive__pagination) solo fijaba
   min-width/min-height sin display:inline-flex, así que no hacían nada sobre
   un <a> inline. Ver design.md para "bordes todo o nada" y el criterio de
   foco (--focus-ring, doble aro) en controles angostos como estos.

   Props de variante, redefinibles en el nav (ver .pagination--compact /
   .pagination--quiet más abajo) — así una densidad o tono distinto no
   duplica reglas. */
.wp-block-query-pagination,
.woocommerce-pagination {
	--pg-size: 44px;
	--pg-gap: 6px;
	--pg-radius: var(--radius);
	--pg-face: var(--color-surface);
	--pg-line: var(--color-line);
	--pg-active-bg: var(--color-ink);
	--pg-active-ink: var(--color-surface);

	margin: 8px 0 40px;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: var(--pg-gap);
}
/* Markup clásico: <ul class="page-numbers"><li>...</li></ul> — el <ul> ya es
   el propio .woocommerce-pagination, así que solo hace falta desnudar la
   lista; el layout flex/gap lo hereda del bloque de arriba. */
.woocommerce-pagination ul.page-numbers {
	display: contents;
	list-style: none;
	margin: 0;
	padding: 0;
}
.woocommerce-pagination ul.page-numbers li {
	list-style: none;
	display: contents;
}

/* --- Ítem (número, flecha, elipsis) — mismo trato en los dos markups ---
   theme.json pinta todo <a> con --color-accent-ink por defecto: acá se pisa
   explícito con --color-ink, igual que el resto de links del tema. */
.wp-block-query-pagination a,
.wp-block-query-pagination .page-numbers,
.wp-block-query-pagination-previous,
.wp-block-query-pagination-next,
.woocommerce-pagination .page-numbers a,
.woocommerce-pagination .page-numbers span {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
	min-width: var(--pg-size);
	min-height: var(--pg-size);
	padding: 0 10px;
	border-radius: var(--pg-radius);
	border: 1px solid var(--pg-line);
	background: var(--pg-face);
	color: var(--color-ink);
	font-weight: 600;
	font-size: 14px;
	line-height: 1;
	text-decoration: none;
}
.wp-block-query-pagination a:hover,
.woocommerce-pagination .page-numbers a:hover {
	border-color: var(--color-ink);
	background: var(--color-field);
}
.wp-block-query-pagination a:focus-visible,
.woocommerce-pagination .page-numbers a:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
}

/* --- Activo: fondo oscuro + texto claro (fondo + color, nunca solo un borde
   suelto — design.md "Bordes: todo o nada") + aria-current, no solo color
   (WCAG). --color-ink/--color-surface en vez de --color-accent: el verde de
   marca es "solo fondo" (design.md) pero acá se repetía en un elemento chico
   y recurrente — se ve muy saturado; --color-ink ya invierte solo en modo
   oscuro (ver tokens.css). --- */
.wp-block-query-pagination .page-numbers.current,
.wp-block-query-pagination a[aria-current="page"],
.woocommerce-pagination .page-numbers.current,
.woocommerce-pagination a[aria-current="page"] {
	background: var(--pg-active-bg);
	border-color: var(--pg-active-bg);
	color: var(--pg-active-ink);
	font-weight: 700;
}

/* --- Elipsis (…): sin caja, no es un control --- */
.wp-block-query-pagination .page-numbers.dots,
.woocommerce-pagination .page-numbers.dots {
	min-width: 24px;
	border: none;
	background: none;
	color: var(--color-ink-soft);
	font-weight: 400;
}

/* --- Flechas anterior/siguiente: glifo + texto accesible (ver
   inc/pagination.php, que inyecta este markup en los dos filtros de Woo/
   core). El glifo va aparte del texto para poder ocultar el texto sin tocar
   el <a> completo. --- */
.pagination__arrow {
	font-size: 18px;
	line-height: 1;
}

/* --- Mobile-first: 40px de objetivo bajo 640px (sigue sobre el mínimo
   táctil recomendado sin AAA estricto de 44px; el desktop sí lo cumple). --- */
@media (min-width: 640px) {
	.wp-block-query-pagination,
	.woocommerce-pagination {
		--pg-size: 48px;
		--pg-gap: 8px;
	}
}

/* --- Variantes: redefinen solo las props, sin repetir reglas --- */

/* Densidad reducida (listados secundarios, ej. dentro de un panel angosto). */
.pagination--compact {
	--pg-size: 36px;
	--pg-gap: 4px;
}

/* Sin caja en reposo — los números quedan como links simples; el activo
   conserva la pastilla de marca para no perder el indicador de estado. */
.pagination--quiet {
	--pg-face: transparent;
	--pg-line: transparent;
}
.pagination--quiet .page-numbers:hover,
.pagination--quiet a:hover {
	background: var(--color-field);
}

/* assets/css/woocommerce.css */
/* Cohasa — estilos sobre el markup por defecto de WooCommerce que no
   pasamos por content-product.php (carrito, checkout, cuenta, ficha). */

/* El breadcrumb de la ficha de producto ya no es woocommerce_breadcrumb()
   (.woocommerce-breadcrumb): inc/woocommerce-hooks.php lo reemplaza por
   cohasa_breadcrumb(), el mismo componente único que usa TODO el sitio
   (.breadcrumb, assets/css/main.css, inc/breadcrumb.php) — listados de
   tienda incluidos, ya no hay una segunda implementación acá. */

/* Botones genéricos de Woo (agregar al carrito en listado, "Actualizar carrito", etc.) */
.woocommerce a.button,
.woocommerce button.button,
.woocommerce input.button,
.woocommerce #respond input#submit {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 44px;
	padding: 10px 20px;
	border-radius: var(--radius);
	border: 1px solid transparent;
	background: var(--color-accent);
	color: var(--color-accent-ink);
	font-weight: 700;
	font-size: 14px;
	text-decoration: none;
	cursor: pointer;
}
.woocommerce a.button.alt,
.woocommerce #respond input#submit.alt {
	background: var(--color-accent);
}
.woocommerce a.button:focus-visible,
.woocommerce button.button:focus-visible,
.woocommerce input.button:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
}

/* Avisos: siempre con texto, nunca solo color — Woo ya los trae con texto,
   acá solo se asegura contraste AA y un borde lateral perceptible sin color.
   .woocommerce-noreviews NO es un aviso: se oculta acá y se reemplaza por
   .cohasa-empty-state (ver assets/css/producto.css, inc/reviews.php) — un
   borde de alerta ahí se leía como error, no como estado neutro. */
.woocommerce-noreviews { display: none; }
.woocommerce-message,
.woocommerce-error,
.woocommerce-info {
	margin: 16px 0;
	padding: 14px 16px;
	border-radius: var(--radius);
	background: var(--color-surface);
	border: 1px solid var(--color-line-strong); /* 3:1 WCAG 1.4.11, ver .spec-table */
	border-left-width: 4px;
	box-shadow: var(--shadow-card);
	list-style: none;
	font-size: 14px;
}
.woocommerce-error { border-left-color: var(--color-error); }
.woocommerce-message { border-left-color: var(--color-ok); }

/* Links dentro del aviso ("Confirm email address", "Ver carrito"): sin
   subrayado (design.md, "Sin redundancia ni texto subrayado") — se
   distinguen por peso de fuente, ya con suficiente contraste de color. */
.woocommerce-message a,
.woocommerce-error a,
.woocommerce-info a {
	font-weight: 700;
	text-decoration: none;
}

/* Ícono por delante del texto — el color nunca es el único portador del
   estado (design.md / WCAG 1.4.1). mask-image en vez de <svg> inline: el
   aviso lo imprime el core sin ningún hook disponible antes del texto. */
.woocommerce-message,
.woocommerce-error,
.woocommerce-info {
	display: flex;
	align-items: flex-start;
	gap: 10px;
}
.woocommerce-message::before,
.woocommerce-error::before,
.woocommerce-info::before {
	content: "";
	flex-shrink: 0;
	width: 18px;
	height: 18px;
	margin-top: 1px;
	background: currentColor;
	-webkit-mask-size: contain;
	mask-size: contain;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
}
.woocommerce-message::before {
	color: var(--color-ok);
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
}
.woocommerce-error::before {
	color: var(--color-error);
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
.woocommerce-info::before {
	color: var(--color-ink-soft);
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='12' y2='16'/%3E%3Cline x1='12' x2='12.01' y1='8' y2='8'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='12' y2='16'/%3E%3Cline x1='12' x2='12.01' y1='8' y2='8'/%3E%3C/svg%3E");
}
/* "Ver carrito" dentro del aviso: hereda el botón de acento a tamaño
   completo, desproporcionado dentro de una barra de 14px. */
.woocommerce-message .button.wc-forward {
	min-height: 32px;
	padding: 4px 14px;
	font-size: 13px;
	margin-left: auto;
}

/* Barra de aviso de tienda (Ajustes > Tienda > "Bloque de venta") y el
   wrapper de avisos de Mi Cuenta — hoy sin cobertura del tema. */
.woocommerce-store-notice {
	background: var(--color-ink);
	color: var(--color-bg);
	padding: 10px var(--gutter);
	font-size: 13.5px;
	text-align: center;
}
.woocommerce-store-notice__dismiss-link {
	color: inherit;
	text-decoration: underline;
	margin-left: 10px;
}
.woocommerce-notices-wrapper:empty {
	display: none;
}

/* Formularios: checkout, mi cuenta, login */
.woocommerce form .form-row label {
	display: block;
	font-weight: 600;
	font-size: 13.5px;
	margin-bottom: 6px;
}
.woocommerce form .form-row {
	margin-bottom: 16px;
}
/* Región/comuna (assets/js/checkout-select.js envuelve el <select> nativo
   en .cohasa-select): ancho completo como el resto de los campos del form-row.
   Acotado a .form-row para no afectar al select compacto del toolbar de
   orden (.shop-archive__toolbar .cohasa-select), que no vive en un form-row. */
.woocommerce form .form-row .cohasa-select { width: 100%; }
/* Componente de campo unificado (--input-*, forms.css) — mismo look que el
   select y el resto de campos del sitio, ver design.md "Campos". */
.woocommerce form .woocommerce-input-wrapper input,
.woocommerce form input.input-text:not(.cohasa-qty__input),
#review_form input[type="text"],
#review_form input[type="email"],
#review_form textarea,
.woocommerce form textarea {
	width: 100%;
	min-height: var(--input-h);
	padding: var(--input-py) var(--input-px);
	border: 1px solid var(--input-border);
	border-radius: var(--input-radius);
	background: var(--input-bg);
	color: var(--color-ink);
	font-family: inherit; /* sin esto, el <textarea> queda con el monospace por defecto del navegador. */
	font-size: var(--input-fs);
}
.woocommerce form input.input-text:not(.cohasa-qty__input):hover,
.woocommerce form textarea:hover {
	border-color: var(--input-border-hover);
}
/* Anillo neutro de un solo aro, no --focus-ring: mismo motivo que
   .wc-block-components-text-input input:focus más abajo — --focus-ring es
   doble aro pensado para botones/links angostos, sobre un input ancho se ve
   como un marco duro (ver design.md, "Foco visible"). */
.woocommerce form input.input-text:not(.cohasa-qty__input):focus-visible,
.woocommerce form textarea:focus-visible {
	outline: none;
	background: var(--input-bg);
	box-shadow: 0 0 0 3px var(--input-ring);
	border-color: var(--input-border-hover);
}
.woocommerce form .required { color: var(--color-error); }

/* Botón "mostrar contraseña" (assets/js/frontend/woocommerce.js del plugin
   envuelve todo <input type="password"> en <span class="password-input">
   y le agrega <button class="show-password-input">, sin depender de ningún
   hook de plantilla) — dependía 100% del CSS core de WooCommerce
   (posición absoluta + ícono de ojo) para verse. Al desactivarlo
   (woocommerce_enqueue_styles, más abajo) quedaba un botón vacío y sin
   posicionar, suelto debajo del campo (bug real, visto en login y en
   Mi cuenta > Detalles de la cuenta). Mismo patrón de ícono con mask-image
   que los avisos de arriba — cohasa_icon() no aplica: este botón lo genera
   JS del plugin, no hay dónde inyectar el <svg> inline del tema. */
.password-input {
	position: relative;
	display: block;
}
.password-input input[type="password"],
.password-input input[type="text"] {
	padding-right: 44px;
}
.show-password-input {
	position: absolute;
	top: 0;
	right: 0;
	width: 44px;
	height: 44px;
	padding: 0;
	border: 0;
	background: transparent;
	cursor: pointer;
	border-radius: var(--radius);
}
.show-password-input::before {
	content: "";
	display: block;
	width: 20px;
	height: 20px;
	margin: 0 auto;
	background: var(--color-ink-soft);
	-webkit-mask-size: contain;
	mask-size: contain;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-position: center;
	mask-position: center;
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E");
}
/* .display-password: clase que el JS del plugin agrega al revelar el valor — ícono "ojo tachado". */
.show-password-input.display-password::before {
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49'/%3E%3Cpath d='M14.084 14.158a3 3 0 0 1-4.242-4.242'/%3E%3Cpath d='M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143'/%3E%3Cpath d='m2 2 20 20'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49'/%3E%3Cpath d='M14.084 14.158a3 3 0 0 1-4.242-4.242'/%3E%3Cpath d='M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143'/%3E%3Cpath d='m2 2 20 20'/%3E%3C/svg%3E");
}
.show-password-input:hover::before { background: var(--color-ink); }
.show-password-input:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
}

/* Tabla de carrito: se convierte en tarjetas apiladas en móvil */
.woocommerce table.shop_table {
	width: 100%;
	border-collapse: collapse;
	margin: 0 0 24px;
}
.woocommerce table.shop_table th,
.woocommerce table.shop_table td {
	padding: 12px 8px;
	border-bottom: 1px solid var(--color-line);
	text-align: left;
	font-size: 14px;
}
@media (max-width: 640px) {
	.woocommerce table.shop_table thead { display: none; }
	.woocommerce table.shop_table tr { display: block; border-bottom: 1px solid var(--color-line); padding: 10px 0; }
	.woocommerce table.shop_table td { display: flex; justify-content: space-between; gap: 12px; border: none; padding: 6px 0; }
	.woocommerce table.shop_table td::before { content: attr(data-title); font-weight: 600; color: var(--color-ink-soft); }
	/* La fila de método de envío (cart-shipping.php de WooCommerce core, sin
	   override) ya trae su propio label dentro de la tarjeta de
	   .woocommerce-shipping-methods (carrito.css) — el data-title="Envío"
	   duplicaba la etiqueta y empujaba la tarjeta pegada al borde derecho. */
	.woocommerce table.shop_table tr.woocommerce-shipping-totals td::before { content: none; }
}

/* Selector de cantidad [−] 1 [+] (woocommerce/global/quantity-input.php):
   caja única con borde completo, sin divisores internos. */
.woocommerce div.quantity.cohasa-qty,
.cohasa-qty {
	display: inline-flex;
	align-items: stretch;
	min-height: 44px;
	border: 1px solid var(--color-line);
	border-radius: var(--radius);
	background: var(--color-surface);
	overflow: hidden;
}
.cohasa-qty:focus-within {
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-ink) 15%, transparent);
}
.cohasa-qty__btn {
	min-width: 44px;
	padding: 0;
	border: 0;
	background: transparent;
	color: var(--color-ink);
	font-size: 20px;
	line-height: 1;
	cursor: pointer;
}
.cohasa-qty__btn:hover:not(:disabled) { background: var(--color-field); }
.cohasa-qty__btn:disabled { opacity: 0.4; cursor: not-allowed; }
.cohasa-qty__input {
	width: 56px;
	min-height: 0;
	padding: 0;
	border: 0;
	border-radius: 0;
	background: transparent;
	box-shadow: none;
	color: var(--color-ink);
	text-align: center;
	font-variant-numeric: tabular-nums;
	font-size: 15px;
}
/* El aro de foco va en el contenedor (arriba, :focus-within); sin esto el
   input hereda el --focus-ring global (main.css) y lo pinta encima del
   borde de .cohasa-qty, que además recorta con overflow:hidden — mismo
   patrón que .site-search input:focus. */
.cohasa-qty__input:focus { outline: none; box-shadow: none; }
/* Refuerzo de padding/font-size del stepper dentro de la ficha de producto
   (cohasa/product-add-to-cart) — antes compensaba el CSS de WooCommerce
   Blocks (add-to-cart-form.css, con su propia regla .input-text) que solo
   se enqueueaba por usar el bloque nativo wp:woocommerce/add-to-cart-form;
   al reemplazarlo por un bloque propio ese CSS ya no se carga, pero la
   regla se mantiene igual como fuente de verdad de estos valores. */
.wp-block-cohasa-product-add-to-cart .cohasa-qty .cohasa-qty__input {
	padding: 0;
	font-size: 15px;
}

/* Precios y estrellas de valoración. Un solo componente de precio para TODO
   el sitio: .woocommerce .price cubre el markup clásico (tienda, mini-cart),
   .wc-block-formatted-money-amount es el wrapper único que WooCommerce
   Blocks pone alrededor de CUALQUIER importe (líneas del carrito, envío,
   subtotal, total del checkout), y .woocommerce-Price-amount es el que usa
   wc_price() puertas adentro de woocommerce/product-price (bloque nativo de
   la ficha) — un tercer wrapper con el mismo rol que ninguno de los otros
   dos selectores alcanzaba. Antes solo tienda/carrito salían en mono; la
   ficha (bloque nativo) quedaba en Inter. JetBrains Mono con
   font-variant-numeric ya presente arriba (dígitos tabulares): son importes
   comparables en columna, el mono los alinea. */
.woocommerce .price,
.wc-block-formatted-money-amount,
.woocommerce-Price-amount {
	font-family: var(--font-mono);
	font-weight: 700;
}
/* El navegador subraya <ins> por defecto (igual que <u>); .product-card__price
   y .quick-view__price ya lo resetean — acá cubre el precio de la ficha
   completa (woocommerce/product-price) y cualquier otro .woocommerce .price
   que use <ins> para el precio rebajado. */
.woocommerce .price ins {
	text-decoration: none;
}
/* Precio de la ficha (woocommerce/product-price, cohasa_block_product_price):
   mismo criterio que .product-card__price — precio actual (<ins>) primero,
   tachado (<del>) después. order:-1 en <ins> lo adelanta visualmente sin
   tocar el DOM (el <del> sigue antes que el <ins> para lectores de pantalla,
   "antes $X, ahora $Y") ni reordenar otros hijos del contenedor — a
   diferencia de flex-direction: row-reverse, que también invertía el rango
   de precio (mín–máx) de productos agrupados/variables. */
.wp-block-cohasa-product-price .price {
	display: flex;
	align-items: baseline;
	gap: 10px;
}
.wp-block-cohasa-product-price .price ins {
	order: -1;
}

/* Precio de cada fila del listado de agrupados (woocommerce/single-product/
   add-to-cart/grouped.php): get_price_html() de un hijo no trae el <span
   class="price"> que envuelve el precio en el resto del sitio, así que la
   regla de arriba no lo alcanza. El span .precio-inner (agregado en el
   template, no un filtro) es quien lleva el flex — nunca el <td> mismo, que
   perdería su comportamiento de celda de tabla (vertical-align, estirado al
   alto de la fila) y desalinearía la línea divisoria de la fila. */
.cohasa-matriz-tallas__precio-inner {
	display: inline-flex;
	align-items: baseline;
	gap: 6px;
	white-space: nowrap;
}
.cohasa-matriz-tallas__precio-inner ins {
	order: -1;
	text-decoration: none;
}
/* Nombre de producto (vs. "S"/"M"/"L" de la matriz de tallas original) es
   mucho más largo y se lleva la mayoría del ancho de la tabla en layout
   automático — precio/stock/cantidad quedaban demasiado angostos y
   "disponibles" se partía a mitad de palabra (word-break heredado de
   .wp-block-column, mismo bug que ya se vio en el listado de agrupados).
   Estas tres columnas son texto corto que nunca necesita envolver: se fija
   a una sola línea para que el layout automático les deje el ancho mínimo
   necesario y ceda el resto a la columna de producto. */
.cohasa-matriz-tallas__tabla td.cohasa-matriz-tallas__stock {
	white-space: nowrap;
}
/* El nowrap de arriba le devuelve ancho a "Producto", pero la celda sigue
   heredando `word-break: break-word` de un ancestro `.wp-block-column`
   (columna del layout de la ficha) — la propiedad SÍ se hereda en cascada,
   así que aunque haya ancho de sobra, el navegador puede seguir partiendo
   el nombre letra por letra en vez de recién en el siguiente espacio.
   `word-break: normal` corta la herencia en este nodo. Sin min-width a
   propósito: la tabla vive en la columna angosta de .pdp__layout (la otra
   mitad es la galería) y esta variante ya tiene overflow:visible (abajo,
   para el panel del select de talla) — un min-width que no entrara habría
   desbordado la tabla en vez de encogerla, cortando las columnas
   Stock/Cantidad contra el borde. Mejor dejar que el layout automático de
   la tabla la encoja: con la herencia cortada, ahora envuelve por espacio
   en vez de por letra. */
.cohasa-matriz-tallas__tabla--agrupado th[scope="row"] {
	word-break: normal;
	overflow-wrap: break-word; /* solo si una palabra sola no entra ni angosta */
}
/* Mismo quiebre a tarjeta apilada que .woocommerce table.shop_table (main.css
   de este mismo archivo, arriba) y mismo breakpoint — solo para la variante
   ".--agrupado" (woocommerce/single-product/add-to-cart/grouped.php): la
   matriz de tallas real (single-product/add-to-cart/variable.php) nunca
   necesitó esto porque "S"/"M"/"L" siempre entra en una columna angosta;
   el nombre del producto acá no. Sin esto, con las otras 3 columnas fijas
   en una línea (arriba), a "Producto" no le quedaba ancho y se partía letra
   por letra (word-break heredado de .wp-block-column). */
/* Select de talla de un componente dentro de la tabla de agrupado
   (woocommerce/single-product/add-to-cart/grouped.php, .cohasa-set-talla):
   .cohasa-select trae min-width:220px pensado para un formulario suelto
   (forms.css) — en esta celda angosta esos 220px forzaban el layout
   automático de la tabla a exprimir la columna "Producto" hasta partir el
   texto letra por letra para compensar. */
.cohasa-set-talla .cohasa-select {
	min-width: 0;
	width: 100%;
	max-width: 160px;
}
.cohasa-set-talla__qty {
	margin-top: 8px;
}
/* .woocommerce div.quantity.cohasa-qty (más arriba en este archivo) le pone
   display:inline-flex con especificidad (0,0,3,1) — más alta que un simple
   [hidden], así que el atributo quedaba sin efecto y el stepper se veía
   aunque no se hubiese elegido talla todavía. Se iguala la especificidad
   agregando las mismas clases. */
.woocommerce div.quantity.cohasa-qty.cohasa-set-talla__qty[hidden],
.cohasa-set-talla__qty[hidden] {
	display: none;
}

/* El panel del select de talla (.cohasa-select__panel, forms.css) es
   position:absolute y depende de que ningún ancestro lo recorte. La tabla
   de matriz-tallas.css trae overflow:hidden (solo para redondear las 4
   esquinas con border-collapse:collapse) — eso también recorta el panel
   cuando se abre en la última fila. Solo la variante --agrupado necesita
   overflow:visible (es la única que mete un .cohasa-select adentro; la
   matriz de tallas normal no tiene overflow:hidden por otra razón que no
   pueda perder). border-collapse:separate + border-spacing:0 evitan que el
   cambio de overflow deje ver el borde recto de las celdas por fuera del
   radius de la tabla (las celdas de esta tabla no tienen fondo propio, así
   que basta con el border-radius que ya trae .cohasa-matriz-tallas__tabla). */
.cohasa-matriz-tallas__tabla--agrupado {
	overflow: visible;
	border-collapse: separate;
	border-spacing: 0;
}

@media (max-width: 640px) {
	.cohasa-matriz-tallas__tabla--agrupado thead { display: none; }
	.cohasa-matriz-tallas__tabla--agrupado .cohasa-matriz-tallas__fila {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: 4px 10px;
		/* Tarjeta por producto: el padding pasa de la celda (4px 0, abajo) a la
		   fila completa, y el separador entre productos vive acá también —
		   mismo criterio que .cohasa-matriz-tallas__fila:last-child en
		   matriz-tallas.css (borde solo entre filas, no en la última). */
		padding: 14px 16px;
		border-bottom: 1px solid var(--color-line);
	}
	.cohasa-matriz-tallas__tabla--agrupado .cohasa-matriz-tallas__fila:last-child {
		border-bottom: 0;
	}
	.cohasa-matriz-tallas__tabla--agrupado .cohasa-matriz-tallas__fila th,
	.cohasa-matriz-tallas__tabla--agrupado .cohasa-matriz-tallas__fila td {
		display: block;
		border: none;
		padding: 4px 0;
	}
	.cohasa-matriz-tallas__tabla--agrupado th[scope="row"] { order: 1; flex: 1 1 100%; font-weight: 500; }
	.cohasa-matriz-tallas__tabla--agrupado .cohasa-matriz-tallas__precio { order: 2; }
	.cohasa-matriz-tallas__tabla--agrupado .cohasa-matriz-tallas__stock { order: 3; margin-left: auto; }
	.cohasa-matriz-tallas__tabla--agrupado td:last-child { order: 4; flex: 1 1 100%; padding-top: 6px; }

	/* Fila SIN talla: el stepper es el único control de la celda, se estira
	   a todo el ancho de la tarjeta. .cohasa-qty es inline-flex sin
	   flex-grow en sus hijos (así queda en el resto del sitio, donde nunca
	   tiene que llenar el contenedor) — sin flex:1 en el input, el
	   width:100% del contenedor no reparte el espacio sobrante y los ±44px
	   quedan pegados al borde izquierdo con un hueco vacío a la derecha. */
	.cohasa-matriz-tallas__tabla--agrupado .cohasa-qty {
		width: 100%;
	}
	.cohasa-matriz-tallas__tabla--agrupado .cohasa-qty__input {
		flex: 1;
	}

	/* Fila CON talla: select + stepper lado a lado en vez de apilados
	   (.cohasa-set-talla__qty trae margin-top:8px pensado para el apilado de
	   desktop) — apilar dos controles de 44px de alto en una tarjeta ya
	   apretada por el padding nuevo alarga la fila sin necesidad. */
	.cohasa-matriz-tallas__tabla--agrupado .cohasa-set-talla {
		display: flex;
		gap: 8px;
	}
	.cohasa-matriz-tallas__tabla--agrupado .cohasa-set-talla .cohasa-select {
		/* max-width:160px (arriba, fuera del media query) es para la columna
		   angosta de desktop; acá el select vive en una fila propia y debe
		   repartirse el ancho con el stepper como cualquier flex item. */
		flex: 1;
		max-width: none;
	}
	.cohasa-matriz-tallas__tabla--agrupado .cohasa-set-talla__qty {
		flex: 1;
		margin-top: 0;
	}
}

.woocommerce .star-rating { color: var(--color-accent-text); }
/* WC fija el color de la estrella VACÍA (::before, detrás del span lleno)
   a #cfc8d8 fijo en su propio CSS — 1.5-1.63:1 sobre --color-bg/--color-surface
   claro (invisible), bajo el mínimo 3:1 de WCAG 1.4.11 para gráficos con
   significado. Mismo bug que .product-card__star (ver main.css), mismo fix:
   --color-line-strong (3.08-3.89:1 según fondo). */
.woocommerce .star-rating::before { color: var(--color-line-strong); }

/* Galería de producto: ver assets/css/producto.css (markup propio en woocommerce/single-product/product-image.php).
   Sección de reseñas (#review_form, .cohasa-reviews): también en producto.css — solo existe en la ficha. */

/* Grilla nativa de WooCommerce Blocks (ej. "Recién llegados" del carrito
   vacío) — sus imágenes traen width/height reales en el HTML, pero el CSS
   del bloque las estira a 100% de ancho sin aspect-ratio, así que el
   navegador no puede reservar el alto real hasta que la imagen carga
   (Chrome lo marca como salto de layout potencial). */
.wc-block-grid__product-image img {
	aspect-ratio: 1 / 1;
	object-fit: contain;
	width: 100%;
	height: auto;
	border-radius: var(--radius);
}

.wc-block-grid__product-title {
	font-weight: 600;
	color: var(--color-ink);
	text-decoration: none;
}

/* Pedido recibido (order-confirmation.html, bloques woocommerce/order-
   confirmation-*): sin cobertura propia, salía entero con la paleta y los
   radios por defecto de wc-blocks.css. Reusa el mismo tratamiento de
   tarjeta que .wc-block-checkout__sidebar (resumen de checkout, arriba) y
   .woocommerce-Address (Mi cuenta, más abajo). */
/* Sin padding-inline: order-confirmation.html ya envuelve en <main
   class="container">, que aporta el gutter — esta regla no tiene caja propia
   (sin fondo/borde) así que no necesita el suyo. */
.wc-block-order-confirmation-status {
	margin: 0 0 24px;
}
.wc-block-order-confirmation-status__description {
	font-family: var(--font-display);
	font-size: clamp(22px, 3vw, 30px);
}
.wc-block-order-confirmation-summary {
	margin: 0 0 24px;
	padding: 16px var(--gutter);
	background: var(--color-surface);
	border: 1px solid var(--color-line-strong); /* 3:1 WCAG 1.4.11, ver .spec-table */
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-card);
}
.wc-block-order-confirmation-summary-list {
	display: flex;
	flex-wrap: wrap;
	gap: 16px 32px;
	list-style: none;
	margin: 0;
	padding: 0;
}
.wc-block-order-confirmation-summary-list-item__key {
	color: var(--color-ink-soft);
	font-size: 12.5px;
}
.wc-block-order-confirmation-summary-list-item__value {
	color: var(--color-ink);
	font-weight: 700;
}
/* Lista de beneficios del bloque "Crear cuenta" en la confirmación del
   pedido: WooCommerce le pone la clase is-style-checkmark-list pero nunca
   registra el ícono — sin esto quedaba con el bullet redondo por defecto
   del navegador. Mismo ícono/técnica que .woocommerce-message::before. */
.is-style-checkmark-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 8px;
}
.is-style-checkmark-list li {
	display: flex;
	align-items: flex-start;
	gap: 10px;
}
.is-style-checkmark-list li::before {
	content: "";
	flex-shrink: 0;
	width: 18px;
	height: 18px;
	margin-top: 2px;
	background: currentColor;
	color: var(--color-ok);
	-webkit-mask-size: contain;
	mask-size: contain;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
}

.wc-block-grid__product-price {
	color: var(--color-ink-soft);
}
.wc-block-grid .wp-block-button__link,
.wc-block-grid__product-add-to-cart .wp-block-button__link {
	background: var(--color-accent);
	color: var(--color-accent-ink);
	border-radius: var(--radius);
	font-weight: 600;
	padding: 10px 18px;
}
.wc-block-grid .wp-block-button__link:hover,
.wc-block-grid__product-add-to-cart .wp-block-button__link:hover {
	filter: brightness(0.95);
}

/* La ficha de producto migró de woocommerce/legacy-template a bloques
   (templates/single-product.html + cohasa/*, inc/blocks.php) — el layout de
   dos columnas ahora es .pdp__layout (main.css), no esta regla. El wrapper
   <div class="woocommerce product type-product ..."> sigue existiendo (lo
   sigue generando la capa de compatibilidad de bloques de WooCommerce,
   SingleProductTemplateCompatibility, para que hooks de terceros como
   woocommerce_after_single_product — Facebook/Google Ads — no dejen de
   disparar) y sigue envolviendo <main>, pero ya NO debe forzar layout
   propio: antes esta regla ponía display:grid con 2 columnas y como <main>
   es su único hijo, todo el contenido quedaba metido en una sola celda de
   ~620px con la segunda columna vacía — ficha angosta y matriz de tallas
   con las palabras partidas letra por letra. Se deja solo el padding
   inferior; el ancho ya lo resuelve <main class="container">. */
.woocommerce div.product {
	padding-bottom: 40px;
}

/* La ficha de producto migró de woocommerce/legacy-template a bloques
   (templates/single-product.html + cohasa/*, ver Fase 4 del refactor) — el
   markup ".summary"/".product_title"/".woocommerce-product-rating" de acá
   abajo pertenecía al resumen clásico (float title+rating, tarjeta con
   borde propio) y ya no existe en el DOM: el título es post-title suelto,
   el rating usa cohasa_product_rating_html() (.product-card__rating, no
   .woocommerce-product-rating — mismo componente desde antes de esta
   migración, esta regla ya estaba muerta), el precio es
   .wp-block-cohasa-product-price (estilo nuevo en main.css). Todo ese
   bloque se retiró acá; .cohasa-price-installments sigue vivo (lo sigue
   emitiendo cohasa_precio_cuotas() vía el bloque cohasa/product-cuotas). */
.cohasa-price-installments {
	font-family: var(--font-body);
	font-size: 13.5px;
	font-weight: 400;
	color: var(--color-ink-soft);
	margin-top: 6px;
}
.cohasa-price-installments strong {
	color: var(--color-ok);
	font-weight: 700;
}

/* Botones "Comprar ahora" (nuevo, ver inc/product-summary-hooks.php) +
   "Agregar al carrito" (nativo): apilados a todo ancho, orden fijo tipo
   mockup (cantidad, Comprar ahora, Agregar al carrito). Comprar ahora usa
   el estilo primario de acento; agregar al carrito queda como acción
   secundaria (outline) para no competir visualmente.
   .wp-block-cohasa-product-add-to-cart form.cart: wrapper del bloque propio
   cohasa/product-add-to-cart (templates/single-product.html) — antes
   apuntaba a ".summary form.cart", markup del legacy-template que ya no se
   usa (ver migración a bloques). */
.wp-block-cohasa-product-add-to-cart form.cart,
.wp-block-cohasa-product-add-to-cart .woocommerce-variation-add-to-cart {
	display: flex;
	flex-direction: column;
	gap: 10px;
	margin-bottom: 4px;
}
.wp-block-cohasa-product-add-to-cart form.cart .quantity,
.wp-block-cohasa-product-add-to-cart .woocommerce-variation-add-to-cart .quantity {
	order: 0;
	align-self: flex-start;
}
.woocommerce .wp-block-cohasa-product-add-to-cart .cohasa-buy-now-button {
	order: 1;
	width: 100%;
	min-height: 48px;
	background: var(--color-accent);
	color: var(--color-accent-ink);
	font-size: 15px;
}
/* .woocommerce antepuesto: sube la especificidad a (0,3,0) para ganarle a
   ".woocommerce button.button" (0,2,1, más arriba en este archivo) — con
   solo 2 clases el botón secundario volvía a salir verde sólido en vez del
   outline pensado para no competir con "Comprar ahora". */
.woocommerce .wp-block-cohasa-product-add-to-cart .single_add_to_cart_button {
	order: 2;
	width: 100%;
	min-height: 48px;
	background: transparent;
	/* Mismos valores que .btn--secondary (main.css): fuente de verdad del par
	   primario/secundario. El markup lo genera el core, sin poder sumar la clase. */
	border: 1px solid var(--color-ink);
	color: var(--color-ink);
}
.woocommerce .wp-block-cohasa-product-add-to-cart .single_add_to_cart_button:hover {
	background: var(--color-field);
}

/* Franja de confianza (ver inc/product-summary-hooks.php,
   cohasa_franja_confianza()): despacho/retiro/garantía, configurable desde
   el Customizer — bajo los botones de compra. */
.cohasa-trust {
	display: flex;
	flex-direction: column;
	gap: 8px;
	margin: 16px 0 0;
	padding: 16px 0 0;
	border-top: 1px solid var(--color-line);
	list-style: none;
	font-size: 13.5px;
}
.cohasa-trust__item {
	display: flex;
	align-items: center;
	gap: 8px;
}
.cohasa-trust svg {
	width: 18px;
	height: 18px;
	color: var(--color-accent-text);
	flex-shrink: 0;
}

/* Tabla de variaciones (producto variable): el core de WooCommerce está
   deshabilitado vía woocommerce_enqueue_styles (ver functions.php), así que
   <table class="variations"> llega sin ningún spacing — el <select> ya
   hereda el estilo genérico de "form select" más abajo. */
.woocommerce table.variations {
	width: 100%;
	margin: 0 0 16px;
	border-collapse: collapse;
}
.woocommerce table.variations th.label {
	padding: 8px 12px 8px 0;
	text-align: left;
	font-weight: 600;
	font-size: 14px;
	vertical-align: middle;
	white-space: nowrap;
}
.woocommerce table.variations td.value {
	padding: 8px 0;
	display: flex;
	align-items: center;
	gap: 12px;
}
.woocommerce table.variations td.value select { max-width: 260px; }
.woocommerce .reset_variations {
	font-size: 13px;
	color: var(--color-ink-soft);
	text-decoration: underline;
}
/* WooCommerce lo oculta con visibility:hidden (sigue ocupando alto). */
.woocommerce .reset_variations[style*="hidden"] {
	display: none;
}
.wp-block-cohasa-product-add-to-cart table.variations {
	margin-bottom: 0;
}
.woocommerce .woocommerce-variation-add-to-cart {
	margin-top: 16px;
}

/* Paginación de la tienda: ver assets/css/pagination.css — componente único
   compartido con core/query-pagination (/tienda/). */

/* Carrito/checkout por bloques (WooCommerce Blocks): usan sus propias clases
   wc-block-components-* con colores y radios fijos del plugin, sin relación
   a los tokens del theme ni a modo oscuro. Se alinean acá. */
.wc-block-components-notice-banner {
	margin: 16px 0;
	border-radius: var(--radius);
	background: var(--color-surface);
	color: var(--color-ink);
}
.wc-block-components-notice-banner.is-error {
	background: var(--color-surface);
	border-color: var(--color-error);
}
.wc-block-components-notice-banner.is-error > svg {
	background-color: var(--color-error);
	color: var(--color-on-status); /* glifo currentColor sobre el fondo de color: blanco/#fff en
		claro (8.17:1), --color-bg oscuro en modo oscuro (9.75:1) — antes blanco fijo daba 1.74:1
		en oscuro con --color-error claro */
}
.wc-block-components-notice-banner.is-success {
	background: var(--color-surface);
	border-color: var(--color-ok);
}
.wc-block-components-notice-banner.is-success > svg {
	background-color: var(--color-ok);
	color: var(--color-on-status);
}
/* .is-info / .is-warning: antes sin cubrir acá, el plugin fija un fondo
   celeste/amarillo claro fijo sin considerar modo oscuro — con el texto
   claro global del tema quedaba prácticamente invisible (ej. "No se ha
   hecho ningún pedido todavía" en /mi-cuenta/pedidos/). Mismo criterio que
   error/success: fondo de superficie del tema, borde lateral semántico. */
.wc-block-components-notice-banner.is-info,
.wc-block-components-notice-banner.is-warning {
	background: var(--color-surface);
	border-color: var(--color-line);
}
.wc-block-components-notice-banner.is-info > svg {
	background-color: var(--color-ink-soft);
}
.wc-block-components-notice-banner.is-warning > svg {
	background-color: var(--color-oferta-bg);
}
/* Enlace de acción ("Ver carrito", "Confirm email address"): el plugin le
   fija un color sin considerar modo oscuro. El reset global de main.css
   (`a { text-decoration: none }`, especificidad 0,1,0) NO alcanza acá: WC
   fija su propio "text-decoration: underline" en ".button.wc-forward"
   (0,2,0, le gana) — quedaba subrayado pese al comentario que asumía lo
   contrario (bug real, visto en /mi-cuenta/pedidos/, aviso "confirma tu
   correo", 2026-09-24). Se distingue por peso de fuente, no por subrayado. */
.wc-block-components-notice-banner .wc-forward,
.wc-block-components-notice-banner > .wc-block-components-notice-banner__content .wc-forward,
.wc-block-components-notice-banner__content a {
	color: var(--color-ink) !important; /* el plugin fija #2f2f2f !important con selector de igual especificidad */
	text-decoration: none;
	opacity: 1;
	font-weight: 700;
	display: inline-flex;
	align-items: center;
	min-height: 44px;
}
.wc-block-components-notice-banner .wc-forward:focus-visible,
.wc-block-components-notice-banner__content a:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
}

.wc-block-components-totals-coupon__input input[type="text"] {
	min-height: var(--input-h);
	border-radius: var(--input-radius);
	border-color: var(--input-border);
	background: var(--input-bg);
	color: var(--color-ink);
}
.wc-block-components-totals-coupon__input input[type="text"]:hover {
	border-color: var(--input-border-hover);
}
.wc-block-components-totals-coupon__input input[type="text"]:focus {
	outline: none;
	border-color: var(--input-border-hover);
	box-shadow: 0 0 0 3px var(--input-ring);
}
.wc-block-components-totals-coupon__button {
	min-height: 44px;
	padding: 10px 20px;
	border: 1px solid transparent;
	border-radius: var(--radius);
	background: var(--color-accent) !important;
	color: var(--color-accent-ink) !important;
	font-weight: 700;
	opacity: 1;
}
.wc-block-components-totals-coupon__button:hover {
	opacity: .9;
}
.wc-block-components-totals-coupon__button:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
}
/* Fieldset de cambio de contraseña en "Datos de la cuenta": Woo entrega un
   <fieldset><legend> nativo sin clase — borde/legend con el estilo por
   defecto del navegador, inconsistente con el resto de tarjetas del theme.
   (Mi cuenta propiamente tal: ver assets/css/cuenta.css — este selector
   sigue acá porque #review_form también usa <fieldset>.) */
.woocommerce form fieldset {
	margin: 8px 0 16px;
	padding: 16px;
	border: 1px solid var(--color-line);
	border-radius: var(--radius);
}
.woocommerce form fieldset legend {
	padding: 0 8px;
	font-weight: 700;
	font-size: 14px;
}

/* Editar cuenta / editar dirección: nombre+apellido y campos pareados a
   2 columnas desde tablet — llegaban apilados a ancho completo siempre. */
@media (min-width: 640px) {
	.woocommerce-form-row--first {
		display: inline-block;
		width: 48%;
		margin-right: 4%;
	}
	.woocommerce-form-row--last {
		display: inline-block;
		width: 48%;
	}
}

/* Datos del cliente (ver pedido / pedido recibido): mismo tratamiento de
   tarjeta que .woocommerce-Address, ya que es el mismo tipo de contenido
   (nombre, dirección, contacto). */
.woocommerce-customer-details {
	display: grid;
	grid-template-columns: 1fr;
	gap: 16px;
	margin: 24px 0;
}
@media (min-width: 640px) {
	.woocommerce-customer-details.woocommerce-columns--addresses {
		grid-template-columns: 1fr 1fr;
	}
}
.woocommerce-customer-details .woocommerce-column {
	background: var(--color-surface);
	border: 1px solid var(--color-line);
	border-radius: var(--radius-lg);
	padding: 20px;
}
.woocommerce-customer-details .woocommerce-column__title {
	font-family: var(--font-display);
	font-size: 17px;
	margin: 0 0 12px;
}
.woocommerce-customer-details address {
	font-style: normal;
	font-size: 14px;
	line-height: 1.6;
	color: var(--color-ink-soft);
}

/* Notas del pedido (Mi cuenta > Ver pedido): ol.woocommerce-OrderUpdates
   también usa la clase commentlist, pero NO es la lista de reseñas —
   acá se estiliza aparte de #reviews ol.commentlist (producto.css). */
.woocommerce-OrderUpdates {
	list-style: none;
	margin: 16px 0 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 8px;
}
.woocommerce-OrderUpdates .note_content {
	padding: 10px 14px;
	border-radius: var(--radius);
	background: var(--color-field);
	font-size: 13.5px;
}

/* Selector de cantidad +/- en el carrito por bloques: por defecto mide
   ~30px de alto/ancho por botón, bajo el mínimo táctil de 44px. */
.wc-block-components-quantity-selector {
	min-height: 44px;
	border-radius: var(--radius);
}
.wc-block-components-quantity-selector:after {
	border-color: var(--color-line);
	border-radius: var(--radius);
}
.wc-block-components-quantity-selector__button {
	min-width: 44px;
	opacity: 1;
	color: var(--color-ink);
}
.wc-block-components-quantity-selector__input {
	color: var(--color-ink);
}

/* --- Barra fija "Añadir al carrito" en ficha de producto (móvil) ---
   Aparece cuando el botón real (.single_add_to_cart_button) sale de vista
   al hacer scroll (ver assets/js/sticky-add-to-cart.js). Pegada al fondo real
   de la pantalla (no hay tabbar móvil que compensar — ver la nota en
   main.css). Solo aplica en móvil, mismo breakpoint (900px)
   que el resto del chrome mobile-only. */
.sticky-add-to-cart {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 41;
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 10px var(--gutter) calc(10px + env(safe-area-inset-bottom));
	background: var(--color-surface);
	border-top: 1px solid var(--color-line);
	box-shadow: 0 -4px 16px -10px rgb(13 17 23 / 0.25);
	transform: translateY(100%);
	opacity: 0;
	pointer-events: none;
	transition: transform var(--dur-base) var(--ease-out), opacity var(--dur-base) var(--ease-out);
}
.sticky-add-to-cart.is-visible {
	transform: translateY(0);
	opacity: 1;
	pointer-events: auto;
}
.sticky-add-to-cart__info {
	flex: 1 1 auto;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 2px;
}
.sticky-add-to-cart__title {
	font-size: 12.5px;
	font-weight: 600;
	color: var(--color-ink);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.sticky-add-to-cart__price {
	font-family: var(--font-mono);
	font-weight: 700;
	font-size: 13px;
	color: var(--color-ink);
}
.sticky-add-to-cart__button {
	flex: 0 0 auto;
}
.sticky-add-to-cart__button:disabled {
	opacity: 0.5;
	cursor: not-allowed;
}

@media (prefers-reduced-motion: reduce) {
	.sticky-add-to-cart {
		transition: opacity var(--dur-fast) linear;
		transform: none;
	}
}

@media (min-width: 900px) {
	.sticky-add-to-cart {
		display: none;
	}
}

/* ==========================================================================
   Archivo de productos — /tienda/ (templates/archive-product.html) y
   categorías (templates/taxonomy-product_cat.html). Ambas plantillas usan
   el bloque nativo woocommerce/product-collection + sidebar de filtros, y
   comparten estas mismas reglas .shop-archive__*.

   La tarjeta de cada producto es cohasa/product-card (inc/blocks.php), que
   reusa cohasa_render_product_card() (inc/template-tags.php) — el mismo
   componente que usan búsqueda, home y relacionados. El <li> de la grilla
   solo es un item neutro (ver li.wc-block-product más abajo).
   ========================================================================== */

/* Sin max-width/margin/padding-inline propios en esta regla: el <main
   class="site-main container shop-archive"> (archive-product.html,
   taxonomy-product_cat.html) ya aporta el gutter — volver a aplicarlo acá
   sumaba un segundo gutter (32px en vez de 16px, y desalineaba la grilla
   16px respecto del header). El breadcrumb en sí (.breadcrumb) ya no vive
   acá: archive-product.html, product-search-results.html y
   taxonomy-product-header.html usan cohasa/breadcrumb (inc/breadcrumb.php),
   el mismo componente único de todo el sitio, ver assets/css/main.css. */
.shop-archive__title.shop-archive__title {
	padding: 4px 0;
	font-family: var(--font-display);
}

/* Descripción del término (solo categorías; core/term-description no emite
   nada si está vacía). Párrafo a ~68ch. */
.shop-archive__description {
	color: var(--color-ink-soft);
	font-size: 14px;
}
.shop-archive__description > * { max-width: 68ch; }

.shop-archive__layout {
	padding: 8px 0 40px;
	align-items: flex-start;
	gap: 28px;
}

/* --- Sidebar de filtros ---
   Va DESPUÉS de .shop-archive__content en el markup (templates/archive-product.html):
   WooCommerce marca "hay bloques de filtro en esta página" (ProductCollection::
   add_support_for_filter_blocks(), hook render_block_data) al renderizar el
   bloque product-collection, y ese hook corre en orden de documento — si los
   filtros van antes en el HTML, se renderizan vacíos porque el flag todavía no
   existe. `order: -1` la vuelve a poner visualmente primero (columna izquierda)
   sin tocar el orden real del markup. */
.shop-archive__filters {
	order: -1;
	flex: 0 0 240px;
	width: 240px;
	background: var(--color-surface);
	border: 1px solid var(--color-line);
	border-radius: var(--radius);
	padding: 18px;
	display: flex;
	flex-direction: column;
	gap: 18px;
	position: sticky;
	top: 16px;
}
/* Encabezado del panel "Filtrar" (inc/woocommerce-hooks.php,
   cohasa_filtros_panel_a_boton()): span de texto + botón coexisten en el
   HTML, ambos ya renderizados del servidor (sin JS que arme nada tras
   cargar — bug real de flash, 2026-09-25). El CSS alterna cuál de los dos
   se ve por media query en vez de montar/desmontar el botón por JS:
   display:none saca al que no corresponde del foco y del árbol de
   accesibilidad, así que en desktop (sidebar fijo, siempre expandido) no
   queda un control falso, y en mobile/tablet no queda un texto plano
   duplicado. */
.shop-archive__filters-heading-text {
	display: block;
	font-size: 15px;
	font-weight: 700;
	margin: 0;
}
.shop-archive__filters-panel-toggle {
	all: unset;
	display: none;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	/* Área táctil de 44px (el <span> de texto interno mide 15px de línea) —
	   antes el botón solo tenía el ícono de 18px de alto, así que tocar el
	   resto de su propia caja no abría el panel (bug real, 2026-09-28). */
	min-height: 44px;
	width: 100%;
	font: inherit;
	font-size: 15px;
	font-weight: 700;
	color: var(--color-ink);
	cursor: pointer;
}
.shop-archive__filters-panel-toggle:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
}
.shop-archive__filters-panel-toggle-icon {
	width: 16px;
	height: 16px;
	flex-shrink: 0;
}

/* --- Bloque woocommerce/product-filters (implementado 2026-09-23) ---
   Cada filtro (precio, calificación, atributo, categoría, disponibilidad)
   es una sección hija de .wc-block-product-filters__content; se les agrega
   el mismo separador que antes tenía el h3 "Categorías" a mano
   (:first-child sin borde, WC ya lo maneja con margin:0 — acá solo el
   borde). Selector por debajo de la especificidad de WC (":where(...)" en
   su propio CSS, especificidad 0) así que alcanza sin !important. */
/* Contención del sidebar (root cause, verificado en pantalla con
   getBoundingClientRect — el intento anterior con min-width:0 solo en
   "> *" no alcanzaba): en desktop WC muestra el contenido de los filtros
   DENTRO de .wc-block-product-filters__overlay (no de .content — ese es el
   panel del drawer móvil; ver su propio CSS, @media(min-width:601px) pone
   el overlay en position:relative/flex-grow:1 para que actúe como el
   contenido normal). Esa cadena de contenedores (overlay > overlay-wrapper
   > overlay-dialog > overlay-content) es flex/grid anidado, y CADA eslabón
   mantiene "min-width:auto" por defecto — no se encogen más abajo del
   min-content de sus hijos. El disparador real: el <input type="text"> de
   precio no tenía "width" propio, así que tomaba el ancho por defecto del
   navegador (~170px) dentro de la grilla "auto 1fr auto" del slider — eso
   solo ya empujaba el árbol completo a 365px, muy por encima de los ~280px
   disponibles del aside. min-width:0 en toda la cadena + un ancho real al
   input son las dos partes del fix; sin la segunda, la primera no alcanza
   (el contenido seguiría siendo "ancho" aunque se le permita encogerse). */
.wc-block-product-filters,
.wc-block-product-filters__overlay,
.wc-block-product-filters__overlay-wrapper,
.wc-block-product-filters__overlay-dialog,
.wc-block-product-filters__content,
.wc-block-product-filters__overlay-content,
.wc-block-product-filters__content > *,
.wc-block-product-filters__overlay-content > *,
.wc-block-product-filter-price-slider__content,
.wc-block-product-filter-price-slider__left,
.wc-block-product-filter-price-slider__right {
	min-width: 0;
}
.wc-block-product-filters__content > *,
.wc-block-product-filters__overlay-content > * {
	padding-top: 12px;
	border-top: 1px solid var(--color-line);
}
.wc-block-product-filters__content > *:first-child,
.wc-block-product-filters__overlay-content > *:first-child {
	padding-top: 0;
	border-top: none;
}
.shop-archive__filters-group h3.wp-block-heading {
	font-size: 13px;
	font-weight: 800;
	text-transform: uppercase;
	letter-spacing: 0.02em;
	margin: 0 0 10px;
}

/* Secciones colapsables (inc/woocommerce-hooks.php,
   cohasa_filtros_secciones_a_boton() reemplaza cada <h3> por este botón,
   ya con aria-expanded="false" desde el servidor — sin flash de JS) — mismo
   texto/tamaño que el h3 que reemplaza, agregando solo la flecha y el
   cursor de interactividad. El estado de colapso se deriva de
   aria-expanded, no de una clase: :has() abajo oculta todo el contenido de
   la sección salvo el propio botón cuando aria-expanded="false". */
.shop-archive__filters-toggle {
	all: unset;
	display: flex;
	align-items: center;
	justify-content: space-between;
	width: 100%;
	margin: 0 0 10px;
	font-size: 13px;
	font-weight: 800;
	text-transform: uppercase;
	letter-spacing: 0.02em;
	color: var(--color-ink);
	cursor: pointer;
}
.shop-archive__filters-toggle-icon {
	width: 16px;
	height: 16px;
	flex-shrink: 0;
	transition: transform 0.15s ease;
}
.shop-archive__filters-toggle:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
}
.shop-archive__filters-toggle[aria-expanded="false"] {
	margin-bottom: 0;
}
.shop-archive__filters-toggle[aria-expanded="false"] .shop-archive__filters-toggle-icon {
	transform: rotate(-90deg);
}
/* El botón puede ser hijo directo de la sección (Precio, Categoría…) o vivir
   un nivel más adentro, en el grupo "Header" que envuelve el heading de
   product-filter-attribute (marca/tela/norma — ver
   cohasa_bloque_filtro_atributo() en inc/woocommerce-hooks.php). En ambos
   casos se oculta cualquier hijo directo de la sección que no sea, ni
   contenga, el botón — así el grupo "Header" (que sí lo contiene) queda
   visible con solo el botón adentro. */
.wc-block-product-filters__overlay-content > :has(.shop-archive__filters-toggle[aria-expanded="false"]) > :not(.shop-archive__filters-toggle):not(:has(.shop-archive__filters-toggle)) {
	display: none;
}

/* Calificación ("X estrellas y más") — cohasa/product-filter-rating
   (inc/blocks.php), no woocommerce/product-filter-rating: ver el comentario
   largo en el render_callback de por qué se reemplazó el bloque nativo
   entero (ocultaba las calificaciones sin productos, y su SVG de estrellas
   recortado por %, sin contorno para las vacías, terminaba viéndose casi
   igual en "3 de 5" y "5 de 5" — bug real, visto en pantalla con
   getBoundingClientRect). Acá: checkboxes normales + cohasa_estrellas_html()
   (mismo dibujo que la tarjeta de producto, contorno siempre visible,
   relleno hasta el rating) — sin Interactivity API de por medio. */
.cohasa-filtro-rating__item {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 4px 0;
	cursor: pointer;
}
.cohasa-filtro-rating__item:has(.cohasa-filtro-rating__input:disabled) {
	cursor: not-allowed;
	opacity: 0.4;
}
.cohasa-filtro-rating__input:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
}
.cohasa-filtro-rating__item .product-card__stars { display: inline-flex; gap: 1px; }
.cohasa-filtro-rating__item .product-card__star { width: 16px; height: 16px; color: var(--color-line); }
.cohasa-filtro-rating__item .product-card__star--full { color: var(--color-accent-text); }
.cohasa-filtro-rating__sufijo {
	font-size: 12px;
	font-weight: 600;
	color: var(--color-ink-soft);
}

/* <fieldset> nativo de checkbox-list/chips: WC le pone "display:contents"
   (product-filter-checkbox-list-style-inline-css) para sacarlo del árbol de
   caja, pero Chrome/Firefox IGNORAN display:contents en <fieldset> (caso
   especial del spec, un fieldset nunca deja de generar su caja) — queda
   con el borde "groove" nativo del navegador, un recuadro visible flotando
   sobre la grilla de productos (verificado en pantalla: WC solo pensó el
   caso display:contents, no el caso en que el navegador no lo respeta).
   Reset explícito en vez de confiar en display:contents. */
.wc-block-product-filters fieldset {
	all: unset;
	display: block;
}

/* Checkbox list (marca, norma, tela, categoría, disponibilidad, calificación):
   WC trae su PROPIA regla para este input (product-filter-checkbox-list.css,
   selector "input[type=checkbox].wc-block-product-filter-checkbox-list__input",
   especificidad (0,2,1)) que le gana a la regla genérica de forms.css
   ("input[type=\"checkbox\"]", especificidad (0,1,1)) y lo deja
   width/height:1em con borde transparente — invisible (verificado en
   pantalla, no solo leyendo el CSS: checkbox visible en la tarjeta de
   producto, ausente acá). Se repite acá el mismo selector con clase para
   igualar la especificidad y que gane forms.css por orden de carga
   (woocommerce.css del tema se encola después que los bloques de WC). */
input[type="checkbox"].wc-block-product-filter-checkbox-list__input {
	appearance: none;
	-webkit-appearance: none;
	width: 20px;
	height: 20px;
	min-width: 20px;
	border: 1.5px solid var(--color-line-strong);
	border-radius: 5px;
	background: var(--color-surface);
}
input[type="checkbox"].wc-block-product-filter-checkbox-list__input:checked {
	border-color: var(--color-ink);
	background: var(--color-ink);
}
.wc-block-product-filter-checkbox-list__input-wrapper::before { content: none; }

.wc-block-product-filter-checkbox-list__items { display: flex; flex-direction: column; gap: 8px; }
.wc-block-product-filter-checkbox-list__label {
	display: flex;
	align-items: center;
	gap: 8px;
	font-size: 13.5px;
	color: var(--color-ink);
	cursor: pointer;
}
.wc-block-product-filter-checkbox-list__count { color: var(--color-ink-soft); font-size: 12px; }

/* Chips (talla y cualquier atributo con etiquetas cortas — ver
   inc/woocommerce-hooks.php, cohasa_atributo_usa_chips()): mismos tokens
   que .variant-chip (cohasa-core/assets/css/swatches.css) para que ambos
   selectores de talla del sitio (ficha de producto y filtro) se vean igual. */
.wc-block-product-filter-chips__item.wc-block-product-filter-chips__item {
	min-width: 40px;
	min-height: 36px;
	padding: 6px 14px;
	border: 1.5px solid var(--color-line);
	border-radius: var(--radius);
	background: var(--color-surface);
	color: var(--color-ink);
	font-family: var(--font-body);
	font-size: 13px;
	font-weight: 600;
}
.wc-block-product-filter-chips__item[aria-checked="true"] {
	border-color: var(--color-ink);
	background: var(--color-ink);
	color: var(--color-bg);
}
.wc-block-product-filter-chips__item:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
}

/* Precio: WC ya trae su propio thumb personalizado (círculo + borde, no el
   nativo del navegador), con estos 3 custom properties como único punto de
   entrada de color (product-filter-price-slider-style.css) — se fijan a la
   paleta del sitio en vez de dejar sus valores fijos (#fff/#1e1e1e, sin
   relación con el tema claro/oscuro). */
.wc-block-product-filters {
	--wc-product-filter-price-slider: var(--color-ink);
	--wc-product-filter-price-slider-handle: var(--color-surface);
	--wc-product-filter-price-slider-handle-border: var(--color-ink);
}
/* Los dos campos "$5.500"/"$22.500": el wrapper del bloque es
   ".wp-block-woocommerce-product-filter-price-slider" (prefijo estándar de
   Gutenberg), NO ".wc-block-product-filter-price-slider" a secas (esa clase
   no existe en el DOM, solo sus variantes con "__algo") — con ese selector
   mal escrito la regla nunca hacía match y el <input type="text"> quedaba
   100% con el estilo nativo del navegador (verificado en Computed Style:
   "2px inset rgb(118,118,118)", el default de Chrome sin CSS de por medio).
   ".text" alcanza solo: es una clase real y suficientemente específica acá. */
.wc-block-product-filter-price-slider__left.text input[type="text"],
.wc-block-product-filter-price-slider__right.text input[type="text"] {
	/* Variante --sm (forms.css) redefinida acá en vez de vía clase: el bloque
	   es de WooCommerce, sin markup propio donde agregar .cohasa-input--sm. */
	--input-h: 36px;
	--input-px: 10px;
	--input-py: 6px;
	--input-fs: 13px;
	/* Sin "width", el navegador le da su ancho por defecto (~170px, el
	   causante real del desborde del sidebar — ver comentario arriba de
	   .wc-block-product-filters). La columna de la grilla que lo contiene
	   es "auto" (se ajusta al contenido del item, no reparte espacio como
	   "1fr"), así que "width:100%" sería circular acá — un ancho fijo,
	   suficiente para "$22.500" con el padding de abajo, es lo que hace que
	   la columna se achique al tamaño real en vez de tomar el default del
	   navegador. */
	width: 76px;
	box-sizing: border-box;
	border: 1px solid var(--input-border);
	border-radius: var(--input-radius);
	background: var(--input-bg);
	color: var(--color-ink);
	padding: var(--input-py) var(--input-px);
	font-family: var(--font-body);
	font-size: var(--input-fs);
}
.wc-block-product-filter-price-slider__left.text input[type="text"]:hover,
.wc-block-product-filter-price-slider__right.text input[type="text"]:hover {
	border-color: var(--input-border-hover);
}
.wc-block-product-filter-price-slider__left.text input[type="text"]:focus-visible,
.wc-block-product-filter-price-slider__right.text input[type="text"]:focus-visible {
	outline: none;
	border-color: var(--input-border-hover);
	box-shadow: 0 0 0 3px var(--input-ring);
}

/* Filtros activos + botón limpiar */
.wc-block-product-filter-active .wc-block-product-filter-removable-chips__item {
	font-size: 12.5px;
	border-radius: var(--radius);
	border: 1px solid var(--color-line);
	background: var(--color-surface);
}
.wc-block-product-filter-clear-button {
	font-size: 12.5px;
	color: var(--color-ink-soft);
	text-decoration: underline;
}

/* --- Columna de contenido --- */
.shop-archive__content { flex: 1 1 0; min-width: 0; }

.shop-archive__toolbar {
	margin: 0 0 14px;
	padding: 10px 0;
	border-bottom: 1px solid var(--color-line);
	font-size: 13px;
	color: var(--color-ink-soft);
	flex-wrap: wrap;
	gap: 10px;
}
/* El select de orden ya no es nativo: assets/css/forms.css (.cohasa-select)
   vía el override woocommerce/loop/orderby.php. */
/* Variante --sm (forms.css): .cohasa-select__trigger consume --input-fs/h/px. */
.shop-archive__toolbar .cohasa-select {
	--input-h: 36px;
	--input-px: 10px;
	--input-py: 6px;
	--input-fs: 13px;
	min-width: 180px;
}

/* --- Grilla de productos: mismo ritmo que .product-grid (main.css) --- */
/* Sin !important: (0,2,1) ya supera a .wc-block-product-template.is-flex-container
   (0,2,0) y a __responsive (0,1,0) de WC Blocks — verificado contra
   product-template.css de WC 9.4.2. */
.shop-archive__collection ul.wc-block-product-template {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 14px;
	list-style: none;
	margin: 0;
	padding: 0;
}
@media (min-width: 640px) {
	.shop-archive__collection ul.wc-block-product-template { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 1180px) {
	.shop-archive__collection ul.wc-block-product-template { grid-template-columns: repeat(4, 1fr); gap: 20px; }
}

/* Tarjeta: el contenido real de cada li.wc-block-product ya es .product-card
   (cohasa/product-card, ver inc/blocks.php + cohasa_render_product_card en
   inc/template-tags.php) — MISMO markup que categoría, búsqueda, home y
   relacionados. .product-card ya trae su propio fondo/borde/radius/hover
   (assets/css/main.css); el <li> solo necesita ser un item de grilla neutro,
   sin repetir esa apariencia (antes quedaba una tarjeta dentro de otra). */
.shop-archive__collection li.wc-block-product {
	list-style: none;
	padding: 0;
}

/* El "pill" y el activo ya vienen de .wp-block-query-pagination (ver
   assets/css/pagination.css) — acá solo el respiro extra bajo la grilla. */
.shop-archive__pagination {
	margin-top: 28px;
}

/* --- Responsive: la sidebar de filtros baja arriba de la grilla en móvil --- */
@media (max-width: 899px) {
	.shop-archive__layout {
		flex-direction: column;
	}
	.shop-archive__filters {
		width: 100%;
		flex: 1 1 auto;
		position: static;
	}
}

/* Panel colapsable completo en mobile Y tablet (bajo 900px), no solo
   tablet: WC trae el filtro como drawer/modal nativo bajo 600px (botón
   "Filtrar productos" que abre un overlay a pantalla completa vía
   Interactivity API) — visualmente inconsistente con el panel inline
   compacto de tablet y más pesado de usar (bug real, reportado 2026-09-24:
   "Filtrar" + "Filtrar productos" quedaban como dos filas sueltas, sin
   estilo, mucho más alto que el toggle de tablet). Se anula el modal de WC
   y se fuerza el mismo layout "inline" que WC ya aplica solo desde 601px
   (ver su propio CSS, @media(min-width:601px) sobre .wc-block-product-
   filters__overlay*) — pero sin el media query, así que aplica también
   bajo 600px. Selectores sin prefijo, especificidad 0,1,0, le ganan sin
   !important a los :where(...) (especificidad 0) de WC en cualquier ancho. */
.wc-block-product-filters,
.wc-block-product-filters.is-overlay-opened {
	display: flex;
}
.wc-block-product-filters .wc-block-product-filters__open-overlay,
.wc-block-product-filters .wc-block-product-filters__overlay-footer,
.wc-block-product-filters .wc-block-product-filters__overlay-header {
	display: none;
}
.wc-block-product-filters .wc-block-product-filters__overlay {
	background: inherit;
	color: inherit;
	flex-grow: 1;
	inset: 0;
	pointer-events: auto;
	position: relative;
	transition: none;
}
.wc-block-product-filters .wc-block-product-filters__overlay-wrapper {
	background: inherit;
	color: inherit;
	height: auto;
	width: auto;
}
.wc-block-product-filters .wc-block-product-filters__overlay-dialog {
	background: inherit;
	color: inherit;
	position: relative;
	transform: none;
}
.wc-block-product-filters .wc-block-product-filters__overlay-content {
	background: inherit;
	color: inherit;
	flex-grow: 1;
	overflow: visible;
	padding: 0;
}

/* Bajo 900px: el heading vuelve botón (texto plano oculto) y el panel
   colapsa cuando aria-expanded="false" — mismo default que el servidor ya
   entrega (ver cohasa_filtros_panel_a_boton()), sin sessionStorage: cada
   carga nueva parte colapsada. Desde 900px es sidebar lateral fijo, siempre
   expandido, con el botón fuera del árbol (regla de arriba). */
@media (max-width: 899px) {
	.shop-archive__filters-heading-text {
		display: none;
	}
	.shop-archive__filters-panel-toggle {
		display: flex;
	}
	.shop-archive__filters:has(.shop-archive__filters-panel-toggle[aria-expanded="false"]) .shop-archive__filters-group {
		display: none;
	}
}

/* --- Marginales: registro, descargas, métodos de pago (heredan
   .woocommerce form / table.shop_table / botones genéricos, ya cubiertos
   arriba) — acá solo el remate que falta. --- */
.woocommerce-privacy-policy-text {
	font-size: 12.5px;
	color: var(--color-ink-soft);
	margin-top: 12px;
}
.woocommerce-MyAccount-downloads table.shop_table td,
.woocommerce-MyAccount-paymentMethods table.shop_table td {
	vertical-align: middle;
}
.woocommerce-PaymentMethod.woocommerce-PaymentMethod--default .woocommerce-PaymentMethod-token {
	font-weight: 700;
}
.woocommerce-PaymentMethod-actions .button {
	min-height: 36px;
	padding: 0 14px;
	font-size: 13px;
}

/* Select2 (País/Región del checkout clásico y de Mi cuenta > Direcciones —
   único selector de esta página que no pasa por assets/js/select.js /
   .cohasa-select, es un <select> normal). Sin esto queda con el blanco/negro
   por defecto del navegador: invisible en tema oscuro. Mismos tokens que
   .cohasa-select__trigger (main.css) para que no se note el salto de
   componente. */
.select2-container--default .select2-selection--single {
	background: var(--input-bg);
	border: 1px solid var(--input-border);
	min-height: var(--input-h);
	display: flex;
	align-items: center;
	font-size: var(--input-fs);
}
.select2-selection__rendered {
	color: var(--color-ink) !important;
}
.select2-selection__arrow b {
	border-color: var(--color-ink-soft) transparent transparent transparent !important;
}
.select2-dropdown {
	background: var(--color-surface);
	border-color: var(--input-border);
}
.select2-container--default .select2-results__option--highlighted[aria-selected] {
	background: var(--color-accent);
	color: var(--color-accent-ink);
}
.select2-search--dropdown .select2-search__field {
	background: var(--input-bg);
	border-color: var(--input-border);
	color: var(--color-ink);
}

/* --- Radius global: elementos por defecto de WordPress/WooCommerce --- */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
select,
textarea,
.select2-container--default .select2-selection--single,
.select2-dropdown,
.wp-block-search__input,
.wp-block-search__button,
.wp-block-button__link,
.button,
.woocommerce-message,
.woocommerce-info,
.woocommerce-error,
.wc-block-components-notice-banner,
.wc-block-components-product-image,
.wc-block-grid__product-image,
.woocommerce-tabs .panel,
.woocommerce table.shop_table,
.wp-block-table table,
.wp-block-image img,
.wp-block-cover,
.wp-block-group.has-background,
.wp-block-quote,
.wp-block-code,
.wp-block-preformatted,
.wp-block-details,
.wc-block-components-order-summary,
.wc-block-components-panel,
.wc-block-components-totals-coupon,
.wc-block-components-radio-control__option,
.wc-block-components-checkbox__mark,
.wc-block-components-quantity-selector,
.woocommerce-product-gallery__image img,
.woocommerce-MyAccount-navigation a,
.woocommerce-checkout-review-order,
.product-card__media {
	border-radius: var(--radius);
}
.product-card__media,
.wc-block-components-product-image,
.wc-block-grid__product-image {
	overflow: hidden;
}
.wc-block-components-order-summary img,
.wc-block-cart-item__image img,
.wc-block-components-product-image img,
.attachment-woocommerce_thumbnail {
	border-radius: var(--radius);
}

/* ==========================================================================
   Ficha de producto — ficha técnica, precio por volumen (sin matriz de
   tallas). Ver inc/especificaciones.php.
   ========================================================================== */

.cohasa-pdp-seccion {
	margin: 32px 0;
}
.cohasa-pdp-seccion h2 {
	font-family: var(--font-display);
	font-size: 19px;
	margin: 0 0 12px;
}

.spec-table {
	width: 100%;
	border-collapse: collapse;
	/* --color-line-strong (3:1, WCAG 1.4.11), no --color-line (1.24:1): el
	   borde es lo único que marca la caja, mismo criterio que chips/campos. */
	border: 1px solid var(--color-line-strong);
	border-radius: var(--radius);
	overflow: hidden;
	background: var(--color-surface);
	/* --color-surface (blanco) es intencionalmente muy cercano a --color-bg
	   (design.md) — la separación real la da la sombra, mismo patrón que
	   .product-card (main.css), no el fill. */
	box-shadow: var(--shadow-card);
}
.spec-table tr:nth-child(even) {
	background: var(--color-field);
}
.spec-table th,
.spec-table td {
	padding: 10px 16px;
	text-align: left;
	font-size: 14px;
	border-bottom: 1px solid var(--color-line);
}
.spec-table tr:last-child th,
.spec-table tr:last-child td {
	border-bottom: 0;
}
.spec-table th {
	font-weight: 600;
	color: var(--color-ink-soft);
	width: 40%;
}

/* En móvil, etiqueta/valor apilados en vez de dos columnas angostas
   (mismo criterio mobile-first del resto del archivo). */
@media (max-width: 639px) {
	.spec-table tr {
		display: flex;
		flex-direction: column;
	}
	.spec-table th,
	.spec-table td {
		width: auto;
		padding: 8px 16px 0;
		border-bottom: 0;
	}
	.spec-table td {
		padding-bottom: 10px;
	}
}

.cohasa-tramos-precio {
	margin: 16px 0;
	padding: 14px 16px;
	background: var(--color-surface);
	border: 1px solid var(--color-line-strong); /* 3:1 WCAG 1.4.11, ver .spec-table */
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-card);
}
.cohasa-tramos-precio__titulo {
	margin: 0 0 8px;
	font-size: 13.5px;
	font-weight: 600;
	color: var(--color-ink-soft);
}
.cohasa-tramos-precio-tabla {
	width: 100%;
	border-collapse: collapse;
}
.cohasa-tramos-precio-tabla td {
	padding: 6px 8px;
	border-bottom: 1px solid var(--color-line-strong);
}
.cohasa-tramos-precio-tabla td:last-child {
	color: var(--color-brand-ink, var(--color-ink-soft));
	font-weight: 600;
	text-align: right;
}

/* Fila "ahorras Z%" bajo la lista de piezas del kit (grouped.php,
   woocommerce_grouped_product_list_after) — mismo patrón de tokens que
   .cohasa-tramos-precio, sin marco propio porque va dentro del formulario
   del kit, que ya tiene su propio contenedor. */
.cohasa-kit-ahorro {
	display: flex;
	flex-wrap: wrap;
	gap: 6px 16px;
	margin: 12px 0 0;
	font-size: 14px;
	color: var(--color-ink-soft);
}
.cohasa-kit-ahorro__kit {
	font-weight: 600;
	color: var(--color-ink);
}
.cohasa-kit-ahorro__pct {
	color: var(--color-brand-ink, var(--color-ink));
	font-weight: 600;
}

/* --- Ficha de producto: secciones de la ficha (Descripción, Ficha técnica,
   Valoraciones) --------------------------------------------------------
   cohasa_block_product_tabs() (inc/blocks.php) ya no arma la nav
   <ul class="tabs"> ni los paneles ocultos del core: cada tab de
   woocommerce_product_tabs se apila siempre visible en
   <section class="cohasa-pdp-seccion"> — el espaciado entre secciones ya
   lo da .cohasa-pdp-seccion{margin:32px 0} (arriba), que colapsa entre
   hermanos igual que antes con .cohasa-specs. */
.woocommerce table.woocommerce-product-attributes {
	width: 100%;
	border-collapse: collapse;
}
.woocommerce table.woocommerce-product-attributes th,
.woocommerce table.woocommerce-product-attributes td {
	padding: 12px 0;
	text-align: left;
	vertical-align: baseline;
	border-bottom: 1px solid var(--color-line);
}
.woocommerce table.woocommerce-product-attributes tr:last-child th,
.woocommerce table.woocommerce-product-attributes tr:last-child td {
	border-bottom: 0;
}
.woocommerce table.woocommerce-product-attributes th {
	width: 30%;
	font-size: 14px;
	font-weight: 600;
}
.woocommerce table.woocommerce-product-attributes td p {
	margin: 0;
}

/* SKU + categoría + etiquetas: dato secundario, no texto de cuerpo, en una
   sola voz. .pdp__summary-col (no .summary): cohasa/product-meta ahora vive
   ahí directo, sin wrapper de tarjeta. Se apunta a .product_meta, el <div>
   que imprime woocommerce/single-product/meta.php (span.sku_wrapper +
   span.posted_in + span.tagged_as) — antes (bloque nativo
   wp:woocommerce/product-meta) esos tres venían en bloques separados
   agrupados con un wp:group propio; ahora ya salen juntos en un solo
   contenedor del template de WooCommerce, sin necesidad de ese grupo. */
.pdp__summary-col .wp-block-cohasa-product-meta .product_meta {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 4px 20px;
	margin-top: 12px;
	font-size: 13px;
	color: var(--color-ink-soft);
}
.pdp__summary-col .wp-block-cohasa-product-meta .product_meta a {
	color: var(--color-ink-soft);
}

/* Sección de reseñas (#review_form, .cohasa-reviews, #reviews): movida a
   assets/css/producto.css — solo existe en la ficha de producto. */

/* assets/css/quick-view.css */
/*
 * Vista rápida: botón overlay en la tarjeta de producto + modal accesible.
 * Reusa tokens de assets/css/tokens.css (radius, colores, tipografía,
 * duraciones) — nada de color hardcodeado, respeta el tema claro/oscuro.
 */

/* --- Acciones flotantes sobre la imagen de la tarjeta: Vista rápida +
   Guardar en lista, apiladas en columna en la esquina superior derecha
   (mismo criterio de wrapper que .product-card__badges a la izquierda, ver
   assets/css/main.css — evita calcular offsets a mano entre botones). --- */
.product-card {
	position: relative;
}
.product-card__actions {
	position: absolute;
	top: 8px;
	right: 8px;
	z-index: 2;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 6px;
}
.product-card__quick-view {
	display: flex;
	align-items: center;
	gap: 6px;
	padding: 7px 12px;
	border: none;
	border-radius: var(--radius);
	background: var(--color-surface);
	color: var(--color-ink);
	font-family: var(--font-body);
	font-size: 12px;
	font-weight: 600;
	cursor: pointer;
	box-shadow: var(--shadow-sm);
}
.product-card__quick-view:hover {
	background: var(--color-field);
}
.product-card__quick-view:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
}

/* Solo ícono (ver inc/listas.php, cohasa_boton_lista_card) — mismo tamaño
   que .product-card__variantes para que ambas columnas de chips combinen. */
.product-card__list {
	display: grid;
	place-items: center;
	width: 26px;
	height: 26px;
	border: none;
	border-radius: var(--radius);
	background: var(--color-surface);
	color: var(--color-ink);
	cursor: pointer;
	box-shadow: var(--shadow-sm);
}
.product-card__list:hover {
	background: var(--color-field);
}
.product-card__list:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
}

/* Siempre visible en móvil (no hay "hover"); en escritorio solo al pasar
   el mouse o al enfocar la tarjeta por teclado — breakpoint estándar del tema. */
@media (min-width: 900px) {
	.product-card__actions {
		opacity: 0;
		transform: translateY(-4px);
		transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
	}
	.product-card:hover .product-card__actions,
	.product-card:focus-within .product-card__actions {
		opacity: 1;
		transform: translateY(0);
	}
}

@media (prefers-reduced-motion: reduce) {
	.product-card__actions {
		transition: none;
	}
}

/* --- Modal --- */
.quick-view-overlay {
	position: fixed;
	inset: 0;
	z-index: 2000;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--gutter);
	background: var(--color-scrim);
}
.quick-view-overlay[hidden] {
	display: none;
}

.quick-view-modal {
	position: relative;
	width: 100%;
	/* Más ancho que una tarjeta de detalle angosta, pero sin llegar a --maxw
	   (1280px, el contenedor general de página) para que siga leyéndose como
	   modal y no como una vista a pantalla completa. */
	max-width: 1200px;
	max-height: calc(100vh - 2 * var(--gutter));
	max-height: calc(100dvh - 2 * var(--gutter));
	overflow-y: auto;
	background: var(--color-surface);
	color: var(--color-ink);
	border-radius: var(--radius-lg);
	padding: 24px;
	box-shadow: 0 8px 20px -12px rgb(13 17 23 / 0.25);
}
.quick-view-modal:focus {
	outline: none;
}

.quick-view-modal__close {
	position: absolute;
	top: 14px;
	right: 14px;
	z-index: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	border: 1px solid var(--color-line);
	border-radius: 999px;
	background: var(--color-surface);
	color: var(--color-ink);
	cursor: pointer;
}
.quick-view-modal__close:hover {
	background: var(--color-field);
}
.quick-view-modal__close:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
}

.quick-view-modal__error {
	padding: 40px 0;
	text-align: center;
	color: var(--color-error);
}

/* --- Skeleton de carga --- */
.quick-view-modal__skeleton {
	display: grid;
	gap: 12px;
	padding-top: 4px;
}
.qv-skel {
	border-radius: var(--radius);
	background: var(--color-field);
	position: relative;
	overflow: hidden;
}
.qv-skel::after {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(90deg, transparent, rgb(255 255 255 / 0.35), transparent);
	animation: quick-view-shimmer 1.3s var(--ease-out) infinite;
}
.qv-skel--img { aspect-ratio: 1 / 1; max-width: 360px; }
.qv-skel--line { height: 16px; max-width: 70%; }
.qv-skel--short { max-width: 40%; }
.qv-skel--btn { height: 44px; max-width: 200px; margin-top: 8px; }

@keyframes quick-view-shimmer {
	100% { transform: translateX(100%); }
}
@media (prefers-reduced-motion: reduce) {
	.qv-skel::after { animation: none; }
}

/* --- Contenido del producto --- */
.quick-view .quick-view__gallery,
.quick-view .quick-view__summary {
	min-width: 0;
}
@media (min-width: 640px) {
	.quick-view {
		display: grid;
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
		gap: 28px;
	}
}

.quick-view__main-image {
	position: relative;
	aspect-ratio: 1 / 1;
	border-radius: var(--radius);
	overflow: hidden;
	background: var(--color-field);
}
.quick-view__main-image img { width: 100%; height: 100%; object-fit: contain; }
.quick-view__placeholder { position: absolute; inset: 0; display: grid; place-items: center; color: var(--color-ink-soft); }

.quick-view__thumbs {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin-top: 10px;
}
.quick-view__thumb {
	width: 56px;
	height: 56px;
	padding: 0;
	border: 1px solid var(--color-line);
	border-radius: var(--radius);
	overflow: hidden;
	background: var(--color-field);
	cursor: pointer;
}
.quick-view__thumb:focus-visible {
	outline: none;
	box-shadow: var(--focus-ring);
}
.quick-view__thumb.is-active {
	border-color: var(--color-accent-text);
}
.quick-view__thumb img { width: 100%; height: 100%; object-fit: cover; }

.quick-view__title {
	font-family: var(--font-display);
	font-size: 22px;
	line-height: 1.2;
	margin: 0 0 6px;
	padding-right: 40px; /* espacio para el botón de cerrar en columna única */
}
.quick-view__sku {
	font-size: 12.5px;
	color: var(--color-ink-soft);
	margin: 0 0 10px;
}
.quick-view__price {
	font-family: var(--font-mono);
	font-size: 22px;
	font-weight: 700;
	margin-bottom: 8px;
}
.quick-view__price del { color: var(--color-ink-soft); font-weight: 500; font-size: 16px; margin-right: 8px; text-decoration: line-through; }
.quick-view__price ins { text-decoration: none; }

.quick-view__excerpt {
	font-size: 14px;
	color: var(--color-ink-soft);
	margin: 10px 0 16px;
}
.quick-view__excerpt p:first-child { margin-top: 0; }

/* Cantidad y «Añadir al carrito» eran inline dentro de un form.cart en bloque (pegados a ~5px por el espacio en
   blanco del HTML); mismo gap que el formulario de la ficha. Lo que no sea cantidad/botón (tabla de variaciones,
   envoltorio de variación) ocupa su propia fila. */
.quick-view form.cart,
.quick-view .woocommerce-variation-add-to-cart {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px;
}
.quick-view form.cart > :not(.quantity):not(.single_add_to_cart_button) {
	flex: 1 1 100%;
}

.quick-view .single_add_to_cart_button.is-loading {
	opacity: 0.6;
	cursor: progress;
}

.quick-view__permalink {
	display: inline-block;
	margin-top: 14px;
	font-size: 13px;
	color: var(--color-ink-soft);
	text-decoration: underline;
}

/* assets/css/carrito.css */
/*
 * Carrito 100% propio: drawer lateral (cohasa/cart-drawer) + página
 * /carrito/ (woocommerce/cart/*.php). Reusa tokens de tokens.css — nada de
 * color hardcodeado, respeta el tema claro/oscuro. Breakpoints mobile-first
 * literales (var() no funciona en @media): base <640 · sm ≥640 · md ≥900 · lg ≥1180.
 */

/* ============ Campos propios (cupón, nota) ============ */
/* Componente de campo unificado (--input-*, forms.css) — mismo look que el
   select y el resto de campos del sitio. Foco: anillo neutro con
   :focus-within en vez de --focus-ring (design.md, "Foco visible" — el
   doble aro pesa en campos anchos). */
.cart-drawer__coupon-form,
.cart-drawer__note-form,
.cart-page__coupon {
	border-radius: var(--input-radius);
}
.cart-drawer__coupon-form:focus-within,
.cart-drawer__note-form:focus-within,
.cart-page__coupon:focus-within {
	box-shadow: 0 0 0 3px var(--input-ring);
	border-radius: var(--input-radius);
}
.cart-drawer input[type="text"]:not(.cohasa-qty__input),
.cart-drawer textarea,
.cart-page__coupon input[type="text"]:not(.cohasa-qty__input) {
	min-height: var(--input-h);
	padding: var(--input-py) var(--input-px);
	background: var(--input-bg);
	color: var(--color-ink);
	border: 1px solid var(--input-border);
	border-radius: var(--input-radius);
	font: inherit;
	font-size: var(--input-fs);
}
.cart-drawer textarea { min-height: 64px; resize: vertical; }
.cart-drawer input[type="text"]:not(.cohasa-qty__input):hover,
.cart-drawer textarea:hover,
.cart-page__coupon input[type="text"]:not(.cohasa-qty__input):hover {
	border-color: var(--input-border-hover);
}
.cart-drawer input[type="text"]:not(.cohasa-qty__input):focus,
.cart-drawer textarea:focus,
.cart-page__coupon input[type="text"]:not(.cohasa-qty__input):focus {
	outline: none;
	border-color: var(--input-border-hover);
}

/* ============ Drawer ============ */

.cart-drawer-overlay {
	position: fixed;
	inset: 0;
	z-index: 2000;
	background: var(--color-scrim);
}
.cart-drawer-overlay[hidden] { display: none; }

.cart-drawer {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	width: 100%;
	max-width: 420px;
	display: flex;
	flex-direction: column;
	background: var(--color-surface);
	border-top-left-radius: var(--radius-lg);
	border-bottom-left-radius: var(--radius-lg);
	box-shadow: var(--shadow-float);
	transform: translateX(0);
	animation: cart-drawer-in var(--dur-base) var(--ease-out);
}
@keyframes cart-drawer-in {
	from { transform: translateX(100%); }
	to { transform: translateX(0); }
}
@media (prefers-reduced-motion: reduce) {
	.cart-drawer { animation: none; }
}
.cart-drawer:focus-visible,
.cart-drawer:focus { outline: none; }

.cart-drawer__header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding: 20px;
	border-bottom: 1px solid var(--color-line);
}
.cart-drawer__title {
	font-family: var(--font-display);
	font-size: 19px;
	margin: 0;
}

.cart-drawer__empty {
	flex: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	text-align: center;
	gap: 14px;
	padding: 24px 20px;
}
.cart-drawer__empty svg {
	width: 40px;
	height: 40px;
	color: var(--color-ink-soft);
}

.cart-drawer__body {
	flex: 1;
	overflow-y: auto;
	padding: 4px 20px 12px;
}

.cart-drawer__footer {
	border-top: 1px solid var(--color-line);
	padding: 16px 20px 20px;
	display: flex;
	flex-direction: column;
	gap: 10px;
}
.cart-drawer__subtotal {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	font-size: 15px;
}
.cart-drawer__subtotal strong {
	font-family: var(--font-mono);
	font-size: 18px;
}

.cart-drawer__extra {
	border-top: 1px solid var(--color-line);
	padding: 12px 0;
}
.cart-drawer__extra summary {
	cursor: pointer;
	font-weight: 600;
	font-size: 14px;
	list-style: none;
}
.cart-drawer__extra summary::-webkit-details-marker { display: none; }
.cart-drawer__extra summary::before {
	content: "+ ";
	color: var(--color-ink-soft);
}
.cart-drawer__extra[open] summary::before { content: "− "; }
.cart-drawer__coupon-form,
.cart-drawer__note-form {
	display: flex;
	gap: 8px;
	margin-top: 10px;
}
.cart-drawer__coupon-form input,
.cart-drawer__note-form textarea {
	flex: 1;
}
.cart-drawer__coupons {
	list-style: none;
	margin: 10px 0 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 6px;
	font-size: 13px;
}
.cart-drawer__coupons li {
	display: flex;
	align-items: center;
	justify-content: space-between;
	background: var(--color-field);
	border-radius: var(--radius);
	padding: 6px 10px;
}
.cart-drawer__coupon-remove {
	background: none;
	border: none;
	color: var(--color-ink-soft);
	text-decoration: underline;
	cursor: pointer;
	padding: 6px;
}

/* ============ Barra de envío gratis (drawer y página) ============ */

.cart-shipping-bar {
	padding: 14px 20px;
	border-bottom: 1px solid var(--color-line);
}
.cart-page .cart-shipping-bar { padding: 0 0 18px; border-bottom: none; }
.cart-shipping-bar__track {
	height: 6px;
	border-radius: 999px;
	background: var(--color-field);
	overflow: hidden;
}
.cart-shipping-bar__fill {
	height: 100%;
	background: var(--color-accent);
	transition: width var(--dur-base) var(--ease-out);
}
@media (prefers-reduced-motion: reduce) {
	.cart-shipping-bar__fill { transition: none; }
}
.cart-shipping-bar__label {
	display: flex;
	align-items: center;
	gap: 6px;
	margin: 8px 0 0;
	font-size: 13px;
	color: var(--color-ink-soft);
}
.cart-shipping-bar.is-complete .cart-shipping-bar__label {
	color: var(--color-accent-text);
}

/* ============ Línea de carrito (compartida drawer + página) ============ */

.cart-drawer__lines,
.cart-page__lines {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
}
/* Línea en estilo recibo — mismo tratamiento que .order-recibo__item de "Tu
   pedido" (checkout.css): separador punteado, miniatura de 52px con
   insignia de cantidad superpuesta, nota de tramo en caja. */
.cart-line {
	display: flex;
	align-items: flex-start;
	gap: 12px;
	padding: 16px 0;
	border-bottom: 1px dashed var(--color-line-strong);
}
.cart-line:last-child { border-bottom: none; }
/* Checkbox re-estilado por forms.css (appearance:none) — acá solo su
   posición dentro de la línea. */
.cart-line__select { flex-shrink: 0; margin-top: 22px; }
.cart-line__thumb {
	position: relative;
	flex-shrink: 0;
	width: 52px;
	height: 52px;
	border: 1px solid var(--color-line);
	border-radius: var(--radius);
	background: var(--color-field);
}
.cart-line__thumb img {
	width: 100%;
	height: 100%;
	border-radius: inherit;
	object-fit: contain;
}
.cart-line__body {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 4px;
}
.cart-line__name {
	font-weight: 600;
	font-size: 14px;
	color: var(--color-ink);
	text-decoration: none;
}
.cart-line__name:hover { text-decoration: underline; }
/* Nota de tramo (dl.variation de wc_get_formatted_cart_item_data) — misma
   caja "oportunidad" que .order-recibo__nota, con el ícono tag. */
.cart-line__meta {
	display: flex;
	gap: 6px;
	align-items: flex-start;
	margin-top: 2px;
	padding: 6px 10px;
	border-radius: 8px;
	background: var(--color-field);
	font-size: 12px;
	color: var(--color-ink-soft);
}
.cart-line__meta svg {
	flex-shrink: 0;
	margin-top: 1px;
	color: var(--color-accent-text);
}
.cart-line__meta dl,
.cart-line__meta dd,
.cart-line__meta p { margin: 0; display: inline; }
.cart-line__meta dt { display: inline; font-weight: 600; }
.cart-line__unit-price {
	margin: 0;
	font-family: var(--font-mono);
	font-size: 13px;
	color: var(--color-ink-soft);
}
.cart-line__row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	margin-top: 4px;
}
.cart-line__subtotal {
	font-family: var(--font-mono);
	font-weight: 600;
	font-size: 14px;
	white-space: nowrap;
}
.cart-line__acciones {
	display: flex;
	align-items: center;
	gap: 12px;
	margin-top: 2px;
}
.cart-line__remove,
.cart-line__save-later {
	background: none;
	border: none;
	color: var(--color-ink-soft);
	font-size: 12px;
	text-decoration: underline;
	cursor: pointer;
	padding: 4px 0;
}
.cart-line__remove:hover { color: var(--color-error); }
.cart-line__save-later:hover { color: var(--color-ink); }

/* ============ Barra "Guardar para después (N)" (selección múltiple) ============ */
.cart-bulk-bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	margin-bottom: 12px;
	padding: 8px 12px;
	background: var(--color-field);
	border-radius: var(--radius);
	font-size: 13px;
	color: var(--color-ink-soft);
}
.cart-bulk-bar[hidden] { display: none; }

/* ============ Toast de deshacer ============ */

.cart-toast {
	position: fixed;
	left: 50%;
	bottom: 24px;
	transform: translateX(-50%);
	z-index: 2100;
	display: flex;
	align-items: center;
	gap: 16px;
	background: var(--color-ink);
	color: var(--color-bg);
	padding: 12px 18px;
	border-radius: var(--radius);
	box-shadow: var(--shadow-float);
	font-size: 14px;
}
@media (prefers-color-scheme: dark) {
	:root:not([data-cohasa-theme="light"]) .cart-toast { background: var(--color-surface); color: var(--color-ink); border: 1px solid var(--color-line); }
}
:root[data-cohasa-theme="dark"] .cart-toast { background: var(--color-surface); color: var(--color-ink); border: 1px solid var(--color-line); }
.cart-toast__undo {
	background: none;
	border: none;
	color: var(--color-accent-text);
	font-weight: 700;
	cursor: pointer;
	padding: 4px;
}
/* "Ver mis listas" del toast de "Guardado para después" (solo con sesión). */
.cart-toast__link {
	color: var(--color-accent-text);
	font-weight: 700;
	text-decoration: underline;
	white-space: nowrap;
}

/* ============ Página /carrito/ ============ */

/* Método de envío (wc_cart_totals_shipping_html(), template cart-shipping.php
   de WooCommerce): "Resumen del pedido" de /carrito/ y /checkout/ usan la
   MISMA lista nativa — antes solo tenía estilo en checkout.css, así que en
   el carrito salía sin tarjeta ni gap, como una lista HTML sin re-estilar
   (bug real, viñeta de navegador incluida). El radio en sí ya lo cubre
   forms.css (input[type=radio], genérico); acá solo la fila/tarjeta. */
.woocommerce-shipping-methods {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 8px;
}
.woocommerce-shipping-methods li {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 10px 12px;
	border: 1px solid var(--color-line);
	border-radius: var(--radius);
}
.woocommerce-shipping-methods label { cursor: pointer; }
.woocommerce-shipping-destination {
	margin: 10px 0 0;
	font-size: 13px;
	color: var(--color-ink-soft);
}

.cart-page__empty { padding: 48px 0; }
.cart-empty {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: 10px;
	padding: 40px 16px;
	color: var(--color-ink-soft);
}
.cart-empty__title { font-family: var(--font-display); color: var(--color-ink); margin: 4px 0 0; }
.cart-empty__text { margin: 0 0 12px; max-width: 40ch; }

.cart-page__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 32px;
	padding: 24px 0 48px;
}
@media (min-width: 900px) {
	.cart-page__grid { grid-template-columns: 1fr 360px; align-items: start; }
}

/* Tarjeta que envuelve la barra de envío gratis + líneas + acciones —
   mismo tratamiento de superficie que .checkout-summary/.cart-summary
   (border-line-strong, radius-lg, shadow-card), para que /carrito/ luzca
   igual de "tarjeta" que el checkout. */
.cart-page__main-card {
	background: var(--color-surface);
	border: 1px solid var(--color-line-strong); /* 3:1 WCAG 1.4.11, ver .spec-table */
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-card);
	padding: 20px;
}
.cart-page__main-card .cart-shipping-bar { padding: 0 0 18px; }

.cart-page__form { display: block; }
.cart-page__actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 12px;
	padding-top: 16px;
}
.cart-page__coupon {
	display: flex;
	gap: 8px;
	flex: 1;
	min-width: 220px;
}
.cart-page__coupon input { flex: 1; }
.cart-page__coupons {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	gap: 8px;
	flex-wrap: wrap;
}
.cart-page__coupons li {
	display: flex;
	align-items: center;
	gap: 8px;
	background: var(--color-field);
	border-radius: var(--radius);
	padding: 6px 10px;
	font-size: 13px;
}
.cart-page__coupon-remove {
	background: none;
	border: none;
	color: var(--color-ink-soft);
	text-decoration: underline;
	cursor: pointer;
}

.cart-page__cross-sells { margin-top: 40px; }

.cart-summary {
	background: var(--color-surface);
	border: 1px solid var(--color-line-strong); /* 3:1 WCAG 1.4.11, ver .spec-table */
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-card);
	padding: 20px;
}
@media (min-width: 900px) {
	.cart-summary { position: sticky; top: 24px; }
}
.cart-summary__title {
	font-family: var(--font-display);
	font-size: 17px;
	margin: 0 0 14px;
}
.cart-summary__proceed { margin-top: 16px; }
.cart-summary__proceed .checkout-button,
.cart-summary__proceed a.button {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
}

/* Tabla de totales, compartida entre "Tu pedido" (checkout/review-order.php)
   y "Resumen del pedido" (cart/cart-totals.php) — MISMO markup
   (<table class="order-recibo__totales">) en las dos plantillas, para que
   luzcan idénticas. wc_cart_totals_shipping_html() (WooCommerce core)
   imprime <tr>, por eso la raíz tiene que ser <table>, no <dl>: un <tr>
   fuera de una tabla lo descarta el parser del navegador. No cambiar acá sin
   revisar las dos plantillas. */
.order-recibo__totales {
	width: 100%;
	border-collapse: collapse;
	margin-top: 4px;
}
.order-recibo__totales tbody { display: grid; gap: 10px; padding-top: 14px; }
.order-recibo__totales tr {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: 12px;
}
.order-recibo__totales th,
.order-recibo__totales td {
	padding: 0;
	border: 0;
	font-size: 14px;
	text-align: left;
}
.order-recibo__totales th { font-weight: 400; color: var(--color-ink-soft); }
.order-recibo__totales td { text-align: right; }
/* Envío: etiqueta arriba, tarjetas de método a ancho completo. */
.order-recibo__totales tr.woocommerce-shipping-totals {
	flex-direction: column;
	align-items: stretch;
	gap: 8px;
}
.order-recibo__totales tr.woocommerce-shipping-totals td { text-align: left; }
.order-recibo__totales .woocommerce-shipping-methods label { flex: 1; }
/* Sin redundancia: con un único método de envío (input hidden, sin radio) la
   tarjeta ya dice "Envío …" — el título "Envío" de arriba repite lo mismo. */
.order-recibo__totales tr.woocommerce-shipping-totals:has(input[type="hidden"].shipping_method) th { display: none; }
/* Total: bloque navy de marca, fijo en los dos temas (--color-hero-*). */
.order-recibo__totales tr.order-total {
	align-items: center;
	margin-top: 6px;
	padding: 16px;
	border: 1px solid var(--color-hero-border);
	border-radius: var(--radius);
	background: var(--color-hero-bg);
	color: var(--color-hero-ink);
}
.order-recibo__totales tr.order-total th {
	font-family: var(--font-display);
	font-size: 16px;
	font-weight: 700;
	color: inherit;
}
.order-recibo__totales tr.order-total td {
	font-size: 24px;
	font-weight: 700;
}
.order-recibo__totales tr.order-total small.includes_tax {
	display: block;
	font-size: 12px;
	font-weight: 400;
	color: var(--color-hero-ink-soft);
}

/* Variante compacta del stepper [−] 1 [+] (.cohasa-qty, definido en
   assets/css/woocommerce.css — componente COMPARTIDO con ficha de
   producto, agrupados, quick view y matriz de tallas). Scopeada por
   selector descendiente a la línea de carrito/drawer: no se toca la regla
   global ni woocommerce/global/quantity-input.php, así el resto de usos
   del componente no cambia. */
/* div.quantity.cohasa-qty + <li>: hay que igualar/superar la especificidad de
   `.woocommerce div.quantity.cohasa-qty` (woocommerce.css, 0,3,1) o el
   min-height:44px global le gana a la variante. */
.cart-page__lines li div.quantity.cohasa-qty,
.cart-drawer__lines li div.quantity.cohasa-qty {
	min-height: 32px;
}
.cart-page__lines .cohasa-qty__btn,
.cart-drawer__lines .cohasa-qty__btn {
	min-width: 32px;
	font-size: 16px;
}
.cart-page__lines .cohasa-qty__input,
.cart-drawer__lines .cohasa-qty__input {
	width: 36px;
	font-size: 14px;
}

