/* ============================================================
   Fonda Lady Inés · landing de evento
   Referencia: source/LANDING-LADY-INES-ok.png, 1080 × 3422 px.
   Cada banda es un lienzo con la proporción de su franja en la
   maqueta y sus piezas colocadas en % de esos 1080 px. Como todo
   lo visible es imagen (cintas, titulares, lineups, CTA), el
   porcentaje escala el conjunto sin reflujo de texto.
   Colores medidos en la tarea 1.5 (INVENTARIO.md).
   ============================================================ */

:root {
  --rojo: #ea5050;
  --azul: #507ec0;
  --negro: #030405;
  --arena: #e3cda2; /* tostado visible, medido en la maqueta */
  --tinte-arena: #efbd4d; /* el tinte que, al 32 % sobre el fondo, da --arena */
  --yeso: #d7d2cb;
  /* La tinta de los marcos: mediana del borde del póster del hero (26,28,27).
     Es el único negro de la maqueta que hace de marco, así que lo usan las dos
     secciones que enmarcan en vez de pintar sobre yeso — hero y vídeo. */
  --marco: #1a1c1b;
  /* El pie no es marco: en la maqueta es vino tinto, no negro (1.5). Este es el
     tinte que se MULTIPLICA sobre el granito, ajustado por canal contra la
     maqueta (57,14,22); el pie compuesto sale en 47-50,12,18. Ver `.banda--pie`. */
  --vino: #390e16;
  --ancho: 1080px;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* 3.12 · Foco visible en todo lo enfocable. Los CTA lo afinan más abajo; esto
   cubre el resto (cabecera, cerrar del modal, vía alternativa de compra). */
:focus-visible {
  outline: 3px solid var(--rojo);
  outline-offset: 3px;
}

html {
  scroll-behavior: smooth;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  background: var(--yeso);
  color: var(--negro);
  font-family:
    system-ui,
    -apple-system,
    'Segoe UI',
    Roboto,
    sans-serif;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}

h1,
h2,
h3,
p {
  margin: 0;
}

.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- Cabecera Eventrid ----------
   Portada de `evolucion-insurtech-latam-2026/styles.css`, mismos nombres de
   clase y mismas medidas (logo 130-170 px, fila centrada al ancho del cuerpo).
   Dos cambios: el degradado usa la tinta de los marcos de esta landing en vez
   del azul de aquella, y la barra es `sticky` en vez de `fixed`, que es lo que
   hacen las otras cinco landings con `sticky-top` de Bootstrap — así no hay que
   compensar el alto con relleno en `.fonda` ni rehacerlo por breakpoint.
   z-index 50: por encima de la página, por debajo del modal (999). */
.eventrid-header {
  position: sticky;
  top: 0;
  z-index: 50;
  padding: 0.75rem clamp(1.25rem, 5vw, 4rem);
  background: linear-gradient(
    90deg,
    var(--marco) 0%,
    #2f3331 50%,
    var(--marco) 100%
  );
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

.eventrid-header__inner {
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.eventrid-header__brand {
  display: inline-flex;
  align-items: center;
}

.eventrid-header__logo {
  width: clamp(130px, 17vw, 170px);
}

.eventrid-header__cta {
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.18);
  color: #fff;
  text-decoration: none;
  font-family: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.42rem 1rem;
  border-radius: 999px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  transition: all 0.2s ease;
}

.eventrid-header__cta:hover {
  background: var(--rojo);
  border-color: var(--rojo);
  color: #fff;
  text-decoration: none;
  box-shadow: 0 4px 14px rgba(234, 80, 80, 0.4);
  transform: translateY(-1px);
}

.eventrid-header__cta:active {
  transform: translateY(0) scale(0.98);
}

.fonda {
  position: relative;
  display: block;
  isolation: isolate;
  overflow-x: clip;
}

/* Las bandas van a sangre; el contenido se centra en 1080 px (design.md D6). */
.banda {
  position: relative;
  width: 100%;
  z-index: 1;
}

/* Scroll margin compensando la cabecera sticky (64 px en escritorio, 48 px en móvil) */
.banda[id] {
  scroll-margin-top: 4.5rem;
}

/* En escritorio la cinta de viernes tiene top: -12.97% (desborda por arriba de la banda) */
#dia-vie {
  scroll-margin-top: 9rem;
}
.lienzo {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--ancho);
  margin-inline: auto;
}

/* En escritorio ninguna banda se queda en 1080: el tope se levanta y cada lienzo
   ocupa el ancho del viewport conservando su proporción de la maqueta, así que
   toda la página escala en bloque en vez de quedarse en una columna centrada con
   la textura a sangre a los lados. El alto crece con el ancho — es el trato: se
   conserva el aspecto, no la altura.

   `--ancho` no se retira: lo sigue usando `.eventrid-header__inner`, que es cromo
   del sitio y no una sección de la landing, y por eso se queda centrado en 1080
   como en las otras landings de `public/`.

   Va en `min-width: 769px` por lo mismo que el hero: por debajo el layout ya es
   una columna apilada y `.lienzo` no llega nunca a los 1080, así que el tope no
   pinta nada y el móvil no cambia.

   Techo conocido, no defecto: cada foto trae UN candidato en su `srcset`, a 2x
   del tamaño de presentación en 1080 (656 px -> 1312w). A 1920 la misma foto se
   pinta a ~1166 px, así que la densidad efectiva cae de 2,0x a 1,13x: nítida a
   DPR 1, blanda en un monitor ancho y denso. Subirla pide reexportar los assets
   con `work/build.py`, que vive fuera del repo. */
