/* ==========================================================================
   Sproochegalerie — Hero

   Las coordenadas salen de los tres artboards del .ai: lienzo 361,411 × 650,54
   pt, cuerpo 88,5378, Sans Plomb Condensed Bold. El SVG usa ese lienzo como
   viewBox, así que cada número de acá abajo es literalmente el del diseño.

   Las palabras nunca desaparecen: son seis piezas fijas que se trasladan y
   giran entre las tres composiciones.
   ========================================================================== */

.hero {
  /* Mínima y no definida, a propósito. En pantallas altas el hero mide una
     pantalla exacta y el tablero se estira para llenarla. En pantallas bajas
     —por debajo de ~805px a 375 de ancho— el tablero reclama el alto que
     necesita para que la composición conserve sus proporciones, el hero crece
     con él y los botones quedan un poco abajo del pliegue. Es deliberado: la
     alternativa era que la composición se encogiera y se despegara de los
     márgenes laterales mientras la bajada y los botones siguen a ancho
     completo, que se leía como un error.
     `svh` porque en iOS `vh` cuenta la barra del navegador que después se va. */
  min-height: 100svh;
  display: flex;
  flex-direction: column;      /* tablero arriba, botones abajo */
  /* Sin aire arriba: la composición llega al borde de la pantalla y su propio
     margen —los ~15pt del artboard— es el que respira. El botón de menú flota
     encima, y el diseño ya lo tiene en cuenta: en las tres mesas el hueco de
     arriba a la derecha está libre. */
  padding: 0;
  overflow: hidden;
  position: relative;

  --dur-move: 1100ms;
  --dur-logo: 620ms;      /* el viaje del logo, en el hueco entre salida y entrada */
  --ease-move: cubic-bezier(0.4, 0.05, 0.25, 1);
}

/* Los tres pares del hero. La banda entera los hereda. */
/* El logo no participa de la rotación: va siempre en la esquina superior
   izquierda. Antes cambiaba de sitio en cada mesa —derecha en rojo, medio a la
   izquierda en avena— y era una pieza más de la composición; ahora es un punto
   fijo y lo que rota son sólo las palabras. Las coordenadas son las de la mesa
   lila, que es donde ya estaba arriba a la izquierda. */
.hero {
  --logo-x: 16.932px;
  --logo-y: 15.1px;
  --logo-dy: 0px;
  /* 0,220196 era la escala calcada del artboard, donde el logo era una pieza
     de la composición. Fijo en la esquina es una marca, no un elemento
     tipográfico: a esa escala pesaba como una palabra más. */
  --logo-escala: 0.132;
}

.hero[data-pair="lilac"] { --paper: var(--lilac);      --ink: var(--purple); }
.hero[data-pair="red"]   { --paper: var(--bright-red); --ink: var(--burgundy); }
.hero[data-pair="oat"]   { --paper: var(--oat);        --ink: var(--grey); }


/* --- El tablero ----------------------------------------------------------
   La cadena de alturas: .hero (flex column) -> .hero__claim (crece) ->
   .hero__stage (crece). Los `min-height: 0` son imprescindibles: sin ellos un
   ítem flex no baja de su alto de contenido, y el SVG impone el suyo por la
   proporción del viewBox — el hero se pasaba de la pantalla y los botones
   quedaban abajo del pliegue. */

.hero__claim {
  /* El piso de alto del tablero, en proporción a su ancho. 594 es 650,54 ×
     0,913: la compresión exacta a la que la composición está verificada —375
     x812, donde IS cae en el canto de OUR y OUR despeja PLAYGROUND por 21px—.
     Por debajo de ahí las palabras empiezan a pisarse: con 0,86 el pie de OUR
     ya cruzaba PLAYGROUND. Con este piso la composición se dibuja SIEMPRE en
     las proporciones en que fue ajustada; lo que cambia en pantallas bajas es
     cuánto hay que scrollear, no cómo se ve.

     Además, al no recortar nunca `vs`, el viewBox conserva la proporción del
     tablero y la composición llega a los dos márgenes del sitio.
     Va como `min-height` y no como `aspect-ratio`: con `aspect-ratio` el alto
     base lo terminaba fijando el alto intrínseco del SVG —la proporción de su
     viewBox inicial, 1,800— en vez de la razón pedida, y el piso quedaba en
     vs = 1,0. Entonces el hero scrolleaba hasta en pantallas altas. Con
     `min-height` el piso es el que dice el número y `flex: 1` deja que encoja
     hasta ahí y que crezca por encima. */
  /* La base del flex es el piso, no `auto`. Con `auto` la base la fija el alto
     intrínseco del SVG —la proporción de su viewBox, 675px a 375 de ancho—, el
     hero crece para contenerlo y nadie le pide nunca encoger: scrolleaba hasta
     en pantallas altas. Con la base en el piso, el contenido del hero mide
     776px a 375 de ancho, entra en una pantalla de 812 y el `flex-grow` estira
     el tablero para llenarla; en una de 667 no entra y el hero crece. */
  flex: 1 1 calc(100vw * 594.0 / 361.411);
  min-height: calc(100vw * 594.0 / 361.411);
  margin: 0;
  display: flex;
  font-size: inherit;
  /* La capa de cubos se posiciona contra esta caja. */
  position: relative;
}

