:root {
  --bg: #F0EBE3;
  --fg: #000000;
  --accent: #E10000;
  --off-white: rgba(245,245,245,1);
  --muted: rgba(0,0,0,0.55);
  --ph-a: #DAD3C3;
  --ph-b: #B9B2A0;

  /* Escala real del sitio de referencia: base 1rem, con utilidades
     fs-medium (1.5rem) y fs-large (3rem) para los pocos elementos que
     destacan (nombre del artista, título de proyecto, clon del hover).
     Tomamos ~12px como equivalente de 1rem en escritorio. */
  --fs-base: 12px;
  --fs-medium: 18px;
  --fs-large: 36px;

  /* Márgenes reales (--padding: 2rem ≈ 24px, --grid-gutter: 1rem ≈ 12px),
     mucho más ajustados que un margen genérico de 40-48px. */
  --pad: 24px;
  --gutter: 12px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-size: var(--fs-base);
}

a { color: inherit; }

/* Animación de entrada de la portada, igual que el sitio real: el logo cae
   desde arriba y la lista aparece en cascada (cada fila con un pequeño
   delay asignado desde main.js). */
@keyframes logo-drop {
  from { transform: translateY(-120%); }
  to { transform: translateY(0); }
}
@keyframes row-in {
  from { opacity: 0; transform: translateY(-0.5em); }
  to { opacity: 1; transform: translateY(0); }
}
.home .logo {
  animation: logo-drop .8s cubic-bezier(.16, 1, .3, 1) both;
}
.home .roster-group h2,
.home .roster-item-wrap {
  opacity: 0;
  animation: row-in .5s ease both;
}
@media (prefers-reduced-motion: reduce) {
  .home .logo,
  .home .roster-group h2,
  .home .roster-item-wrap {
    animation: none;
    opacity: 1;
  }
}

/* Evita que un clic/arrastre sobre texto interactivo lo seleccione
   (destello azul de selección) o muestre el resaltado táctil del navegador —
   el sitio de referencia hace esto con su clase "hideselect". */
.no-select {
  -webkit-user-select: none; user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-user-drag: none;
  outline: 0;
}

/* En la página de Info, pasar el cursor sobre el logo tiñe toda la pantalla
   de rojo con texto claro — sin transición: en el sitio real el cambio es
   instantáneo (la clase "accent" se activa/desactiva en seco). */
