/**
 * CP-FICHA-V2 · COMPONENTES COMPARTIDOS de la ficha (G2 · FIX-FICHA-9).
 *
 * Esto NO es una hoja nueva de estilos: son los bloques que estaban en
 * assets/css/ficha-v2.css y que a partir de G2 hacen falta también FUERA de la
 * ficha, porque las tarjetas de los listados abren la MISMA modal —con las mismas
 * tarjetas de recambio y el mismo botón-stepper dentro— que la ficha.
 *
 * POR QUÉ SE PARTE EL FICHERO EN VEZ DE ENCOLAR ficha-v2.css EN EL LISTADO.
 * Medido: ficha-v2.css pesa 29 KB comprimidos y ficha-v2.js 13 KB. Encolar la hoja
 * entera en /tienda/ y en cada categoría habría metido 29 KB en toda página de
 * catálogo para pintar una modal que la mayoría de visitas no abre, y casi todo
 * ello —galería, rejilla de dos columnas, caja pegada, prosa, manuales— no tiene
 * a quién aplicarse allí. Lo que sí se comparte entero es el JS: son 13 KB y
 * partirlo habría duplicado el arranque y la hidratación por fragmentos, que es
 * justo el código que no conviene tener por duplicado.
 *
 * QUÉ HAY AQUÍ, y por qué cada cosa:
 *   · los TOKENS de `.ficha-v2` (color, tipografía, medidas) — la modal los
 *     necesita, y en un listado no hay ningún `.ficha-v2` encima, así que el
 *     propio <dialog> lleva la clase;
 *   · la fuente del cuerpo (D4) y los títulos de sección `.fv2-h2` / `.fv2-h3`,
 *     que la modal usa en sus dos bloques;
 *   · el BOTÓN de compra, el stepper y el formulario nativo de los variables;
 *   · la tabla de COMPATIBLES y la tarjeta de RECAMBIO;
 *   · las MODALES.
 *
 * QUIÉN LO ENCOLA: inc/modules/woocommerce/ficha-v2.php. En la ficha, siempre y
 * antes que ficha-v2.css (que lo declara como dependencia). En el resto del
 * sitio, solo si alguna tarjeta llegó a pintar una modal — la bandera la levanta
 * mhw_fv2_modales().
 */

/* =========================================================================
   0) LA FUENTE DEL CUERPO DE LAS SECCIONES (D4)
   =========================================================================
   QUÉ SE LEYÓ. Con el navegador del arnés, en malossistore: la ficha del cilindro
   3117968 y la camiseta 4120775_Y4. La `font-family` COMPUTADA es la misma en el
   cuerpo de la descripción (16px/1.6) y en la tabla de compatibles (14px/1.6, con
   los encabezados a 12px): **Graphik**, servida por el propio sitio desde
   /css/fonts/Graphik-Regular.woff2.
 *
   QUÉ SE DECIDE. Graphik es COMERCIAL (Commercial Type): no se puede adoptar ni
   alojar. La gemela libre más cercana es **Hanken Grotesk** (OFL, Google Fonts):
   mismo esqueleto neo-grotesco de baja modulación, «g» de un piso, terminales
   rectos y una altura de x parecida — que es lo que hace que un párrafo largo se
   lea con el mismo color de página. Se aloja aquí (nada de CDN de terceros) en el
   subconjunto `latin` y en su fichero VARIABLE, 34,7 KB, que cubre 400 y 600 con
   una sola descarga; pedir dos estáticas habría costado dos peticiones y más bytes.
 *
   CÓMO CARGA. `font-display: optional` + preload (inc/modules/woocommerce/ficha-v2.php),
   el mismo patrón que las condensadas: si no llega a tiempo, esa carga se pinta con
   Barlow y NO hay reflujo a mitad de lectura. Y solo en la ficha: esta hoja se
   encola únicamente en is_product().
   Los TÍTULOS no se tocan — siguen en Barlow Semi Condensed. */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 100 900;
  font-display: optional;
  src: url('../fonts/hanken-grotesk-var.woff2') format('woff2');
}

.ficha-v2 {
  --fv2-rojo: #e11414;
  --fv2-rojo-hover: #c40f0f;
  --fv2-verde: #127a38;
  --fv2-verde-punto: #16a34a;
  --fv2-gris-txt: #6e6e6e;
  --fv2-gris-micro: #8a8a8a;
  --fv2-gris-tenue: #9a9a9a;
  --fv2-borde: #e4e4e4;
  --fv2-hairline: #eeeeee;
  --fv2-fondo: #f5f5f5;
  --fv2-fondo-banner: #f2f2f2;

  /* E1 · EL AMARILLO DE OFERTA. RESERVADO: no se usa en nada más.
     Leído en malossistore con el navegador (camiseta 4120775_Y4 y cilindro
     3117968): su resaltado de descuento es `.c-badge` con fondo rgb(255,255,51)
     y tinta rgb(27,33,48), 12 px/500, relleno 4px 8px y esquina de 2 px. Dentro
     del resaltado van JUNTOS el porcentaje y el precio regular tachado; la cifra
     que se paga queda FUERA, grande y en casi-negro.
     Se adopta el mismo amarillo. Contraste con nuestra tinta #111 sobre #ffff33:
     18.5:1, muy por encima del 4.5:1 de AA, así que no hace falta el equivalente
     vivo de reserva que el encargo permitía.
     Un amarillo con un solo trabajo es una señal; el mismo amarillo en tres
     sitios es decoración. Por eso este token no entra en avisos, ni en focos, ni
     en sellos: solo en el resaltado de oferta. */
  --fv2-oferta: #ffff33;
  --fv2-oferta-tinta: #111;

  /* E3 · EL GRIS INFORMATIVO, también leído en malossistore (`.c-shop__infobox`
     de las dos fichas): fondo rgb(231,231,231), tinta rgb(57,61,71), 14 px con
     interlineado 21, relleno 16 y esquina de 4. Es su color de INFORMACIÓN, y por
     eso el párrafo de modelo lo hereda; su rosado/ámbar es de ADVERTENCIA y aquí
     no pinta nada. */
  --fv2-info-fondo: #e7e7e7;
  --fv2-info-tinta: #393d47;

  /* A2 · DOS ANCHOS, NO UNO.
     El brief traía 1020 px para todo y en un monitor de 27" o 32" eso deja la
     ficha como una columna estrecha en medio de un desierto blanco. Se separan
     los dos trabajos que hacía ese número:
       --fv2-ancho  (1440) la ficha: breadcrumb, zona de compra y barra de anclas.
                    Es donde el sitio tiene que aprovechar la pantalla, porque lo
                    que crece es la FOTO (la galería se lleva su 58 %).
       --fv2-lectura (1200) las secciones de contenido. Más ancho que antes, pero
                    con freno: una tabla de compatibles a 1440 px separa tanto el
                    modelo de sus años que hay que seguir la fila con el dedo.
     Y dentro de la lectura, la PROSA lleva su propio tope en `ch` (ver
     .fv2-prosa): con líneas de más de ~75 caracteres el ojo pierde el renglón al
     volver a la izquierda, y eso no se arregla con más ancho sino con menos. */
  --fv2-ancho: 1440px;
  --fv2-lectura: 1200px;

  /* D3 · LA COLUMNA DE LA CAJA DE COMPRA, QUE AHORA VA PEGADA.
     395 px es la medida que fijó Rafael, y es la misma con la que se calibró la
     escalera de títulos en FIX-FICHA-2 (ver mhw_ficha_clase_titulo). El resto del
     ancho —1400 de contenido menos 395 menos los 40 de calle— se lo queda la
     columna izquierda: 965 px. */
  --fv2-caja: 395px;
  --fv2-calle: 40px;

  /* D1/D3 · Y LA GALERÍA NO CRECE CON LA COLUMNA.
     La izquierda pasa de 789 a 965 px, pero la foto se queda en el hueco de
     siempre: 790. Crecer con la columna habría deshecho justo lo que D1 viene a
     arreglar (fotos demasiado grandes) y habría cambiado de tamaño TODAS las
     fichas, no solo las que se ven con zoom. */
  --fv2-galeria: 790px;

  /* AQUÍ NO HAY TOKEN DE SOMBRA PARA LA FOTO, Y ES A PROPÓSITO (H1 · FIX-FICHA-10).
     G3 de FIX-FICHA-9 pedía «restaurar la sombra de la galería». Se midió con
     tests/cdp/_barrido-g3.py —estilos COMPUTADOS de prod, que sirve fd49b58, contra
     los de este árbol— y el `box-shadow` de la foto, del enlace, del slide y del
     contenedor salía `none` en los DOS lados: no había sombra que restaurar. La
     única declaración de la galería en el theme.css de fd49b58 era `box-shadow:
     none`, y lo único que hacían con la sombra las dos reglas que FIX-FICHA-6 acotó
     con `:not(.ficha-v2)` era quitarla.
     Se implementó igualmente como ELECCIÓN (`--fv2-sombra-foto`), y Rafael la
     retiró al ver la medición: la foto principal va limpia sobre el fondo de la
     página, sin marco, sin borde y sin sombra — la misma regla que ya seguían la
     foto de las tarjetas (G1) y las miniaturas. Si alguna vez vuelve a pedirse,
     vuelve como token aquí y una sola declaración en la regla de la imagen. */

  /* Barlow Semi Condensed y Barlow tienen métricas distintas del fallback; se
     nombran con su fallback más cercano para que el salto, si la fuente no
     llega, sea el menor posible.
     CP-CRITICAL-CSS/FIX-3 · dos de estas tres pilas no nombraban la reserva CALIBRADA
     que les toca: --fv2-titulos pide Barlow Semi Condensed y detrás sólo tenía las
     reservas de Barlow —otra métrica, y encima Barlow tampoco ha llegado todavía— y
     --fv2-mono caía a `ui-monospace`. Las caras van declaradas en header-racing.css,
     que se encola en todas las páginas; aquí sólo se nombran. La ficha SÍ es una de
     las seis plantillas con bloque crítico, así que su primer pintado se adelantó y
     el relevo pasó a verse. */
  --fv2-titulos: 'Barlow Semi Condensed', 'Barlow SemiCond Reserva DejaVu',
                 'Barlow SemiCond Reserva Arial', 'Barlow', 'Barlow Reserva DejaVu',
                 'Barlow Reserva Arial', system-ui, sans-serif;
  --fv2-cuerpo: 'Barlow', 'Barlow Reserva DejaVu', 'Barlow Reserva Arial', system-ui, sans-serif;
  --fv2-mono: 'JetBrains Mono', 'JetBrains Reserva', ui-monospace, monospace;

  font-family: var(--fv2-cuerpo);
  color: #1a1a1a;
}