.hero__stage {
  flex: 1;
  min-width: 0;
  min-height: 0;
  width: 100%;
  overflow: visible;
}

/* --- Las piezas -----------------------------------------------------------
   Cada una se coloca con `translate` + `rotate` sobre el origen del viewBox.
   La transición es la que hace viajar al logo entre composiciones; las letras
   no la usan, las anima la Web Animations API. */

.p {
  transform-box: view-box;
  transform-origin: 0 0;
  transition: transform var(--dur-move) var(--ease-move);
}

/* El escalonado hace que el grupo no se mueva en bloque: cada palabra sale un
   pelo después que la anterior y el conjunto se lee como una recomposición,
   no como un empujón. */
.p--logo     { transition-delay: 0ms; }
.p--language { transition-delay: 40ms; }
.p--is       { transition-delay: 80ms; }
.p--our      { transition-delay: 120ms; }
.p--play     { transition-delay: 160ms; }
.p--ground   { transition-delay: 0ms; }   /* viaja con PLAY, no por su cuenta */

.p--language, .p--is, .p--our, .p--play, .p--ground {
  font-family: var(--font-display-cond);
  font-weight: 700;
  font-size: 88.5378px;        /* el cuerpo del artboard, en unidades del viewBox */
  text-transform: uppercase;
  letter-spacing: -0.012em;    /* el tracking del .ai */
  fill: var(--ink);
}

.p--logo use { color: var(--ink); }

/* Colocación: cada pieza lee sus tres variables, que fija el layout activo. */
/* `--vs` estira las verticales para que la composición llene la pantalla: el
   artboard es 361×650 (más ancho de lo que es un teléfono), así que sin esto
   sobraba una banda muerta abajo. Lo calcula js/main.js con el alto real.
   Las horizontales no se tocan —el ancho ya coincide— y el desplazamiento
   interno de GROUND tampoco: es el avance de una palabra, no una distancia de
   la composición, y estirarlo abriría la palabra. */
/* `--*-dy` es un desplazamiento vertical que NO se estira con la pantalla: se
   usa para las distancias tipográficas —el interlineado de IS/OUR, el largo de
   una palabra girada— que no son medidas de la composición. Va sumado después
   del `* var(--vs)`, así que sobrevive al estirado. */
.p--logo     { transform: translate(var(--logo-x), calc(var(--logo-y) * var(--vs, 1) + var(--logo-dy, 0px))) scale(var(--logo-escala, 0.220196)); }
.p--language { transform: translate(var(--language-x), calc(var(--language-y) * var(--vs, 1) + var(--language-dy, 0px))) rotate(var(--language-r)); }
.p--is       { transform: translate(var(--is-x), calc(var(--is-y) * var(--vs, 1) + var(--is-dy, 0px))) rotate(var(--is-r)); }
.p--our      { transform: translate(var(--our-x), calc(var(--our-y) * var(--vs, 1) + var(--our-dy, 0px))) rotate(var(--our-r)); }
.p--play     { transform: translate(var(--play-x), calc(var(--play-y) * var(--vs, 1) + var(--play-dy, 0px))) rotate(var(--play-r)); }
/* GROUND cuelga de PLAY con un desplazamiento local, no con coordenadas
   propias. Con coordenadas propias la distancia entre las dos quedaba
   multiplicada por `--vs` —el estirado de la composición— y la palabra se
   abría: esa distancia es el avance de una palabra, no una medida del layout. */
.p--ground   { transform: translate(var(--ground-dx), var(--ground-dy)); }

/* --- La grilla ------------------------------------------------------------
   Los tres artboards comparten dos guías verticales: el contenido va de
   x = 14.674 a x = 346.285 sobre un lienzo de 361,411, o sea márgenes de ~15pt a cada
   lado. Se confirma solo: en la mesa roja IS y OUR ya caen exactamente en la
   guía derecha. Todo lo que toca un borde se alinea ahí. */

/* --- Layout A · mesa 18 (lila) ------------------------------------------- */

.hero[data-layout="a"] {
  /* LANGUAGE e IS bajan 26,6 en bloque respecto de la mesa. Quien manda es IS:
     su línea de base tiene que caer en el final de OUR (ver abajo). LANGUAGE
     lleva el mismo `dy` y no uno propio, que es lo que mantiene entre las dos
     el interlineado exacto del .ai —con `dy` distintos el par se desarma y
     LANGUAGE deja de leerse como el renglón de arriba—. Sin escalar, para que
     el desplazamiento sea el mismo en cualquier alto de pantalla. */
  --language-x: 90.855px; --language-y: 257.557px; --language-dy: 24.7px; --language-r: 0deg;
  /* IS no acompaña a LANGUAGE: su línea de base se alinea con el final de OUR.
     OUR va girada -90°, así que avanza hacia arriba —la O abajo, la R arriba— y
     la palabra termina en su canto superior. Mismo criterio que en el layout B,
     donde la punta de arriba de PLAYGROUND es el final de la palabra. */
  --is-x: 14.674px;      --is-y: 332.194px; --is-dy: 24.7px;     --is-r: 0deg;
  /* OUR sube 12: girada queda encajonada entre la cola de LANGUAGE y el tope
     de PLAYGROUND, y en la mesa se apoyaba casi encima de PLAYGROUND (8px).
     Es lo que entra sin pegarla a LANGUAGE, que baja al mismo tiempo. */
  --our-x: 346.285px;     --our-y: 486.178px; --our-dy: -12px;    --our-r: -90deg;
  --play-x: 15.865px; --play-y: 560.267px; --play-r: 0deg;
  --ground-dx: 120.94px; --ground-dy: 0px;
}