@media (min-width: 769px) {
  .lienzo {
    max-width: none;
  }
}

.pieza {
  position: absolute;
}

.pieza img,
.logo,
.ico {
  width: 100%;
  height: auto;
}

/* Las fotos van por debajo: las cintas, los titulares y los iconos las cruzan. */
.foto {
  display: block;
  z-index: 0;
}

/* ---------- fondos ----------

   `tex-fondo.webp` es el fondo YA APLANADO a 1080x3422, no una textura que el navegador
   tenga que colocar. Lo compone `work/fondo.py` reproduciendo el stack real del `.ai`,
   que no es un muro opaco: sobre la página blanca van cinco pintadas con blend mode —
   el yeso en `Darken` al 31 %, el MISMO yeso otra vez en `ColorBurn` al 25 %, y la
   textura ocre tres veces en `Multiply` (73 %, 94 % y 74 %), la última volteada y caída
   justo sobre la banda de jueves. Ese tercer ocre es el óxido que antes faltaba: la
   «coloración distinta» del fondo no salía de teñir el yeso ni de ningún color plano.

   Servirlo aplanado quita el problema que traía la textura suelta: ya no hay que acertar
   ni la escala (`min(200.741%, 2168px)`, que se desfasaba hasta 665 px al pie por debajo
   de 1080 px de viewport) ni el color a base de `filter`. `100% 100%` estira la capa a la
   caja de `.fonda`, así que el óxido acompaña a su banda aunque el alto real se desvíe
   del de la maqueta.

   Contra `LANDING-LADY-INES-ok.png`, el fondo compuesto queda en |Δ| 4-6 niveles por
   canal (bandas y1750-2050, y600-820 y la del óxido y470-1180).

   Las bandas tostadas NO están en ese stack: son cuatro rellenos `scn` del content
   stream, y siguen aquí como capa de tinte (maqueta: mediana 227,208,168, desviación
   13-22), no un color plano. Y su límite NO es horizontal: medido sobre
   `LANDING-LADY-INES-ok.png` con ajuste robusto, la arena entra por
   `y = 1029,2 + 0,03648·x` (+2,09°, rms 0,8 px) y sale por `y = 1648,8 − 0,02935·x`
   (−1,68°, rms 0,3 px). Los otros dos límites sí son rectos: 2190 y 2639.

   Ambas capas van en z-index negativo dentro de `.fonda`, que aísla el contexto: así el
   tinte de viernes queda por debajo de TODO el contenido aunque su franja se meta en la
   banda de jueves, y los pies de la foto de Moral Distraída se ven encima de la arena. */

.fonda::before,
.banda--arena::before,
.banda--pie::before {
  content: '';
  position: absolute;
  inset: 0;
}

/* El alto NO es `100% 100%`. La composición reproduce la página de la maqueta
   entera, hero incluido, y su franja superior está hecha para quedar debajo de él:
   papel liso 243,245,247 con sd 0,0 hasta la fila 420 (el `.ai` corta en la 423 —
   «el yeso solo cubre de y=423 hacia abajo», `work/fondo.py`), y el canto duro con
   el que entra el óxido en la 469 (el calor R−B salta de 1,6 a 12,6 en una sola
   fila). Las dos quedan por encima de la 511, que es donde acaba el hero en la
   maqueta (`aspect-ratio: 1080/511`), así que allí no se ven.

   En escritorio el hero ya no es esa proporción sino `100svh - 4rem`, y con
   `100% 100%` la capa se estiraba a la página entera: la fila 511 dejaba de caer en
   el borde del hero y las dos costuras asomaban debajo — el papel como franja blanca
   (96 px a 1920x760, 87 a 2000x800, 141 a 2560x950) y el óxido como una raya
   horizontal cruzando la banda de jueves.

   Se ancla abajo y se escala para que las 2911 filas que van por debajo de la 511
   cubran exactamente lo que hay debajo del hero: `(100% - alto del hero) * 3422/2911`.
   Así la fila 511 vuelve a caer en el borde del hero, las dos costuras quedan tapadas
   por él y recortadas por arriba, y el óxido vuelve a caer sobre la banda de jueves
   (a 1920 px de ancho acaba en el 1180 de la maqueta contra los 1172 que mide la
   banda). El factor sale del asset y de la proporción del hero en la maqueta: si
   `fondo.py` cambia el recorte, cambia con él. Los 4rem son la cabecera, los mismos
   de `.lienzo--hero`.

   En móvil no aplica: el bloque de `max-width: 768px` sustituye imagen, posición,
   repetición y tamaño por la franja que sí repite. */
.fonda::before {
  z-index: -2;
  background: url(../img/tex-fondo.webp) center bottom no-repeat;
  background-size: 100% calc((100% - (100vh - 4rem)) * 1.1756);
  background-size: 100% calc((100% - (100svh - 4rem)) * 1.1756);
}

.banda--arena::before {
  z-index: -1;
  background: var(--tinte-arena);
  opacity: 0.32;
}

