/* ==========================================================================
   bonfibra.css — pagina de caso, en clave de galeria
   --------------------------------------------------------------------------
   Misma arquitectura que `barkys.css`: hoja unica, sin dependencias, con TODO
   colgado de una clase para que sirva suelta y dentro del sitio. Lo que cambia
   es la marca que se presenta, no el sistema.

   TRES DECISIONES QUE EXPLICAN TODO LO DEMAS

   1. Un solo tema, blanco.  Las piezas de Bonfibra estan compuestas sobre
      blanco y sobre campos de verde muy claro. Sobre fondo oscuro pierden 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 verde de marca es el unico
      acento y tiene un solo trabajo: los titulos de seccion y el boton.
      Verde = lo que pone Bonfibra. 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 35 JPG originales, no elegida de un catalogo:
     #6CC000  verde vivo de las ondas    #16561D  verde institucional de fondo
   El verde vivo da 2,29:1 sobre blanco y NO se usa en interfaz en ningun sitio:
   con texto encima es ilegible en cualquier direccion. El token de acento es
   #3E7A00, el mismo verde bajado hasta 5,26:1, que es exactamente el mismo
   contraste con el que trabaja el rojo de Barkys.

   TIPOGRAFIAS — son de la marca presentada, no de Ballestastudio. Lo unico
   propio es el logo:
     Montserrat 600/700   la que usan los titulares de las piezas: geometrica,
                          ancha, de terminales PLANAS, con la A de vertice
                          plano y las O casi circulares. Se saco mirando las
                          letras ampliadas de "LAVADO DE MANOS", "DONACION" y
                          "LOS RINONES", no del logotipo
     Source Sans 3 400    humanista y neutra. Contrasta con la geometria del
                          titular en vez de duplicarla, y es la que la base de
                          `ui-ux-pro-max` marca para salud y accesibilidad,
                          que es el registro real de esta cuenta
     IBM Plex Mono        "1 / 4" es especificacion, no titulo. La mono lo hace
                          leer como ficha tecnica. Es la misma que usan los
                          demas casos: el unico rasgo tipografico que el
                          estudio conserva de pagina a pagina

   > OJO: la primera version de esta hoja usaba Nunito, de terminales
   > REDONDEADAS, deducida del logotipo. Estaba mal: el logotipo de Bonfibra es
   > un lockup con script y no dice nada de la tipografia del sistema. Las
   > piezas mandan, y las piezas son geometricas de terminal plana. Corregido
   > en ago 2026.
   ========================================================================== */

