/* ==========================================================================
   Sección «Feed» del home: el banner del line up y los cuatro accesos.

   Se carga después del <style> que Framer inyecta en index.html, así que gana
   por orden sin necesidad de !important salvo donde se indica. Las clases
   framer-* son las que genera Framer; se respetan tal cual porque el markup lo
   escribe build_home_feed.py clonando sus nodos.

   Ojo: esto se aplica sobre HTML generado. Si alguien vuelve a migrar el home
   con migrate_one.py, hay que correr build_home_feed.py otra vez.
   ========================================================================== */

/* La sección traía altura fija (166.5vh / 100vh según breakpoint) calculada
   para dos accesos en una fila. Con cuatro en rejilla el alto lo tiene que
   poner el contenido, o los tiles de abajo quedan cortados. */
.framer-ia6sb2 {
    height: auto !important;
    padding-bottom: 60px;
}

/* --------------------------------------------------------- el banner --- */

/* El alto fijo de 580px que traía Framer recortaba el arte; lo pone la
   proporción del propio banner. */
.framer-1d0qxdu {
    height: auto !important;
    aspect-ratio: 16 / 9;
}

.framer-1d0qxdu img,
.framer-1d0qxdu video {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* El video va encima del póster y se funde cuando ya tiene fotogramas: así el
   arte estático hace de preloader en vez de dejar un hueco en negro. */
.framer-efn3ma-container {
    position: absolute !important;
    inset: 0;
    width: 100% !important;
    height: 100% !important;
    aspect-ratio: auto !important;
}

.framer-efn3ma-container video {
    opacity: 0;
    transition: opacity 0.45s ease;
}

.framer-efn3ma-container video[data-listo="si"] {
    opacity: 1;
}

/* En celular el banner va vertical: por debajo de 810px Framer ya sirve
   lineup-v.mp4 y lineup-poster-v.jpg, que son 1080x1920. Con el hueco en 16:9
   el `object-fit: cover` se comía el logo, las fechas y media lista de
   artistas, así que la proporción del hueco tiene que ser la del arte.

   El breakpoint es el mismo 809.98px que usa Framer para cambiar de asset: si
   los dos no coinciden queda una franja donde el arte vertical se recorta. */
@media (max-width: 809.98px) {
    .framer-1d0qxdu {
        aspect-ratio: 9 / 16;
        /* A todo el ancho, un 9:16 se sale de pantalla en cuanto el hueco pasa
           de unos 500px (tablet en vertical: 708 de ancho → 1259 de alto). Se
           topa el ancho para que el alto no pase de 85vh —alto = ancho × 16/9,
           así que ancho ≤ 85vh × 9/16—: el arte nunca se recorta, sólo se
           centra más estrecho. En celular no llega a activarse. */
        max-width: min(100%, calc(85vh * 9 / 16));
        margin-inline: auto;
    }
}

/* --------------------------------------------------------- los accesos -- */

.framer-vmf3ud {
    display: grid !important;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 27px;
    height: auto !important;
    flex: none !important;
}

/* Cada acceso: la foto de fondo, el texto abajo a la izquierda y un velo para
   que el texto se lea sobre cualquier foto. */
.framer-vmf3ud > a {
    position: relative;
    display: block;
    width: auto !important;
    height: auto !important;
    min-height: 260px;
    aspect-ratio: 4 / 3;
    border-radius: 10px;
    overflow: hidden;
    text-decoration: none;
    background: var(--ffmx-hueco, #e7e2de);
    flex: none !important;
}

/* La foto ocupa el tile entero. Framer la mete en un wrapper que hereda el
   tamaño intrínseco de la imagen; sin esto, una foto más chica que el tile
   deja franjas del fondo asomando. */
.framer-vmf3ud > a > [data-framer-background-image-wrapper] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

.framer-vmf3ud > a img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.5s ease;
}

.framer-vmf3ud > a:hover img {
    transform: scale(1.04);
}

/* El texto se queda abajo. Framer ya lo pone en absolute, pero con offsets
   distintos por breakpoint (bottom:31px/left:23px en escritorio, centrado con
   translate en celular). Aquí se fija de una sola forma para los cuatro. */
.framer-vmf3ud > a .framer-s0n1vk {
    position: absolute;
    top: auto;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1;
    width: 100%;
    max-width: none;
    padding: 26px;
    transform: none;
    background: linear-gradient(to top, rgba(0, 0, 0, 0.78) 0%, rgba(0, 0, 0, 0.38) 60%, rgba(0, 0, 0, 0) 100%);
    color: #fff;
    align-items: flex-start;
}

.framer-vmf3ud > a h2 {
    margin: 0;
    font-family: "Inter Tight", Inter, Arial, sans-serif;
    font-size: clamp(20px, 2.4vw, 27px);
    font-weight: 700;
    line-height: 1.05;
    letter-spacing: -0.01em;
    color: #fff;
}

.framer-vmf3ud > a h3 {
    margin: 8px 0 0;
    max-width: 42ch;
    font-family: Inter, Arial, sans-serif;
    font-size: 14px;
    font-weight: 500;
    line-height: 1.4;
    color: rgba(255, 255, 255, 0.86);
}

.framer-vmf3ud > a:focus-visible {
    outline: 3px solid #fff;
    outline-offset: 3px;
}

@media (max-width: 809.98px) {
    .framer-vmf3ud {
        grid-template-columns: minmax(0, 1fr);
        gap: 16px;
    }

    .framer-vmf3ud > a {
        aspect-ratio: 3 / 2;
        min-height: 200px;
    }

    .framer-vmf3ud > a .framer-s0n1vk {
        padding: 20px;
    }
}

/* ------------------------------------------------- banner de ABONO ------ */

/* La gráfica industrial es oscura a la izquierda y clara a la derecha, y el
   banner es una franja muy apaisada, así que el recorte deja «TODO FUTUR»
   sobre la parte clara. Un velo de izquierda a derecha mantiene el texto
   legible sin tapar la gráfica. */
/* El wrapper de la imagen va absoluto y es el primer hijo, así que sin fijarle
   el z-index se pinta por encima del ::before y el velo no se ve. */
.framer-1bv4n6n > [data-framer-background-image-wrapper] {
    z-index: 0;
}

.framer-1bv4n6n::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    border-radius: inherit;
    background: linear-gradient(to right, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0.42) 55%, rgba(0, 0, 0, 0) 100%);
    pointer-events: none;
}