/* La franja tostada de viernes empieza dentro de la banda de jueves y acaba dentro de la
   de sábado, así que su capa se desborda por arriba y por abajo y se corta en diagonal.
   Caja: y 1000-1700 de la maqueta; banda 1170-1643, alto 473. */
.banda--vie::before {
  top: -35.94%;
  bottom: -12.05%;
  clip-path: polygon(0 4.17%, 100% 9.87%, 100% 88.16%, 0 92.69%);
}

.banda--hero,
.banda--video {
  background: var(--marco);
}

/* El pie no es un plano de color: es el mismo granito del resto de la página visto a
   través de una tinta vino. Comprobado sobre la maqueta — el grano del pie correlaciona
   0,83 con `tex-fondo.webp` en esas mismas coordenadas, así que es la misma textura, sin
   desplazar. El modelo que ajusta es multiplicar, no cubrir con opacidad: por canal,
   maqueta = textura x `--vino` / 255 deja residuo 3,1 / 1,1 / 1,7 niveles, mientras que
   una capa plana con opacidad exigiría tintes negativos en verde y azul.

   Se multiplica contra la capa de `.fonda::before`, que ya cubre esta banda, en vez de
   traer un recorte del granito: un asset menos y ni un byte más. `--vino` es la tinta del
   multiplicado (57,14,22), no el color resultante — el pie compuesto sale en 50,12,18. */
.banda--pie::before {
  z-index: -1;
  background: var(--vino);
  mix-blend-mode: multiply;
}

/* ---------- 1 · hero ---------- */

.lienzo--hero {
  aspect-ratio: 1080 / 511;
}

/* El póster va en la MISMA caja que el vídeo: absoluto y `cover`. En flujo, con
   el `height: auto` global de `img`, conservaba su relación propia (2160/1021) e
   ignoraba el alto del hero — que en escritorio es `100svh - 4rem`, no una
   proporción — así que en una pantalla baja se salía por debajo y se montaba
   sobre la banda de jueves. Ahora el respaldo y el vídeo recortan igual siempre. */
.hero__logo {
  position: absolute;
  inset: 0;
  line-height: 0;
}

.hero__logo picture,
.hero__logo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* 3.10 · El vídeo cubre el póster, que sigue debajo haciendo de <h1>. `poster`
   en el propio elemento es lo que se ve mientras carga y si el mp4 falla, y el
   navegador le aplica el mismo `object-fit`, así que aquí no hace falta nada
   más. Lo que recorta `cover` depende de la caja, que ya no es una sola: ver
   `.lienzo--hero` y el bloque de escritorio de abajo. */
