/* ============================================================
   Carolina Cerutti — hoja de estilos del home
   Extraida de index.html (fase 0) y rehecha sobre el sistema visual 2026
   (fase 1): Inter Tight desde Google Fonts, fondo off-white, sin fuentes
   autohospedadas.
   ============================================================ */

/* ============================================
   RESET & BASE
   ============================================ */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; -webkit-font-smoothing: antialiased; }

/* ============================================
   SISTEMA VISUAL 2026
   Una sola familia (Inter Tight, de Google Fonts). La jerarquia se hace
   con tamano y peso, no con cambio de tipografia ni de color.
   ============================================ */
:root {
  /* Color ------------------------------------------------------------- */
  --bg: #FAFAF7;          /* off-white calido */
  --fg: #141414;          /* texto principal, casi negro */
  --fg-dim: #6B6B66;      /* texto secundario */
  --fg-faint: rgba(20,20,20,0.30);
  --fg-ghost: rgba(20,20,20,0.26);
  --line: rgba(20,20,20,0.08);
  /* Sin color de marca: el enfasis se hace pasando de --fg-dim a --fg.
     --accent queda como token para no romper las reglas que lo usan. */
  --accent: #141414;

  /* Tipografia -------------------------------------------------------- */
  --ff: 'Inter Tight', system-ui, sans-serif;
  --display: var(--ff);
  --body: var(--ff);

  /* Glass ------------------------------------------------------------- */
  --glass-bg: rgba(255,255,255,0.55);
  --glass-border: rgba(255,255,255,0.7);
  --glass-shadow: 0 2px 8px rgba(20,20,20,0.04), 0 8px 24px rgba(20,20,20,0.05);
  --glass-shadow-hover: 0 4px 12px rgba(20,20,20,0.06), 0 16px 40px rgba(20,20,20,0.09);
  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  --pad-x: clamp(40px, 9vw, 160px);
}

/* Jerarquia por peso:
     display grande  500-600
     texto corrido   400
     labels          500 + tracking amplio + tamano chico          */
.big-title, .hero-title, .hero-name, .work-title, .copyright,
.intro-name, .cs-intro h2, .nav-logo {
  font-weight: 600;
  letter-spacing: -0.03em;
}
.hero-sub, .skill-name, .personal-text, .cs-desc-statement,
.cs-quote, .cs-process-text h3 {
  font-weight: 500;
  letter-spacing: -0.015em;
}
.section-label, .marquee, .hero-band-track, .label, .btn {
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

body {
  font-family: var(--ff);
  font-weight: 400;
  background: var(--bg);
  color: var(--fg);
  overflow-x: hidden;
  line-height: 1.5;
}
img, video { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; }

/* ============================================
   GLASS — clase reutilizable para superficies elevadas.
   Se aplica sola (.glass) o se hereda con @extend manual sumando la
   clase al elemento. Los valores viven en tokens para que un cambio
   de material se haga en un solo lugar.
   ============================================ */
.glass {
  background: var(--glass-bg);
  backdrop-filter: blur(12px) saturate(1.1);
  -webkit-backdrop-filter: blur(12px) saturate(1.1);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  box-shadow: var(--glass-shadow);
  transition: box-shadow 300ms var(--ease),
              transform  300ms var(--ease),
              background 300ms var(--ease);
}
.glass:hover {
  box-shadow: var(--glass-shadow-hover);
  background: rgba(255,255,255,0.68);
}
/* El lift al hover queda para enlaces y botones. No se aplica a .pp-row:
   el JS de apilado le escribe transform inline en cada frame y ganaria el. */
a.glass:hover, button.glass:hover {
  transform: translateY(-2px);
}
/* .reveal se declara mas abajo y transition es una sola propiedad: sin esta
   regla combinada, la entrada del reveal pisaba por completo el hover glass. */
.reveal.glass {
  transition: box-shadow 300ms var(--ease),
              background  300ms var(--ease),
              opacity     0.9s  var(--ease),
              transform   0.9s  var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  .glass, .reveal.glass { transition: none; }
  a.glass:hover, button.glass:hover { transform: none; }
}

/* ============================================
   UTILITIES
   ============================================ */
.section-label {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  padding: 14px var(--pad-x);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.section-label > span:nth-child(2) { text-align: center; color: var(--accent); }
.section-label > span:nth-child(3) { text-align: right; }

.placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, #232323, #0e0e0e);
  color: var(--fg-dim);
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  text-align: center;
  padding: 12px;
  border: 1px dashed var(--line);
  border-radius: 12px;
  overflow: hidden;
  width: 100%;
  height: 100%;
  min-height: 200px;
}
.placeholder.video::before {
  content: '▶';
  position: absolute;
  font-size: 28px;
  opacity: 0.4;
}
.placeholder span { position: relative; z-index: 2; }

/* Reveal animations */
/* Mismo criterio que las cards del Index: visible por defecto. El estado
   inicial lo pone el JS al marcar el body, asi que si el observer no dispara
   el contenido igual se ve. */
.reveal {
  transition: opacity 0.9s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.9s cubic-bezier(0.22, 1, 0.36, 1);
}
body.js-reveal .reveal { opacity: 0; transform: translateY(30px); }
body.js-reveal .reveal.in { opacity: 1; transform: translateY(0); }
.reveal-delay-1 { transition-delay: 0.1s; }
.reveal-delay-2 { transition-delay: 0.2s; }
.reveal-delay-3 { transition-delay: 0.3s; }

/* Accent details */
/* Los separadores viven tanto sobre el fondo claro como dentro de las bandas
   invertidas. currentColor los hace adaptarse a la superficie que les toque:
   con un color fijo quedaban negros sobre negro. */
.dot { color: currentColor; opacity: 0.4; }
::selection { background: var(--accent); color: var(--fg); }

/* ============================================
   NAV
   ============================================ */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  padding: 22px var(--pad-x);
  background: var(--glass-bg);
  backdrop-filter: blur(12px) saturate(1.1);
  -webkit-backdrop-filter: blur(20px);
  z-index: 100;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
  align-items: start;
}
.nav-logo {
  font-family: var(--display);
  font-weight: 600;
  font-size: 22px;
  letter-spacing: 0.02em;
  line-height: 1;
}
.nav-links { text-align: left; }
.nav-links .label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--fg);
  margin-bottom: 6px;
  letter-spacing: 0;
}
.nav-links a {
  color: var(--fg-dim);
  transition: color 0.2s;
}
.nav-links a:hover { color: var(--accent); }
.nav-meta { text-align: left; }
.nav-meta .label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--fg);
  margin-bottom: 6px;
  letter-spacing: 0;
}
.nav-meta > span:not(.label) {
  color: var(--fg-dim);
}
.nav-networks { text-align: left; }
.nav-networks .label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--fg);
  margin-bottom: 6px;
  letter-spacing: 0;
}
.nav-networks a {
  color: var(--fg-dim);
  transition: color 0.2s;
}
.nav-networks a:hover { color: var(--accent); }

/* ============================================
   HERO BAND (horizontal marquee divider)
   ============================================ */
.hero-band {
  /* Al fondo de .hero-top = pie del video visible del reel */
  margin: auto 0 0 0;
  margin-right: calc(var(--reel-w) + 30px);
  background: var(--fg);
  color: var(--bg);
  overflow: hidden;
  white-space: nowrap;
  display: flex;
  padding: 9px 0;
  transform: scaleX(0);
  transform-origin: center;
  position: relative;
  z-index: 1;
}
.hero-band-track {
  display: flex;
  gap: 100px;
  animation: marquee 28s linear infinite;
  flex-shrink: 0;
  padding-right: 100px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* ============================================
   HERO
   ============================================ */
.hero {
  padding: 180px var(--pad-x) 0;
  display: flex;
  flex-direction: column;
  /* Medidas del reel en un solo lugar: las usan el propio reel y el alto
     de .hero-top, así nunca pueden quedar desfasados. */
  --reel-w: clamp(280px, 38vw, 520px);
  --reel-top: 175px;
  /* OJO: el contenedor del reel es 3/4 pero el video de Vimeo es 16/9, así que
     queda centrado con barras negras arriba y abajo (invisibles sobre el fondo
     oscuro). El borde que se VE no es el del contenedor sino el del video.
     Distancia desde el techo de .hero-top hasta el pie del video visible:
       (alto caja + alto video)/2 - 175  =  ancho * (4/3 + 9/16)/2 - 175
                                        =  ancho * 91/96 - 175 */
  --reel-video-bottom: calc(var(--reel-w) * 91 / 96 - var(--reel-top));
}
/* Columna flex: la banda va al fondo con margin-top:auto. El min-height deja
   el fondo justo en el pie del video visible → alineadas. Si en pantallas
   angostas el texto es más alto que eso, el flex empuja la banda hacia abajo
   en vez de dejarla pisar el titular. */
.hero-top {
  display: flex;
  flex-direction: column;
  position: relative;
  min-height: var(--reel-video-bottom);
}
.hero-headline {
  /* Mismo ancho que la columna izquierda del grid original (1fr 1fr, gap 40px) */
  max-width: min(720px, calc((100% - 40px) / 2));
  margin-top: 25px;
  /* Aire mínimo contra la banda en pantallas angostas, donde no hay lugar
     para alinearla con el video y el flex la empuja hasta acá */
  margin-bottom: 24px;
}
.hero-title {
  font-family: var(--display);
  font-size: clamp(21px, 2.5vw, 35px);
  line-height: 1.05;
  letter-spacing: -0.02em;
}
/* Subtítulo: la jerarquía contra el título se hace con tamaño, aire y color,
   no con un cambio de familia. */
.hero-sub {
  font-family: var(--display);
  font-size: clamp(15px, 1.5vw, 21px);
  line-height: 1.3;
  letter-spacing: -0.005em;
  opacity: 0.7;
  margin-top: clamp(14px, 1.5vw, 22px);
}
.hero-image {
  position: absolute;
  top: calc(-1 * var(--reel-top));
  right: 0;
  width: var(--reel-w);
  /* Alto explícito además de aspect-ratio: idéntica caja (w × 4/3), pero
     resuelve también en Chrome viejos, donde aspect-ratio no aplica. */
  height: calc(var(--reel-w) * 4 / 3);
  aspect-ratio: 3 / 4;
  overflow: hidden;
  border-radius: 12px;
  z-index: 2;
  cursor: pointer;
}
.hero-image iframe {
  width: 100%; height: 100%;
  border: none;
  pointer-events: none;
}
.hero-play-btn {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%) scale(0.9);
  background: var(--fg);
  color: var(--bg);
  padding: 14px 28px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0;
  transition: opacity 0.3s, transform 0.3s;
  z-index: 3;
  pointer-events: none;
}
.hero-image:hover .hero-play-btn {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

/* Video Lightbox */
.video-lightbox {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.92);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s;
}
.video-lightbox.active {
  opacity: 1;
  pointer-events: all;
}
/* El slot recibe iframe de Vimeo o <video> local: mismas medidas para los dos */
.video-lightbox-slot {
  width: 85vw;
  height: 47.8vw;
  max-width: 1200px;
  max-height: 675px;
}
.video-lightbox-slot iframe,
.video-lightbox-slot video {
  width: 100%;
  height: 100%;
  border: none;
  border-radius: 12px;
  display: block;
  background: #000;
}
.video-lightbox-close {
  position: absolute;
  top: 30px; right: 40px;
  background: none;
  border: none;
  /* el scrim del lightbox es oscuro: el aspa va clara, no con --fg */
  color: #FAFAF7;
  font-size: 32px;
  font-weight: 300;
  opacity: 0.6;
  transition: opacity 0.3s;
}
.video-lightbox-close:hover { opacity: 1; }

.hero-name {
  font-family: var(--display);
  font-weight: 600;
  line-height: 0.9;
  letter-spacing: -0.04em;
  /* La banda es absolute (no ocupa flujo): este margen reemplaza los
     40px de margin-bottom que ella aportaba + los 80px originales */
  margin-top: 120px;
  /* Aire entre el nombre y la banda PROJECTS (antes lo daba el marquee) */
  margin-bottom: 170px;
  white-space: nowrap;
  overflow: hidden;
}

/* ============================================
   MARQUEE
   ============================================ */
.marquee {
  display: flex;
  overflow: hidden;
  padding: 14px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.05em;
}
.marquee-track {
  display: flex;
  gap: 80px;
  animation: marquee 40s linear infinite;
  flex-shrink: 0;
  padding-right: 80px;
}
.marquee:hover .marquee-track { animation-play-state: paused; }
@keyframes marquee {
  from { transform: translateX(0); }
  to { transform: translateX(-100%); }
}
.marquee.fast .marquee-track { animation-duration: 25s; }
.marquee.reverse .marquee-track { animation-direction: reverse; }
/* La banda venia en negro pleno, del sistema viejo. En una pagina que es toda
   papel y linea fina, tres slabs negras eran lo unico que gritaba — y en
   telefono quedaba un bloque negro con una sola palabra adentro. Se queda el
   movimiento y la funcion (separar secciones), se va el relleno: filete arriba
   y abajo y la tipografia en gris, como el resto de las etiquetas.
   Para volver al negro: background var(--fg) y color var(--bg). */
.marquee.marquee-light {
  background: none;
  color: var(--fg-dim);
  border-color: var(--line);
  position: relative;
  z-index: 1;
}
/* Banda de disciplinas: va entre el section-label de Projects y "Highlighted designs".
   El big-title ya trae 80px de padding-top, por eso el margin-bottom es corto. */
.marquee.hero-marquee {
  margin: 100px 0 40px;
  position: relative;
  z-index: 1;
}
.btn {
  display: inline-block;
  padding: 12px 28px;
  border: 1px solid var(--fg);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-top: 28px;
  transition: background 0.3s, color 0.3s;
}
.btn:hover { background: var(--fg); color: var(--bg); }

/* ============================================
   SELECTED DESIGNS
   ============================================ */
.big-title {
  font-family: var(--display);
  font-size: clamp(40px, 6.5vw, 96px);
  font-weight: 600;
  line-height: 1.0;
  letter-spacing: -0.035em;
  padding: 120px var(--pad-x) 48px;
  max-width: 18ch;
}
.big-title.with-num sup {
  font-size: 0.35em;
  vertical-align: super;
  font-weight: 500;
  margin-left: 0.1em;
}

.selected-intro {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px;
  padding: 0 var(--pad-x) 80px;
  align-items: end;
}
.selected-intro p {
  font-size: 15px;
  line-height: 1.5;
  color: var(--fg-dim);
  max-width: 480px;
}
.selected-intro p strong { color: var(--fg); font-weight: 500; }