body.info-page.accent { background: var(--accent); color: #fff; }

/* Portada: fondo rojo de base (como siempre) y todas las tipografías en
   blanco. Los enlaces, el logo y el clon del hover heredan el color del
   body, así que basta con cambiarlo acá. */
body.home { background: var(--accent); color: #fff; }
/* Mientras se ve la foto/video de un talento o proyecto (".is-focusing",
   que ya pone main.js), el fondo del body pasa a negro: en celular, al
   rebotar el scroll o detrás de la barra de Safari, asoma el fondo del
   body en vez del de la foto — con rojo ahí se veía como un borde de
   color sin sentido alrededor de la imagen; en negro se nota mucho menos.
   Sin ninguna foto activa, sigue siendo rojo como siempre. */
body.home.is-focusing { background: #000; }
/* Mientras una imagen está de fondo, el texto toma el color elegido para
   ella ("textColor" en el JSON): blanco (por defecto), negro o rojo. */
body.home[data-text="black"] { color: #000; }
body.home[data-text="red"] { color: var(--accent); }

/* Pista de "deslizá" al cargar la home de talentos/proyectos en celular:
   solo un empujoncito visual, no un control — ver la animación en el media
   query de celular más abajo. */
.swipe-hint { display: none; }
.home-logo-float { display: none; }

/* Header */
.site-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  padding: var(--pad);
  position: relative; z-index: 2;
}
.logo {
  font-size: 112px;
  font-weight: 800;
  line-height: 0.9;
  letter-spacing: -0.02em;
  text-decoration: none;
  white-space: nowrap;
}
/* Cada línea del logo es un bloque: main.js mide la tinta de los glifos y
   le pone a la segunda línea su tamaño, margin-left y margin-top exactos
   (trazo de la T = pata de la "m", y la "m" casi tocando la T). */
/* Espaciado entre letras tomado de la maqueta (medido contra el grosor del
   trazo): "mit." bien cerrado, y la "N" casi pegada a la "T". */
.logo-line1 { display: block; letter-spacing: -0.047em; }
.logo-line2 { display: block; width: max-content; letter-spacing: -0.07em; }
.nav-link {
  font-size: var(--fs-base);
  font-weight: 400;
  letter-spacing: 0.08em;
  text-decoration: none;
  text-transform: uppercase;
}
.nav-link:hover { opacity: 0.4; }

/* Navegación de las portadas: TALENTOS · PROYECTOS · INFO. La sección actual
   va subrayada. */
.home-nav { display: flex; gap: var(--pad); }
.nav-current { text-decoration: underline; text-underline-offset: 4px; }

/* Roster (home) — el área que "escucha" el mouse para el efecto imán es
   mucho más ancha y alta que el propio texto (igual que el sitio real, cuyo
   contenedor de la lista mide 50rem de ancho y llega hasta abajo del
   viewport): así reacciona aunque el cursor venga por los costados o por
   debajo del último nombre, no solo pasando justo por encima de las letras. */
.roster {
  padding: 0 var(--pad) calc(var(--pad) * 3);
  width: 700px; max-width: calc(100vw - var(--pad) * 2);
  min-height: 65vh;
  position: relative; z-index: 2;
}
.roster-group { margin-bottom: var(--pad); }
/* Sin gap: los nombres van en flujo de bloque normal, tocándose entre sí
   (el espaciado lo da el line-height), para que el cursor nunca pierda
   cobertura al bajar por la lista — un gap entre filas crea una franja
   muerta donde ningún nombre está "activo" y la imagen de fondo se apaga. */
.roster-list { display: block; }

/* Capa fija a pantalla completa con la foto de portada de cada talento,
   igual que ".roster--list__medias" del sitio de referencia: cubre todo el
   viewport detrás del listado y se revela al pasar el cursor por un nombre.
   Sin transición: el cambio es instantáneo, igual que en el sitio real. */
.roster-medias { position: fixed; inset: 0; pointer-events: none; z-index: 1; }
.roster-media {
  position: absolute; inset: 0; opacity: 0;
  background-size: cover; background-position: center;
  background-color: var(--ph-a);
}
.roster-media.active { opacity: 1; }
.roster-media video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}

/* Video en loop de la ficha (para los talentos cuya portada es un video). */
.artist-video {
  display: grid; grid-template-columns: 280px 1fr; column-gap: var(--gutter);
  padding: 0 var(--pad); margin-bottom: var(--pad);
}
.artist-video video {
  width: 100%; aspect-ratio: 16 / 9; object-fit: cover; display: block;
  background: var(--ph-a);
}
.roster-media.empty {
  background-image: none;
  background: repeating-linear-gradient(45deg, var(--ph-a), var(--ph-a) 10px, var(--ph-b) 10px, var(--ph-b) 20px);
}
.roster-media.empty::after {
  content: attr(data-label);
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-base); letter-spacing: 0.04em; text-transform: uppercase;
  color: rgba(0,0,0,0.4); text-align: center; padding: var(--pad);
}

/* Cada nombre lleva un "clon" al triple de tamaño (fs-large) superpuesto,
   centrado en su propia fila. El cruce de opacidad título↔clon usa la clase
   .is-active que pone main.js (no :hover): como esa misma fila se mueve por
   el efecto magnético, dejar la detección en manos del :hover nativo del
   navegador se desincroniza con el layout que se está corriendo. El margen
   de la fila y la escala del clon los controla continuamente main.js en cada
   mousemove según la distancia vertical del cursor a CADA nombre de la
   lista (no solo el activo) — así es como el sitio real logra el efecto de
   "magnetismo": es una función continua, no un on/off. */
.roster-item-wrap {
  position: relative;
  transition: margin-top .1s linear, margin-bottom .1s linear;
}

.roster-item {
  display: block;
  font-size: var(--fs-base); line-height: 1.85; text-decoration: none;
  text-transform: uppercase;
  position: relative; z-index: 1;
}
.roster-item-wrap.is-active .roster-item { opacity: 0; }

/* pointer-events NO va en none: dejamos que el clon (ya agrandado, aunque
   esté invisible) reciba hover como hace el sitio real — así, cuando el
   texto crece e "invade" el espacio de la fila vecina, seguís técnicamente
   arriba del mismo link y no se apaga hasta que de verdad salís de esa área.
   Quitarle el pointer-events fue lo que causaba el hueco/flash en blanco. */
.roster-item-clone {
  position: absolute; left: 0; top: 50%;
  transform: translateY(-50%) scale(0.8);
  transform-origin: left center;
  transition: transform .2s linear;
  font-size: var(--fs-large); font-weight: 700; line-height: 1; white-space: nowrap;
  text-transform: uppercase; text-decoration: none;
  opacity: 0; z-index: 2;
}
.roster-item-wrap.is-active .roster-item-clone { opacity: 1; }

/* Artist page */
/* Proporciones y áreas de grid tomadas del CSS real (header--bottom):
   grid-template-columns: 3fr 1fr 9fr; areas "title . nav" / "bio . sections". */
.artist-grid {
  display: grid;
  grid-template-columns: 3fr 1fr 9fr;
  grid-template-areas: "title gap nav" "bio gap sections";
  column-gap: var(--gutter); row-gap: var(--pad); align-items: baseline;
  padding: var(--pad) var(--pad) 0; margin-bottom: calc(var(--pad) * 1.5);
}
.artist-name { grid-area: title; font-size: var(--fs-large); font-weight: 800; margin: 0; letter-spacing: -0.01em; }
.artist-bio-col { grid-area: bio; }

/* Ficha nueva (body.artist-v2): portada arriba, nombre sobre la foto, logo y
   nombre flotando, y todos los textos en rojo. */
.artist-cover { padding: var(--pad) var(--pad) 0; display: flex; justify-content: center; position: relative; }
/* La portada mantiene el formato de la foto y va centrada: si es horizontal
   su ANCHO mide el 60% de la ventana; si es vertical, su ALTO. */
.artist-cover-frame { position: relative; min-height: 40vw; }
.artist-cover-frame img, .artist-cover-frame video { display: block; background: var(--ph-a); }
.artist-cover-frame.is-ready { min-height: 0; }
.artist-cover-frame picture { display: contents; }
.artist-cover-frame.is-horizontal img, .artist-cover-frame.is-horizontal video { width: 60vw; height: auto; }
.artist-cover-frame.is-vertical img, .artist-cover-frame.is-vertical video { height: 60vw; width: auto; }
/* El nombre va sobre la foto, abajo a la izquierda, metido una "pad". */
.artist-name-wrap {
  position: absolute; left: var(--pad); bottom: var(--pad); z-index: 3;
}
.artist-name-wrap .artist-name { margin: 0; color: var(--accent); }
/* Link de descarga: misma letra que el menú de categorías. Arranca marginado a
   la derecha, a la altura del nombre grande, y al hacer scroll queda fijo
   debajo del nombre chico (el que aparece bajo el menú). */
.artist-download {
  position: absolute; z-index: 3;
  right: calc(var(--pad) * 2);
  top: calc(var(--name-top, 200px) + var(--pad) + var(--name-h, 0px) / 2); transform: translateY(-50%);
  color: var(--accent); text-decoration: none; white-space: nowrap;
  font-size: var(--fs-base); font-weight: 400; letter-spacing: 0.08em; text-transform: uppercase;
}
.artist-v2.name-docked .artist-download {
  position: fixed; z-index: 20; transform: none;
  top: calc(var(--nav-bottom, 64px) + clamp(22px, 2.4vw, 34px) + 8px);
}
.artist-download:hover { opacity: 0.4; }
/* El logo y INFO van encima de la portada, metidos una "pad" adentro de la
   foto para respetar el mismo margen del costado. */
/* Logo y menú quedan fijos flotando sobre el scroll. */
.artist-v2 .site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 20;
  padding: calc(var(--pad) * 2); color: var(--accent); pointer-events: none;
}
.artist-v2 .site-header a { pointer-events: auto; }
/* El nombre grande sigue su camino con el scroll. Al llegar al logo aparece,
   fijo a la derecha y bajo el menú, el nombre chico (y nada más). */