.hero__video {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* En escritorio el hero deja de ser la franja de la maqueta y pasa a llenar la
   pantalla: el vídeo la cubre entera, siempre, sin el marco lateral que dejaba
   el tope de 1080 px. Va en `min-width: 769px` — el complemento exacto del
   breakpoint móvil de abajo — para que el móvil no cambie ni un píxel: ahí el
   hero sigue siendo la banda 1080/511 apilada sobre la banda de datos, que es
   la que lleva el rótulo legible de sede y fechas.

   Se le restan los 4rem de `.eventrid-header`. La cabecera es `sticky` con
   `z-index: 50`, así que está siempre encima: con `100svh` a secas el hero mide
   la pantalla entera pero su franja inferior nace ya fuera del pliegue, y lo que
   se ve del vídeo son los mismos 836 px de todos modos. Restándola, el hero
   ocupa exactamente el hueco visible y no queda nada cortado. Los 4rem son la
   altura medida de la cabecera en escritorio (64 px a 1024, 1440 y 1920): si se
   toca su `padding` o el cuerpo de `.eventrid-header__cta`, este número va con
   ella.

   El precio es el recorte: el mp4 es 1920x900 (2,133) y el hueco visible va de
   1,72 (1440x836) a 1,89 (1920x1016), así que `cover` escala a lo alto y se come
   entre el 11 % y el 19 % del ancho del clip, la mitad por cada lado. Es la
   decisión tomada: llenar la pantalla manda sobre encuadrar el clip. El póster
   que hay debajo se recorta igual, así que el respaldo no se desalinea con el
   vídeo.

   `svh` y no `vh`: en un navegador móvil ancho (tablet en horizontal) `vh`
   cuenta con las barras retraídas y el hero se pasa de alto al cargar. Se deja
   `vh` delante como respaldo para quien no entienda `svh`. */
@media (min-width: 769px) {
  .lienzo--hero {
    aspect-ratio: auto;
    height: calc(100vh - 4rem);
    height: calc(100svh - 4rem);
  }
}

/* ---------- identidad en texto real ----------
   La maqueta no la dibuja: el hero es un ráster con el nombre, la sede y las
   fechas incrustados. Se mantiene en el cuerpo para buscadores y lectores de
   pantalla, y se hace visible en móvil, donde ese texto no se lee (3.15). */

.banda--datos {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
}

/* ---------- 2 · jueves 17 ---------- */

.lienzo--jue {
  aspect-ratio: 1080 / 659;
}

.foto--jue {
  right: 0;
  top: 13.99%;
  width: 60.73%;
}

/* Carpeta 8: «La previa» deja de ser una pastilla centrada sobre la cinta de fecha y
   pasa a banderola en diagonal clavada en la esquina superior izquierda de la banda,
   cortada por los dos bordes. De ahí que vaya a 0,0: la pieza ES su caja envolvente. */
.cinta--previa {
  left: 0;
  top: 0;
  width: 20.93%;
}

/* Al quitarse la pastilla de encima, la cinta, el titular y el lineup bajan 14 px en la
   maqueta. Los CTA no se mueven. */
.cinta--jue {
  left: 2.5%;
  top: 15.02%;
  width: 52.65%;
}

.titular--jue {
  left: 14.17%;
  top: 27.47%;
  width: 29.1%;
}

.lineup--jue {
  left: 12.31%;
  top: 53.57%;
  width: 33.21%;
}

.cta--vecino {
  left: 8.46%;
  top: 67.37%;
  width: 18.24%;
  aspect-ratio: 197 / 55;
  background-image: url(../img/btn-gratis-tarjeta-vecino.webp);
}

.cta--compra-jue {
  left: 28.24%;
  top: 67.37%;
}

.ico--volantin {
  left: 45.77%;
  top: 32.27%;
  width: 7.07%;
}

/* ---------- 3 · viernes 18 ---------- */

.lienzo--vie {
  aspect-ratio: 1080 / 473;
}

.foto--vie {
  left: 0;
  top: -6.47%;
  width: 59.55%;
}

.cinta--vie {
  left: 41.33%;
  top: -12.97%;
  width: 56.02%;
}

/* El titular perdió la tilde de la «A» (el cliente escribe «LOS VASQUEZ», como el
   original que entregó). Al recortarse por la tinta, la pieza empieza ahora en la punta
   de la «V» y no en la tilde: 9,67 px más abajo en la maqueta de 1080. */
.titular--vie {
  left: 51.85%;
  top: 7.26%;
  width: 38.09%;
}

.lineup--vie {
  left: 52.99%;
  top: 28.19%;
  width: 36.98%;
}

.cta--compra-vie {
  left: 59.35%;
  top: 72.09%;
}

.ico--mote {
  left: 2.04%;
  top: -6.41%;
  width: 9.75%;
}

/* ---------- 4 · sábado 19 ---------- */

.lienzo--sab {
  aspect-ratio: 1080 / 547;
}

.foto--sab {
  left: 53.36%;
  top: -4.57%;
  width: 43.64%;
}

.cinta--sab {
  left: 4.85%;
  top: 5.24%;
  width: 56.79%;
}

.titular--sab {
  left: 18.06%;
  top: 27.97%;
  width: 31.6%;
}

.lineup--sab {
  left: 16.39%;
  top: 43.69%;
  width: 36.48%;
}

.cta--compra-sab {
  left: 22.5%;
  top: 82.08%;
}

.ico--empanada {
  left: 7.69%;
  top: 48.08%;
  width: 9.78%;
}

/* ---------- 5 · domingo 20 ---------- */

.lienzo--dom {
  aspect-ratio: 1080 / 450;
}

.foto--dom {
  left: 0;
  top: 0;
  width: 41.46%;
}

.cinta--dom {
  left: 36.79%;
  top: 5.7%;
  width: 56.79%;
}

.titular--dom {
  left: 37.72%;
  top: 25.11%;
  width: 54.48%;
}

/* La caja empieza en el texto (x 464) y no en x 402: hasta Carpeta 8 la pieza traia
   pegado un trozo de la foto de artista, que se solapa con ella en x (`build.py`,
   `sin_foto`). En escritorio caia sobre la foto real y no se veia; en movil viajaba
   con el lineup. */
.lineup--dom {
  left: 42.96%;
  top: 44.22%;
  width: 45.19%;
}

.cta--compra-dom {
  left: 53.52%;
  top: 80%;
}

.ico--anticucho {
  left: 89.35%;
  top: 48.44%;
  width: 7.62%;
}

/* ---------- 6 · vídeo ---------- */

.lienzo--video {
  aspect-ratio: 1080 / 530;
}

.foto--video {
  left: 0;
  top: 0;
  width: 100%;
  cursor: pointer;
}

.video__barra {
  left: 0;
  top: 86.74%;
  width: 100%;
  height: 13.26%;
  background: #0d0d0d;
}

/* ---------- 7 · footer ---------- */

.lienzo--pie {
  aspect-ratio: 1080 / 171;
}

.logo--providencia {
  left: 15.96%;
  top: 19.11%;
  width: 33.98%;
}

.logo--media-partner {
  left: 66.94%;
  top: 15.2%;
  width: 12.59%;
}

.logo--tvn {
  left: 66.85%;
  top: 28.85%;
  width: 17.19%;
}

/* ---------- CTA ---------- */

/* Sin la forma abreviada `background`: reventaría el background-image que cada
   CTA declara más arriba, en su banda. */
.cta {
  padding: 0;
  border: 0;
  background-color: transparent;
  background-repeat: no-repeat;
  background-position: center;
  background-size: 100% 100%;
  cursor: pointer;
}

.cta--compra {
  width: 23.36%;
  aspect-ratio: 252.33 / 55;
  background-image: url(../img/btn-compra-aqui.webp);
}

.cta:hover {
  filter: brightness(1.35);
}

.cta:focus-visible {
  outline: 3px solid var(--rojo);
  outline-offset: 4px;
}

.cta[aria-disabled='true'] {
  cursor: default;
  opacity: 0.45;
}

/* ---------- botón de reproducción (lo pone la landing, no el .ai) ---------- */

.play {
  position: absolute;
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.32);
  pointer-events: none;
}