/* El contenedor de WooCommerce imponía sus propios anchos y flotados a
   .summary/.images. La ficha v2 se maqueta con rejilla propia, así que se
   neutralizan aquí en vez de ir persiguiéndolos con !important repartidos. */
.woocommerce div.product.ficha-v2 { float: none; width: auto; }
.ficha-v2::after { content: ''; display: table; clear: both; }

/* DOS COSAS QUE LA HOJA DE WOOCOMMERCE GANABA POR ESPECIFICIDAD, Y QUE HAY QUE
   DEJAR ZANJADAS ARRIBA DEL TODO PARA NO IR PERSIGUIÉNDOLAS REGLA A REGLA:

   1. `[hidden]`. El atributo vale `display:none` en la hoja del navegador, y
      CUALQUIER regla de autor con `display` le gana. Como el botón y el stepper
      son `inline-flex`, ponerles `hidden` no los ocultaba: se veían los dos a la
      vez, botón rojo y «− 1 +» uno debajo del otro. Medido en la primera tanda
      de capturas.

   2. `.woocommerce img, .woocommerce-page img { height:auto; max-width:100% }`
      (0,1,1) le gana a cualquier clase suelta (0,1,0). Por eso los logos de
      marca salían a 452x183 px en vez de a 26 px de alto: la altura se
      descartaba y el ancho lo fijaba el 100 % del contenedor. Todo lo que
      dimensione imágenes en esta ficha va prefijado por `.ficha-v2`, que sube la
      especificidad a 0,2,x y gana sin recurrir a `!important`. */
.ficha-v2 [hidden] { display: none !important; }

/* D4 · LA FUENTE DEL CUERPO, EN UN SOLO SITIO.
   Se redefine la VARIABLE dentro de las secciones (y de las modales, que pintan
   esas mismas secciones) en vez de repetir `font-family` en veinte reglas: todo
   lo que ya decía `var(--fv2-cuerpo)` —párrafos, tablas, listas, tarjetas de
   recambio— pasa a Hanken Grotesk de una vez, y lo que declara `--fv2-titulos` o
   `--fv2-mono` no se entera. Fuera de aquí (breadcrumb y caja de compra) sigue
   mandando Barlow: el brief pide la fuente para el CUERPO DE LAS SECCIONES.
   El fallback es Barlow, que es la que se venía usando: si la fuente no llega
   (font-display: optional), la ficha se ve exactamente como antes de D4. */
.fv2-contenido,
.fv2-modal {
  --fv2-cuerpo: 'Hanken Grotesk', 'Barlow', 'Barlow Reserva DejaVu', 'Barlow Reserva Arial', system-ui, sans-serif;
  font-family: var(--fv2-cuerpo);
}

/* Título de sección con subrayado rojo de 3 px DEL ANCHO DEL TEXTO y DEBAJO de
   la última línea.
   CORRECCIÓN C2 respecto al mock: allí el subrayado sale a media altura,
   atravesando la segunda línea de «MARCAS Y MODELOS COMPATIBLES». Eso pasa
   cuando la raya se pinta sobre el bloque del título en vez de sobre el texto.
   Aquí el <span> interior es inline: su caja termina donde acaba la última
   línea, así que el border-bottom cae siempre debajo, sin importar cuántas
   líneas ocupe. */
.fv2-h2 {
  margin: 0 0 20px;
  font-family: var(--fv2-titulos);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.15;
  text-transform: uppercase;
  color: #111;
}