.projects-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 400px 60px;
  padding: 0 var(--pad-x) 160px;
}
.project-card {
  position: relative;
  cursor: pointer;
}
.project-card:nth-child(1) { margin-top: 40px; max-width: 90%; }
.project-card:nth-child(2) { margin-top: 220px; max-width: 75%; }
.project-card:nth-child(3) {
  grid-column: 1 / -1;
  width: 40%;
  margin: 0 auto;
}
.project-card:nth-child(4) { max-width: 75%; margin-top: 60px; }
.project-card:nth-child(5) { max-width: 85%; margin-top: -80px; }
.project-images {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: 12px;
}
.project-card:nth-child(1) .project-images { aspect-ratio: 4 / 4.5; }
.project-card:nth-child(2) .project-images { aspect-ratio: 557 / 339; }
.project-card:nth-child(2) .img-fg { aspect-ratio: 277 / 195; }
.project-card:nth-child(3) .project-images { aspect-ratio: 4 / 5; }
.project-card:nth-child(3) .img-fg { aspect-ratio: 3 / 4; }
.project-card:nth-child(4) .project-images { aspect-ratio: 5 / 4; }
.project-card:nth-child(4) .img-fg { aspect-ratio: 1 / 1.1; }
.project-card:nth-child(5) .project-images { aspect-ratio: 4 / 4.5; }
.project-images .img-bg {
  position: absolute; inset: 0;
  transition: transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}
.project-images .img-fg {
  position: absolute;
  width: 55%;
  aspect-ratio: 1/1;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  transition: transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
  box-shadow: 0 18px 44px rgba(20,20,20,0.10);
  border-radius: 12px;
  overflow: hidden;
}
.img-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,0);
  transition: background 0.5s ease;
  z-index: 1;
}
.project-card:hover .img-bg::after {
  background: rgba(0,0,0,0.35);
}
.project-card:hover .img-bg { transform: scale(1.05); }
.project-card:hover .img-fg { transform: translate(-50%, -55%) scale(1.08); }
.sd-category {
  position: absolute;
  left: 0; right: 0;
  top: 50%;
  background: var(--fg);
  color: var(--bg);
  font-family: var(--body);
  font-size: 16px;
  font-weight: 500;
  text-align: center;
  padding: 12px 0;
  z-index: 2;
  transform: translateY(-50%) scaleX(0);
  opacity: 0;
  transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.3s ease;
}
.sd-category span {
  display: inline-block;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.3s ease 0.25s, transform 0.3s ease 0.25s;
}
.project-card:hover .sd-category {
  transform: translateY(-50%) scaleX(1);
  opacity: 1;
}
.project-card:hover .sd-category span {
  opacity: 1;
  transform: translateY(0);
}

.project-meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-top: 20px;
  font-size: 14px;
}
.project-meta .name { font-weight: 500; }
.project-meta .num { color: var(--fg-dim); font-size: 12px; }
.project-role {
  font-size: 12px;
  color: var(--fg-dim);
  margin-top: 4px;
  letter-spacing: 0.03em;
}

/* ============================================
   SKILLS
   ============================================ */
.skills-list {
  padding: 0 var(--pad-x) 140px;
}
.skill-row {
  display: grid;
  grid-template-columns: 80px 1fr 2fr;
  gap: 40px;
  padding: 36px 0;
  border-top: 1px solid var(--line);
  align-items: start;
  transition: padding 0.4s cubic-bezier(0.22, 1, 0.36, 1), background 0.3s ease;
  border-radius: 4px;
  cursor: pointer;
}
.skill-row:hover {
  padding: 52px 24px;
  background: rgba(255,255,255,0.04);
}
.skill-row:last-child { border-bottom: 1px solid var(--line); }
.skill-num { color: var(--fg-dim); font-size: 13px; padding-top: 4px; }
.skill-name {
  font-family: var(--display);
  font-size: clamp(16px, 1.5vw, 20px);
  font-weight: 500;
  letter-spacing: -0.01em;
}
.skill-desc {
  font-size: 14px;
  line-height: 1.55;
  color: var(--fg-dim);
  max-width: 520px;
}

/* ============================================
   PERSONAL PROFILE
   ============================================ */
.personal-profile {
  position: relative;
  padding: 160px var(--pad-x) 600px;
  min-height: 150vh;
  overflow: hidden;
}
.personal-text {
  font-family: var(--display);
  font-size: clamp(19px, 2.1vw, 29px);
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.01em;
  max-width: 52%;
  margin-left: 22%;
  padding-top: 260px;
  color: var(--fg-dim);
  position: relative;
  z-index: 2;
}
.personal-text strong { font-weight: 600; }
/* Sin mix-blend-mode: estaba pensado para el fondo oscuro. Sobre el off-white,
   difference invierte el casi-negro a un gris clarisimo y el texto desaparece. */
.pp-word { transition: color 0.15s ease; }
.personal-secondary {
  font-size: 14px;
  max-width: 360px;
  color: var(--fg-dim);
  margin: 400px 0 0 35%;
  position: relative;
  z-index: 2;
}
.floating-imgs {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.floating-imgs > div {
  position: absolute;
  pointer-events: auto;
  border-radius: 16px;
  overflow: hidden;
}
.floating-imgs img,
.floating-imgs video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.floating-imgs .f1 { top: 10%; left: 18%; width: 12vw; min-width: 140px; aspect-ratio: 3/4; z-index: 1; }
.floating-imgs .f2 { top: 58%; left: 17%; width: 17vw; min-width: 180px; aspect-ratio: 3/4; z-index: 3; }
.floating-imgs .f3 { top: 22%; right: 16%; width: 22vw; min-width: 240px; aspect-ratio: 3/5; z-index: 1; }
.floating-imgs .f4 {
  top: 76%; left: 42%;
  width: 22vw; min-width: 260px;
  font-size: 0.94rem;
  line-height: 1.55;
  color: var(--fg-dim);
  letter-spacing: 0.01em;
  z-index: 4;
  border-radius: 0;
  overflow: visible;
}

/* ============================================
   EXPERIENCE / WORK
   ============================================ */
.work-header {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: start;
  padding: 80px var(--pad-x) 40px;
  gap: 40px;
}
.work-titles {
  position: relative;
  height: clamp(44px, 7.6vw, 122px);
}
.work-title {
  font-family: var(--display);
  font-size: clamp(44px, 7.6vw, 122px);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.04em;
  margin: 0;
  position: absolute;
  top: 0;
  left: 0;
  white-space: nowrap;
}
.work-title .lw {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding: 0.05em 0.04em 0.25em;
  margin: -0.05em -0.04em -0.25em;
}
.work-title .wl {
  display: inline-block;
  transform: translateY(120%);
}
.work-thumb {
  width: 165px;
  aspect-ratio: 3/4;
  border-radius: 8px;
  overflow: hidden;
  margin-top: 20px;
}
.work-table {
  padding: 40px var(--pad-x) 140px;
}
.work-row {
  display: grid;
  grid-template-columns: 2fr 1fr 1.5fr 1fr;
  gap: 24px;
  padding: 24px 0;
  border-top: 1px solid var(--line);
  font-size: 14px;
  align-items: start;
}
.work-row:last-child { border-bottom: 1px solid var(--line); }
.work-row .company { font-weight: 500; }
.work-row .date,
.work-row .role,
.work-row .location { color: var(--fg-dim); }
.work-row .location { text-align: right; }

/* ============================================
   COMPETITIONS
   ============================================ */
.comp-list {
  padding: 80px var(--pad-x) 160px;
}
.comp-row {
  display: grid;
  grid-template-columns: 100px 200px 1fr 1.2fr;
  gap: 30px;
  padding: 36px 0;
  border-top: 1px solid var(--line);
  align-items: start;
  font-size: 13px;
}
.comp-row:last-child { border-bottom: 1px solid var(--line); }
.comp-year { color: var(--fg-dim); }
.comp-name { font-weight: 500; font-size: 14px; }
.comp-desc { color: var(--fg-dim); line-height: 1.5; max-width: 280px; }
.comp-imgs {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  align-items: start;
}
.comp-imgs > div {
  aspect-ratio: 3/4;
  border-radius: 6px;
  overflow: hidden;
  height: auto;
  min-height: 0;
}
.comp-imgs > div:nth-child(2),
.comp-imgs > div:nth-child(4) {
  aspect-ratio: 1/1;
}

/* ============================================
   CLIENTS / VIDEO SPIRAL
   ============================================ */
.clients-section {
  padding: 0 var(--pad-x);
  position: relative;
  height: 500vh;
  margin-bottom: 10px;
}
.video-spiral {
  position: sticky;
  top: 0;
  width: 100%;
  height: 100vh;
  perspective: 1100px;
  perspective-origin: 50% 50%;
  transform-style: preserve-3d;
}
.video-spiral > div {
  position: absolute;
  top: 50%;
  left: 50%;
  box-shadow: 0 18px 44px rgba(20,20,20,0.10);
  border-radius: 16px;
  overflow: hidden;
  transform-style: preserve-3d;
  will-change: transform;
  transition: box-shadow 0.4s;
}
.video-spiral > div:hover { box-shadow: 0 26px 60px rgba(20,20,20,0.16); }
.video-spiral .v1 { width: clamp(280px, 30vw, 460px); aspect-ratio: 16/9; }
.video-spiral .v2 { width: clamp(240px, 26vw, 380px); aspect-ratio: 16/9; }
.video-spiral .v3 { width: clamp(240px, 26vw, 380px); aspect-ratio: 16/9; }
.video-spiral .v4 { width: clamp(200px, 22vw, 320px); aspect-ratio: 16/9; }
.video-spiral .v5 { width: clamp(220px, 24vw, 360px); aspect-ratio: 16/9; }

/* ============================================
   PERSONAL PROJECTS
   ============================================ */
.pp-grid {
  padding: 80px var(--pad-x) 0;
  position: relative;
}
.pp-row {
  /* superficie glass: el padding la separa de las imagenes que contiene */
  padding: 18px;
  display: grid;
  grid-template-columns: 1fr 0.8fr;
  gap: 60px;
  align-items: stretch;
  position: sticky;
  top: 80px;
  margin-bottom: 60vh;
  will-change: transform, opacity;
}
.pp-row:nth-child(1) { z-index: 1; }
.pp-row:nth-child(2) { z-index: 2; }
.pp-row:nth-child(3) { z-index: 3; }
.pp-row:nth-child(4) { z-index: 4; }
.pp-row:last-child {
  margin-bottom: 200px;
}
.pp-image-main {
  aspect-ratio: 1.15 / 1;
  border-radius: 12px;
  overflow: hidden;
  position: relative;
}
.pp-category {
  position: absolute;
  left: 0; right: 0;
  top: 50%;
  background: var(--fg);
  color: var(--bg);
  font-family: var(--body);
  font-size: 16px;
  font-weight: 500;
  text-align: center;
  padding: 12px 0;
  z-index: 2;
  transform: translateY(-50%) scaleX(0);
  opacity: 0;
  transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.3s ease;
}
.pp-category span {
  display: inline-block;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.3s ease 0.25s, transform 0.3s ease 0.25s;
}
.pp-row:hover .pp-category {
  transform: translateY(-50%) scaleX(1);
  opacity: 1;
}
.pp-row:hover .pp-category span {
  opacity: 1;
  transform: translateY(0);
}
.pp-side {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}
.pp-image-overlay {
  width: 37%;
  aspect-ratio: 1/1;
  margin: 0 auto;
  position: relative;
}
.pp-img-clip {
  width: 100%;
  height: 100%;
  border-radius: 12px;
  overflow: hidden;
}
.pp-img-clip img {
  transition: transform 0.5s ease;
}
.pp-row:hover .pp-img-clip img {
  transform: scale(1.12);
}
.pp-image-overlay .label {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  white-space: nowrap;
  font-family: var(--display);
  font-size: 48px;
  font-weight: 600;
  z-index: 3;
  /* Iba en difference contra el fondo oscuro. Sobre la tarjeta clara ese modo
     devolvia un gris lavado, asi que va color plano. */
  color: var(--fg);
  letter-spacing: 0.12em;
}

/* ============================================
   FOOTER GALLERY CAROUSEL
   ============================================ */
.gallery-carousel {
  display: flex;
  overflow: hidden;
  gap: 16px;
  padding: 60px 0;
}
.gallery-carousel-track {
  display: flex;
  gap: 16px;
  animation: marquee 50s linear infinite;
  flex-shrink: 0;
  padding-right: 16px;
}
.gallery-carousel-track > div {
  width: 140px;
  aspect-ratio: 4/5;
  flex-shrink: 0;
  border-radius: 8px;
  overflow: hidden;
}

/* the whole strip is the door into the gallery */
.gallery-carousel-link {
  display: block; text-decoration: none; color: inherit;
  position: relative;
}
.gallery-carousel-link .gallery-carousel-track > div { transition: opacity 0.4s ease, filter 0.4s ease; }
/* Al pasar por encima la tira se aquieta y se apaga, y queda el boton */
.gallery-carousel-link:hover .gallery-carousel-track > div { opacity: 0.38; }
.gallery-carousel-link:hover .gallery-carousel-track { animation-play-state: paused; }

/* El boton no vive abajo de la tira sino ENCIMA, en el centro: la tira entera
   es el enlace, asi que el boton tiene que aparecer donde esta el cursor, no
   en una esquina. */
.gallery-ver {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%) scale(0.96);
  z-index: 2;
  padding: 13px 30px;
  border-radius: 999px;
  background: var(--fg);
  color: var(--bg);
  font-size: 12px; font-weight: 500;
  letter-spacing: 0.1em; text-transform: uppercase;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 300ms var(--ease), transform 300ms var(--ease);
}
.gallery-carousel-link:hover .gallery-ver,
.gallery-carousel-link:focus-visible .gallery-ver {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}
/* Sin hover no hay forma de descubrirlo: en tactil va siempre puesto, y la
   tira no se apaga porque nada la esta "senalando". */
@media (hover: none) {
  .gallery-ver { opacity: 1; transform: translate(-50%, -50%); }
  .gallery-carousel-link:hover .gallery-carousel-track > div { opacity: 1; }
}

/* quiet, persistent CTA under the strip */
.gallery-cta {
  display: flex; justify-content: flex-end;
  padding: 0 var(--pad-x);
  margin-top: -34px;
}
.gallery-cta a {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--display); font-size: 11px; font-weight: 500;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--fg-dim); text-decoration: none;
  padding-bottom: 5px; border-bottom: 1px solid var(--line);
  transition: color 0.3s ease, border-color 0.3s ease;
}
.gallery-cta a:hover { color: var(--accent); border-color: var(--accent); }
.gallery-cta a .gt-arrow { transition: transform 0.3s ease; }
.gallery-cta a:hover .gt-arrow { transform: translate(3px, -3px); }

/* ============================================
   GALLERY SIDE TAB — vertical signage on the right edge
   ============================================ */
