/* ═══════════════════════════════════════════════════════════════
   PORTFOLIO — el mosaico y su barra de filtros.

   Medidas tomadas de la referencia (captura de 2531 px de ancho):
     · titular en versalitas ocupando casi todo el ancho, dos líneas
     · miniaturas de ~215×110 metidas DENTRO del texto, entre palabras
     · mosaico de tres columnas con alturas desiguales, esquinas ~16 px
     · nombre abajo a la izquierda y categoría abajo a la derecha, los
       dos en blanco y solo al pasar el puntero
     · barra de filtros oscura y translúcida, flotando pegada abajo
   ═══════════════════════════════════════════════════════════════ */

.pf {
  background: var(--bg);
  padding: calc(var(--nav-alto) + clamp(30px, 7vh, 96px)) var(--hd-pad) 0;
}


/* ── El titular ────────────────────────────────────────────────── */
.pf-cabeza {
  max-width: var(--ancho-max);
  margin: 0 auto clamp(30px, 5vh, 64px);
  /* El titular se mide contra ESTA caja, no contra la ventana. Ver la
     nota de .pf-titular. */
  container-type: inline-size;
}

/* Ata el tamaño al ancho de SU CAJA y no a una escala de texto: es una
   pieza gráfica que tiene que llenar la línea, no un titular corriente.
   El interlineado baja de 1 porque a este cuerpo el espacio normal
   entre líneas abre un hueco enorme.

   El cuerpo va en 'cqi' —el ancho de .pf-cabeza— y no en 'vw'. En 'vw'
   se partía: la caja deja de crecer en --ancho-max (1440px) pero la
   ventana sigue, así que pasados unos 1620px el texto seguía engordando
   dentro de una caja parada, «A FINE ▭ SELECTION» ya no cabía en un
   renglón y el titular pasaba de dos líneas a tres. Contra la caja, el
   cuerpo se congela cuando ella se congela y la proporción no cambia
   nunca. El tope en px es solo un seguro por si --ancho-max sube. */
.pf-titular {
  font-size: clamp(38px, 9.2cqi, 138px);
  font-weight: 800;
  letter-spacing: -.04em;
  line-height: .92;
  text-transform: uppercase;
  color: var(--tinta-alta);
}

/* Cada línea es un bloque flexible: así la miniatura se centra con las
   mayúsculas en vez de sentarse sobre la línea base, que es donde queda
   colgando si se deja como texto en línea. */
.pf-linea {
  display: flex;
  align-items: center;
  gap: clamp(10px, 1.2vw, 22px);
  flex-wrap: wrap;
}
/* La segunda línea entra desde un poco más adentro, como la referencia:
   rompe el bloque de dos líneas alineadas y lo hace menos rígido. */
.pf-linea + .pf-linea { padding-left: clamp(0px, 8vw, 150px); }

/* La miniatura hereda su alto del texto que la rodea —en 'em'— así que
   crece y encoge con el titular sola. En píxeles habría que retocarla en
   cada punto de corte. */
.pf-mini {
  display: inline-block;
  width: 1.42em;
  height: .74em;
  border-radius: .1em;
  overflow: hidden;
  background: #16181c;
  flex-shrink: 0;
}
/* Igual que .pf-obra picture, más abajo. */
.pf-mini picture { display: contents; }

.pf-mini img {
  width: 100%; height: 100%;
  object-fit: cover; display: block;
}


/* ── La tira de clientes ──────────────────────────────────────────
   Gira sin parar. El marcado imprime la lista DOS veces y aquí se
   desplaza exactamente la mitad de la pista: al llegar al final, el
   segundo grupo está justo donde empezó el primero, así que el salto de
   vuelta cae en un punto idéntico y no se ve.

   Por eso el desplazamiento es -50% y no una medida en píxeles: los
   logotipos cambian de ancho con la ventana, y cualquier número fijo
   dejaría un salto visible en cuanto se redimensiona. */