.framer-1bv4n6n > *:not([data-framer-background-image-wrapper]) {
    position: relative;
    z-index: 2;
}

@media (prefers-reduced-motion: reduce) {
    .framer-vmf3ud > a img,
    .framer-efn3ma-container video {
        transition: none;
    }
}

/* ---------------------------------------------------------------- prensa -- */

/* La sección PRENSA, al estilo del «Latest news» de kappafuturfestival.it: una
   tira de tarjetas con titular grande, flechas y puntos de paginación.

   De qué se parte. El carrusel salió mal del export de Framer: las nueve
   tarjetas quedaron dentro de **un solo slide**, así que el componente cree que
   tiene una sola página («1 of 1»), esconde sus propias flechas con
   `display: none` —y si se las enseña no hacen nada, porque paginan por índice
   de slide y sólo hay uno— y oculta la barra de scroll con
   `scrollbar-width: none`. De 810px para arriba, además, reparte las tarjetas
   en una rejilla que envuelve, y la tira deja de ser una tira.

   Aquí se deshace eso: una sola línea en los dos tamaños, y `home-feed.js` le
   pone flechas y puntos propios, fuera del árbol de React —cablear las del
   componente no prosperó: las vuelve a crear al hidratar y los listeners se
   quedan en nodos desechados—. Hay que responderle con `!important` porque
   inyecta su CSS al montarse, o sea después de este archivo.

   La tarjeta también cambia. Framer dejaba el titular al mismo cuerpo que el
   texto y la entradilla como cita —cursiva gris con rayita al margen—, así que
   las nueve notas se leían igual de planas: ahora el titular manda y la
   entradilla es un párrafo corriente. La fecha y el medio se quedan: son
   recortes de prensa reales y sin ellos no se sabe de dónde salió cada nota.

   Todo cuelga de `.framer-or1tzw` —el bloque «News»— para no tocar los mismos
   presets en el resto de la página: `nspcl7`, por ejemplo, es también el de los
   encabezados de la tabla de boletos. */