.gallery-tab {
  position: fixed;
  right: 0; top: 50%;
  transform: translate(100%, -50%);
  z-index: 9994;
  /* column-reverse → dot sits at the bottom, then GALLERY, arrow on top */
  display: flex; flex-direction: column-reverse; align-items: center; gap: 11px;
  padding: 20px 12px;
  font-family: var(--display);
  font-size: 11px; font-weight: 500;
  text-transform: uppercase;
  /* light frosted panel + dark type: pops against the dark page,
     and reads better than cream-on-wine did */
  color: var(--fg);
  text-decoration: none;
  background: var(--glass-bg);
  backdrop-filter: blur(20px) saturate(1.3); -webkit-backdrop-filter: blur(20px) saturate(1.3);
  border: 1px solid var(--glass-border); border-right: 0;
  border-radius: 10px 0 0 10px;
  opacity: 0; pointer-events: none;
  transition: transform 0.6s cubic-bezier(0.22,1,0.36,1),
              opacity 0.5s ease, background 0.35s ease,
              color 0.35s ease, border-color 0.35s ease;
}
.gallery-tab.is-visible { transform: translate(0, -50%); opacity: 1; pointer-events: auto; }
/* rotated so the word reads bottom-to-top (left-to-right with your head tilted) */
.gallery-tab .gt-text {
  writing-mode: vertical-rl; text-orientation: mixed;
  transform: rotate(180deg);
  letter-spacing: 0.18em;
}
.gallery-tab .gt-dot {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--accent);
  animation: gtPulse 2.8s ease-in-out infinite;
}
.gallery-tab .gt-arrow { font-size: 12px; line-height: 1; }
.gallery-tab:hover {
  background: var(--accent); color: #fff; border-color: var(--accent);
}
.gallery-tab:hover .gt-dot { background: #fff; animation: none; }
@keyframes gtPulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.35; transform: scale(0.82); }
}
@media (prefers-reduced-motion: reduce) {
  .gallery-tab .gt-dot { animation: none; }
}
@media (max-width: 768px) {
  .gallery-tab { padding: 14px 9px; font-size: 10px; gap: 9px; }
  .gallery-cta { margin-top: -20px; }
}

.thank-you {
  text-align: center;
  padding: 60px 0 40px;
  font-size: 13px;
}

.footer {
  padding: 30px var(--pad-x) 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px;
  font-size: 13px;
  border-top: 1px solid var(--line);
}
.footer .label {
  font-weight: 600;
  margin-bottom: 6px;
  font-size: 12px;
}
.footer .right { text-align: right; }
.footer a:hover { color: var(--accent); }

.copyright {
  font-family: var(--display);
  font-size: clamp(76px, 17vw, 288px);
  font-weight: 600;
  line-height: 0.85;
  letter-spacing: -0.05em;
  text-align: center;
  padding: 30px var(--pad-x) 30px;
  overflow: hidden;
}

/* ============================================
   INTRO ANIMATION
   ============================================ */
body.loading { overflow: hidden; height: 100vh; }

.intro-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.intro-bg {
  position: absolute;
  inset: 0;
  background: var(--bg);
  z-index: 1;
}
body.loaded .intro-bg {
  animation: intro-bg-fade 0.6s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
@keyframes intro-bg-fade {
  to { opacity: 0; }
}

.intro-name-wrap {
  position: relative;
  z-index: 2;
  display: inline-block;
  transform-origin: center center;
  will-change: transform;
  opacity: 0;
  animation: intro-name-in 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.4s forwards;
}
@keyframes intro-name-in {
  to { opacity: 1; }
}

.intro-name {
  font-family: var(--display);
  font-size: clamp(28px, 5vw, 64px);
  font-weight: 600;
  letter-spacing: -0.04em;
  line-height: 0.9;
  display: block;
  white-space: nowrap;
}
.intro-name-base {
  color: var(--fg-ghost);
}
.intro-name-reveal {
  position: absolute;
  inset: 0;
  color: var(--fg);
  clip-path: inset(0 100% 0 0);
  animation: intro-reveal 0.55s cubic-bezier(0.76, 0, 0.24, 1) 2.5s forwards;
}

@keyframes intro-reveal {
  to { clip-path: inset(0 0 0 0); }
}

/* Initial states for hero elements (hidden during intro) */
.nav {
  opacity: 0;
  transform: translateY(-100%);
}
.hero-headline {
  opacity: 0;
  transform: translateY(40px);
}
.hero-image {
  opacity: 0;
  transform: scale(0.92);
}
.hero-band {
  transform: scaleX(0);
}
.hero-name {
  opacity: 0;
}

/* When body.loaded (triggered when morph starts), each element enters with its own timing & character */
body.loaded .nav {
  animation: nav-down 0.8s cubic-bezier(0.22, 1, 0.36, 1) 0.3s forwards;
}
body.loaded .hero-image {
  animation: hero-image-in 0.8s cubic-bezier(0.22, 1, 0.36, 1) 0.15s forwards;
}
body.loaded .hero-headline {
  animation: fade-up 0.85s cubic-bezier(0.22, 1, 0.36, 1) 0.5s forwards;
}
body.loaded .hero-band {
  animation: scale-x 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.85s forwards;
}
/* Hero name appears only when the morph finishes */
body.morph-done .hero-name {
  opacity: 1;
  transition: opacity 0.15s;
}

@keyframes nav-down {
  to { opacity: 1; transform: translateY(0); }
}
@keyframes fade-up {
  to { opacity: 1; transform: translateY(0); }
}
@keyframes hero-image-in {
  to { opacity: 1; transform: scale(1); }
}
@keyframes scale-x {
  to { transform: scaleX(1); }
}

/* ============================================
   MOBILE
   ============================================ */
@media (max-width: 900px) {
  /* El desborde horizontal ya lo corta el `overflow-x: hidden` del body (arriba
     de todo), que se propaga al viewport mientras html quede en `visible`.
     Ponerlo TAMBIEN en html rompia esa propagacion, y ahi empezaba el problema:
     con html fuera de `visible` el body deja de propagar y pasa a ser un
     contenedor de scroll de verdad. Safari en iPhone entonces no ancla al
     viewport los `position: fixed` que cuelgan del body — que son justo los dos
     esfumados, `body::before` y `body::after`. Se corrian con la pagina y el
     contenido se veia pasar por arriba del menu y por abajo del pie.
     Encaja con todo lo observado: solo en telefono, porque la regla vivia en
     este @media; solo en Safari, porque Chrome ancla al viewport igual; y no en
     Overview, porque `.ov-lock` bloquea el scroll y ahi no hay nada que correr.
     Sacarlo de html no reintroduce scroll horizontal: esta medido, el marquee
     lo corta su propio `overflow: hidden`.
     `overflow-x: clip` seria lo que indica la spec para clipear sin crear
     contenedor de scroll, pero Safari todavia clipea tambien el eje Y con ese
     valor y cortaria la pagina entera. */
  html, body { max-width: 100%; }
  .hero-marquee { min-width: 0; max-width: 100%; }
  .nav { grid-template-columns: 1fr 1fr; gap: 8px; font-size: 11px; }
  .nav-meta { display: none; }
  .nav-networks { display: none; }
  .section-label { grid-template-columns: 1fr auto; gap: 4px 16px; }
  .section-label > span:nth-child(2) { text-align: right; }
  .section-label > span:nth-child(3) { grid-column: 1 / -1; text-align: left; font-size: 10px; opacity: 0.7; line-height: 1.5; }
  /* Los saltos fijos no entran en mobile: el texto fluye solo */
  .hero-title { font-size: clamp(22px, 6vw, 30px); }
  .hero-sub { font-size: clamp(15px, 3.9vw, 19px); margin-top: 14px; }
  .hero-title br, .hero-sub br { display: none; }
  .hero { padding: 100px var(--pad-x) 24px; }
  /* El reel vuelve al flujo y en 16/9 (sin letterbox), y la banda sin margin-top:auto */
  .hero-top { min-height: 0; }
  .hero-image { position: relative; top: auto; right: auto; justify-self: start; width: 100%; height: auto; aspect-ratio: 16 / 9; margin-top: 8px; }
  .hero-band { margin: 12px 0; }
  .hero-name { margin-top: 8px; margin-bottom: 72px; }
  .hero-marquee { margin-top: 44px !important; margin-bottom: 8px !important; }
  .selected-intro { grid-template-columns: 1fr; }
  .projects-grid { grid-template-columns: 1fr; gap: 72px; }
  .project-card:nth-child(1),
  .project-card:nth-child(2),
  .project-card:nth-child(3),
  .project-card:nth-child(4),
  .project-card:nth-child(5) { max-width: 100%; width: 100%; margin: 0; }
  .skill-row { grid-template-columns: 50px 1fr; gap: 20px; }
  .skill-desc { grid-column: 1 / -1; }
  .work-header { grid-template-columns: 1fr; }
  .work-row { grid-template-columns: 1fr; gap: 4px; }
  .work-row .location { text-align: left; }
  .comp-row { grid-template-columns: 1fr; gap: 12px; }
  .comp-imgs { grid-template-columns: repeat(4, 1fr); }
  .clients-section { height: auto; padding: 60px var(--pad-x); margin-bottom: 60px; }
  .video-spiral { position: static; height: auto; perspective: none; display: flex; flex-direction: column; gap: 16px; }
  .video-spiral > div { position: relative; top: auto; left: auto; width: 100% !important; aspect-ratio: 16/9 !important; transform: none !important; margin: 0; }
  .pp-row { grid-template-columns: 1fr; gap: 24px; }

  /* Personal profile: statement first, then media composition (imgs + video + small text) */
  .personal-profile { display: flex; flex-direction: column; padding: 80px var(--pad-x) 120px; min-height: auto; overflow: visible; }
  .personal-text { order: 1; max-width: 100%; margin-left: 0; padding-top: 0; font-size: clamp(17px, 4.5vw, 23px); }
  .floating-imgs { order: 2; display: grid; grid-template-columns: 1fr 1fr; gap: 14px; position: static; inset: auto; margin-top: 40px; pointer-events: auto; }
  .floating-imgs > div { position: static !important; top: auto !important; left: auto !important; right: auto !important; width: auto !important; min-width: 0 !important; transform: none !important; border-radius: 12px; }
  .floating-imgs .f1, .floating-imgs .f2 { aspect-ratio: 3/4; }
  .floating-imgs .f3 { grid-column: 1 / -1; aspect-ratio: 16/9; }
  .floating-imgs .f4 { grid-column: 1 / -1; font-size: 0.95rem; line-height: 1.55; color: var(--fg-dim); padding-top: 8px; }

  /* Big titles: scale down for mobile */
  .big-title { font-size: clamp(24px, 7.5vw, 46px); padding: 40px var(--pad-x) 20px; }

  /* Personal projects stacking: disable sticky, normal flow */
  .pp-row { position: relative !important; top: auto !important; margin-bottom: 72px !important; }
  .pp-row:last-child { margin-bottom: 0 !important; }
  .pp-grid { padding-bottom: 64px; }

  /* Footer */
  .footer { grid-template-columns: 1fr 1fr; gap: 20px; padding: 20px var(--pad-x) 0; }
  .copyright { font-size: clamp(32px, 12vw, 76px); padding: 20px var(--pad-x); }

  /* Homie quote: allow wrap on mobile */
  .cs-quote[style*="white-space"] { white-space: normal !important; }
}

/* ============================================
   CASE STUDY MODAL
   ============================================ */
.cs-overlay {
  position: fixed; inset: 0; z-index: 10000;
  background: rgba(20, 20, 20, 0.28);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  opacity: 0; pointer-events: none;
  transition: opacity 0.4s ease;
}
.cs-overlay.open { opacity: 1; pointer-events: auto; }

.cs-modal {
  position: fixed; top: 60px; left: 0; right: 0; bottom: 0;
  z-index: 10001;
  background: var(--bg);
  border-radius: 16px 16px 0 0;
  overflow-y: auto; overflow-x: hidden;
  transform: translateY(100%);
  transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1),
              opacity 0.3s ease;
}
.cs-overlay.open .cs-modal { transform: translateY(0); }

.cs-dismiss-zone {
  height: 110vh;
  display: flex; align-items: center; justify-content: center;
  color: rgba(128,128,128,0.3); font-size: 0.8rem;
  letter-spacing: 0.1em; text-transform: uppercase;
  padding-bottom: 40px;
}

.cs-header {
  position: sticky; top: 0; z-index: 10;
  display: flex; justify-content: space-between; align-items: center;
  padding: 20px 40px;
  background: var(--glass-bg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
  font-family: var(--ff);
}
.cs-header .cs-close,
.cs-header .cs-back { cursor: pointer; font-size: 0.85rem; letter-spacing: 0.05em; text-transform: uppercase; background: none; border: none; color: var(--fg); font-family: var(--ff); }
.cs-header .cs-title { font-size: 0.85rem; letter-spacing: 0.05em; text-transform: uppercase; }

/* 1 — Info: título + metadatos */
.cs-intro {
  padding: 80px 40px 60px;
  display: grid; grid-template-columns: 1.4fr 1fr; gap: 60px;
  align-items: start;
}
.cs-intro h2 {
  font-family: var(--ff); font-size: clamp(1.5rem, 3vw, 2.6rem);
  font-weight: 400; line-height: 1.1; margin: 0;
}
.cs-meta-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 20px 40px;
  font-size: 0.85rem; padding-top: 8px;
}
.cs-meta-grid dt { color: rgba(128,128,128,0.7); margin-bottom: 4px; text-transform: uppercase; letter-spacing: 0.05em; font-size: 0.7rem; }
.cs-meta-grid dd { margin: 0 0 12px; }

/* 2 — Imagen grande full width */
.cs-hero-img {
  width: 100%; aspect-ratio: 16/9; overflow: hidden;
  margin-bottom: 80px;
}
.cs-hero-img img { width: 100%; height: 100%; object-fit: cover; display: block; }

.cs-body { padding: 0 40px 80px; }

/* 3 — Descripción: statement grande izq + texto chico 2 cols der */
.cs-desc {
  display: grid; grid-template-columns: 1fr 1fr; gap: 60px;
  align-items: start; margin-bottom: 80px;
}
.cs-desc-statement {
  font-family: var(--ff); font-size: clamp(1.05rem, 2vw, 1.5rem);
  font-weight: 400; line-height: 1.35; margin: 0;
  text-wrap: balance; /* reparte los renglones para que el ultimo no quede corto */
}
.cs-desc-statement + .cs-desc-statement { margin-top: 0.9em; }
.cs-desc-detail {
  display: grid; grid-template-columns: 1fr 1fr; gap: 24px;
  font-size: 0.95rem; line-height: 1.75; color: var(--fg-dim);
}
.cs-desc-detail p { margin: 0 0 1.5em; }
.cs-desc-detail p:has(strong) { margin-top: 2.2em; margin-bottom: 0.5em; }
.cs-desc-detail > div > p:first-child { margin-top: 0; }
.cs-desc-detail strong { color: var(--fg); }

