/* ==========================================================================
   famoc.css — pagina de caso, en clave de galeria
   --------------------------------------------------------------------------
   Misma arquitectura que `barkys.css`, `bonfibra.css` y `coltanques.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.  Casi todas las piezas de Famoc Depanel estan
      compuestas sobre blanco o sobre fotografia de espacio, y cierran con el
      logotipo azul al pie. Sobre fondo oscuro ese remate deja de leerse. Y el
      caso se presenta como galeria, que 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 azul de marca es el unico
      acento y tiene un solo trabajo: los titulos de seccion y el boton.
      Azul = lo que pone Famoc Depanel. Negro = lo que dice el estudio.

      OJO EN ESTE CASO. La cuenta cambio de sistema grafico a mitad de camino:
      2021 es multicolor (verde, vinotinto, naranja) y el segundo semestre de
      2022 se asienta en el azul marino con marco de esquinas. La tentacion era
      darle a cada seccion el color de su epoca. No se hizo, por lo mismo de
      siempre: esos colores viven dentro de las imagenes, que es donde el
      cliente los puso.

   3. Radio 0 en todo, sin excepcion.  Incluido el boton.

   PALETA — muestreada de los 453 JPG originales, no elegida de un catalogo:
     #007BA5  el azul de servicio tal como sale en las piezas. Da 4,80:1 sobre
              blanco, que ya pasa AA por poco
     #243060  el azul marino del sistema de 2022. Da 12,60:1 sobre blanco, o
              sea que como acento se confundiria con la tinta. NO es el acento:
              es el fondo del hero, que es el trabajo que sabe hacer un color
              tan oscuro
     --azul   #007597, el mismo azul de servicio bajado hasta 5,26:1. Es
              exactamente el contraste con el que trabajan Barkys, Bonfibra y
              Coltanques

   TIPOGRAFIAS — son de la marca presentada, no de Ballestastudio. Lo unico
   propio es el logo. Se sacaron AMPLIANDO LAS LETRAS DE LOS TITULARES, no del
   logotipo, que es una humanista bold y no dice nada del sistema:
     Poppins 600/700      geometrica de a de un solo piso y O casi circular,
                          que es lo que se ve en "CREAMOS ESPACIOS", "ESPACIOS
                          FUNCIONALES" y "5 CLAVES PARA UNA OFICINA MODERNA"
     Source Sans 3 400/600  humanista y neutra. Contrasta con la geometria del
                          titular en vez de duplicarla
     IBM Plex Mono        los datos son ficha tecnica, no titulo. Es la misma
                          que usan los demas casos: el unico rasgo tipografico
                          que el estudio conserva de pagina a pagina
   ========================================================================== */

