/* Identidad Noche editorial de AppLinkers. Unica fuente de verdad visual.
   Minimalista elaborado: pocas cosas por pantalla, cada una precisa.
   Tema principal noche; claro derivado. Las superficies migran por fases:
   hoy la consumen el Inicio hub y los tokens de /entradas/. */
:root {
  --al-noche: #0e0d10;
  --al-superficie: #17151b;
  --al-hairline: rgba(255, 255, 255, 0.08);
  --al-tinta: #f2f0f4;
  --al-tinta-2: #8b8794;
  /* Dos corales con oficios distintos:
     --al-coral es el de marca, para acentos, bordes, foco y titulares grandes
     (sobre noche da 5.28:1 como texto).
     --al-coral-texto es el fondo de las piezas con texto BLANCO encima (CTA):
     blanco sobre #e11d48 da 4.70:1 y pasa AA en 0.76rem, mientras que sobre
     el coral de marca se queda en 3.67:1. Sobre noche #e11d48 se sigue
     leyendo coral, no rojo, asi que vale para los dos temas. */
  --al-coral: #f43f5e;
  --al-coral-texto: #e11d48;
  /* Y un tercero con el oficio contrario al anterior: el coral que se LEE
     sobre el lienzo en texto pequeno (el enlace de las notas). Sobre noche
     #e11d48 se queda en 4.12:1 y hace falta el coral de marca (5.28:1); sobre
     el lienzo claro pasa justo lo contrario (#f43f5e 3.52:1, #e11d48 4.51:1).
     Por eso este si cambia de valor segun el tema. */
  --al-coral-enlace: #f43f5e;
  /* Fondo de la caja de imagen de las filas: se ve mientras el banner carga y si
     el archivo se ha perdido del storage. Cambia con el tema porque es interfaz
     y no foto: en claro, el degradado morado de noche se leia como una losa
     oscura sobre el lienzo, casi como una imagen rota. Las filas SIN banner ya
     no lo usan (llevan icono, ver --al-icono-*). */
  --al-relleno: linear-gradient(120deg, #241f2e, #3b2340);
  /* Iconos de las filas: blob translucido + trazo saturado, un par por hue.
     El fondo es un TINTE (12% en claro, 17-20% en noche) sobre el lienzo y no un
     color plano: da ambiente sin convertirse en un acento que le dispute la
     pantalla al coral del CTA. Y no son pastel: el trazo va saturado y el dibujo
     es de linea, nunca un emoji.
     Los valores cambian por tema: en noche el par sale del extremo LUMINOSO de
     cada rampa (el 300) y en claro del PROFUNDO (el 700), que es lo que se lee
     en cada lienzo. Medido en captura: con el tinte tomado del coral de marca
     (#f43f5e) al 16% el blob sobre el casi negro se apagaba a un granate sucio,
     asi que en noche el velo parte del tono claro y sube un par de puntos; en
     claro con el 12% ya se ve el guijarro.
     Tres hues, uno por mundo: coral tests, azul grupos, verde pisos. */
  --al-icono-coral-fondo: rgba(253, 164, 175, 0.2);
  --al-icono-coral-trazo: #fda4af;
  --al-icono-azul-fondo: rgba(147, 197, 253, 0.18);
  --al-icono-azul-trazo: #93c5fd;
  --al-icono-verde-fondo: rgba(94, 234, 212, 0.17);
  --al-icono-verde-trazo: #5eead4;
  /* Relleno del hero cuando el evento no tiene banner. Al contrario que
     --al-relleno, este NO cambia con el tema y vale lo mismo en los cuatro
     bloques: encima siempre va texto BLANCO (la fecha y el titular, mas el velo
     oscuro del ::after), asi que en claro tiene que seguir siendo oscuro o el
     titular se queda ilegible. Es un token por coherencia (nadie tiene que ir a
     buscar el degradado dentro de la regla) y para que un cambio de morado se
     haga en un sitio, no porque vaya a derivar en claro. */
  --al-hero-relleno: linear-gradient(115deg, #241f2e 0%, #3b2340 55%, #1a1522 100%);
  --al-radio: 16px;
  --al-radio-s: 12px;
  --al-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
  /* Display juvenil, no condensada: la Bricolage Grotesque tiene caracter
     (contrastes raros, terminaciones cortadas) sin caer en lo infantil ni en
     el titular ciberpunk. Se pide SOLO el 800, el unico peso que se usa (el
     saludo y el titulo del hero), y no se bajan pesos de reserva: cada peso
     extra es otro fichero woff2 en la ruta critica.
     Cae a la sans de interfaz mientras carga o si Google Fonts falla: otra
     condensada de sistema desfiguraria el bloque entero. */
  --al-display: 'Bricolage Grotesque', var(--al-sans);
}
@media (prefers-color-scheme: light) {
  :root {
    --al-noche: #fbfaf8;
    --al-superficie: #ffffff;
    --al-hairline: rgba(25, 23, 20, 0.1);
    --al-tinta: #191714;
    --al-tinta-2: #6d675f;
    --al-coral-texto: #e11d48; /* mismo coral profundo que en noche */
    --al-coral-enlace: #e11d48;
    --al-relleno: linear-gradient(120deg, #efeae3, #e2dbd2);
    /* Mismo valor que en noche a proposito: el hero lleva texto blanco encima. */
    --al-hero-relleno: linear-gradient(115deg, #241f2e 0%, #3b2340 55%, #1a1522 100%);
    /* Tintes un punto mas suaves y trazos profundos: sobre el lienzo claro los
       trazos luminosos de noche desaparecerian. */
    --al-icono-coral-fondo: rgba(225, 29, 72, 0.12);
    --al-icono-coral-trazo: #be123c;
    --al-icono-azul-fondo: rgba(37, 99, 235, 0.12);
    --al-icono-azul-trazo: #1e40af;
    --al-icono-verde-fondo: rgba(13, 148, 136, 0.12);
    --al-icono-verde-trazo: #0f766e;
  }
}
:root[data-theme="dark"] {
  --al-noche: #0e0d10;
  --al-superficie: #17151b;
  --al-hairline: rgba(255, 255, 255, 0.08);
  --al-tinta: #f2f0f4;
  --al-tinta-2: #8b8794;
  --al-coral-texto: #e11d48;
  --al-coral-enlace: #f43f5e;
  --al-relleno: linear-gradient(120deg, #241f2e, #3b2340);
  --al-hero-relleno: linear-gradient(115deg, #241f2e 0%, #3b2340 55%, #1a1522 100%);
  --al-icono-coral-fondo: rgba(253, 164, 175, 0.2);
  --al-icono-coral-trazo: #fda4af;
  --al-icono-azul-fondo: rgba(147, 197, 253, 0.18);
  --al-icono-azul-trazo: #93c5fd;
  --al-icono-verde-fondo: rgba(94, 234, 212, 0.17);
  --al-icono-verde-trazo: #5eead4;
}
:root[data-theme="light"] {
  --al-noche: #fbfaf8;
  --al-superficie: #ffffff;
  --al-hairline: rgba(25, 23, 20, 0.1);
  --al-tinta: #191714;
  --al-tinta-2: #6d675f;
  --al-coral-texto: #e11d48;
  --al-coral-enlace: #e11d48;
  --al-relleno: linear-gradient(120deg, #efeae3, #e2dbd2);
  /* Mismo valor que en noche a proposito: el hero lleva texto blanco encima. */
  --al-hero-relleno: linear-gradient(115deg, #241f2e 0%, #3b2340 55%, #1a1522 100%);
  --al-icono-coral-fondo: rgba(225, 29, 72, 0.12);
  --al-icono-coral-trazo: #be123c;
  --al-icono-azul-fondo: rgba(37, 99, 235, 0.12);
  --al-icono-azul-trazo: #1e40af;
  --al-icono-verde-fondo: rgba(13, 148, 136, 0.12);
  --al-icono-verde-trazo: #0f766e;
}

/* ===== Lienzo ===== */
/* .al-main viste el contenedor con scroll de la pagina (.main-content de
   style.css, que trae 1rem de padding arriba y abajo y le reserva sitio a la
   bottom nav): el fondo se pinta aqui ademas de en .al-hub porque si no se
   ven franjas del fondo del body sobre y bajo el lienzo y por detras de la nav
   translucida. El padding lateral 0 es un seguro: si base.html volviera a
   meter el .container de Bootstrap en la cadena, el hub seguiria de borde a
   borde en vez de dejar franjas a los lados. */
.al-main { padding-left: 0; padding-right: 0; background: var(--al-noche); }
/* Tope de ancho a la medida del portatil de 1280 (con sus 40px de padding, las
   mismas dos columnas de 560): mas alla de ahi el hero se estiraba a 1840px de
   ancho por 260 de alto y las filas se quedaban con 800px de vacio entre el
   nombre y la accion. El fondo lo sigue pintando .al-main de borde a borde, asi
   que centrarlo no deja franjas de otro color.
   El width: 100% no es decorativo: .main-content es un flex en columna y un
   item con margenes laterales auto deja de estirarse, se queda del ancho de su
   contenido (en la captura de 1280 el hub se encogio a 1208 y el lienzo dejaba
   de encajar con el hero). Con el 100% vuelve a mandar el contenedor.
   El flex-shrink: 0 tampoco: .main-content tiene ALTO definido (100dvh - 73px),
   asi que encoge a sus items, y un item solo se resiste porque su min-height
   auto vale su propio contenido. Aqui el min-height: 100% de arriba pisa ese
   auto, con lo que el hub se quedaba del alto del contenedor y su contenido se
   salia de la caja: el padding inferior que .main-content reserva para la
   bottom nav se lo comia ese desbordamiento y la ultima fila del hub quedaba
   debajo de la nav (medido a 375x1200: la fila acababa en 1194 y la nav
   empieza en 1139). Con shrink 0 el hub mide lo que mide su contenido y el
   min-height: 100% vuelve a ser solo un suelo para las paginas cortas. */
/* --al-hero-alto vive aqui (y no en los bloques de tema, que son de color)
   porque lo comparten DOS piezas: la caja de la foto del hero y la banda de
   puntos del carrusel, que se pega a su esquina inferior. Con un solo valor,
   cambiar el alto en escritorio no descuadra los puntos. */
.al-hub { --al-hero-alto: 200px; background: var(--al-noche); color: var(--al-tinta); font-family: var(--al-sans); padding: 24px 16px 40px; min-height: 100%; flex-shrink: 0; width: 100%; max-width: 1280px; margin-left: auto; margin-right: auto; }

/* Con la bottom nav pintada, el contenedor con scroll ya reserva 74px al final
   para que la nav no tape nada (regla de components/bottom_nav.html). El
   padding de 40 del hub se SUMABA a esa reserva y dejaba 114px de vacio bajo la
   ultima fila: en un iPhone 14 Pro Max eso era scroll para no ver nada
   (peticion de Pedro: si el contenido cabe, ni scroll ni hueco muerto). Se
   queda en 8 (escalon de la escala de aire) y el resto lo pone la reserva: 13px
   de los 74 quedan a la vista sobre la nav, que mide 61.
   El :has() es el unico camino: la nav es hermana POSTERIOR del contenedor, asi
   que no hay combinador que llegue desde el hub. Un navegador sin :has() se
   queda con los 40 de siempre (se pierde el ajuste, no el layout). */
@media (max-width: 768px) {
  body:has(.bottom-nav) .al-hub { padding-bottom: 8px; }
  /* Arriba pasaba lo contrario que abajo: al padding del hub (24) se le sumaba
     el padding-top de .main-content (1rem de style.css), o sea 40px de vacio
     entre el header y el saludo en la pantalla mas pequena, que es donde menos
     sobra (peticion de Pedro: "el margen arriba es demasiado alto en el movil").
     En el hub ese relleno del contenedor no hace falta (el fondo lo pinta
     .al-main de borde a borde) y el aire lo decide el hub: 12px, medio escalon
     de la escala, que deja el saludo cerca del header sin pegarlo.
     El :has() acota el ajuste al Inicio: .al-main lo comparten las pantallas de
     entradas, que tienen su propia cabecera y no han pedido nada. Un navegador
     sin :has() se queda con los 16 del contenedor mas 12 (28 en vez de 40): se
     pierde parte del ajuste, no el layout.
     Escritorio no se toca: tiene su propio bloque con 40 arriba. */
  .al-main:has(> .al-hub) { padding-top: 0; }
  /* 18px: Pedro pidio "un poquito mas de margen arriba" del saludo (antes 12). */
  .al-hub { padding-top: 18px; }
}

/* ===== Tipografia ===== */
/* El saludo y el titulo del hero van en CAJA DE FRASE: en versales la display
   sonaba a cartel de discoteca, y el hub le habla a un publico de 18-21, no
   le grita. El tracking negativo y el interlineado casi solido son los que
   hacen el bloque compacto, no las mayusculas. */
/* El margen de abajo es 16 y no los 8 de antes porque el saludo se ha quedado
   SOLO en la cabecera: la linea de la ciudad que iba debajo (con sus 24 de
   margen) se fue del hub (peticion de Pedro: "no hace falta poner Madrid", el
   usuario ya sabe en que ciudad esta). Con 8 el titular de la zona destacada se
   pegaba al saludo; con 16 hay aire y aun se ganan 16px de los 32 que sumaban
   las dos lineas. */
/* El saludo NUNCA parte en dos lineas (peticion de Pedro): si el @usuario es
   largo se queda en una linea y se desvanece por la derecha con una mascara,
   en vez de saltar de linea o cortarse en seco. Con nombres cortos la zona de
   fade queda vacia y no se nota. */
.al-saludo { font-family: var(--al-display); font-weight: 800; font-size: 1.9rem; line-height: 1.02; letter-spacing: -0.02em; margin: 0 0 16px; white-space: nowrap; overflow: hidden; -webkit-mask-image: linear-gradient(to right, #000 88%, transparent); mask-image: linear-gradient(to right, #000 88%, transparent); }
.al-saludo em { font-style: normal; color: var(--al-coral); }

/* El acceso a novedades ya no cuelga del saludo: se volvio al header, que es
   donde Pedro acepta ese boton (el unico de arriba), asi que el saludo no
   necesita fila ni pildora que vestir. Le basta el .al-saludo de aqui encima. */

/* ===== Titulos de seccion ===== */
.al-seccion { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: var(--al-tinta-2); margin: 40px 0 8px; }
/* Ultimo paso para que el Inicio entre COMPLETO en un movil grande sin scroll:
   los 40 de separacion entre secciones bajan al escalon de 24 de la escala de
   aire (8/12/16/24/40). Con tres secciones son 48px, y lo que faltaba medido en
   el navegador a 430x932 eran 33 (scrollHeight 892 contra clientHeight 859).
   Por que aqui y no en otro sitio: es el unico hueco que se repite tres veces,
   asi que el ajuste se reparte en vez de recortar 33px de un solo lugar. Con 32
   se quedaba en 9px de scroll (o sea: no cumplia por si solo) y para llegar con
   32 habia que tocar ademas el cierre de abajo y el aire del bloque destacado,
   que son aire de UNA vez cada uno: peor reparto.
   Va en su propio media DESPUES de la regla base a proposito: el media de movil
   de arriba de la hoja esta antes, y a igual especificidad gana la ultima.
   Escritorio no se toca (sigue en 40): alli las secciones van en dos columnas y
   la primera de cada columna ya anula su margen de arriba. */
@media (max-width: 768px) {
  /* Separacion entre secciones mas compacta (24 -> 16): el hueco DEBAJO de Tests
     (tests -> promociones) se veia demasiado (peticion de Pedro). Encima de Tests
     el aire lo da el carrusel + el first-child de abajo. */
  /* Hueco ENTRE secciones (peticion de Pedro: tests -> promociones quedaba
     demasiado). El hueco real = padding-bottom de la ultima fila (12) + esto,
     asi que con 8 el salto entre secciones es 20px, uniforme en toda la pagina.
     El PRIMER titulo es otra cosa: no separa dos secciones, separa la seccion
     del carrusel, que es una pieza con foto y peso visual. Con los mismos 20px
     se leia como pie del hero (peticion de Pedro con captura), asi que ahi el
     hueco sube a 8 (carrusel) + 20 = 28. */
  .al-seccion { margin-top: 8px; }
  .al-secciones .al-seccion-bloque:first-child .al-seccion { margin-top: 20px; }
}

/* ===== Iconos de fila ===== */
/* Blob organico (los "circulitos irregulares") con un icono de TRAZO dentro, en
   el sitio de la foto de las filas que no tienen banner propio.
   La caja mide 52 como .al-fila-img y el blob 44 (inset de 4): asi una lista con
   filas de foto y filas de icono mantiene el texto alineado, y el icono pesa
   menos que una foto, que es lo que toca (es interfaz, no contenido).
   El blob va en un ::before y no en la propia caja para poder GIRARLO sin
   torcer el dibujo: el icono se queda recto encima.
   El area pulsable no se toca: el ::before esta contenido en la caja (inset
   positivo), sin z-index ni desbordamientos, dentro del <a> de la fila. */
.al-icono { position: relative; flex: 0 0 52px; width: 52px; height: 52px; display: flex; align-items: center; justify-content: center; color: var(--al-icono-trazo); }
.al-icono::before { content: ""; position: absolute; inset: 4px; background: var(--al-icono-fondo); border-radius: 68% 32% 55% 45% / 42% 58% 42% 58%; transform: rotate(-8deg); }
.al-icono svg { position: relative; width: 22px; height: 22px; }
/* Cada variante trae su par de tokens y su propia deformacion: son circulos
   irregulares, no el mismo circulo repetido tres veces. */
.al-icono--coral { --al-icono-fondo: var(--al-icono-coral-fondo); --al-icono-trazo: var(--al-icono-coral-trazo); }
.al-icono--azul { --al-icono-fondo: var(--al-icono-azul-fondo); --al-icono-trazo: var(--al-icono-azul-trazo); }
.al-icono--azul::before { border-radius: 38% 62% 44% 56% / 60% 38% 62% 40%; transform: rotate(7deg); }
.al-icono--verde { --al-icono-fondo: var(--al-icono-verde-fondo); --al-icono-trazo: var(--al-icono-verde-trazo); }
.al-icono--verde::before { border-radius: 57% 43% 63% 37% / 37% 62% 38% 63%; transform: rotate(-5deg); }
/* Y dentro de un mismo mundo (la seccion de pisos son tres filas verdes) el
   blob tampoco se repite: las filas en posicion par giran al otro lado. El
   contador es del <section>, cuyo primer hijo es el <h2> del titulo. */
.al-fila:nth-child(even) .al-icono::before { border-radius: 44% 56% 35% 65% / 58% 42% 60% 40%; transform: rotate(9deg); }

/* ===== Hero ===== */
/* Ya no hay nada colgando bajo la foto: el boton y el dato secundario viven
   DENTRO de ella (ver .al-hero-abajo), asi que el articulo es la foto y su
   margen es todo el cierre del bloque. Sin hairline: la foto es un rectangulo
   redondeado con su propio borde visual, y una linea pegada debajo solo repetia
   el corte que ya hace la imagen. */
/* 8px (antes 16): el hueco hero -> primera seccion se veia muy alto (peticion
   de Pedro). Con la seccion a 24 arriba, el gap queda en 32 en vez de 40. */
.al-hero { margin-bottom: 8px; }
/* space-between (antes flex-end): el bloque de arriba (fecha + titulo) se ancla
   al borde superior y el de abajo (boton coral) al inferior. Peticion de Pedro:
   fecha/titulo arriba para que no choquen con el boton ni con los puntos. */
.al-hero-foto { position: relative; height: var(--al-hero-alto); border-radius: var(--al-radio); overflow: hidden; display: flex; flex-direction: column; justify-content: space-between; padding: 16px; background: var(--al-hero-relleno); }
/* La foto llega dentro de un <picture> (components/al_hero_foto.html), que
   elige la version apaisada o la cuadrada segun el ancho de pantalla. El
   selector del <img> es descendiente y no de hijo directo justamente por eso:
   cuelga del <picture>, no de la caja.
   Y el <picture> tiene que salir del flujo con la misma insistencia que el
   <img>: esta caja es un flex en columna con space-between y DOS bloques
   (el titulo arriba, el boton abajo). Un tercer hijo en el flujo, aunque mida
   cero, se lleva su reparto y el titulo se cae al centro de la foto con su velo
   detras (roto en la captura de Pedro). Con inset 0 el <picture> cubre la caja
   y ademas es el contenedor posicionado del <img>, que se estira sobre el. */
.al-hero-foto picture { position: absolute; inset: 0; }
.al-hero-foto img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Velo de DOS capas y no de una: los banners reales son carteles de discoteca, o
   sea que la mitad de abajo ya trae TEXTO impreso (nombre del local, cartel de
   djs, "invitados sorpresa") en blanco y en negrita, justo donde el hero pone su
   titular.
     - Capa 1 (velo general): arranca transparente y sube por cuatro paradas
       hasta un maximo SUAVE abajo.
     - Capa 2 (contraste local): del 42% para abajo, o sea la mitad donde viven
       la fecha y el titular, para que la parte alta de la foto no pague el
       contraste de la parte baja.
   El degradado es MUCHO mas suave que en la version anterior (la capa 1 cerraba
   en 0.99 y la 2 en 0.90, o sea 0.999 de negro juntas): peticion de Pedro, "que
   se reconozca el fondo". Con aquellos valores, la mitad inferior del cartel
   quedaba en 0.94-1.00 de negro, o sea que la foto desaparecia y el bloque
   destacado se leia como un rectangulo negro con una franja de imagen arriba.
   Ahora el velo cierra en 0.38 juntas las dos capas: la foto se lee como foto en
   TODA la tarjeta y el texto flota encima.
   Lo que da el contraste ya no es este velo sino el panel del bloque de texto
   (.al-hero-abajo::before), que cubre solo la franja donde estan las letras. El
   velo es el degradado de composicion, no la herramienta de legibilidad: por eso
   puede ser suave. Y por eso ya no necesita cerrar opaco abajo, que era para
   tapar el corte con una fila de meta que hoy no existe (el boton y el pie viven
   dentro de la foto). */
.al-hero-foto::after { content: ""; position: absolute; inset: 0; background: rgba(14, 13, 16, 0.18); }
/* Pero si la diapositiva NO lleva titulo encima, la foto va LIMPIA: sin velo y
   sin panel (peticion de Pedro, 2026-08-10: "tiene que verse la imagen como la
   estoy subiendo"). Es el caso de una creatividad que ya trae su mensaje
   escrito: el velo solo estaba ahi para que se leyera un texto que no existe, y
   lo unico que hacia era apagarle la imagen.
   Va en negativo (:not(:has())) a proposito: un navegador sin :has() se salta
   estas dos reglas y se queda con el velo, que es el comportamiento de siempre.
   Al reves, los que no lo soportan se quedarian sin velo con el titulo puesto,
   que si seria un fallo de legibilidad. */
.al-hero-foto:not(:has(.al-hero-titulo))::after { background: transparent; }
.al-hero-foto:not(:has(.al-hero-titulo)) .al-hero-abajo::before { background: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
/* Todo el contenido de la foto (etiqueta, titular, linea de apoyo y boton) va en
   este bloque, anclado al borde inferior por el justify-content de la foto.
   El z-index lo sube por encima del velo de una vez (antes lo pedian la etiqueta
   y el titular cada uno por su cuenta) y el blanco lo hereda todo: dentro de la
   foto, el texto se lee sobre el velo y no sobre el lienzo.
   El boton NO va al lado del titular sino en su propia fila debajo (ver
   .al-hero-accion). Probado con captura de las dos formas: como hermano de flex
   del texto, el titular se quedaba con la mitad del ancho (200px de 398) y
   'Fiesta de bienvenida · Oh My Club' pasaba de dos lineas a tres, con la
   ultima huerfana. El titular es la pieza dominante de la pantalla y necesita
   todo el ancho; el boton no cuesta vertical de pagina en ninguna de las dos
   formas, porque la foto mide lo que mide. */
.al-hero-abajo { position: relative; z-index: 1; color: #fff; }
/* Bloque de arriba (fecha + titulo). SIN velo propio: peticion de Pedro
   (2026-08-10, viendo 'Verano Sanxenxo 2026' en el Destacado), la banda oscura
   degradada detras del titular se notaba como una mancha y no le gusta. Queda
   solo el velo base de la foto, que es parejo en toda la tarjeta.
   Si en algun cartel muy claro el titular se lee justo, la solucion NO es
   devolver esta banda: es el panel de .al-hero-abajo::before, que cubre la
   franja del texto sin dibujar un borde. */
.al-hero-arriba { position: relative; z-index: 1; color: #fff; }
/* PANEL DE LEGIBILIDAD, la pieza que hace que el titular gane SIEMPRE al cartel.
   El problema medido (captura extra9-hub-claro, y con numeros en extra10): un
   flyer de discoteca trae su propio lettering impreso (nombre de la sala, la
   hora, 'AFORO COMPLETO') justo en la franja donde el hero pone su titular. Con
   solo el velo de degradado, ese texto del cartel se transparentaba a medias
   detras del titular y parecia un defecto de maquetacion. Contraste medido del
   blanco del titular contra el peor pixel de su propia caja, sobre un cartel
   claro y saturado: 1.49:1, o sea ilegible.
   Reforzar el velo una tercera vez no era el camino (a base de negro global la
   foto se convierte en un rectangulo negro y deja de ser una foto). Lo que hay
   aqui es una capa que cubre SOLO la franja del bloque de texto:
     - blur del fondo: el lettering del cartel deja de ser tipografia legible y
       pasa a ser un campo de color. Es lo que quita la pelea de dos textos, y no
       se puede conseguir oscureciendo (por muy oscuro que este, un texto nitido
       detras de otro texto sigue leyendose como texto).
     - saturate 0.85 baja los rosas y amarillos del cartel, que son los que se
       comen un blanco.
     - mas un oscurecido semitransparente, que es lo que da el contraste
       numerico: 0.55 de negro deja el peor pixel del caso extremo en 5.7:1
       (medido, no calculado).
   La capa se ancla al BLOQUE DE TEXTO y no a un porcentaje de la foto: si el
   titular ocupa tres lineas el panel crece con el, y si ocupa una se queda en la
   banda de abajo. Asi cubre lo necesario y nada mas.
   Y no se ve como un rectangulo: la mascara lo desvanece en los 40px de ARRIBA
   del bloque, o sea que la transicion vive en la zona limpia de la foto y el
   texto siempre cae en la parte de alfa completa (si el desvanecido acabase
   dentro del bloque, la primera linea del titular caeria en la parte floja, que
   es justo donde se veia el defecto). El fundido es LARGO y con dos paradas
   intermedias (0.18 y 0.62) en vez de una sola al 50%: con 32px lineales se
   adivinaba el borde de arriba del panel, y esta es la unica pieza cuyo borde
   podria delatar que hay una capa ahi.
   CALIBRACION (peticion de Pedro: "un blur oscuro pequenito, que no se note
   mucho pero se reconozca el fondo"): el blur baja de 10px a 5px y el negro de
   0.55 a 0.52. El negro no puede bajar mas: es lo que da el contraste, y medido
   en el navegador sobre el peor cartel (claro y saturado justo debajo del texto)
   con 0.30 de negro el peor pixel del titular se queda en 2.8:1, o sea ilegible.
   Con 0.52 son 5.1:1 el titular y 4.7:1 la etiqueta, que es el suelo de 4.5:1
   con un poco de margen. Lo que se aligero de verdad es el VELO de la foto (ver
   .al-hero-foto::after): el conjunto pasa de 0.94-1.00 de negro en la mitad
   inferior a 0.60-0.70, y ahi si se reconoce el cartel.
   z-index -1 lo pone detras del texto de su propio bloque y, como el bloque es
   contexto de apilado (z-index 1), el panel sigue por ENCIMA de la imagen y del
   velo. Los puntos del carrusel se suben a 2 para que no queden debajo del panel
   (borrosos y apagados no dirian en que diapositiva estas). */
.al-hero-abajo::before { content: ""; position: absolute; z-index: -1; inset: 0 -16px -16px; background: linear-gradient(180deg, rgba(14, 13, 16, 0) 0%, rgba(14, 13, 16, 0.12) 65%); }
/* Sin backdrop-filter (Firefox con la bandera apagada, WebView viejo) el
   lettering del cartel se queda NITIDO detras del titular y ademas el peor pixel
   no se promedia con sus vecinos, asi que la unica palanca que queda es mas
   negro: 0.58 en vez de 0.52. Medido en el mismo cartel del peor caso, 0.58 sin
   blur da 5.7:1 en el titular y 5.4:1 en la etiqueta, o sea por encima de lo que
   da la version con blur; con 0.52 y sin blur se caeria a 4.3:1. Tapa un poco
   mas de foto, que es el orden correcto de prioridades cuando no se puede
   difuminar. */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .al-hero-foto::after { background: rgba(14, 13, 16, 0.25); }
  .al-hero-abajo::before { background: linear-gradient(180deg, rgba(14, 13, 16, 0) 0%, rgba(14, 13, 16, 0.58) 65%); }
}
/* SIN sombra en el texto de la foto: peticion de Pedro (2026-08-10), en el
   Destacado se le notaba al titular y no le gusta. Era una compensacion
   tipografica de haber aligerado el velo, y sumaba 0.3 puntos de contraste
   (5.1:1 -> 5.4:1 en el peor cartel), pero NO era el suelo: los 4.5:1 exigidos
   los cumple el fondo desnudo, asi que quitarla no baja de AA.
   Lo que si se queda de aquel ajuste es la tinta del texto pequeno al 0.95 de
   blanco (ver .al-hero-fecha mas abajo), que ese SI era el suelo. Con el velo suave,
   un blanco al 78% sobre un cartel claro se acerca demasiado a su propio fondo:
   medido, la etiqueta se quedaba en 4.4:1 incluso con el velo VIEJO (ya era el
   peor dato de la pantalla). Un texto translucido sobre un fondo claro se acerca
   a su propio fondo por los dos lados a la vez, asi que aqui la transparencia
   cuesta contraste de verdad. A 0.95 la etiqueta y el pie tienen holgura (4.7:1
   en el peor cartel, contra 4.5:1 exigido; a 0.92 se quedaban en 4.53:1, que es
   pasar por los pelos) y siguen leyendose como secundarios, que es cosa del
   tamano y del peso, no de la transparencia. */
.al-hero-fecha, .al-hero-titulo, .al-hero-pie, .al-hero-estado { text-shadow: none; }
/* La fecha sigue siendo una etiqueta en versales (es un dato, no una frase),
   pero con el tracking suavizado a 0.1em: con 0.16em y el titulo ya en caja de
   frase era la unica pieza de la pantalla que gritaba.
   En blanco y no en rosa: sobre el cartel era un cuarto acento calido (con el
   coral del CTA, el 'hoy' del saludo y el enlace de la nota) y encima competia
   con los rosas que suele traer el propio cartel. Ahora es lo que es, el pie de
   foto de la imagen. Al 95% y no al 78% (ver la regla de la sombra): es el texto
   mas pequeno de la foto y era el dato peor medido de la pantalla. */
.al-hero-fecha { font-size: 0.66rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: rgba(255, 255, 255, 0.95); margin-bottom: 6px; }
/* Tres lineas como techo: Evento.nombre admite 200 caracteres y la foto tiene
   alto fijo con el contenido pegado abajo, asi que un nombre largo se recortaba
   por ARRIBA (se perdia el principio del titulo, que es lo que se lee). Con el
   clamp el recorte pasa al final y con puntos suspensivos.
   Y sin text-wrap: balance, aunque el saludo si lo lleve. Probado con captura: a
   375px equilibra las lineas (301/100 px pasaban a 251/150) pero los nombres de
   evento los escribe el admin y suelen traer el punto medio de la casa
   ('Fiesta de bienvenida · Oh My Club'); al equilibrar, el separador se iba al
   principio de la segunda linea y se leia como una vineta. Rellenando de
   izquierda a derecha el punto se queda pegado a lo que separa. */
.al-hero-titulo { font-family: var(--al-display); font-weight: 800; font-size: 1.6rem; line-height: 1.02; letter-spacing: -0.02em; margin: 0; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; }
/* El dato secundario (el subtitulo de un destacado) era el texto de al lado del
   boton en la fila que colgaba de la foto. Ahora es una linea fina bajo el
   titular, dentro de la foto: no se pierde y no cuesta vertical. En blanco al
   95% (no en --al-tinta-2) porque se lee sobre el velo, y a una sola linea con
   puntos suspensivos: son 160 caracteres de campo y aqui es un pie, no un
   parrafo. */
.al-hero-pie { font-size: 0.74rem; color: rgba(255, 255, 255, 0.95); margin: 6px 0 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Fila del boton: ultima linea del bloque y alineada a la derecha, o sea la
   esquina inferior derecha de la foto (peticion de Pedro). Como es su propia
   fila, el titular de arriba conserva TODO el ancho. */
.al-hero-accion { display: flex; justify-content: flex-end; align-items: center; margin-top: 8px; }

/* ===== Carrusel de destacados ===== */
/* Arriba del Inicio puede haber VARIAS cosas promocionadas (modelo Destacado)
   pasando una a una cada 10 segundos.
   Las diapositivas se APILAN en una sola celda de grid en vez de posicionarse
   absolutas: la caja mide lo que la mas alta, todas comparten el mismo hueco y
   al cambiar de una a otra no se mueve ni un pixel de lo que hay debajo. Y sin
   altura muerta: el grid no reserva mas de lo que ocupa su contenido, asi que
   el hub sigue cabiendo en una pantalla.
   .al-slide es la mecanica (apilado, desvanecido, estado) y .al-hero el vestido:
   el hero de una diapositiva es exactamente el mismo componente que el hero de
   siempre, con su foto, su velo, su etiqueta y su boton. */
.al-carrusel { position: relative; }
.al-slides { display: grid; }
.al-slide { grid-area: 1 / 1; transition: opacity 0.26s ease; }
/* La oculta se desvanece pero NO sale del flujo: si saliera (display: none), la
   caja del carrusel cambiaria de alto al pasar de una diapositiva a otra.
   aria-hidden la saca del lector de pantalla, inert del tabulador y
   pointer-events cierra la puerta al raton donde inert no llegue. */
.al-slide[aria-hidden="true"] { opacity: 0; pointer-events: none; }
/* Los puntos van SOBRE la foto y no en una fila propia debajo: una fila mas
   seria alto muerto en la unica pantalla que tiene el hub. Cubren toda la caja
   de la foto (de ahi el --al-hero-alto) con el raton desactivado y se pegan a su
   franja inferior, que es la parte mas oscura de la tarjeta (velo y panel juntos,
   ~0.70 de negro) y ademas llevan sombra propia: en blanco se leen encima de
   cualquier cartel.
   Alineados a la izquierda, en el mismo eje que la etiqueta y el titular, para
   que se lean como parte de la composicion y no como un mando pegado en una
   esquina. Solo se pintan cuando el JS ha arrancado (data-al-listo): sin JS no
   llevarian a ninguna parte.
   El relleno de abajo (25) los pone en la MISMA fila que el boton coral, que
   ahora vive en la esquina inferior derecha de la foto: 16 del relleno de la
   foto mas la mitad de la diferencia de altos (44 del boton, 26 del punto), asi
   que los dos quedan centrados en el mismo eje. */
/* El z-index 2 los pone por encima del panel de legibilidad del bloque de texto
   (que va en z-index 1): si quedaran debajo, el blur y el negro del panel los
   apagarian y dejarian de decir en que diapositiva estas. Al boton no le quitan
   nada porque no se cruzan: el CTA esta acotado para que no llegue a su banda
   (ver la regla de .al-hero-cta con carrusel). */
/* Puntos en la esquina inferior IZQUIERDA, mas pegados al borde de abajo (14 en
   vez de 25): peticion de Pedro ("no tan arriba"). El titulo ya no comparte esa
   banda (se fue arriba), asi que solo conviven con el boton coral de la derecha. */
.al-puntos { position: absolute; left: 0; right: 0; top: 0; z-index: 2; height: var(--al-hero-alto); display: none; align-items: flex-end; padding: 0 11px 14px; pointer-events: none; }
.al-carrusel[data-al-listo] .al-puntos { display: flex; }
/* El circulo mide 6px pero el boton llega a 26 de alto y 16 de ancho: el dedo
   necesita area, la vista no. */
.al-punto { pointer-events: auto; height: 26px; padding: 0 5px; display: flex; align-items: center; border: 0; background: none; cursor: pointer; }
.al-punto::before { content: ""; width: 6px; height: 6px; border-radius: 999px; background: rgba(255, 255, 255, 0.45); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45); transition: width 0.22s ease, background 0.22s ease; }
/* El activo se estira a pildora en vez de crecer de tamano: dice donde estas
   sin convertirse en un boton gordo. */
.al-punto[aria-current="true"]::before { width: 16px; background: #fff; }
.al-punto:focus-visible { outline: 2px solid #fff; outline-offset: 1px; border-radius: 999px; }
/* Los puntos comparten fila con el boton, asi que normalmente no hay que
   reservarles nada: la fila de accion ya deja libre esa banda de la foto.
   La excepcion es una diapositiva SIN boton (un destacado puede no llevar
   enlace): ahi no hay fila que ceder el sitio y el titular se cruzaria con los
   puntos, asi que el bloque reserva la banda el mismo. El :not(:has()) es lo que
   distingue los dos casos sin tocar la plantilla; un navegador sin :has() se
   salta la regla y en ese caso los puntos quedan mas pegados al titular (se
   pierde el aire, no el layout). */
.al-carrusel[data-al-carrusel] .al-hero-abajo:not(:has(.al-hero-accion)) { padding-bottom: 46px; }
/* Y con carrusel el boton no se estira hasta la banda de los puntos: medido con
   un texto de boton de 43 caracteres (el campo admite 50), la pildora llegaba a
   x=74 y se cruzaba con el tercer punto. Los 110px dejan sitio a cuatro puntos;
   con muchos mas destacados la rotacion ya seria demasiado larga de ver entera.
   Ahora los puntos van por encima (z-index 2, por el panel de legibilidad), asi
   que sin este tope el punto se pintaria SOBRE la pildora coral: mismo remedio,
   una razon mas. */
.al-carrusel[data-al-carrusel] .al-hero-cta { max-width: calc(100% - 110px); }
/* El estado tiene la misma forma que el boton, asi que el mismo tope. */
.al-carrusel[data-al-carrusel] .al-hero-estado { max-width: calc(100% - 110px); }
/* Y con carrusel el cierre del bloque (el aire de debajo) pasa a ser del
   contenedor en vez de de cada diapositiva: una sola medida para las tres,
   pase lo que pase con el alto de cada una. */
.al-carrusel[data-al-carrusel] { margin-bottom: 8px; }
.al-carrusel[data-al-carrusel] .al-hero { margin-bottom: 0; }

/* ===== CTA ===== */
/* El texto del CTA de una promo lo escribe el admin (Evento.texto_boton, hasta
   50 caracteres), asi que no puede empujar la fila: cede ancho (shrink) y corta
   con puntos suspensivos en vez de desbordar el lienzo. Medido a 375px con 49
   caracteres: caja de 339px de los 343 disponibles y el documento sin scroll
   horizontal. Mismo remedio en .al-fila-chevron. */
.al-cta { flex: 0 1 auto; min-width: 0; display: inline-block; background: var(--al-coral-texto); color: #fff; font-size: 0.76rem; font-weight: 700; letter-spacing: 0.04em; padding: 9px 18px; border-radius: 999px; text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: transform 0.15s ease, opacity 0.15s ease; }
.al-cta:hover { opacity: 0.92; color: #fff; }
.al-cta-off { flex: 0 0 auto; font-size: 0.76rem; color: var(--al-tinta-2); }
/* Variante del CTA dentro de la foto del hero, en su esquina inferior derecha
   (peticion de Pedro: "quiza deberia estar en la esquina derecha inferior para
   que no ocupe tanto espacio vertical"). Tres cosas cambian y ninguna es
   decorativa:
     - min-height 44 con inline-flex: es el unico control de la zona destacada y
       en la fila de debajo se quedaba en 36px de dedo. El texto no crece, crece
       la caja, y el centrado lo pone el propio flex (con min-height a secas la
       palabra se queda arriba).
     - max-width 100%: Evento.texto_boton admite 50 caracteres, asi que en su
       fila el boton llega como mucho de borde a borde y corta con puntos
       suspensivos (lo hereda de .al-cta). Al titular no le quita ancho porque
       no comparten fila.
   El contraste lo da el token de siempre (--al-coral-texto, blanco 4.70:1) y el
   fondo lo tiene ganado: en la franja inferior el velo y el panel juntos dejan
   ~0.70 de negro, asi que la pildora coral se lee sobre cualquier cartel. La
   sombra corta la despega del cartel cuando el cartel trae su propio rosa justo
   detras. */
.al-hero-cta { display: inline-flex; align-items: center; min-height: 44px; max-width: 100%; padding: 0 18px; box-shadow: 0 2px 8px rgba(14, 13, 16, 0.35); }
/* Estado sin destino ('Cerrado', 'Muy pronto'): no es un control, asi que no
   lleva pildora, pero ahora se lee sobre la foto y no sobre el lienzo, o sea
   que --al-tinta-2 (gris oscuro en tema claro) lo dejaba ilegible. Mismo blanco
   al 95% que la etiqueta y el pie. Los 12px de relleno le dan a su fila el aire
   que en el boton pone la pildora, para que el bloque no cambie de alto entre
   una diapositiva con boton y otra sin el. La regla va DESPUES de .al-cta-off a
   proposito: misma especificidad, gana la ultima. */
/* Misma pildora que el CTA pero apagada y sin destino (peticion de Pedro: le
   gusta el boton, lo quiere ahi pero que no se pueda pulsar). Como texto pelado
   se quedaba pegado al canto derecho de la foto: la fila alinea a la derecha y
   era la pildora la que ponia el relleno de esa esquina.
   No lleva coral: el coral es el acento de lo que SI se puede hacer, y esto es
   un estado. Blanco translucido con hairline y un desenfoque corto detras, que
   es lo que lo despega de un cartel claro sin pintarle una caja opaca encima.
   El min-height de 44px es el mismo del boton, asi la fila no cambia de alto
   entre una diapositiva con boton y otra con estado. */
.al-hero-estado {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 44px; padding: 0 18px;
    font-weight: 700; letter-spacing: 0.04em; white-space: nowrap;
    color: rgba(255, 255, 255, 0.95);
    /* Relleno OSCURO y no blanco translucido: sin velo (una creatividad sin
       titulo) un blanco al 14% sobre un cartel claro deja la pildora y su letra
       blanca sobre casi el mismo tono. El negro al 45% se lee sobre lo que
       venga, claro u oscuro. */
    background: rgba(14, 13, 16, 0.45);
    border: 1px solid rgba(255, 255, 255, 0.30);
    border-radius: 999px;
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
}
/* Los dos CTA se disenaron para <a>; el formulario de comunicaciones necesita
   botones de verdad (POST), asi que se les quita el vestido del navegador.
   El de rechazar SI lleva pildora de hairline: como texto pelado al lado del
   coral no se leia como un boton, parecia la etiqueta del de al lado (y es la
   respuesta 'no' de una pregunta, tiene que poderse pulsar sin dudar). El
   .al-cta-off de las filas se queda en texto plano a proposito: ahi no es un
   control, es un estado ('Cerrado', 'Muy pronto'). */
button.al-cta, button.al-cta-off { font-family: inherit; cursor: pointer; }
button.al-cta { border: 0; }
button.al-cta-off { background: none; border: 1px solid var(--al-hairline); border-radius: 999px; padding: 8px 16px; font-weight: 600; }
button.al-cta-off:hover { color: var(--al-tinta); border-color: var(--al-tinta-2); }
.al-cta:focus-visible, .al-cta-off:focus-visible { outline: 2px solid var(--al-coral); outline-offset: 2px; }

/* ===== Filas y cards ===== */
.al-fila { display: flex; gap: 12px; align-items: center; padding: 12px 0; border-bottom: 1px solid var(--al-hairline); text-decoration: none; color: inherit; transition: opacity 0.18s ease; }
.al-fila:last-child { border-bottom: none; }
/* Acordeon colapsado: la ultima fila visible queda JUSTO antes de .al-mas-extra
   (oculto), asi que :last-child no la coge y le sobraba una raya de separacion
   (peticion de Pedro: sin separador tras la 2a fila hasta que se despliega).
   Cuando .al-mas-extra esta [hidden] esa fila pierde el borde; al desplegar
   (.al-mas-extra sin [hidden]) vuelve, para separarla de la 3a. */
.al-fila:has(+ .al-mas-extra:not(.is-open)) { border-bottom: none; }
/* "Ver N mas" en la MISMA linea del titulo de seccion (Promociones y eventos):
   la cabecera es flex (titulo a la izquierda, boton a la derecha con flechita) y
   las filas 3+ viven en .al-mas-extra, que el boton despliega. Peticion de
   Pedro: que no ocupe una fila propia. El margen de separacion de seccion se
   mueve a la cabecera y el h2 de dentro va sin margen. */
.al-seccion-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin: 40px 0 8px; }
/* El override movil va AQUI (despues de la base) a proposito: la base esta mas
   abajo en la hoja que el @media de arriba, asi que a igual especificidad ganaba
   los 40px y el hueco tests -> promociones salia 5x mas grande que el resto.
   Medido con Chrome headless: 40px vs 8px. Con esto los dos huecos son 8px. */
@media (max-width: 768px) { .al-seccion-head { margin-top: 8px; } }
.al-seccion-head .al-seccion { margin: 0; min-width: 0; }
.al-mas-btn { flex: none; cursor: pointer; display: inline-flex; align-items: center; gap: 5px; background: none; border: 0; padding: 0; font-family: inherit; font-size: 0.8rem; font-weight: 600; color: var(--al-coral); white-space: nowrap; }
.al-mas-btn:hover { opacity: 0.82; }
.al-mas-chevron { width: 7px; height: 7px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(45deg); margin-top: -2px; transition: transform 0.2s ease; }
.al-mas-btn.is-open .al-mas-chevron { transform: rotate(-135deg); margin-top: 2px; }
/* Despliegue ANIMADO (peticion de Pedro: animacion limpia al "Ver N mas").
   grid-template-rows 0fr -> 1fr anima a altura AUTOMATICA sin saltos ni JS de
   medir; el wrapper interno recorta con overflow mientras crece. */
.al-mas-extra { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.34s cubic-bezier(0.4, 0, 0.2, 1); }
.al-mas-extra.is-open { grid-template-rows: 1fr; }
.al-mas-inner { overflow: hidden; min-height: 0; }
@media (prefers-reduced-motion: reduce) { .al-mas-extra { transition: none; } }
a.al-fila:hover { opacity: 0.85; color: inherit; }
/* La foto de la fila: la version CUADRADA del evento (banner_hub_cuadrado), que
   para eso existe, porque en una caja de 52x52 un 16:9 se queda en la franja
   del centro. Cuando la fila no tiene foto de ninguna clase, en su sitio va
   .al-icono. El fondo se ve mientras la imagen carga (y si el archivo ya no
   esta en el storage).
   Misma forma de guijarro que el blob de los iconos, y no un cuadrado
   redondeado (peticion de Pedro): en una lista donde unas filas llevan foto y
   otras icono, dos siluetas distintas se leen como dos tipos de fila. El
   guijarro NO se gira como el del icono: alli lo que rota es un ::before vacio
   y el dibujo se queda recto encima, mientras que rotar esto inclinaria la
   foto. */
.al-fila-img { width: 52px; height: 52px; border-radius: 68% 32% 55% 45% / 42% 58% 42% 58%; flex: 0 0 52px; object-fit: cover; background: var(--al-relleno); }
/* Y como en los iconos, dentro de una misma lista el guijarro no se repite: las
   filas pares llevan otra deformacion. */
.al-fila:nth-child(even) .al-fila-img { border-radius: 44% 56% 35% 65% / 58% 42% 60% 40%; }
.al-fila-txt { flex: 1; min-width: 0; }
/* 600 y no 650: la Plus Jakarta Sans que importa style.css trae 300-700 sin el
   650, y pedirla otra vez con un peso suelto arriesga la hoja entera. */
.al-fila-txt b { display: block; font-size: 0.88rem; font-weight: 600; }
.al-fila-txt span { font-size: 0.72rem; color: var(--al-tinta-2); }
/* Dos lineas como techo: la linea de apoyo puede ser la descripcion del evento
   (12 palabras) y a 375px, con el hueco de la imagen y la accion a los lados,
   se iba a tres o cuatro lineas y rompia el ritmo de la lista. El clamp va
   acotado a .al-fila: la card del consentimiento reutiliza .al-fila-txt y ahi el
   texto es legal (RGPD), no se puede recortar. La tipografia se queda fuera del
   acote para que la card no suba a tamano de cuerpo (se leeria mas grande que su
   propio titulo). */
.al-fila .al-fila-txt span { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
/* Cierre de fila: la accion mas el chevron. Va en tinta (el subtitulo va en
   tinta-2) para que se lea como algo pulsable, y sin coral: el unico acento de
   la pantalla es el CTA del hero. Es un <a> cuando la fila NO es el enlace
   (los tests, que se pintan en <article>) y un <span> decorativo cuando la
   fila entera ya enlaza. Los estados sin destino usan .al-cta-off. */
.al-fila-chevron { margin-left: auto; flex: 0 1 auto; min-width: 0; font-size: 0.72rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--al-tinta); text-decoration: none; }
/* Cuando enlaza, el area pulsable crece a ~40px de alto sin mover el texto (el
   negativo devuelve el aire que mete el padding): a 0.72rem el glifo solo daria
   17px de dedo. Margenes en longhand para no pisar el margin-left: auto. */
a.al-fila-chevron { padding: 12px 0; margin-top: -12px; margin-bottom: -12px; }
a.al-fila-chevron:hover { color: var(--al-tinta); text-decoration: underline; }
a.al-fila-chevron:focus-visible { outline: 2px solid var(--al-coral); outline-offset: 2px; }
/* Card: reservada para lo que de verdad es un bloque (hoy, el formulario de
   consentimiento: pregunta + dos botones + texto legal). Los avisos de perfil
   ya no la usan, son .al-nota. */
.al-card { background: var(--al-superficie); border: 1px solid var(--al-hairline); border-radius: var(--al-radio); padding: 12px 16px; margin-bottom: 12px; }

/* ===== Nota ===== */
/* Aviso de una linea, sin fondo ni borde: los recados de perfil (sube foto,
   verifica Instagram) son secundarios y como tarjeton se comian el hueco del
   hero. La vineta es un punto por ::before, no un emoji ni un icono de archivo
   (principio 6), y va en tinta-2 como el texto que acompana: en coral era la
   cuarta pieza coral de la pantalla por un adorno de 5px. El enlace es lo unico
   pulsable, y va en el coral que se lee sobre el lienzo (--al-coral-enlace,
   distinto por tema).
   La vineta va posicionada y no en flex: con flex, el texto y el enlace serian
   dos items distintos y el enlace dejaria de fluir con la frase. Asi el
   parrafo es normal y las lineas siguientes sangran bajo la primera. */
.al-nota { position: relative; padding-left: 13px; font-size: 0.76rem; line-height: 1.45; color: var(--al-tinta-2); margin: 0 0 12px; }
.al-nota::before { content: ""; position: absolute; left: 0; top: 0.55em; width: 5px; height: 5px; border-radius: 50%; background: var(--al-tinta-2); }
/* El padding vertical crece el dedo de 18px a 30px sin mover ni una linea: en un
   <a> en linea el relleno de arriba y abajo no cuenta para la caja de linea.
   Mismo remedio que en a.al-fila-chevron, alli con margen negativo porque es un
   item de flex y si cuenta. */
.al-nota a { color: var(--al-coral-enlace); font-weight: 600; text-decoration: underline; text-underline-offset: 2px; white-space: nowrap; padding: 6px 0; }
.al-nota a:hover { color: var(--al-coral-enlace); text-decoration: none; }
.al-nota a:focus-visible { outline: 2px solid var(--al-coral); outline-offset: 2px; }

/* ===== Avisos de cuenta ===== */
/* Solo queda el formulario de comunicaciones, que SI es una card: pregunta,
   texto legal y dos botones que hacen POST. Reutiliza .al-fila-txt.
   Pregunta con dos respuestas: los botones bajan a su propia linea, que a
   375px no caben al lado del texto. */
.al-aviso-acciones { display: flex; align-items: center; gap: 16px; margin-top: 12px; }

/* ===== Movimiento ===== */
@media (prefers-reduced-motion: reduce) {
  .al-cta, .al-fila { transition: none; }
  /* Quien pide menos movimiento no tiene por que ver el desvanecido (ni la
     rotacion automatica, que la corta el JS): el cambio de diapositiva es seco
     y los puntos siguen funcionando. */
  .al-slide, .al-punto::before { transition: none; }
}

/* ===== Escritorio ===== */
@media (min-width: 992px) {
  /* DOS COLUMNAS en escritorio (peticion de Pedro): el carrusel GRANDE a la
     izquierda (como una sola imagen bien formada) y las tres secciones a la
     derecha. Saludo y avisos abarcan las dos columnas arriba; el 'order' los
     coloca primero aunque en el markup los avisos vayan tras el carrusel. */
  .al-hub {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
    column-gap: 36px;
    align-items: start;
    max-width: 1120px;
    padding: 40px 40px 56px;
    --al-hero-alto: 460px;
  }
  /* El saludo va dentro de un <header> sin estilos: sin esto, el grid item seria
     el <header> (no el .al-saludo), asi que las reglas de grid del saludo (span,
     stretch) NO aplicaban y el saludo se quedaba del ancho de la 1a columna.
     display:contents hace el <header> transparente y el .al-saludo pasa a ser
     item del grid. Ese era el fallo real del fade (no la cache). */
  .al-hub > header { display: contents; }
  /* El saludo llega hasta el borde de la primera columna sin cruzar a la
     segunda, pero el fade es MENOS conservador (94%, no 88%): solo se desvanece
     lo que de verdad se pasa, no un nombre normal con sitio de sobra. */
  /* El saludo vive en la fila de ARRIBA, encima de las dos columnas, asi que usa
     TODO el ancho (no lo limito a la 1a columna: eso hacia que se desvaneciera
     justo al borde del carrusel). Caja de ancho fijo (stretch, no start) para
     que un nombre corto no llegue al fade, y el fade al 94%: solo se difumina un
     @usuario larguisimo de verdad. */
  .al-saludo { grid-column: 1 / -1; order: 0; font-size: 2.4rem; justify-self: stretch; -webkit-mask-image: linear-gradient(to right, #000 94%, transparent); mask-image: linear-gradient(to right, #000 94%, transparent); }
  .al-nota, .al-card { grid-column: 1 / -1; order: 1; }
  .al-card { max-width: 560px; }
  .al-carrusel { grid-column: 1; order: 2; }
  .al-secciones { grid-column: 2; order: 2; margin-top: 0; }
  .al-hero-titulo { font-size: 2rem; }
  /* Separacion entre secciones en la columna derecha; la primera empieza arriba
     del todo, a la altura del carrusel. */
  .al-seccion { margin-top: 8px; }
  .al-seccion-head { margin-top: 8px; }
  .al-secciones .al-seccion-bloque:first-child .al-seccion { margin-top: 0; }
  /* Carrusel VACIO (sin diapositivas): no dejar las secciones pinchadas a la
     derecha con un hueco a la izquierda. Pasan a una sola columna a la IZQUIERDA,
     sin centrar todo (peticion de Pedro). */
  .al-hub:not(:has(.al-carrusel .al-slide)) {
    grid-template-columns: minmax(0, 640px);
    justify-content: start;
  }
  .al-hub:not(:has(.al-carrusel .al-slide)) .al-carrusel { display: none; }
  .al-hub:not(:has(.al-carrusel .al-slide)) .al-secciones { grid-column: 1; }
}
