/* ==========================================================================
   barkys.css — pagina de caso, en clave de galeria
   --------------------------------------------------------------------------
   Reemplaza a caso-base.css + caso-barkys.css. Aquellas hojas estan hechas
   para fragmentos apilados dentro de /proyectos-pequenos/ y traen tema oscuro;
   esta pagina es propia y va en blanco fijo, asi que arrastrarlas era heredar
   problemas que aca no existen.

   TRES DECISIONES QUE EXPLICAN TODO LO DEMAS

   1. Un solo tema, blanco.  Las piezas de Barkys son rojas, amarillas y muy
      saturadas. Sobre fondo oscuro pierden el blanco de su propio fondo y se
      ven sucias. Ademas el caso se presenta como galeria, y una galeria se
      pinta de blanco por la misma razon que un museo.

   2. La pagina calla para que el trabajo hable.  Sin cajas, sin sombras, sin
      degradados, sin rotulos sobre las imagenes. El rojo de marca es el unico
      acento y tiene un solo trabajo: marcar los titulos de seccion y el boton.
      Rojo = lo que pone Barkys. Negro = lo que dice el estudio.

   3. Radio 0 en todo, sin excepcion.  Incluido el boton. Un borde redondeado
      dentro de una rejilla de cuadrados es ruido.

   PALETA — muestreada de los JPG originales, no inventada:
     #E5383C  rojo de marca      #EEBD00  amarillo Chuletitas
   El rojo de marca da 4,23:1 sobre blanco y NO pasa AA. El token de acento es
   #D0262B, el mismo rojo bajado hasta 5,26:1. El vivo no se usa en interfaz.
   ========================================================================== */

/* TODO cuelga de `.caso-barkys`, no de `:root` ni de `body`. Asi la misma hoja
   sirve para la pagina suelta y para el fragmento incrustado en el sitio, sin
   pisar los tokens ni la tipografia de ballestastudio.com. Integrar es enlazar
   esta hoja y envolver el cuerpo en <div class="caso-barkys">, nada mas. */
.caso-barkys {
  color-scheme: light;

  --tinta:        #131313;
  --tinta-media:  #5c5c5c;   /* 6,9:1 sobre blanco */
  --tinta-suave:  #767676;   /* 4,7:1 sobre blanco: el minimo para texto */
  --linea:        #e8e8e8;
  --papel:        #ffffff;
  --papel-alt:    #fafafa;
  --rojo:         #d0262b;   /* 5,26:1 sobre blanco */
  --rojo-hondo:   #b81c21;   /* fondo del hero, bajo las tiras */

  /* Escala de espacio. Todo el ritmo vertical sale de aqui. */
  --e1: .5rem;  --e2: 1rem;   --e3: 1.5rem;  --e4: 2.5rem;
  --e5: 4rem;   --e6: 6rem;   --e7: clamp(5rem, 12vw, 9rem);

  --ancho: 1240px;
  --margen: clamp(1.25rem, 5vw, 3.5rem);

  --display: "Fredoka", ui-sans-serif, system-ui, sans-serif;
  --texto:   "Outfit", ui-sans-serif, system-ui, sans-serif;
  --dato:    "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --salida: cubic-bezier(.16, 1, .3, 1);
}

.caso-barkys, .caso-barkys *, .caso-barkys *::before, .caso-barkys *::after {
  box-sizing: border-box;
}