/* --- la tira --- */

/* Sin `scroll-snap`: con un único punto de anclaje sólo estorba al arrastrar. */
.framer-or1tzw .framer--carousel {
    scroll-snap-type: none !important;
}

/* La fila interna, en una sola línea y del ancho de su contenido, que es lo que
   le da a la <ul> algo que desplazar. `justify-content` a flex-start: centrado,
   Chrome deja el arranque de una tira desbordada fuera de alcance. */
.framer-or1tzw .framer--carousel > li > * {
    width: min-content !important;
    flex-wrap: nowrap !important;
    justify-content: flex-start !important;
}

/* --- la tarjeta --- */

.framer-or1tzw .framer-159a1og {
    gap: 12px;
    padding: 24px 22px 22px;
}

/* Titular. */
.framer-or1tzw .framer-8d5se1 h3.framer-text {
    --framer-font-size: 20px;
    --framer-line-height: 1.15em;
    font-size: 20px;
    line-height: 1.15;
    text-transform: uppercase;
    letter-spacing: -0.01em;
    color: #111;
}

/* Fecha: dato de servicio, no titular. */
.framer-or1tzw .framer-oewpbv p.framer-text {
    --framer-font-size: 13px;
    font-size: 13px;
    line-height: 1.2;
    color: #6b6b6b;
    margin-top: -4px;
}

/* Entradilla. Era una cita: cursiva, gris claro y rayita al margen. Pasa a
   párrafo corriente, y de paso se resetean el borde y el sangrado que Framer le
   pone al <blockquote>, sin depender de qué propiedad concreta usó.

   El tercer selector es por la nota de MDM: se capturó sin el <blockquote> que
   llevan las otras ocho —su texto quedó como párrafo suelto— y no se puede
   arreglar en origen, porque el feed sale de los .framercms congelados de la
   migración y tocarlos mueve los índices por rangos de bytes. Con la entradilla
   ya sin formato de cita, las nueve se leen igual. */
.framer-or1tzw .framer-1o8uy5l blockquote.framer-text,
.framer-or1tzw .framer-1o8uy5l blockquote.framer-text p.framer-text,
.framer-or1tzw .framer-1o8uy5l > p.framer-text {
    border: 0;
    padding: 0;
    margin: 0;
    font-style: normal;
    --framer-blockquote-font-style: normal;
    --framer-font-style: normal;
    --framer-font-size: 15px;
    --framer-line-height: 1.5em;
    --framer-text-color: #333;
    font-size: 15px;
    line-height: 1.5;
    color: #333;
}

/* La rayita al margen de la cita la dibuja un pseudoelemento, no un borde, así
   que el `border: 0` de arriba no la tocaba: seguía ahí. Y peor que antes —
   al quitarle el sangrado que la separaba, quedaba encima de las primeras
   letras de cada línea. */
.framer-or1tzw .framer-1o8uy5l blockquote.framer-text::before {
    content: none;
}

/* El medio, firmando al pie. */
.framer-or1tzw .framer-j1us36 p.framer-text {
    --framer-font-size: 12px;
    font-size: 12px;
    line-height: 1.2;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #6b6b6b;
}

/* --- los controles --- */

/* La fila del título ya es flex y el <h1> ocupa el hueco (`flex: 1 0 0`), así
   que los controles caen solos a la derecha sin tocar el layout de Framer. */
