/**
 * Personalización en la ficha de producto.
 *
 * La @font-face carga el MISMO TTF que usa el render del servidor. Si aquí se sirve
 * otra tipografía, la previsualización miente.
 *
 * ---------------------------------------------------------------------------
 * El resto del archivo es presentación de la ficha personalizable, no lógica.
 *
 * Todo lo que va aquí y no en el theme tiene el mismo motivo: el mu-plugin pinta
 * el campo, el canvas y la casilla de confirmación en un solo bloque enganchado a
 * `woocommerce_before_add_to_cart_button`, así que esos tres elementos no llevan
 * clases del theme y no hay forma de dárselas desde Blade. Lo que sí se puede es
 * colocarlos: el <form> de compra es la rejilla y `display: contents` reparte los
 * hijos del bloque de personalización entre las dos columnas.
 *
 * Todos los colores salen de los tokens --3s-* de app.css. Ni un valor literal:
 * si se escribiera un color a pelo, ese trozo dejaría de tener modo oscuro y
 * nadie lo notaría hasta verlo de noche.
 *
 * Esta hoja se encola solo en fichas de producto personalizable, así que nada de
 * lo de aquí puede afectar al resto del sitio.
 */

@font-face {
  font-family: 'Soletes Placa';
  src: url('fonts/placa.ttf') format('truetype');
  font-weight: 700;
  font-display: swap;
}

/* ==========================================================================
   1. El bloque de personalización, pieza a pieza

   Los selectores llevan un ancestro propio y `.form-row.soletes-perso__x` a
   propósito. El campo vive dentro de `.soletes-perso`; la confirmación, dentro
   de `.pdp-buy--perso` porque su posición en el DOM coincide con la cantidad.
   El marcado del mu-plugin usa la clase `form-row` de WooCommerce y el <body>
   lleva la clase `woocommerce`, así que reglas como
   `.woocommerce form .form-row label { display: block }` (0,2,1) le caen encima.
   Esta hoja se imprime ANTES que la de WooCommerce, así que empatar en
   especificidad no basta: hay que subir un peldaño. Con especificidad, nunca
   con !important, que además desactivaría el modo oscuro en el componente sin
   que nadie lo note hasta verlo de noche.

   Lo correcto de verdad es desencolar `woocommerce-general`, `-layout` y
   `-smallscreen` y reconstruir el cromo con los tokens del theme (§11 de la
   especificación). Eso vive en app/setup.php del theme, fuera de esta hoja.
   ========================================================================== */

/* El contenedor del campo no necesita el padding ni el margen de Woo: la
   separación entre bloques la reparte la rejilla del formulario. */
.soletes-perso .form-row.soletes-perso__field,
.pdp-buy--perso .form-row.soletes-perso__confirm {
  padding: 0;
  margin: 0;
}

.soletes-perso .form-row.soletes-perso__field label {
  display: block;
  line-height: 1.35;
  font-variation-settings: 'wght' 600;
  margin-bottom: 0.4rem;
}

/* 17px: por debajo de 16px iOS hace zoom al enfocar el campo. */
.soletes-perso .form-row.soletes-perso__field input[type='text'] {
  width: 100%;
  min-height: 3rem;
  font-size: 1.0625rem;
}

/* Tabular para que el contador no baile al escribir. */
.soletes-perso__counter {
  display: block;
  margin-top: 0.4rem;
  font-size: var(--3s-text-sm);
  color: var(--3s-fg-muted);
  font-variant-numeric: tabular-nums;
}

/* El error es un bloque completo con filete, no texto suelto de color: el color
   no puede ser la única señal. Misma forma que .notice--error de app.css, que no
   se puede reutilizar porque el marcado lo pinta PHP sin esa clase. */
.soletes-perso__error:not([hidden]) {
  display: block;
  margin-top: 0.6rem;
  padding: 0.7rem 0.85rem;
  background: var(--3s-danger-bed);
  border-left: 3px solid var(--3s-danger);
  border-radius: 0 var(--3s-radius-sm) var(--3s-radius-sm) 0;
  color: var(--3s-danger);
  font-size: var(--3s-text-sm);
  line-height: 1.5;
}

/* Aviso sobre desistimiento en personalizados. No es una casilla suelta al pie: es un bloque de aviso
   completo, inmediatamente encima del botón de compra y visible sin desplegar
   nada. Es requisito legal (los bienes personalizados quedan fuera del derecho
   de desistimiento) y además el bloque que más soporte ahorra. */
.pdp-buy--perso .form-row.soletes-perso__confirm {
  padding: 0.9rem 1rem;
  background: var(--3s-warn-bed);
  border-left: 3px solid var(--3s-accent);
  border-radius: 0 var(--3s-radius-sm) var(--3s-radius-sm) 0;
  color: var(--3s-warn);
  font-size: var(--3s-text-sm);
  line-height: 1.5;
}

