/* ===========================================================================
   Joik · 3D Experience Lab — adaptaciones sobre la plantilla Jack Ryan
   ---------------------------------------------------------------------------
   Este archivo se carga DESPUES de ms-main.css y solo agrega lo que la
   plantilla no tiene: el escenario 3D, el visor de la galeria y la navegacion
   entre las dos demos.

   REGLA QUE SE RESPETA ACA: no se redefine la tipografia, ni la escala de
   texto, ni los colores de la plantilla. Todo usa sus propios tokens
   (--color-bg, --color-contrast-*, --font-primary, --space-*), que es lo que
   mantiene la identidad visual intacta en las dos demos.

   Las demos NO usan la paleta de Joik a proposito: tienen que leerse como
   sitios independientes hechos para marcas reales. Joik aparece solo como
   firma discreta y como enlace de vuelta al portfolio.
   ======================================================================== */

/* --- Acento de marca ---------------------------------------------------- */

/* El celeste de Joik (#01d1fe, el mismo de css/mordida-ui.css y del portfolio).
   Se usa SOLO en estados de interaccion: hover, foco, elemento activo y algun
   detalle del visor. La paleta, la tipografia y la composicion siguen siendo
   las de la plantilla: esto es un guino de marca, no un recoloreado. */
:root {
  --joik-cyan: #01d1fe;
  --joik-cyan-h: 193;
  --joik-cyan-s: 99%;
  --joik-cyan-l: 50%;
  --joik-cyan-suave: rgba(1, 209, 254, 0.16);
  --joik-cyan-borde: rgba(1, 209, 254, 0.55);
  --joik-cyan-brillo: rgba(1, 209, 254, 0.28);
}

/* --- Fondo de las paginas oscuras --------------------------------------- */

/* En los ultimos pixeles del recorrido el escenario sticky se despega (es lo
   que hace sticky al llegar al final de su contenedor) y deja ver el fondo de
   la pagina. Pintarlo con el mismo color que el final del degradado evita que
   aparezca una banda de otro tono justo antes de la barra. */
body[data-theme='dark'] {
  background: hsl(216, 22%, 7%);
}

/* --- Marca de las demos ------------------------------------------------- */

/* Las dos demos son showrooms ficticios, con nombre propio. Se escribe con la
   Bebas Neue de la plantilla en lugar de usar su logo: la identidad grafica se
   mantiene, la marca del autor original no aparece. */
.lab-marca {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5em;
  text-decoration: none;
  font-family: 'Bebas Neue', var(--font-primary, sans-serif);
  line-height: 1;
}

.lab-marca__nombre {
  font-size: 1.65rem;
  letter-spacing: 0.1em;
  color: var(--color-contrast-higher);
}

.lab-marca__sufijo {
  font-size: 0.7rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--color-contrast-medium);
}

/* En la demo 01 la cabecera va sobre el escenario oscuro. */
[data-theme='dark'] .lab-marca__nombre {
  color: hsl(0, 0%, 97%);
}

[data-theme='dark'] .lab-marca__sufijo {
  color: hsla(0, 0%, 100%, 0.55);
}

/* --- Barra de navegacion entre demos ------------------------------------ */

.lab-bar {
  position: fixed;
  z-index: 40;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  left: 50%;
  display: flex;
  align-items: center;
  gap: 6px;
  width: max-content;
  max-width: calc(100vw - 32px);
  padding: 6px;
  transform: translateX(-50%);
  border: 1px solid rgba(191, 215, 226, 0.24);
  border-radius: 18px;
  background: rgba(18, 31, 41, 0.95);
  box-shadow: 0 16px 48px rgba(7, 20, 30, 0.24), 0 2px 8px rgba(7, 20, 30, 0.14);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  font-family: var(--font-primary, sans-serif);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  line-height: 1;
  text-transform: uppercase;
}

.lab-bar__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 16px;
  border: 1px solid transparent;
  border-radius: 12px;
  color: #e5edf1;
  text-decoration: none;
  white-space: nowrap;
  transition: color 0.22s ease, background-color 0.22s ease, border-color 0.22s ease;
}

.lab-bar__link:hover,
.lab-bar__link:focus-visible {
  color: #fff;
  background: rgba(1, 209, 254, 0.16);
  border-color: rgba(1, 209, 254, 0.44);
}

.lab-bar__link:focus-visible {
  outline: 2px solid var(--joik-cyan);
  outline-offset: 2px;
}

.lab-bar__link[aria-current='page'] {
  color: #102b36;
  background: #8ceaff;
  border-color: #8ceaff;
}

.lab-bar__sep {
  width: 1px;
  height: 24px;
  margin: 0 3px;
  background: rgba(223, 238, 245, 0.24);
}

/* Firma de Joik. Discreta a proposito: estas paginas son demos de producto,
   no publicidad de la agencia. */
.lab-firma {
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  color: var(--color-contrast-low);
  text-transform: uppercase;
}

.lab-firma a {
  color: var(--color-contrast-medium);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}

.lab-firma a:hover,
.lab-firma a:focus-visible {
  color: var(--color-contrast-higher);
  border-bottom-color: currentColor;
}

/* Deja aire para que la barra fija no tape el final del contenido. */
.lab-espacio-barra {
  height: calc(6.25rem + env(safe-area-inset-bottom, 0px));
}

.lab-firma--pie {
  margin: 2rem 0 0;
  text-align: center;
  color: var(--exp-apagado, var(--color-contrast-medium));
}

/* P11. Atribucion del modelo de terceros. Va en el pie y siempre visible:
   CC BY pide nombrar obra, autor y licencia donde se lean, no detras de un
   desplegable. No hereda de .lab-firma porque aquella va en mayusculas y muy
   espaciada, que para una frase con nombre propio y licencia se lee mal.
   El enlace toma el color del texto en vez de uno propio: asi el contraste
   que cumple la frase lo cumple tambien el enlace, en claro y en oscuro. */
.lab-credito {
  margin: 0.9rem auto 0;
  max-width: 62ch;
  padding: 0 1.25rem;
  text-align: center;
  font-size: 0.72rem;
  line-height: 1.7;
  color: var(--exp-credito, var(--color-contrast-medium));
}

.lab-credito a {
  color: inherit;
  text-decoration: underline;
}

.lab-credito a:hover,
.lab-credito a:focus-visible {
  color: var(--color-contrast-higher);
}

.tienda .lab-firma--pie {
  color: #56636d;
}

/* --- Temas de la demo 01 ------------------------------------------------- */

/* El escenario tiene dos ambientes y uno solo de ellos se ve a la vez. Todo lo
   que cambia de color vive aca para que el resto de las reglas no repita
   valores: cambiar de tema es cambiar estas variables, no reescribir reglas.
   El claro es el predeterminado; el oscuro conserva la identidad anterior. */
[data-theme='light'] {
  --exp-fondo-1: hsl(210, 36%, 99%);
  --exp-fondo-2: hsl(212, 20%, 94%);
  --exp-fondo-3: hsl(214, 16%, 87%);
  --exp-vineta: hsla(214, 24%, 58%, 0.2);
  --exp-velo: hsla(0, 0%, 100%, 0.72);
  --exp-velo-suave: hsla(0, 0%, 100%, 0.38);
  --exp-titulo: hsl(216, 30%, 13%);
  --exp-texto: hsla(216, 22%, 22%, 0.82);
  --exp-apagado: hsla(216, 16%, 34%, 0.7);
  /* La atribucion no puede usar --exp-apagado: con 0.7 de alfa se compone a
     3.62:1 sobre el fondo del pie, por debajo del 4.5 que pide AA a este
     cuerpo. Con 0.88 da 5.57:1 y sigue leyendose como texto secundario.
     (Medido con tests/3d/qa-credito-demo01.cjs.) */
  --exp-credito: hsla(216, 16%, 34%, 0.88);
  --exp-linea: hsla(216, 22%, 22%, 0.16);
  --exp-cta-fondo: hsl(216, 30%, 13%);
  --exp-cta-texto: hsl(0, 0%, 98%);
  --exp-scroll: hsla(216, 20%, 28%, 0.68);
  --exp-scroll-linea: hsla(216, 22%, 24%, 0.5);
  --exp-chip-fondo: hsla(0, 0%, 100%, 0.7);
  --exp-chip-borde: hsla(216, 22%, 22%, 0.2);
  --exp-chip-texto: hsla(216, 20%, 26%, 0.8);
  --exp-aviso-fondo: hsla(0, 0%, 100%, 0.92);
  --exp-aviso-borde: hsla(216, 22%, 22%, 0.16);
  --exp-aviso-texto: hsla(216, 24%, 18%, 0.88);
  /* Franja de lectura de movil: ahi el texto va abajo y el producto arriba. */
  --exp-franja: hsla(210, 30%, 97%, 0.94);
  --exp-franja-media: hsla(210, 30%, 97%, 0.78);
  --exp-acento: hsl(196, 92%, 34%);
}

[data-theme='dark'] {
  --exp-fondo-1: hsl(210, 14%, 22%);
  --exp-fondo-2: hsl(214, 18%, 12%);
  --exp-fondo-3: hsl(216, 22%, 7%);
  --exp-vineta: hsla(216, 30%, 5%, 0.55);
  --exp-velo: hsla(216, 34%, 4%, 0.55);
  --exp-velo-suave: hsla(216, 34%, 4%, 0.3);
  --exp-titulo: hsl(0, 0%, 97%);
  --exp-texto: hsla(0, 0%, 100%, 0.74);
  --exp-apagado: hsla(0, 0%, 100%, 0.5);
  /* En oscuro el apagado ya da 5.34:1: la atribucion no necesita excepcion. */
  --exp-credito: hsla(0, 0%, 100%, 0.5);
  --exp-linea: hsla(0, 0%, 100%, 0.14);
  --exp-cta-fondo: hsl(0, 0%, 97%);
  --exp-cta-texto: hsl(216, 25%, 10%);
  --exp-scroll: hsla(0, 0%, 100%, 0.62);
  --exp-scroll-linea: hsla(0, 0%, 100%, 0.55);
  --exp-chip-fondo: hsla(216, 30%, 8%, 0.6);
  --exp-chip-borde: hsla(0, 0%, 100%, 0.22);
  --exp-chip-texto: hsla(0, 0%, 100%, 0.66);
  --exp-aviso-fondo: hsla(216, 30%, 8%, 0.9);
  --exp-aviso-borde: hsla(0, 0%, 100%, 0.14);
  --exp-aviso-texto: hsla(0, 0%, 100%, 0.84);
  --exp-franja: hsla(216, 32%, 5%, 0.92);
  --exp-franja-media: hsla(216, 32%, 5%, 0.72);
  --exp-acento: var(--joik-cyan);
}

/* El cambio de tema se acompaña, no se corta en seco. */
.exp-escenario,
.exp-escenario::after,
body[data-theme] {
  transition: background-color 0.5s ease, background 0.5s ease;
}

/* --- Demo 01 · escenario sticky ----------------------------------------- */

.exp-recorrido {
  position: relative;
}

/* 300vh = tres secciones de pantalla completa. El escenario queda pegado
   mientras el recorrido pasa por debajo: asi el producto no se mueve de la
   pantalla y el que cambia es el texto. */
.exp-escenario {
  position: sticky;
  top: 0;
  height: 100vh;
  /* 100dvh evita el salto de la barra de direcciones en iOS. */
  height: 100dvh;
  width: 100%;
  overflow: hidden;
  background:
    radial-gradient(
      120% 90% at 50% 15%,
      var(--exp-fondo-1) 0%,
      var(--exp-fondo-2) 55%,
      var(--exp-fondo-3) 100%
    );
}

.exp-escenario canvas {
  display: block;
  width: 100%;
  height: 100%;
  /* El canvas no recibe eventos: el scroll y los clics pasan de largo, que es
     lo que mantiene la navegacion en manos del usuario. */
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.8s ease;
}

.exp-escenario.is-listo canvas {
  opacity: 1;
}

/* Vineta suave para que el texto se lea siempre sobre el modelo. */
.exp-escenario::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(
    75% 65% at 50% 45%,
    transparent 40%,
    var(--exp-vineta) 100%
  );
}

.exp-estado {
  position: absolute;
  z-index: 3;
  left: 50%;
  bottom: 2.2rem;
  transform: translateX(-50%);
  margin: 0;
  padding: 0.5em 1.1em;
  border-radius: 999px;
  background: hsla(216, 30%, 6%, 0.7);
  color: hsl(0, 0%, 88%);
  font-family: var(--font-primary, sans-serif);
  font-size: 0.8rem;
  letter-spacing: 0.06em;
}