.play::after {
  content: '';
  width: 44%;
  aspect-ratio: 1 / 1.15;
  margin-left: 10%;
  background: #fff;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}

.play--video {
  left: 50%;
  top: 43.37%;
  width: 8.33%;
  transform: translate(-50%, -50%);
}

/* 3.10 · El play de la sección de vídeo es un <button>, no el adorno de la
   maqueta: hay que devolverle el clic que `.play` quita y quitarle el cromo que
   el navegador le pone. `display: grid` de `.play` gana al `display: none` del
   agente de usuario, así que `[hidden]` necesita decirlo aquí. */
.video__play {
  padding: 0;
  border: 0;
  cursor: pointer;
  pointer-events: auto;
  color: inherit;
  font: inherit;
}

.video__play[hidden] {
  display: none;
}

.video__play:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 3px;
}

.video__play:hover {
  background: rgba(255, 255, 255, 0.5);
}

.video__iframe {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  border: 0;
}

/* ============================================================
   MODAL DE COMPRA — portado de evolucion-insurtech-latam-2026
   (design.md D1). El alto y el estado de error se cierran en la
   fase 3 contra una URL real.
   ============================================================ */

body.modal-open {
  overflow: hidden;
}

/* ============================================================
   MODAL SELECTOR DE FECHAS (2h) — 4 jornadas con artista y compra
   ============================================================ */

.fechas-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  padding: 1.25rem;
  overflow-y: auto;
}

.fechas-modal[hidden] {
  display: none;
}

.fechas-modal__backdrop {
  position: fixed;
  inset: 0;
  background: rgba(5, 6, 7, 0.88);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

.fechas-modal__dialog {
  position: relative;
  z-index: 1;
  width: min(1200px, 100%);
  max-height: calc(100vh - 2.5rem);
  overflow-y: auto;
  border-radius: 20px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.9);
  color: #fff;
  padding: 1.75rem 2rem 2.25rem;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  animation: fechasModalIn 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes fechasModalIn {
  from {
    opacity: 0;
    transform: scale(0.96) translateY(12px);
  }
  to {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

.fechas-modal__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.5rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

.fechas-modal__eyebrow {
  display: inline-block;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--rojo);
  margin-bottom: 0.35rem;
}

.fechas-modal__title {
  font-size: clamp(1.4rem, 2.5vw, 2.1rem);
  font-weight: 800;
  letter-spacing: -0.01em;
  color: #fff;
  margin: 0;
  line-height: 1.15;
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
}

.fechas-modal__subtitle {
  font-size: 0.95rem;
  color: rgba(255, 255, 255, 0.8);
  margin: 0.4rem 0 0;
  line-height: 1.4;
}

.fechas-modal__close {
  flex-shrink: 0;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  font-size: 1.6rem;
  line-height: 1;
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: all 0.2s ease;
}

.fechas-modal__close:hover {
  background: var(--rojo);
  border-color: var(--rojo);
  color: #fff;
  transform: rotate(90deg);
}

.fechas-modal__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.25rem;
}

.fechas-card {
  position: relative;
  display: flex;
  flex-direction: column;
  border-radius: 14px;
  border: 2px solid rgba(0, 0, 0, 0.18);
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.4);
  overflow: visible;
  transition:
    transform 0.25s cubic-bezier(0.16, 1, 0.3, 1),
    border-color 0.25s ease,
    box-shadow 0.25s ease;
  cursor: pointer;
}

.fechas-card:hover {
  transform: translateY(-6px);
  border-color: rgba(0, 0, 0, 0.35);
  box-shadow: 0 16px 36px -10px rgba(0, 0, 0, 0.7);
}

.fechas-card--jue:hover {
  border-color: #1a1c1b;
  box-shadow:
    0 16px 36px -10px rgba(0, 0, 0, 0.7),
    0 0 18px -4px rgba(26, 28, 27, 0.5);
}

.fechas-card--vie:hover {
  border-color: var(--azul);
  box-shadow:
    0 16px 36px -10px rgba(0, 0, 0, 0.7),
    0 0 20px -4px rgba(80, 126, 192, 0.45);
}

.fechas-card--sab:hover {
  border-color: var(--rojo);
  box-shadow:
    0 16px 36px -10px rgba(0, 0, 0, 0.7),
    0 0 20px -4px rgba(234, 80, 80, 0.45);
}

.fechas-card--dom:hover {
  border-color: #ffffff;
  box-shadow:
    0 16px 36px -10px rgba(0, 0, 0, 0.7),
    0 0 20px -4px rgba(255, 255, 255, 0.35);
}

.fechas-card--jue,
.fechas-card--sab {
  background: #ebe6dd url(../img/tex-tile-movil.webp);
  background-size: 280px;
}

.fechas-card--vie,
.fechas-card--dom {
  background: #e2cca2 url(../img/tex-tile-movil.webp);
  background-size: 280px;
}

.fechas-card__header {
  position: relative;
  padding: 0.9rem 0.9rem 0.6rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.45rem;
  background: rgba(0, 0, 0, 0.06);
  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}