.artist-name-dock { display: none; }
.artist-v2.name-docked .artist-name-dock {
  display: block; position: fixed; z-index: 20;
  right: calc(var(--pad) * 2); top: var(--nav-bottom, 64px);
  text-align: right; font-weight: 800; line-height: 1;
  font-size: clamp(22px, 2.4vw, 34px); letter-spacing: -0.02em;
}
/* Nombres con marca reconocida (ver split_brand_name en generate.py): mismo
   formato que la portada, MARCA arriba y el nombre del proyecto debajo, un
   poco más chico. Ojo: en celular, todo junto en un renglón ("SOHO HOUSE 3
   ANIVERSARIO") es tan ancho que se pisa de verdad con el logo; partido en
   dos líneas cada una es angosta y entra al lado sin pisarlo. */
.artist-name-dock-brand, .artist-name-dock-rest { display: block; }
.artist-name-dock-rest { font-size: 0.62em; font-weight: 700; }
/* Escritorio: el menú flotante va un poco más arriba que en celular. */
@media (min-width: 701px) {
  body.artist-v2 .artist-nav { bottom: calc(var(--pad) * 2 + env(safe-area-inset-bottom, 0px)); }
}
/* Escritorio: el nombre, mucho más grande, arranca donde termina el punto del
   logo (main.js mide ese borde y lo deja en --name-left) y a la altura donde
   termina el logo (--name-top), sobre la foto. */
@media (min-width: 701px) {
  .artist-v2 .artist-name-wrap {
    left: var(--name-left, var(--pad)); top: var(--name-top, 200px); bottom: auto;
    width: max-content; max-width: var(--name-max, 60vw);
  }
  .artist-v2 .artist-name-wrap .artist-name { font-size: clamp(96px, 11vw, 200px); line-height: 0.92; }
}
/* Los títulos de grupo se pegan justo debajo del logo. */
/* Los títulos flotan sin fondo (en celular también, sin la barra beige). */
.artist-v2 .project > div:first-child { top: var(--dock-top, var(--pad)); background: none; }
.artist-v2 { color: var(--accent); }
.artist-v2 .artist-bio, .artist-v2 .project-credit { color: inherit; }
.artist-v2 .artist-category { display: none; }
/* Menú de categorías: mayúsculas y sin negrita. */
.artist-v2 .artist-nav, .artist-v2 .tab { font-weight: 400; letter-spacing: 0.08em; text-transform: uppercase; }
.artist-v2 .artist-grid { grid-template-areas: "bio gap nav"; }
/* El menú de categorías flota centrado en el margen inferior de la pantalla,
   desde el principio. */
.artist-v2 .artist-nav {
  display: flex; position: fixed; z-index: 20;
  left: 50%; transform: translateX(-50%);
  bottom: calc(var(--pad) + env(safe-area-inset-bottom, 0px));
  justify-content: center; flex-wrap: nowrap; white-space: nowrap; gap: var(--pad);
}
.artist-v2 .artist-name { font-size: clamp(72px, 7.2vw, 144px); line-height: 0.95; letter-spacing: -0.03em; }
.artist-category { font-size: var(--fs-base); font-weight: 700; letter-spacing: 0.08em; margin-bottom: var(--gutter); text-transform: uppercase; }
.artist-bio { font-size: var(--fs-base); line-height: 1.7; margin: 0; max-width: 260px; color: var(--muted); }
.artist-bio + .artist-bio { margin-top: var(--gutter); }