.caso-barkys {
  background: var(--papel);
  color: var(--tinta);
  font-family: var(--texto);
  font-weight: 300;
  font-size: clamp(1rem, .96rem + .2vw, 1.075rem);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* La pagina suelta no tiene mas contenido que el caso, asi que el papel sube
   al <body> para que cubra la ventana entera. En el sitio esta regla no
   aplica: alli el fondo lo pone el sitio. */
body:has(> .caso-barkys) { margin: 0; background: var(--papel); }

.caso-barkys img, .caso-barkys video { display: block; max-width: 100%; }

.caso-barkys a { color: inherit; }

.caso-barkys ::selection { background: var(--rojo); color: #fff; }

.caso-barkys :focus-visible { outline: 2px solid var(--rojo); outline-offset: 3px; }

.contenedor { max-width: var(--ancho); margin-inline: auto; padding-inline: var(--margen); }

.salta {
  position: absolute; left: -9999px;
}
.salta:focus {
  left: var(--margen); top: var(--e2); z-index: 60;
  padding: .7rem 1.1rem; background: var(--tinta); color: #fff;
  font-family: var(--dato); font-size: .82rem;
}

/* --- Apertura -----------------------------------------------------------
   Antes aqui iba la lamina de Behance a sangre. Se retiro por dos razones:

     1. Resolucion. El original mide 1920 px y el hero ocupa el ancho de la
        ventana, asi que en cualquier monitor grande o pantalla retina se
        estiraba y se veia blando. Ese limite es del archivo, no del codigo:
        no hay forma de arreglarlo sin reexportar el PSD de 315 MB.
     2. Contenido. Una lamina entera de presentacion como primer pantallazo
        dice mucho antes de que nadie haya pedido nada.

   Lo que hay ahora es corto y se mueve: el FONDO son las piezas reales
   desplazandose en tiras a distintas velocidades, y encima va una frase que
   invita a bajar. El fondo es el trabajo, que es lo que se vino a ver.

   Cuatro tiras y no mas: pasada esa cantidad el efecto no gana profundidad y
   si multiplica el coste de pintado. */

.portada {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: min(78dvh, 760px);
  overflow: hidden;
  background: var(--rojo-hondo);
  isolation: isolate;
}

.portada__fondo {
  position: absolute; inset: 0;
  z-index: -2;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(8px, 1.2vw, 16px);
  padding: clamp(8px, 1.2vw, 16px);
}
@media (max-width: 699px) {
  .portada__fondo { grid-template-columns: repeat(2, 1fr); }
  .portada__fondo > :nth-child(n+3) { display: none; }
}

.tira {
  display: grid;
  gap: clamp(8px, 1.2vw, 16px);
  align-content: start;
  /* La tira se sale por arriba y por abajo a proposito: asi el bucle nunca
     ensena un borde. El contenedor recorta. */
  will-change: transform;
}
.tira img { width: 100%; height: auto; }

/* El velo. Va aparte del fondo y no como sombra sobre el texto, porque tiene
   que cubrir 15 imagenes de colores muy distintos por igual. A 0,90 el blanco
   encima pasa AA contra cualquiera de ellas. */
.portada__velo {
  position: absolute; inset: 0;
  z-index: -1;
  background:
    linear-gradient(to top, rgb(140 18 22 / .55), transparent 62%),
    rgb(184 28 33 / .90);
}

.portada__texto {
  position: relative;
  width: 100%;
  padding-block: clamp(6rem, 14vw, 9rem) clamp(2.5rem, 6vw, 4.5rem);
  color: #fff;
}
.portada__rotulo {
  margin: 0 0 var(--e2);
  font-family: var(--dato);
  font-size: .74rem; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase;
  color: rgb(255 255 255 / .82);
}
.portada__titulo {
  margin: 0;
  max-width: 22ch;
  font-family: var(--display); font-weight: 600;
  font-size: clamp(2.1rem, 5.2vw, 3.9rem);
  line-height: 1.06; letter-spacing: -.03em;
  color: #fff;
  /* Son dos frases: `balance` las reparte en dos lineas parejas en vez de
     dejar "una." sola abajo. Se prefiere a un <br> fijo, que se rompe en
     cuanto cambia el ancho o el idioma. */
  text-wrap: balance;
}
.portada__bajada {
  margin: var(--e3) 0 0;
  max-width: 46ch;
  font-size: clamp(1.02rem, .95rem + .35vw, 1.2rem);
  color: rgb(255 255 255 / .92);
  /* Reparte las dos lineas en vez de dejar "para perro." colgando sola. Se
     prefiere a un <br> fijo: el <br> corta igual de bien en espanol y mal en
     ingles, y se rompe en cuanto cambia el ancho o el cuerpo de la fuente. */
  text-wrap: balance;
}

/* --- La marca -----------------------------------------------------------
   El logo y nada mas, como en el caso de Exopartes: sin barra, sin fondo, sin
   linea y sin quedarse pegado al hacer scroll. Va montado sobre la lamina,
   alineado con el margen del contenedor.

   Usa el lockup INVERTIDO (`logo-ballestastudio-blanco.webp`), que es el que el
   estudio ya tiene para fondos de color. El logo normal es negro con turquesa
   y sobre el rojo de la lamina no se leeria. */

.marca {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 3;
  max-width: var(--ancho);
  margin-inline: auto;
  padding: clamp(var(--e2), 2.5vw, var(--e4)) var(--margen);
}
/* El enlace se cine al logo. Si la caja clicable fuera toda la franja, medio
   pantallazo llevaria al inicio sin avisar. */
.marca a { display: inline-block; }
.marca img { width: clamp(104px, 11vw, 132px); height: auto; }


/* --- Lamina a sangre ----------------------------------------------------
   Ancho completo de la VENTANA, no del contenedor. Las laminas ya estan
   compuestas sobre blanco, asi que no necesitan marco ni pie: se sientan
   sobre el papel de la pagina y el corte no se ve. Sin pie de foto a
   proposito: una linea gris debajo de una imagen que ocupa la pantalla la
   convierte en una ilustracion con leyenda y le quita la fuerza.

   Sin trucos de 100vw: la figura es hija directa de <main>, que ya ocupa todo
   el ancho del documento. El `max-width` vive en `.contenedor`, y estas
   figuras no lo llevan. Un `width: 100vw` aqui solo serviria para sumar los
   pixeles de la barra de scroll y provocar desborde horizontal. */

.lamina {
  margin-block: clamp(3.5rem, 7vw, 5.5rem);
  /* El navegador le da a <figure> un margen lateral de 40 px por su cuenta.
     `margin-block` no lo toca, asi que hay que anularlo a mano o la lamina se
     queda 80 px angosta y deja de ir a sangre. */
  margin-inline: 0;
  overflow: hidden;
}
.lamina img { width: 100%; height: auto; }

/* --- Bloques de texto ---------------------------------------------------- */

.bloque { margin-block: clamp(3.5rem, 7vw, 5.5rem); }

/* Los titulos van en el rojo de la marca. Es el sistema de acento de la
   pagina: rojo = lo que Barkys pone, negro = lo que dice el estudio. Da
   5,26:1 sobre blanco, de sobra para AA incluso a este tamano. */
.bloque__titulo {
  margin: 0 0 var(--e3);
  font-family: var(--display); font-weight: 500;
  font-size: clamp(1.75rem, 1.2rem + 2vw, 2.75rem);
  line-height: 1.1; letter-spacing: -.025em;
  color: var(--rojo);
}

/* Cuando el titulo es lo unico que lleva la seccion, respira mas abajo y va
   centrado: sin texto al lado, un titulo suelto pegado a la izquierda deja un
   vacio raro a su derecha. */
.bloque__titulo--solo {
  margin-bottom: var(--e4);
  text-align: center;
}

/* El bloque de los pares centra titulo y linea, pero NO las piezas: esas
   siguen su propia rejilla. */
.bloque--centrado > .bloque__titulo,
.bloque--centrado > .bloque__texto {
  text-align: center;
  margin-inline: auto;
}
.bloque__texto {
  margin: 0;
  max-width: 62ch;
  color: var(--tinta-media);
}
.bloque__texto + .bloque__texto { margin-top: var(--e2); }

/* Dos columnas para el encargo. Es el unico texto largo de la pagina y en una
   sola columna a 1240 px quedaria una linea de 140 caracteres. */
.dos-columnas {
  display: grid; gap: var(--e3) var(--e5);
  grid-template-columns: 1fr;
}
@media (min-width: 900px) {
  .dos-columnas { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); align-items: start; }
}

.alcance { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--e2); }
.alcance li {
  padding-top: var(--e2);
  border-top: 1px solid var(--linea);
  color: var(--tinta-media);
}