.pdp-buy--perso .form-row.soletes-perso__confirm label {
  display: flex;
  gap: 0.75rem;
  align-items: flex-start;
  min-height: 44px;
  line-height: 1.5;
  cursor: pointer;
}

/* La regla base de app.css da a todo input 3rem de alto y padding, que en una
   casilla se ve como un rectángulo enorme. Se recupera el cuadro de 22px con
   área de toque de 44px por la etiqueta. */
.pdp-buy--perso .form-row.soletes-perso__confirm input[type='checkbox'] {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  min-height: 22px;
  margin: 0.15rem 0 0;
  padding: 0;
  border: 2px solid var(--3s-border-ctrl);
  border-radius: var(--3s-radius-xs);
  accent-color: var(--3s-action);
}

/* ==========================================================================
   2. El canvas es el héroe

   El contenedor del canvas recibe la clase `canvas-stage` desde la plantilla
   (partials/product/buy-form.blade.php), así que la isla de luz —fondo blanco,
   color-scheme: light, sombra de prueba de imprenta— vive una sola vez, en
   app.css. Aquí solo se coloca y se ajusta a la pantalla.

   REGLA DURA: dentro del escenario no entra ningún filter, ningún
   mix-blend-mode y ningún cambio de tema. El canvas es una prueba de impresión,
   no un componente de interfaz: en modo oscuro sigue siendo blanco, y es
   deliberado.
   ========================================================================== */

/* EL CANVAS YA NO SE PEGA, Y NO ES UNA RENUNCIA ESTÉTICA: PEGADO, TAPABA EL
   BOTÓN DE COMPRAR.

   La idea era buena —el canvas fijo bajo la cabecera mientras el pulgar escribe—
   pero `position: sticky` no sabe dónde parar. El bloque contenedor del canvas
   es el `form.cart` entero, que en móvil llega hasta los plazos de envío, así
   que el escenario —fondo blanco opaco, z-index 3— se deslizaba por encima de
   color, talla, cantidad, la casilla de confirmación y el botón.

   Medido a 500 px con Chrome, con el botón centrado en pantalla:
   `document.elementFromPoint()` en el centro de «Afegir a la cistella» devolvía
   el CANVAS, no el botón. En un móvil eso es una tienda en la que no se puede
   comprar el único producto personalizable: el dedo toca la previsualización.

   No hay forma de acotar el recorrido de un sticky solo con CSS —haría falta un
   envoltorio en el DOM alrededor del campo y del canvas, y ese envoltorio hoy es
   `display: contents` porque es lo que permite ordenar las piezas en móvil y
   repartirlas en dos columnas en escritorio—. Mientras no exista ese
   envoltorio, el canvas se desplaza con la página: se ve menos rato, pero no
   esconde nada.

   PENDIENTE (no es de superficie): si se quiere recuperar el canvas fijo, hay
   que envolver campo + canvas en un solo bloque y pegar el bloque, no la pieza.
*/

/* Sin esto el canvas se come la pantalla en móvil y el campo del nombre queda
   fuera de vista, que es justo lo contrario de lo que se busca. El fondo del
   escenario ya es blanco, así que el ajuste no deja franjas visibles. */
@media (max-width: 63.999rem) {
  .pdp-buy--perso .canvas-stage canvas {
    max-height: 40vh;
    object-fit: contain;
  }
}

.pdp-stage-label {
  margin: 0;
}

.pdp-stage-foot {
  margin: 0;
}

/* ==========================================================================
   3. La rejilla de la ficha personalizable

   El <form> de compra es la rejilla. `display: contents` sobre el bloque de
   personalización sube sus tres hijos —campo, canvas y casilla— a esa rejilla,
   que es lo que permite que el canvas viva en una columna y el formulario en la
   otra sin tocar el PHP que los pinta juntos.
   ========================================================================== */

/* El hueco sale de --3s-buy-gap, el token del theme (app.css, «Densidad»). Es
   el mismo que usa la ficha NO personalizable, y por eso las dos se leen igual.
   El valor de reserva es el que tenía escrito aquí: si esta hoja se sirviera
   sin el theme, el formulario sigue teniendo aire. */
.pdp-buy--perso form.cart {
  display: flex;
  flex-direction: column;
  gap: var(--3s-buy-gap, 1.25rem);
}

.pdp-buy--perso .soletes-perso {
  display: contents;
}

/* Móvil: una columna. El orden visible coincide con el DOM y con los pasos de
   la cabecera: escribir, comprobar, elegir, confirmar y comprar. */
.pdp-buy--perso .pdp-stage-label           { order: 1; }
.pdp-buy--perso .soletes-perso__field      { order: 2; }
.pdp-buy--perso .soletes-perso__preview    { order: 3; }
.pdp-buy--perso .pdp-stage-foot            { order: 4; }
.pdp-buy--perso .pdp-options               { order: 5; }
.pdp-buy--perso .quantity                  { order: 6; }
/* El aviso sobre desistimiento va inmediatamente encima del botón. Es requisito
   legal y es el bloque que más soporte ahorra: nada se cuela entre los dos. */