.artist-nav { grid-area: nav; display: flex; gap: var(--pad); font-size: var(--fs-base); font-weight: 600; }
.tab {
  background: none; border: none; font: inherit; color: inherit;
  padding: 0 0 2px; opacity: 0.55; cursor: pointer;
}
.tab.active { opacity: 1; border-bottom: 1px solid currentColor; }

.meta-cols { grid-area: sections; display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--pad); }
.meta-cols h3 { font-size: var(--fs-base); font-weight: 700; letter-spacing: 0.08em; margin: 0 0 var(--gutter); text-transform: uppercase; }
.meta-cols p { font-size: var(--fs-base); line-height: 1.7; margin: 0; }

.project { display: grid; grid-template-columns: 280px 1fr; column-gap: var(--gutter); padding: 0 var(--pad); margin-bottom: var(--pad); align-items: start; }
/* Igual que ".artist--projects .card--info" de Artlist: el título del grupo
   queda pegado arriba y acompaña el scroll mientras se ven sus fotos, hasta
   que termina el grupo. */
.project > div:first-child {
  position: sticky; top: var(--pad); z-index: 3;
  padding-right: var(--pad); background-color: var(--bg);
}
.ph, .project-video { cursor: pointer; }
.project-video { cursor: auto; }
.project-title { font-size: var(--fs-medium); font-weight: 700; }
.project-credit { font-size: var(--fs-base); opacity: 0.6; margin-top: 2px; }
.project-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gutter); align-items: start; }

/* Cada pieza toma el ancho de su columna y su alto natural: se ve completa,
   sin recortar, y se reajusta sola al achicar la ventana. */
.project-video { width: 100%; height: auto; display: block; background: var(--ph-a); }

.projects-empty { grid-column: 1 / -1; padding: 0 var(--pad); font-size: var(--fs-base); color: var(--muted); }

.ph {
  background-size: 100% 100%; background-position: center;
  background-color: var(--ph-a);
  aspect-ratio: 4 / 5; /* provisorio hasta que carga la imagen (ver main.js) */
  position: relative;
}
.ph.empty {
  background: repeating-linear-gradient(45deg, var(--ph-a), var(--ph-a) 10px, var(--ph-b) 10px, var(--ph-b) 20px);
}
.ph.empty::after {
  content: attr(data-label);
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-base); letter-spacing: 0.04em; text-transform: uppercase;
  color: rgba(0,0,0,0.45); text-align: center; padding: var(--gutter);
}

/* Info page — dos columnas reales (about--page del sitio de referencia):
   izquierda = oficinas + sobre nosotros; derecha = contacto + (redes/boletín
   en fila) + créditos. Nunca todo apilado en una sola columna. */
.info-page main { padding: 0 var(--pad) calc(var(--pad) * 2); }
.about-page {
  display: grid; grid-template-columns: 1fr 1fr; gap: calc(var(--pad) * 2);
}
.about-column { display: flex; flex-direction: column; gap: var(--pad); }

.section-label { font-size: var(--fs-base); font-weight: 700; letter-spacing: 0.08em; margin: 0 0 var(--gutter); text-transform: uppercase; }
.section-body { font-size: var(--fs-base); line-height: 1.7; margin: 0; }
/* Mismo peso que section-label, pero en minúsculas (sin uppercase). */
.about-tagline { font-size: var(--fs-base); font-weight: 700; letter-spacing: 0.08em; line-height: 1.7; margin: var(--gutter) 0 0; }

.info-locations { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--pad); }
.info-office .section-body { margin-bottom: var(--gutter); }
.info-office .clock { font-size: var(--fs-base); font-weight: 700; }
.info-office .clock .utc { font-weight: 400; opacity: 0.55; margin-left: 4px; }

.info-contact-list { display: flex; flex-direction: column; gap: var(--pad); }
.info-contact-item .section-label { margin-bottom: 6px; }

/* Redes (1fr) y boletín (3fr) van en la misma fila, como en el original. */
.info-footer { display: grid; grid-template-columns: 1fr 3fr; gap: var(--pad); }
.info-socials { display: flex; flex-direction: column; gap: 4px; }
.info-socials a { font-size: var(--fs-base); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; }
.info-socials a:hover { opacity: 0.4; }

.newsletter-row {
  display: flex; justify-content: space-between; align-items: center;
  border-bottom: 1px solid currentColor; padding-bottom: var(--gutter);
}
.newsletter-row input {
  border: none; background: none; outline: none;
  font-size: var(--fs-base); flex-grow: 1; color: inherit; font-family: inherit;
}
.newsletter-row input::placeholder { color: inherit; opacity: 0.5; }
.newsletter-row button {
  border: none; background: none; font: inherit; cursor: pointer; color: inherit;
  font-size: var(--fs-base); font-weight: 700; letter-spacing: 0.06em; white-space: nowrap; text-transform: uppercase;
}
.newsletter-row button:hover { opacity: 0.55; }

.info-credits { font-size: var(--fs-base); line-height: 1.7; opacity: 0.6; margin-top: auto; }

@media (max-width: 900px) {
  .about-page { grid-template-columns: 1fr; }
  .info-locations { grid-template-columns: 1fr; }
  .info-footer { grid-template-columns: 1fr; }
}

/* Visor a pantalla completa (clic en una foto), como el "project-slider" de
   Artlist: fondo beige de la web, pieza completa centrada (object-fit: contain), datos
   a la izquierda a media altura, CLOSE arriba a la derecha y el contador
   "01/05" acompañando al cursor. Clic en la mitad izquierda = anterior,
   derecha = siguiente; también flechas y Esc. */
