/* Rompecabezas — estilos del PLAYER. Contrato (docs/estilos-de-actividad.md):
   NADA con tamaño fijo (cq*/% o piso max(); un clamp con techo bajo CONGELA) y
   colores pintables por token var(--ww-*) para que los skins recoloreen. La
   IMAGEN es DATO (llega inline por JS como data: URL, igual que las bolas de
   Pelotas) — este CSS no nombra ni un solo color del dibujo. */

.pu-play {
  display: flex; flex-direction: column; height: 100%; gap: 2cqmin;
  /* CONTENEDOR DE TAMAÑO: todo lo que mide el juego sale de UN número, el LADO
     del tablero (`--pu-lado`, que calcula `.pu-arena`), y la pieza es una
     FRACCIÓN DE CELDA, nunca una fracción del ancho de la página: en pantalla
     completa (1515×1023) un `90cqw/total` daba piezas de 430 px que se comían
     el tablero (captura del dueño, v1.51.668). El reparto exacto —cuánto del
     alto es del tablero y cuánto de la bandeja— ya no es un porcentaje fijo:
     sale de la cuenta de `.pu-arena`. */
  container-type: inline-size;
}

/* LA CADENA (lección de `styles/ballsort.css`): cabecera (lo suyo) · tablero
   (`flex:1 1 auto; min-height:0`, ESTIRA) · bandeja (`flex:0 0 auto`, hug de
   su contenido). Cada eslabón que no declara su parte de la cadena hace que
   el siguiente mida mal: el tablero era un `100cqh` medido contra el MARCO
   ENTERO (la única consulta de bloque válida más arriba era la del widget,
   porque el propio `.pu-arena` no era contenedor de nada) — así que el
   cuadrado salía más alto que su propio hueco, se metía bajo la cabecera por
   arriba y pisaba la bandeja por abajo. `.pu-arena` es AHORA su propio
   contenedor de tamaño (`container-type: size`, válido porque su alto lo da
   el flex del padre, no su contenido — el mismo truco de
   `#ww-player-widget` en `styles/player.css`), así que el `100cqh` del
   tablero mide el hueco REAL que le queda tras restar cabecera y bandeja. */
.pu-arena {
  flex: 1 1 auto; min-height: 0;
  /* UN contenedor de tamaño para tablero Y bandeja: su alto lo da el flex de la
     columna (definido), así que `cqh`/`cqw` son estables y NADA depende de lo
     que pinte dentro — sin JS y sin repintar.

     EL LADO DEL TABLERO SALE DE LA BANDEJA, no al revés (v1.51.718). La pieza
     suelta medía la MITAD de su hueco en escritorio y un tercio en móvil
     (medido: 117 px contra 234; 64 contra 191), y el dueño lo dijo en una
     frase: «las piezas no están del mismo tamaño que donde encajan». En un
     rompecabezas eso no es un detalle de maquetación: comparar la pieza con el
     hueco ES el juego. Así que las piezas van a tamaño 1:1 y el tablero ocupa
     lo que quede.

     UNA PIEZA TIENE DOS MEDIDAS Y NO SON LA MISMA. El tablero es CUADRADO y la
     rejilla no tiene por qué serlo: con `c` columnas y `f` filas, la celda mide
     `lado/c` de ancho y `lado/f` de alto. Así que la caja de la pieza vale
     `kx = caja/c` en tableros de ancho y `ky = caja/f` de alto. Con `F` filas y
     `C` por fila de bandeja, el tablero cabe si:
       lado ≤ 100cqw / (C · kx)        (la fila más ancha de la bandeja)
       lado ≤ 100cqh / (1 + F · ky)    (tablero y bandeja apilados)
     Las dos van en un `min()`: una cuenta, sin medir nada en JS.

     AQUÍ HABÍA UN SOLO `k`, el de ancho, usado TAMBIÉN para el presupuesto de
     alto. Con rejilla cuadrada (3×3, que es como nace) los dos valen lo mismo y
     no se notaba nada; con «6 piezas» (2×3) el alto de la bandeja se calculaba
     un 50 % más pequeño de lo que ocupa, la columna se desbordaba y quien cedía
     era el tablero: 385×116 px con piezas de 205×308 — más altas que el tablero
     entero (medido, v1.51.733; el dueño: «los tamaños no corresponden, y en
     pantalla completa la diferencia es muchísimo mayor»). La red de la matriz no
     lo veía porque derivaba el hueco de estas mismas variables: comparaba la
     cuenta consigo misma, y solo en 3×3. */
  container-type: size;
  /* LO QUE CUESTA REPARTIR, contado y no estimado. Estos tres números son los
     MISMOS que usa la bandeja más abajo (por eso viven aquí y no ahí): si la
     cuenta y la maquetación no comparten el número, la cuenta habla de una
     bandeja que no existe. Antes el presupuesto restaba `2cqmin` de ancho y
     `4cqmin` de alto —dos cifras a ojo— mientras la bandeja gastaba
     `(por_fila − 1) · gap + 2 · padding`: con 4 piezas en escritorio las cuatro
     pedían EXACTAMENTE el ancho disponible, los huecos no cabían, `flex-wrap`
     bajaba una a una segunda fila que nadie había presupuestado y esa fila se
     salía del marco hasta 111 px (medido, v1.51.735). */
  --pu-gap: max(2px, .6cqmin);
  --pu-pad: max(4px, 1cqmin);
  --pu-hueco: 2cqmin;            /* el aire entre el tablero y la bandeja */
  --pu-kx: calc(var(--pu-caja) / var(--pu-columnas, 2));
  --pu-ky: calc(var(--pu-caja) / var(--pu-filas, var(--pu-columnas, 2)));
  --pu-lado: min(
    calc((100cqw - (var(--pu-por-fila, 1) - 1) * var(--pu-gap) - 2 * var(--pu-pad))
         / (var(--pu-por-fila, 1) * var(--pu-kx))),
    calc((100cqh - var(--pu-hueco) - (var(--pu-filas-bandeja, 1) - 1) * var(--pu-gap) - 2 * var(--pu-pad))
         / (1 + var(--pu-filas-bandeja, 1) * var(--pu-ky)))
  );
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--pu-hueco);
}
/* EN VERTICAL la bandeja se reparte en más filas: con la de apaisado (hasta 5
   por fila) el tablero se quedaba en 146 px en un móvil. El player declara las
   dos repartos y aquí se elige el que toca — el CSS sabe la forma del hueco,
   el JS sabe cuántas piezas hay. */