/* Capa de texto: va por encima del canvas pero sin bloquear el scroll.
   El margen negativo la sube sobre el escenario sticky, que ocupa 100vh en el
   flujo. Sin esto habria que bajar una pantalla entera antes de leer el
   primer titular. */
.exp-capa {
  position: relative;
  z-index: 5;
  margin-top: -100vh;
  margin-top: -100dvh;
  pointer-events: none;
}

.exp-capa a,
.exp-capa button {
  pointer-events: auto;
}

.exp-seccion {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  padding: var(--space-xl) 0;
  /* Contiene el velo de lectura, que se extiende 9rem a cada lado de la
     columna de texto: a 768px la columna queda pegada al borde y ese
     pseudoelemento provocaba 105px de scroll horizontal.
     No afecta al escenario sticky, que es hermano de estas secciones. */
  overflow: hidden;
}

/* Reparto del ancho: el texto ocupa una columna de 34% y el resto queda para
   el producto, que el JS corre al lado contrario en cada seccion
   (config-3d.js → estados[].desplazamiento). Asi el objeto manda en la
   composicion sin pisar el copy.
   El tope en rem evita que en pantallas muy anchas la columna se estire hasta
   volverse ilegible. */
.exp-seccion__inner {
  width: 34%;
  max-width: 30rem;
  min-width: 20rem;
  position: relative;
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.9s ease, transform 0.9s ease;
}

/* Zona segura de lectura: un velo muy suave detras de la columna de texto,
   por si el producto llega a asomar por el borde. No se ve como una caja;
   solo baja el contraste del fondo lo justo. */
/* La caja del velo es bastante mas grande que el texto y el degradado llega a
   transparente MUY adentro de ella: si el gradiente se corta en el borde del
   pseudoelemento se ve el rectangulo, y queda como un panel pegado encima. */
.exp-seccion__inner::before {
  content: '';
  position: absolute;
  inset: -7rem -9rem;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    closest-side at 40% 50%,
    var(--exp-velo) 0%,
    var(--exp-velo-suave) 48%,
    transparent 78%
  );
}

.exp-seccion--derecha .exp-seccion__inner::before {
  background: radial-gradient(
    closest-side at 60% 50%,
    var(--exp-velo) 0%,
    var(--exp-velo-suave) 48%,
    transparent 78%
  );
}

.exp-seccion--centro .exp-seccion__inner::before {
  background: radial-gradient(
    closest-side at 50% 55%,
    var(--exp-velo) 0%,
    var(--exp-velo-suave) 50%,
    transparent 80%
  );
}

/* La clase de estado se llama exp-visible y NO is-visible.
   ms-main.css define `.is-visible { display: var(--display) !important }` como
   utilidad, y ese !important le ganaba al `display: flex` de .exp-seccion: la
   seccion volvia a `block` y en movil el texto se iba arriba, encima de la
   cabecera. Cualquier clase de estado nueva va con prefijo propio. */
.exp-seccion.exp-visible .exp-seccion__inner {
  opacity: 1;
  transform: none;
}


/* Revelado escalonado del bloque de texto.
   Cada elemento entra con un retardo propio en lugar de aparecer todo junto:
   el ojo sigue el orden de lectura (contador, titular, bajada, detalles, CTA)
   en vez de recibir el bloque entero de golpe. Son 18px y medio segundo, no
   un numerito saltando: tiene que acompañar, no llamar la atencion. */
.exp-seccion__inner > * {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.75s cubic-bezier(0.22, 0.7, 0.25, 1),
    transform 0.75s cubic-bezier(0.22, 0.7, 0.25, 1);
}

.exp-seccion.exp-visible .exp-seccion__inner > * {
  opacity: 1;
  transform: none;
}

.exp-seccion.exp-visible .exp-conteo { transition-delay: 0.05s; }
.exp-seccion.exp-visible .exp-titular { transition-delay: 0.15s; }
.exp-seccion.exp-visible .exp-bajada { transition-delay: 0.28s; }
.exp-seccion.exp-visible .exp-detalles { transition-delay: 0.4s; }
.exp-seccion.exp-visible .exp-cta { transition-delay: 0.5s; }

/* Los detalles entran uno detras de otro dentro de su propia lista. */
.exp-detalles li {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.exp-seccion.exp-visible .exp-detalles li:nth-child(1) { transition-delay: 0.46s; }
.exp-seccion.exp-visible .exp-detalles li:nth-child(2) { transition-delay: 0.57s; }
.exp-seccion.exp-visible .exp-detalles li:nth-child(3) { transition-delay: 0.68s; }

.exp-seccion.exp-visible .exp-detalles li {
  opacity: 1;
  transform: none;
}

/* Palabra destacada dentro de un titular: acento celeste de Joik, discreto.
   Sirve para partir titulares largos y marcar donde esta el peso. */
.exp-destacado {
  color: var(--exp-acento);
}

/* Linea fina sobre el contador: separa el bloque del resto sin cargar. */
.exp-conteo::before {
  content: '';
  display: block;
  width: 2.4rem;
  height: 1px;
  margin-bottom: 1.1em;
  background: var(--exp-acento);
  opacity: 0.85;
}

.exp-seccion--derecha .exp-conteo::before { margin-left: auto; }
.exp-seccion--centro .exp-conteo::before { margin-left: auto; margin-right: auto; }

/* La seccion 2 manda el texto a la derecha y el producto a la izquierda.
   OJO: el flex item de .exp-seccion es .container, no .exp-seccion__inner, asi
   que justify-content NO mueve el copy. La columna se corre con margin-left
   auto, que es lo unico que la empuja de verdad. */
.exp-seccion--derecha .exp-seccion__inner {
  margin-left: auto;
  margin-right: 0;
  text-align: right;
}

/* El dock flotante ocupa la franja inferior. La lista de la sección 02
   necesita aire extra en escritorio para terminar por encima de él. */
@media (min-width: 1024px) {
  .exp-seccion--derecha {
    padding-bottom: calc(var(--space-xl) + 4rem);
  }
}

/* En la tercera seccion el producto sube (desplazamiento.y) y el texto baja:
   el reparto deja de ser izquierda/derecha y pasa a ser arriba/abajo, que es
   lo que pide un cierre centrado sin partir la composicion en dos columnas
   rigidas. */
.exp-seccion--centro {
  justify-content: center;
  align-items: flex-end;
  text-align: center;
}

.exp-seccion--centro .exp-seccion__inner {
  width: 100%;
  max-width: 38rem;
  margin-left: auto;
  margin-right: auto;
  text-align: center;
  padding-bottom: 4.5rem;
}

/* Titular mas contenido solo en el cierre: con el reparto arriba/abajo, el
   bloque de texto medido ocupaba 468px de 900 y no quedaba sitio para el
   producto. Con esto baja a ~330px y el producto se queda con la mitad de
   arriba, sin que se pisen. */
.exp-seccion--centro .exp-titular {
  font-size: clamp(2rem, 4.2vw, 3.4rem);
}

.exp-seccion--centro .exp-bajada {
  font-size: clamp(0.95rem, 1.3vw, 1.05rem);
}

.exp-titular {
  font-family: 'Bebas Neue', var(--font-primary, sans-serif);
  font-size: clamp(2.6rem, 7vw, 5.4rem);
  line-height: 0.95;
  letter-spacing: 0.01em;
  color: var(--exp-titulo);
  margin: 0 0 0.55em;
  text-wrap: balance;
}

.exp-bajada {
  font-size: clamp(1rem, 1.6vw, 1.15rem);
  line-height: 1.75;
  color: var(--exp-texto);
  margin: 0;
  max-width: 42ch;
}

.exp-seccion--derecha .exp-bajada,
.exp-seccion--centro .exp-bajada {
  margin-left: auto;
}

.exp-seccion--centro .exp-bajada {
  margin-right: auto;
}

/* Contador, tomado del slider de la plantilla para mantener su lenguaje. */
.exp-conteo {
  font-family: 'Bebas Neue', var(--font-primary, sans-serif);
  font-size: 1.1rem;
  letter-spacing: 0.22em;
  color: var(--exp-apagado);
  margin-bottom: 1.45em;
  display: block;
}

.exp-conteo strong {
  color: var(--exp-titulo);
  font-weight: inherit;
}

.exp-detalles {
  list-style: none;
  margin: 2.4em 0 0;
  padding: 0;
  display: grid;
  gap: 1.25em;
}

.exp-detalles li {
  border-top: 1px solid var(--exp-linea);
  padding-top: 1em;
  color: var(--exp-texto);
  font-size: 0.95rem;
  line-height: 1.65;
}

.exp-detalles b {
  display: block;
  font-family: 'Bebas Neue', var(--font-primary, sans-serif);
  font-size: 1.05rem;
  letter-spacing: 0.1em;
  color: var(--exp-titulo);
  font-weight: inherit;
  margin-bottom: 0.35em;
}

/* --- CTA ---------------------------------------------------------------- */

.exp-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  margin-top: 2em;
  padding: 0.95em 1.9em;
  border-radius: 999px;
  background: var(--exp-cta-fondo);
  color: var(--exp-cta-texto);
  font-family: var(--font-primary, sans-serif);
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  transition: transform 0.25s ease, background-color 0.25s ease;
}

.exp-cta:hover,
.exp-cta:focus-visible {
  background: var(--joik-cyan);
  transform: translateY(-2px);
  color: hsl(216, 28%, 8%);
  box-shadow: 0 10px 30px -12px var(--joik-cyan-brillo);
}

.exp-cta svg {
  width: 1em;
  height: 1em;
  flex: none;
}

/* --- Indicador de scroll ------------------------------------------------ */

.exp-scroll {
  position: absolute;
  z-index: 6;
  left: 50%;
  bottom: 5.5rem;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55em;
  color: var(--exp-scroll);
  font-family: var(--font-primary, sans-serif);
  font-size: 0.68rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  transition: opacity 0.45s ease, transform 0.45s ease;
}

.exp-scroll.is-oculto {
  opacity: 0;
  transform: translateX(-50%) translateY(10px);
  pointer-events: none;
}

.exp-scroll__linea {
  width: 1px;
  height: 2.6rem;
  background: linear-gradient(to bottom, var(--exp-scroll-linea), transparent);
  animation: expScrollLinea 2.1s ease-in-out infinite;
}

@keyframes expScrollLinea {
  0%,
  100% {
    transform: scaleY(0.45);
    transform-origin: top;
    opacity: 0.5;
  }
  50% {
    transform: scaleY(1);
    transform-origin: top;
    opacity: 1;
  }
}

/* --- Avisos: carga, error, sin WebGL ------------------------------------ */

.exp-aviso {
  position: absolute;
  z-index: 7;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  max-width: 26rem;
  padding: 1.1em 1.4em;
  border-radius: 10px;
  background: var(--exp-aviso-fondo);
  border: 1px solid var(--exp-aviso-borde);
  color: var(--exp-aviso-texto);
  font-family: var(--font-primary, sans-serif);
  font-size: 0.88rem;
  line-height: 1.55;
  text-align: center;
}

.exp-aviso[hidden] {
  display: none;
}

/* Marca de placeholder. Es informacion honesta para el que mira la demo:
   lo que ve no es el producto definitivo. */
/* Abajo a la izquierda. Arriba a la derecha chocaba con el contador de la
   seccion 02, y arriba a la izquierda con el logo en la 03. Abajo esta libre
   en las tres secciones y por encima de la barra de navegacion. */