.viewer {
  position: fixed; inset: 0; z-index: 100; background: var(--bg); cursor: none;
}
.viewer[hidden] { display: none; }
.viewer-stage {
  position: absolute; inset: 0;
  padding: calc(var(--pad) * 2.5) 16vw;
}
.viewer-stage img, .viewer-stage video {
  display: block; width: 100%; height: 100%; object-fit: contain; object-position: center;
}
.viewer-info {
  position: fixed; left: var(--pad); top: 50%; transform: translateY(-50%);
  z-index: 2; pointer-events: none; display: grid; gap: 2px;
}
.viewer-info .viewer-artist { font-size: var(--fs-medium); font-weight: 700; margin-bottom: 0.2rem; }
.viewer-info .viewer-title { font-weight: 700; }
.viewer-close {
  position: fixed; top: var(--pad); right: var(--pad); z-index: 3; cursor: pointer;
  font: inherit; font-size: var(--fs-base); letter-spacing: 0.08em; text-transform: uppercase;
  background: none; border: 0; padding: 0; color: inherit;
}
.viewer-close:hover { opacity: 0.4; }
.viewer-counter {
  position: fixed; top: 0; left: 0; z-index: 4; pointer-events: none;
  font-size: var(--fs-base); white-space: nowrap; transform: translate(-50%, -50%);
}
@media (hover: none) {
  .viewer-counter { top: calc(var(--pad) * 2.5); left: auto; right: var(--pad); transform: none; }
}

/* ---------- Celular y tablet (hasta 1024 px), como la versión móvil de Artlist ----------
   El logo y el menú quedan fijos; el dedo solo desplaza la lista, que corre a
   la derecha del logo. El nombre que cruza la línea bajo el logo se agranda y
   muestra su portada mientras se desliza (ver initMobileRoster en main.js). */
@media (max-width: 1024px) {
  .logo { font-size: clamp(56px, 16vw, 112px); }

  body.home .site-header {
    position: fixed; top: 0; left: 0; right: 0; z-index: 5; pointer-events: none;
  }
  body.home .site-header a { pointer-events: auto; }
  /* Por defecto (home, fichas de talento y de proyecto) el menú sigue
     apilado arriba a la derecha, como estaba. */
  .home-nav { flex-direction: column; align-items: flex-end; gap: 6px; }
  /* En talentos/proyectos (body.home) el menú baja abajo, flotando sobre el
     contenido y sin fondo de ningún color, para no pisarse con la lista de
     nombres que arranca justo bajo el logo. */
  body.home .home-nav {
    flex-direction: row; gap: var(--pad);
    position: fixed; left: 0; right: 0; bottom: 0; top: auto; z-index: 5;
    justify-content: center; padding: 14px var(--pad);
    pointer-events: none;
  }
  body.home .home-nav a { pointer-events: auto; }
  .nav-link { font-size: 13px; }

  /* Pista de "deslizá": centrada en el ancho del logo (JS la ubica exacto
     en alignRosterIndent), a media altura de la pantalla. Aparece una vez
     sola al cargar, sube y se desvanece, vuelve a aparecer en el mismo
     lugar, baja y se desvanece — y ya no vuelve a mostrarse. */
  body.home .swipe-hint {
    display: block; position: fixed; top: 50%; z-index: 4;
    text-align: center; pointer-events: none;
    font-size: 12px; font-weight: 700; letter-spacing: 0.2em;
    text-transform: uppercase; color: inherit; opacity: 0;
    transform: translateY(-50%);
    animation: swipe-hint 4.6s ease-in-out 1;
    animation-delay: 900ms;
  }
  @keyframes swipe-hint {
    0%    { opacity: 0; transform: translateY(-50%) translateY(0); }
    10%   { opacity: 1; transform: translateY(-50%) translateY(0); }
    35%   { opacity: 0; transform: translateY(-50%) translateY(-28px); }
    50%   { opacity: 1; transform: translateY(-50%) translateY(-28px); }
    75%   { opacity: 0; transform: translateY(-50%) translateY(28px); }
    100%  { opacity: 0; transform: translateY(-50%) translateY(28px); }
  }

  body.home .roster {
    position: static; width: auto; max-width: none; min-height: 0;
    padding: 0 var(--gutter) 60px 0;
  }
  /* Los nombres largos pueden partirse en dos líneas: el aire entre nombres
     es mayor que el de las líneas de un mismo nombre. */
  .home .roster-item-wrap { padding: 4px 0; }
  .home .roster-item { font-size: 14px; line-height: 1.25; }
  .home .roster-item-clone {
    font-size: 19px; white-space: normal; width: calc(100% / 0.8);
    overflow-wrap: anywhere; pointer-events: none;
  }
  /* Nombres largos con cliente reconocido (ver split_brand_name en
     generate.py): si el nombre completo no entra en una línea, que el corte
     caiga justo después de la MARCA y no en cualquier palabra. El "rest" va
     sin poder partirse internamente (nowrap), así el navegador lo manda
     entero a la línea siguiente cuando no entra; si el nombre completo SÍ
     entra en una línea (ej. "LIVERPOOL FW26"), sigue en una sola línea como
     antes. */
  .roster-name-rest { white-space: nowrap; }

  /* La portada queda detrás de toda la lista (antes tapaba todo menos el
     nombre activo, y no se podía ver ni tocar el resto mientras se deslizaba). */
  /* La capa se pasa 100 px por arriba y por abajo de la pantalla: los
     navegadores del celular muestran u ocultan sus barras al deslizar y, si la
     capa mide justo lo que la pantalla, quedan franjas rojas arriba y abajo. */
  .roster-medias {
    z-index: 2; inset: auto; left: 0; right: 0; top: -100px;
    height: calc(100vh + 200px);
    height: calc(100lvh + 200px);
  }
  .roster-item-wrap { z-index: 3; }

  /* Sin mouse, portada y nombre agrandado solo se ven mientras se desliza
     ("is-focusing" lo pone main.js). */
  .roster-media.active { opacity: 0; }
  body.is-focusing .roster-media.active { opacity: 1; }
  .roster-item-wrap.is-active .roster-item { opacity: 1; }
  .roster-item-wrap.is-active .roster-item-clone { opacity: 0; }
  body.is-focusing .roster-item-wrap.is-active .roster-item { opacity: 0; }
  body.is-focusing .roster-item-wrap.is-active .roster-item-clone { opacity: 1; }
}