.ff-prensa-controles {
    display: flex;
    flex: none;
    align-items: center;
    gap: 20px;
}

.ff-prensa-puntos {
    display: flex;
    align-items: center;
    gap: 8px;
}

.ff-prensa-punto {
    width: 9px;
    height: 9px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: #c9c9c9;
    cursor: pointer;
    transition: background 0.2s;
}

.ff-prensa-punto[aria-current="true"] {
    background: #111;
}

.ff-prensa-flechas {
    display: flex;
    gap: 10px;
}

.ff-prensa-flecha {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    padding: 0;
    border: 1px solid #d8d8d8;
    border-radius: 14px;
    background: #fff;
    color: #111;
    cursor: pointer;
    transition: border-color 0.2s, color 0.2s;
}

.ff-prensa-flecha svg {
    width: 22px;
    height: 22px;
}

.ff-prensa-flecha:hover:not(:disabled) {
    border-color: #111;
}

.ff-prensa-flecha:disabled {
    color: #c9c9c9;
    cursor: default;
}

/* En táctil el gesto natural sigue siendo deslizar, así que se le devuelve la
   barra que Framer escondía; los controles se quedan, más chicos. */
@media (max-width: 809.98px) {
    .framer-or1tzw .framer--carousel {
        scrollbar-width: thin !important;
        scrollbar-color: rgba(0, 0, 0, 0.3) transparent !important;
    }

    .framer-or1tzw .framer--carousel::-webkit-scrollbar {
        display: block !important;
        height: 8px;
    }

    .framer-or1tzw .framer--carousel::-webkit-scrollbar-track {
        background: transparent;
    }

    .framer-or1tzw .framer--carousel::-webkit-scrollbar-thumb {
        background: rgba(0, 0, 0, 0.3);
        border-radius: 999px;
    }

    /* Con la pantalla estrecha salen siete grupos y los puntos no caben junto
       al título; las flechas bastan. Y el margen porque la sección sólo trae
       relleno por la izquierda: sin él las flechas quedan pegadas al borde. */
    .ff-prensa-puntos {
        display: none;
    }

    .ff-prensa-controles {
        gap: 12px;
        margin-right: 20px;
    }

    .ff-prensa-flecha {
        width: 42px;
        height: 42px;
        border-radius: 12px;
    }

    .ff-prensa-flecha svg {
        width: 18px;
        height: 18px;
    }
}

/* ------------------------------------------- los mapas del recinto --- */

/* Los dos mapas llevan la leyenda rotulada dentro de la propia imagen, en una
   franja bajo el plano, y son cuadrados. Framer le daba a la caja un alto que
   no era el suyo en dos de los tres tramos, y con `object-fit:cover` lo que
   sobraba se recortaba:

   - Hasta 809 px, alto fijo de 309. La imagen se escalaba al ancho y se comía
     la franja de abajo, justo la leyenda: se veía el plano y no lo que
     significaba cada icono. En tablet vertical era 728 de ancho contra 309.
   - De 1200 en adelante, `height:100%` dentro de una fila de 628 px. La caja
     quedaba en 575 × 628 y el recorte se iba a los lados, un 4% por lado.
   - El tramo de en medio ya venía bien de Framer.

   Una regla para los tres: la caja es cuadrada como el original y no hay nada
   que recortar. Sin `@media` a propósito —en el tramo de en medio no cambia
   nada, porque ya era eso— y sin `!important`: misma especificidad que las
   reglas de Framer y este archivo se carga después, así que gana por orden.

   El ancho lo sigue poniendo Framer. En escritorio la fila está topada en
   1160 px, así que la caja nunca pasa de 575 y el cuadrado siempre cabe en los
   628 px de la fila; queda centrado, con aire arriba y abajo. */
.framer-PAW52 .framer-6y4xg,
.framer-PAW52 .framer-101393c {
    height: auto;
    aspect-ratio: 1;
}