.exp-provisional {
  position: absolute;
  z-index: 6;
  bottom: 5.2rem;
  left: var(--space-md);
  padding: 0.4em 0.85em;
  border-radius: 999px;
  border: 1px solid var(--exp-chip-borde);
  background: var(--exp-chip-fondo);
  color: var(--exp-chip-texto);
  font-family: var(--font-primary, sans-serif);
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* --- Pagina selectora --------------------------------------------------- */

/* Es la entrada unica desde el portfolio de Joik: una sola tarjeta alla, dos
   experiencias aca. A diferencia de las demos, esta pagina SI lleva la marca
   de Joik, porque es parte del portfolio y no del showroom ficticio. */
.lab-selector {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  padding: calc(var(--space-xl) * 1.5) 0 var(--space-lg);
  background:
    radial-gradient(
      110% 80% at 15% 0%,
      hsl(212, 16%, 20%) 0%,
      hsl(214, 20%, 12%) 55%,
      hsl(216, 24%, 8%) 100%
    );
}

.lab-selector__intro {
  max-width: 38rem;
  margin-bottom: var(--space-lg);
}

.lab-selector .exp-titular {
  font-size: clamp(2.4rem, 6vw, 4.4rem);
}

.lab-selector__nota {
  margin: 1.4em 0 0;
  padding-left: 0.9em;
  border-left: 2px solid var(--joik-cyan-borde);
  color: hsla(0, 0%, 100%, 0.58);
  font-size: 0.86rem;
  line-height: 1.55;
  max-width: 40rem;
}

.lab-selector__opciones {
  display: grid;
  gap: var(--space-xs);
}

/* Fichas editoriales: preview grande arriba, texto debajo. La imagen es lo
   que comunica que tipo de experiencia se abre, asi que manda en la jerarquia.
   Contenido y rutas salen de DEMOS_LAB en config-3d.js. */
.lab-ficha {
  position: relative;
  border: 1px solid hsla(0, 0%, 100%, 0.1);
  border-radius: 14px;
  overflow: hidden;
  background: hsla(0, 0%, 100%, 0.025);
  transition: border-color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
}

.lab-ficha:hover,
.lab-ficha:focus-within {
  border-color: var(--joik-cyan-borde);
  transform: translateY(-3px);
  box-shadow: 0 18px 50px -24px var(--joik-cyan-brillo);
}

.lab-ficha__enlace {
  display: block;
  text-decoration: none;
  color: inherit;
}

/* El enlace cubre toda la ficha, asi que el foco se dibuja sobre la ficha y no
   sobre un rectangulo interno. */
.lab-ficha__enlace:focus-visible {
  outline: none;
}

.lab-ficha:focus-within {
  outline: 2px solid var(--joik-cyan);
  outline-offset: 3px;
}

.lab-ficha__visual {
  position: relative;
  margin: 0;
  overflow: hidden;
  aspect-ratio: 16 / 10;
  background: hsl(214, 20%, 11%);
}

.lab-ficha__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transform: scale(1.01);
  transition: transform 0.6s cubic-bezier(0.2, 0.7, 0.2, 1), filter 0.4s ease;
  filter: saturate(0.92);
}

.lab-ficha:hover .lab-ficha__img,
.lab-ficha:focus-within .lab-ficha__img {
  transform: scale(1.05);
  filter: saturate(1.05);
}

/* Degradado de pie: ata la imagen con el texto y evita el corte seco. */
.lab-ficha__visual::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 32%;
  pointer-events: none;
  background: linear-gradient(
    to top,
    hsl(216, 24%, 9%) 0%,
    hsla(216, 24%, 9%, 0.72) 42%,
    transparent 100%
  );
}

.lab-ficha__numero {
  position: absolute;
  z-index: 2;
  top: 0.7rem;
  right: 1.1rem;
  font-family: 'Bebas Neue', var(--font-primary, sans-serif);
  font-size: 2.1rem;
  line-height: 1;
  letter-spacing: 0.08em;
  color: hsla(0, 0%, 100%, 0.85);
  text-shadow: 0 2px 14px hsla(216, 30%, 5%, 0.8);
  transition: color 0.3s ease;
}

.lab-ficha:hover .lab-ficha__numero,
.lab-ficha:focus-within .lab-ficha__numero {
  color: var(--joik-cyan);
}

/* El texto NO se monta sobre la imagen: el preview de la galeria es claro y el
   de producto oscuro, asi que cualquier titulo encima dependeria del brillo de
   la captura. Sobre el fondo de la ficha el contraste es siempre el mismo. */
.lab-ficha__cuerpo {
  position: relative;
  z-index: 2;
  padding: var(--space-sm) var(--space-md) var(--space-md);
}

.lab-ficha__titulo {
  font-family: 'Bebas Neue', var(--font-primary, sans-serif);
  font-size: clamp(1.7rem, 2.4vw, 2.3rem);
  line-height: 1.05;
  letter-spacing: 0.03em;
  color: hsl(0, 0%, 97%);
  margin: 0 0 0.45em;
}

.lab-ficha__texto {
  color: hsla(0, 0%, 100%, 0.68);
  font-size: 0.95rem;
  line-height: 1.55;
  margin: 0;
  max-width: 44ch;
}

.lab-ficha__meta {
  margin: 1.1em 0 0;
  padding-top: 0.9em;
  border-top: 1px solid hsla(0, 0%, 100%, 0.1);
  font-family: var(--font-primary, sans-serif);
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: hsla(0, 0%, 100%, 0.42);
  transition: color 0.3s ease, border-color 0.3s ease;
}

.lab-ficha:hover .lab-ficha__meta,
.lab-ficha:focus-within .lab-ficha__meta {
  border-top-color: var(--joik-cyan-borde);
  color: hsla(0, 0%, 100%, 0.6);
}

.lab-ficha__cta {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  margin-top: 1.2em;
  font-family: var(--font-primary, sans-serif);
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: hsl(0, 0%, 92%);
  transition: color 0.3s ease, gap 0.3s ease;
}

.lab-ficha__cta svg {
  width: 1.05em;
  height: 1.05em;
  flex: none;
  transition: transform 0.3s ease;
}

.lab-ficha:hover .lab-ficha__cta,
.lab-ficha:focus-within .lab-ficha__cta {
  color: var(--joik-cyan);
  gap: 0.85em;
}

.lab-ficha:hover .lab-ficha__cta svg,
.lab-ficha:focus-within .lab-ficha__cta svg {
  transform: translateX(3px);
}

@media (min-width: 900px) {
  .lab-selector__opciones {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-sm);
  }
}

@media (prefers-reduced-motion: reduce) {
  .lab-ficha,
  .lab-ficha__img,
  .lab-ficha__cta,
  .lab-ficha__cta svg {
    transition-duration: 0.01ms !important;
  }

  .lab-ficha:hover {
    transform: none;
  }

  .lab-ficha:hover .lab-ficha__img,
  .lab-ficha:focus-within .lab-ficha__img {
    transform: scale(1.01);
  }
}


/* --- Conmutador de tema -------------------------------------------------- */

/* Vive en la cabecera, a la derecha del logo. Pastilla discreta: tiene que
   leerse como parte de la interfaz premium, no como un control de sistema. */
.lab-tema {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  margin-left: auto;
  padding: 0.55em 1.1em;
  border: 1px solid var(--exp-chip-borde);
  border-radius: 999px;
  background: var(--exp-chip-fondo);
  color: var(--exp-chip-texto);
  font-family: var(--font-primary, sans-serif);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: border-color 0.25s ease, color 0.25s ease, background-color 0.25s ease;
  /* Area tactil comoda sin agrandar la pastilla visualmente. */
  min-height: 44px;
}

.lab-tema:hover,
.lab-tema:focus-visible {
  border-color: var(--joik-cyan-borde);
  color: var(--joik-cyan);
}

.lab-tema__icono {
  position: relative;
  display: grid;
  place-items: center;
  width: 1.05rem;
  height: 1.05rem;
  flex: none;
}

.lab-tema__icono svg {
  position: absolute;
  width: 100%;
  height: 100%;
  transition: opacity 0.3s ease, transform 0.4s ease;
}

/* En claro se ofrece la luna; en oscuro, el sol. El icono anuncia el destino,
   igual que el texto. */
[data-theme='light'] .lab-tema__sol { opacity: 0; transform: rotate(-70deg) scale(0.6); }
[data-theme='light'] .lab-tema__luna { opacity: 1; transform: none; }
[data-theme='dark'] .lab-tema__sol { opacity: 1; transform: none; }
[data-theme='dark'] .lab-tema__luna { opacity: 0; transform: rotate(70deg) scale(0.6); }

/* La cabecera tiene que poder empujar el boton al extremo. */
.main-header__layout {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

@media (max-width: 560px) {
  /* En pantallas chicas queda el icono solo: el texto no aporta y la barra
     tiene poco ancho. El aria-label sigue describiendo la accion. */
  .lab-tema__texto {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
  }

  .lab-tema {
    padding: 0.55em 0.75em;
    min-width: 44px;
    justify-content: center;
  }
}

@media (prefers-reduced-motion: reduce) {
  .lab-tema__icono svg,
  .exp-seccion__inner > *,
  .exp-detalles li {
    transition-duration: 0.01ms !important;
  }
}


/* --- Dock compacto en móvil --------------------------------------------- */
@media (max-width: 767px) {
  .lab-bar {
    bottom: calc(10px + env(safe-area-inset-bottom, 0px));
    gap: 4px;
    max-width: calc(100vw - 20px);
    padding: 5px;
    border-radius: 16px;
    font-size: 0.7rem;
  }

  .lab-bar__link {
    padding: 0 12px;
  }

  .lab-bar__sep {
    display: none;
  }

  .lab-espacio-barra {
    height: calc(6.5rem + env(safe-area-inset-bottom, 0px));
  }

  .exp-scroll {
    bottom: calc(5.2rem + env(safe-area-inset-bottom, 0px));
  }
}

@media (max-width: 400px) {
  .lab-bar__link {
    padding: 0 10px;
  }
}

/* --- Demo 02 · galeria -------------------------------------------------- */

.showroom-intro {
  padding-top: var(--space-xl);
}

.showroom-intro__kicker {
  display: block;
  font-family: var(--font-primary, sans-serif);
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--color-contrast-medium);
  margin-bottom: 0.9em;
}

.showroom-aviso {
  margin: var(--space-md) 0 0;
  padding: 0.9em 1.1em;
  border-left: 2px solid var(--joik-cyan);
  background: var(--color-contrast-lower);
  color: var(--color-contrast-high);
  font-size: 0.86rem;
  line-height: 1.55;
  max-width: 44rem;
}

/* .row de grid.min.css lleva margenes horizontales de -10px para compensar el
   padding de sus columnas. Dentro de .container eso se absorbe, pero en
   pantallas chicas el padding del contenedor se queda corto y la rejilla
   sobresalia 10px, lo que provocaba scroll horizontal. Se anulan los margenes
   y el aire lo pone el padding que las columnas ya traen. */
.showroom-rejilla {
  margin-left: 0;
  margin-right: 0;
}

/* La tarjeta reutiliza .work-card de la plantilla; aca solo se agrega lo que
   una tarjeta de catalogo necesita y una de portfolio no tenia. */
.prod-card__visual {
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(
      100% 80% at 50% 20%,
      hsl(210, 16%, 94%) 0%,
      hsl(212, 14%, 86%) 100%
    );
  aspect-ratio: 3 / 4;
}