/* ---------- Fichas de talento y de proyecto en celular (hasta 700 px) ----------
   Como Artlist en vertical: todo en una sola columna, el título de cada grupo
   pegado arriba mientras se ven sus fotos y las fotos a todo el ancho. */
@media (max-width: 700px) {
  .artist-grid {
    grid-template-columns: 1fr;
    grid-template-areas: "title" "nav" "bio" "sections";
    row-gap: var(--gutter);
  }
  .artist-nav { flex-wrap: wrap; gap: var(--gutter) var(--pad); }
  /* Si las categorías no caben en una fila, pasan a una segunda, centradas. */
  .artist-v2 .artist-nav { flex-wrap: wrap; gap: 6px var(--gutter); width: max-content; max-width: calc(100vw - var(--pad) * 2); }
  .meta-cols { grid-template-columns: 1fr 1fr; }

  /* Ficha nueva: portada casi a pantalla completa, logo arriba y nombre abajo. */
  .artist-v2 .artist-grid { grid-template-areas: "bio" "nav"; row-gap: var(--pad); }
  .artist-v2 .artist-name { font-size: clamp(40px, 12.5vw, 72px); }
  /* Nombres largos: MARCA en una línea y el resto del nombre del proyecto
     debajo, en vez de cortar en cualquier palabra. El resto va en un tamaño
     menor para que entre en una sola línea (el más largo, "DRIVING CENTER",
     mide bastante más que cualquier marca). */
  .artist-name-brand, .artist-name-rest { display: block; }
  .artist-name-rest { font-size: clamp(30px, 9.5vw, 54px); }
  /* Celular: el link va abajo a la derecha, alineado con el borde derecho del
     menú, y el nombre sube lo justo para dejarle lugar. */
  .artist-name-wrap { left: var(--gutter); bottom: calc(var(--gutter) + 22px); }
  .artist-download { right: calc(var(--pad) + var(--gutter)); top: auto; bottom: var(--gutter); transform: none; }
  .artist-v2.name-docked .artist-download { top: calc(var(--nav-bottom, 64px) + 20px + 8px); bottom: auto; }
  .artist-v2 .site-header { padding: calc(var(--pad) + var(--gutter)); }
  .artist-v2.name-docked .artist-name-dock { right: calc(var(--pad) + var(--gutter)); font-size: 17px; }
  /* En celular la portada sigue como antes: a todo el ancho, casi a pantalla
     completa y recortada para llenar (el formato original es solo de escritorio). */
  .artist-cover-frame { width: 100%; min-height: 0; }
  .artist-cover-frame img, .artist-cover-frame video,
  .artist-cover-frame.is-horizontal img, .artist-cover-frame.is-horizontal video,
  .artist-cover-frame.is-vertical img, .artist-cover-frame.is-vertical video {
    width: 100%;
    height: min(calc(100vh - 2 * var(--pad)), 150vw);
    height: min(calc(100svh - 2 * var(--pad)), 150vw);
    min-height: 360px;
    object-fit: cover; object-position: center 30%;
  }

  .artist-video { grid-template-columns: 1fr; }
  .project { grid-template-columns: 1fr; margin-bottom: calc(var(--pad) * 1.5); }
  .project > div:first-child { top: 0; padding: var(--gutter) 0; }
  .artist-v2 .project > div:first-child { top: var(--dock-top, 0); }
  .project-grid { grid-template-columns: 1fr; }

  /* Visor: la pieza ocupa casi todo el ancho y los datos van arriba. */
  .viewer-stage { padding: calc(var(--pad) * 3) var(--gutter) var(--pad); }
  .viewer-info { top: var(--pad); left: var(--pad); transform: none; }
}

/* ---------- Grilla de 5 columnas (fichas nuevas, body.artist-v2) ----------
   Como el portafolio de referencia: las fotos ocupan 1, 2, 3, 4 o las 5
   columnas ("cols" en el JSON) y cada una conserva su alto según su
   proporción. Los títulos de grupo flotan encima, sin ocupar lugar. */