.fv2-h2 > span {
  display: inline;
  border-bottom: 3px solid var(--fv2-rojo);
  padding-bottom: 6px;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

/* B1: 34 -> 30 en escritorio, con su aire (20 -> 18). El de móvil (24) se queda. */
@media (min-width: 1000px) {
  .fv2-h2 { font-size: 30px; margin-bottom: 18px; }
}

.fv2-h3 {
  margin: 28px 0 12px;
  font-family: var(--fv2-titulos);
  font-weight: 600;
  font-size: 17px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #111;
}

/* =========================================================================
   3) BOTÓN DE COMPRA Y STEPPER
   ========================================================================= */

/* El botón y el stepper ocupan EL MISMO hueco y la MISMA altura: al añadir, uno
   sustituye al otro sin que nada se mueva de sitio. Por eso la altura vive en el
   contenedor y no en cada pieza. */
/* B1: el botón de la caja de compra baja de 60 a 54 px de alto en escritorio. Como
   54 es justo la altura base, la regla que lo subía a 60 desaparece en vez de
   quedarse escribiendo el mismo número dos veces. La altura de las tarjetas (48)
   no se toca: no estaba entre lo que había que encoger. */
.fv2-compractl {
  --fv2-alto: 54px;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.fv2-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: var(--fv2-alto);
  padding: 0 26px;
  border: 0;
  background: var(--fv2-rojo);
  color: #fff;
  font-family: var(--fv2-titulos);
  font-weight: 600;
  font-size: 16px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.fv2-btn:hover { background: var(--fv2-rojo-hover); }
.fv2-btn:focus-visible { outline: 2px solid #111; outline-offset: 2px; }

/* CP-RECAMBIOS-VAR · EL CARRITO A LA IZQUIERDA DEL RÓTULO.
   El aire va SOLO en los botones que llevan ícono —el de comprar de los simples y
   el nativo de los variables—, no en `.fv2-btn`: «VER OPCIONES» y «No disponible»
   son un único nodo de texto y un `gap` allí no haría nada más que estar puesto.
   El tamaño se repite en los atributos `width`/`height` del propio <svg>
   (mhw_fv2_icono_carrito): así el ícono ya nace de 20 px aunque esta hoja llegue
   tarde, que es exactamente lo que pasa con el CSS crítico por delante. */
.fv2-btn--comprar { gap: 10px; }

.fv2-btn__ico {
  width: 20px;
  height: 20px;
  flex: none;
}

/* G2 · El enlace «VER OPCIONES» que sustituye al formulario de variantes fuera de
   la ficha (ver template-parts/single-product/ficha-v2/boton.php). Es un <a>, así
   que hay que devolverle lo que .fv2-btn da por hecho en un <button>: sin subrayado
   y con el texto centrado en la caja, que el `display:inline-flex` de .fv2-btn ya
   resuelve. */
.fv2-btn--opciones { text-decoration: none; }
.fv2-btn--opciones:hover { color: #fff; text-decoration: none; }

.fv2-btn--agotado {
  background: #ededed;
  color: var(--fv2-gris-micro);
  cursor: not-allowed;
}

/* En la caja de compra el control ocupa el ancho de la columna. Cuando aparece
   el stepper, la etiqueta «EN EL CARRITO» va A SU LADO dentro de la MISMA fila
   (sección 7: «nada se mueve de sitio»): el stepper cede el sitio justo de la
   etiqueta con flex:1 y la fila conserva la altura y la caja del botón. Si la
   etiqueta cayera a una segunda línea, la caja de garantías bajaría de golpe —
   que es justo el salto que el brief quiere evitar. */
.fv2-compractl--ancho { flex-wrap: nowrap; }
.fv2-compractl--ancho .fv2-btn { width: 100%; }
.fv2-compractl--ancho .fv2-stepper { flex: 1 1 auto; width: auto; }
.fv2-compractl--ancho .fv2-encarrito { flex: 0 0 auto; max-width: 96px; }

.fv2-stepper {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  height: var(--fv2-alto);
  min-width: 132px;
  padding: 0 6px;
  border: 2px solid var(--fv2-rojo);
  box-sizing: border-box;
  background: #fff;
}

.fv2-stepper__btn {
  width: 42px;
  height: 100%;
  border: 0;
  background: none;
  color: var(--fv2-rojo);
  font-family: var(--fv2-cuerpo);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}

.fv2-stepper__btn:hover { color: var(--fv2-rojo-hover); }
.fv2-stepper__btn:disabled { opacity: 0.4; cursor: default; }

.fv2-stepper__n {
  font-family: var(--fv2-titulos);
  font-weight: 600;
  font-size: 18px;
  min-width: 28px;
  text-align: center;
  color: #111;
}

.fv2-encarrito {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  line-height: 1.3;
  color: var(--fv2-verde);
}

.fv2-deshacer {
  border: 0;
  background: none;
  padding: 0;
  font-family: var(--fv2-cuerpo);
  font-size: 13px;
  font-weight: 600;
  color: var(--fv2-rojo);
  text-decoration: underline;
  cursor: pointer;
}

.fv2-compractl.is-cargando { opacity: 0.55; pointer-events: none; }

/* -------------------------------------------------------------------------
   3b) PRODUCTOS VARIABLES Y BUNDLES: EL FORMULARIO NATIVO, VESTIDO (F7)
   -------------------------------------------------------------------------
   Los 96 productos VARIABLES no pueden usar el botón-stepper: hay que elegir algo
   ANTES de añadir. (Aquí decía «96 variables y 2 bundles»; los bundles no existen
   como tipo desde que CP-LIMPIEZA se llevó su plugin — ver boton.php, H2.)
   Por eso boton.php pinta ahí el formulario de WooCommerce, que
   trae su propio JS de variaciones y no se toca. Lo que entró sin vestir fue el
   ASPECTO: sin el envoltorio `.summary` de la ficha vieja, la regla de theme.css
   que pintaba ese botón dejó de aplicar y salía el morado de fábrica de
   WooCommerce (#7f54b3), con su campo de cantidad y un selector suelto.
   Aquí se reviste con el mismo sistema que los simples. El comportamiento —qué
   variante hay elegida, cuándo se habilita el botón, el precio por variante— sigue
   siendo el de WooCommerce.
   Vale igual en la caja de compra y en las tarjetas de recambio, que es donde de
   verdad se veía: la ficha del variador es SIMPLE y sus recambios son variables. */

.ficha-v2 .fv2-compractl form.cart {
  display: block;
  width: 100%;
  margin: 0;
}

.ficha-v2 .fv2-compractl table.variations {
  width: 100%;
  margin: 0 0 12px;
  border-collapse: collapse;
}

.ficha-v2 .fv2-compractl table.variations tbody,
.ficha-v2 .fv2-compractl table.variations tr,
.ficha-v2 .fv2-compractl table.variations th,
.ficha-v2 .fv2-compractl table.variations td {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  text-align: left;
}

/* La etiqueta del atributo SIEMPRE visible: es la que dice qué hay que escoger,
   ahora que no hay recuadro amarillo que lo grite.

   FIX-FICHA-16 · POR QUÉ SOBRA `form.cart` EN EL PREFIJO. Sin él el selector pesa
   (0,4,3) y la hoja de WooCommerce trae `.woocommerce div.product form.cart
   .variations label { font-weight:700 }`, que pesa EXACTAMENTE lo mismo: el 600 de
   aquí solo ganaba porque nuestra hoja se encola después. Eso no es una regla que
   gane, es una que va ganando; cualquier reordenación del <head> —un plugin de
   combinado, un cambio de dependencias en wp_enqueue_style— la pone en 700 sin que
   nadie toque este fichero. `form.cart` es un ancestro CIERTO (WooCommerce envuelve
   todos sus formularios de añadir en él, y ya se le apunta en la regla de arriba),
   así que sube el peso a (0,5,4) sin cambiar ni un nodo de los que casan y sin un
   solo !important. Medido con el oráculo de la revisora: poner nuestras hojas
   DELANTE de las de Woo ya no cambia ninguna propiedad computada. */
.ficha-v2 .fv2-compractl form.cart table.variations th.label label {
  display: block;
  margin: 0 0 6px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fv2-gris-txt);
}

.ficha-v2 .fv2-compractl table.variations select {
  width: 100%;
  height: 48px;
  padding: 0 12px;
  border: 1px solid #cfcfcf;
  border-radius: 0;
  background: #fff;
  font-family: var(--fv2-cuerpo);
  font-size: 15px;
  color: #1a1a1a;
  box-sizing: border-box;
}

.ficha-v2 .fv2-compractl table.variations select:focus-visible {
  outline: 2px solid var(--fv2-rojo);
  outline-offset: 1px;
}

.ficha-v2 .fv2-compractl a.reset_variations {
  display: inline-block;
  margin-top: 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--fv2-gris-txt);
  text-decoration: underline;
}

/* Sin campo de cantidad (sección 6 del brief). Se OCULTA en vez de quitarlo del
   formulario: el input sigue enviando `quantity=1`, que es justo lo que se
   quiere, y así no hay que tocar la plantilla de WooCommerce ni su JS.
   E2 · EL `!important` NO ES PEREZA, ES LA ÚNICA HERRAMIENTA QUE SIRVE. Sin él
   la regla funcionaba hasta que se elegía una variante, y entonces el campo
   aparecía: `add-to-cart-variation.js` de WooCommerce llama a `.show()` de jQuery
   sobre el bloque, y eso escribe `style="display: block"` EN LÍNEA. Un estilo en
   línea gana a cualquier hoja por especificidad que tenga, así que la única forma
   de ganarle desde CSS es esta. Medido: sin elegir, el campo estaba oculto; tras
   elegir, `inline_div = "display: block;"` y 22 px de alto en Arial negro dentro
   de la caja de compra. */
.ficha-v2 .fv2-compractl form.cart .quantity { display: none !important; }

.ficha-v2 .fv2-compractl .woocommerce-variation-price {
  margin: 0 0 10px;
  font-family: var(--fv2-titulos);
  font-weight: 700;
  font-size: 26px;
  line-height: 1.1;
  color: #111;
}

.ficha-v2 .fv2-compractl .woocommerce-variation-price .woocommerce-Price-amount {
  font: inherit;
  color: inherit;
}

/* E2 · EL OLIVA DE WOOCOMMERCE. El precio de la variante salía en #958e09 —un
   verde apagado que WooCommerce pinta con
   `.woocommerce:where(...) div.product span.price`— dentro de una caja donde
   todas las cifras son casi negras. Vestir el CONTENEDOR no bastaba: la regla del
   core apunta al `span.price` de dentro, así que gana a cualquier color heredado.
   Se le apunta al mismo nodo con la especificidad suficiente (el `:where()` del
   core no suma nada) y el color vuelve a heredarse del bloque, que es quien sabe
   de qué color va el precio en esta ficha. */
.woocommerce div.product.ficha-v2 .fv2-compractl .woocommerce-variation-price .price {
  color: inherit;
}

/* El precio de la variante en oferta hereda el sistema de E1: el `<del>` y el
   `<ins>` que mete WooCommerce dentro de `price_html` no pueden salir con el
   tachado gris de fábrica al lado de una cifra que aquí es de 26 px. */
.ficha-v2 .fv2-compractl .woocommerce-variation-price ins { text-decoration: none; }
.ficha-v2 .fv2-compractl .woocommerce-variation-price del {
  font-size: 0.55em;
  font-weight: 400;
  color: var(--fv2-gris-micro);
}

/* E2 · BARRIDO DEL FORMULARIO: TODO CON EL SISTEMA DE LA FICHA.
   Lo que quedaba con estilo genérico eran las piezas que WooCommerce pinta
   DENTRO del envoltorio de la variación (disponibilidad, avisos de stock, el
   alerta de reset) y que no habían pasado por ninguna regla nuestra: heredaban
   la familia del documento y el color del tema. Se declaran explícitas —familia,
   tamaño y tinta— en vez de confiar en la herencia, que es justo lo que se rompe
   cuando el nodo cambia de sitio. */
.ficha-v2 .fv2-compractl .single_variation_wrap,
.ficha-v2 .fv2-compractl .woocommerce-variation,
.ficha-v2 .fv2-compractl .woocommerce-variation-availability,
.ficha-v2 .fv2-compractl .woocommerce-variation-availability p,
.ficha-v2 .fv2-compractl .stock,
.ficha-v2 .fv2-compractl .wc-no-matching-variations {
  font-family: var(--fv2-cuerpo);
  color: var(--fv2-gris-txt);
}

.ficha-v2 .fv2-compractl .woocommerce-variation-availability {
  margin: 0 0 10px;
  font-size: 13px;
}

.ficha-v2 .fv2-compractl .woocommerce-variation-availability p { margin: 0; }

/* «Disponible» y «Agotado» de la variante, con los mismos dos colores que el
   sello de la caja: verde para lo que se puede comprar, gris para lo que no. */
.ficha-v2 .fv2-compractl .stock.in-stock { color: var(--fv2-verde); font-weight: 600; }
.ficha-v2 .fv2-compractl .stock.out-of-stock { color: var(--fv2-gris-micro); font-weight: 600; }

.ficha-v2 .fv2-compractl .wc-no-matching-variations {
  margin: 0 0 10px;
  font-size: 13px;
  color: var(--fv2-rojo);
}

/* E2 · LA DESCRIPCIÓN DE LA VARIACIÓN NO SE PINTA EN LA CAJA.
   Se esconde SOLO en la caja de compra, que es la que va pegada y tiene que
   caber: en las tarjetas de recambio no hay restricción de alto, así que allí se
   sigue leyendo donde WooCommerce la pone. `display: none` la saca también del
   árbol de accesibilidad, así que la copia que ficha-v2.js lleva a la sección
   Descripción no duplica nada para quien usa lector de pantalla. */
.ficha-v2 .fv2-compra__caja .fv2-compractl .woocommerce-variation-description { display: none; }

.ficha-v2 .fv2-compractl .woocommerce-variation-add-to-cart {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* El botón, con el sistema de la ficha: rojo, mismas medidas que el de los
   simples y a lo ancho en la caja de compra.

   FIX-FICHA-16 · `form.cart` EN LAS CINCO REGLAS DEL BOTÓN, Y EN LAS CINCO A LA VEZ.
   La hoja de WooCommerce le apunta a este mismo botón con diez reglas, y la más
   pesada —`.woocommerce:where(body:not(.woocommerce-block-theme-has-button-styles))
   button.button.alt.disabled:hover`— pesa (0,5,1). Sin `form.cart`, la base de aquí
   pesa (0,4,1) y la de `.disabled` de más abajo (0,5,1): la primera PIERDE y la
   segunda EMPATA, y las dos acababan bien solo por el orden del <head>. Con
   `form.cart` la base sube a (0,5,2) y las de estado a (0,6,2), que le ganan a las
   diez sin !important.
   Se toca EN BLOQUE —base, :hover, .disabled y las dos de @media— porque todas
   suben lo mismo (+1 clase, +1 elemento) y así la cascada ENTRE NOSOTROS queda
   igual que estaba. Subir solo la base habría dejado a las de @media por debajo, y
   el botón de las tarjetas de recambio habría recuperado el `width:100%` que esas
   reglas existen para quitarle. */
.woocommerce .ficha-v2 .fv2-compractl form.cart button.single_add_to_cart_button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;   /* CP-RECAMBIOS-VAR: el mismo aire que .fv2-btn--comprar, para el ícono */
  width: 100%;
  height: var(--fv2-alto);
  padding: 0 26px;
  border: 0;
  border-radius: 0;
  background: var(--fv2-rojo);
  color: #fff;
  font-family: var(--fv2-titulos);
  font-weight: 600;
  font-size: 16px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.woocommerce .ficha-v2 .fv2-compractl form.cart button.single_add_to_cart_button:hover { background: var(--fv2-rojo-hover); }

/* Hasta que no hay variante escogida el botón está INACTIVO, y eso es todo el
   aviso que hace falta: las clases las pone el JS de variaciones de WooCommerce.
   Sigue recibiendo el clic a propósito —ajax-single-add-to-cart.js lo usa para
   llevar el foco al primer desplegable sin elegir. */
.woocommerce .ficha-v2 .fv2-compractl form.cart button.single_add_to_cart_button.disabled,
.woocommerce .ficha-v2 .fv2-compractl form.cart button.single_add_to_cart_button.wc-variation-selection-needed {
  background: #ededed;
  color: var(--fv2-gris-micro);
  cursor: not-allowed;
}

@media (min-width: 1000px) {
  .woocommerce .ficha-v2 .fv2-recambio .fv2-compractl form.cart button.single_add_to_cart_button {
    width: auto;
    min-width: 190px;
  }
  .ficha-v2 .fv2-recambio .fv2-compractl form.cart { width: auto; min-width: 240px; }
}

.fv2-compractl__error {
  flex-basis: 100%;
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--fv2-rojo);
}

/* --- Compatibles -------------------------------------------------------- */

.fv2-compat {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* M5 (FIX-FICHA-13) · LA MISMA REJILLA LA COMPARTEN LA FILA Y EL ENCABEZADO.
   El encabezado tiene que caer al píxel sobre las columnas de las filas, y la única
   forma de garantizarlo sin repetir números es que los dos declaren la MISMA
   plantilla. De ahí el selector doble: si mañana cambia un ancho, cambia para los
   dos o no cambia para ninguno. */
.fv2-compat__fila,
.fv2-compat__cab {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    'modelo tuya'
    'notas  notas'
    'years  years';
  gap: 2px 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--fv2-hairline);
  font-size: 14px;
}

/* BANDA MEDIA (1000–1239) · CUATRO COLUMNAS, LA NOTA APILADA BAJO EL MODELO.
   Es la disposición de antes de M5, y se conserva a propósito para esta banda —ver
   el porqué, con números, en el bloque de 1240 de aquí abajo—. Única diferencia con
   J2: la nota ya no vive DENTRO de la celda del modelo, ocupa su propia fila de la
   rejilla en la columna del modelo. Se lee igual y el marcado es uno solo. */
@media (min-width: 1000px) {
  .fv2-compat__fila,
  .fv2-compat__cab {
    grid-template-columns: 120px minmax(0, 1fr) 130px 80px;
    grid-template-areas:
      'marca modelo years tuya'
      '.     notas  .     .';
    align-items: baseline;
    gap: 0 16px;
    padding: 14px 0;
  }
}

/* M5.3 · LA QUINTA COLUMNA, Y EL PUNTO DE CORTE POR ANCHO MEDIDO.
   Censo de los datos (tests/_medir-anios-m5.php · 2690 parejas que pintan fila, 537
   con `_compat_fit`):

     392 filas con AÑOS  — 73.0 % de las que tienen fit   (largo máx. 11 caracteres)
     174 filas con NOTA  — 32.4 % de las que tienen fit   (mediana 10, p90 22, máx 41)

   OJO CON LA HIPÓTESIS DE PARTIDA: la ronda daba por hecho que «Años» saldría vacía
   en la gran mayoría y que había que estrecharla para pagar «Notas». Es al revés —
   cuando hay fitment, los años están en tres de cada cuatro filas. Así que a «Años»
   se le quita solo el sobrante (130 px para 11 caracteres como mucho), no presencia:

     marca   120px  — igual que antes.
     modelo  1fr    — sigue siendo la elástica y la más ancha de la fila.
     años     84px  — baja desde 130. «2015 – 2024» son ~72 px a 13 px de cuerpo.
     notas   170px  — del p90 (22 caracteres), no del máximo. Los 22 caben en una
                      línea; los pocos de 41 envuelven a dos, que en una celda de
                      texto gris es lo correcto y no descuadra la fila (las celdas
                      alinean por `baseline`, o sea por su PRIMERA línea).
     tuya     80px  — igual que antes.

   POR QUÉ 1240 Y NO 1000, MEDIDO Y NO A OJO (tests/cdp/_medir-reparto-m5.py). Las
   cinco pistas fijas suman 454 px más cuatro huecos de 16 = 518 px, y el ancho de la
   lista NO es el de la ventana: la ficha es de dos columnas y la tabla vive en la
   izquierda. Medido, ventana → ancho de la lista: 1500→965, 1280→790, 1100→610,
   1024→534, 1000→510. Con el corte en 1000 el resultado era este:

       ventana 1100 → modelo 92 px      ventana 1024 → modelo 16 px
       ventana 1000 → modelo 0 px  ← la columna que se lee, desaparecida

   El nombre de modelo más largo de esta tabla mide 155 px, así que por debajo de
   ~1240 la quinta columna se paga con la primera. En 1240 la lista da ~750 px y al
   modelo le quedan ~232, que es más de lo que tenía en la banda media de siempre.
   Por eso el corte va aquí y no en el 1000 que gobierna el resto de la ficha: es el
   ancho el que decide, no el dispositivo ni la simetría con los otros breakpoints. */
@media (min-width: 1240px) {
  .fv2-compat__fila,
  .fv2-compat__cab {
    grid-template-columns: 120px minmax(0, 1fr) 84px 170px 80px;
    grid-template-areas: 'marca modelo years notas tuya';
  }
}

/* N5 (FIX-FICHA-14) · LA SEGUNDA FORMA DE LA TABLA: SIN COLUMNA «NOTAS».
   Solo 73 de los 1019 productos del catálogo tienen alguna nota, así que en el 93 %
   de las fichas la forma de arriba deja un rótulo «NOTAS» presidiendo una columna
   entera de celdas vacías. Cuando la plantilla no encuentra ni una nota marca la
   lista con `--sinnotas` y aquí se reparte el ancho entre las columnas que quedan.
   No es solo quitar una columna: los 170 px de «Notas» y los 16 del hueco se los
   lleva el MODELO, que es lo que se lee, y «Años» recupera los 130 px que tenía
   antes de que hubiera que hacerle sitio a la nota (su contenido más largo son 11
   caracteres, así que 130 le sobran igual, pero con la nota fuera ese sobrante ya
   no le hace falta a nadie más). Medido a 1500: en la forma CON notas al modelo le
   quedan 447 px; en la forma SIN notas, 587.
   La forma sin notas no necesita esperar al 1240 —cuatro columnas caben desde el
   1000 y de hecho es el reparto que la banda media ya usaba—, pero el ENCABEZADO sí
   espera, para no tener dos umbrales distintos según lo que lleve dentro. */
@media (min-width: 1000px) {
  .fv2-compat--sinnotas .fv2-compat__fila,
  .fv2-compat--sinnotas .fv2-compat__cab {
    grid-template-columns: 120px minmax(0, 1fr) 130px 80px;
    grid-template-areas: 'marca modelo years tuya';
  }
}

/* M5.2 · LA FILA DE ENCABEZADOS. Tipografía y peso del sistema, sin fondo de color:
   una guía de columnas, no una barra. El hairline lo hereda de la regla compartida
   de arriba, así que cierra contra la primera fila igual que las filas entre sí.
   SE PINTA SOLO DONDE EXISTEN LAS CUATRO COLUMNAS QUE NOMBRA, o sea a partir del
   mismo 1240 que abre la columna «Notas». Por debajo no se pinta y no es una
   omisión: en la banda media la nota va apilada bajo el modelo y en móvil ni
   siquiera hay columna de marca — un encabezado «Marca · Modelo · Años · Notas»
   estaría rotulando columnas que ahí no están. */
.fv2-compat__cab {
  display: none;
}

@media (min-width: 1240px) {
  .fv2-compat__cab {
    display: grid;
    padding: 0 0 8px;
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--fv2-gris-micro, #8a8a8a);
  }

  /* Los encabezados son etiquetas, no datos: ninguna hereda el peso, el color ni la
     alineación de la columna que rotulan (el «Años» de las filas va a la derecha; el
     rótulo, no — pisaría el aire que separa Años de Notas). */
  .fv2-compat__cab .fv2-compat__marca,
  .fv2-compat__cab .fv2-compat__modelo,
  .fv2-compat__cab .fv2-compat__years,
  .fv2-compat__cab .fv2-compat__notas {
    font: inherit;
    color: inherit;
    text-align: left;
  }
}

.fv2-compat__marca {
  grid-area: marca;
  color: var(--fv2-gris-txt);
}

/* En móvil la marca se pliega dentro del modelo (la fila no da para 4 columnas
   sin apretar los años contra el borde).

   F2 (CP-GALERIA/FIX-1) · ESTE COMENTARIO PROMETÍA UN PLIEGUE QUE NADIE HACÍA.
   La columna se escondía y ya: la celda del modelo solo lleva la parte del nombre
   posterior a la primera palabra, así que Rafael leía «MOTO 450 SR» donde el
   término dice «CF MOTO 450 SR» y «NMAX 155» donde dice «YAMAHA NMAX 155». El
   pliegue existe ahora de verdad — `.fv2-compat__marcain`, emitido por la
   plantilla dentro de la celda del modelo— y esta regla se queda para que la
   marca no salga DOS veces en la misma fila. Escritorio, al revés: manda la
   columna y sobra el pliegue. */
/* CP-FUENTES · A4 · EL CORTE ES 999.98, NO 999, Y AQUÍ SÍ IMPORTA.
   La ficha cambia de una columna a dos en 1000 px, y ese corte se escribe en toda la
   hoja como `max-width: 999.98px` / `min-width: 1000px` — la pareja que NO deja
   hueco—. Estas dos reglas se habían escrito con 999 a secas, y `999` y `1000` dejan
   entre medias toda la banda fraccionaria: 999,5 px es un ancho perfectamente real
   (zoom del navegador, pantallas con escala no entera, la barra lateral de las
   herramientas de desarrollo). En esa banda no se cumple NINGUNA de las dos, o sea
   que ni se esconde `.fv2-compat__marca` ni se esconde `.fv2-compat__marcain`: la
   marca sale DOS VECES en la misma fila, que es exactamente lo que el pliegue de F2
   vino a evitar.
   No es un cambio de diseño: en 999 y en 1000 el resultado es idéntico al de antes.
   Solo se tapa el hueco de en medio. */
@media (max-width: 999.98px) {
  .fv2-compat__marca { display: none; }
}

@media (min-width: 1000px) {
  .fv2-compat__marcain { display: none; }
}

.fv2-compat__modelo {
  grid-area: modelo;
  font-weight: 600;
  color: #1a1a1a;
}

.fv2-compat__modelo a { color: inherit; text-decoration: none; }
.fv2-compat__modelo a:hover { text-decoration: underline; }

/* M5.1 (FIX-FICHA-13) · LA NOTA, EN COLUMNA PROPIA. Sustituye a `.fv2-compat__nota`,
   que J2 metía DENTRO de la celda del modelo.
   Peso y tinta se conservan tal cual (400, 12.5 px, gris): lo que cambia es dónde
   vive, no cómo se ve. Alineada a la izquierda por M5.1 — no a la derecha como los
   años— porque es texto, y el texto se lee desde un borde fijo.
   En MÓVIL ocupa su propia fila de la rejilla, justo debajo del modelo y encima de
   los años: exactamente la misma lectura que tenía cuando colgaba de la celda del
   modelo, sin las cuatro columnas que no caben en 390 px. */
.fv2-compat__notas {
  grid-area: notas;
  font-weight: 400;
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--fv2-gris-txt);
  text-align: left;
}

/* Sin nota, la celda no debe reservar la fila apilada del móvil (dejaría un escalón
   de 2 px de gap entre modelo y años en las filas sin nota, que son la mayoría). */
.fv2-compat__notas:empty {
  display: none;
}

.fv2-compat__years {
  grid-area: years;
  color: var(--fv2-gris-txt);
  font-size: 13px;
}

@media (min-width: 1000px) {
  .fv2-compat__years { text-align: right; }
}

.fv2-compat__tuya {
  grid-area: tuya;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fv2-rojo);
  text-align: right;
}