.fechas-card__cinta {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 38px;
}

.fechas-card__cinta img {
  max-height: 36px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
}

.fechas-card__ico {
  position: absolute;
  top: -10px;
  right: -6px;
  height: 38px;
  width: auto;
  object-fit: contain;
  z-index: 2;
  filter: drop-shadow(1.5px 0 0 #ffffff) drop-shadow(-1.5px 0 0 #ffffff)
    drop-shadow(0 1.5px 0 #ffffff) drop-shadow(0 -1.5px 0 #ffffff)
    drop-shadow(0 3px 6px rgba(0, 0, 0, 0.45));
  pointer-events: none;
}

.fechas-card__badge-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  flex-wrap: wrap;
}

.fechas-card__tag {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  line-height: 1;
}

.fechas-card__tag--previa {
  background: #1a1c1b;
  color: #ffffff;
  border: 1px solid #1a1c1b;
}

.fechas-card__tag--dia {
  background: rgba(0, 0, 0, 0.1);
  color: #1a1c1b;
}

.fechas-card__tag--cierre {
  background: var(--rojo);
  color: #fff;
  border: 1px solid var(--rojo);
}

.fechas-card__media {
  position: relative;
  height: 175px;
  background: transparent;
  overflow: hidden;
}

.fechas-card__media-gradient {
  display: none;
}

.fechas-card__body {
  padding: 0.75rem 1rem 1.25rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  flex-grow: 1;
  text-align: center;
}

.fechas-card__artist-title {
  height: 2.8rem;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0.2rem 0 0.5rem;
}

.fechas-card__artist-title img {
  max-height: 100%;
  max-width: 92%;
  width: auto;
  object-fit: contain;
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.25));
}

.fechas-card__lineup {
  font-size: 0.74rem;
  line-height: 1.35;
  color: #2d302f;
  font-weight: 600;
  margin: 0 0 1rem;
  min-height: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.fechas-card__footer {
  width: 100%;
  margin-top: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
}

.fechas-card__btn {
  background: transparent url(../img/btn-compra-aqui.webp) center / contain
    no-repeat;
  border: none;
  box-shadow: none;
  aspect-ratio: 505 / 110;
  height: 44px;
  width: auto;
  max-width: 100%;
  color: transparent;
  padding: 0;
  cursor: pointer;
  transition:
    transform 0.2s ease,
    filter 0.2s ease;
}

.fechas-card__btn:hover {
  background-color: transparent;
  filter: brightness(1.18) drop-shadow(0 4px 10px rgba(234, 80, 80, 0.4));
  transform: translateY(-2px);
}

.fechas-card__btn:active {
  transform: translateY(0) scale(0.98);
}

.fechas-card__btn-vecino {
  background: transparent url(../img/btn-gratis-tarjeta-vecino.webp) center /
    contain no-repeat;
  border: none;
  box-shadow: none;
  aspect-ratio: 394 / 110;
  height: 36px;
  width: auto;
  max-width: 100%;
  color: transparent;
  padding: 0;
  cursor: pointer;
  transition:
    transform 0.2s ease,
    filter 0.2s ease;
}

.fechas-card__btn-vecino:hover {
  background-color: transparent;
  filter: brightness(1.2);
  transform: translateY(-1px);
}

.fechas-card__link {
  font-size: 0.74rem;
  color: #4a4d4b;
  font-weight: 600;
  text-decoration: none;
  transition: color 0.15s ease;
}

.fechas-card__link:hover {
  color: var(--rojo);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.fechas-card.fechas-card--finalizado {
  opacity: 0.55;
  filter: grayscale(0.5);
  cursor: not-allowed;
}

.fechas-card.fechas-card--finalizado:hover {
  transform: none;
  box-shadow: none;
  border-color: rgba(0, 0, 0, 0.22);
}

.fechas-card.fechas-card--finalizado .fechas-card__btn {
  filter: grayscale(1) opacity(0.5);
  cursor: not-allowed;
}

.ticket-modal {
  position: fixed;
  inset: 0;
  z-index: 1001;
  display: grid;
  place-items: center;
  padding: 1rem;
}

.ticket-modal[hidden] {
  display: none;
}

.ticket-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(3, 4, 5, 0.82);
}

.ticket-modal__content {
  position: relative;
  z-index: 1;
  width: min(1120px, 100%);
  /* Con el alto del iframe pegado al contenido, el que desplaza es el
     diálogo — igual que el modal de Bootstrap de las otras landings. */
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  border-radius: 18px;
  background: var(--marco);
  color: #fff;
}

.ticket-modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.95rem 1.1rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.14);
}

.ticket-modal__header h2 {
  font-size: 1rem;
  font-weight: 600;
}

.ticket-modal__close {
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: transparent;
  color: #fff;
  font-size: 1.35rem;
  line-height: 1;
  cursor: pointer;
}

.ticket-modal__close:hover {
  background: rgba(255, 255, 255, 0.12);
}

.ticket-modal__iframe-wrap {
  position: relative;
  width: 100%;
}

.ticket-modal__loader {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.65rem;
  background: rgba(29, 29, 29, 0.9);
  color: #fff;
  font-size: 0.92rem;
  z-index: 2;
}

.ticket-modal__loader[hidden] {
  display: none;
}