.pf-clientes {
  /* De filo a filo, saliéndose del relleno de la sección: una cinta que
     se corta a 1440 parece una lista, no una cinta. */
  margin: 0 calc(var(--hd-pad) * -1) clamp(34px, 6vh, 70px);
  padding: clamp(18px, 3vh, 32px) 0;
  border-top: 1px solid var(--border);
  overflow: hidden;

  /* Los logotipos se desvanecen en los dos extremos en lugar de
     aparecer y desaparecer de golpe contra el borde de la pantalla. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}

.pf-cinta {
  display: flex;
  width: max-content;
  animation: pf-girar 42s linear infinite;
}

/* Al acercarse se para, para poder mirar un logotipo concreto. Una
   cinta que huye del puntero es de las cosas que más molestan de este
   recurso. */
.pf-clientes:hover .pf-cinta { animation-play-state: paused; }

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

.pf-logos {
  display: flex; align-items: center;
  list-style: none; margin: 0; padding: 0;
  filter: grayscale(1);
  opacity: .34;
}

/* CASILLA FIJA, y es lo que arregla el desorden.

   Estos logotipos van de 1,7:1 a 6:1 de proporción. Con alto fijo y
   ancho libre, "bolds" salía casi cuatro veces más ancho que "mitrip".

   La casilla manda: mide siempre lo mismo y la imagen se ajusta dentro.
   Así todos pesan ópticamente igual, midan lo que midan por dentro.

   min-width: 0 no es adorno. Un elemento de una fila flexible tiene por
   defecto un ancho mínimo igual al de su contenido, y eso le gana al
   width de aquí arriba: la casilla se estiraba hasta lo que midiera el
   dibujo y las de al lado se montaban unas sobre otras. */
.pf-logos li {
  flex: 0 0 auto;
  min-width: 0;
  width: clamp(120px, 11vw, 175px);
  height: clamp(26px, 2.4vw, 38px);
  padding: 0 clamp(6px, .7vw, 14px);
}

/* Medidas EXACTAS, no máximos.

   Estos SVG traen viewBox pero no width ni height, así que no tienen
   tamaño propio: el navegador les da uno por defecto —300×150— y con
   'width: auto' era ese el que se usaba, saltándose el max-width porque
   el porcentaje no tenía contra qué resolverse de forma fiable. Fijando
   la caja al 100% de la casilla no queda nada que interpretar, y
   object-fit se encarga de encajar el dibujo dentro sin deformarlo ni
   recortarlo, centrado. */
.pf-logos img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
  display: block;
}


/* ── El mosaico ────────────────────────────────────────────────────
   Columnas de CSS y no una rejilla. Con grid haría falta decidir a mano
   en qué fila empieza cada obra para que las alturas encajen; con
   columnas el navegador va colocando y el hueco se cierra solo. Y al
   filtrar recoloca sin que haya que recalcular nada.

   El precio es que el orden baja por columnas en lugar de cruzar de
   izquierda a derecha. Aquí no importa: son obras sueltas, no una
   secuencia que haya que leer en orden. */
.pf-mosaico {
  max-width: var(--ancho-max);
  margin: 0 auto;
  column-count: 3;
  column-gap: clamp(12px, 1.5vw, 24px);
  column-fill: balance;
  /* Sitio para que la barra flotante no tape la última fila. */
  padding-bottom: clamp(90px, 12vh, 140px);
}

/* Con pocas obras a la vista, menos columnas.

   Filtrando por una categoría de una sola obra, tres columnas dejan dos
   vacías: un cuadro blanco enorme al lado de una foto. El JavaScript
   cuenta lo que queda visible y lo escribe en data-cols; aquí se le hace
   caso. Sin JavaScript no se escribe nada y se queda en tres, que es lo
   correcto para la vista completa. */
.pf-mosaico[data-cols="2"] { column-count: 2; }
.pf-mosaico[data-cols="1"] { column-count: 1; }

.pf-obra {
  /* Sin esto una obra puede partirse entre el final de una columna y el
     principio de la siguiente, y se ve la mitad de una foto arriba y la
     otra mitad al lado. */
  break-inside: avoid;
  position: relative;
  display: block;
  margin-bottom: clamp(12px, 1.5vw, 24px);
  border-radius: clamp(12px, 1.2vw, 18px);
  overflow: hidden;
  background: #dfe2e6;
  text-decoration: none;
}

/* Las tres alturas del patrón. Son proporciones y no píxeles para que
   el mosaico siga cuadrando a cualquier ancho de columna. */
/* ── LAS TRES ALTURAS, ACOTADAS ──────────────────────────────────
   Eran 3/4, 1/1 y 4/3. El problema: TODAS las portadas se generan a
   1.60 —es la proporción del hueco de /showcase-slider y la que usa
   assets/obras—, y object-fit: cover recorta lo que sobre.

   Con 3/4 eso significaba tirar el 53% DEL ANCHO. En una portada que es
   una tarjeta de marca con el logotipo centrado, eso lo parte por la
   mitad. Pasaba en Cleansify, Green House y Aalo, que son justo las que
   caen en 'alto' con el ciclo de $FORMATOS.

   Ahora las tres proporciones se quedan cerca de 1.60:

     alto   4/3   = 1.33   pierde 17% del ancho
     medio  3/2   = 1.50   pierde  6%
     bajo   16/10 = 1.60   no pierde nada

   SE PAGA CON VARIEDAD: antes las alturas iban de 595 a 335px y ahora
   de 335 a 279. El mosaico es más parejo. Es un intercambio consciente
   — en un portafolio, que el trabajo se vea entero pesa más que que la
   rejilla tenga relieve.

   Si algún día se quiere recuperar el relieve sin recortar, la salida
   es generar una portada VERTICAL propia por obra, no forzar la
   apaisada dentro de un hueco que no le corresponde. */