/* --- Layout B · mesa 19 (rojo) -------------------------------------------
   La punta de arriba de PLAYGROUND —girada, es el final de la palabra— se
   alinea con el alto de mayúsculas de OUR. */

.hero[data-layout="b"] {
  /* LANGUAGE va anclada al margen superior: su `y` no se comprime con la
     pantalla, porque el largo de la palabra tampoco lo hace y el margen se
     iría comiendo hasta cortarla. */
  --language-x: 14.674px; --language-y: 0px; --language-dy: 77.981px; --language-r: 0deg;
  --is-x: 298.385px;  --is-y: 188.098px; --is-r: 0deg;
  /* IS, OUR y PLAYGROUND cuelgan de la misma línea, y lo que las separa son
     distancias tipográficas que no se estiran:
       OUR  = IS + 75,08   (el interlineado de 0,848 em del .ai)
       PLAY = IS + 342,64  (lo anterior más 267,56, que es el largo de
                            PLAYGROUND menos el alto de mayúsculas: así la punta
                            de la palabra girada cae en el tope de OUR) */
  --our-x: 243.145px;  --our-y: 188.098px;  --our-dy: 75.08px;   --our-r: 0deg;
  --play-x: 77.314px;  --play-y: 188.098px; --play-dy: 342.64px; --play-r: -90deg;
  --ground-dx: 120.94px; --ground-dy: 0px;
}

/* --- Layout C · mesa 20 (oat) --------------------------------------------
   Acá la guía es horizontal: el pie de LANGUAGE, girada, comparte línea con la
   base de IS OUR. Y es el único layout donde PLAY y GROUND se separan: su
   desplazamiento local cambia y la palabra se parte en dos renglones. */

.hero[data-layout="c"] {
  /* LANGUAGE girada arranca en el margen superior y baja; IS OUR comparten su
     línea de base. Los tres van anclados —`y: 0` más un `dy` fijo— porque el
     largo de la palabra no se comprime con la pantalla y, si el ancla sí lo
     hiciera, la palabra se saldría por arriba. */
  --language-x: 79.443px; --language-y: 0px; --language-dy: 270.53px; --language-r: -90deg;
  --is-x: 180.115px; --is-y: 0px; --is-dy: 270.53px; --is-r: 0deg;
  --our-x: 243.145px; --our-y: 0px; --our-dy: 270.53px; --our-r: 0deg;
  --play-x: 225.615px; --play-y: 493.603px; --play-r: 0deg;
  --ground-dx: -88.81px; --ground-dy: 70.388px;
}

/* --- Modo letras ---------------------------------------------------------
   Con `?anim=letters` cada palabra se parte en letras y cada letra viaja por
   su cuenta con un escalonado corto: las palabras se ven re-ficharse, como
   fichas que se reacomodan en un tablero. El corte lo hace el JS midiendo la
   posición real de cada carácter, así que el kerning de pares se conserva.
   Sin JS —o sin el parámetro— siguen siendo palabras enteras. */

.l {
  transform-box: view-box;
  transform-origin: 0 0;
  transition: transform var(--dur-move) var(--ease-move);
  transition-delay: calc(var(--i, 0) * var(--stagger-letra, 18ms));
  font-family: var(--font-display-cond);
  font-weight: 700;
  font-size: 88.5378px;
  text-transform: uppercase;
  fill: var(--ink);
}

/* Con las fichas en pie, las palabras enteras del SVG sobran: todas. */
.hero[data-letras] .p[data-w],
.hero[data-letras] .p--play { display: none; }

/* En modo ficha el movimiento lo maneja la Web Animations API: la transición
   de CSS pelearía con ella por la misma propiedad. */

/* --- Bajada ---------------------------------------------------------------
   El brief pide «slogan et courte introduction» en la home. Va entre el tablero
   y los botones, con las mismas guías laterales, y se queda quieta: junto con
   los botones forma el marco estable dentro del cual juega la composición. Si
   también se moviera, la página entera temblaría en cada vuelta. */

/* --- El control de la rotación -------------------------------------------
   Chico y al margen derecho de la composición, debajo del tablero. Es el único
   modo de parar el hero, así que tiene que ser alcanzable: la marca mide 10px
   pero el blanco táctil llega a 32×32 por el padding, que es lo que pide el
   criterio de tamaño de objetivo (WCAG 2.5.8 pide 24×24 como mínimo).
   `margin-left: auto` lo empuja a la derecha sin sacarlo del flujo, así que
   sigue restando su alto al tablero y no se superpone con nada. */