/* 4 — Full image/video */
.cs-full-media { width: 100%; margin-bottom: 80px; }
.cs-full-media img,
.cs-full-media video,
.cs-full-media iframe { width: 100%; display: block; border-radius: 8px; aspect-ratio: 16/9; object-fit: cover; }
.cs-full-strip img { aspect-ratio: auto; object-fit: contain; height: auto; }

/* Que el video entre entero en pantalla.
   A 16/9 y ancho completo, en un monitor ancho el alto se pasa del alto del
   modal: quedaba el video cortado abajo y los controles fuera de cuadro. En
   vez de topar el alto —que con object-fit: cover recortaria la imagen— se
   topa el ANCHO en el que hace que el alto 16/9 quepa. La proporcion se
   respeta, el video se achica un poco y queda centrado.

   El aire que se descuenta: 60px que el modal deja arriba, mas la barra de
   CLOSE, mas un respiro para que no quede pegado al borde. */
.cs-full-media video,
.cs-full-media iframe {
  --cs-aire: 190px;
  /* Primero en vh, para navegadores sin svh. */
  width: min(100%, calc((100vh - var(--cs-aire)) * 16 / 9));
  /* svh usa el viewport con la barra del navegador desplegada: en telefono
     evita que el tope cambie de tamano mientras se scrollea. */
  width: min(100%, calc((100svh - var(--cs-aire)) * 16 / 9));
  margin-left: auto;
  margin-right: auto;
}

/* 5 — Proceso: texto izq + galería scroll der */
.cs-process {
  display: grid; grid-template-columns: 520px 1fr; gap: 80px;
  align-items: start; margin-bottom: 80px;
  margin-right: -15px;
}
.cs-process-text {
  position: sticky; top: 80px;
  font-size: 0.85rem; line-height: 1.75; color: var(--fg-dim);
  column-count: 2; column-gap: 40px;
}
.cs-process-text h3 {
  font-family: var(--ff); font-size: clamp(1rem, 1.5vw, 1.3rem);
  font-weight: 400; margin: 0 0 24px; color: var(--fg);
  column-span: all;
}
.cs-process-text p { margin: 0 0 1.5em; }
/* fuerza el arranque de la segunda columna en este parrafo, sin partirlo al medio */
.cs-process-text p.cs-col-break { break-before: column; }
.cs-process-single { grid-template-columns: 1fr; gap: 0; }
.cs-process-single .cs-process-text { position: static; column-count: 1; max-width: 720px; }
.cs-process-cols .cs-process-text { column-count: 2; column-gap: 48px; max-width: 900px; }
.cs-process-gallery {
  display: flex; flex-direction: column; gap: 16px;
  width: 1037px; max-width: 100%; margin-left: auto;
}
.cs-process-gallery .cs-placeholder,
.cs-process-gallery > img,
.cs-process-gallery > video { width: 100%; border-radius: 8px; display: block; }
.cs-process-gallery > img,
.cs-process-gallery > video { object-fit: cover; }

/* Asset 1 — scattered floating cards */
.cs-scatter {
  position: relative; width: 100%; height: 660px;
}
.cs-scatter-card {
  position: absolute; cursor: pointer;
  animation: scatterFloat var(--dur, 7s) ease-in-out infinite;
  animation-delay: var(--delay, 0s);
  will-change: transform;
}
.cs-scatter-card img {
  width: 100%; display: block; border-radius: 8px; object-fit: cover;
  box-shadow: 0 8px 26px rgba(20,20,20,0.08);
  transform: rotate(var(--rot, 0deg));
  transition: transform 0.45s cubic-bezier(0.16,1,0.3,1), box-shadow 0.45s ease;
}
.cs-scatter-card:hover { z-index: 50; }
.cs-scatter-card:hover img {
  transform: rotate(0deg) scale(1.16);
  box-shadow: 0 16px 44px rgba(20,20,20,0.14);
}
@keyframes scatterFloat {
  0%, 100% { transform: translate(0, 0); }
  50%      { transform: translate(5px, -16px); }
}

/* Asset 10 — diagonal stacked deck */
.cs-stack {
  position: relative; width: 100%; height: 660px;
}
.cs-stack-card {
  position: absolute; cursor: pointer;
  animation: stackFloat var(--dur, 8s) ease-in-out infinite;
  animation-delay: var(--delay, 0s);
  will-change: transform;
}
.cs-stack-card img {
  width: 100%; display: block; border-radius: 8px; object-fit: cover;
  box-shadow: 0 8px 24px rgba(20,20,20,0.08);
  transform: rotate(var(--rot, 0deg));
  transition: transform 0.5s cubic-bezier(0.16,1,0.3,1), box-shadow 0.5s ease;
}
.cs-stack-card:hover { z-index: 99; }
.cs-stack-card:hover img {
  transform: translateY(-55px) scale(1.06) rotate(0deg);
  box-shadow: 0 20px 50px rgba(20,20,20,0.14);
}
@keyframes stackFloat {
  0%, 100% { transform: translate(0, 0); }
  50%      { transform: translate(4px, -12px); }
}

/* Character design — interactive floating area (full-bleed dentro del modal) */
.cs-char {
  position: relative;
  margin: 0 -40px 80px;
  padding: 60px 40px 70px;
}
.cs-char .cs-scatter { height: 1198px; }
/* el titulo vive arriba a la derecha; el layout del scatter le reserva ese hueco */
.cs-char-label {
  position: absolute; top: 0; right: 40px; width: 760px; z-index: 40;
}
/* texto en dos columnas angostas; el titulo cruza las dos */
.cs-char-label > div { column-count: 2; column-gap: 44px; }
.cs-char-label h3 {
  font-family: var(--ff); font-size: clamp(1.1rem, 2vw, 1.6rem);
  font-weight: 400; margin: 0 0 20px; color: var(--fg);
  column-span: all;
}
.cs-char-label p {
  margin: 0 0 1.4em;
  font-size: 0.85rem; line-height: 1.75; color: var(--fg-dim);
}
.cs-char-label p:last-child { margin-bottom: 0; }

/* Video + texto: el video ocupa más ancho, el texto respira */
.cs-media-split {
  display: grid; grid-template-columns: 1.75fr 1fr;
  gap: 80px; align-items: center; margin-bottom: 80px;
}
.cs-media-split-reverse { grid-template-columns: 1fr 1.75fr; }
.cs-media-split video,
.cs-media-split iframe {
  width: 100%; display: block; border-radius: 8px;
  aspect-ratio: 16/9; object-fit: cover; border: 0;
}
.cs-media-split-text {
  padding: 40px 20px;
  font-size: 0.9rem; line-height: 1.75; color: var(--fg-dim);
}
.cs-media-split-text h4 {
  font-family: var(--ff); font-size: clamp(1rem, 1.5vw, 1.3rem);
  font-weight: 400; margin: 0 0 16px; color: var(--fg);
}
.cs-media-split-text p { margin: 0 0 1.3em; }
.cs-media-split-text p:last-child { margin-bottom: 0; }

@media (max-width: 900px) {
  .cs-media-split,
  .cs-media-split-reverse { grid-template-columns: 1fr; gap: 24px; }
  .cs-media-split-reverse .cs-media-split-text { order: 2; }
  .cs-media-split-text { padding: 0; }
}
@media (max-width: 768px) {
  .cs-char { margin: 0 -20px 40px; padding: 30px 20px 40px; }
  .cs-char .cs-scatter { height: auto; }
  .cs-char-label { position: static; width: auto; margin-bottom: 20px; }
  .cs-char-label > div { column-count: 1; }
}

/* Image lightbox (scatter / ring) */
.cs-img-lightbox {
  position: fixed; inset: 0; z-index: 10020;
  background: rgba(0,0,0,0.92);
  display: flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none; transition: opacity 0.35s ease;
  padding: 5vh 5vw;
}
.cs-img-lightbox.open { opacity: 1; pointer-events: auto; }
.cs-img-lightbox img {
  max-width: 100%; max-height: 100%;
  object-fit: contain; border-radius: 8px;
  box-shadow: 0 20px 56px rgba(20,20,20,0.14);
}
.cs-img-lightbox .cs-img-close {
  position: absolute; top: 28px; right: 36px;
  background: none; border: none; color: #fff;
  font-size: 2rem; cursor: pointer; line-height: 1;
}

/* Drag gallery — scattered image cloud, click-drag to explore, focal scaling */
.cs-drag-gallery {
  position: relative; margin: 90px -40px 0;
  height: 900px; overflow: hidden;
  background: #F2F0EB; /* un paso mas oscuro que el fondo, para separar la galeria */
  cursor: grab;
  -webkit-user-select: none; user-select: none;
}
.cs-drag-gallery.is-dragging { cursor: grabbing; }
.cs-drag-hint {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  display: flex; align-items: center; gap: 10px;
  padding: 13px 24px;
  background: var(--glass-bg);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--fg);
  font-size: 0.82rem; letter-spacing: 0.08em;
  text-transform: uppercase; white-space: nowrap;
  pointer-events: none; z-index: 40;
  box-shadow: 0 4px 20px rgba(20,20,20,0.08);
  transition: opacity 0.5s ease;
  animation: csDragPulse 1.9s ease-in-out infinite;
}
.cs-drag-hint .cs-drag-ico {
  display: inline-block; font-size: 1.05rem;
  animation: csDragNudge 1.9s ease-in-out infinite;
}
@keyframes csDragPulse {
  0%, 100% { transform: translate(-50%, -50%) scale(1); }
  50%      { transform: translate(-50%, -50%) scale(1.05); }
}
@keyframes csDragNudge {
  0%, 100% { transform: translateX(-3px); }
  50%      { transform: translateX(3px); }
}
.cs-drag-gallery.has-dragged .cs-drag-hint { opacity: 0; }
.cs-drag-hint .cs-hint-m { display: none; }
.cs-drag-inner {
  position: absolute;
  width: 3200px; height: 2200px;
  will-change: transform;
}
.cs-drag-item {
  position: absolute;
  border-radius: 10px; overflow: hidden;
  will-change: transform;
  cursor: pointer;
  box-shadow: 0 3px 16px rgba(20,20,20,0.07);
}
.cs-drag-item img {
  width: 100%; display: block;
  pointer-events: none;
}

.cs-bm-full { margin: 0 -40px; }
.cs-bm-full img { width: 100%; display: block; }

@media (max-width: 768px) {
  /* Mobile: horizontal swipe carousel (single row, native scroll-snap) */
  .cs-drag-gallery {
    margin: 0 -20px; height: auto;
    overflow-x: auto; overflow-y: hidden;
    cursor: auto; background: #F2F0EB;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    touch-action: pan-x;
    position: relative;
  }
  .cs-drag-inner {
    position: relative !important;
    width: max-content !important; height: auto !important;
    transform: none !important;
    display: flex; flex-wrap: nowrap; gap: 12px;
    padding: 24px 20px;
  }
  .cs-drag-item {
    position: static !important;
    flex: 0 0 auto;
    width: 74vw !important; max-width: 300px;
    transform: none !important;
    scroll-snap-align: center;
  }
  .cs-drag-item img { border-radius: 10px; }
  .cs-drag-hint { display: flex; }
  .cs-drag-hint .cs-hint-d { display: none; }
  .cs-drag-hint .cs-hint-m { display: inline; }
}

/* Duo — asset 3 left / asset 4 right, same height */
.cs-duo {
  margin: 0 -40px; display: grid;
  grid-template-columns: 1fr 1fr; gap: 4px;
}
.cs-duo img,
.cs-duo video {
  width: 100%; height: 560px; object-fit: cover; display: block; border-radius: 0;
}

@media (max-width: 768px) {
  .cs-scatter, .cs-stack {
    height: auto; display: flex; flex-direction: column; gap: 12px;
  }
  .cs-scatter-card, .cs-stack-card {
    position: static !important; width: 100% !important;
    margin: 0 !important; transform: none !important;
    animation: none !important;
  }
  .cs-scatter-card img, .cs-stack-card img { transform: none !important; }
  .cs-duo { margin: 0 -20px; grid-template-columns: 1fr; }
  .cs-duo img, .cs-duo video { height: 320px; }
}

/* 6 — Frase highlight */
.cs-quote {
  padding: 80px 40px;
  font-family: var(--ff); font-size: clamp(1.15rem, 2.4vw, 2rem);
  font-weight: 400; line-height: 1.25; text-align: center;
  max-width: 900px; margin: 0 auto;
}
/* closing phrase — 3 controlled lines, pushed lower */
.cs-quote.cs-quote-oneline {
  max-width: none;
  font-size: clamp(0.95rem, 1.8vw, 1.4rem);
  line-height: 1.4;
  padding: 120px 40px 96px;
}

/* Placeholder genérico */
.cs-placeholder {
  background: rgba(128,128,128,0.08); border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  color: rgba(128,128,128,0.4); font-size: 0.85rem;
  text-transform: uppercase; letter-spacing: 0.1em;
}
.cs-placeholder.tall { width: 100%; aspect-ratio: 16/9; }
.cs-placeholder.square { aspect-ratio: 1/1; }
.cs-placeholder.portrait { aspect-ratio: 3/4; }

@media (max-width: 768px) {
  .cs-modal { top: 0; border-radius: 0; }
  .cs-header { padding: 16px 20px; }
  .cs-intro { grid-template-columns: 1fr; padding: 40px 20px 30px; gap: 30px; }
  .cs-body { padding: 0 20px 40px; overflow-x: hidden; }
  .cs-desc { grid-template-columns: 1fr; gap: 30px; }
  .cs-desc-detail { grid-template-columns: 1fr; }
  .cs-process { grid-template-columns: 1fr; margin-right: 0; gap: 30px; }
  .cs-process-text { position: static; column-count: 1; }
  .cs-process-gallery { width: 100%; }
  .cs-quote { padding: 40px 20px; white-space: normal !important; max-width: 100%; }
  .cs-full-media { margin-bottom: 40px; }
  .cs-bm-full { margin: 0 -20px; }
  .cs-float { height: auto; padding: 40px 20px; }
  .cs-float img { position: static !important; width: 30% !important; }
}

/* ============================================
   DISTORTION — case study (editorial + glass lens)
   ============================================ */
/* title + subtitle — opens the case study, with air above from the modal top */
.dst-title { padding: 120px 40px 0; margin-bottom: 200px; }
.dst-title h2 {
  font-family: var(--ff); font-weight: 400;
  font-size: clamp(2.6rem, 9vw, 7rem); line-height: 0.92;
  letter-spacing: -0.015em; margin: 0 0 18px;
}
.dst-title .dst-sub {
  font-size: 0.78rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--fg-dim);
}