.pf-alto  { aspect-ratio: 4 / 3; }
.pf-medio { aspect-ratio: 3 / 2; }
.pf-bajo  { aspect-ratio: 16 / 10; }

.pf-obra picture { display: contents; }

.pf-obra img {
  width: 100%; height: 100%;
  object-fit: cover; display: block;
  transition: transform .8s cubic-bezier(.16,1,.3,1);
}
.pf-obra:hover img { transform: scale(1.05); }

/* El velo existe para que el texto blanco se lea sobre CUALQUIER foto,
   incluidas las claras. Sin él, un nombre blanco sobre una imagen
   pálida desaparece justo cuando hace falta. */
.pf-velo {
  position: absolute; inset: 0;
  background: linear-gradient(0deg, rgba(8,8,12,.62) 0%, rgba(8,8,12,.16) 42%, transparent 68%);
  opacity: 0;
  transition: opacity .45s ease;
}

.pf-nombre, .pf-tipo {
  position: absolute;
  bottom: clamp(14px, 1.5vw, 22px);
  color: #fff;
  opacity: 0;
  /* Suben un poco al aparecer: entran, no se encienden. */
  transform: translateY(9px);
  transition: opacity .45s ease, transform .45s cubic-bezier(.16,1,.3,1);
}

.pf-nombre {
  left: clamp(14px, 1.5vw, 24px);
  font-size: clamp(15px, 1.35vw, 22px); font-weight: 800;
  letter-spacing: -.01em; text-transform: uppercase;
  /* Deja sitio a la categoría de al lado. */
  max-width: calc(100% - 120px);
}

.pf-tipo {
  right: clamp(14px, 1.5vw, 24px);
  font-size: clamp(12px, .95vw, 15px);
  color: rgba(255,255,255,.9);
}

.pf-obra:hover .pf-velo,
.pf-obra:focus-visible .pf-velo { opacity: 1; }

.pf-obra:hover .pf-nombre, .pf-obra:focus-visible .pf-nombre,
.pf-obra:hover .pf-tipo,   .pf-obra:focus-visible .pf-tipo {
  opacity: 1; transform: none;
}
/* La categoría entra un pelo después que el nombre: se leen en orden en
   vez de aparecer las dos de golpe. */
.pf-obra:hover .pf-tipo { transition-delay: .06s; }

/* ── La invitación ─────────────────────────────────────────────────
   La última pieza del mosaico. Va en el color de acento porque tiene que
   distinguirse de las obras a simple vista: es una invitación, no un
   trabajo, y confundirlas sería peor que no ponerla. */
.pf-invitacion {
  break-inside: avoid;
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  aspect-ratio: 1 / 1;
  margin-bottom: clamp(12px, 1.5vw, 24px);
  padding: clamp(18px, 1.8vw, 30px);
  border-radius: clamp(12px, 1.2vw, 18px);
  background: var(--acento);
  color: #fff;
  text-decoration: none;
  overflow: hidden;
  transition: filter .4s ease;
}
.pf-invitacion:hover { filter: brightness(1.06); }

.pf-invitacion-rotulo {
  font-size: clamp(11px, .85vw, 13px); font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase;
  opacity: .72;
}

.pf-invitacion-titulo {
  font-size: clamp(22px, 2.1vw, 34px); font-weight: 800;
  letter-spacing: -.03em; line-height: 1.06;
  text-transform: uppercase;
  margin: auto 0;
}

.pf-invitacion-pie {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: clamp(12px, .95vw, 14px); font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase;
}
.pf-invitacion-pie svg {
  width: 17px; height: 17px;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .4s cubic-bezier(.16,1,.3,1);
}
.pf-invitacion:hover .pf-invitacion-pie svg { transform: translateX(5px); }


/* Mientras el filtro recoloca. No se vacía de golpe: se atenúa, para
   que el alto de la página no se desplome y vuelva a crecer. */
.pf-mosaico.esta-filtrando { opacity: .38; transition: opacity .2s ease; }

/* Lo que el filtro descarta desaparece del flujo, no se queda hueco. */
.pf-obra[hidden] { display: none; }


/* ── Los filtros ───────────────────────────────────────────────────
   Flotan pegados abajo y no se pierden al bajar: son el mando de esta
   página, y tener que subir a buscarlos cada vez la haría inservible. */