/* TODO cuelga de `.caso-bonfibra`, 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-bonfibra">. */
.caso-bonfibra {
  color-scheme: light;

  --tinta:        #131313;   /* 18,58:1 sobre blanco */
  --tinta-media:  #5c5c5c;   /* 6,69:1 sobre blanco */
  --tinta-suave:  #767676;   /* 4,54:1 sobre blanco: el minimo para texto */
  --linea:        #e8e8e8;
  --papel:        #ffffff;
  --papel-alt:    #fafafa;
  --verde:        #3e7a00;   /* 5,26:1 sobre blanco. El unico acento */
  --verde-oscuro: #326200;   /* 7,28:1. Solo el hover del boton */
  --verde-hondo:  #16561d;   /* 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: "Montserrat", ui-sans-serif, system-ui, sans-serif;
  --texto:   "Source Sans 3", "Source Sans Pro", 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-bonfibra, .caso-bonfibra *, .caso-bonfibra *::before, .caso-bonfibra *::after {
  box-sizing: border-box;
}

.caso-bonfibra {
  background: var(--papel);
  color: var(--tinta);
  font-family: var(--texto);
  /* 400 y no 300 como en Barkys: Outfit aguanta el 300, Source Sans 3 es
     humanista y de menos contraste, y a 300 el gris del cuerpo se lava. */
  font-weight: 400;
  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-bonfibra) { margin: 0; background: var(--papel); }

.caso-bonfibra img { display: block; max-width: 100%; }

.caso-bonfibra a { color: inherit; }

.caso-bonfibra ::selection { background: var(--verde); color: #fff; }

.caso-bonfibra :focus-visible { outline: 2px solid var(--verde); 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 -----------------------------------------------------------
   El FONDO son las piezas reales desplazandose en tiras a distintas
   velocidades, y encima va una frase corta que invita a bajar. El fondo es el
   trabajo, que es lo que se vino a ver, y no una animacion abstracta pegada
   encima.

   La lamina 01 de la presentacion NO se usa aqui, por la misma razon que en
   Barkys: mide 1920 px de ancho y el hero ocupa el ancho de la ventana, asi
   que en cualquier monitor grande se estira y se ve blanda. Sigue existiendo,
   pero como og:image, que es donde ese tamano alcanza de sobra.

   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(--verde-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 18 imagenes de valores muy distintos por igual.

   CONTRASTE GARANTIZADO POR CONSTRUCCION. A 0,88 sobre el peor caso posible
   —un pixel blanco de una pieza— el resultado es rgb(50 106 56), que con texto
   blanco encima da 6,45:1. Cualquier pixel mas oscuro da mas. No depende de
   que imagen toque en cada momento del bucle.

   Se queda en 0,88 y no en 0,90 a proposito: las piezas de Bonfibra ya son
   verdes, y un velo verde mas cerrado las borra del todo. */
.portada__velo {
  position: absolute; inset: 0;
  z-index: -1;
  background:
    linear-gradient(to top, rgb(8 40 12 / .55), transparent 62%),
    rgb(22 86 29 / .88);
}

.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: 700;
  font-size: clamp(2.1rem, 5.2vw, 3.9rem);
  line-height: 1.06; letter-spacing: -.03em;
  color: #fff;
  /* `balance` reparte el titular en lineas parejas. Se prefiere a un <br>
     fijo, que corta bien en un idioma y mal en el otro y se rompe en cuanto
     cambia el ancho. */
  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);
  text-wrap: balance;
}

/* --- La marca -----------------------------------------------------------
   El logo y nada mas: sin barra, sin fondo, sin linea y sin quedarse pegado al
   hacer scroll. Va montado sobre el hero, alineado con el margen del
   contenedor. Mismo tratamiento que en Exopartes y en Barkys.

   Usa el lockup INVERTIDO a una tinta. El logo normal es negro con "STUDIO" en
   turquesa, y sobre el verde institucional ese turquesa se pierde. Un logo a
   una tinta para fondos de color es un recurso normal de manual de marca. */

.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. Un `width: 100vw` aqui solo serviria para sumar los
   pixeles de la barra de scroll y provocar desborde horizontal. */

.lamina {
  margin-block: clamp(2.75rem, 5.5vw, 4.25rem);
  /* 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 ---------------------------------------------------- */

/* 4,25rem y no 5,5rem: medido en Chrome, el ritmo anterior dejaba 83 px
   parejos entre TODAS las secciones (la maqueta nunca estuvo desigual, lo que
   se veia desigual era la animacion de entrada a medio camino). 83 px en una
   pagina que es casi toda imagenes hacia que cada seccion pareciera flotar
   suelta. A 68 px las secciones siguen separadas y la galeria se lee seguida. */
.bloque { margin-block: clamp(2.75rem, 5.5vw, 4.25rem); }

/* Los titulos van en el verde de la marca. Es el sistema de acento de la
   pagina: verde = lo que Bonfibra 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: 600;
  font-size: clamp(1.75rem, 1.2rem + 2vw, 2.75rem);
  line-height: 1.1; letter-spacing: -.025em;
  color: var(--verde);
}

/* 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(--e3);
  text-align: center;
}

/* Los bloques del carrusel y de los pares centran 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: dieciocho 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;
  }
}

/* Las stories van en UNA sola fila y con piezas que se distingan entre si, no
   en la rejilla de cuatro del feed. La razon es de contenido: el archivo tiene
   9 verticales y solo 6 distintas (cuatro son variaciones del carrusel del
   yoga); cuatro de esas seis se van a los pares y aqui quedan dos. Rellenar
   celdas obligaria a repetir la misma story.

   Por eso la fila NO usa fracciones: usa columnas de ancho fijo centradas. Asi
   la seccion se ve deliberada con dos piezas o con cinco, y ninguna se estira
   a media pantalla solo porque sobre sitio. 290 px es el ancho al que una
   story de 9:16 sigue leyendose y queda cerca del de la story de los pares. */
.galeria--vertical {
  grid-auto-flow: row;
  grid-template-columns: repeat(auto-fit, minmax(0, 290px));
  justify-content: center;
}

/* En movil las dos rejillas van a dos columnas, la del feed y la de stories.
   Las stories se nombran aparte a proposito y no por herencia de la cascada:
   a 375 px cada una queda en 163 px, el mismo ancho que una pieza del feed, y
   la seccion cabe entera en media pantalla. La alternativa era conservar los
   290 px fijos, que en un telefono obliga a apilarlas y estira una seccion de
   dos piezas a dos pantallas de scroll. */
@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); }

/* --- El carrusel --------------------------------------------------------
   Cuatro piezas en UNA fila, siempre, y con numero encima. Es la unica parte
   de la pagina donde el orden es informacion: si se mezclan en la galeria del
   feed y una de ellas cae en la celda 2x2, la secuencia se pierde y se leen
   como cuatro piezas sueltas.

   El numero es la unica etiqueta que sobrevive en toda la pagina, y esta
   justificada: sin el, "se leen en orden" es una afirmacion que el visitante
   no puede comprobar. Va en la mono, como los demas datos.

   En movil pasa a dos columnas y no a scroll horizontal: un carrusel dentro de
   un carrusel obliga a arrastrar para ver algo que cabe. */

.carrusel {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(10px, 1.4vw, 20px);
  margin: 0; padding: 0; list-style: none;
  counter-reset: paso;
}
@media (max-width: 699px) { .carrusel { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.carrusel > li { counter-increment: paso; margin: 0; }
.carrusel > li::before {
  content: counter(paso) " / 4";
  display: block;
  margin-bottom: .55rem;
  font-family: var(--dato); font-size: .72rem; letter-spacing: .1em;
  color: var(--tinta-suave);
}

/* --- 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. */

/* Cuatro pares en 2x2. Antes iban tres apilados a lo largo y con `--e6` (6rem)
   de separacion: la seccion se hacia larguisima y cada par quedaba solo en
   pantalla, sin nada con que compararse, que es justo lo contrario de lo que
   este bloque existe para hacer. En dos filas de dos se ven dos casos a la vez
   y se lee como un sistema, no como tres ejemplos sueltos.

   Al caber dos por fila, la separacion baja de `--e6` a `--e4`: con la mitad de
   ancho, 6rem de aire vertical dejaban un hueco mas alto que las propias
   piezas. */
.pares {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--e5);
  margin: 0; padding: 0; list-style: none;
}
@media (min-width: 900px) {
  .pares {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--e4) var(--e5);
  }
}
.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; }

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