/* --- Rejilla de galeria -------------------------------------------------
   Ni pies, ni nombres, ni fechas: solo la imagen y el zoom. Lo que hace una
   galeria es dejar mirar; cada rotulo que se agrega es una interrupcion. La
   descripcion sigue existiendo en el `alt` de cada imagen, o sea que un lector
   de pantalla la lee aunque no se vea. */

.galeria {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(10px, 1.4vw, 20px);
  margin: 0; padding: 0; list-style: none;
  /* `dense` es obligatorio con spans mezclados: sin el, la rejilla deja el
     hueco donde la pieza grande no cabia y se lee como celda vacia. */
  grid-auto-flow: dense;
}

/* Una de cada seis ocupa 2x2. No es decoracion: quince cuadrados iguales en
   fila se leen como hoja de contactos, y lo que se quiere es una galeria. La
   estructura sale de "Bento Box Grid"; su decoracion (radio 24 px, sombras,
   fondo gris) NO se toma, porque esta pagina va a radio 0 y sin sombras. */
@media (min-width: 900px) {
  .galeria:not(.galeria--vertical) > li:nth-child(6n + 1) {
    grid-column: span 2;
    grid-row: span 2;
  }
}

.galeria--vertical { grid-auto-flow: row; }

@media (max-width: 899px) {
  .galeria, .galeria--vertical { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* La pieza es un boton que envuelve la imagen. Sin JS sigue siendo un boton
   inerte y la imagen se ve igual: la galeria nunca depende del script para
   mostrar el trabajo. */
.pieza {
  position: relative;
  display: block; width: 100%; padding: 0;
  border: 0; background: var(--papel-alt);
  cursor: zoom-in;
  overflow: hidden;
}
.pieza img {
  width: 100%; height: auto;
  transition: transform .5s var(--salida), opacity .3s ease;
}
.pieza:hover img, .pieza:focus-visible img { transform: scale(1.06); }

/* --- Pares 1:1 y 9:16 ---------------------------------------------------
   El bloque que sostiene la pagina. Las dos columnas estan en proporcion
   1 : 0.5625, o sea la del 9:16 frente al cuadrado: asi las dos imagenes
   terminan exactamente a la misma altura y la comparacion es honesta. Si se
   dejaran a anchos iguales, la story se veria mas alta y pareceria otra cosa.
   En movil se apilan y la story se topa, porque a ancho completo mide casi
   dos pantallas ella sola. */

.pares { display: grid; gap: var(--e6); margin: 0; padding: 0; list-style: none; }
.par { margin: 0; }
.par__visor { display: grid; gap: clamp(10px, 1.4vw, 20px); align-items: end; }
@media (min-width: 700px) { .par__visor { grid-template-columns: 1fr .5625fr; } }
@media (max-width: 699px) { .par__lado--story { max-width: 58%; } }

.par__lado { min-width: 0; }

/* --- Reels --------------------------------------------------------------
   Sin autoplay y con preload="none". Seis videos con audio arrancando solos
   es hostil, y sin el preload se bajan 16 MB a quien solo venia a ver las
   piezas. */

.reels {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(var(--e2), 2vw, var(--e3));
  margin: 0; padding: 0; list-style: none;
}
@media (max-width: 899px) { .reels { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.reel { margin: 0; }
.reel video {
  width: 100%; aspect-ratio: 9 / 16; height: auto;
  background: #000;
}
.reel figcaption {
  margin-top: .6rem;
  font-family: var(--dato); font-size: .72rem; line-height: 1.45;
  color: var(--tinta-suave);
}

/* --- Nota de creditos ---------------------------------------------------- */

.creditos {
  max-width: 68ch;
  margin: 0;
  padding-left: var(--e3);
  border-left: 2px solid var(--rojo);
  font-size: .95rem;
  color: var(--tinta-media);
}
.creditos strong { font-weight: 500; color: var(--tinta); }

/* --- Cierre -------------------------------------------------------------- */

.cierre {
  margin-block: clamp(2.5rem, 5vw, 4rem) 0;
  padding-block: clamp(2.25rem, 4vw, 3.25rem) clamp(2.5rem, 5vw, 3.5rem);
  border-top: 1px solid var(--linea);
}
.cierre h2 {
  margin: 0 0 var(--e2);
  color: var(--rojo);
  max-width: none;
  font-family: var(--display); font-weight: 500;
  font-size: clamp(1.75rem, 1.2rem + 2vw, 2.75rem);
  line-height: 1.1; letter-spacing: -.025em;
}
.cierre p { margin: 0 0 var(--e3); max-width: 60ch; color: var(--tinta-media); }

/* OJO CON EL SELECTOR, que aqui hubo un fallo de verdad.

   Este boton salia con el texto con la TINTA DEL CIERRE, no blanco. La causa es
   de especificidad y no se ve leyendo esta regla sola, porque esta regla dice
   `color: #fff` y parece correcta:

     .caso-barkys a { color: inherit; }   ->  (0,1,1)  GANA
     .boton         { color: #fff; }       ->  (0,1,0)

   El boton es un <a>, asi que la regla generica de enlaces le ganaba y le metia
   `inherit`. Y no era solo feo: #131313 sobre #d0262b da 3.53:1, que NO pasa AA. En blanco da 5.26:1.

   Por eso el selector lleva la clase del caso delante. No se arregla con
   `!important`: lo que hay que hacer es empatarle la especificidad al selector
   que estaba ganando.

   Encontrado en ago 2026 al construir la pagina de Coltanques, que tenia el
   mismo fallo. Lo que hay que comprobar en cada pagina nueva no es la regla,
   es el valor calculado:

     getComputedStyle(document.querySelector('.boton')).color
*/
.caso-barkys .boton {
  display: inline-block;
  padding: .95rem 2rem;
  background: var(--rojo); color: #fff;
  font-family: var(--texto); font-weight: 500; font-size: 1rem;
  text-decoration: none;
  transition: background .2s var(--salida), transform .2s var(--salida);
}
.caso-barkys .boton:hover { background: #b01e23; }
.caso-barkys .boton:active { transform: translateY(1px); }

.pie {
  padding: clamp(2.5rem, 5vw, 3.5rem) var(--margen) clamp(2rem, 4vw, 3rem);
  /* Mismo papel que el resto de la pagina. El original de Circulo Cultural lo
     pone gris para separarlo del cuerpo; aqui la separacion ya la hace el
     filete de la seccion de cierre, y una franja gris al final rompia el
     blanco continuo que sostiene toda la galeria. */
  background: var(--papel);
  text-align: center;
}
.pie > .contenedor { padding-inline: 0; }

/* Filete con la marca partiendo la linea. */
.pie__filete {
  display: flex;
  align-items: center;
  gap: var(--e3);
  margin-bottom: var(--e4);
}
.pie__filete::before,
.pie__filete::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--linea);
}
.pie__filete img { height: 26px; width: auto; }

/* Menu del pie: enlaces separados por un filete vertical. */
.pie__menu {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--e2) 0;
  margin-bottom: var(--e4);
}
.pie__menu a {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 44px;              /* objetivo tactil */
  padding: 0 clamp(9px, 1.4vw, 17px);
  font-size: .87rem;
  color: var(--tinta-suave);
  text-decoration: none;
  transition: color .2s;
}
.pie__menu a + a::before {
  content: "";
  position: absolute;
  left: 0; top: 50%;
  width: 1px; height: 11px;
  margin-top: -5px;
  background: var(--linea);
}
.pie__menu a:hover { color: var(--rojo); }

/* En movil el menu cae en dos filas, y el filete de `a + a` deja una rayita
   suelta al empezar la segunda: el selector no sabe donde envuelve el flex.
   Abajo de 700 px se quitan los filetes y separa el espacio. */
@media (max-width: 699px) {
  .pie__menu { gap: 0 var(--e1); }
  .pie__menu a::before { display: none; }
}

.pie__legal { margin: 0; font-size: .8rem; color: var(--tinta-suave); }
.pie__nota { margin: 6px 0 0; font-size: .78rem; color: var(--tinta-suave); opacity: .85; }

/* --- Visor (lightbox) ---------------------------------------------------
   <dialog> nativo: trae el foco atrapado, el Esc y el fondo inerte sin una
   linea de JS. Lo unico que agrega el script es la navegacion con flechas.
   El fondo va oscuro aunque la pagina sea blanca: es la unica manera de que
   una pieza con fondo blanco se lea como pieza y no como parte de la pagina. */

.visor {
  width: 100vw; max-width: 100vw;
  height: 100dvh; max-height: 100dvh;
  padding: 0; border: 0;
  background: transparent;
  overflow: hidden;
}
.visor::backdrop { background: rgb(17 17 17 / .95); }
/* `minmax(0, 1fr)` y no `1fr`: son cosas distintas. `1fr` equivale a
   `minmax(auto, 1fr)`, y ese minimo `auto` es el min-content de lo que hay
   dentro — o sea el alto INTRINSECO de la imagen. Con una pieza vertical la
   fila crecia hasta el tamano real del archivo, la imagen se salia por abajo
   del dialogo y tapaba la barra de navegacion. Medido en Eterna: en un visor
   de 257px de alto, una pieza de 600x1600 se pintaba a 981px.
   El `0` de minimo deja que la fila se encoja y la imagen se ajuste. */
.visor[open] { display: grid; grid-template-rows: minmax(0, 1fr) auto; }

/* Flex y no grid: con `place-items: center` la imagen quedaba de item de
   rejilla y su `max-height: 100%` se resolvia contra una altura que la propia
   imagen estaba estirando. En flex el marco manda y la imagen se ajusta.
   `overflow: hidden` es el cinturon de seguridad por si algo se escapa. */
.visor__marco {
  display: flex; align-items: center; justify-content: center;
  min-height: 0; min-width: 0;
  overflow: hidden;
  padding: clamp(var(--e3), 5vw, var(--e5));
}
.visor__marco img {
  max-width: 100%; max-height: 100%;
  width: auto; height: auto;
  object-fit: contain;
  background: #fff;
}
.visor__barra {
  display: flex; align-items: center; gap: var(--e3);
  padding: var(--e2) clamp(var(--e2), 4vw, var(--e4)) var(--e4);
  color: #f2f2f2;
}
.visor__cuenta {
  flex: 1;
  font-family: var(--dato); font-size: .78rem;
  color: #9a9a9a; white-space: nowrap;
}
.visor__nav { display: flex; gap: .5rem; }

.visor button {
  display: grid; place-items: center;
  width: 2.6rem; height: 2.6rem;
  color: #fff; background: rgb(255 255 255 / .1);
  border: 0; cursor: pointer;
  font-size: 1.1rem; line-height: 1;
  transition: background .2s var(--salida);
}
.visor button:hover:not(:disabled) { background: rgb(255 255 255 / .24); }
.visor button:disabled { opacity: .3; cursor: default; }
.visor__cerrar {
  position: absolute; top: var(--e2); right: clamp(var(--e2), 4vw, var(--e4));
}

/* ==========================================================================
   MOVIMIENTO
   --------------------------------------------------------------------------
   Hay tres capas y cada una responde a una pregunta distinta. Ninguna esta
   por verse bonita: si no se puede decir en una frase que comunica, sobra.

     1. Entrada al hacer scroll     ¿esto es nuevo? ¿de donde venia?
     2. Profundidad en la galeria   las piezas llegan desde atras y se posan
     3. Secuencia de apertura       jerarquia: marca, cifra, contexto

   El motor preferido es `animation-timeline: view()`, o sea animacion ligada
   al scroll HECHA POR EL NAVEGADOR. No hay un solo listener de scroll ni un
   requestAnimationFrame: el compositor la corre fuera del hilo principal y no
   se cae aunque la pagina tenga 33 imagenes. Donde no exista, el observador de
   `barkys.js` hace la version simple y nadie se entera.
   ========================================================================== */

/* --- Capa 1: entrada, version de respaldo -------------------------------
   Se oculta SOLO si el JS ya corrio (clase .js en el <html>): sin script no se
   esconde nada, porque una animacion no puede ser el motivo por el que alguien
   vea una pagina en blanco. */

.js [data-entra] {
  opacity: 0;
  transform: translateY(20px) scale(.985);
}
.js [data-entra].visible {
  opacity: 1;
  transform: none;
  transition:
    opacity .75s var(--salida) var(--retraso, 0ms),
    transform .75s var(--salida) var(--retraso, 0ms);
}

/* --- Capa 2: profundidad ligada al scroll -------------------------------
   Lo que se toma de la referencia de galeria 3D. Las piezas no aparecen: se
   acercan. Entran inclinadas y desde el fondo, y terminan de posarse cuando
   estan bien dentro de la pantalla, asi que el efecto se siente al scrollear
   y no como un parpadeo al cruzar un umbral.

   Se queda corto a proposito. La referencia gira las imagenes durante todo el
   recorrido; aca la pieza se endereza y para. Con 33 imagenes muy saturadas,
   mantenerlas girando convierte la galeria en un carrusel y deja de poderse
   mirar el trabajo, que es para lo que existe la pagina. */

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    .galeria, .reels, .pares { perspective: 1500px; }
    .galeria > li, .reels > li, .pares > .par { transform-style: preserve-3d; }

    /* La animacion manda sobre el estado de la capa 1: una animacion en curso
       gana sobre el valor declarado y sobre la transicion.
       Solo las IMAGENES llegan con profundidad. El texto sube y ya: una linea
       de texto girando en perspectiva se lee peor y no comunica nada. */
    .js:not(.sin-timeline) .galeria > li,
    .js:not(.sin-timeline) .reels > li,
    .js:not(.sin-timeline) .par {
      opacity: 1;
      transform: none;
      animation: llega linear both;
      animation-timeline: view();
      animation-range: entry 4% cover 34%;
    }

    .js:not(.sin-timeline) .bloque__titulo[data-entra],
    .js:not(.sin-timeline) .bloque__texto[data-entra] {
      opacity: 1;
      transform: none;
      animation: asoma linear both;
      animation-timeline: view();
      animation-range: entry 8% cover 26%;
    }

    /* Las dos mitades del par llegan desde profundidades distintas y se posan
       en el mismo plano. Es literal: son dos versiones de la misma pieza. */
    .js:not(.sin-timeline) .par__lado--story { animation: llega-story linear both;
      animation-timeline: view(); animation-range: entry 4% cover 40%; }

    /* Las laminas hacen zoom de salida dentro de su marco durante todo el
       recorrido. Da profundidad sin mover nada de sitio, que es lo unico que se
       puede permitir un elemento que ocupa el ancho completo. La figura solo
       aparece: dos movimientos encima de la misma imagen se pelean. */
    .js:not(.sin-timeline) .lamina { opacity: 1; transform: none;
      animation: asoma linear both;
      animation-timeline: view(); animation-range: entry 4% cover 22%; }

    .lamina { overflow: hidden; }
    .js:not(.sin-timeline) .lamina img {
      animation: acerca linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
      will-change: transform;
    }
  }
}