/* TODO cuelga de `.caso-famoc`, 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-famoc">. */
.caso-famoc {
  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;
  --azul:         #007597;   /* 5,26:1 sobre blanco. El unico acento */
  --azul-oscuro:  #005A75;   /* 7,52:1. Solo el hover del boton */
  --hero:         #14182c;   /* fondo del hero, bajo las tiras */
  --hero-brillo:  #243060;   /* el marino que sube desde el pie del hero */

  /* 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: "Poppins", ui-sans-serif, system-ui, sans-serif;
  --texto:   "Source Sans 3", 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-famoc, .caso-famoc *, .caso-famoc *::before,
.caso-famoc *::after {
  box-sizing: border-box;
}

.caso-famoc {
  background: var(--papel);
  color: var(--tinta);
  font-family: var(--texto);
  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-famoc) { margin: 0; background: var(--papel); }

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

.caso-famoc a { color: inherit; }

.caso-famoc ::selection { background: var(--azul); color: #fff; }

.caso-famoc :focus-visible { outline: 2px solid var(--azul); 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.

   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(--hero);
  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 veinticuatro 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(48 52 69), que con texto
   blanco encima da 12,3:1. Cualquier pixel mas oscuro da mas. No depende de
   que imagen toque en cada momento del bucle.

   Y el peor caso aqui es el caso normal: mas de la mitad de las piezas de
   Famoc son blancas. El velo tiene que estar calculado sobre blanco puro o el
   titular se pierde apenas gira el bucle.

   El marino NO va en el velo plano sino en el degradado que sube desde el pie:
   un velo marino cerrado sobre las piezas del sistema de 2022, que ya son
   marinas, las borra del todo y el hero deja de ensenar el trabajo. */
.portada__velo {
  position: absolute; inset: 0;
  z-index: -1;
  background:
    linear-gradient(to top, rgb(36 48 96 / .60), transparent 64%),
    rgb(20 24 44 / .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: 44ch;
  /* 800 y no 900. Poppins TIENE 900, pero a este cuerpo la diferencia entre
     800 y 900 es de un pelo y cada peso extra es una peticion mas de fuente.
     Ojo: si algun dia alguien vuelve a poner 900, hay que pedirlo tambien en
     la URL de Google Fonts o el navegador lo SINTETIZA engordando el 700, y
     eso si se ve. */
  font-family: var(--display); font-weight: 800;
  font-size: clamp(2.1rem, 4.6vw, 3.3rem);
  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__titulo > span { display: inline; white-space: nowrap; }
.portada__titulo > span[lang="en"] { display: none; }
.palabra-clave {
  color: #8ed7e6;
  text-decoration: underline;
  text-decoration-thickness: .08em;
  text-underline-offset: .12em;
}
.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 Barkys y Bonfibra.

   Usa el lockup INVERTIDO a una tinta, porque sobre el hero oscuro el logo
   normal (negro con "STUDIO" en turquesa) se pierde. */

.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; }


/* --- Tira a sangre ------------------------------------------------------
   Ancho completo de la VENTANA, no del contenedor.

   ESTE PROYECTO NO TIENE LAMINAS DE PRESENTACION, pero tiene algo mejor: los
   cuatro mosaicos `Feed.jpg` que se le entregaban al cliente para aprobar la
   parrilla del mes. `build_assets.py` recorta UNA FILA de ese mosaico (ver
   `recortar_fila`) y la deja a sangre. No es una tira compuesta a posteriori:
   es la parrilla como se aprobo, con su propio orden y su propia calle.

   Cumple la condicion del 7.1 de `00_LEEME_Portafolio_MKT.md` sin discusion,
   porque lo que se ve son NUEVE PIEZAS DISENADAS y no fotos de la operacion.

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

.tira-sangre {
  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 tira se
     queda 80 px angosta y deja de ir a sangre. */
  margin-inline: 0;
  overflow: hidden;
}
.tira-sangre img { width: 100%; height: auto; }

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

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

/* Los titulos van en el azul de la marca. Es el sistema de acento de la
   pagina: azul = lo que Famoc Depanel pone, negro = lo que dice el estudio. Da
   5,26:1 sobre blanco, de sobra para AA incluso a este tamano.

   EN CAJA BAJA, al reves que Coltanques y como Barkys y Bonfibra. Coltanques
   rotula en mayuscula porque su registro es normativo, de senalizacion. El de
   Famoc no: su sistema de 2022 titula en caja mixta, con la geometrica ancha y
   mucho aire. Una version en versales aqui contradice lo que hay debajo.

   El `letter-spacing` vuelve a ser NEGATIVO, que es lo que pide la caja baja:
   cierra el aire que dejan las minusculas con ascendentes y descendentes. */
.bloque__titulo {
  margin: 0 0 var(--e3);
  display: flex;
  align-items: center;
  gap: .85rem;
  font-family: var(--display); font-weight: 700;
  font-size: clamp(1.7rem, 1.15rem + 2vw, 2.75rem);
  line-height: 1.12;
  letter-spacing: -.02em;
  text-wrap: balance;
  color: var(--azul);
  text-transform: uppercase;
}
.bloque__titulo::after {
  content: "";
  flex: 0 0 2.6rem;
  height: .35rem;
  border-top: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  opacity: .55;
}
.bloque--centrado > .bloque__titulo::before,
.bloque__titulo--solo::before {
  content: "";
  flex: 0 0 2.6rem;
  height: .35rem;
  border-top: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  opacity: .55;
}
.bloque--centrado > .bloque__titulo,
.bloque__titulo--solo { justify-content: center; }

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

/* Los bloques con una linea de apoyo 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;
}
/* `balance` reparte la linea de apoyo en renglones parejos. Sin el, la linea
   de la campana de seguridad rompia dejando "dice dos." solo en el segundo
   renglon: dos palabras sueltas debajo de una linea llena se leen como un
   error de maqueta. Es la misma regla que ya usaba el titular del hero, y aqui
   hacia mas falta todavia, porque estas lineas van centradas y un huerfano
   centrado se nota el doble. */
.bloque__texto {
  margin: 0;
  max-width: 62ch;
  color: var(--tinta-media);
  text-wrap: balance;
}
.bloque__texto + .bloque__texto { margin-top: var(--e2); }
.bloque--centrado > .bloque__texto { margin-bottom: var(--e4); }
.bloque--centrado > .bloque__texto,
.portada__bajada {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  /* TRES, no dos. Corregido el 21 ago 2026. Con dos, «El sistema» y «Ventanas
     de San Joaquin» salian cortadas a 1440 px: las dos miden tres lineas. El
     recorte esta aqui para que una linea de seccion no deje un huerfano
     centrado, no para esconder la mitad de la frase. */
  -webkit-line-clamp: 3;
  overflow: hidden;
}

/* Y EL RECORTE ES UN PROBLEMA DE ANCHO, asi que se afloja cuando el ancho
   baja. A 1240 px la columna mide 530 px; a 375 px la MISMA frase mide de
   cuatro a cinco lineas, y ahi el clamp deja de evitar un huerfano y empieza a
   esconder media frase. A 375 px estaban cortadas SEIS de las siete. */
@media (max-width: 899px) {
  .bloque--centrado > .bloque__texto,
  .portada__bajada { -webkit-line-clamp: 5; }
}

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

.bloque--encargo { position: relative; isolation: isolate; overflow: hidden; }
.bloque--encargo::before,
.bloque--encargo::after {
  position: absolute;
  z-index: -1;
  color: var(--azul);
  opacity: .08;
  font-family: var(--display);
  font-size: clamp(5rem, 12vw, 10rem);
  line-height: 1;
  pointer-events: none;
}
.bloque--encargo::before { content: "✦"; right: 4%; top: 2%; transform: rotate(12deg); }
.bloque--encargo::after { content: "＋"; left: 2%; bottom: -8%; transform: rotate(-16deg); }

/* --- 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: veinte 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--serie) > li:nth-child(6n + 1) {
    grid-column: span 2;
    grid-row: span 2;
  }
  /* La última pieza cierra el feed: debe completar la fila, no convertirse
     en otro bloque 2x2 y dejar el final visualmente desbalanceado. */
  .galeria:not(.galeria--serie) > li:last-child {
    grid-column: span 1;
    grid-row: span 1;
  }
}