/* Act 1 — opening statement: left-aligned to match the direction column, more air */
.dst-act1 { max-width: 920px; margin: 175px auto 210px; padding: 0 40px; }
.dst-act1 p {
  font-family: var(--ff); font-weight: 400; max-width: 620px;
  font-size: clamp(1.1rem, 2vw, 1.5rem); line-height: 1.4;
  margin: 0; text-align: left;
}

/* Act 2 — the direction: titled two-column editorial prose */
.dst-direction { max-width: 920px; margin: 0 auto 330px; padding: 0 40px; }
.dst-direction h3 {
  font-family: var(--ff); font-weight: 400;
  font-size: clamp(1.1rem, 2vw, 1.65rem); margin: 0 0 34px; color: var(--fg);
}
.dst-direction .dst-cols { column-count: 2; column-gap: 60px; }
.dst-direction p {
  font-size: 0.95rem; line-height: 1.85; color: var(--fg-dim);
  margin: 0 0 1.5em; break-inside: avoid;
}
.dst-direction p:last-child { margin-bottom: 0; }

/* Series — small images, staggered, lots of air and play across the space */
.dst-series { padding: 0 clamp(24px, 6vw, 96px); margin-bottom: 40px; }
.dst-fig { margin: 0; }
.dst-series img { width: 100%; height: auto; display: block; border-radius: 4px; }

/* centered group shots — small, lots of breathing room above and below */
.dst-solo { max-width: 26%; margin: 0 auto clamp(200px, 35vh, 500px); }
/* the closing group sits well right of centre, and larger */
.dst-solo--right { max-width: 36%; margin-left: auto; margin-right: clamp(90px, 15vw, 340px); }

/* staggered pairs — small images, pulled in from the edges, offset vertically */
.dst-pair {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(75px, 11vw, 240px); align-items: start;
  margin: 0 auto clamp(200px, 35vh, 500px);
}
.dst-pair .dst-fig { max-width: 48%; }
.dst-pair .dst-fig:nth-child(odd)  { justify-self: start; }
.dst-pair .dst-fig:nth-child(even) { justify-self: end; }
/* pair A (A·B): A a touch off the left edge, B pulled toward centre, big gap before C */
.dst-pair--a { margin-bottom: clamp(300px, 46vh, 660px); }
.dst-pair--a .dst-fig:nth-child(odd)  { max-width: 86%; margin-left: clamp(20px, 4vw, 90px); }
/* B drops far enough below the (now much larger) A to keep a full gap between them */
.dst-pair--a .dst-fig:nth-child(even) { max-width: 55%; margin-top: clamp(800px, 92vw, 1400px); margin-right: clamp(70px, 10vw, 220px); }
/* pair B (D·E): whole block much lower; D dropped + nudged right, E out toward the right */
.dst-pair--b { gap: clamp(115px, 15vw, 300px); margin-top: clamp(140px, 24vh, 340px); }
.dst-pair--b .dst-fig { max-width: 46%; }
.dst-pair--b .dst-fig:nth-child(odd)  { margin-top: clamp(240px, 40vh, 480px); margin-left: clamp(80px, 12vw, 260px); }
.dst-pair--b .dst-fig:nth-child(even) { margin-top: clamp(120px, 22vh, 300px); }

/* Closing */
.dst-closing { padding-top: 160px; }
.dst-coda {
  max-width: 640px; margin: 170px auto 0; padding: 0 40px; text-align: center;
  font-size: 0.95rem; line-height: 1.85; color: var(--fg-dim);
}
.dst-credits {
  max-width: 640px; margin: 200px auto 0; padding: 70px 40px 0;
  border-top: 1px solid var(--line);
  text-align: center; font-size: 0.74rem; line-height: 2;
  letter-spacing: 0.02em; color: var(--fg-dim);
}

/* Signature interaction — glass lens cursor (desktop / fine pointer only) */
.dst-lens {
  position: fixed; top: 0; left: 0;
  width: 190px; height: 190px; border-radius: 50%;
  pointer-events: none; z-index: 10005;
  opacity: 0; transition: opacity 0.2s ease;
  overflow: hidden; will-change: transform;
  box-shadow:
    inset 0 3px 12px rgba(255,255,255,0.35),
    inset 0 -8px 18px rgba(0,0,0,0.20),
    0 12px 34px rgba(0,0,0,0.30);
  -webkit-mask: radial-gradient(circle at 50% 50%, #000 60%, rgba(0,0,0,0.4) 82%, transparent 100%);
          mask: radial-gradient(circle at 50% 50%, #000 60%, rgba(0,0,0,0.4) 82%, transparent 100%);
}
.dst-lens.is-active { opacity: 1; }
/* an <img> (not a background) so the SVG refraction filter renders reliably */
.dst-lens-img {
  position: absolute; top: 0; left: 0;
  max-width: none; height: auto; display: block;
  /* OJO: el filter: url(#dst-refract) NO va aca. En una hoja externa el
     fragmento resuelve contra la URL de la hoja (styles.css#dst-refract),
     no contra el documento, asi que el filtro no se encontraria. Se aplica
     como estilo inline al crear el elemento en main.js. */
  will-change: left, top;
}
.dst-lens::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: radial-gradient(circle at 38% 30%, rgba(255,255,255,0.28), transparent 44%);
  pointer-events: none;
}
body.dst-lens-on img.dst-img { cursor: none; }

/* Distortion: fondo un tono mas calido y oscuro que el resto del sitio, tomado
   de los fondos de las fotos. Ya no redefine tokens: hereda los globales. */
.cs-modal--distortion {
  background: #DCD8D2;
}
.cs-modal--distortion .cs-header {
  background: rgba(220, 216, 210, 0.86);
  border-bottom-color: var(--line);
}
.cs-modal--distortion .dst-credits {
  border-top-color: var(--line);
  color: var(--fg-dim);
}
.cs-modal--distortion .cs-dismiss-zone { color: var(--fg-faint); }

@media (max-width: 768px) {
  .dst-title { padding: 72px 20px 0; margin-bottom: 130px; }
  .dst-act1 { padding: 0 20px; margin: 90px auto 150px; }
  .dst-act1 p { max-width: 100%; }
  .dst-direction { padding: 0 20px; margin-bottom: 180px; }
  .dst-direction .dst-cols { column-count: 1; }
  .dst-series { padding: 0 20px; }
  .dst-pair { grid-template-columns: 1fr; gap: 110px; margin-bottom: 150px; }
  .dst-pair--a, .dst-pair--b { margin-top: 0; margin-bottom: 150px; }
  .dst-pair .dst-fig { max-width: 64%; }
  .dst-pair--a .dst-fig:nth-child(odd),
  .dst-pair--a .dst-fig:nth-child(even),
  .dst-pair--b .dst-fig:nth-child(odd),
  .dst-pair--b .dst-fig:nth-child(even) { max-width: 64%; margin-top: 0; margin-left: 0; margin-right: 0; }
  .dst-solo { max-width: 64%; margin-bottom: 150px; }
  .dst-solo--right { max-width: 64%; margin-left: auto; margin-right: auto; }
  .dst-coda, .dst-credits { padding-left: 20px; padding-right: 20px; }
}

/* ============================================
   PP COMING SOON TOOLTIP
   ============================================ */
.pp-coming-soon {
  position: absolute; inset: 0; z-index: 5;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; transition: opacity 0.3s ease;
  pointer-events: none;
}
.pp-row:hover .pp-coming-soon { opacity: 1; }
.pp-coming-soon span {
  background: var(--fg); color: var(--bg);
  padding: 10px 28px; border-radius: 50px;
  font-size: 0.8rem; letter-spacing: 0.15em;
  text-transform: uppercase; font-family: var(--ff);
}

/* ============================================
   GRANO — unica capa de textura sobre el fondo.
   SVG inline (feTurbulence) en un data URI: pesa ~350 bytes, no es
   una imagen. Fijo, sin animacion y sin capturar clicks.
   ============================================ */
.grain-overlay {
  position: fixed;
  inset: 0;
  z-index: 9990;
  pointer-events: none;
  opacity: 0.018;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-size: 200px 200px;
}

html { background: var(--bg); }

/* Intro progress bar (sumado al loader existente) */
.intro-bar {
  position: relative;
  z-index: 2;
  margin-top: 28px;
  width: clamp(180px, 22vw, 320px);
  height: 1px;
  background: var(--line);
  overflow: hidden;
  opacity: 0;
  animation: intro-bar-in 0.6s cubic-bezier(0.22,1,0.36,1) 0.5s forwards;
}
@keyframes intro-bar-in {
  to { opacity: 1; }
}
.intro-progress {
  width: 0%;
  height: 100%;
  background: var(--fg);
  transition: width 0.18s linear;
}
.intro-loader-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
  z-index: 2;
}

/* ============================================
   CHROMAWISE — case study (light canvas, GPT-start-screen language)
   ============================================ */
.cw {
  /* scoped tokens — light neutral canvas, sober type */
  --cw-bg: #f2efe9;
  --cw-surface: #f8f6f1;
  --cw-ink: #1b1a18;
  --cw-muted: #6d6a63;
  --cw-line: rgba(27, 26, 24, 0.14);
  --cw-line-soft: rgba(27, 26, 24, 0.08);
  background: var(--cw-bg);
  color: var(--cw-ink);
  font-family: var(--body);
  /* break out of the dark modal padding to paint a full light canvas */
  margin: -1px 0 0;
  min-height: calc(100vh - 60px);
  /* own stacking context so the fixed colour field sits behind all content */
  position: relative;
  isolation: isolate;
}
.cw *::selection { background: rgba(27,26,24,0.12); }

/* Reactive colour field — soft gradient clouds across the WHOLE page, drifting
   and blooming where the pointer moves. Pinned to the modal viewport so it
   stays put while the content scrolls over it. */
.cw-bg {
  position: absolute; top: 0; left: 0;
  width: 100%; height: 100vh;
  z-index: 0; display: block;
  pointer-events: none;
  will-change: transform;
}
.cw > *:not(.cw-bg) { position: relative; z-index: 1; }

/* shared rhythm: one block per screen, generous silence */
.cw-sec {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 clamp(24px, 6vw, 96px);
}
.cw-eyebrow {
  font-family: var(--body);
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--cw-muted);
}
.cw-sectitle {
  font-family: var(--ff);
  font-weight: 400;
  font-size: clamp(0.78rem, 1.1vw, 0.9rem);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--cw-muted);
  margin: 0 0 clamp(28px, 4vw, 48px);
}