.prod-card__poster {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Previsualizacion estatica: la galeria NO monta tres canvas WebGL a la vez.
   Se dibuja una imagen del modelo y el visor real se arma al abrirlo. */
.prod-card__preview {
  width: 100%;
  height: 100%;
  display: block;
}

/* Canvas del preview vivo. Se monta sobre el poster y lo tapa; el poster
   sigue ahi debajo para cuando el cursor se va. No recibe eventos: el que
   escucha el movimiento es la tarjeta. */
.prod-card__preview3d {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
  animation: previewEntra 0.35s ease both;
}

@keyframes previewEntra {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Señal de que la pieza es manipulable, antes incluso de tocarla. */
.prod-card__pista {
  position: absolute;
  z-index: 3;
  right: 0.8rem;
  bottom: 0.8rem;
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.38em 0.7em;
  border-radius: 999px;
  border: 1px solid var(--joik-cyan-borde);
  background: hsla(216, 28%, 8%, 0.72);
  color: hsl(0, 0%, 95%);
  font-family: var(--font-primary, sans-serif);
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.3s ease, transform 0.3s ease;
  pointer-events: none;
}

.prod-card__pista svg {
  width: 0.85em;
  height: 0.85em;
}

.work-card:hover .prod-card__pista,
.work-card:focus-within .prod-card__pista {
  opacity: 1;
  transform: none;
}

/* Mientras hay preview vivo, el poster se atenua para que la transicion no
   sea un corte seco. */
.work-card.tiene-preview .prod-card__poster {
  opacity: 0;
}

.prod-card__poster {
  transition: opacity 0.3s ease;
}

/* Sin cursor (tactil) la pista no aparece: ahi el toque abre el visor y no
   hay preview que anunciar. */
@media (hover: none) {
  .prod-card__pista {
    display: none;
  }
}

.prod-card__badge-tmp {
  position: absolute;
  top: 0.8rem;
  left: 0.8rem;
  z-index: 2;
  padding: 0.35em 0.7em;
  border-radius: 999px;
  background: hsla(216, 25%, 12%, 0.82);
  color: hsl(0, 0%, 96%);
  font-family: var(--font-primary, sans-serif);
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.prod-card__abrir {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  margin-top: 0.9em;
  padding: 0.7em 1.3em;
  border: 1px solid var(--color-contrast-low);
  border-radius: 999px;
  background: none;
  color: var(--color-contrast-higher);
  font-family: var(--font-primary, sans-serif);
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color 0.2s ease, background-color 0.2s ease;
}

.prod-card__abrir:hover,
.prod-card__abrir:focus-visible {
  border-color: var(--joik-cyan);
  background: var(--joik-cyan-suave);
  color: var(--color-contrast-higher);
}

.prod-card__detalle {
  display: block;
  margin-top: 0.4em;
  font-size: 0.8rem;
  color: var(--color-contrast-medium);
}


/* --- Tarjetas de la tienda: tratamiento premium --------------------------- */

/* El encargo pedia que no se leyeran como una tienda generica. Lo que separa
   una tarjeta "de plantilla" de una de catalogo caro no son los efectos: es el
   aire, la profundidad contenida y que el movimiento sea lento y corto.
   Por eso aca hay sombra de dos capas, borde que apenas se insinua y un hover
   de 2px, no de 10. */
.work-card {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  background: var(--color-bg);
  border: 1px solid hsla(216, 20%, 40%, 0.12);
  box-shadow:
    0 1px 2px hsla(216, 30%, 20%, 0.05),
    0 12px 28px -18px hsla(216, 30%, 20%, 0.18);
  transition: transform 0.45s cubic-bezier(0.22, 0.7, 0.25, 1),
    box-shadow 0.45s ease, border-color 0.45s ease;
  height: 100%;
  display: flex;
  flex-direction: column;
}

.work-card:hover,
.work-card:focus-within {
  transform: translateY(-4px);
  border-color: var(--joik-cyan-borde);
  box-shadow:
    0 2px 4px hsla(216, 30%, 20%, 0.06),
    0 26px 52px -26px hsla(196, 70%, 30%, 0.3);
}

/* El visual ocupa la parte de arriba con su propia superficie: un degradado
   suave que da sensacion de profundidad detras del producto, en lugar de un
   gris plano. */
.prod-card__visual {
  position: relative;
  margin: 0;
  overflow: hidden;
  aspect-ratio: 3 / 4;
  background:
    radial-gradient(120% 90% at 50% 15%, hsl(210, 24%, 97%) 0%, hsl(212, 16%, 90%) 60%, hsl(214, 14%, 84%) 100%);
}

/* Una luz que cruza el visual al pasar el cursor. Es un barrido lento y de muy
   poca opacidad: se percibe como material, no como un brillo de banner. */
.prod-card__visual::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(
    105deg,
    transparent 38%,
    hsla(0, 0%, 100%, 0.42) 50%,
    transparent 62%
  );
  transform: translateX(-120%);
  transition: transform 0.9s cubic-bezier(0.3, 0.7, 0.3, 1);
}

.work-card:hover .prod-card__visual::after,
.work-card:focus-within .prod-card__visual::after {
  transform: translateX(120%);
}

.prod-card__poster {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  transition: opacity 0.35s ease, transform 0.7s cubic-bezier(0.22, 0.7, 0.25, 1);
}

.work-card:hover .prod-card__poster {
  transform: scale(1.03);
}

/* Numero de pieza: lenguaje de catalogo, no de tienda. */
.tienda-numero {
  position: absolute;
  z-index: 3;
  top: 0.9rem;
  left: 1rem;
  font-family: var(--font-primary, sans-serif);
  font-size: 0.64rem;
  letter-spacing: 0.18em;
  color: hsla(216, 22%, 24%, 0.55);
}

.work-card__content {
  padding: var(--space-sm) var(--space-sm) var(--space-md);
  display: flex;
  flex-direction: column;
  flex: 1;
}

.work-card__badge {
  font-size: 0.64rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-contrast-medium);
}

.work-card__title {
  font-family: 'Bebas Neue', var(--font-primary, sans-serif);
  font-size: 1.85rem;
  letter-spacing: 0.03em;
  line-height: 1.05;
  margin: 0.35em 0 0.3em;
  color: var(--color-contrast-higher);
}

.tienda-precio {
  margin: auto 0 0;
  padding-top: 1em;
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--color-contrast-higher);
  letter-spacing: 0.01em;
}

.tienda-precio span {
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  color: var(--color-contrast-medium);
  margin-left: 0.3em;
}

/* Apilados y a ancho completo, no lado a lado: con la columna de ~320px que
   deja una grilla de tres, "Agregar al carrito" se salia de la tarjeta. Asi
   ademas el area tactil es comoda en movil sin tocar nada mas. */
.tienda-acciones {
  display: grid;
  gap: 0.55em;
  margin-top: 1.2em;
}

/* Botones: el principal con relleno, el secundario como contorno. La jerarquia
   es lo que evita el aspecto de plantilla con dos botones iguales. */
.tienda-acciones .prod-card__abrir {
  width: 100%;
  margin-top: 0;
  min-height: 46px;
  justify-content: center;
}

.tienda-acciones .tienda-btn {
  width: 100%;
  min-height: 46px;
  padding: 0.7em 1.1em;
  border-radius: 999px;
  border: 1px solid transparent;
  background: var(--color-contrast-higher);
  color: var(--color-bg);
  font-family: var(--font-primary, sans-serif);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  cursor: pointer;
  transition: background-color 0.25s ease, transform 0.25s ease;
}

.tienda-acciones .tienda-btn:hover,
.tienda-acciones .tienda-btn:focus-visible {
  background: var(--joik-cyan);
  color: hsl(216, 28%, 8%);
  transform: translateY(-1px);
}

@media (prefers-reduced-motion: reduce) {
  .work-card,
  .prod-card__poster,
  .prod-card__visual::after {
    transition-duration: 0.01ms !important;
  }

  .work-card:hover {
    transform: none;
  }

  .work-card:hover .prod-card__visual::after {
    transform: translateX(-120%);
  }
}

/* --- Demo 02 · visor ---------------------------------------------------- */

.visor {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  /* Opaco del todo: con alfa, el texto del showroom se leia por detras del
     modelo y ensuciaba la lectura. */
  background: hsl(216, 28%, 7%);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0.3s ease;
}

.visor.is-abierto {
  opacity: 1;
  visibility: visible;
}

.visor__barra {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  color: hsl(0, 0%, 95%);
}

/* El color va explicito: la galeria corre en tema claro, y los h2 de la
   plantilla traen un color oscuro que sobre el visor no se leia. */
.visor__titulo {
  font-family: 'Bebas Neue', var(--font-primary, sans-serif);
  font-size: 1.6rem;
  letter-spacing: 0.04em;
  margin: 0;
  line-height: 1.1;
  color: hsl(0, 0%, 96%);
}

.visor__desc {
  margin: 0.3em 0 0;
  font-size: 0.85rem;
  line-height: 1.5;
  color: hsla(0, 0%, 100%, 0.66);
  max-width: 42ch;
}

.visor__cerrar {
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  border: 1px solid hsla(0, 0%, 100%, 0.24);
  border-radius: 50%;
  background: none;
  color: hsl(0, 0%, 95%);
  cursor: pointer;
  transition: background-color 0.2s ease, border-color 0.2s ease;
}

.visor__cerrar:hover,
.visor__cerrar:focus-visible {
  background: var(--joik-cyan-suave);
  border-color: var(--joik-cyan-borde);
  color: var(--joik-cyan);
}

.visor__cerrar svg {
  width: 1.1rem;
  height: 1.1rem;
}

.visor__lienzo-wrap {
  position: relative;
  flex: 1;
  min-height: 0;
  /* touch-action pan-y NO: dentro del visor el gesto gira el modelo. El visor
     es una capa a pantalla completa, asi que no hay scroll que robarle. */
  touch-action: none;
}

.visor__lienzo-wrap canvas {
  display: block;
  width: 100%;
  height: 100%;
  cursor: grab;
}

.visor__lienzo-wrap canvas:active {
  cursor: grabbing;
}

.visor__pie {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md) var(--space-md);
}

.visor__ayuda {
  margin: 0;
  font-family: var(--font-primary, sans-serif);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: hsla(0, 0%, 100%, 0.5);
}

.visor__acciones {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6em;
}

.visor__btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.7em 1.3em;
  border: 1px solid hsla(0, 0%, 100%, 0.26);
  border-radius: 999px;
  background: none;
  color: hsl(0, 0%, 95%);
  font-family: var(--font-primary, sans-serif);
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.2s ease, border-color 0.2s ease;
}

.visor__btn:hover,
.visor__btn:focus-visible {
  background: var(--joik-cyan-suave);
  border-color: var(--joik-cyan-borde);
  color: hsl(0, 0%, 98%);
}

.visor__btn--primario {
  background: hsl(0, 0%, 96%);
  color: hsl(216, 25%, 10%);
  border-color: hsl(0, 0%, 96%);
}

.visor__btn--primario:hover,
.visor__btn--primario:focus-visible {
  background: var(--joik-cyan);
  border-color: var(--joik-cyan);
  color: hsl(216, 28%, 8%);
}

/* El body no scrollea mientras el visor esta abierto. */
body.visor-abierto {
  overflow: hidden;
}

/* --- Accesibilidad ------------------------------------------------------ */

.lab-skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 0.8em 1.2em;
  background: hsl(0, 0%, 10%);
  color: hsl(0, 0%, 100%);
  text-decoration: none;
}

.lab-skip:focus {
  left: var(--space-sm);
  top: var(--space-sm);
}

.lab-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--joik-cyan);
  outline-offset: 3px;
}

/* --- Movimiento reducido ------------------------------------------------ */

/* El modelo sigue estando y sigue girando con el scroll (eso es el contenido,
   no decoracion), pero se quita todo lo que se mueve por si solo. */
@media (prefers-reduced-motion: reduce) {
  .exp-seccion__inner,
  .exp-escenario canvas,
  .visor,
  .exp-cta,
  .prod-card__abrir {
    transition-duration: 0.01ms !important;
  }

  .exp-seccion__inner {
    opacity: 1;
    transform: none;
  }

  .exp-scroll__linea {
    animation: none;
    transform: scaleY(1);
  }
}

/* --- Responsive --------------------------------------------------------- */

/* Por debajo de 1024px el reparto deja de ser izquierda/derecha y pasa a ser
   arriba/abajo.
   POR QUE. Una tablet en vertical (820x1180) no tiene ancho para una columna
   de texto legible Y el producto al lado: medido, el ensamble se salia por el
   borde derecho. Con el producto arriba y el texto abajo entran los dos.
   Una tablet apaisada (1024x768) sigue usando el reparto de desktop. */
@media (max-width: 1023px) {
  .exp-seccion {
    align-items: flex-end;
    padding: var(--space-lg) 0;
  }

  .exp-seccion__inner,
  .exp-seccion--derecha .exp-seccion__inner,
  .exp-seccion--centro .exp-seccion__inner {
    width: 100%;
    min-width: 0;
    max-width: 100%;
    margin-left: 0;
    margin-right: 0;
    text-align: left;
    padding-bottom: 7rem;
  }

  .exp-seccion--derecha,
  .exp-seccion--centro {
    justify-content: flex-start;
  }

  .exp-seccion--derecha .exp-bajada,
  .exp-seccion--centro .exp-bajada {
    margin-left: 0;
    margin-right: 0;
  }

  /* La linea de acento sigue al texto: en movil el bloque es a la izquierda,
     asi que los margenes automaticos de escritorio la dejaban suelta. */
  .exp-seccion--derecha .exp-conteo::before,
  .exp-seccion--centro .exp-conteo::before {
    margin-left: 0;
    margin-right: 0;
  }

  /* El velo radial de la columna ya no hace falta: el degradado del escenario
     cubre toda la franja inferior de lectura. */
  .exp-seccion__inner::before,
  .exp-seccion--derecha .exp-seccion__inner::before,
  .exp-seccion--centro .exp-seccion__inner::before {
    display: none;
  }

  /* Degradado de apoyo, el mismo que ya usaba movil. */
  .exp-escenario::after {
    background:
      radial-gradient(75% 65% at 50% 38%, transparent 40%, var(--exp-vineta) 100%),
      linear-gradient(to top, var(--exp-franja) 0%, var(--exp-franja-media) 28%, transparent 52%);
  }
}