/* La campana de seguridad usa la misma rejilla SIN la celda doble. En una
   serie numerada, sacar una pieza al doble de tamano dice que esa importa mas
   que las otras, y no es cierto: las ocho pesan lo mismo y por eso se
   publicaron juntas. */
.galeria--serie { grid-auto-flow: row; }

/* --- Aplicaciones: el sistema de 2022 -----------------------------------
   Tres columnas y celda cuadrada. Las seis piezas del sistema son 1:1, asi
   que ninguna pierde un pixel; la regla de `contain` se queda igual para el
   dia en que entre una que no lo sea. */

.aplicaciones {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(12px, 1.8vw, 24px);
  margin: 0; padding: 0; list-style: none;
}

/* TODAS LAS CELDAS, EL MISMO ALTO.

   Cuadrado y `contain`, no `cover`. `cover` igualaria el alto recortando, y
   una pieza recortada deja de ser la pieza que se publico. Con `contain` entra
   entera y lo que sobra es papel, que es exactamente lo que hay detras. */
.aplicaciones > li { aspect-ratio: 1; }
/* La variante de los mosaicos de parrilla: DOS columnas y no tres. Son nueve
   piezas dentro de cada imagen; a un tercio del contenedor cada pieza del
   mosaico se queda en 120 px y deja de leerse que es una cuadricula de trabajo.
   A la mitad se lee. Y con dos mosaicos, dos columnas es la fila entera. */