.creditos {
  max-width: 68ch;
  margin: 0;
  padding-left: var(--e3);
  border-left: 2px solid var(--verde);
  font-size: .95rem;
  color: var(--tinta-media);
}
.creditos strong { font-weight: 600; 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(--verde);
  max-width: none;
  font-family: var(--display); font-weight: 600;
  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-bonfibra 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 #3e7a00 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-bonfibra .boton {
  display: inline-block;
  padding: .95rem 2rem;
  background: var(--verde); color: #fff;
  font-family: var(--texto); font-weight: 600; font-size: 1rem;
  text-decoration: none;
  transition: background .2s var(--salida), transform .2s var(--salida);
}
.caso-bonfibra .boton:hover { background: var(--verde-oscuro); }
.caso-bonfibra .boton:active { transform: translateY(1px); }

/* --- El pie -------------------------------------------------------------
   El mismo patron de Editorial Circulo Cultural y de Barkys, que es el pie de
   las paginas de caso y de las landings: filete con la marca partiendo la
   linea, menu del sitio separado por filetes verticales, linea legal y nota de
   que trabajo fue y de que ano.

   Viaja DENTRO del fragmento, no en `shared-components`: al integrar, esta
   pagina conserva el suyo. */

.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(--verde); }

/* 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, titular, 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 31 imagenes. Donde no exista, el observador de
   `bonfibra.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 -------------------------------
   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 de galeria 3D gira las imagenes
   durante todo el recorrido; aqui la pieza se endereza y para. Con 31 imagenes
   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, .carrusel, .pares { perspective: 1500px; }
    .galeria > li, .carrusel > 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) .carrusel > li,
    .js:not(.sin-timeline) .par {
      opacity: 1;
      transform: none;
      animation: llega linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 24%;
    }

    .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 0% cover 28%;
    }

    /* 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%;
    }

    .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 --------------------------------------
   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: la marca, el rotulo, el
   titular y la bajada. Es la jerarquia de quien mira: de quien es la pagina,
   que trabajo es y de quien es el cliente. */
.js .marca           { animation: sube .7s var(--salida) both; animation-delay: .05s; }
.js .portada__rotulo { animation: sube .8s var(--salida) both; animation-delay: .10s; }
.js .portada__titulo { animation: sube .9s var(--salida) both; animation-delay: .22s; }
.js .portada__bajada { animation: sube .9s var(--salida) both; animation-delay: .38s; }

@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 .carrusel > 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); }
}