/* Y la fila que los contiene deja de medir 628 px fijos.

   Al volver cuadrado el mapa, su caja pasó de 628 a 575 y Framer la centraba
   en una fila que seguía midiendo 628: el mapa quedaba 27 px por debajo del
   título del día y 26 px por encima del borde inferior, con la tabla empezando
   64 px más abajo todavía. Tres bordes superiores distintos donde antes había
   uno, que es lo que se veía descuadrado.

   Con la fila a `auto` la manda el mapa: 575 px de alto, o sea que vuelve a
   quedar a ras del título arriba y a ras del borde abajo, como en la versión
   original — pero sin el recorte del 4 % por lado. Si alguna tabla llegara a
   ser más alta que el mapa, la fila crece con ella en vez de recortarla: era
   justo lo que le pasaba a la de SATURDAY, que perdía sus esquinas
   redondeadas por abajo.

   Sólo de 1200 px en adelante: por debajo Framer ya apila mapa y tabla en
   columna con `height: min-content`, y esto no aplica. */
@media (min-width: 1200px) {
    .framer-PAW52 .framer-1mk0eig,
    .framer-PAW52 .framer-ocml9u {
        height: auto;
    }
}

/* ------------------------------------------ el logo sobre el hero --- */

/* El logo entra con una animación «appear» de Framer que se lanza desde un
   requestAnimationFrame al arrancar la página. Es una carrera: si la
   hidratación se retrasa, la animación no llega a correr y el logo se queda con
   el `opacity:0.001` en línea que trae el HTML del servidor, es decir invisible.
   En inglés fallaba casi siempre y en español de vez en cuando.

   Aquí se replica la misma entrada como animación CSS, con los tiempos y la
   curva que declara el propio JSON de Framer (delay 0.1s, 0.9s, cubic-bezier
   .44,0,.56,1). Las animaciones pisan al atributo `style` en la cascada, así
   que el estado final queda garantizado corra o no el JavaScript; y si Framer
   sí llega a animar, las dos terminan en el mismo sitio. */