/* La moto del contexto en la ficha combo.
   EL REALCE NO PUEDE MOVER LA FILA. Antes esto era `border-left: 3px` más 14 px de
   padding a cada lado, y eso empuja el CONTENIDO: la marca y el modelo de la moto
   del contexto salían 17 px a la derecha de los de las demás filas, y su columna de
   años 14 px a la izquierda. Con cuatro filas en una tabla, esa fila desalineada se
   ve enseguida — que es lo que Rafael vio.
   La caja de color se saca AFUERA con márgenes negativos que cancelan exactamente
   el borde y el padding (17 a la izquierda, 14 a la derecha): la caja de contenido
   vuelve a empezar y terminar donde la de las otras filas, así que las cuatro
   columnas de la rejilla se alinean al píxel, y lo único que se sale de la lista es
   la banda rosa. Cabe: la sección tiene 20 px de aire a cada lado. */
.fv2-compat__fila--tuya {
  background: #faf3f3;
  border-left: 3px solid var(--fv2-rojo);
  margin-left: -17px;
  margin-right: -14px;
  padding-left: 14px;
  padding-right: 14px;
}

/* --- Recambios ---------------------------------------------------------- */

.fv2-recambios {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* REJILLA EXPLÍCITA (corrección C3): foto | info | acciones. Cada pieza tiene su
   celda, así que el precio no puede acabar debajo de un botón ni partirse con
   aspecto de tachado. */
.fv2-recambio {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  grid-template-areas:
    'foto info'
    'acciones acciones';
  gap: 14px;
  padding: 14px;
  border: 1px solid var(--fv2-borde);
  align-items: start;
}

@media (min-width: 1000px) {
  .fv2-recambio {
    grid-template-columns: 170px minmax(0, 1fr) minmax(220px, auto);
    grid-template-areas: 'foto info acciones';
    gap: 20px;
    padding: 18px;
    align-items: center;
  }
}

/* G1: la foto de la tarjeta también pierde el cuadro. Queda sobre el blanco de
   la página, igual que la foto principal. `position: relative` se queda porque
   en MÓVIL el logo sigue apoyado dentro de la foto (G5). */
/* El logo ya no va SOBRE la foto (ver B5b más abajo): la celda pasa a ser una
   columna —foto arriba, logo debajo y centrado— para que ninguno tape al otro. */
.fv2-recambio__foto {
  grid-area: foto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  background: transparent;
  border: 0;
}

.fv2-recambio__foto a {
  display: block;
  width: 100%;
}

/* Sin cuadro alrededor, el padding que separaba la foto del borde ya no separa
   de nada: se retira y la foto ocupa toda su celda (G1). */
.ficha-v2 .fv2-recambio__img {
  width: 100%;
  height: 80px;
  object-fit: contain;
  padding: 0;
  box-sizing: border-box;
  display: block;
}

@media (min-width: 1000px) {
  .ficha-v2 .fv2-recambio__img { height: 120px; }
}

/* B5 · EL LOGO VUELVE A LA FOTO, Y GRANDE.
   G5 lo sacó de la foto en escritorio y lo llevó a la línea del código; A5 lo subió
   allí de 20 a 28 px. Rafael decide volver atrás: el logo va DENTRO del bloque de
   la foto, esquina inferior izquierda, en los dos anchos — 28 px en escritorio y 24
   en móvil. Ahí es donde se lee como lo que es (la marca de ESA pieza) y no compite
   con el precio por el sitio de la línea de datos.
   Con esto desaparece el segundo nodo `--meta`: era la copia que se pintaba en la
   línea del código, y ya no la emite ninguna plantilla (ver tarjeta-recambio.php).
   Vale igual en la sección, en la nueva «Se aplica a» (B3) y dentro de las
   modales: todas pintan la misma tarjeta.

   B5b · Y DEBAJO DE LA FOTO, NO ENCIMA. Apoyado en la esquina inferior izquierda
   el logo se comía un trozo de la pieza —en un resorte, justo las últimas
   espiras—, que es lo que Rafael vio. Deja de ser una capa flotante: es el segundo
   elemento de la columna, centrado bajo la foto y con 10 px de aire. Ahí puede
   crecer sin tapar nada (28 -> 34 px en escritorio, 24 -> 28 en móvil) y ya no
   necesita `pointer-events: none`, porque no se solapa con el enlace de la foto.
   El único coste es que la celda crece lo que mide el logo, y la tarjeta con
   ella; no rompe la rejilla de G6 porque esa altura es la misma en todas. */
.ficha-v2 .fv2-recambio__logo--foto {
  height: 28px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  display: block;
}

@media (min-width: 1000px) {
  .ficha-v2 .fv2-recambio__logo--foto { height: 34px; }
}

.fv2-recambio__info {
  grid-area: info;
  min-width: 0;
}

/* F5: código, logo, precio y sello en una sola fila. Cada uno en su celda, así
   que el precio no puede pisar nada ni partirse.
   G6: la fila tiene ALTURA RESERVADA. Sin ella, un recambio sin código o sin
   logo encogía la fila y movía hacia arriba el precio y el botón respecto a la
   tarjeta de al lado. */
/* B5: el logo se ha ido de esta fila (vuelve a la foto), así que el aire extra que
   A5 le había hecho sitio se devuelve: separación 24 -> 18 y altura reservada
   40 -> 34, que es lo que mide la línea con el precio dentro. La altura sigue
   RESERVADA aunque falte el código: sin ella, una tarjeta sin código encoge y mueve
   el precio y el botón respecto a la de al lado (G6). */
.fv2-recambio__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 18px;
  margin: 0 0 10px;
  min-height: 34px;
}