.aplicaciones--parrilla { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.aplicaciones > li > .pieza { height: 100%; }
.aplicaciones > li > .pieza > img { height: 100%; object-fit: contain; }

/* --- Correo -------------------------------------------------------------
   REJILLA DE CELDAS IGUALES y la pieza ENTERA dentro, sin recortar.

   Aqui esta la diferencia con Coltanques, y es por el material. Alla los
   correos median hasta 2.900 px de alto: entraran como entraran, la miniatura
   iba a ser un asomo, asi que la celda recortaba con `cover` anclado arriba y
   el correo completo quedaba a un clic en el visor.

   Los de Famoc son cortos. Miden 651 px de ancho y entre 663 y 1.097 de alto,
   o sea proporciones de 0,59 a 0,98. En una celda 2/3 con `contain` los ocho
   entran COMPLETOS: el mas alto se ajusta por altura y el mas ancho por ancho,
   y lo que sobra es papel blanco, que es el mismo blanco de la pagina y no se
   ve. Recortar aqui no ahorraria nada y taparia el encabezado de uno de ellos.

   La celda es 2/3 y no 3/4 porque la mediana de los ocho esta en 0,70: a 2/3
   ninguno se queda con banda de papel a los lados ni arriba mas alla de lo
   inevitable. */

.correos {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(10px, 1.4vw, 20px);
  margin: 0; padding: 0; list-style: none;
}
.correos > li { aspect-ratio: 2 / 3; }
.correos > li > .pieza { height: 100%; }
.correos > li > .pieza > img {
  height: 100%;
  object-fit: contain;
  /* Anclada ARRIBA, no al centro. Un correo se lee de arriba abajo, y cuando
     sobra papel es mejor que sobre al pie: asi los ocho encabezados quedan a la
     misma altura y la fila se lee como una fila. */
  object-position: top;
}

@media (max-width: 1099px) { .correos { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* --- Video --------------------------------------------------------------
   AGRUPADA POR FORMA, y por eso es flex y no grid.

   En esta pagina hay DOS secciones de video y dos formas: ocho reels 9:16 en
   la seccion de reels, y un solo institucional 16:9 en la de San Joaquin. En
   una misma rejilla quedarian escalonados; separados por forma, cada fila
   cuadra sola.

   La salida NO es recortarlos a todos al mismo cuadrado: un vertical es
   vertical, y meterlo en una caja cuadrada con bandas negras a los lados es
   enseñar el reproductor en vez de la pieza. La salida es AGRUPAR: como
   `seleccion.py` ya lista los videos por forma (cuadrados, verticales,
   horizontal), basta con darle a cada forma su ancho y dejar que el flex
   reparta. Salen tres filas y cada una cuadra sola:

     [vertical] [vertical] [vertical] [vertical]
     [vertical] [vertical] [vertical] [vertical]
     [        el 16:9, a ancho completo        ]

   Ocho verticales llenan dos filas de cuatro exactas. `justify-content:
   center` solo se nota si algun dia entra un numero que no sea multiplo de
   cuatro, y entonces la fila corta queda centrada en vez de coja. */

.videos {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  gap: clamp(12px, 1.8vw, 24px);
  margin: 0; padding: 0; list-style: none;
  --calle: clamp(12px, 1.8vw, 24px);
}
.videos > li { margin: 0; min-width: 0; }

/* Un cuarto del ancho, descontando las tres calles que hay entre cuatro
   piezas. Los cuatro cuadrados llenan la primera fila exacta. */
.video--cuadrado { flex: 0 0 calc((100% - var(--calle) * 3) / 4); }

/* Los verticales van al MISMO ancho que un cuadrado, no mas anchos: asi la
   fila de abajo se lee como continuacion de la de arriba y no como otra cosa.
   Al ser solo dos, `justify-content: center` los deja centrados. */
.video--vertical { flex: 0 0 calc((100% - var(--calle) * 3) / 4); }

/* Ancho completo para un horizontal. Aqui SI se usa: el manifiesto de Ventanas
   de San Joaquin es 1920x1080 y es la unica pieza de la pagina que pide
   pantalla. Al ser flex y no grid, no hay columna que recalcular. */
.video--ancho { flex: 0 0 100%; }
/* `display: block` no es cosmetico: <video> es inline por defecto y deja 8 px
   de hueco bajo la caja, el mismo del descendente de una linea de texto. Con
   cuatro videos alineados arriba, esos 8 px desalinean la fila entera. */
.video video {
  display: block;
  width: 100%; height: auto;
  background: #000;
}
.video--ancho { grid-column: span 2; }

.videos--sanjoaquin {
  display: flex;
  justify-content: center;
  align-items: flex-start;
}
.videos--sanjoaquin .video--vertical {
  flex: 0 0 clamp(170px, 22%, 270px);
}

/* A dos por fila: los ocho reels quedan en cuatro filas de dos y el 16:9 sigue
   solo. Todas las filas siguen cuadrando. */
@media (max-width: 899px) {
  .video--cuadrado,
  .video--vertical { flex-basis: calc((100% - var(--calle)) / 2); }
  .videos--sanjoaquin .video--vertical { flex-basis: clamp(150px, 27%, 220px); }
}

/* En movil las rejillas de cuatro caen a dos columnas. Las de tres caen a una
   sola: una pieza del sistema de 2022 a 46vw en un telefono se queda en 170 px
   y su parrafo deja de leerse. */
@media (max-width: 899px) {
  .galeria, .correos { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 699px) {
  .portada__titulo > span { white-space: normal; }
  .aplicaciones { grid-template-columns: 1fr; }
  .video--cuadrado,
  .video--vertical { flex-basis: 100%; }
  .videos--sanjoaquin .video--vertical { flex-basis: min(42vw, 190px); }
  .creditos-cierre { grid-template-columns: 1fr; gap: var(--e4); }
  .creditos-cierre__boton { grid-column: auto; }

  /* A una columna se suelta el cuadrado. Ya no hay fila que cuadrar, y forzar
     `contain` dentro de un cuadrado a ancho completo dejaria bandas de papel de
     100 px arriba y abajo de cada pieza. Cada una vuelve a su proporcion. */
  .aplicaciones > li { aspect-ratio: auto; }
  .aplicaciones > li > .pieza > img { height: auto; object-fit: fill; }
}

/* 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 ---------------------------------------------------
   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;
  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 ----------------------------------------------------
   SIN RECORTE. Corregido el 21 ago 2026, al construir Gasolina Extra.

   Este parrafo llevaba `-webkit-line-clamp: 4` y NO cabe en cuatro lineas: a
   1440 px mide seis y a 375 px mide treinta y una, o sea que en el telefono se
   estaba viendo el 13 % del bloque de derechos, con puntos suspensivos y sin
   forma de desplegarlo.

   Un recorte tipografico sirve para que una linea de seccion no deje un
   huerfano. No sirve para un bloque legal: ahi lo que no se lee es lo que no
   se dijo. */

.creditos-cierre {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--e5);
  align-items: start;
  margin-block: clamp(2.75rem, 5.5vw, 4.25rem);
}
.creditos {
  max-width: 68ch;
  margin: 0;
  padding-left: var(--e3);
  border-left: 2px solid var(--azul);
  font-size: .95rem;
  color: var(--tinta-media);
}
.creditos strong { font-weight: 600; color: var(--tinta); }

.creditos-cierre__columna .bloque__titulo { margin-bottom: var(--e3); }
.cierre__contenido h2 {
  margin: 0 0 var(--e2);
  color: var(--azul);
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.7rem, 1.15rem + 2vw, 2.75rem);
  line-height: 1.12;
  letter-spacing: -.02em;
  text-transform: uppercase;
  text-wrap: balance;
}
.cierre__contenido p {
  max-width: 60ch;
  margin: 0;
  color: var(--tinta-media);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

/* En el telefono el cierre pasa a una sola columna estrecha y esta frase mide
   ocho lineas. Recortarla a dos deja el llamado a la accion sin las tres
   cuartas partes de lo que dice, asi que abajo de 900 px no se recorta. La
   regla va AQUI y no arriba con las otras por orden de cascada: a igual
   especificidad gana la ultima. */
@media (max-width: 899px) {
  .cierre__contenido p { display: block; overflow: visible; }
}

.creditos-cierre__boton {
  grid-column: 1 / -1;
  justify-self: center;
}

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

/* EL AIRE ALREDEDOR DEL FILETE, medido y recortado el 20 ago 2026.

   Antes sobraban unos 120 px repartidos a los dos lados de la linea y el cierre
   se leia despegado del caso, como si fuera otra pagina. Y venian de dos sitios
   distintos, que es por lo que no bastaba con tocar aqui:

     - ARRIBA lo ponia el `margin-bottom` del bloque de creditos (4,25rem), que
       COLAPSA con el `margin-top` de esta seccion y gana el mas grande de los
       dos. Bajar solo el de aqui no hacia nada: seguia mandando el del bloque.
       Por eso el margen de arriba se pone en 0 y el espacio lo decide el bloque
       anterior, con la regla `:has(+ .cierre)` de mas abajo.
     - ABAJO lo pone el `padding-top` de esta seccion, que si se controla aqui.

   Queda en unos 40 px arriba y 32 abajo: suficiente para que el filete separe,
   y poco para que el cierre siga perteneciendo al caso. */
.cierre {
  margin-block: 0;
  /* El de abajo baja de 3rem a 1,75rem: entre el boton y el filete del pie
     habia 104 px (48 de aqui y 56 del pie) y sobraban. Ver `.pie`. */
  padding-block: clamp(1.5rem, 2.5vw, 2rem) clamp(1.25rem, 2vw, 1.75rem);
  border-top: 1px solid var(--linea);
}

/* El bloque que va justo antes del cierre acorta su margen inferior. `:has` es
   lo que permite que la regla viva aca y no haya que marcar ese bloque a mano
   en `generar_pagina.py`: si algun dia se agrega una seccion antes del cierre,
   el espacio se ajusta solo. */
.bloque:has(+ .cierre) { margin-bottom: clamp(1.75rem, 3vw, 2.5rem); }
/* Mismo tratamiento que los titulos de seccion: es uno mas, aunque viva en
   otro bloque. */
.cierre h2 {
  margin: 0 0 var(--e2);
  color: var(--azul);
  max-width: none;
  font-family: var(--display); font-weight: 700;
  font-size: clamp(1.7rem, 1.15rem + 2vw, 2.75rem);
  line-height: 1.12;
  letter-spacing: -.02em;
  text-wrap: balance;
}
.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 NEGRO sobre el color, no blanco. La causa es de
   especificidad y no se ve leyendo esta regla sola:

     .caso-famoc 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`, o sea la tinta del cierre. Y no era solo feo: #131313 sobre
   #d60724 da 3,5:1, que NO pasa AA. En blanco da 5,36: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.

   ESTE MISMO FALLO ESTABA EN LAS TRES HOJAS ANTERIORES, que tienen la
   pareja de reglas identica. Corregidos los dos en ago 2026, igual que aqui.
   Los tres daban practicamente el mismo contraste, 3,5:1, y no por casualidad:
   los tres acentos estan calibrados a 5,26-5,36:1 contra blanco, asi que contra
   la tinta #131313 (18,58:1 con blanco) los tres caen en 18,58/5,3 = 3,5. */
.caso-famoc .boton {
  display: inline-block;
  padding: .95rem 2rem;
  background: var(--azul); color: #fff;
  font-family: var(--texto); font-weight: 600; font-size: 1rem;
  text-decoration: none;
  transition: background .2s var(--salida), transform .2s var(--salida);
  border-radius: 999px;
}
.caso-famoc .boton:hover { background: var(--azul-oscuro); }
.caso-famoc .boton:active { transform: translateY(1px); }

/* --- El pie -------------------------------------------------------------
   El mismo patron de Barkys y Bonfibra, 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. */

/* El `padding-top` baja de 3,5rem a 2rem. Sumado al `padding-bottom` del
   cierre, el hueco entre el boton y el filete de la marca pasa de 104 px a 60.
   El de abajo NO se toca: es el aire al final del documento y sostiene la linea
   legal. */
.pie {
  padding: clamp(1.5rem, 2.5vw, 2rem) var(--margen) clamp(2rem, 4vw, 3rem);
  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(--azul); }

/* 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));
  overflow: hidden;
}
.visor__marco img {
  display: block;
  max-width: calc(100vw - 6rem);
  max-height: calc(100dvh - 10rem);
  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 sesenta imagenes. Donde no exista, el
   observador de `famoc.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 pieza se endereza y para: con sesenta
   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) {

    /* `.correos` va en la lista aunque sea multicolumna y no rejilla. Se quedo
       fuera en la primera version y se detecto leyendo `getComputedStyle`: sin
       perspective en el padre, el translate3d en Z y el rotateX de `llega` se
       aplanan, o sea que las piezas de correo subian sin profundidad mientras
       las otras cinco rejillas si la tenian. Se veia como si esa seccion
       estuviera a medio hacer. */
    .galeria, .aplicaciones, .videos, .pares, .correos { perspective: 1500px; }
    .galeria > li, .aplicaciones > li, .videos > li,
    .correos > 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) .aplicaciones > li,
    .js:not(.sin-timeline) .videos > li,
    .js:not(.sin-timeline) .correos > 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 tiras 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) .tira-sangre {
      opacity: 1; transform: none;
      animation: asoma linear both;
      animation-timeline: view(); animation-range: entry 4% cover 22%;
    }

    .js:not(.sin-timeline) .tira-sangre 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 .aplicaciones > li,
  .js .videos > li, .js .correos > li, .js .par,
  .js .par__lado--story, .js .tira-sangre, .js .tira-sangre 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); }
  /* `.videos` es flex, no grid: `grid-template-columns` aqui no hacia nada. Al
     imprimir, los cuadrados van de a dos y el 16:9 se queda con su fila. */
  .video--cuadrado, .video--vertical { flex-basis: calc((100% - var(--calle)) / 2); }
}