/* Entre fotos: 20 px de lado a lado (como estaba) y el espacio entre filas es cuatro veces el anterior (24 px -> 96 px). */
.artist-v2 { --col-gap: 20px; --row-gap: calc(var(--pad) * 4); }
.artist-v2 .project { display: block; position: relative; }
.artist-v2 .project > div:first-child {
  position: sticky; top: var(--dock-top, var(--pad)); height: 0; z-index: 3;
  padding-right: 0; overflow: visible; background: none;
}
.artist-v2 .project-grid {
  grid-template-columns: repeat(5, 1fr); gap: var(--row-gap) var(--col-gap); align-items: start;
}
.artist-v2 .project-grid .ph { grid-column: var(--col, auto) / span var(--cols, 2); }
.ph-fill { grid-column: span var(--cols, 1); height: 0; pointer-events: none; }
@media (max-width: 700px) {
  .ph-fill { display: none; }
  .artist-v2 .project-grid { grid-template-columns: 1fr; }
  .artist-v2 .project-grid .ph { grid-column: auto; }
}

/* Sin títulos de grupo (Selected, Celebrities…) flotando sobre la grilla. Siguen
   en el HTML: el visor los usa para mostrar el nombre del grupo. */
.artist-v2 .project > div:first-child { display: none; }

/* ---------- Proyectos con el formato nuevo ---------- */
/* Sin menú de categorías ni ficha vacía arriba de la grilla. */
.project-page .artist-grid { display: none; }
.project-page .artist-nav { display: none; }

/* Fila INFO / FOTÓGRAFOS / DIRECTORES / PARTNER / TEAM: cinco columnas
   alineadas con la grilla de fotos, cada texto pegado al borde izquierdo de su columna. */
.info-cols {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 0 var(--col-gap, 20px);
  padding: var(--pad) var(--pad) calc(var(--pad) * 2);
}
.info-col h2 {
  margin: 0 0 var(--gutter); font-size: var(--fs-base); font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
}
.info-col p { margin: 0 0 6px; font-size: var(--fs-base); line-height: 1.5; }
.artist-v2 .project-grid .project-video-wrap { grid-column: var(--col, auto) / span var(--cols, 3); }
.project-video-wrap { position: relative; color: var(--accent); }
.project-video-wrap .project-video { width: 100%; height: auto; display: block; cursor: pointer; }
/* Los controles van sobre la imagen, en texto rojo y sin fondo (nada opaca el film). */
.project-video-wrap .vc { position: absolute; left: 14px; right: 14px; bottom: 12px; padding-top: 0; z-index: 2; }
/* Clips en loop dentro de la grilla del proyecto (sin controles, como el video de portada). */
.artist-v2 .project-grid .project-video-loop { grid-column: var(--col, auto) / span var(--cols, 3); }
.project-video-loop video { width: 100%; height: auto; display: block; }
@media (max-width: 700px) {
  .info-cols { grid-template-columns: 1fr; gap: var(--pad); }
  .info-col.is-empty { display: none; }
  .artist-v2 .project-grid .project-video-wrap { grid-column: auto; }
  .artist-v2 .project-grid .project-video-loop { grid-column: auto; }
}

/* Controles propios de los videos: una fila de texto debajo (o al pie del
   visor), sin nada encima del film. */
.vc {
  display: flex; align-items: center; gap: var(--pad); padding-top: 10px;
  font-size: var(--fs-base); letter-spacing: 0.08em; text-transform: uppercase; white-space: nowrap;
}
.vc button {
  background: none; border: 0; padding: 0; margin: 0; cursor: pointer;
  font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit;
}
.vc button:hover { opacity: 0.4; }
.vc-bar { position: relative; flex: 1; height: 13px; cursor: pointer; }
.vc-bar::before { content: ""; position: absolute; left: 0; right: 0; top: 6px; height: 1px; background: currentColor; opacity: 0.3; }
.vc-bar span { position: absolute; left: 0; top: 6px; height: 1px; width: 0; background: currentColor; }
.viewer-stage .vc {
  position: absolute; left: calc(var(--pad) * 2.5); right: calc(var(--pad) * 2.5); bottom: var(--pad);
  padding-top: 0; cursor: auto;
}
.viewer-stage video { height: calc(100% - 28px); }

/* Triángulo de play, rojo y centrado sobre el video; se oculta mientras corre. */
.vc-big {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 2;
  width: clamp(48px, 5vw, 76px); height: clamp(48px, 5vw, 76px);
  padding: 0; border: 0; background: none; cursor: pointer; color: var(--accent); display: block;
}
.vc-big svg { display: block; width: 100%; height: 100%; }
.vc-big:hover { opacity: 0.7; }
.is-playing > .vc-big { display: none; }
.viewer-stage { color: var(--accent); }

/* Videos dentro de los portafolios de talentos: mismo control que en los proyectos,
   con el título del video debajo. */
.project-video-item { margin: 0; grid-column: var(--col, auto) / span var(--cols, 2); }
.project-video-item figcaption {
  margin-top: 10px; font-size: var(--fs-base); letter-spacing: 0.08em; text-transform: uppercase;
}
@media (max-width: 700px) { .project-video-item { grid-column: auto; } }

/* ---------- Home (prueba): entrada del sitio con proyectos en la grilla de 5
   columnas de los portafolios, cada pieza es un link directo al proyecto. ---------- */