/* G6 · LA REJILLA NO SE MUEVE CON EL LARGO DEL TÍTULO.
   El título ocupa SIEMPRE dos líneas: `min-height` reserva las dos aunque el
   texto quepa en una, y el recorte a dos líneas impide que un título largo
   empuje el resto hacia abajo. Con eso, precio, disponibilidad y botones caen en
   la misma posición en todas las tarjetas, que es lo que pidió Rafael. Vale
   igual en móvil y en escritorio: la altura va en `em`, así que sigue a la
   tipografía sin repetir el número. */
.fv2-recambio__titulo {
  margin: 0 0 6px;
  font-family: var(--fv2-cuerpo);
  font-weight: 600;
  font-size: 15px;
  line-height: 1.32;
  color: #1a1a1a;
  min-height: 2.64em;          /* 2 líneas x 1.32 */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

.fv2-recambio__titulo a { color: inherit; text-decoration: none; }
.fv2-recambio__titulo a:hover { text-decoration: underline; }

.fv2-recambio__codigo {
  margin: 0;
  font-family: var(--fv2-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fv2-gris-micro);
}

.fv2-recambio__precio {
  margin: 0;
  font-family: var(--fv2-titulos);
  font-weight: 700;
  font-size: 24px;
  line-height: 1.1;
  color: #111;
  /* El precio nunca se parte: partido en dos líneas es justo lo que en el mock
     parecía un precio tachado. */
  white-space: nowrap;
}

.fv2-recambio__precio .woocommerce-Price-amount { font: inherit; color: inherit; }
.fv2-recambio__precio del { font-size: 0.55em; color: var(--fv2-gris-micro); font-weight: 400; }
.fv2-recambio__precio ins { text-decoration: none; }

/* D2 + E1 en la tarjeta: las mismas dos piezas, más apretadas.
   El `white-space: nowrap` de arriba existe para que una CIFRA no se parta en
   dos líneas (partida parece un precio tachado, que es lo que se vio en el mock).
   Con la cifra y el resaltado en la misma línea ese nowrap pasaría de red de
   seguridad a problema: en 390 px la columna de datos de la tarjeta mide ~210 px
   y la línea entera no cabe. Así que cuando hay oferta la LÍNEA puede saltar y
   cada PIEZA no —el resaltado ya trae su propio nowrap—. */
.fv2-recambio__precio:has(.fv2-precio__oferta) { white-space: normal; }
.fv2-recambio__precio .woocommerce-Price-amount { white-space: nowrap; }

.fv2-recambio__precio .fv2-precio__oferta {
  margin-left: 8px;
  padding: 3px 6px;
  gap: 5px;
  font-size: 11px;
  vertical-align: 0.24em;
}

/* Solo el botón, centrado en su celda: sin los chips dentro ya no hay hueco
   muerto que rellenar. */
.fv2-recambio__acciones {
  grid-area: acciones;
  display: flex;
  align-items: center;
  justify-content: stretch;
}

@media (min-width: 1000px) {
  .fv2-recambio__acciones { justify-content: flex-end; }
}

.fv2-recambio__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
}