.ticket-modal__spinner {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, 0.22);
  border-top-color: var(--rojo);
  animation: ticket-spin 0.8s linear infinite;
}

/* 3.6 · Ocupa el marco cuando el flujo no carga, en lugar del blanco. */
.ticket-modal__error {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.9rem;
  padding: 1.5rem;
  text-align: center;
  background: var(--marco);
  color: #fff;
  z-index: 3;
}

.ticket-modal__error[hidden] {
  display: none;
}

.ticket-modal__error-link {
  padding: 0.6rem 1.1rem;
  border-radius: 999px;
  background: var(--rojo);
  /* 3.12 · Tinta oscura, no blanca: blanco sobre `--rojo` da 3,64:1 y este
     texto no es grande. Con `--marco` sube a 4,70:1 y pasa AA. */
  color: var(--marco);
  font-weight: 600;
  text-decoration: none;
}

/* 3.4/D1 · `iframe.resizer.js` escribe el alto en línea, así que esto es solo
   el alto de reserva mientras llega el primer mensaje del hijo — y el que
   queda si el script del CDN no carga. */
.ticket-modal__iframe {
  display: block;
  width: 100%;
  height: min(760px, calc(100vh - 6.8rem));
  border: 0;
  background: #fff;
}

.ticket-modal__iframe.is-loading {
  opacity: 0;
}

@keyframes ticket-spin {
  to {
    transform: rotate(360deg);
  }
}

/* ============================================================
   2.13 · TABLET Y MÓVIL

   Un solo breakpoint, 768 px: el que usan las otras cinco landings
   de `public/` (no 960/640 — eso lo escribió tasks.md sin mirar el
   repo). Por encima no hace falta nada: el escritorio es un lienzo
   de posiciones en % sobre 1080 px, así que ya escala solo, y
   `.lienzo` ya centra con `max-width`. Por debajo, las cuatro
   jornadas dejan de ser lienzo y pasan a columna — foto arriba con
   su encuadre móvil de 1.6, y debajo cinta, titular, lineup y CTA
   en el orden en que ya están en el HTML (no hace falta `order`).
   Las bandas siguen a sangre; lo que se centra con `max-width` es
   el bloque de titular y lineup.

   Este es también el breakpoint de `<source media>` en el HTML: si
   no coincidieran, entre 641 y 768 la columna serviría el recorte
   de escritorio, que es casi cuadrado, a todo el ancho.
   ============================================================ */