body.home-preview { background: var(--accent); color: #fff; }
/* Logo y menú quedan fijos, flotando sobre el primer proyecto (igual que en
   las fichas de talento/proyecto), sin ocupar espacio propio: por eso la
   grilla empieza con el mismo margen arriba que a los costados. */
body.home-preview .site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 20;
  padding: var(--pad); pointer-events: none;
}
body.home-preview .site-header a { pointer-events: auto; }
/* Escritorio: home y fichas de talento/proyecto comparten la misma
   geometría de header — 48 px de margen (logo a la izquierda, menú a la
   derecha) y el menú arranca a la altura del borde superior de las letras
   del logo (la "N" y la "T" empiezan ~9,4 px más abajo que la caja del
   menú). Antes el home tenía 24 px y el menú pegado al borde de la imagen. */
@media (min-width: 701px) {
  body.home-preview .site-header { padding: calc(var(--pad) * 2); }
  body.home-preview .home-nav,
  .artist-v2 .home-nav { margin-top: 9.4px; }
}
.home-grid {
  --col-gap: 20px; --row-gap: calc(var(--pad) * 9);
  display: grid; grid-template-columns: repeat(5, 1fr);
  gap: var(--row-gap) var(--col-gap);
  padding: var(--pad) var(--pad) calc(var(--pad) * 4);
}
.home-tile { grid-column: var(--col, auto) / span var(--cols, 2); margin: 0; }
.home-tile .ph { width: 100%; display: block; }
/* Portada en video: se ve corriendo (autoplay/mute/loop), no una foto fija.
   Es "home-tile-video", no ".ph" — initPlaceholders() marca como "vacío" (con
   rayas) cualquier ".ph" sin "data-src", y este no lo necesita. */
.home-tile-video { position: relative; display: block; overflow: hidden; cursor: pointer; background: var(--ph-a); }
.home-tile-video video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.home-tile figcaption {
  margin-top: 10px; font-size: var(--fs-base); font-weight: 100;
  letter-spacing: 0.1em; text-transform: uppercase;
}
@media (max-width: 700px) {
  /* Solo en el home: en vez del logo de texto en vivo (que depende de JS
     midiendo tipografía en cada dispositivo — eso era lo que terminaba
     desalineándose o desbordando según el navegador), se usa un SVG fijo
     con el formato ya resuelto (ver assets/icons/logo-nt-mit.svg, generado
     una vez a partir de la alineación correcta). Al ser vectorial escala
     sin recalcular nada: mismo resultado siempre. Flota al pie, grande,
     sin ser clickeable (ya estamos en el home, y taparía proyectos de la
     grilla al scrollear). Al ocultar ".logo" (único hijo visible que
     quedaba en el flex del site-header), el menú se iba a la izquierda con
     el space-between normal — por eso el margin-left:auto. */
  body.home-preview .logo { display: none; }
  body.home-preview .home-logo-float {
    display: block; position: fixed; left: 50%; bottom: var(--pad);
    transform: translateX(-50%); z-index: 21; width: 100vw;
    pointer-events: none;
  }
  body.home-preview .home-nav { margin-left: auto; }

  .home-grid {
    grid-template-columns: repeat(2, 1fr); padding-top: var(--pad);
    --row-gap: calc(var(--pad) * 2.25);
  }
  .home-tile { grid-column: span 2; }
  /* Las fotos sueltas (1 columna en desktop) van de a 2 por fila. */
  .home-tile.home-tile-half { grid-column: span 1; }
  /* Algunas fotos sueltas solo se ven en desktop (recorte curado en mobile). */
  .home-tile.home-tile-mobile-hide { display: none; }
  /* Video de portada con un recorte aparte (ej. 4:5) para mobile. Con
     !important porque el aspect-ratio de desktop va inline (pisa cualquier
     regla de hoja de estilos que no lo lleve). */
  .home-tile-video.home-tile-video-mobile-crop { aspect-ratio: var(--aspect-mobile) !important; }
}

/* Videos de YouTube incrustados en las fichas de talentos (mismo ancho/posición que un video). */
.embed-item { margin: 0; grid-column: var(--col, auto) / span var(--cols, 2); }
.embed-wrap { position: relative; width: 100%; aspect-ratio: 16 / 9; background: #000; }
.embed-wrap iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.embed-item figcaption {
  margin-top: 10px; font-size: var(--fs-base); letter-spacing: 0.08em; text-transform: uppercase;
}
@media (max-width: 700px) { .embed-item { grid-column: auto; } }

/* Fotos de las fichas con nombre debajo (campo "caption" de la foto). */
.photo-item { margin: 0; grid-column: var(--col, auto) / span var(--cols, 2); }
.photo-item figcaption {
  margin-top: 10px; font-size: var(--fs-base); letter-spacing: 0.08em; text-transform: uppercase;
}
@media (max-width: 700px) { .photo-item { grid-column: auto; } }

/* Ficha oculta "IA": cada trabajo lleva su título arriba de sus fotos. */
.artist-v2.ia-page .project > div:first-child {
  display: block; position: static; height: auto; overflow: visible;
  padding: calc(var(--pad) * 1.5) var(--pad) 12px;
}
.artist-v2.ia-page .project > div:first-child:has(.project-title:empty) { display: none; }
.ia-page .project-title { font-size: var(--fs-base); letter-spacing: 0.08em; text-transform: uppercase; font-weight: 400; }
/* 12 categorías no caben en una línea: el menú flotante se parte en dos. */
.artist-v2.ia-page .artist-nav { flex-wrap: wrap; width: max-content; max-width: min(1100px, calc(100vw - var(--pad) * 2)); gap: 6px var(--gutter); }