@keyframes ff-logo-hero-entra {
    from {
        opacity: 0.001;
        transform: translateY(150px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.framer-atr8l {
    animation: ff-logo-hero-entra 0.9s cubic-bezier(0.44, 0, 0.56, 1) 0.1s both;
}

@media (prefers-reduced-motion: reduce) {
    .framer-atr8l {
        animation-duration: 1ms;
        animation-delay: 0ms;
    }
}

/* Encabezados de la tabla de boletos, sólo en inglés.

   Las cinco columnas miden 91px y a Framer le alcanzan para «CATEGORIA» o
   «FASE 1», pero no para «1ST RELEASE», «3RD RELEASE» ni «FINAL RELEASE»: en
   escritorio los deja en `white-space: pre`, así que el texto se salía de su
   celda y se encimaba con el de la siguiente. Se les permite envolver, que es
   justo lo que el propio Framer hace abajo de 810px. En español no cambia
   nada porque ninguna etiqueta llega a desbordar. */
/* Y con el encabezado en dos líneas, las filas de la tabla dejan de ser todas
   iguales. Framer las reparte con `grid-template-rows: repeat(N, minmax(0,1fr))`,
   así que la fila más alta marca el alto de todas: el encabezado envuelto
   pasaba cada una de las ocho filas de 26 a 38 px y la tabla del sábado crecía
   102 px de golpe — lo justo para desbordar su fila y perder las esquinas
   redondeadas de abajo. En alto de contenido sólo crece el encabezado. */
html[lang="en"] .framer-cn01gc,
html[lang="en"] .framer-1h3p7rb {
    grid-template-rows: auto;
    grid-auto-rows: auto;
}

html[lang="en"] .framer-d54xia,
html[lang="en"] .framer-2hb8gc,
html[lang="en"] .framer-1psni40,
html[lang="en"] .framer-vg42fi,
html[lang="en"] .framer-128ydcl,
html[lang="en"] .framer-30q5lo,
html[lang="en"] .framer-15s7ijp,
html[lang="en"] .framer-umma9x,
html[lang="en"] .framer-1ii79te,
html[lang="en"] .framer-3dd7tt {
    white-space: pre-wrap;
    height: auto;
}

/* Los rótulos del encabezado no caían sobre su columna, sino a la izquierda.

   El cuadro entero es una sola rejilla de cinco columnas iguales —62px en
   celular, 130px en tableta, 91px en escritorio— y las celdas la ocupan de dos
   maneras. Las de importe miden la columna completa y centran el texto dentro.
   Las del encabezado deberían hacer lo mismo, y en el cuadro del viernes lo
   hacen; en el del sábado Framer las dejó en `width: fit-content` con
   `place-self: start`, así que se encogen al ancho de su texto y se pegan al
   inicio de la columna.

   El desfase es esa diferencia: la mitad de lo que le sobra al rótulo respecto
   de la columna. Por eso cada uno se corría distinto —«FASE 1», que es corto,
   unos 21px; «ÚLTIMA FASE», que llena la columna, apenas 3— y por eso no se
   leía como una tabla movida sino como cinco rótulos sueltos.

   Se ve sobre todo en celular, que es donde el sábado encoge las cinco.

   Se centra la celda en la columna en vez de estirarla, que es lo que parecía
   la respuesta obvia. «ÚLTIMA FASE» mide 100,6px en una columna de 91 y va en
   `white-space: pre`: estirada la celda el texto sigue sin caber y se sale
   entero por la derecha —le pasaba al viernes desde siempre—, mientras que
   centrada se reparte el sobrante a los dos lados y el rótulo queda sobre su
   columna, que es lo que se busca. Lo que sobra cae en el aire que le queda a
   «FASE 2», que ocupa la mitad de la suya.

   Centrar tampoco toca dónde envuelve «FINAL RELEASE» en inglés —de eso se
   ocupa la regla de arriba—: la celda mide lo mismo que antes, sólo cambia
   dónde se apoya.

   CATEGORIA es la excepción y va al revés: sus valores —SUNSET, GENERAL, VIP
   PREMIUM…— van a la izquierda, así que su rótulo también. Encogida al ancho
   del texto queda anclada al inicio de la columna, justo donde empiezan ellos;
   centrada en la columna, como la tenía el viernes, se metía 5px hacia dentro
   y no cuadraba con su propia lista.

   Sólo se toca el eje horizontal: el `place-self: start` vertical es con el
   que cada fila se apoya en su línea de base.

   Va con `html` delante porque `home-feed.css` se carga antes que la hoja de
   Framer que trae `place-self: start`, y a igualdad de peso ganaría aquélla.

   Y va por descendencia, no por hijo directo, porque las dos versiones de la
   página no tienen el mismo árbol: en español React hidrata y se lleva los
   envoltorios `.ssr-variant`, así que la celda cuelga de la rejilla; en inglés
   no llega a hidratar —el fallo que ya documenta `build_i18n.py`— y el
   envoltorio se queda en medio. Como es `display: contents` la celda sigue
   siendo el elemento de la rejilla y `justify-self` le aplica igual, pero un
   `>` no la alcanzaba y la regla se caía entera en `/en`. */
html .framer-cn01gc .framer-2hb8gc,
html .framer-cn01gc .framer-1psni40,
html .framer-cn01gc .framer-vg42fi,
html .framer-cn01gc .framer-128ydcl,
html .framer-1h3p7rb .framer-15s7ijp,
html .framer-1h3p7rb .framer-umma9x,
html .framer-1h3p7rb .framer-1ii79te,
html .framer-1h3p7rb .framer-3dd7tt {
    justify-self: center;
    width: fit-content;
}

html .framer-cn01gc .framer-d54xia,
html .framer-1h3p7rb .framer-30q5lo {
    justify-self: start;
    width: fit-content;
}