.fv2-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  border: 1px solid var(--fv2-borde);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--fv2-gris-txt);
  white-space: nowrap;
  cursor: pointer;
}

.fv2-chip:hover { border-color: #c9c9c9; color: #1a1a1a; }
.fv2-chip:focus-visible { outline: 2px solid var(--fv2-rojo); outline-offset: 2px; }

/* N1 (FIX-FICHA-14) · EL ÚNICO SITIO DONDE EL ANILLO SE APAGA, Y CON SUSTITUTO.
   El <dialog> nativo devuelve el foco al chip cuando se cierra, y el navegador
   marca esa devolución como foco de TECLADO aunque haya venido de un ratón: por
   eso el chip se quedaba con recuadro rojo después del clic. Esta clase la pone
   assets/js/fv2-nucleo.js solo en ese caso, y la quita en cuanto se pulsa una
   tecla o el foco se va. Con Tab el anillo sigue apareciendo siempre — no hay
   `outline: none` que valga sin eso. */
.fv2-sin-anillo:focus-visible { outline: none; }

/* En móvil el botón de compra va a lo ancho (corrección C3). */
.fv2-recambio .fv2-compractl { --fv2-alto: 48px; width: 100%; }
.fv2-recambio .fv2-compractl .fv2-btn { width: 100%; }

@media (min-width: 1000px) {
  .fv2-recambio .fv2-compractl { width: auto; justify-content: flex-end; }
  .fv2-recambio .fv2-compractl .fv2-btn { width: auto; min-width: 190px; }
}

/* =========================================================================
   7) MODALES DE LOS CHIPS DE RECAMBIO (G7)
   =========================================================================
   Se usa el <dialog> nativo y no un div con clases: Esc, el foco atrapado
   dentro, el fondo inerte y la capa oscura los pone el navegador, y son justo
   las cuatro cosas que salen mal cuando se reimplementa una modal a mano. Sin
   librerías nuevas, que era la condición.
   El estilo es el del sistema: blanco, título en Barlow Semi Condensed con el
   subrayado rojo de las secciones, y la X arriba a la derecha. */

.fv2-modal {
  /* A4: la ventana crece de 720 a 920 px porque ahora lleva dentro la tarjeta de
     recambio entera —foto, datos y botón en tres columnas—, que a 720 salía
     apretada contra los bordes. */
  width: min(920px, calc(100vw - 32px));
  max-height: 84vh;
  margin: auto;
  padding: 24px;
  border: 0;
  background: #fff;
  color: #1a1a1a;
  font-family: var(--fv2-cuerpo);
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.25);
  overflow: auto;
  overscroll-behavior: contain;
}