/* SECTION 1 — HERO */
.cw-hero {
  position: relative;
  min-height: calc(100vh - 60px);
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  text-align: center;
  padding: clamp(80px, 12vh, 160px) clamp(24px, 6vw, 96px);
}
.cw-hero .cw-eyebrow { margin-bottom: clamp(28px, 5vh, 56px); }
.cw-swatch {
  position: relative;
  width: clamp(120px, 16vw, 160px);
  aspect-ratio: 1;
  border-radius: 50%;
  margin: 0 auto clamp(24px, 4vh, 40px);
  box-shadow: 0 18px 50px -22px rgba(27,26,24,0.55);
  overflow: hidden;
  isolation: isolate;
  /* Static fallback (reduced-motion / no-canvas): a logo-like 3-colour blend. */
  background:
    radial-gradient(circle at 58% 24%, #e2793a 0%, rgba(226,121,58,0) 60%),
    radial-gradient(circle at 74% 62%, #cf3a24 0%, rgba(207,58,36,0) 58%),
    radial-gradient(circle at 30% 74%, #2f5ec2 0%, rgba(47,94,194,0) 62%),
    linear-gradient(150deg, #e2793a, #2f5ec2);
}
/* Living blend — 3–4 colour clouds sweep top→bottom and sink round the far
   side while new hues emerge behind them (rendered on canvas by JS). */
.cw-swatch-canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block; border-radius: 50%;
}
/* Volume: white highlight top-left, soft shadow bottom-right — sits above the
   colour so the disc reads as a lit sphere, like the logo. */
.cw-swatch-shade {
  position: absolute; inset: 0;
  border-radius: 50%;
  pointer-events: none;
  background:
    radial-gradient(circle at 32% 27%, rgba(255,255,255,0.55) 0%, rgba(255,255,255,0) 46%),
    radial-gradient(circle at 72% 80%, rgba(18,14,10,0.30) 0%, rgba(18,14,10,0) 56%);
}
.cw-h1 {
  font-family: var(--ff);
  font-weight: 400;
  font-size: clamp(2.6rem, 7vw, 5.2rem);
  line-height: 0.98;
  letter-spacing: -0.01em;
  margin: 0 0 clamp(18px, 3vh, 30px);
}
.cw-lead {
  font-family: var(--ff);
  font-weight: 400;
  font-size: clamp(1.25rem, 3vw, 2rem);
  line-height: 1.2;
  margin: 0 0 clamp(20px, 3vh, 30px);
}
.cw-subline {
  font-family: var(--body);
  font-size: clamp(0.98rem, 1.4vw, 1.1rem);
  line-height: 1.6;
  color: var(--cw-muted);
  max-width: 560px;
  margin: 0 auto clamp(28px, 4vh, 44px);
  text-wrap: balance;
}
.cw-roles {
  font-family: var(--body);
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  color: var(--cw-muted);
}

/* SECTION 2 — THE DIRECTION */
.cw-direction { padding: clamp(80px, 14vh, 180px) 0; }
.cw-direction .cw-sec { max-width: 720px; }
.cw-prose p {
  font-family: var(--body);
  font-size: clamp(1.02rem, 1.5vw, 1.22rem);
  line-height: 1.7;
  margin: 0 0 1.5em;
  color: var(--cw-ink);
  text-wrap: pretty;
}
.cw-prose p:last-child { margin-bottom: 0; }
.cw-prose p.cw-consequence { color: var(--cw-muted); }

/* SECTION 3 — THE SYSTEM */
.cw-system { padding: clamp(60px, 10vh, 140px) 0; }
.cw-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(18px, 2vw, 28px);
}
.cw-card {
  border: 1px solid var(--cw-line);
  border-radius: 16px;
  background: var(--cw-surface);
  padding: clamp(26px, 3vw, 40px);
  display: flex; flex-direction: column;
}
.cw-card h4 {
  font-family: var(--ff);
  font-weight: 400;
  font-size: clamp(1.15rem, 1.8vw, 1.5rem);
  line-height: 1.15;
  margin: 0 0 14px;
}
.cw-card p {
  font-family: var(--body);
  font-size: 0.96rem;
  line-height: 1.65;
  color: var(--cw-muted);
  margin: 0;
}
/* Card 2 — semantic token list micro-animation */
.cw-tokens {
  margin-top: 26px;
  display: flex; flex-direction: column;
  gap: 12px;
}
.cw-token {
  display: flex; align-items: center; gap: 14px;
  opacity: 0; transform: translateY(8px);
  transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
.cw-token.is-in { opacity: 1; transform: translateY(0); }
.cw-token-chip {
  width: 26px; height: 26px; border-radius: 7px;
  border: 1px solid var(--cw-line-soft);
  flex: none;
}
.cw-token-name {
  font-family: 'Inter', monospace;
  font-size: 0.82rem;
  letter-spacing: 0.01em;
  color: var(--cw-ink);
}
.cw-token-name span { color: var(--cw-muted); }

/* SECTION 4 — IN USE */
.cw-inuse { padding: clamp(60px, 10vh, 140px) 0; }
.cw-video-frame {
  border: 1px solid var(--cw-line);
  border-radius: 16px;
  overflow: hidden;
  background: var(--cw-surface);
  aspect-ratio: 16 / 9;
}
.cw-video-frame video,
.cw-video-frame img {
  width: 100%; height: 100%;
  object-fit: cover; display: block;
}
.cw-caption {
  font-family: var(--body);
  font-size: 0.9rem;
  color: var(--cw-muted);
  margin: 20px 0 0;
}

/* SECTION 5 — LIVE */
.cw-live {
  min-height: 70vh;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  text-align: center;
  padding: clamp(80px, 12vh, 160px) clamp(24px, 6vw, 96px) clamp(60px, 10vh, 120px);
}
.cw-live-line {
  font-family: var(--ff);
  font-weight: 400;
  font-size: clamp(1.5rem, 3.5vw, 2.4rem);
  line-height: 1.2;
  margin: 0 0 clamp(32px, 5vh, 48px);
  max-width: 620px;
  text-wrap: balance;
}
.cw-cta {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--ff);
  font-size: clamp(1rem, 1.6vw, 1.2rem);
  letter-spacing: 0.01em;
  color: var(--cw-ink);
  padding: 14px 28px;
  border: 1px solid var(--cw-ink);
  border-radius: 999px;
  transition: background 0.3s ease, color 0.3s ease, transform 0.3s ease;
}
.cw-cta:hover { background: var(--cw-ink); color: var(--cw-bg); }
.cw-cta .cw-arrow { transition: transform 0.3s ease; }
.cw-cta:hover .cw-arrow { transform: translateX(4px); }

/* Fade-up on scroll (System cards + generic) */
.cw-fade {
  opacity: 0; transform: translateY(20px);
  transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}
.cw-fade.is-in { opacity: 1; transform: translateY(0); }

@media (max-width: 768px) {
  .cw-grid { grid-template-columns: 1fr; }
  .cw-hero { min-height: calc(100svh - 60px); }
}

@media (prefers-reduced-motion: reduce) {
  .cw-swatch-canvas, .cw-bg { display: none; }
  .cw-token, .cw-fade { opacity: 1 !important; transform: none !important; transition: none; }
}

/* ============================================================
   HOME COMO CATALOGO (fase 2)
   Layout de esquinas fijo + vista Index en masonry.
   ============================================================ */
:root {
  --corner-pad: clamp(18px, 2.4vw, 40px);
  --idx-gap: 32px;   /* tablet y mobile lo bajan mas abajo */
}

/* --- Esquinas ------------------------------------------------------- */
/* Las esquinas son texto suelto sobre la grilla: cuando una card pasa por
   detras, el texto se pierde. Estos dos scrims son el minimo que hace falta
   para sostener la legibilidad sin agregar cajas ni bordes. */
/* El alto de los dos scrims vive en estas dos variables y en ningun otro lado.
   El JS necesita medirlos (de ahi sale el area util donde entra el riel) y
   getComputedStyle sobre un ::before/::after no es confiable — Safari devuelve
   "auto" y el calculo daba cero, con lo cual el riel se creia con mucho mas
   alto disponible y dibujaba las placas bastante mas grandes que en Chrome.
   Ahora el JS mide un elemento de verdad que usa estas mismas variables
   (ver altoScrim en main.js). */
:root {
  /* Las franjas del sistema: barra de estado arriba, indicador de inicio
     abajo. Con viewport-fit=cover en el <meta>, la pagina llega hasta el borde
     real de la pantalla y estas dos dicen cuanto de ese borde esta tapado por
     iOS. Fuera de un telefono valen 0 y nada de esto cambia. */
  --safe-arriba: env(safe-area-inset-top, 0px);
  --safe-abajo:  env(safe-area-inset-bottom, 0px);

  /* El scrim tiene que cubrir SU franja del sistema ademas de su propio alto,
     porque ahi tambien pasa contenido por detras. */
  --scrim-alto-arriba: calc(var(--corner-pad) * 2 + 20px + var(--safe-arriba));
  --scrim-alto-abajo:  calc(var(--corner-pad) * 2 + 62px + var(--safe-abajo));
}
/* Los dos esfumados son DIVS DE VERDAD, no `body::before` / `::after`.
   Eran pseudo-elementos y en Safari de iPhone se corrian con la pagina al
   scrollear: se veia el contenido pasar por arriba del menu y por abajo del
   pie. Las esquinas (.corner), que hacen `position: fixed` igual pero sobre
   elementos reales, nunca fallaron en el mismo telefono y en la misma
   pantalla. Esa era la unica diferencia entre lo que andaba y lo que no, asi
   que los esfumados pasan a ser elementos reales tambien.
   Van como primeros hijos del <body> en las cuatro paginas. */
.scrim {
  position: fixed;
  left: 0; right: 0;
  height: var(--scrim-alto-arriba);
  pointer-events: none;
  z-index: 150;
}
.scrim-arriba {
  top: 0;
  background: linear-gradient(to bottom, var(--bg) 18%, rgba(250,250,247,0.72) 55%, transparent 100%);
}
.scrim-abajo {
  bottom: 0;
  height: var(--scrim-alto-abajo);
  background: linear-gradient(to top, var(--bg) 18%, rgba(250,250,247,0.72) 58%, transparent 100%);
}
/* Estas tres paginas scrollean y no llevan barra fija abajo. */
body.page-about   .scrim-abajo,
body.page-gallery .scrim-abajo,
body.page-contact .scrim-abajo { display: none; }
/* Sin la clase has-corners no hay chrome fijo que tapar. */
body:not(.has-corners) .scrim { display: none; }
/* Lo que mide el JS. Invisible y fuera de cuadro, pero un elemento real: su
   getBoundingClientRect().height si es confiable en todos los navegadores. */
.medidor-scrim {
  position: absolute;
  left: -9999px; top: 0; width: 1px;
  visibility: hidden;
  pointer-events: none;
}
.medidor-scrim.arriba { height: var(--scrim-alto-arriba); }
.medidor-scrim.abajo  { height: var(--scrim-alto-abajo); }

.corner {
  position: fixed;
  z-index: 200;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.04em;
}
.corner-tl {
  top: calc(var(--corner-pad) + var(--safe-arriba)); left: var(--corner-pad);
  font-size: 22px; font-weight: 600; letter-spacing: -0.02em;
}
.corner-tr { top: calc(var(--corner-pad) + var(--safe-arriba)); right: var(--corner-pad); text-align: right; }
.corner-bl { bottom: calc(var(--corner-pad) + var(--safe-abajo)); left: var(--corner-pad); }
.corner-br { bottom: calc(var(--corner-pad) + var(--safe-abajo)); right: var(--corner-pad); }
/* La firma, centrada al pie. Va mas apagada que el resto de las esquinas: es
   un dato de procedencia, no un elemento de navegacion. Se alinea con la
   primera linea del bloque de la izquierda, no con las redes. */
.corner-bc {
  /* Comparte renglon con las redes, que es el segundo del bloque de la
     izquierda — no con el toggle. Ahi abajo pesa menos y no compite con la
     navegacion. */
  bottom: calc(var(--corner-pad) + var(--safe-abajo));
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  /* --fg-faint (30%) quedaba tan claro que casi no se leia. Con --fg-dim es el
     mismo gris que las redes con las que ahora comparte linea. */
  color: var(--fg-dim);
  white-space: nowrap;
  pointer-events: none;
}

.corner a { color: var(--fg); transition: opacity 200ms var(--ease); }
.corner a:hover { opacity: 0.55; }
.corner .sep { color: var(--fg-faint); margin: 0 6px; }

/* Toggle de vista y redes: separacion clara entre los dos bloques */
.view-toggle { display: flex; align-items: baseline; gap: 8px; }
.view-btn {
  background: none; border: 0; padding: 0;
  font: inherit; color: var(--fg-dim);
  letter-spacing: 0.04em; cursor: pointer;
  transition: color 200ms var(--ease);
}
.view-btn:hover { color: var(--fg); }
.view-btn.is-active { color: var(--fg); font-weight: 500; }
.view-btn[aria-disabled="true"] { opacity: 0.4; cursor: default; }
.view-btn[aria-disabled="true"]:hover { color: var(--fg-dim); }
.view-sep { color: var(--fg-faint); }
.corner-social { margin-top: 18px; color: var(--fg-dim); }
.corner-social a { color: var(--fg-dim); }
.corner-social a:hover { color: var(--fg); opacity: 1; }

/* --- Pills de filtro ------------------------------------------------ */
/* En columna, uno abajo del otro y alineados a la derecha: es una lista de
   categorias, no una barra de tags. */
.filters {
  display: flex; flex-direction: column; align-items: flex-end;
  gap: 7px;
}
.pill {
  font: inherit; font-size: 12px; font-weight: 500;
  letter-spacing: 0.06em;
  padding: 10px 18px;
  border-radius: 999px;
  color: var(--fg-dim);
  cursor: pointer;
  white-space: nowrap;
}
.pill:hover { color: var(--fg); }
.pill.is-active {
  background: var(--fg);
  border-color: var(--fg);
  color: var(--bg);
  box-shadow: var(--glass-shadow);
}
.pill.is-active:hover { background: var(--fg); color: var(--bg); }

/* --- Vista Index ---------------------------------------------------- */
.view { display: none; }
.view.is-active { display: block; }

.idx-grid {
  display: grid;
  /* contiene a las cards filtradas, que van en absolute */
  position: relative;
  grid-template-columns: repeat(4, 1fr);
  /* Filas chicas: el JS calcula cuantas ocupa cada card segun su alto real.
     Es lo que permite masonry denso con gaps parejos. */
  /* Filas de 1px y sin row-gap: el aire vertical lo pone el margin-bottom de
     cada card. Con filas gruesas, redondear el span hacia arriba dejaba hasta
     14px de sobra y los gaps salian disparejos. */
  grid-auto-rows: 1px;
  /* dense: cuando una card large deja un hueco al costado, la siguiente que
     entre lo rellena en vez de arrastrar el vacio hasta el final. Es lo que
     mantiene la grilla compacta sola, sin celdas vacias puestas a mano. */
  grid-auto-flow: row dense;
  row-gap: 0;
  column-gap: var(--idx-gap);
  /* Sin esto la card se estira al alto del span que le asigna el JS, y medirla
     devuelve ese alto en vez del natural: el masonry no converge nunca. */
  align-items: start;
  padding: calc(var(--corner-pad) + 46px) var(--corner-pad) calc(var(--corner-pad) + 92px);
}

.idx-card {
  display: block;
  color: var(--fg);
  /* Sin esto el nowrap de .idx-role impone un min-content mayor que 1fr y las
     columnas salen desiguales (en mobile se notaba: 148px contra 194px). */
  min-width: 0;
  margin-bottom: var(--idx-gap);
  transition: opacity 620ms var(--ease), transform 620ms var(--ease);
}
/* Progressive enhancement: las cards son visibles por defecto. El estado
   inicial de la animacion lo pone el JS al marcar la grilla con .js-anim,
   asi un fallo del observer nunca deja el catalogo en blanco. */
/* La card asoma desde abajo, pero poco: 12px alcanzan para que se lea el
   gesto. Mas recorrido lo vuelve un carrusel y se pierde la calma. */
/* .pre-anim la pone el script del <head> para que las cards ya nazcan
   apagadas: main.js va al final del body y sin esto el navegador alcanzaba a
   pintar la grilla visible antes de que el JS la escondiera. */
html.pre-anim .idx-card,
.idx-grid.js-anim .idx-card { opacity: 0; transform: translateY(12px); }
.idx-grid.js-anim .idx-card.is-in { opacity: 1; transform: translateY(0); }
.idx-card.is-large { grid-column: span 2; }

.idx-media {
  overflow: hidden;
  border-radius: 12px;
  aspect-ratio: 3 / 4;
  /* Sin glass a proposito: en el Index la imagen manda y no lleva marco.
     El glass va en la vista Overview, donde sostiene la superposicion. */
}
.is-large  .idx-media { aspect-ratio: 3 / 2; }
.is-small  .idx-media { aspect-ratio: 1 / 1; }
/* Los videos van siempre apaisados, sin importar el tamano de la card */
.idx-card[data-video] .idx-media { aspect-ratio: 16 / 9; }

/* El reel se achica desde la punta de abajo a la derecha: el media se angosta
   y, como el aspect esta fijo, tambien baja de alto. El origen queda arriba a
   la izquierda. El margen extra abre el aire contra el proyecto de abajo. */
.idx-card.is-reel .idx-media { width: 78%; }
.idx-card.is-reel { margin-bottom: calc(var(--idx-gap) * 2.4); }

/* Un escalon por debajo de una large entera, para que respire al lado */
.idx-card.is-encogida .idx-media { width: 88%; }


.idx-media img, .idx-media video, .idx-media iframe {
  width: 100%; height: 100%;
  object-fit: cover; display: block;
  border: 0;
  transition: transform 600ms var(--ease);
}
/* El embed del reel se come el click: sin esto la card no abre el modal */
.idx-media iframe { pointer-events: none; }
.idx-card:hover .idx-media img,
.idx-card:hover .idx-media video,
.idx-card:hover .idx-media iframe { transform: scale(1.03); }

/* Meta siempre visible, sin hover. Dos lineas como maximo. */
.idx-meta { padding: 10px 2px 0; }
.idx-name {
  display: block;
  font-size: 13px; font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.35;
}
.idx-role {
  display: block;
  font-size: 12px; font-weight: 400;
  color: var(--fg-dim);
  line-height: 1.35;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Filtrado: la card se va y deja de ocupar lugar en la grilla */
/* Filtrado: la card se va y deja de ocupar lugar. Iba con position:absolute a
   secas, pero sin contenedor posicionado su bloque contenedor era la pagina y
   seguia estirando el alto del documento: en los filtros con pocas cards
   quedaban ~900px de scroll en blanco despues de la ultima. Clavarlas en el
   origen de la grilla, con tamano cero y ocultas, las saca del todo. */
.idx-card.is-filtered {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  overflow: hidden;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.idx-empty {
  padding: 0 var(--corner-pad) 120px;
  color: var(--fg-dim);
  font-size: 13px;
}

@media (max-width: 1024px) {
  :root { --idx-gap: 24px; }
  .idx-grid { grid-template-columns: repeat(2, 1fr); }
}
/* --- Mobile: las esquinas de abajo se vuelven una barra ---------------
   En pantalla ancha los filtros son una columna a la derecha y el toggle vive
   en la esquina opuesta. En telefono esa columna medía 183px de alto y flotaba
   encima de las cards, y el bloque de la izquierda obligaba a reservar 290px
   al pie. Las dos esquinas de abajo pasan a ser dos renglones a lo ancho:
   arriba los filtros en una fila que se desliza, abajo vista y redes. Todo el
   pie ocupa ~76px y ya no tapa nada. */
/* La barra hace falta en cualquier pantalla chica, no solo angosta: un
   telefono acostado mide 844x390 y por ancho se llevaba la columna de filtros
   de escritorio encima de las cards, en 390px de alto. */
@media (max-width: 768px), (max-height: 520px) {
  .corner { font-size: 11px; }
  .corner-tl { font-size: 18px; }

  /* Tres renglones, de abajo hacia arriba: la firma, despues vista + redes, y
     arriba de todo los filtros. Entra sin robarle alto al riel porque el
     esfumado del pie ya reservaba 146px y el chrome solo usaba 84. */
  .corner-bl {
    left: 0; right: 0;
    bottom: calc(var(--corner-pad) + 22px + var(--safe-abajo));
    display: flex; justify-content: space-between; align-items: baseline;
    padding: 0 var(--corner-pad);
  }
  .corner-social { margin-top: 0; }
  /* La firma, en su propio renglon abajo de todo y centrada. Mas chica que en
     escritorio: es un dato de procedencia, lo ultimo que tiene que competir
     por atencion en una pantalla de telefono. */
  .corner-bc {
    bottom: calc(var(--corner-pad) + var(--safe-abajo));
    font-size: 10px;
  }

  /* El toggle de vista, resaltado. En una pantalla chica "Overview | Index"
     en gris al pie no se lee como un control y mucha gente no se entera de
     que hay una segunda vista. Con fondo se vuelve un boton.
     El gris es mas claro que el negro del filtro activo a proposito: llama la
     atencion sin pelearse con el, que es el control principal. */
  .view-toggle {
    background: #3A3A38;
    border-radius: 999px;
    padding: 7px 12px;
    gap: 6px;
    flex: 0 0 auto;
  }
  /* El fondo del toggle se come ancho y las redes pasaban a dos renglones,
     encimandose. Se achican apenas: 124 + 215 daban exactamente los 339
     utiles, o sea cero aire. */
  .corner-social { font-size: 10px; }
  .corner-social .sep { margin: 0 4px; }
  .view-btn { color: rgba(250,250,247,0.62); }
  .view-btn.is-active { color: var(--bg); font-weight: 600; }
  .view-sep { color: rgba(250,250,247,0.34); }

  /* Renglon de los filtros, justo encima. Se desliza en horizontal y sangra
     hasta los dos bordes para que se lea que sigue. */
  .corner-br {
    left: 0; right: 0;
    bottom: calc(var(--corner-pad) + 52px + var(--safe-abajo));
  }
  .filters {
    flex-direction: row; align-items: center;
    gap: 6px;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding: 4px var(--corner-pad);
    /* Sin esto el ultimo pill queda pegado al borde y no se ve que hay mas */
    scroll-padding-inline: var(--corner-pad);
    /* OJO: nada de scroll-behavior: smooth aca. El JS centra el filtro elegido
       escribiendo scrollLeft, y con smooth esa escritura se vuelve una
       animacion que necesita que el navegador este componiendo — en una
       pestana en segundo plano no corre y la fila se queda sin mover. */
  }
  .filters::-webkit-scrollbar { display: none; }
  .pill { padding: 9px 15px; font-size: 11px; flex: 0 0 auto; }

  .idx-grid {
    padding: calc(var(--corner-pad) + 40px + var(--safe-arriba)) var(--corner-pad) calc(var(--corner-pad) + 118px + var(--safe-abajo));
  }
  /* El esfumado del pie tiene que sostener DOS renglones, no uno: con el
     degradado de escritorio los titulos de las cards se leian por detras de
     los filtros. Se alarga y se mantiene opaco mas arriba. */
  :root {
    /* Arriba tambien se agranda: con el alto de escritorio la zona solida
       terminaba a 22px del borde y el nav vive entre 20 y 32, o sea justo
       sobre el desvanecido — por eso se leian los titulos de las cards por
       detras de "About · Gallery · Contact". */
    --scrim-alto-arriba: calc(var(--corner-pad) * 2 + 42px + var(--safe-arriba));
    --scrim-alto-abajo:  calc(var(--corner-pad) * 2 + 110px + var(--safe-abajo));
    /* Cuanto se estira el fondo mas alla del borde de la pantalla.
       Safari en iPhone corre los elementos fijos hacia abajo mientras se
       contrae la barra de direcciones al scrollear: el fondo se despega del
       borde y por esa franja se ve pasar el contenido. Medido sobre una
       captura del telefono, el corrimiento llega a unos 130px; con los 80px
       que habia quedaba corto por unos 50, y esa era toda la franja que se
       veia mal. 260 lo absorbe con margen de sobra.
       No cambia como se ve: el degradado se mide desde el borde interior de
       la caja (calc(100% - 34px)), asi que agrandarla hacia afuera solo suma
       zona solida fuera de pantalla — el desvanecido queda donde estaba. */
    --sangria: 260px;
  }

  /* Los dos scrims SANGRAN por fuera del borde de la pantalla.
     En Safari de iPhone las barras del navegador son translucidas y dejan ver
     la pagina por detras: un esfumado que termina justo en el borde deja una
     franja donde el contenido se transparenta, y en el Index y el About —que
     son texto negro sobre papel— eso se lee como un error.
     Van solidos de punta a punta y solo se desvanecen en los ultimos 34px del
     borde de adentro — medida absoluta y no porcentaje, para que el desvanecido
     mida siempre lo mismo sin importar cuanto sangre la caja. En telefono el
     pie es una barra densa; el degradado largo del escritorio es un lujo que
     ahi solo sirve para dejar pasar contenido.
     El alto que el JS usa para calcular el area util sigue siendo la variable,
     no la caja: la sangria no le come espacio al riel. */
  /* PLAN B — el esfumado deja de ser una capa aparte.
     En Safari de iPhone los esfumados se corrian con la pagina al scrollear y
     dejaban ver el contenido por arriba del menu y por abajo del pie. Probamos
     cuatro arreglos distintos y ninguno lo movio. Las esquinas, en cambio,
     nunca fallaron en ese mismo telefono: el menu siempre estuvo donde tenia
     que estar. Asi que el degradado deja de vivir en un elemento propio y pasa
     a colgar de las esquinas, que son las que sabemos que funcionan.

     No es una explicacion del bug: es dejar de depender de lo que esta roto.
     El degradado es el mismo, el alto es el mismo y sangra los mismos 80px;
     lo unico que cambia es de quien cuelga. Y como cuelga de un elemento que
     ya esta bien ubicado, no puede quedar en otro lado que no sea el correcto.

     Solo en telefono. En escritorio los esfumados andan bien y siguen intactos. */
  .scrim { display: none; }

  /* ═══ EL BODY NO SCROLLEA EN TELEFONO ═══
     Safari contrae la barra de direcciones solo cuando scrollea LA PAGINA, y
     al contraerse deja a la vista una franja que queda fuera del viewport de
     maquetado — donde ningun `position: fixed` puede llegar. Por ahi se veia
     pasar el contenido, arriba del nav y abajo del pie, y por eso ninguno de
     los intentos anteriores servia: no habia forma de tapar esa franja.

     La pista estaba desde el principio: entrar a un proyecto y salir lo
     arreglaba. Lo unico que hace el modal es bloquear el scroll del body. Con
     el body quieto, la barra no se contrae y la franja no existe.

     Asi que el scroll pasa a ocurrir DENTRO de una capa, entre las dos barras.
     El body queda del alto de la pantalla y no se mueve nunca. El nav y el pie
     dejan de depender de que Safari se porte bien: no hay nada que se pueda
     despegar.

     Solo en index y about, que son las que scrollean con el body. Gallery
     tiene su propio manejo de scroll y contact entra en una pantalla. */
  html { height: 100%; }
  body.page-index, body.page-about { height: 100%; overflow: hidden; }
  body.page-index .view-index,
  body.page-about .capa-scroll {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* Que el scroll no se propague al body ni al navegador: es justamente la
       propagacion la que le avisa a Safari que puede contraer la barra. */
    overscroll-behavior: contain;
  }

  /* Arriba: cuelga del "CC", que es la primera esquina del DOM, asi que el
     menu de la derecha se dibuja por encima. Se estira a todo el ancho con
     100vw y se corre a la izquierda lo que la esquina tiene de margen. */
  .corner-tl::before {
    content: "";
    position: absolute;
    left: calc(-1 * var(--corner-pad));
    top: calc(-1 * var(--sangria) - var(--corner-pad) - var(--safe-arriba));
    width: 100vw;
    height: calc(var(--scrim-alto-arriba) + var(--sangria));
    /* Bloque solido, no degradado. El desvanecido suave quedaba lindo pero
       dejaba pasar contenido apenas la barra se despegaba un poco; con un
       bloque opaco, lo que quede tapado queda tapado y punto. */
    background: var(--bg);
    z-index: -1;
    pointer-events: none;
  }

  /* Abajo: cuelga de la fila del toggle, que en telefono ya ocupa todo el
     ancho. Va antes que la firma y que la fila de abajo en el DOM, asi que
     las tres quedan por encima del degradado. */
  .corner-bl::before {
    content: "";
    position: absolute;
    left: 0; right: 0;
    bottom: calc(-1 * var(--sangria) - var(--corner-pad) - 22px - var(--safe-abajo));
    height: calc(var(--scrim-alto-abajo) + var(--sangria));
    background: var(--bg);
    z-index: -1;
    pointer-events: none;
  }
  /* Estas tres scrollean y no llevan barra fija abajo, igual que antes. */
  body.page-about   .corner-bl::before,
  body.page-gallery .corner-bl::before,
  body.page-contact .corner-bl::before { content: none; }
}

/* La grilla de dos columnas si es cosa del ancho: en horizontal el telefono
   tiene 844px y las cuatro columnas de siempre entran bien. */
@media (max-width: 768px) {
  :root { --idx-gap: 16px; }
  /* Dos columnas de verdad: solo el reel cruza el ancho entero, que es la
     portada de la pagina. Si las cuatro cards large lo hicieran, se verian
     una y media por pantalla y el catalogo dejaria de leerse de un vistazo,
     que es justo para lo que sirve el Index en telefono. */
  .idx-card.is-large { grid-column: auto; }
  .idx-card.is-reel  { grid-column: span 2; }
  /* Los recortes de ancho son para la composicion de escritorio. En una
     columna de 162px achicar mas deja la portada en miniatura. */
  .idx-card.is-reel .idx-media,
  .idx-card.is-encogida .idx-media { width: 100%; }
  .idx-card.is-reel { margin-bottom: calc(var(--idx-gap) * 1.4); }
  /* En una columna de 162px el rol se cortaba con puntos suspensivos
     ("Creative Direction + AI Produ…"). Mejor que baje a dos renglones: el
     titulo y la categoria son lo unico que orienta cuando no hay hover. */
  .idx-role { white-space: normal; overflow: visible; text-overflow: clip; }
  .idx-meta { padding-top: 8px; }
}

@media (prefers-reduced-motion: reduce) {
  .idx-card { transition: opacity 200ms linear; transform: none; }
  .idx-card.is-in { transform: none; }
  .idx-card:hover .idx-media img,
  .idx-card:hover .idx-media video { transform: none; }
}


/* ============================================================
   PAGINAS INTERNAS — mismo layout de esquinas que el home
   ============================================================ */
/* El contenido arranca debajo del nav fijo, no pegado a el */
.about-main { padding-top: calc(var(--corner-pad) * 2 + 90px); }

/* --- Intro de About --------------------------------------------------
   La unica pagina con scroll narrativo abre con una sola frase y el texto de
   posicionamiento al lado. Un escalon por debajo de .big-title: "Skills" y
   "Competitions" son los titulos de seccion, y esto es la entrada — si midiera
   lo mismo, competirian. */
.about-intro {
  display: grid;
  grid-template-columns: 1.25fr 1fr;
  gap: clamp(32px, 6vw, 96px);
  align-items: start;
  padding: clamp(70px, 11vh, 130px) var(--pad-x) clamp(70px, 11vh, 130px);
}
.about-lead {
  font-family: var(--display);
  /* El cuerpo esta calibrado para que "Grounded in graphic design," entre en
     un renglon dentro de su columna: la frase corta donde dice el <br> y no
     antes. Mas grande, "design," se quedaba sola en una linea. */
  font-size: clamp(26px, 3.4vw, 46px);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.03em;
  margin: 0;
  text-wrap: balance;
}
.about-intro-copy {
  /* Baja a la altura de la segunda linea del titulo: alineadas por arriba las
     dos columnas se leen como dos titulos, no como frase y desarrollo. */
  padding-top: clamp(6px, 1.2vw, 18px);
  max-width: 46ch;
  color: var(--fg-dim);
  font-size: 15px;
  line-height: 1.65;
}
.about-intro-copy p { margin: 0 0 1.15em; }
.about-intro-copy p:last-child { margin-bottom: 0; }
/* El primer parrafo lleva la voz; los que siguen son contexto */
.about-intro-copy p:first-child { color: var(--fg); font-size: 17px; line-height: 1.55; }
/* Sin texto todavia, la columna no debe dejar un hueco raro */
.about-intro-copy:empty { display: none; }

@media (max-width: 900px) {
  .about-intro {
    grid-template-columns: 1fr;
    gap: 28px;
    /* En telefono el aire de escritorio dejaba la frase flotando sola en media
       pantalla; arriba ademas ya esta el aire de .about-main. */
    padding: 44px var(--pad-x) 64px;
  }
  .about-intro-copy { padding-top: 0; }
}

/* Aire al final: sin esto la pagina corta justo despues de los links */
body.page-about .footer { padding-bottom: clamp(80px, 12vh, 160px); }

/* About es la unica pagina con scroll largo y ya tiene sus redes en el pie.
   La esquina fija de abajo repetia esos mismos links y, sin esfumado (esta
   pagina lo apaga a proposito), se leia encima del texto de las secciones. */
body.page-about .corner-bl { display: none; }

/* Gallery y Contact usan las mismas esquinas; su contenido no debe quedar
   tapado por el nav fijo */
body.page-gallery .gallery-title { z-index: 1; }
body.page-contact .contact { padding-top: calc(var(--corner-pad) + 40px); }


/* ============================================================
   VISTA OVERVIEW (fase 3) — stack diagonal en perspectiva 3D
   Placas de vidrio inclinadas, con el cover impreso encima: sin marco, sin
   borde y traslucidas, que es lo que deja ver una card a traves de la otra.

   Cuatro capas de transform, cada una con una sola tarea. La separacion no es
   cosmetica: si .ov-scene lleva perspective Y transform a la vez, el navegador
   hace el hit-test SIN la perspectiva y solo la card en z:0 recibe el cursor.
     .ov-fit    encaje 2D (escala + traslado), fuera de la perspectiva
     .ov-scene  perspective, sin transform propio
     .ov-stage  parallax del cursor
     .ov-card   posicion 3D + inclinacion de cada placa
   ============================================================ */

/* Preferencia de vista aplicada antes del primer pintado (script del <head>).
   Gana por especificidad sobre .view.is-active del HTML. */
html.pref-overview .view-index { display: none; }
html.pref-overview .view-overview { display: block; }
html.pref-overview, html.pref-overview body,
html.ov-lock, html.ov-lock body { overflow: hidden; }

/* Crossfade entre vistas: la saliente se apaga y recien ahi entra la otra */
.view { transition: opacity 240ms var(--ease); }
.view.is-out { opacity: 0; }

.view-overview {
  position: fixed;
  inset: 0;
  overflow: hidden;
}

.ov-fit {
  position: absolute;
  inset: 0;
  transform-origin: 50% 50%;
}

.ov-scene {
  position: absolute;
  inset: 0;
  perspective-origin: 50% 50%;
}

.ov-stage {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transition: transform 700ms var(--ease);
  /* El stage es un plano en z:0 que cubre toda la pantalla, asi que dentro
     del contexto 3D queda DELANTE de cada placa con z negativo y se lleva
     todos los clicks: solo respondia la primera, la unica en z:0. */
  pointer-events: none;
}

/* --- Placas --------------------------------------------------------- */
.ov-card {
  position: absolute;
  left: 50%; top: 50%;
  width: 260px;              /* el JS la recalcula segun el viewport */
  color: var(--fg);
  /* Ni el stage ni las placas reciben el cursor: quien esta bajo el puntero lo
     resuelve el JS con la geometria en reposo (ver placaEn). Si el area
     sensible se moviera con la placa al subir, se saldria de abajo del cursor
     y volveria a titilar. */
  pointer-events: none;
  transition: transform 460ms var(--ease), opacity 400ms var(--ease);
}

/* El hover no apaga al resto: la placa elegida sube y con eso alcanza. Se
   probo transparentar las que la tapaban y le sacaba cuerpo a la fila entera. */
/* Al colocarlas por primera vez no tienen que viajar desde el centro */
.ov-stage.sin-transicion .ov-card { transition: none; }
/* Durante el arrastre las placas siguen al dedo sin suavizado: es lo que hace
   que se sienta como agarrar la fila y no como empujarla. */
.ov-stage.arrastrando .ov-card { transition: none; }
.view-overview.sobre-placa { cursor: pointer; }
.view-overview.hay-riel { cursor: grab; }
.view-overview.hay-riel.arrastrando { cursor: grabbing; }

.ov-media {
  display: block;
  position: relative;
  overflow: hidden;
  border-radius: 2px;
  /* Nada de bordes ni bandas alrededor: la lamina se separa del fondo solo
     por la sombra — una corta de apoyo y una larga de peso en el aire. */
  box-shadow: 0 1px 2px rgba(20,20,20,0.11), 0 28px 66px rgba(20,20,20,0.14);
  transition: transform 420ms var(--ease), box-shadow 420ms var(--ease);
}
.ov-card.is-foco .ov-media {
  box-shadow: 0 2px 5px rgba(20,20,20,0.13), 0 46px 100px rgba(20,20,20,0.22);
}

/* El cover impreso en la placa: translucido, y cuanto mas al fondo esta la
   card, mas se desvanece. El JS escribe --vidrio segun la profundidad. */
.ov-media img, .ov-media video, .ov-media iframe {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; display: block;
  border: 0;
  opacity: var(--vidrio, 1);
  transition: opacity 420ms var(--ease);
}
.ov-card.is-foco .ov-media img,
.ov-card.is-foco .ov-media video,
.ov-card.is-foco .ov-media iframe { opacity: 1; }

/* El vidrio, en una sola capa: el reflejo en diagonal cruzando la lamina y la
   luz en los dos cantos verticales. Arriba y abajo no llevan nada — una linea
   cerrada volveria a leerse como un marco. --brillo lo escribe el JS.

   Va todo en ::after y sin z-index a proposito. Dos razones, las dos
   aprendidas a los golpes dentro del contexto 3D:
   · mix-blend-mode mezcla contra el fondo de la pagina en vez de contra la
     imagen de abajo, y la placa entera se va a blanco;
   · un ::before con z-index positivo hace que el navegador deje de pintar la
     imagen. ::after ya pinta por encima de los hijos sin pedir nada. */
.ov-media::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    /* Doble reflejo: el vidrio tiene dos caras y devuelve la luz dos veces,
       una banda ancha y otra angosta un poco corrida. Es lo que lo saca de
       "imagen con un degrade encima". */
    linear-gradient(114deg,
      rgba(255,255,255,0)    calc(var(--brillo, 0.3) * 100% - 26%),
      rgba(255,255,255,0.22) calc(var(--brillo, 0.3) * 100% - 9%),
      rgba(255,255,255,0.03) calc(var(--brillo, 0.3) * 100% - 1%),
      rgba(255,255,255,0.12) calc(var(--brillo, 0.3) * 100% + 5%),
      rgba(255,255,255,0)    calc(var(--brillo, 0.3) * 100% + 16%)),
    /* canto derecho: con esta inclinacion es el que viene hacia el ojo, o sea
       el filo que de verdad se ve. Muy fino y solo en los dos bordes
       verticales — arriba y abajo nada, cualquier banda ahi se lee como un
       borde puesto encima y no como vidrio. */
    /* El espesor NO se pinta de un color: se deja ver la propia imagen, que
       sigue ahi debajo, y encima va solo el sombreado que lo hace leer como un
       canto — un brillo en el filo y una juntura mas oscura donde termina.
       Asi el costado de Spring Sale es la continuidad de Spring Sale, y no una
       raya blanca pegada al costado. Por eso todos los tramos son
       translucidos: cualquier alfa alta vuelve a tapar la foto. */
    linear-gradient(270deg,
      rgba(255,255,255,0.42) 0,
      rgba(255,255,255,0.16) 3px,
      rgba(255,255,255,0.02) 5px,
      rgba(20,20,20,0.16) 7px,
      rgba(20,20,20,0.06) 9px,
      rgba(20,20,20,0) 11px),
    linear-gradient(90deg,
      rgba(255,255,255,0.22) 0,
      rgba(255,255,255,0.04) 3px,
      rgba(255,255,255,0) 5px);
  transition: opacity 420ms var(--ease);
}
.ov-card.is-foco .ov-media::after { opacity: 0.5; }

/* El embed del reel se come el click: sin esto la card no abre el modal */
.ov-media iframe { pointer-events: none; }

/* --- Titulo, en el plano de la pantalla ------------------------------- */
/* El JS lo traduce a la esquina de arriba a la izquierda de la placa
   enfocada, pero SIN rotarlo: la imagen vive en el espacio y el texto en la
   superficie. Puesto sobre el vidrio se inclinaba con la placa, y la
   tipografia deformada obligaba a ir aplanando la perspectiva. */
.ov-label {
  position: fixed;
  left: 0; top: 0;
  z-index: 210;
  max-width: 460px;
  padding-bottom: 18px;
  pointer-events: none;
  opacity: 0;
  /* Solo la opacidad hace transicion. Si el transform tambien la hiciera, el
     titulo se desliza de una placa a la otra y durante medio segundo no esta
     alineado con ninguna: apaga, salta, enciende. */
  transition: opacity 120ms var(--ease);
  transform-origin: 0 100%;
}
.ov-label.is-on {
  opacity: 1;
  transition: opacity 240ms var(--ease) 70ms;
}
.ov-label > * { display: block; }
/* Numero y titulo comparten renglon, alineados por la base */
.ov-linea { display: flex; align-items: baseline; gap: 5px; }
.ov-num {
  font-size: 10px; font-weight: 500;
  letter-spacing: 0.14em;
  color: var(--fg-faint);
  font-variant-numeric: tabular-nums;
}
.ov-title {
  font-size: 19px; font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.15;
}
.ov-sub {
  margin-top: 4px;
  font-size: 10px; font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--fg-dim);
}

/* --- Indicador del riel ----------------------------------------------- */
/* Cuantos trabajos hay y en cual estas parado. Solo aparece cuando el riel de
   verdad se puede mover. */
/* Arriba a la izquierda, debajo del logo: es la zona que el riel deja libre
   (la fila sube hacia la derecha), y ahi no le compite ni al mazo ni a las
   esquinas. */
.ov-riel {
  position: fixed;
  left: var(--corner-pad);
  top: calc(var(--corner-pad) + 42px);
  z-index: 205;
  display: flex;
  align-items: center;
  gap: 12px;
  opacity: 0;
  transition: opacity 300ms var(--ease);
  pointer-events: none;
}
.ov-riel.is-on { opacity: 1; }
.ov-riel-barra {
  display: block;
  position: relative;
  width: 132px; height: 1px;
  background: var(--line);
  overflow: hidden;
}
.ov-riel-pulgar {
  display: block;
  height: 100%;
  background: var(--fg);
  transition: transform 460ms var(--ease), width 460ms var(--ease);
}
.ov-riel-cuenta {
  font-size: 10px; font-weight: 500;
  letter-spacing: 0.12em;
  color: var(--fg-dim);
  font-variant-numeric: tabular-nums;
}

.ov-card:focus-visible { outline: none; }
.ov-card:focus-visible .ov-media {
  box-shadow: 0 0 0 2px var(--fg), 0 34px 80px rgba(20,20,20,0.16);
}

/* Filtrada: se va al fondo y se apaga, pero sigue en el DOM para volver */
.ov-card.is-oculta { opacity: 0; }

/* Entrada escalonada: fade + scale sutil, 800ms en total.
   Igual que en el Index, las cards son visibles por defecto y el estado
   inicial lo pone el JS, asi un fallo nunca deja el stack vacio. */
/* La opacidad la escribe el JS inline (mezcla el desvanecido de las puntas del
   riel con la entrada), asi que aca solo queda el scale. */
/* Entrada del riel: cada placa se asienta en su lugar viniendo de un poco mas
   chica y un poco mas abajo. Con el escalonado del JS (de adelante hacia
   atras) se lee como cartas que se van apoyando una atras de la otra, no como
   un fundido de todas a la vez. El movimiento es corto a proposito: lo que da
   la sensacion de cuidado es la curva y el ritmo, no la distancia.
   La transicion del media dura 700ms aca y no los 420 de siempre, porque la
   entrada tiene que respirar mas que un hover. */
.ov-stage.js-anim .ov-media {
  /* Sube desde abajo y nada mas — sin escala: sobre una placa girada 22 grados
     en perspectiva, una escala se lee como si entrara de costado.
     El recorrido es largo a proposito. Con 26px la placa se corria apenas y el
     ojo solo registraba el fundido; se necesita que el viaje se VEA. 80px es
     como un cuarto del alto de la placa: suficiente para leerse como que sale
     desde abajo, y poco como para que no parezca que entra deslizandose. */
  transform: translateY(80px);
  transition: transform 820ms var(--ease), box-shadow 420ms var(--ease);
  /* El escalonado lo escribe el JS como transition-delay en la PLACA, no aca.
     Sin este inherit, la opacidad de cada placa entraba en su turno pero las
     ocho subidas arrancaban juntas en el milisegundo cero y terminaban a los
     700ms: para cuando le tocaba aparecer a la septima, su subida ya habia
     pasado y se la veia aparecer sin moverse. Heredando el retardo del padre,
     cada placa sube cuando le toca. */
  transition-delay: inherit;
}
/* El fundido de la placa acompana al movimiento: con los 400ms de siempre la
   placa terminaba de aparecer mucho antes de terminar de asentarse. */
.ov-stage.js-anim .ov-card { transition: transform 460ms var(--ease), opacity 820ms var(--ease); }
.ov-stage.js-anim .ov-card.is-in .ov-media { transform: translateY(0); }

.ov-empty {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  color: var(--fg-dim);
  font-size: 13px;
}

/* --- Overview: el mazo ------------------------------------------------
   Va colgado de .es-mazo, que el JS pone cuando el riel corre parado, y NO de
   un ancho: un telefono acostado mide 844px de ancho y 390 de alto, y por
   ancho se llevaba el layout de escritorio.
   El titulo deja de colgar de la esquina de arriba de la placa enfocada y pasa
   a apoyarse DEBAJO de la de adelante, siempre visible. Por eso crece hacia
   abajo (sin el translateY(-100%) que usa el escritorio) y el aire cambia de
   lado. */
.es-mazo .ov-label {
  padding-bottom: 0;
  padding-top: 14px;
  padding-right: var(--corner-pad);
  transform-origin: 0 0;
  max-width: 100vw;
}
.es-mazo .ov-title { font-size: 15px; }
.es-mazo .ov-sub   { font-size: 10px; }
/* object-fit no existe para un iframe: el embed de Vimeo viene 16/9 y en una
   carta 4/3 dejaba una banda blanca abajo. Se lo agranda a lo ancho hasta
   tapar la carta y el sobrante lo recorta el overflow del media, que es
   exactamente lo que object-fit: cover haria si pudiera.
   133.33% = (16/9) / (4/3). */
.es-mazo .ov-media iframe {
  width: 133.34%;
  left: -16.67%;
}

/* El gesto del riel se lo queda la vista: sin esto el navegador se lleva el
   arrastre como scroll de pagina o pull-to-refresh y el riel no se mueve.
   Va por tipo de puntero, no por tamano: lo necesita cualquier pantalla tactil. */
@media (pointer: coarse) {
  .view-overview {
    touch-action: none;
    overscroll-behavior: contain;
  }
}

/* Cerrar, con area de dedo. Los dos botones median 45x17 y 20x39: con el
   mouse alcanza, con el pulgar no. Se agranda el AREA con padding y margen
   negativo — el aspa y la palabra se ven igual, pero el blanco alrededor
   tambien cierra. */
@media (pointer: coarse) {
  .cs-header .cs-close,
  .cs-header .cs-back {
    padding: 14px 16px;
    margin: -14px -16px;
  }
  .video-lightbox-close {
    top: 12px; right: 12px;
    padding: 10px 18px;
    line-height: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ov-stage, .ov-card, .ov-media, .ov-label, .view { transition: none; }
}

/* Cuantos trabajos hay en cada categoria, al lado del nombre del filtro */
.pill-n {
  margin-left: 5px;
  font-size: 8px;
  font-weight: 500;
  letter-spacing: 0.04em;
  vertical-align: super;
  opacity: 0.55;
  font-variant-numeric: tabular-nums;
}