@keyframes llega {
  from { opacity: 0; transform: translate3d(0, 44px, -150px) rotateX(11deg); }
  to   { opacity: 1; transform: none; }
}
@keyframes llega-story {
  from { opacity: 0; transform: translate3d(0, 44px, -260px) rotateX(11deg); }
  to   { opacity: 1; transform: none; }
}
@keyframes asoma {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: none; }
}
@keyframes acerca {
  from { transform: scale(1.07); }
  to   { transform: scale(1); }
}

/* --- Capa 3: secuencia de apertura --------------------------------------
   Al cargar, y en este orden: la marca, la lamina, el titulo, la bajada y la
   ficha. Es la jerarquia de quien mira: de quien es la pagina, que trabajo es,
   como se llama el cliente, y los datos.

   La lamina se DESCUBRE de arriba hacia abajo, como una persiana, y se asienta
   desde un punto de escala. Se anima `clip-path` y `transform`, nunca `height`:
   animar la altura obligaria a recalcular la maqueta en cada fotograma y
   empujaria la pagina entera hacia abajo mientras carga. */

/* Las tiras del fondo del hero. Cada una recorre la mitad de su propia altura
   y vuelve a empezar; como el contenido esta duplicado, el salto es invisible.
   Velocidades distintas por tira: es lo que vende la profundidad. Las pares van
   al reves para que el conjunto no parezca una sola cortina bajando.

   Se anima `transform`, nunca `top`: solo asi el trabajo se queda en el
   compositor y no obliga a recalcular la maqueta en cada fotograma. */