@media (max-width: 768px) {
  /* A 360 px el logo y el enlace comparten fila justa; se aprieta la barra. */
  .eventrid-header {
    padding-top: 0.55rem;
    padding-bottom: 0.55rem;
  }
  .banda[id] {
    scroll-margin-top: 3.5rem;
  }

  .eventrid-header__cta {
    font-size: 0.78rem;
  }

  /* Fondo distinto en móvil, no el mismo con otro `background-size`.

     `tex-fondo.webp` es una composición aplanada atada al reparto de alturas de
     escritorio: sus primeros ~410 px son papel liso (243,245,247, sd 0,0) porque
     ahí encima va el póster del hero, que en escritorio mide 511 px y los tapa.
     Apilado, el hero baja a 177 px y ese blanco queda a la vista detrás de la
     banda de datos y del hueco transparente de la foto de jueves. Y no se
     recoloca: el hero pasa del 15 % de la página al 4,7 %, así que ninguna
     combinación de `background-size`/`position` la vuelve a alinear en todos los
     viewports. Estirarla con `100% 100%` es peor todavía — apilada la página
     pasa de 1:3,2 a ~1:10 y el grano se va en estrías verticales.

     `tex-tile-movil.webp` (`work/tile_movil.py`) es una franja limpia de la MISMA
     composición, espejada para repetir sin costura (Δ 5,8 por canal, por debajo
     de la propia sd 11-15 del yeso). Repite, así que no le afecta el alto de la
     página. `300%` deja ~360 px de textura por ancho de viewport, el mismo grano
     en pantalla que en escritorio; a `100%` saldría cinco veces más fino y se
     leería como ruido. En móvil se pierde el óxido de la banda de jueves, que
     vive en la zona que la franja no toma. */
  .fonda::before {
    background-image: url(../img/tex-tile-movil.webp);
    background-position: center top;
    background-repeat: repeat-y;
    background-size: 300% auto;
  }

  /* La franja tostada de viernes se desbordaba en diagonal para reproducir
     el límite roto de la maqueta; apilada no hay maqueta que reproducir. */
  .banda--vie::before {
    top: 0;
    bottom: 0;
    clip-path: none;
  }

  .lienzo--dia {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.7rem;
    aspect-ratio: auto;
    padding-block: 1.5rem 2.25rem;
  }

  .lienzo--dia > .pieza {
    position: static;
  }

  /* Foto y cinta de fecha a sangre (de ahí que la columna no lleve padding
     lateral); el resto se mete con su propio ancho. */
  .lienzo--dia > .foto,
  .lienzo--dia > .cinta {
    width: 100%;
  }

  /* El encuadre móvil es 4:3; los atributos width/height del <img> son los
     del recorte de escritorio, así que sin esto el hueco reservado antes
     de cargar tiene la proporción equivocada y la página salta.

     Y se desvanece por abajo: las fotos son siluetas recortadas sobre el yeso,
     y un 4:3 anclado a las cabezas corta piernas (`work/encuadre.py` explica
     por qué se ancla arriba). Sin la máscara ese corte es una línea recta a
     todo el ancho — el defecto que la QA del 2026-08-26 llamó «imágenes
     cortadas». Con ella la silueta se disuelve en el fondo, que es como se
     comporta un recorte de papel en un collage. Empieza al 74 % porque por
     debajo ya no hay caras en ninguna de las cuatro jornadas. */
  .lienzo--dia > .foto img {
    aspect-ratio: 4 / 3;
    object-fit: cover;
    /* Safari sin prefijo solo desde 15.4; por debajo degrada al corte recto. */
    -webkit-mask-image: linear-gradient(to bottom, #000 74%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 74%, transparent 100%);
  }

  /* La banderola de Carpeta 8 no es un item de columna: en el flujo saldría como un
     rectángulo con dos triángulos vacíos. Vuelve a la esquina superior izquierda de la
     jornada, que es donde vive en la maqueta, encima de la foto. */
  .lienzo--dia > .cinta--previa {
    position: absolute;
    left: 0;
    top: 0;
    width: 42%;
    z-index: 1;
  }

  .lienzo--dia > .titular,
  .lienzo--dia > .lineup {
    width: 86%;
    max-width: 26rem;
  }

  /* Ancho fijo: en % el CTA se encogería con el viewport hasta dejar de
     ser pulsable. A 15rem el alto sale de su aspect-ratio en 52 px. */
  .lienzo--dia > .cta--compra {
    width: 15rem;
  }

  .lienzo--dia > .cta--vecino {
    width: 11.7rem;
  }

  /* Los iconos estaban colocados contra el lienzo de escritorio; en la
     columna caen al pie de su jornada y hacen de separador. A menos de
     ~5rem son manchas rojas: dejan de leerse como volantín o empanada
     (en escritorio se sirven a ~106 px). */
  .lienzo--dia > .ico {
    width: 5.5rem;
  }

  /* El póster móvil es 3:2, no la franja 1080/611 de la maqueta. La barra
     oscura imitaba el cromo del reproductor de escritorio y sobre un 3:2
     cortaría imagen, así que se retira: el play real ya dice que hay vídeo. */
  .lienzo--video {
    aspect-ratio: 1280 / 853;
  }

  .video__barra {
    display: none;
  }

  /* En % del lienzo el play se queda en 31 px y sobre la foto de la fonda no se
     ve, y es el único aviso de que la sección es un vídeo. El 43,37 % era el
     centro del encuadre de escritorio. */
  .play--video {
    top: 50%;
    width: 18%;
  }

  /* La banda de datos deja de estar recortada a 1 px y pasa a ocupar sitio, pero
     lo que se ve NO es su texto (ese sigue en `.vh`, para máquinas): es el rótulo
     de la propia maqueta. Servido con la pila del sistema chocaba con el resto de
     la página, que no carga ninguna tipografía web porque todo su texto son
     rásteres del `.ai`. La salida no fue traer una fuente que se pareciera, sino
     recortar la que ya está dibujada dentro del póster del hero
     (`work/rotulo_sede.py`), donde a 375 px queda a ~6 px de altura de mayúscula
     y es justo lo que esta banda viene a arreglar. Aquí sale al 1,3x del tamaño
     de escritorio.

     El tinte tostado lo pone `.banda--arena::before`, la misma capa que la franja
     de viernes: deja pasar el grano del yeso, así que la tira se lee como papel
     de la maqueta y no como un rectángulo plano pegado encima. La línea de tinta
     de arriba continúa el marco del póster, que muere justo ahí. */
  .banda--datos {
    position: relative;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip-path: none;
    border-top: 2px solid var(--marco);
    padding: 1.1rem 1rem 1.25rem;
  }

  .datos {
    display: flex;
    justify-content: center;
  }

  .datos::before {
    content: '';
    display: block;
    width: min(88%, 21rem);
    aspect-ratio: 720 / 149;
    background: url(../img/ttl-sede-fechas.webp) center / contain no-repeat;
  }

  .ticket-modal {
    padding: 0.6rem;
  }

  .ticket-modal__iframe {
    height: calc(100vh - 6rem);
  }
}

@media (max-width: 1024px) {
  .fechas-modal__grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 1.2rem;
  }
}

@media (max-width: 640px) {
  .fechas-modal {
    padding: 0.6rem;
  }

  .fechas-modal__dialog {
    padding: 1.25rem 1rem 1.5rem;
    border-radius: 16px;
    max-height: calc(100vh - 1.2rem);
    gap: 1.1rem;
  }

  .fechas-modal__header {
    gap: 0.8rem;
    padding-bottom: 0.9rem;
  }

  .fechas-modal__title {
    font-size: 1.35rem;
  }

  .fechas-modal__subtitle {
    font-size: 0.82rem;
  }

  .fechas-modal__close {
    width: 2.2rem;
    height: 2.2rem;
    font-size: 1.4rem;
  }

  .fechas-modal__grid {
    grid-template-columns: 1fr;
    gap: 1rem;
  }

  .fechas-card__media {
    height: 155px;
  }

  .fechas-card__body {
    padding: 0.65rem 0.85rem 1rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}