.pf-filtros {
  position: fixed;
  left: 50%;
  bottom: clamp(16px, 3vh, 30px);
  transform: translateX(-50%);
  z-index: 80;

  display: flex; align-items: center;
  gap: clamp(4px, .6vw, 10px);
  padding: 6px;
  border-radius: 99px;
  background: rgba(22, 24, 28, .72);
  backdrop-filter: blur(16px) saturate(1.4);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  box-shadow: 0 10px 34px rgba(10, 10, 14, .22);
  max-width: calc(100vw - 32px);
  overflow-x: auto;
  /* La barra se desplaza sola si no cabe, pero sin enseñar barra de
     desplazamiento: dentro de una píldora quedaría fatal. */
  scrollbar-width: none;
}
.pf-filtros::-webkit-scrollbar { display: none; }

.pf-filtro {
  flex-shrink: 0;
  padding: 10px clamp(12px, 1.1vw, 20px);
  border-radius: 99px;
  color: rgba(255,255,255,.72);
  text-decoration: none;
  font-size: clamp(11.5px, .9vw, 13.5px); font-weight: 600;
  letter-spacing: .07em; text-transform: uppercase;
  white-space: nowrap;
  transition: background .3s ease, color .3s ease;
}
.pf-filtro:hover { color: #fff; }

.pf-filtro sup {
  font-size: .72em;
  margin-left: 2px;
  opacity: .62;
}

/* El activo va con fondo más oscuro, no más claro: se hunde en la barra
   en vez de saltar de ella, que es como se ve en la referencia. */
.pf-filtro.es-activo {
  background: rgba(10, 11, 14, .72);
  color: #fff;
}


/* ── El cierre ─────────────────────────────────────────────────── */
.pf-juntos {
  max-width: var(--ancho-max);
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, .42fr);
  gap: clamp(24px, 4vw, 70px);
  align-items: start;
  border-top: 1px solid var(--border);
  padding: clamp(40px, 7vh, 90px) 0 clamp(50px, 9vh, 120px);
}

.pf-juntos-titulo {
  font-size: clamp(34px, 7vw, 118px);
  font-weight: 800;
  letter-spacing: -.04em;
  line-height: .94;
  text-transform: uppercase;
  color: var(--tinta-alta);
}
.pf-juntos-titulo .pf-linea + .pf-linea { padding-left: 0; }

.pf-juntos-nota {
  font-size: clamp(14px, 1.15vw, 18px);
  line-height: 1.55;
  color: var(--tinta-alta);
  margin-bottom: clamp(14px, 2vh, 22px);
}

.pf-juntos-cta {
  display: inline-flex; align-items: center; gap: 10px;
  color: var(--acento);
  text-decoration: none;
  font-size: clamp(12.5px, 1vw, 15px); font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  /* El subrayado se dibuja aquí para poder separarlo del texto; el que
     pone el navegador va pegado a las letras. */
  border-bottom: 1px solid currentColor;
  padding-bottom: 3px;
}

.pf-juntos-flecha {
  width: 30px; height: 23px;
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .45s cubic-bezier(.16,1,.3,1);
}
.pf-juntos-cta:hover .pf-juntos-flecha { transform: translateX(5px); }


/* ── Tamaños ───────────────────────────────────────────────────── */
@media (max-width: 1000px) {
  /* El atributo se vuelve a nombrar aquí porque su selector es más
     específico que .pf-mosaico a secas: sin repetirlo, un data-cols="2"
     escrito para una pantalla ancha seguiría mandando en una estrecha. */
  .pf-mosaico,
  .pf-mosaico[data-cols="2"] { column-count: 2; }
  .pf-mosaico[data-cols="1"] { column-count: 1; }

  .pf-juntos { grid-template-columns: 1fr; }
}

@media (max-width: 760px) {
  .pf-mosaico,
  .pf-mosaico[data-cols] { column-count: 1; }

  /* Dos líneas de titular con sangría a este ancho dejan renglones de
     una palabra. Se alinean las dos. */
  .pf-linea + .pf-linea { padding-left: 0; }

  /* En una pantalla estrecha la vuelta entera se hace larguísima: se
     recorre lo mismo por mucho menos ancho visible. */
  .pf-cinta { animation-duration: 26s; }

  /* En táctil no hay puntero que pasar por encima, así que el rótulo no
     aparecería nunca. Aquí va siempre puesto. */
  .pf-velo, .pf-nombre, .pf-tipo { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .pf-obra img, .pf-velo, .pf-nombre, .pf-tipo,
  .pf-juntos-flecha, .pf-mosaico { transition: none; }
  /* La cinta se queda quieta. Es movimiento continuo y automático en
     pantalla, justo lo que esta preferencia existe para evitar; los
     logotipos se siguen viendo, sencillamente no pasan. */
  .pf-cinta { animation: none; }
  .pf-obra:hover img { transform: none; }
  .pf-juntos-cta:hover .pf-juntos-flecha { transform: none; }
  .pf-invitacion, .pf-invitacion-pie svg { transition: none; }
  .pf-invitacion:hover .pf-invitacion-pie svg { transform: none; }
}