@media (max-width: 767px) {

  /* Bloque de texto mas compacto. La seccion 02 lleva ademas la lista de
     detalles y medía 599px de 844: el producto se quedaba sin sitio y el
     titular caia justo sobre la parte mas clara del objeto. */
  .exp-titular {
    font-size: clamp(1.9rem, 8vw, 2.7rem);
  }

  .exp-bajada {
    font-size: 0.95rem;
    line-height: 1.5;
  }

  .exp-detalles {
    margin-top: 1.3em;
    gap: 0.55em;
  }

  .exp-detalles li {
    padding-top: 0.55em;
    font-size: 0.88rem;
    line-height: 1.45;
  }

  .exp-detalles b {
    font-size: 0.95rem;
  }

  .exp-conteo {
    margin-bottom: 0.8em;
  }


  .exp-scroll {
    bottom: 4.8rem;
  }

  .exp-provisional {
    bottom: 8.5rem;
    left: var(--space-sm);
  }

  /* Los destinos siguen legibles y táctiles aunque se oculten sus subtítulos. */
  .lab-bar__detalle {
    display: none;
  }

  .visor__barra {
    padding: var(--space-xs) var(--space-sm);
  }

  .visor__titulo {
    font-size: 1.3rem;
  }

  .visor__desc {
    display: none;
  }

  .visor__pie {
    padding: var(--space-xs) var(--space-sm) var(--space-sm);
    justify-content: center;
  }

  .visor__ayuda {
    width: 100%;
    text-align: center;
    order: 2;
  }

  .visor__acciones {
    width: 100%;
    justify-content: center;
  }
}