@container (max-aspect-ratio: 1/1) {
  .pu-arena {
    --pu-por-fila: var(--pu-por-fila-v);
    --pu-filas-bandeja: var(--pu-filas-bandeja-v);
  }
}
.pu-board {
  position: relative;
  /* `flex: 0 0 auto` — el tablero NO se encoge. Es un item de la columna y sin
     esto `flex-shrink` valía 1: en cuanto la cuenta de arriba se quedaba corta,
     el que cedía era él (la bandeja ya declara `0 0 auto`), y un tablero
     aplastado deja de ser cuadrado — con lo que ninguna celda mide lo que la
     pieza cree que mide. Que no ceda convierte un error de cuenta en algo que
     se VE (desborda) en vez de en una deformación silenciosa. */
  flex: 0 0 auto;
  width: var(--pu-lado);
  aspect-ratio: 1 / 1;
  border-radius: max(6px, 1.5cqmin);
  overflow: hidden;
  background: var(--ww-card-bg, var(--ww-bg));
  box-shadow: 0 0 0 max(1px, .25cqmin) var(--ww-border, rgba(0,0,0,.15)) inset;
}
.pu-ghost {
  position: absolute; inset: 0;
  background-image: var(--pu-img);   /* la imagen, escrita UNA vez por el player */
  background-repeat: no-repeat;
  background-size: 100% 100%;
  /* LA PISTA. A .32 el fantasma y las piezas parecían dos dibujos distintos
     (el dueño: «no se ve que es el mismo»); a .5 se lee como el mismo dibujo
     apagado, y la pieza puesta encima sigue destacando porque va al 100 %. */
  opacity: .5;
  pointer-events: none;
}
/* LOS HUECOS NO SE DIBUJAN (ni existen en el DOM). Una rejilla discontinua
   encima del fantasma troceaba la pista en nueve cajas y el niño buscaba «la
   caja», no «el trozo del dibujo»; y el «hueco destino» que el CSS prometía
   nunca lo marcaba nadie (§31). La pista es el fantasma, y basta. */