.js .tira {
  animation: desfilar var(--vel, 70s) linear infinite;
}
.js .tira:nth-child(even) { animation-direction: reverse; }
.js .tira:nth-child(1) { --vel: 68s; }
.js .tira:nth-child(2) { --vel: 84s; }
.js .tira:nth-child(3) { --vel: 74s; }
.js .tira:nth-child(4) { --vel: 92s; }

@keyframes desfilar {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(0, -50%, 0); }
}

/* El texto del hero entra escalonado al cargar. */
.js .portada__rotulo { animation: sube .8s var(--salida) both; animation-delay: .1s; }
.js .portada__titulo { animation: sube .9s var(--salida) both; animation-delay: .22s; }
.js .portada__bajada { animation: sube .9s var(--salida) both; animation-delay: .38s; }
.js .marca { animation: sube .7s var(--salida) both; animation-delay: .05s; }

@keyframes sube {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* --- El interruptor -----------------------------------------------------
   Una sola regla apaga las tres capas. Va al final para que gane siempre. */

@media (prefers-reduced-motion: reduce) {
  .js [data-entra] { opacity: 1; transform: none; transition: none; }
  .js .tira { animation: none; }
  .js .marca, .js .portada__rotulo, .js .portada__titulo,
  .js .portada__bajada,
  .js .galeria > li, .js .reels > li, .js .par,
  .js .par__lado--story, .js .lamina, .js .lamina img {
    animation: none;
    opacity: 1;
    transform: none;
    clip-path: none;
  }
  .pieza img, .boton { transition: none; }
  .pieza:hover img, .pieza:focus-visible img { transform: none; }
}

/* --- Impresion ----------------------------------------------------------
   Un caso de portafolio se imprime a PDF mas seguido de lo que parece. */
@media print {
  .visor, .cierre .boton { display: none; }
  .js [data-entra] { opacity: 1; transform: none; }
  .galeria { grid-template-columns: repeat(3, 1fr); }
}