.pdp-buy--perso .soletes-perso__confirm    { order: 7; }
.pdp-buy--perso .single_add_to_cart_button { order: 8; }
.pdp-buy--perso .pdp-plazos                { order: 9; }

.pdp-buy--perso .quantity {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.pdp-buy--perso .quantity input.qty {
  width: 6rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* Escritorio: 7/5. El canvas a la izquierda, pegado mientras se recorren color,
   talla, aviso y botón.

   La columna del canvas abarca de `field` a `action`, no menos: un elemento que
   abarca varias filas reparte su altura sobrante entre ellas, así que si
   abarcase solo tres, la altura del canvas abriría huecos entre el campo, las
   opciones y el aviso. Con cinco filas, canvas y columna derecha miden casi lo
   mismo y no se estira nada.

   Cada pieza lleva `form.cart` en el selector a propósito: la regla escoba de
   más abajo es `.pdp-buy--perso form.cart > *` (0,2,1) y sin ese peldaño de más
   ganaría ella y todo caería en la columna 2. La escoba existe para que una
   pieza nueva —otro plugin enganchado al mismo hook— no se cuele en la columna
   del canvas. */
@media (min-width: 64rem) {
  .pdp-buy--perso form.cart {
    display: grid;
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    grid-template-areas:
      'label .'
      'stage field'
      'stage options'
      'stage qty'
      'stage confirm'
      'stage action'
      'foot  terms';
    column-gap: clamp(1.5rem, 1rem + 2.5vw, 3.5rem);
    row-gap: var(--3s-buy-gap, 1.25rem);
    align-items: start;
  }

  .pdp-buy--perso form.cart > *,
  .pdp-buy--perso form.cart .soletes-perso > * {
    grid-column: 2;
  }

  .pdp-buy--perso form.cart .pdp-stage-label           { grid-area: label; }
  .pdp-buy--perso form.cart .pdp-stage-foot            { grid-area: foot; }

  /* En escritorio el canvas tampoco se pega: pegado, tapaba su propio pie. El
     área `stage` abarca cinco filas y mide algo más que el canvas, así que
     `sticky` tenía ese sobrante como recorrido y el escenario bajaba sobre la
     fila `foot` y se comía la línea «Així es veurà · Ver a tamaño real».
     Medido a 1350px: 25 px de solape, con el texto cortado por la mitad.
     Aquí, además, no aportaba nada: con las cinco filas las dos columnas ya
     miden casi lo mismo y el canvas se ve entero sin desplazar. */
  .pdp-buy--perso form.cart .soletes-perso__preview {
    grid-area: stage;
  }
  .pdp-buy--perso form.cart .soletes-perso__field      { grid-area: field; }
  .pdp-buy--perso form.cart .pdp-options               { grid-area: options; }
  .pdp-buy--perso form.cart .soletes-perso__confirm    { grid-area: confirm; }
  .pdp-buy--perso form.cart .quantity                  { grid-area: qty; }
  .pdp-buy--perso form.cart .single_add_to_cart_button { grid-area: action; }
  .pdp-buy--perso form.cart .pdp-plazos                { grid-area: terms; }
}

/* La impresión la decide app.css, que oculta form.cart entera: el albarán no
   necesita el formulario de compra. No se contradice desde aquí. */

/* ==========================================================================
   4. M9 — el asentamiento del canvas (MOVIMIENTO.md y §10.4 de DISENO.md)

   Al escribir, el lienzo baja de golpe a la opacidad de suelo y vuelve a 1 en
   120 ms. Se lee como algo que se imprime, no como algo que se teclea.

   Vive aquí y no en app.css porque el canvas es del mu-plugin: el theme no
   puede tener una segunda fuente de verdad sobre él.

   REGLA DURA: dentro de .canvas-stage no se mueve NADA más. Ni la etiqueta, ni
   la pista, ni el botón de tamaño real, ni el chip de la placa. Y sólo se toca
   la opacidad: cero filtros, cero mezclas, cero recorridos. Un lienzo que se
   desplaza o se escala mientras el ojo compara el nombre con la placa es
   exactamente lo contrario de una prueba de imprenta.

   Se declara dentro de `no-preference`: con la preferencia de movimiento
   reducido activada, la regla no llega a existir y el atributo que escribe el
   JavaScript no pinta nada.

   La bajada es instantánea (la regla del atributo anula la transición) y sólo
   se anima la vuelta: 120 ms en total, no 240.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  .canvas-stage canvas {
    transition: opacity var(--3s-settle, 120ms) var(--3s-ease, ease-out);
  }

  .canvas-stage canvas[data-settling] {
    opacity: var(--3s-settle-floor, 0.82);
    transition: none;
  }
}