.fv2-modal::backdrop { background: rgba(0, 0, 0, 0.55); }

.fv2-modal__cab {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}

.fv2-modal__titulo {
  margin: 0;
  font-family: var(--fv2-titulos);
  font-weight: 600;
  font-size: 26px;
  line-height: 1.15;
  text-transform: uppercase;
  color: #111;
}

.fv2-modal__titulo > span {
  display: inline;
  border-bottom: 3px solid var(--fv2-rojo);
  padding-bottom: 6px;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

.fv2-modal__x {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  margin: -8px -8px 0 0;
  border: 0;
  background: none;
  font-family: var(--fv2-cuerpo);
  font-size: 26px;
  line-height: 1;
  color: #6e6e6e;
  cursor: pointer;
}

.fv2-modal__x:hover { color: #111; }
.fv2-modal__x:focus-visible { outline: 2px solid var(--fv2-rojo); outline-offset: 2px; }

/* De qué recambio se está hablando: la modal se abre desde una tarjeta entre
   varias y sin esta línea no hay forma de saber cuál. */
.fv2-modal__sujeto {
  margin: 16px 0 0;
  font-size: 13px;
  line-height: 1.4;
  color: var(--fv2-gris-txt);
}

.fv2-modal__cuerpo > .fv2-h3:first-child { margin-top: 22px; }

/* H3 · ESTADO DE CARGA. El contenido de la modal ya no viene horneado en la
   página: se pide al abrirla. Este aviso está en el HTML de la carcasa —no lo
   inyecta el JS— porque es lo primero que se ve, y va con `min-height` para que
   la ventana no dé un salto de alto cuando llega el contenido de verdad.
   Es el ÚNICO estado que se pinta: si el fetch falla no hay mensaje de error,
   porque el chip es un enlace y el fallback es navegar a la ficha. */
.fv2-modal__cargando {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 120px;
  margin: 22px 0 0;
  font-size: 14px;
  color: var(--fv2-gris-txt);
}

/* A4 · DENTRO DE LA MODAL VA LA MISMA TARJETA DE RECAMBIO.
   Aquí vivía un juego de mini-tarjetas propias (`.fv2-mini*`): foto y nombre para
   «Repuestos donde va», y una variante con precio y botón para «Ver recambios».
   Eran un segundo lenguaje para la misma cosa —el mismo producto se veía de dos
   maneras según dónde saliera— así que se retiran enteras y las modales usan
   `.fv2-recambio`, la de la sección. Lo único que cambia es el ancho: dentro de
   una modal la columna de acciones no necesita sus 220 px mínimos.
   El CSS retirado no lo pinta ya nadie: ninguna plantilla emite `fv2-mini`. */
.fv2-recambios--modal .fv2-recambio {
  padding: 12px;
}

@media (min-width: 1000px) {
  .fv2-recambios--modal .fv2-recambio {
    grid-template-columns: 120px minmax(0, 1fr) minmax(170px, auto);
    gap: 16px;
  }

  .ficha-v2 .fv2-recambios--modal .fv2-recambio__img { height: 92px; }

  .woocommerce .ficha-v2 .fv2-recambios--modal .fv2-compractl form.cart button.single_add_to_cart_button,
  .fv2-recambios--modal .fv2-recambio .fv2-compractl .fv2-btn { min-width: 150px; }

  .ficha-v2 .fv2-recambios--modal .fv2-recambio .fv2-compractl form.cart { min-width: 170px; }
}

/* La tabla de modelos dentro de la modal no tiene la columna «TU MOTO»: ahí no
   hay contexto de moto que resaltar. Se le devuelve su ancho al modelo. */
.fv2-modal .fv2-compat__fila,
.fv2-modal .fv2-compat__cab { grid-template-columns: 1fr auto; }

/* M5.4 (FIX-FICHA-13) · LA COLUMNA «NOTAS» TAMBIÉN CABE AQUÍ, Y ESTÁ MEDIDO.
   La ventana es `min(920px, 100vw - 32px)` con 24 px de padding a cada lado: 872 px
   de caja interior en escritorio. Las columnas fijas suman 110 + 84 + 170 = 364, más
   3 huecos de 16 = 412. Al modelo le quedan 460 px — más que los 407 que recibe en
   la tabla de la ficha, que es la ancha. O sea: la modal no solo lo permite, va más
   holgada que la propia sección. No se queda apilada.
   Los anchos de «Años» y «Notas» son los MISMOS que en la ficha a propósito: es el
   mismo componente y no puede medir distinto según dónde salga. Lo único que cambia
   es la marca (110 en vez de 120, como ya venía) y la ausencia de «TU MOTO». */
@media (min-width: 1000px) {
  .fv2-modal .fv2-compat__fila,
  .fv2-modal .fv2-compat__cab {
    grid-template-columns: 110px minmax(0, 1fr) 84px 170px;
    grid-template-areas: 'marca modelo years notas';
  }

  /* La modal tiene su PROPIO punto de corte, y por eso no espera al 1240 de la
     ficha: su caja no depende del reparto de dos columnas de la página —es
     `min(920px, 100vw - 32px)`—, así que ya en una ventana de 1000 px dispone de
     872 px y las cuatro columnas caben con 460 px para el modelo. Hacerla esperar
     al 1240 sería apagar una columna que ahí sí cabe. */
  .fv2-modal .fv2-compat__cab {
    display: grid;
  }

  /* N5 · la forma sin notas, también dentro de la modal. Va explícita porque
     `.fv2-modal .fv2-compat__fila` pesa lo mismo (0,2,0) que la regla genérica de
     `--sinnotas` y se escribe después: sin esta, la modal seguiría reservando la
     columna «Notas» de una tabla que no tiene ninguna. Caja interior 872 px menos
     110 + 130 + 2 huecos de 16 = 272 -> 600 px para el modelo. */
  .fv2-modal .fv2-compat--sinnotas .fv2-compat__fila,
  .fv2-modal .fv2-compat--sinnotas .fv2-compat__cab {
    grid-template-columns: 110px minmax(0, 1fr) 130px;
    grid-template-areas: 'marca modelo years';
  }
}

/* =========================================================================
   CP-GALERIA · P3 · EN MÓVIL LA MODAL ES UNA HOJA INFERIOR
   =========================================================================
   LO QUE HABÍA: `100vw x 100dvh` a partir de 699 px hacia abajo. Es decir, una
   pantalla completa opaca — y una pantalla completa no se distingue de haber
   NAVEGADO. Al abrir un chip desaparecía el sitio entero y no quedaba ninguna
   pista de que se seguía en la misma página; la única salida visible era la X,
   y quien no la encontrara pulsaba «atrás» y se iba de la ficha.

   LO QUE HAY: una hoja que sube desde abajo y deja ver lo que hay detrás.
     · `92dvh` de alto máximo: el 8 % restante es la franja de fondo oscurecido
       que se ve por arriba, y es ella la que dice «esto está ENCIMA de la
       página». No es decoración: es la afordancia de cerrar tocando fuera.
     · Esquinas superiores redondeadas — el gesto de la hoja.
     · `margin: auto auto 0` la pega abajo. El <dialog> modal trae del navegador
       `position: fixed; inset: 0; margin: auto`; con `bottom: 0` en el margen, el
       reparto vertical deja de estar centrado y toda la holgura se va arriba.
     · `height: fit-content`, y NO `auto`: una modal con dos filas no tiene por qué
       ocupar media pantalla. Con `auto` no basta —medido: la hoja de un recambio
       salía igualmente a 776 px con el contenido ocupando un tercio—, porque el
       <dialog> modal viene del navegador con `position: fixed; inset: 0`, y ahí un
       alto automático entre un `top: 0` y un `bottom: 0` se resuelve a la ventana
       entera. Con `fit-content` el alto sale del contenido, el `max-height` lo
       acota y el margen automático de arriba se queda con lo que sobre.

   EL CORTE PASA DE 699 A 999,98. La ficha entera cambia de una columna a dos en
   1000 (assets/css/ficha-v2.css), y entre 700 y 999 la modal era la ventana
   centrada de escritorio dentro de una página que ya se estaba maquetando como
   móvil. Ese hueco de 300 px era una tercera forma que nadie había decidido.
   ESCRITORIO NO CAMBIA: todo lo de arriba sigue igual y esto vive dentro de una
   media query que allí no aplica. */
@media (max-width: 999.98px) {
  .fv2-modal {
    width: 100vw;
    max-width: 100vw;
    height: fit-content;
    max-height: 92dvh;
    margin: auto auto 0;
    border-radius: 16px 16px 0 0;
    /* Sin padding ARRIBA: la cabecera pegajosa tiene que poder tocar el borde de
       la hoja, o al desplazar el contenido se colaría una rendija por encima de
       ella. El aire de arriba lo pone la propia cabecera. */
    padding: 0 16px 28px;
  }

  /* Más oscuro que en escritorio (0,55): aquí la franja de fondo es estrecha y
     tiene que leerse como «hay algo detrás», no como un borde gris. */
  .fv2-modal::backdrop {
    background: rgba(0, 0, 0, 0.68);
  }

  /* EL TÍTULO Y LA X, SIEMPRE A LA VISTA. Con la lista de modelos de un producto
     con treinta compatibilidades, la X se iba por arriba en el primer gesto y
     había que volver hasta el principio para cerrar. Pegada, la salida está
     donde el pulgar ya está.
     El fondo blanco es obligatorio, no estético: sin él, el contenido que pasa
     por debajo se lee a través de la cabecera. */
  .fv2-modal__cab {
    position: sticky;
    top: 0;
    z-index: 2;
    align-items: center;
    background: #fff;
    padding: 16px 0 10px;
    /* Se estira a los lados hasta el borde de la hoja para tapar también el aire
       lateral; el contenido de dentro se devuelve a su sitio con el padding. */
    margin: 0 -16px;
    padding-left: 16px;
    padding-right: 16px;
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08);
  }

  /* La agarradera de la hoja. Es un adorno con trabajo: es la señal universal de
     «esto se arrastra desde abajo», y va DENTRO de la cabecera pegajosa para que
     no se despegue de ella al desplazar. */
  .fv2-modal__cab::before {
    content: "";
    position: absolute;
    top: 6px;
    left: 50%;
    width: 38px;
    height: 4px;
    margin-left: -19px;
    border-radius: 2px;
    background: #d8d8d8;
  }

  .fv2-modal__titulo {
    font-size: 20px;
  }

  .fv2-modal__x {
    margin: 0 -8px 0 0;
  }
}

/* CP-GALERIA · P3 · Y EL FONDO NO SE MUEVE MIENTRAS LA HOJA ESTÁ ABIERTA.
   MEDIDO, no supuesto: con el <dialog> abierto por showModal() en Chrome 151, un
   `window.scrollTo(0, 800)` movió la página de 0 a 800 con la modal delante. El
   navegador hace inerte el fondo para el TECLADO y el ratón, pero no le quita el
   scroll. La clase la pone y la quita assets/js/fv2-nucleo.js.
   Va en <html> y no en <body>: es el elemento que desplaza el documento, y
   ponerlo en body deja el scroll intacto en este tema.

   SOLO EN MÓVIL, y por eso el candado es una media query y no un `if` del script:
   en escritorio la barra de scroll ocupa sitio, y quitarle el scroll al documento
   la haría desaparecer — la página entera daría un salto lateral de 15 px al abrir
   cada modal. P3 dice que escritorio no cambia, y esta es una de las formas en que
   podría haber cambiado sin querer. El JS se limita a decir «hay una modal
   abierta»; DÓNDE eso significa algo lo decide esta hoja, igual que con el resto
   de los anchos. */
@media (max-width: 999.98px) {
  html.fv2-modal-abierta {
    overflow: hidden;
  }
}