/* P04 — tienda conceptual, sobre la composición editorial Jack Ryan. */
.lab-contacto { display:inline-block; color:#c1eafa; font-size:.85rem; margin-top:1.2rem; }
.tienda .main-header__layout { display:flex; align-items:center; justify-content:space-between; }
.tienda .main-header { background:rgba(255,255,255,.94); }
.tienda-bolsa { display:flex; align-items:center; gap:12px; border:0; background:transparent; color:#20262d; font:inherit; font-size:.8rem; cursor:pointer; min-height:44px; }
.tienda-bolsa span { display:grid; place-items:center; width:28px; height:28px; border:1px solid #95a1a9; border-radius:50%; font-size:.7rem; }
.tienda .showroom-intro { padding-bottom:2rem; }
.tienda .showroom-intro h1 { max-width:14ch; }
.tienda .showroom-aviso { max-width:65ch; font-size:.8rem; color:#56616b; }
.tienda .work-card__content { position:static; padding:28px 28px 30px; background:none; }
.tienda .work-card__title { font-size:2.3rem; color:#20262d; margin:0 0 12px; }
.tienda .work-card__badge { color:#586571; font-size:.7rem; line-height:1.35; margin-bottom:12px; }
.tienda .prod-card__detalle { min-height:3.4em; margin:0; font-size:.85rem; line-height:1.55; color:#58616b; }
.tienda .prod-card__visual { background:#e3e8ec; }
.tienda-numero { position:absolute; z-index:2; top:16px; left:16px; color:#4d5b68; font-size:.68rem; letter-spacing:.12em; }
.tienda-precio { color:inherit; font-size:1.2rem; letter-spacing:.03em; margin:1rem 0 .3rem; }
.tienda .work-card__content .tienda-precio { margin:auto 0 0; padding-top:26px; }
.tienda-precio span { font-size:.65rem; color:#606c77; }
.tienda-acciones { display:grid; gap:10px; margin-top:20px; padding-top:18px; border-top:1px solid #ccd2d7; }
.tienda .prod-card__abrir { margin:0; min-height:44px; }
.tienda-btn { border:1px solid #a7b0b8; border-radius:30px; padding:.7em 1.1em; color:#20262d; background:transparent; font-family:inherit; font-size:.75rem; cursor:pointer; min-height:44px; }
.tienda-btn:hover { background:#d7f5fb; border-color:#16829a; }
.tienda-btn--oscuro { background:#20262d; color:white; width:100%; margin-top:1.4rem; padding:1rem; }
.tienda-btn--oscuro:hover { background:#30535f; color:white; }
.tienda button:disabled { opacity:.4; cursor:default; }
.tienda-cierre { border-top:1px solid #ced4d9; margin-top:1.5rem; padding-top:3rem; padding-bottom:2rem; }
.tienda-cierre h2 { font-family:'Bebas Neue',sans-serif; font-size:clamp(2rem,4vw,3.6rem); line-height:1.05; margin:0 0 1.5rem; }
.tienda-contacto { color:#253b45; border-bottom:1px solid #07859f; font-size:.9rem; text-decoration:none; }
.tienda-creditos { margin-top:3rem; font-size:.75rem; color:#52616b; max-width:75ch; }
.tienda-creditos summary { cursor:pointer; padding:1rem 0; color:#26343d; }
.tienda-creditos li { margin:.8rem 0; line-height:1.6; }
.tienda-creditos a { color:#255b70; text-decoration:underline; }
.visor.tienda-ficha { width:100%; height:100%; height:100dvh; max-width:none; max-height:none; margin:0; border:0; padding:0; overflow:auto; color:#f0f2f4; }
.visor.tienda-ficha:not([open]) { display:none; }
.visor.tienda-ficha[open] { display:block; opacity:1; visibility:visible; }
.tienda-ficha__cabecera { display:flex; align-items:center; justify-content:space-between; gap:1rem; padding:1.3rem 3vw; }
.tienda-ficha__cabecera .lab-marca__nombre { color:#fff; }
.tienda-ficha__layout { display:grid; grid-template-columns:minmax(0,1.4fr) minmax(0,1fr); gap:4vw; padding:0 5vw 3rem 3vw; align-items:center; min-height:calc(100dvh - 100px); }
.tienda-ficha__modelo { min-width:0; }
.tienda-ficha .visor__lienzo-wrap { height:62vh; min-height:340px; max-height:760px; background:radial-gradient(ellipse at 50% 35%,#293642,#111820 72%); border-radius:4px; }
.tienda-ficha__poster { position:absolute; inset:0; width:100%; height:100%; object-fit:contain; }
.tienda-ficha [hidden] { display:none !important; }
.tienda-ficha .visor__titulo { font-size:clamp(3rem,5vw,5.5rem); line-height:1; margin:.7rem 0; }
.tienda-ficha .tienda-precio { font-size:1.6rem; margin:1.4rem 0 .3rem; }
.tienda-ficha__info { font-size:.86rem; line-height:1.65; }
.tienda-ficha__info .visor__desc { font-size:1rem; line-height:1.65; margin:1.5rem 0; }
.tienda-ficha__info .showroom-intro__kicker { color:#a2bdca; }
.tienda-ficha__info p { color:#c4ccd3; }
.tienda-agregar { margin-bottom:1.8rem; min-height:48px; padding:.9rem 1.8rem; }
.tienda-ficha .tienda-nota { color:#a1adb8; font-size:.7rem; line-height:1.6; }
.tienda-ficha__info a { color:#b8eafa; text-decoration:underline; }
.tienda-especificaciones { margin:1.5rem 0; }
.tienda-especificaciones div { display:flex; justify-content:space-between; gap:1rem; border-top:1px solid #34404b; padding:.7rem 0; font-size:.75rem; }
.tienda-especificaciones dt { color:#9dabb7; }
.tienda-especificaciones dd { margin:0; text-align:right; color:#e0e6eb; }
.tienda-controles { display:flex; justify-content:center; flex-wrap:wrap; gap:8px; padding:1rem 0 .8rem; }
.tienda-controles button { min-width:44px; min-height:44px; justify-content:center; }
.tienda-ficha .visor__ayuda { text-align:center; font-size:.6rem; line-height:1.5; color:#b4bec7; }
.tienda-carrito { position:fixed; inset:0 0 0 auto; margin:0; width:520px; max-width:100%; height:100%; height:100dvh; max-height:none; padding:clamp(20px,3vw,36px); border:0; background:#f6f7f8; color:#20262d; overflow:auto; }
.tienda-carrito::backdrop { background:rgba(5,12,18,.72); backdrop-filter:blur(5px); }
.tienda-carrito__cabecera { display:flex; align-items:center; justify-content:space-between; gap:1rem; }
.tienda-carrito h2 { font-family:'Bebas Neue',sans-serif; font-size:2.7rem; margin:0; }
.tienda-nota { font-size:.75rem; color:#5b6670; margin:.7rem 0; }
.tienda-linea { display:grid; grid-template-columns:80px minmax(0,1fr); gap:18px; border-top:1px solid #cbd3d9; padding:1.4rem 0; }
.tienda-linea img { width:80px; height:105px; object-fit:cover; border-radius:3px; }
.tienda-linea h3 { font-family:'Bebas Neue',sans-serif; font-size:1.7rem; margin:0; color:#20262d; }
.tienda-linea p { font-size:.75rem; margin:.2rem 0 .6rem; color:#58636d; }
.tienda-cantidad { display:flex; align-items:center; flex-wrap:wrap; gap:8px; font-size:.85rem; }
.tienda-cantidad .tienda-btn { min-width:44px; padding:.5rem; }
.tienda-eliminar { color:#536775; background:none; border:0; font-size:.7rem; text-decoration:underline; cursor:pointer; min-height:44px; padding:0 5px; }
.tienda-carrito__total { display:flex; justify-content:space-between; gap:1rem; padding-top:1.4rem; border-top:1px solid #b8c2ca; font-size:1rem; }
.tienda-vacio { padding:3rem 0; font-size:1rem; color:#596974; }
.tienda-compra { margin:1.4rem 0; padding:1rem; border-left:3px solid #188198; background:#e3f4f7; font-size:.9rem; line-height:1.6; }
.tienda-anuncio { position:fixed; z-index:65; right:20px; bottom:85px; max-width:calc(100% - 40px); background:#1c303d; color:#fff; border:1px solid #70b3c1; border-radius:5px; padding:12px 20px; font-size:.8rem; opacity:0; pointer-events:none; transition:opacity .2s; }
.tienda-anuncio--visible { opacity:1; }
@media(max-width:900px) {
 .tienda-ficha__layout { grid-template-columns:1fr; padding:0 6vw 3rem; gap:2rem; }
 .tienda-ficha .visor__lienzo-wrap { height:48vh; min-height:280px; max-height:520px; }
 .tienda-ficha__info { max-width:620px; width:100%; margin:auto; }
 .tienda-ficha__cabecera { padding:1rem 5vw; }
 .tienda-ficha__cabecera .lab-marca__nombre { display:none; }
 .tienda-ficha__cabecera .visor__btn { font-size:.64rem; letter-spacing:.03em; padding:.65rem .9rem; }
}
@media(max-width:600px) {
 .tienda .showroom-intro { padding-top:1rem; }
 .tienda .prod-card__detalle { min-height:0; }
 .tienda .work-grid { padding-top:1rem; }
 .tienda .tienda-acciones { gap:10px; }
 .tienda-carrito__cabecera h2 { font-size:2.2rem; }
 .tienda-ficha .visor__lienzo-wrap { min-height:250px; height:40vh; }
 .tienda-linea { grid-template-columns:64px minmax(0,1fr); gap:12px; }
 .tienda-linea img { width:64px; height:90px; }
 .tienda-cantidad { gap:5px; }
}
@media(prefers-reduced-motion:reduce) {
 .tienda *, .lab-ficha, .lab-ficha__img { transition:none !important; animation:none !important; }
}

/* Header clearance and native-dialog defaults overridden by the template reset. */
.lab-selector { padding:120px 0 7rem; }
.tienda-carrito:not([open]) { display:none; }
.tienda .prod-card__detalle { text-transform:none; }
.tienda .showroom-aviso { background:#f2f4f5; }
@media(max-width:600px){ .lab-selector { padding-top:105px; } }
.lab-selector { height:auto; display:block; }
.tienda .main-header__logo { width:auto; flex:0 1 auto; min-width:0; }
.tienda .tienda-bolsa { flex:0 0 auto; }/* Jack Ryan extiende el fondo al 110%; la cabecera de tienda lo contiene. */
.tienda .main-header::after { width:100%; left:0; right:0; }/* La firma conceptual queda fuera del texto de las tres secciones. */
.exp-provisional { top:72px; bottom:auto; left:20px; max-width:calc(100vw - 40px); font-size:.58rem; }
.tienda-ficha .visor__desc { display:block; }
.tienda .main-header {
  position: fixed;
  z-index: 45;
  top: 0;
  left: 0;
  right: 0;
  width: 100%;
  padding-inline: max(20px, calc((100vw - 1200px) / 2));
}

@media (min-width: 1200px) {
  .tienda .container {
    max-width: 1200px;
  }
}

@media (min-width: 768px) and (max-width: 991px) {
  .tienda .ms-content {
    max-width: calc(100% - 40px);
  }
  .tienda .showroom-rejilla > .grid-item {
    padding-inline: 15px;
  }
  .tienda .work-card__content {
    padding: 20px 18px 22px;
  }
}

@media (max-width: 600px) {
  .tienda .showroom-rejilla > .grid-item {
    padding-inline: 15px;
  }
  .tienda .work-card__content {
    padding: 20px 20px 22px;
  }
}

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


/* ===========================================================================
   P09 · Split-screen de la Demo 01
   ---------------------------------------------------------------------------
   El producto queda fijo en una banda superior y el texto avanza por debajo.

   COMO FUNCIONA. El escenario sigue siendo sticky, pero ahora mide una banda
   (--exp-banda) en vez de la pantalla entera. La capa de texto se sube con un
   margen negativo de esa misma banda, asi la primera seccion empieza arriba
   del todo. Cada seccion reserva la banda como padding y fija su bloque de
   texto con sticky al borde inferior de la banda.

   NO HAY UN SEGUNDO SCROLL. El documento se desplaza como cualquier pagina;
   lo unico que hace el JS es leer su posicion. Ni preventDefault, ni rueda
   capturada, ni scroll dentro de un panel, ni esperas: por eso se puede
   volver atras y el recorrido se deshace igual que se hizo.

   POR QUE EL TEXTO VA CON STICKY Y NO EN FLUJO SECO. Con el texto en flujo
   normal, entre un bloque y el siguiente la zona inferior se quedaba vacia
   mas de media pantalla: el bloque saliente se metia detras de la banda
   bastante antes de que el entrante asomara por abajo. Fijandolo al borde de
   la banda, cada bloque llega, se queda quieto y recien despues se va.

   LA ALTURA MANDA, NO EL ANCHO. Medido: con la banda al 54% el bloque de la
   seccion 02 era mas alto que la zona de lectura, la seccion crecia para
   contenerlo y el sticky se quedaba sin recorrido, asi que el texto nunca se
   detenia y entraba parcialmente debajo de la banda. De ahi que los cortes de
   este bloque sean por `max-height` y no solo por ancho: lo que escasea en un
   split es alto. La regla que hay que respetar al tocar cualquier valor es
   banda + aire + alto del bloque + hueco del dock <= alto de la ventana.

   Todo cuelga de [data-layout="split"], que esta puesto en el HTML sobre
   .exp-recorrido. Al no depender del JS no hay parpadeo al cargar, y quitar
   el atributo devuelve el recorrido anterior intacto.

   Las alturas van en dvh sin respaldo en vh a proposito: la pagina necesita
   import maps para cargar three.js, y todo navegador que los soporta
   (Chrome 89, Safari 16.4, Firefox 108) entiende dvh desde antes.
   ======================================================================== */

[data-layout="split"] {
  /* Unica fuente de verdad del tamano de la banda. El canvas no lo repite:
     mide su propia caja (ver escena-base.js, ajustarTamano). */
  --exp-banda: 46dvh;
  --exp-col: 100%;
  /* Aire entre el borde de la banda y el titular. */
  --exp-aire: 1.7rem;
  /* Sitio para que el dock flotante no quede encima del final del texto. */
  --exp-hueco-dock: 4.5rem;
  /* Donde empieza el texto. El padding de la columna y el top del sticky usan
     el mismo valor; si se separan, el texto da un salto al pegarse. */
  --exp-texto-top: calc(var(--exp-banda) + var(--exp-aire));

  /* Banda y zona de lectura comparten el color del empalme (--exp-fondo-2),
     asi el limite entre las dos no se lee como una costura. */
  background: var(--exp-fondo-2);
}

[data-layout="split"] .exp-escenario {
  height: var(--exp-banda);
  width: var(--exp-col);
  /* Por encima del texto, al contrario que en el recorrido anterior: el texto
     tiene que desaparecer limpio al cruzar el borde de la banda, no quedar
     pisando el producto.
     Y por debajo de la cabecera, que es fija y vive en z-index 2. Con la
     banda en 6 la tapaba entera: desaparecian la marca y el conmutador de
     tema. De ahi que el par sea 1 y 0 y no 6 y 1. */
  z-index: 1;
}

/* Cierre de la banda: un degradado corto hacia el color de la zona de
   lectura. La separacion entre areas la da la composicion, no una linea. */
[data-layout="split"] .exp-escenario::before {
  content: "";
  position: absolute;
  z-index: 2;
  inset: auto 0 0 0;
  height: 4rem;
  pointer-events: none;
  background: linear-gradient(to bottom, transparent, var(--exp-fondo-2));
}

/* La vineta estaba calculada para una pantalla completa y para que el texto
   se leyera encima del modelo. En una banda, y sin texto encima, solo
   apagaria el producto: se abre y se suaviza. */
[data-layout="split"] .exp-escenario::after {
  background: radial-gradient(
    90% 85% at 50% 45%,
    transparent 58%,
    var(--exp-vineta) 100%
  );
}

[data-layout="split"] .exp-capa {
  margin-top: calc(-1 * var(--exp-banda));
  z-index: 0;
}

/* La firma conceptual vivia arriba a la izquierda, donde no molestaba en una
   pantalla completa. Dentro de una banda estrecha cae justo sobre el
   producto, asi que baja al pie de la banda, que queda libre en las tres
   secciones. */
[data-layout="split"] .exp-provisional {
  top: auto;
  bottom: 0.9rem;
  left: var(--space-md);
}

[data-layout="split"] .exp-seccion {
  /* stretch para que .container ocupe el alto de la seccion: es el bloque que
     le da al sticky su recorrido. Con center o flex-end la columna medía lo
     que el texto, y el sticky no tenia donde moverse. */
  align-items: stretch;
  padding: 0;
  /* El overflow de la seccion estaba por el velo de lectura, que aca no se
     usa. Y habia que quitarlo igual: un ancestro con overflow distinto de
     visible se vuelve contenedor de scroll y anula el sticky de dentro. */
  overflow: visible;
}

[data-layout="split"] .exp-seccion > .container {
  /* Reserva la banda. Las secciones 2 y 3 no quedan tapadas por el producto
     porque su texto nunca entra en esta franja. */
  padding-top: var(--exp-texto-top);
  padding-bottom: var(--exp-hueco-dock);
}

[data-layout="split"] .exp-seccion__inner,
[data-layout="split"] .exp-seccion--derecha .exp-seccion__inner,
[data-layout="split"] .exp-seccion--centro .exp-seccion__inner {
  position: sticky;
  top: var(--exp-texto-top);
  width: 100%;
  max-width: 52rem;
  min-width: 0;
  margin-left: auto;
  margin-right: auto;
  padding-bottom: 0;
  /* Centrado en las tres: el reparto izquierda/derecha existia para dejarle
     media pantalla al producto. Ahora el producto tiene su propia banda. */
  text-align: center;
}

/* El velo de lectura separaba el texto del modelo cuando compartian sitio.
   Ya no lo comparten. */
[data-layout="split"] .exp-seccion__inner::before,
[data-layout="split"] .exp-seccion--derecha .exp-seccion__inner::before,
[data-layout="split"] .exp-seccion--centro .exp-seccion__inner::before {
  display: none;
}

[data-layout="split"] .exp-conteo::before,
[data-layout="split"] .exp-seccion--derecha .exp-conteo::before,
[data-layout="split"] .exp-seccion--centro .exp-conteo::before {
  margin-left: auto;
  margin-right: auto;
}

[data-layout="split"] .exp-bajada,
[data-layout="split"] .exp-seccion--derecha .exp-bajada,
[data-layout="split"] .exp-seccion--centro .exp-bajada {
  margin-left: auto;
  margin-right: auto;
  max-width: 46ch;
}

/* El titular del cierre habia tenido que achicarse para convivir con el
   producto en la misma pantalla. En el split las tres secciones comparten
   escala, y es una escala de zona baja: no de pantalla completa.
   El tope en vh no es decorativo: sin el, a 1280x720 el titular se comia la
   zona de lectura y el bloque dejaba de entrar. */
[data-layout="split"] .exp-titular,
[data-layout="split"] .exp-seccion--centro .exp-titular {
  font-size: min(clamp(2rem, 4.4vw, 3.4rem), 6vh);
  margin-bottom: 0.45em;
}

[data-layout="split"] .exp-seccion--centro .exp-bajada {
  font-size: inherit;
}

/* La lista de detalles pasa a tres columnas: la zona de texto es ancha y
   baja, y apilada no entraba. Es la misma informacion, repartida. */
[data-layout="split"] .exp-detalles {
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-sm);
  margin-top: 1.9em;
  text-align: left;
}

[data-layout="split"] .exp-detalles li {
  padding-top: 0.85em;
}

/* El indicador vivia a 5.5rem del borde para despegarse del dock. Dentro de
   la banda el dock no existe, y ese valor lo dejaba flotando en el medio. */
[data-layout="split"] .exp-scroll {
  bottom: 1rem;
}

/* La linea medía 2.6rem porque cruzaba una pantalla entera. En la banda, con
   el producto centrado y mas grande, le pasaba por encima la punta. */
[data-layout="split"] .exp-scroll__linea {
  height: 1.4rem;
}

/* --- Tablet ------------------------------------------------------------- */

/* Una tablet en vertical es el caso mas holgado de todos: 1180px de alto dan
   de sobra para las dos zonas, asi que la banda se queda con mas sitio. */
@media (max-width: 1023px) {
  [data-layout="split"] {
    --exp-banda: 48dvh;
  }

  /* El reparto arriba/abajo que hacia el responsive ya lo hace el split, y lo
     hace con la banda: estas secciones vuelven a estar centradas. */
  [data-layout="split"] .exp-seccion,
  [data-layout="split"] .exp-seccion--derecha,
  [data-layout="split"] .exp-seccion--centro {
    align-items: stretch;
    justify-content: center;
  }
}

/* --- Movil -------------------------------------------------------------- */

/* La banda cede sitio en el telefono porque la lista de detalles va apilada y
   es el bloque mas alto del recorrido. Medido a 390x844: con la banda al 46%
   el bloque de la seccion 02 se pasaba 26px y se metia debajo del dock. */
@media (max-width: 767px) {
  [data-layout="split"] {
    --exp-banda: 38dvh;
    --exp-aire: 1.2rem;
    /* El dock compacto se pega mas al borde y suma la zona segura. */
    --exp-hueco-dock: calc(5.5rem + env(safe-area-inset-bottom, 0px));
  }

  /* Apilada de nuevo: a 390px, tres columnas dejan dos palabras por linea. */
  [data-layout="split"] .exp-detalles {
    grid-template-columns: 1fr;
    gap: 0.7em;
    margin-top: 1.3em;
  }

  [data-layout="split"] .exp-titular,
  [data-layout="split"] .exp-seccion--centro .exp-titular {
    font-size: clamp(1.75rem, 7.5vw, 2.4rem);
  }

  [data-layout="split"] .exp-escenario::before {
    height: 2.75rem;
  }

  [data-layout="split"] .exp-scroll {
    bottom: 0.7rem;
  }
}

/* --- Ventana baja de escritorio ----------------------------------------- */

/* Un portatil de 720px de alto tiene ancho de sobra y alto justo. Lleva
   min-width para no pisar al telefono, que ya resolvio su reparto por ancho y
   con otra tipografia. */
@media (min-width: 768px) and (max-height: 800px) {
  [data-layout="split"] {
    --exp-banda: 42dvh;
  }

  [data-layout="split"] .exp-titular,
  [data-layout="split"] .exp-seccion--centro .exp-titular {
    font-size: min(clamp(1.9rem, 4vw, 2.8rem), 5.2vh);
  }
}

/* --- Pantallas bajas ---------------------------------------------------- */

/* Con poca altura, repartir mitad y mitad deja las dos zonas inservibles: la
   banda cede sitio y el texto se compacta para que siga entrando completo.
   El corte en 700px cubre el telefono bajo (360x640) y la ventana muy baja. */
@media (max-height: 700px) {
  [data-layout="split"] {
    --exp-banda: 36dvh;
    --exp-aire: 1rem;
  }

  [data-layout="split"] .exp-titular,
  [data-layout="split"] .exp-seccion--centro .exp-titular {
    font-size: clamp(1.4rem, 4.2vh, 2rem);
    margin-bottom: 0.35em;
  }

  [data-layout="split"] .exp-bajada {
    font-size: 0.9rem;
    line-height: 1.5;
  }

  [data-layout="split"] .exp-conteo {
    margin-bottom: 0.7em;
  }

  /* La linea de acento es lo primero que sobra cuando falta alto. */
  [data-layout="split"] .exp-conteo::before,
  [data-layout="split"] .exp-seccion--derecha .exp-conteo::before,
  [data-layout="split"] .exp-seccion--centro .exp-conteo::before {
    display: none;
  }

  /* auto-fit en vez de un numero fijo de columnas: esta consulta se cruza con
     la de movil (un telefono bajo cumple las dos) y un repeat(3) dejaria tres
     columnas de 110px a 360px de ancho. */
  [data-layout="split"] .exp-detalles {
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
    gap: var(--space-xs);
    margin-top: 1em;
    text-align: left;
  }

  [data-layout="split"] .exp-detalles li {
    font-size: 0.82rem;
    line-height: 1.45;
    padding-top: 0.6em;
  }

  [data-layout="split"] .exp-detalles b {
    font-size: 0.9rem;
    margin-bottom: 0.2em;
  }

  [data-layout="split"] .exp-cta {
    margin-top: 1.2em;
    padding: 0.75em 1.5em;
  }

  /* No cabe, y en una pantalla baja el recorrido se entiende solo. */
  [data-layout="split"] .exp-scroll {
    display: none;
  }
}

/* --- Telefono apaisado: el reparto gira ---------------------------------- */

/* POR QUE CAMBIA DE EJE. Medido a 740x360: con bandas horizontales quedaban
   158px para el producto y 202px para el texto, y ninguna de las dos zonas
   servia. Girar el reparto a dos columnas devuelve los 360px de alto a las
   dos: el producto ocupa la mitad izquierda completa y el texto la derecha.
   Siguen siendo dos areas y un solo scroll; lo unico que cambia es por donde
   se parte la pantalla. */
@media (max-height: 560px) and (min-width: 600px) and (orientation: landscape) {
  [data-layout="split"] {
    /* La banda pasa a ser columna: toma todo el alto y la mitad del ancho.
       --exp-banda sigue siendo el alto del escenario, y por eso el margen
       negativo de la capa y el canvas siguen cuadrando sin tocar nada. */
    --exp-banda: 100dvh;
    --exp-col: 44%;
    /* Debajo de la cabecera, que en esta pagina va fija arriba. */
    --exp-texto-top: 4.25rem;
    --exp-hueco-dock: 1.25rem;
  }

  [data-layout="split"] .exp-seccion > .container {
    /* Deja libre la columna del producto. Reemplaza el padding lateral de la
       plantilla solo del lado izquierdo; el derecho conserva su margen. */
    padding-left: calc(44% + 1.5rem);
  }

  [data-layout="split"] .exp-seccion__inner,
  [data-layout="split"] .exp-seccion--derecha .exp-seccion__inner,
  [data-layout="split"] .exp-seccion--centro .exp-seccion__inner {
    /* Sin sticky aca, a proposito. Con 360px de alto el bloque de la seccion
       02 mide mas que la ventana, y un sticky mas alto que la ventana se
       queda clavado arriba: su parte baja no se alcanza por mas que se
       desplace. En flujo normal el texto sube, se lee entero y responde al
       scroll en todo momento, que es lo que importa. */
    position: relative;
    top: auto;
    max-width: none;
    text-align: left;
  }

  [data-layout="split"] .exp-bajada,
  [data-layout="split"] .exp-seccion--derecha .exp-bajada,
  [data-layout="split"] .exp-seccion--centro .exp-bajada {
    margin-left: 0;
    margin-right: 0;
  }

  /* Una sola columna: la mitad de 740px no da para dos. */
  [data-layout="split"] .exp-detalles {
    grid-template-columns: 1fr;
    gap: 0.5em;
  }

  /* El degradado de cierre gira con el reparto: deja de estar abajo y pasa al
     canto derecho, que es por donde ahora se tocan las dos zonas. Sin el, el
     corte entre columnas se lee como dos paneles pegados. */
  [data-layout="split"] .exp-escenario::before {
    inset: 0 0 0 auto;
    width: 3.5rem;
    height: auto;
    background: linear-gradient(to right, transparent, var(--exp-fondo-2));
  }

  /* Vuelve arriba: el pie de la columna del producto es justo donde se posa
     el dock flotante. */
  [data-layout="split"] .exp-provisional {
    top: 4.5rem;
    bottom: auto;
  }
}

/* ===========================================================================
   P09.1 · La banda de la Demo 01 pasa a panel, en telefono
   ---------------------------------------------------------------------------
   QUE SE ARREGLA. Medido a 390x844 sobre el estado anterior: el escenario
   ocupaba los 390px de ancho con padding 0 y border-radius 0, es decir pegado
   a los tres bordes. El producto no estaba presentado, estaba apoyado. A eso
   se sumaban dos defectos de composicion que se ven en cuanto se mira la
   pantalla entera:

   · la pildora "DEMO CONCEPTUAL CREADA POR JOIK AGENCY" caia encima de la
     palabra "DESPLAZA" del indicador de scroll, las dos al pie de la banda;
   · entre el pie de la banda y el titular quedaban ~370px muertos, asi que el
     3D se veia apretado arriba y la pantalla vacia en el medio.

   COMO SE RESUELVE. El escenario se mete en un panel con margen a los lados,
   esquinas redondeadas, fondo propio y una sombra corta. El limite entre las
   dos zonas deja de ser un degradado que disimula una costura y pasa a ser el
   borde del panel, que es lo que el ojo ya espera de una tarjeta.

   EL PRODUCTO NO PIERDE SITIO, GANA. La banda sube de 38dvh a 44dvh y el
   panel se come 12px arriba y 10 abajo, asi que el canvas queda en 350px a
   390x844 contra los 321 de antes. Mas aire alrededor y mas producto.

   POR QUE 44dvh Y NO MAS. Manda la regla del bloque: banda + aire + alto del
   bloque + hueco del dock <= alto de la ventana. La seccion 02 es la mas alta
   del recorrido y a 46dvh se pasaba 26px, que es el motivo por el que esto
   estaba en 38. A 44dvh entra con margen, comprobado en las dos pantallas de
   la QA. Si alguien sube este valor, tiene que volver a medir la seccion 02.

   EL AIRE DE ENTRADA AL TEXTO baja de 1.2rem a 1rem a proposito: el panel ya
   separa visualmente, asi que el hueco de antes sobra y solo alejaba el
   titular.

   Solo telefono. Escritorio, tablet, ventana baja y apaisado no se tocan.
   =========================================================================== */

/* min-height: 561px deja fuera el modo apaisado, que reparte la pantalla por
   columnas y tiene su propia regla mas arriba (max-height: 560px). Sin esa
   condicion este bloque la pisaba, porque 740px de ancho tambien entra en
   max-width: 767px, y el reparto de dos columnas se perdia. */
@media (max-width: 767px) and (min-height: 561px) {
  [data-layout="split"] {
    --exp-aire: 1rem;
    /* Margen del panel. En un solo sitio para que el canvas, el degradado y
       la pildora usen el mismo numero. */
    --exp-panel-lado: 0.9rem;
    --exp-panel-alto: 0.75rem;
  }

  /* --- El panel -------------------------------------------------------- */
  [data-layout="split"] .exp-escenario {
    /* El alto util es la banda menos lo que se lleva el margen. */
    height: calc(var(--exp-banda) - var(--exp-panel-alto) - 0.6rem);
    width: auto;
    margin: var(--exp-panel-alto) var(--exp-panel-lado) 0;
    border-radius: 1.25rem;
    overflow: hidden;
    /* --exp-fondo-1 es, en los dos temas, un escalon mas claro que el fondo
       de pagina (--exp-fondo-2): 99% contra 94% en claro, 22% contra 12% en
       oscuro. Con una sola declaracion el panel se despega en ambos. Probar
       con un blanco translucido daba un gris lavado sobre el tema oscuro y
       apagaba el producto, que es negro. */
    background: var(--exp-fondo-1);
    /* El borde sostiene la forma donde la sombra no se ve, que es justo el
       tema oscuro. */
    border: 1px solid var(--exp-velo-suave);
    box-shadow: 0 10px 24px -16px rgba(0, 20, 28, 0.5);
  }

  /* El degradado de cierre existia para disimular el empalme entre la banda y
     la zona de lectura. Con panel hay un borde de verdad, asi que sobra: se
     apaga en vez de recortarlo contra las esquinas. */
  [data-layout="split"] .exp-escenario::before {
    display: none;
  }

  /* La vineta se cierra un poco mas que en pantalla completa para que el
     producto se despegue del fondo del panel sin apagarse. */
  [data-layout="split"] .exp-escenario::after {
    background: radial-gradient(
      92% 88% at 50% 46%,
      transparent 62%,
      var(--exp-vineta) 100%
    );
  }

  /* --- La firma deja de pisar al indicador ------------------------------ */
  /* Las dos vivian al pie de la banda y se superponian. La firma se queda
     dentro del panel, abajo a la izquierda; el indicador sale del panel y se
     va al carril de lectura, que ahi esta vacio. */
  [data-layout="split"] .exp-provisional {
    left: calc(var(--exp-panel-lado) + 0.75rem);
    right: auto;
    bottom: 0.6rem;
    transform: none;
    font-size: 0.6rem;
  }

  [data-layout="split"] .exp-scroll {
    bottom: auto;
    top: calc(var(--exp-banda) + 0.1rem);
  }
}

/* La banda sube SOLO donde el alto lo permite. Medido seccion por seccion:
   a 390x844 la 02 aguanta hasta 40dvh con holgura 0 y a 42 se pasa 7px; a
   360x640 ya se pasa 8px con 38. Por eso este valor lleva min-height y no
   solo max-width: sin esa condicion pisaba el @media (max-height: 700px) de
   mas arriba, que baja la banda a 36dvh, y rompia justo las pantallas bajas
   que esa regla protegia. */
@media (max-width: 767px) and (min-height: 701px) {
  [data-layout="split"] {
    --exp-banda: 40dvh;
  }
}

/* En pantalla baja el panel afina sus margenes: a 360x640 la banda vuelve a
   36dvh por la regla de mas arriba, y con el margen completo el producto
   perdia 21px contra el estado anterior. Con estos valores queda en 222px,
   que es lo que medía antes de tener panel. */
@media (max-width: 767px) and (min-height: 561px) and (max-height: 700px) {
  [data-layout="split"] {
    --exp-panel-lado: 0.7rem;
    --exp-panel-alto: 0.5rem;
  }

  [data-layout="split"] .exp-escenario {
    height: calc(var(--exp-banda) - var(--exp-panel-alto) - 0.25rem);
    border-radius: 1rem;
  }
}

/* ===========================================================================
   P09.1 · La Demo 02 se lee como tienda, en telefono
   ---------------------------------------------------------------------------
   QUE PASABA, MEDIDO A 390x844. La tarjeta media 330x800: mas alta que la
   ventana, asi que nunca entraba entera y solo se veia un producto por
   pantalla. Dentro, el visual se llevaba 437px porque esta en aspect-ratio
   3/4, y el titulo iba a 37px, que es tamano de titular editorial y no de
   ficha de producto. El conjunto se leia como una galeria grande, que es
   exactamente lo que se queria cambiar.

   QUE SE HACE. Nada de columnas: sigue siendo una sola, como se pidio. Lo que
   cambia es la proporcion interna de la ficha:

   · El visual pasa a cuadrado. Es el formato de ficha de producto por
     defecto en cualquier tienda, y aqui ademas le sienta bien a las tres
     piezas, que son anchas y no altas. Ahorra 109px de golpe.
   · El titulo baja a 1.45rem y el resto de la jerarquia se acompasa, para
     que el nombre del producto pese como nombre y no como portada.
   · Los espaciados internos se cierran: lo que antes era aire editorial
     ahora es la separacion justa entre dato y dato.
   · El precio sube junto a la descripcion en vez de empujarse al fondo con
     `margin: auto`, que es lo que estiraba la ficha cuando sobraba alto.

   PARA QUE SIRVE QUE SEA MAS BAJA. Con la ficha por debajo de la ventana se
   alcanza a ver el borde de la siguiente al terminar de leer la primera. Esa
   es la senal que distingue un catalogo de una galeria: se intuye que hay
   mas y se invita a seguir.

   LO QUE NO SE TOCA. El carrito y su logica, el selector, los destinos de los
   botones y el visor 3D siguen igual. Esto es proporcion y tipografia.

   Solo telefono: cuelga de max-width 767px. Escritorio y tablet intactos.
   =========================================================================== */

@media (max-width: 767px) {
  /* --- El visual, cuadrado --------------------------------------------- */
  .tienda .prod-card__visual {
    aspect-ratio: 1 / 1;
  }

  /* --- La ficha se cierra ---------------------------------------------- */
  .tienda .work-card__content {
    padding: 16px 18px 18px;
  }

  .tienda .work-card__badge {
    font-size: 0.6rem;
    letter-spacing: 0.14em;
  }

  .tienda .work-card__title {
    font-size: 1.45rem;
    margin: 0.3em 0 0.25em;
  }

  .tienda .prod-card__detalle {
    font-size: 0.88rem;
    line-height: 1.45;
  }

  /* El precio deja de empujarse al fondo: ese margin: auto era lo que
     estiraba la ficha cuando sobraba alto. */
  .tienda .tienda-precio {
    margin: 0.7em 0 0;
    padding-top: 0;
    font-size: 1.25rem;
  }

  /* --- Los dos botones, mas bajos y mas juntos -------------------------- */
  .tienda .prod-card__abrir,
  .tienda .tienda-btn {
    padding-block: 0.7rem;
    font-size: 0.78rem;
  }

  .tienda .prod-card__abrir {
    margin-top: 0.9rem;
  }

  .tienda .tienda-btn {
    margin-top: 0.5rem;
  }
}

/* ===========================================================================
   P09.2 · El panel de la Demo 01 respira, en telefono
   ---------------------------------------------------------------------------
   Revisado en un telefono real. El panel de P09.1 mejoro la presentacion pero
   el conjunto seguia apretado: la bisagra quedaba pegada al rotulo AUREA por
   arriba y a la etiqueta por abajo, sin aire que la presentara.

   DOS CAMBIOS, Y NINGUNO AGRANDA EL PANEL. La banda no puede crecer: a
   390x844 la seccion 02 ya esta al limite con 40dvh (ver seccion 19 del
   documento del lab). Asi que el aire sale de redistribuir lo que hay dentro,
   no de pedir mas alto.

   1. La etiqueta deja de ser una pastilla. Tenia borde, fondo y radio 999px,
      asi que se leia como un boton que invita a tocarse, y ademas ocupaba una
      franja entera al pie del panel. Pasa a pie editorial: sin caja, centrada,
      mas chica y en un tono secundario. Lo que ocupaba de caja se lo queda el
      producto.

   2. El modelo baja y afina su escala desde config-3d.js, no desde aqui: el
      encuadre 3D es asunto del modulo y meterlo en CSS daria dos fuentes de
      verdad. Ver SPLIT_PRODUCTO.encuadre.movil.

   EL CONTADOR, EL TITULAR Y EL PARRAFO tambien se acompasan: con la etiqueta
   sin caja el borde inferior del panel queda mas limpio y el salto al texto
   pedia menos aire, no mas.

   Solo telefono y solo en vertical: min-height 561px deja fuera el apaisado,
   que reparte por columnas y tiene su propia regla.
   =========================================================================== */

@media (max-width: 767px) and (min-height: 561px) {
  /* --- La firma, como pie editorial ------------------------------------ */
  [data-layout="split"] .exp-provisional {
    left: 50%;
    right: auto;
    bottom: 0.5rem;
    transform: translateX(-50%);
    width: max-content;
    max-width: calc(100% - 2.5rem);
    padding: 0;
    border: 0;
    background: none;
    border-radius: 0;
    /* Mas chica que el resto de los rotulos del recorrido y con el tracking
       justo para que no se lea como grito. El color sale de la paleta de
       texto secundario, que ya esta resuelta en los dos temas. */
    font-size: 0.55rem;
    letter-spacing: 0.12em;
    color: var(--exp-texto-suave, var(--color-contrast-medium));
    text-align: center;
    /* Es informativa: no debe interceptar el gesto de girar el producto. */
    pointer-events: none;
  }

  /* --- El salto del panel al texto ------------------------------------- */
  /* Sin la pastilla, el pie del panel quedo limpio y el aire de entrada
     sobraba: el titular se iba demasiado lejos del producto. */
  [data-layout="split"] {
    --exp-aire: 0.85rem;
  }
}

/* ===========================================================================
   P09.2 · La ficha de Aurea toma la jerarquia de una ficha de tienda
   ---------------------------------------------------------------------------
   DE DONDE SALE. El propietario paso una referencia comercial. Lo que se toma
   de ella es la ESTRUCTURA, no el contenido: nombre arriba y con peso,
   descripcion corta debajo, el producto en el medio sobre su propia
   superficie, y al pie el precio a la izquierda con el boton de compra a la
   derecha, en la misma linea. Ni marca, ni producto, ni precios, ni cuotas:
   el catalogo de Aurea sigue siendo el suyo y los precios siguen siendo
   ilustrativos, como dice el aviso de la pagina.

   QUE CAMBIA RESPECTO DE P09.1. El orden. Antes la ficha empezaba por la
   imagen y el nombre aparecia despues, que es como se presenta una obra en
   una galeria. Ahora empieza por el nombre, que es como se presenta un
   articulo en una tienda: primero que es, despues como se ve.

     antes   visual -> categoria -> nombre -> descripcion -> precio -> botones
     ahora   nombre -> categoria -> visual -> descripcion -> precio + boton

   COMO SE REORDENA SIN TOCAR EL MARCADO. El nombre y la imagen viven en
   ramas distintas del arbol —la imagen es hermana de un contenedor que
   agrupa todo el texto—, asi que `order` por si solo no alcanza: solo ordena
   hermanos. Con `display: contents` sobre ese contenedor y sobre el de los
   botones, sus hijos pasan a ser hijos directos de la tarjeta y entonces si
   se pueden ordenar y colocar en una rejilla. El HTML no se toca, con lo que
   el carrito, los enlaces a la ficha y el visor siguen encontrando lo mismo.

   EFECTO SECUNDARIO QUE HAY QUE REPONER: al volverse `contents`, el
   contenedor del texto deja de pintar su propio relleno. Por eso el relleno
   lateral se aplica elemento por elemento. La imagen tambien lo lleva, y con
   esquinas propias: en la referencia el producto esta sobre una superficie
   recuadrada dentro de la tarjeta, no a sangre.

   EL PRECIO Y EL BOTON COMPARTEN LINEA. Es lo que mas distingue una ficha de
   tienda de una de catalogo: el dato y la accion juntos, sin que haya que
   bajar la vista. "Ver producto" baja a renglon propio como enlace discreto,
   porque es exploracion y no compra.

   Una sola columna, como se pidio. Solo telefono.
   =========================================================================== */

/* 599.98px y no 767: medido, la rejilla de la tienda pasa a tres columnas a
   partir de 600px exactos (a 520 es una columna de 460px; a 600 son tres de
   140). Con el limite en 767 esta ficha de una columna se aplicaba tambien a
   tarjetas de 120px y el par precio + boton se salia de la caja. El breakpoint
   sigue a la rejilla real, no a un valor supuesto. */
@media (max-width: 599.98px) {
  /* El relleno lo pone la tarjeta, no cada hijo. Al ponerlo elemento por
     elemento el ancho de cada uno crecia por dentro y el conjunto se salia
     de la caja: medido, 16px fuera por la derecha a 390 y 46 a 360. */
  .tienda .work-card {
    display: grid;
    /* minmax(0, 1fr) y no 1fr: una columna 1fr no baja de su contenido
       minimo, asi que el boton, que va en nowrap, empujaba la rejilla mas
       alla del ancho de la tarjeta. Esa era la causa real del desborde. */
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    row-gap: 0;
    /* El hueco entre el precio y el boton. Sin el, el precio mas largo del
       catalogo ($ 179.000 ARS) llegaba a meterse debajo del boton: en la
       captura del telefono el "ARS" quedaba tapado. */
    column-gap: 16px;
    padding: 22px 20px 20px;
  }

  .tienda .work-card__content,
  .tienda .tienda-acciones {
    display: contents;
  }

  /* --- Orden de lectura: que es, como se ve, cuanto cuesta -------------- */
  .tienda .work-card__title { order: 1; }
  .tienda .work-card__badge { order: 2; }
  .tienda .prod-card__visual { order: 3; }
  .tienda .prod-card__detalle { order: 4; }
  .tienda .tienda-precio { order: 5; }
  .tienda .tienda-btn { order: 6; }
  .tienda .prod-card__abrir { order: 7; }

  .tienda .work-card__title,
  .tienda .work-card__badge,
  .tienda .prod-card__visual,
  .tienda .prod-card__detalle,
  .tienda .prod-card__abrir {
    grid-column: 1 / -1;
  }

  .tienda .tienda-precio { grid-column: 1; }
  .tienda .tienda-btn { grid-column: 2; }

  /* --- El aire de cada junta -------------------------------------------
     Medido antes: 3px entre nombre y categoria, 8 entre categoria y
     producto, 8 entre descripcion y precio. Todo pegado. Los valores de
     abajo son la escala que se buscaba: el nombre y su categoria juntos,
     porque son una unidad, y una separacion mayor y pareja entre bloques
     distintos. */
  .tienda .work-card__title {
    margin: 0 0 2px;
    padding: 0;
    font-size: 1.6rem;
    line-height: 1.08;
  }

  .tienda .work-card__badge {
    margin: 0 0 16px;
    padding: 0;
    font-size: 0.62rem;
  }

  /* --- El producto, sobre su superficie --------------------------------- */
  .tienda .prod-card__visual {
    margin: 0;
    border-radius: 14px;
    overflow: hidden;
  }

  .tienda .prod-card__detalle {
    margin: 18px 0 0;
    padding: 0;
    font-size: 0.86rem;
    line-height: 1.5;
  }

  /* --- Precio y accion, en la misma linea ------------------------------- */
  .tienda .tienda-precio {
    margin: 18px 0 0;
    padding: 0;
    font-size: 1.3rem;
    align-self: center;
    /* La moneda es parte del precio y va en la misma linea. */
    white-space: nowrap;
  }

  .tienda .tienda-btn {
    margin: 18px 0 0;
    width: auto;
    max-width: 100%;
    padding: 0.78rem 1.1rem;
    font-size: 0.78rem;
    white-space: nowrap;
    align-self: center;
  }

  /* --- Explorar en 3D: enlace, no boton --------------------------------- */
  /* Separado del bloque de compra para que se lea como accion secundaria y
     no como un segundo boton pegado al primero. */
  .tienda .prod-card__abrir {
    margin: 20px 0 0;
    padding: 0.5rem 0;
    border: 0;
    background: none;
    font-size: 0.76rem;
    text-decoration: underline;
    text-underline-offset: 0.3em;
  }
}

/* ---------------------------------------------------------------------------
   Tarjetas angostas de la tienda (600-767px)
   ---------------------------------------------------------------------------
   En ese rango la rejilla ya pone tres columnas pero el ancho total sigue
   siendo de telefono, asi que cada tarjeta mide unos 120px. Medido a 740x360
   antes de esta ronda: siete elementos se salian de su tarjeta, el peor por
   226px. Esta ficha de una columna no llega hasta aca —se corta en 599.98— y
   el residuo que quedaba eran el boton y el enlace, que no sabian encogerse.

   No se rehace la rejilla, que es diseno existente y esta fuera del alcance:
   solo se les permite achicarse para que no desborden.
   --------------------------------------------------------------------------- */
@media (min-width: 600px) and (max-width: 767px) {
  .tienda .tienda-btn,
  .tienda .prod-card__abrir {
    max-width: 100%;
    min-width: 0;
    white-space: normal;
    overflow-wrap: anywhere;
  }
}