/* LA BANDEJA — piezas barajadas alrededor del tablero (norte: «repartidas
   alrededor»). `flex: 0 0 auto`: HUG de su contenido — la bandeja mide lo que
   miden sus piezas, nunca al revés. Antes tenía un `flex-basis` fijo del 30 %
   y las piezas se apretaban a lo que cupiera en ESE hueco (55 px en 3×3 sobre
   1000 px: 7,8 % del lado corto, menos que el 12 % mínimo táctil del plan).
   Hoy la pieza mide EXACTAMENTE su hueco del tablero (`--pu-lado · --pu-kx`) y
   el tamaño táctil se cuida al revés: el tablero se presupuesta para que las
   piezas quepan a ese tamaño, y la matriz mide el objetivo más pequeño contra
   el lado corto del marco. No hay piso `12cqw` en el CSS —lo hubo— y el reparto
   ya no lo decide `flex-wrap`: ver la cuadrícula de abajo. */
.pu-pieces {
  flex: 0 0 auto;
  /* SIN `container-type` propio: su alto es CONTENIDO (lo miden sus piezas),
     así que no puede ser contenedor de tamaño de sí mismo (ciclo). Las `cq` de
     lo que hay dentro caen en `.pu-arena`, que sí lo es. */
  /* CUADRÍCULA EXPLÍCITA, no `flex-wrap`. El reparto (`--pu-por-fila` ×
     `--pu-filas-bandeja`) entra en el presupuesto de `--pu-lado`, así que con
     `flex-wrap` era una PREDICCIÓN: el navegador decidía por su cuenta cuántas
     filas hacía y, cuando no coincidía, la cuenta seguía siendo correcta sobre
     una bandeja imaginaria. Medido en v1.51.735, no coincidía casi nunca: 4
     piezas presupuestaban 1 fila y salían 2; en móvil, 2 filas y salían 4; 9
     piezas presupuestaban 3 y salían 5. Con `repeat(var(--pu-por-fila), auto)`
     el número de columnas ES el declarado y las filas salen de dividir, así que
     la fórmula y lo que se ve comparten estructura en vez de parecerse.
     (Coste aceptado: si la última fila va incompleta, sus piezas quedan en sus
     columnas en vez de centradas bajo el resto. En una bandeja de piezas
     barajadas no molesta; un `justify-content` no lo arregla sin devolver la
     posición al navegador, que es lo que se acaba de quitar.) */
  display: grid;
  grid-template-columns: repeat(var(--pu-por-fila, 1), auto);
  justify-content: center; align-content: center;
  /* El hueco entre piezas es pequeño A PROPÓSITO: la caja ya lleva el aire
     de las lengüetas (TAB por lado), que separa los núcleos de sobra. Los DOS
     números salen de `.pu-arena`, que es quien los presupuesta. */
  gap: var(--pu-gap);
  padding: var(--pu-pad);
}
.pu-piece {
  /* EXACTAMENTE LO QUE MIDE SU HUECO: la celda del tablero más las lengüetas.
     El tablero ya está calculado para que quepan (ver `.pu-arena`), así que
     aquí no hay tope ninguno que negociar — antes había tres, y el resultado
     era una pieza a la mitad de su hueco. */
  width: calc(var(--pu-lado) * var(--pu-kx));
  /* La SOMBRA sigue al recorte: `box-shadow` pinta la caja cuadrada; `filter:
     drop-shadow` en la caja EXTERIOR (que no lleva clip) sigue la forma. Es
     ESTÁTICA (nunca se anima ni se transiciona: ley de animaciones). */
  filter: drop-shadow(0 max(2px, .5cqmin) max(3px, .8cqmin) rgba(0,0,0,.35));
  cursor: grab;
  touch-action: none; user-select: none; -webkit-user-select: none;
  will-change: transform;
}
/* LA FORMA: recortada por el <clipPath> de su contorno (objectBoundingBox,
   escala con la caja) y con la imagen ENTERA de fondo, desplazada a su celda
   (`background-size`/`-position` en %, calculados en game/contornos.js). */
.pu-piece__forma {
  width: 100%; height: 100%;
  background-image: var(--pu-img);
  background-repeat: no-repeat;
}
.pu-piece--arrastrando {
  cursor: grabbing;
  z-index: 20;
}
.pu-piece--volviendo { transition: transform 220ms ease; }
.pu-piece--fija {
  cursor: default;
  pointer-events: none;
  filter: none;
}
/* Las definiciones de los recortes no ocupan sitio en el tablero. */
.pu-clips { position: absolute; }

.pu-error {
  margin: auto;
  text-align: center;
  font-weight: 700;
  font-size: max(1rem, 3.6cqmin);
  color: var(--ww-fg);
  padding: 2cqmin;
}