.hero__pausa {
  /* Flota sobre el ángulo inferior derecho del tablero en vez de ocupar una
     fila propia: esos 44px de alto son la diferencia entre que los dos botones
     entren en pantalla o no. El rincón está libre en los tres layouts —en lila
     y avena PLAYGROUND termina más arriba, en rojo el logo también—, igual que
     el de arriba a la derecha lo está para el botón de menú. */
  /* El margen negativo es exactamente su propio alto, así que su aporte al
     alto del hero es cero y se dibuja sobre el tablero. No va con `absolute`
     porque es hermano del tablero, no hijo: `absolute` lo mandaría al pie del
     hero, encima de los botones. */
  --alto: 44px;
  height: var(--alto);
  flex: 0 0 auto;
  margin: calc(var(--alto) * -1) 4.1852% 0 auto;
  padding: 0 11px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--ink);
  -webkit-appearance: none;
  appearance: none;
}
.hero__pausa[hidden] { display: none; }

/* La marca: dos barras cuando está andando —el gesto universal de pausa—, un
   triángulo cuando está parado. Se dibujan con `mask` sobre `currentColor`
   para que sigan al par de color como las flechas de los botones. */
.hero__pausa__marca {
  width: 10px;
  height: 12px;
  display: block;
  background: currentColor;
  --pausa: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 12'%3E%3Cpath d='M0 0h3.4v12H0zM6.6 0H10v12H6.6z'/%3E%3C/svg%3E");
  --play: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 12'%3E%3Cpath d='M0 0l10 6-10 6z'/%3E%3C/svg%3E");
  -webkit-mask-image: var(--pausa);
  mask-image: var(--pausa);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
.hero__pausa[aria-pressed="true"] .hero__pausa__marca {
  -webkit-mask-image: var(--play);
  mask-image: var(--play);
}

/* El rótulo existe para el lector de pantalla: es el que dice qué hace el
   botón y cambia al pulsarlo. Un `aria-pressed` solo no alcanza. */
.hero__pausa__texto {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.hero__pausa:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.hero__intro {
  flex: 0 0 auto;
  margin: 0;
  padding: 0 4.1852% var(--s-4) 4.0602%;
  /* Area Bold es el peso máximo de la familia —sólo trae 400/500/700—, así que
     para que la bajada pese más lo que sube es el cuerpo, no el trazo: 18px en
     vez de los 16 del texto corrido. Es un rótulo de entrada, no párrafo. */
  font-size: 18px;
  font-weight: 700;
  line-height: 1.4;
  color: var(--ink);
}

/* --- Botones del pie ------------------------------------------------------
   Dos bloques rellenos, apilados, alineados con las mismas guías que la
   composición: el contenido del artboard va de x = 14,674 a x = 346,285 sobre
   un lienzo de 361,411, o sea 4,06% y 4,19% de margen. Expresarlo en porcentaje
   hace que sigan a la composición sea cual sea el ancho de pantalla. */

.hero__bar {
  flex: 0 0 auto;
  display: grid;
  gap: 6px;
  padding-left: 4.0602%;
  padding-right: 4.1852%;
  padding-bottom: 4.0602%;
}

.hero__btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 54px;
  padding-inline: var(--s-5);
  background: var(--ink);
  color: var(--paper);
  text-decoration: none;
  font-family: var(--font-text);
  font-weight: 700;
  font-size: var(--fs-sm);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* La flecha se dibuja acá y no en el marcado: es decoración, no contenido.
   Va trazada y no recortada: la versión anterior era un `clip-path` con la
   punta de 10px sobre un asta de 2px, y a esa proporción se leía como un bulto.
   Trazo de 2px, sin remates redondeados —la marca no redondea nada— y del
   mismo grosor que el peso del texto del botón. `mask` en vez de `background`
   para que herede `currentColor`. */
.hero__btn::after {
  content: "";
  width: 17px;
  height: 12px;
  flex: 0 0 auto;
  background: currentColor;
  /* la misma de todos los botones: `--flecha` en tokens.css */
  -webkit-mask-image: var(--flecha);
  mask-image: var(--flecha);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  transition: transform var(--dur-base) var(--ease-out);
}
.hero__btn:hover::after,
.hero__btn:focus-visible::after { transform: translateX(5px); }

/* El segundo botón es el secundario: línea y fondo transparente. El borde se
   descuenta del `padding` para que el texto arranque en la misma vertical que
   el del botón relleno —si no, los dos rótulos quedan desalineados por 2px—.
   Al pasar por encima se rellena, que es la misma transición al revés. */
.hero__btn--linea {
  background: transparent;
  color: var(--ink);
  border: var(--border-w) solid var(--ink);
  padding-inline: calc(var(--s-5) - var(--border-w));
  transition: background var(--dur-base) var(--ease-out),
              color var(--dur-base) var(--ease-out);
}
/* Al pasar por encima se vela, no se rellena: si el secundario se pintara
   sólido quedaría idéntico al primario que tiene justo arriba y se perdería
   la jerarquía entre los dos. El texto sigue en tinta. */
.hero__btn--linea:hover,
.hero__btn--linea:focus-visible {
  background: color-mix(in srgb, var(--ink) 14%, transparent);
}

/* --- Los cubos (modo flip) ------------------------------------------------
   Cada letra es una caja en 3D real: la cara frontal lleva el glifo y la
   lateral está a 90°, así que al girar la caja sobre su eje vertical la primera
   se va y la segunda entra. La perspectiva es lo que hace que se lea como un giro y no como una
   letra que se achata: un `scale(1, coseno)` da la misma silueta pero sin
   fuga, y el ojo lo interpreta como una máscara.

   Va en HTML y no en SVG porque el 3D dentro de un SVG no es fiable entre
   motores. Las posiciones salen del mismo sistema de coordenadas del diseño,
   multiplicadas por la escala a la que el SVG se está dibujando. */

.cubos {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.cubo {
  position: absolute;
  left: 0;
  top: 0;
  transform-origin: 0 0;
}

/* --- El logo que gira -----------------------------------------------------
   En modo `gira` el logo ya no viaja de una posición a la otra: se va girando
   sobre su eje vertical hasta quedar de canto, la composición cambia detrás con
   la pantalla vacía, y vuelve entrando con el mismo giro en su sitio nuevo.

   Está en una caja HTML y no en el <g> del SVG por una razón concreta: Safari y
   Firefox aplanan los transforms 3D dentro de un SVG, así que un `rotateY` ahí
   adentro se vería como un simple achatamiento, sin fuga. Es el mismo motivo
   por el que las letras son cajas. El <g> sigue existiendo y sigue siendo el
   que manda sobre las coordenadas del artboard: la caja le copia la posición
   —medida, no recalculada— y él no se dibuja. */
.logo-caja {
  position: absolute;
  left: 0;
  top: 0;
  display: none;
  transform-origin: 50% 50%;
  /* El giro pasa de 90° a propósito —ver la nota en js/main.js—, así que el
     dorso llega a mirar al espectador. Sin esto se vería el logo espejado; con
     esto, simplemente deja de dibujarse. */
  backface-visibility: hidden;
  color: var(--ink);
}
.hero[data-logo="gira"] .logo-caja { display: block; }
.logo-caja svg { display: block; width: 100%; height: 100%; }

/* El <g> deja de pintarse y, sobre todo, deja de tener transición: en este modo
   no viaja, salta —y tiene que haber saltado antes de que la caja lo mida—. */
.hero[data-logo="gira"] .p--logo {
  visibility: hidden;
  transition: none;
}

/* La celda recorta y la cara se desliza dentro. */
/* La capa que gira en el tiro: en el mismo origen que la ficha HTML, así
   la ficha y la caja de la letra se ubican igual que sin ella. */
.cubo__giro { position: absolute; left: 0; top: 0; }

.cubo__caja {
  position: absolute;
  overflow: hidden;
  transform-origin: 50% 50%;
  will-change: transform;
}

.cubo__cara {
  position: absolute;
  inset: 0;
}

/* La cara no lleva fondo: en reposo sólo se ve la letra, igual que en la
   composición plana —las fichas teñidas quedaban raras contra el fondo—. */
.cubo__cara svg { width: 100%; height: 100%; display: block; overflow: visible; }
.cubo__cara text { fill: var(--ink); font-family: var(--font-display-cond); font-weight: 700; }

/* Con las fichas en pie, las palabras enteras del SVG sobran. */
.hero[data-letras] .letras { display: none; }

/* El `:not` no es decorativo: sin él esta regla empata en especificidad con la
   de `data-logo="gira"`, gana por venir después, y el <g> conserva su
   transición. Entonces `colocarLogo()` lo mide justo después del cambio de
   layout, cuando la transición todavía no avanzó, y la caja se planta en la
   posición vieja. En modo `gira` el <g> tiene que saltar, no transicionar. */
.hero[data-letras]:not([data-logo="gira"]) .p--logo {
  transition-duration: var(--dur-logo);
}

/* --- Sin movimiento -------------------------------------------------------
   Quien pidió no ver animaciones ve una sola composición, quieta. */

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

/* Las fichas son decoración: el contenedor no recibe clics, o taparía los
   botones del hero. */
.cubos { pointer-events: none; }

/* --- Composiciones: sólo se dibuja la activa -------------------------------
   Las fichas de todas las composiciones se construyen una vez al cargar —medir
   texto exige esperar a la webfont, y rehacerlo en cada cambio costaría una
   medición completa—. Lo que cambia es cuáles se ven. */
.cubo[data-comp] { display: none; }
.hero[data-comp="en"] .cubo[data-comp="en"],
.hero[data-comp="fr"] .cubo[data-comp="fr"],
.hero[data-comp="rot"] .cubo[data-comp="rot"],
.hero[data-comp="de"] .cubo[data-comp="de"] { display: block; }

/* Sin JS no hay fichas y se ven las palabras enteras del SVG: ahí sólo tiene
   que verse la composición en inglés. Va con `visibility` y NO con `display`,
   que es la diferencia entre que funcione o no: un elemento sin caja no se
   puede medir, y `partirEnLetras` mide cada carácter con
   `getStartPositionOfChar` antes de que exista ninguna ficha. Con `display:
   none` las siete palabras francesas se descartaban al partirlas. */
.hero:not([data-letras]) .p[data-comp="fr"],
.hero:not([data-letras]) .p[data-comp="rot"],
.hero:not([data-letras]) .p[data-comp="de"] { visibility: hidden; }

/* --- Mesa D · la composición en francés -------------------------------------
   OJO: estas coordenadas están ESTIMADAS leyendo los fotogramas del video, no
   calcadas de un artboard como las tres mesas en inglés. Sirven para ver el
   sistema funcionando con una composición de otro idioma y otro recuento de
   palabras; para dejarla fina hacen falta los números reales.

   Lo que esta mesa demuestra que el sistema ya soporta: siete palabras en vez
   de cinco, y un cuerpo distinto por palabra. */
.hero[data-layout="d"] {
  /* Cuerpos y x medidos en pantalla con las fichas puestas: cada fila entra
     entre 14 y 347 del ancho de 361, como las mesas en inglés. La versión
     anterior, estimada del video, se pasaba hasta 53 por la derecha
     (TERRAIN a 130 medía 405). LANGUES, NOTRE y JEU anclan a la derecha. */
  --les-x: 29px;       --les-y: 196px;     --les-dy: 0px;     --les-r: -18deg;
  --langues-x: 101.7px; --langues-y: 162px; --langues-dy: 0px; --langues-r: -4deg;
  --sont-x: 18px;      --sont-y: 293px;    --sont-dy: 0px;    --sont-r: 3deg;
  --notre-x: 182px;    --notre-y: 302px;   --notre-dy: 0px;   --notre-r: -2deg;
  --terrain-x: 18px;   --terrain-y: 464px; --terrain-dy: 0px; --terrain-r: -3deg;
  --de-x: 27px;        --de-y: 560px;      --de-dy: 0px;      --de-r: -8deg;
  --jeu-x: 196px;      --jeu-y: 566px;     --jeu-dy: 0px;     --jeu-r: 5deg;
}

/* El cuerpo de cada palabra. Las de las mesas en inglés heredan el del artboard;
   las francesas lo declaran, que es lo que permite que TERRAIN pese y LES no. */
.p--les     { font-size: 53px; }
.p--langues { font-size: 75px; }
.p--sont    { font-size: 70px; }
.p--notre   { font-size: 70px; }
.p--terrain { font-size: 106px; }
.p--de      { font-size: 104px; }
.p--jeu     { font-size: 104px; }

.p--les     { transform: translate(var(--les-x),     calc(var(--les-y)     * var(--vs, 1) + var(--les-dy, 0px)))     rotate(var(--les-r)); }
.p--langues { transform: translate(var(--langues-x), calc(var(--langues-y) * var(--vs, 1) + var(--langues-dy, 0px))) rotate(var(--langues-r)); }
.p--sont    { transform: translate(var(--sont-x),    calc(var(--sont-y)    * var(--vs, 1) + var(--sont-dy, 0px)))    rotate(var(--sont-r)); }
.p--notre   { transform: translate(var(--notre-x),   calc(var(--notre-y)   * var(--vs, 1) + var(--notre-dy, 0px)))   rotate(var(--notre-r)); }
.p--terrain { transform: translate(var(--terrain-x), calc(var(--terrain-y) * var(--vs, 1) + var(--terrain-dy, 0px))) rotate(var(--terrain-r)); }
.p--de      { transform: translate(var(--de-x),      calc(var(--de-y)      * var(--vs, 1) + var(--de-dy, 0px)))      rotate(var(--de-r)); }
.p--jeu     { transform: translate(var(--jeu-x),     calc(var(--jeu-y)     * var(--vs, 1) + var(--jeu-dy, 0px)))     rotate(var(--jeu-r)); }

/* El par verde para la mesa francesa. */
.hero[data-pair="green"] { --paper: var(--light-green); --ink: var(--dark-green); }

/* --- Mesa E · la frase y su reflejo -----------------------------------------
   Calcada del artboard "Mesa de trabajo 18 copia 3": LANGAGE / IS OUR /
   PLAYGROUND, y debajo las mismas tres líneas giradas 180°, como un naipe. Se
   lee igual dada vuelta, y por eso es la mesa del remolino: cada letra gira
   sobre sí misma y, al completar la vuelta, la composición es la misma.

   Las líneas giradas anclan por la derecha y por arriba: girada 180°, la línea
   de base queda arriba y el texto corre hacia la izquierda. */
/* Un solo cuerpo para las seis líneas: así la mayúscula mide lo mismo en
   todas (0,70 del cuerpo = 46,2) y la interlínea puede ser una sola. La
   interletra va cerrada (−3,5) para que en reposo la palabra sea un bloque
   apretado: cuando las letras giran y se empujan, el contraste se nota más.

   Todas las líneas se centran en el eje del artboard (180,7): la derecha se
   ancla en `centro − ancho/2` y la girada en `centro + ancho/2`, porque girada
   corre hacia la izquierda. Anchos medidos con las fichas puestas, a cuerpo 66
   y −3,5 de interletra: LANGAGE 192,5 · IS OUR 134,6 · PLAYGROUND 279,2. Si
   cambia el cuerpo o la interletra, hay que volver a medirlos.
   Las giradas van 3 más a la izquierda que esa cuenta: centradas por el
   ancho tipográfico, en pantalla la tinta de abajo caía 3 a la derecha de la
   de arriba —el aire lateral de cada letra no es simétrico y, girado 180°,
   cambia de lado—. Medido en píxeles con las dos PLAYGROUND en reposo.

   En vertical es un bloque rígido: seis mayúsculas de 46,2 con 9 de aire
   entre cada una —también entre las dos PLAYGROUND—, 55,2 de paso. El bloque
   se centra en el hueco entre el pie del logo y el pie del escenario, para
   que quede el mismo aire arriba y abajo. El pie del escenario se estira con
   la pantalla (650,54 × vs) y el logo no (15,1 × vs + 92 de alto), así que el
   centro es la mitad de los dos: 333,15 × vs + 46. Lo que se estira va en
   `--rot-centro` y lo fijo, sumado a cada `-dy`. */
.p--rot { font-size: 66px; letter-spacing: -3.5px; }
.hero[data-layout="e"] {
  --rot-centro: 333.15px;
  --langage-x: 84.45px;     --langage-y: var(--rot-centro);     --langage-dy: -69.3px;     --langage-r: 0deg;
  --isour-x: 113.4px;        --isour-y: var(--rot-centro);       --isour-dy: -14.1px;       --isour-r: 0deg;
  --playground-x: 41.1px;   --playground-y: var(--rot-centro);  --playground-dy: 41.1px;   --playground-r: 0deg;
  --playground2-x: 317.3px; --playground2-y: var(--rot-centro); --playground2-dy: 50.1px;  --playground2-r: 180deg;
  --isour2-x: 245px;        --isour2-y: var(--rot-centro);      --isour2-dy: 105.3px;      --isour2-r: 180deg;
  --langage2-x: 273.95px;   --langage2-y: var(--rot-centro);    --langage2-dy: 160.5px;    --langage2-r: 180deg;
}
.p--langage     { transform: translate(var(--langage-x),     calc(var(--langage-y)     * var(--vs, 1) + var(--langage-dy)))     rotate(var(--langage-r)); }
.p--isour       { transform: translate(var(--isour-x),       calc(var(--isour-y)       * var(--vs, 1) + var(--isour-dy)))       rotate(var(--isour-r)); }
.p--playground  { transform: translate(var(--playground-x),  calc(var(--playground-y)  * var(--vs, 1) + var(--playground-dy)))  rotate(var(--playground-r)); }
.p--playground2 { transform: translate(var(--playground2-x), calc(var(--playground2-y) * var(--vs, 1) + var(--playground2-dy))) rotate(var(--playground2-r)); }
.p--isour2      { transform: translate(var(--isour2-x),      calc(var(--isour2-y)      * var(--vs, 1) + var(--isour2-dy)))      rotate(var(--isour2-r)); }
.p--langage2    { transform: translate(var(--langage2-x),    calc(var(--langage2-y)    * var(--vs, 1) + var(--langage2-dy)))    rotate(var(--langage2-r)); }

/* --- Mesa E con fichas (la versión principal; `?fichas=no` la quita) --------
   Cada letra dentro de su ficha, dibujada sólo con el contorno en la tinta y
   las esquinas apenas redondeadas. Es gráfico a propósito: sin puntaje ni
   relieve que lo disfracen de juego — la idea de ficha se lee igual. Altas y
   del ancho de la letra, no cuadradas: con esta tipografía condensada, una
   ficha cuadrada obligaría a achicar mucho todo. (Se probó el bloque relleno
   en bordó con la letra en rojo: pesaba demasiado.)

   Todas las fichas tienen el mismo ancho: cada letra va en una casilla de
   `--ficha-paso` (33 = ficha de 31 + hueco de 2) y se centra en ella por su
   tinta —js/main.js la mide—. Los espacios son una casilla vacía. A cuerpo 66
   la letra más ancha (N) mide 25,5 de tinta, así que en una ficha de 31 queda
   aire a los dos lados, y PLAYGROUND (10 casillas) mide 330.

   Las líneas se centran en el eje con su cantidad de casillas: la derecha
   arranca en 180,7 − n·paso/2 y la girada en 180,7 + n·paso/2. Sin la
   corrección de 3 de la versión sin fichas: acá todo es geométrico.

   Entre filas: cada ficha sobresale 6 de la mayúscula arriba y abajo y quedan
   3 de hueco, así que el paso entre filas es 61,2 (en vez de 55,2). */
.ficha { display: none; }
/* La letra un poco más chica que la ficha, para que respire adentro: se
   escala la caja de la letra —máscara incluida— y no la ficha, así la ficha
   conserva su tamaño y su lugar. La caja ya está centrada en la casilla, y en
   vertical su centro cae a medio punto del de la mayúscula: no se nota. */
.cubo:has(.ficha) .cubo__caja { scale: 0.86; }
.hero[data-fichas] .ficha {
  display: block;
  position: absolute;
  /* sólo el contorno, en la tinta: la letra queda en su color de siempre y la
     ficha es un dibujo, no un objeto */
  border: 1.3px solid var(--ink);
  border-radius: 4px;
  box-sizing: border-box;
  /* rellena con el color del fondo: cuando dos fichas se montan, la de arriba
     tapa a la de abajo como un objeto, en vez de verse los dos contornos
     cruzados a través */
  background: var(--paper);
}

.hero[data-fichas] { --ficha-paso: 33px; }
/* x = 180,7 ∓ n · 33 / 2 (n = casillas de la línea). Van escritas como número
   y no con calc(): js/main.js las lee con parseFloat. */
.hero[data-fichas][data-layout="e"] {
  --langage-x: 65.2px;      --langage-dy: -83.9px;
  --isour-x: 81.7px;        --isour-dy: -22.7px;
  --playground-x: 15.7px;   --playground-dy: 38.5px;
  --playground2-x: 345.7px; --playground2-dy: 53.5px;
  --isour2-x: 279.7px;      --isour2-dy: 114.7px;
  --langage2-x: 296.2px;    --langage2-dy: 175.9px;
}

/* --- Mesa D con fichas (la versión principal; `?verde=sin` la quita) --------
   La verde con las mismas fichas que la roja: todas del mismo tamaño (cuerpo
   66, casillas de 33), así que las palabras dejan de tener cuerpos distintos.
   Lo que se conserva es el desorden: cada palabra mantiene su inclinación y
   las filas no se alinean entre sí. Anchos: LES 99 · LANGUES 231 · SONT 132 ·
   NOTRE 165 · TERRAIN 231 · DE 66 · JEU 99. */
.hero[data-verde="fichas"] { --ficha-paso: 33px; }
.hero[data-verde="fichas"] .p[data-comp="fr"] { font-size: 66px; }
.hero[data-verde="fichas"][data-layout="d"] {
  /* Filas juntas y palabras casi pegadas, con las inclinaciones un poco más
     marcadas: separadas de forma pareja se leía demasiado prolijo. */
  --les-x: 12px;       --les-y: 279px;     --les-r: -18deg;
  --langues-x: 112px;  --langues-y: 283px; --langues-r: -6deg;
  --sont-x: 16px;      --sont-y: 371px;    --sont-r: 4deg;
  --notre-x: 160px;    --notre-y: 381px;   --notre-r: -3deg;
  --terrain-x: 58px;   --terrain-y: 455px; --terrain-r: -4deg;
  --de-x: 20px;        --de-y: 533px;      --de-r: -9deg;
  --jeu-x: 228px;      --jeu-y: 540px;     --jeu-r: 7deg;
}

/* Una mesa recién puesta espera oculta a que arranque su entrada (ver
   `fijarEstado` en js/main.js). */
.hero[data-preparando] .cubo { visibility: hidden; }

/* --- Mesa F · en alemán, sobre una grilla ------------------------------------
   SPRACHE / IST UNSER / SPIELPLATZ en una grilla de 10 columnas de 33: la
   misma casilla que las otras fichas, así que SPIELPLATZ ocupa la grilla
   entera. SPRACHE arranca en la primera columna, IST en la segunda y UNSER en
   la sexta —una casilla vacía entre las dos—. Las filas tienen 61,2 de paso,
   como la roja con fichas. El bloque es rígido y se centra en el escenario
   igual que la roja: `--rot-centro` se estira con la pantalla y cada fila
   cuelga de él (la fila de IST UNSER, en el centro, con la mayúscula
   centrada en él). La animación que la arma vive en js/main.js (`grilla`). */
.hero { --ficha-paso: 33px; }
.p--grilla { font-size: 66px; }
.hero[data-layout="f"] {
  --rot-centro: 333.15px;
  --sprache-x: 15.7px;     --sprache-y: var(--rot-centro);     --sprache-dy: 7.9px;     --sprache-r: 0deg;
  --ist-x: 48.7px;         --ist-y: var(--rot-centro);         --ist-dy: 69.1px;        --ist-r: 0deg;
  --unser-x: 180.7px;      --unser-y: var(--rot-centro);       --unser-dy: 69.1px;      --unser-r: 0deg;
  --spielplatz-x: 15.7px;  --spielplatz-y: var(--rot-centro);  --spielplatz-dy: 130.3px; --spielplatz-r: 0deg;
}
.p--sprache    { transform: translate(var(--sprache-x),    calc(var(--sprache-y)    * var(--vs, 1) + var(--sprache-dy)))    rotate(var(--sprache-r)); }
.p--ist        { transform: translate(var(--ist-x),        calc(var(--ist-y)        * var(--vs, 1) + var(--ist-dy)))        rotate(var(--ist-r)); }
.p--unser      { transform: translate(var(--unser-x),      calc(var(--unser-y)      * var(--vs, 1) + var(--unser-dy)))      rotate(var(--unser-r)); }
.p--spielplatz { transform: translate(var(--spielplatz-x), calc(var(--spielplatz-y) * var(--vs, 1) + var(--spielplatz-dy))) rotate(var(--spielplatz-r)); }

/* --- La entrada del pie del hero ---------------------------------------------
   El texto y los dos botones suben al cargar la página, escalonados, mientras
   la composición se arma arriba: sin esto aparecían de golpe, quietos, y eran
   lo único de la home que no entraba. Es una animación y no una transición
   porque pasa una sola vez, al cargar, sin esperar al scroll. */
@keyframes hero-subir {
  from { opacity: 0; transform: translateY(14px); }
}
.hero__intro,
.hero__btn {
  animation: hero-subir 620ms var(--ease-out) both;
}
.hero__intro          { animation-delay: 350ms; }
.hero__btn            { animation-delay: 470ms; }
.hero__btn--linea     { animation-delay: 560ms; }
@media (prefers-reduced-motion: reduce) {
  .hero__intro, .hero__btn { animation: none; }
}
