/* ==========================================================================
   SOLÍS FM DIGITAL — style.css
   Fase 1: Sistema de diseño + estructura (Mobile First)
   ========================================================================== */

/* ---------- 1. VARIABLES DE DISEÑO (Design Tokens) ---------- */
:root {
  /* Paleta de marca (fija por especificación del proyecto) */
  --primario: #04B8DC;      /* Cian de transmisión: CTAs, links, dial */
  --secundario: #043F53;    /* Azul profundo "cabina": headers, footer */

  /* Paleta funcional derivada */
  --acento-vivo: #FF3B30;      /* Rojo "ON AIR" para el indicador EN VIVO — fijo, no personalizable (convención de UX, no de marca) */
  --primario-oscuro: #037c96;  /* Hover/estados activos sobre --primario */
  --secundario-claro: #0a5c78; /* Superficies elevadas sobre --secundario */

  /* Fase 6 (white-label): acento y gradiente personalizables por cliente
     vía marca.json → colores. Ambos extremos del gradiente arrancan en
     --secundario a propósito (mismo color, sin degradado visible) — un
     cliente que no configure gradiente_inicio/gradiente_fin debe ver
     exactamente el mismo header sólido de siempre, no un gradiente nuevo
     que nadie pidió. app.js solo pisa estas variables si marca.json trae
     esos campos (ver aplicarTema()). */
  --acento: var(--primario);        /* Resaltados/badges genéricos (distinto de --acento-vivo) */
  --gradiente-inicio: var(--secundario);
  --gradiente-fin: var(--secundario);

  /* Neutros */
  --claro: #F5FAFB;         /* Fondo general del sitio */
  --superficie: #FFFFFF;    /* Tarjetas y superficies */
  --texto: #071A21;         /* Texto principal (alto contraste) */
  --texto-suave: #4C6672;   /* Texto secundario / metadatos */
  --borde: #DCE7EA;         /* Líneas divisorias sutiles */

  /* Tipografía */
  --fuente-display: 'Barlow Condensed', sans-serif; /* Titulares */
  --fuente-cuerpo: 'Inter', sans-serif;              /* Texto de lectura */
  --fuente-mono: 'JetBrains Mono', monospace;        /* Frecuencia / reloj */

  /* Escala tipográfica fluida */
  --fs-xs: 0.8rem;
  --fs-sm: 0.925rem;
  --fs-base: 1rem;
  --fs-lg: clamp(1.125rem, 1rem + 0.6vw, 1.375rem);
  --fs-xl: clamp(1.5rem, 1.2rem + 1.5vw, 2.25rem);
  --fs-2xl: clamp(2rem, 1.5rem + 2.5vw, 3.5rem);

  /* Espaciado */
  --space-1: 0.5rem;
  --space-2: 1rem;
  --space-3: 1.5rem;
  --space-4: 2.5rem;
  --space-5: 4rem;

  /* Estructura */
  --radio-borde: 10px;
  --sombra-suave: 0 4px 20px rgba(4, 63, 83, 0.08);
  --sombra-flotante: 0 -4px 24px rgba(4, 63, 83, 0.18);
  --altura-header: 76px;
  --altura-player: 92px;
  --ancho-contenido: 1200px;
  --transicion: 180ms ease;
}

/* ---------- 2. RESET Y BASE ---------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--altura-header) + var(--space-2));
}

body {
  margin: 0;
  font-family: var(--fuente-cuerpo);
  font-size: var(--fs-base);
  color: var(--texto);
  background: var(--claro);
  line-height: 1.55;
  /* Reserva espacio para que el reproductor sticky nunca tape contenido.
     OJO: NO sumar env(safe-area-inset-bottom) acá — .player-sticky ya mide
     exactamente --altura-player hacia afuera (box-sizing: border-box) y
     absorbe el safe-area con su propio padding-bottom interno (ver más
     abajo). Sumarlo dos veces dejaba un hueco blanco entre el footer y el
     player del tamaño del safe-area, visible en iPhones sin botón físico
     (home indicator) — reportado por el cliente con una captura real. */
  padding-bottom: var(--altura-player);
}

img { max-width: 100%; display: block; }
/* Fase 25 duodecies: <picture> (AVIF+JPEG) es "inline" por defecto — sin
   esto, dejaría un pequeño hueco debajo (comportamiento típico de
   elementos inline/imagen) donde antes había un <img> a secas. */
picture { display: block; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; margin: 0; padding: 0; }
h1, h2, h3, p { margin: 0; }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  background: var(--secundario);
  color: var(--claro);
  padding: var(--space-1) var(--space-2);
  z-index: 200;
}
.skip-link:focus {
  left: var(--space-2);
  top: var(--space-2);
}

/* Accesibilidad: foco visible consistente en toda la marca */
a:focus-visible,
button:focus-visible,
input:focus-visible {
  outline: 3px solid var(--primario);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Respeta a usuarios que prefieren menos movimiento */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}

/* ---------- 3. HEADER / MASTHEAD ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  height: var(--altura-header);
  /* Fase 6 (white-label): degradado personalizable por cliente (marca.json
     → colores.gradiente_inicio/gradiente_fin). Por defecto va de
     --secundario a --primario, así un cliente que no lo configure ve
     exactamente el mismo header sólido de siempre (ambos extremos caen en
     los mismos tonos de marca). */
  background: linear-gradient(120deg, var(--gradiente-inicio), var(--gradiente-fin));
  box-shadow: var(--sombra-suave);
}

.header-inner {
  max-width: var(--ancho-contenido);
  height: 100%;
  margin: 0 auto;
  padding: 0 var(--space-2);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  line-height: 1;
}

/* Logo real del cliente (marca.json → logo), junto al wordmark de texto.
   Si no hay imagen o falla la carga, app.js le pone [hidden] y el wordmark
   de texto ocupa el espacio solo, sin huecos ni íconos rotos. */
.brand-logo {
  height: 34px;
  width: auto;
  display: block;
  border-radius: 4px;
}
.brand-logo[hidden] { display: none; }

.brand-text {
  display: flex;
  flex-direction: column;
  line-height: 1;
}

.brand-name {
  font-family: var(--fuente-display);
  font-weight: 800;
  font-size: 1.6rem;
  letter-spacing: 0.5px;
  color: var(--claro);
}
.brand-accent { color: var(--primario); }

.brand-tag {
  font-family: var(--fuente-mono);
  font-size: 0.6rem;
  letter-spacing: 2px;
  color: var(--primario);
  margin-top: 2px;
}

/* Navegación: colapsada en móvil, botón hamburguesa */
.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px; height: 40px;
  background: transparent;
  border: 1px solid var(--secundario-claro);
  border-radius: 6px;
  cursor: pointer;
}
.nav-toggle-bar,
.nav-toggle-bar::before,
.nav-toggle-bar::after {
  content: '';
  display: block;
  width: 20px; height: 2px;
  background: var(--claro);
  position: relative;
}
.nav-toggle-bar::before { top: -6px; position: absolute; }
.nav-toggle-bar::after { top: 6px; position: absolute; }

.nav-menu {
  position: absolute;
  top: var(--altura-header);
  left: 0; right: 0;
  background: var(--secundario);
  display: flex;
  flex-direction: column;
  padding: var(--space-2);
  gap: var(--space-1);
  border-top: 1px solid var(--secundario-claro);
  transform: translateY(-8px);
  opacity: 0;
  pointer-events: none;
  transition: transform var(--transicion), opacity var(--transicion);
}
.nav-menu.is-open {
  transform: translateY(0);
  opacity: 1;
  pointer-events: auto;
}
.nav-link {
  font-family: var(--fuente-display);
  font-size: var(--fs-lg);
  color: var(--claro);
  padding: var(--space-1) 0;
}
.nav-link:hover { color: var(--primario); }

/* ---------- 3b. DESTACADOS: cintillo de últimas noticias (Fase 13) ----------
   Una sola animación CSS (transform, compositor de GPU) en vez de JS moviendo
   el DOM cada frame — deliberadamente más liviano que carruseles con
   librerías. app.js duplica la lista una vez para el loop infinito y calcula
   --destacados-duracion según el ancho real del contenido. */
.destacados-ticker {
  position: sticky;
  top: var(--altura-header);
  z-index: 90;
  display: flex;
  align-items: center;
  background: var(--secundario-claro);
  border-bottom: 1px solid rgba(4, 184, 220, 0.25);
  overflow: hidden;
}
.destacados-ticker[hidden] { display: none; }

.destacados-label {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--fuente-mono);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--secundario);
  background: var(--primario);
  padding: 6px var(--space-2);
  white-space: nowrap;
}

/* Fase 16: "radar" de noticia en vivo — un punto con un anillo que se
   expande y se desvanece (clásico "ping" de radar/sonar). Es CSS puro:
   un ::before con dos propiedades animadas (transform, opacity), ambas
   corren en el compositor de la GPU sin tocar layout — no cuesta más que
   el pulso que ya existe en .live-dot del reproductor (misma técnica). */
.destacados-radar {
  position: relative;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--secundario);
  flex-shrink: 0;
}
.destacados-radar::before {
  content: '';
  position: absolute;
  inset: -5px;
  border-radius: 50%;
  border: 1.5px solid var(--secundario);
  animation: destacados-radar-ping 1.6s ease-out infinite;
}
@keyframes destacados-radar-ping {
  0%   { transform: scale(0.5); opacity: 0.9; }
  100% { transform: scale(2); opacity: 0; }
}

.destacados-track-wrap {
  flex: 1;
  min-width: 0;
  overflow: hidden;
}

.destacados-track {
  display: flex;
  width: max-content;
  animation: destacados-scroll var(--destacados-duracion, 30s) linear infinite;
}
.destacados-ticker:hover .destacados-track,
.destacados-ticker:focus-within .destacados-track {
  animation-play-state: paused;
}
@keyframes destacados-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

.destacados-item {
  flex-shrink: 0;
  white-space: nowrap;
  border-right: 1px solid rgba(245, 250, 251, 0.15);
}
.destacados-item a {
  display: block;
  font-size: var(--fs-sm);
  color: var(--claro);
  padding: 6px var(--space-2);
}
.destacados-item a:hover { color: var(--primario); }

/* ---------- 4. CONTENIDO PRINCIPAL ---------- */
.site-main {
  max-width: var(--ancho-contenido);
  margin: 0 auto;
  padding: var(--space-3) var(--space-2) var(--space-5);
  display: grid;
  /* Fase 25 sexies: SIN esto, un grid de una sola columna implícita se
     dimensiona por el contenido más ancho de sus hijos (ver nota abajo),
     no por el ancho disponible — "1fr" fuerza la columna a llenar el
     contenedor siempre, aunque algún hijo pida más espacio. */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
}

.section-title {
  font-family: var(--fuente-display);
  font-size: var(--fs-xl);
  font-weight: 700;
  color: var(--secundario);
  margin-bottom: var(--space-2);
  border-left: 5px solid var(--primario);
  padding-left: var(--space-1);
}

/* --- Hero / noticia destacada ---
   Fase 25 nonies: SIN padding en la tarjeta — la foto sangra hasta el
   borde (antes dejaba un marco/espacio alrededor de la imagen, el mismo
   problema ya corregido en las tarjetas del carrusel). El padding vive en
   .hero-card-texto, solo alrededor de categoría/título/botón. */
.hero-card {
  background: var(--secundario);
  color: var(--claro);
  border-radius: var(--radio-borde);
  overflow: hidden;
  box-shadow: var(--sombra-suave);
}

.hero-card-texto {
  /* Fase 25 undecies: menos aire entre la foto y la categoría (antes
     tenía el mismo padding en los 4 lados) — el de arriba se achica. */
  padding: var(--space-1) var(--space-3) var(--space-3);
}

.eyebrow {
  font-family: var(--fuente-mono);
  font-size: var(--fs-xs);
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--primario);
  margin-bottom: var(--space-1);
}

/* Fase 10 · Capa 1: imagen destacada del hero. Oculta por defecto (mismo
   patrón que el logo y la carátula: nunca un hueco ni un ícono roto si la
   noticia todavía no tiene imagen). Fase 25 nonies: ahora sangra a los 3
   bordes superiores de la tarjeta (sin margen ni radio propio — el
   "overflow: hidden" de .hero-card ya recorta las esquinas).
   Fase 25 duodecies: el cliente pidió "ancho fijo" además del alto fijo —
   un ancho en píxeles reales rompería mobile (desborda o deja de ser
   "fijo" cuando el navegador lo encoge). En su lugar: "width: 100%" se
   mantiene fluido (correcto para mobile-first) y "aspect-ratio" reemplaza
   al "height" fijo — el alto se calcula solo para mantener SIEMPRE la
   misma proporción 16:9, así que en mobile la caja es más baja (porque es
   más angosta) y en desktop más alta, pero con la MISMA forma en
   cualquier pantalla — sin desbordar nunca y sin el "brinco" entre fotos
   de proporciones distintas. object-fit: contain sigue mostrando la foto
   completa sin recortar, con el fondo rellenando el sobrante. */
.hero-imagen {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: contain;
  background: var(--secundario-claro);
  display: block;
}
.hero-imagen[hidden] { display: none; }

.hero-title {
  font-family: var(--fuente-display);
  /* Fase 25 nonies: -25% a pedido del cliente — antes ocupaba demasiado
     espacio vertical. */
  font-size: calc(var(--fs-2xl) * 0.75);
  font-weight: 800;
  line-height: 1.1;
  margin-bottom: var(--space-2);
}

/* Fase 25 decies: indicadores de posición del carrusel automático del
   hero — puntos clicleables (saltan a esa noticia y reinician el timer).
   El punto activo se agranda un poco, sin animación cara. */
.hero-dots {
  display: flex;
  gap: 8px;
  margin-top: var(--space-3);
}
.hero-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: none;
  padding: 0;
  background: rgba(245, 250, 251, 0.35);
  cursor: pointer;
  transition: background var(--transicion), transform var(--transicion);
}
.hero-dot:hover { background: rgba(245, 250, 251, 0.6); }
.hero-dot[aria-selected="true"] {
  background: var(--primario);
  transform: scale(1.3);
}

.btn {
  display: inline-block;
  font-family: var(--fuente-cuerpo);
  font-weight: 600;
  font-size: var(--fs-sm);
  padding: 0.75rem 1.5rem;
  border-radius: 6px;
  transition: background var(--transicion), transform var(--transicion);
}
.btn-primary {
  background: var(--primario);
  color: var(--secundario);
}
.btn-primary:hover {
  background: var(--primario-oscuro);
  color: var(--claro);
  transform: translateY(-1px);
}

/* --- Aliados: banner rotativo de patrocinantes --- */
.aliados-strip {
  background: var(--superficie);
  border: 1px solid var(--borde);
  border-radius: var(--radio-borde);
  padding: var(--space-2);
  display: grid;
  gap: var(--space-1);
}
.aliados-strip[hidden] { display: none; }

/* Variante activa solo mientras el reproductor está realmente en vivo
   (aliados.en_vivo en marca.json) — reutiliza el acento rojo "ON AIR"
   para que se lea como un espacio patrocinado exclusivo, no genérico. */
.aliados-strip--en-vivo {
  border-color: var(--acento-vivo);
}
.aliados-strip--en-vivo .aliados-eyebrow {
  color: var(--acento-vivo);
}

.aliados-eyebrow {
  font-family: var(--fuente-mono);
  font-size: var(--fs-xs);
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--primario-oscuro);
}

/* Fase 2: barra de progreso tipo "Stories" — indica cuánto falta para que
   rote al siguiente banner. Se reinicia (transition: none + width: 0%) y
   luego anima a 100% en la duración exacta de ese banner (ver
   mostrarAliado() en app.js). Respeta prefers-reduced-motion ocultándola
   (la rotación en sí ya se desactiva del todo con ese ajuste). */
.aliados-progreso-pista {
  height: 3px;
  border-radius: 3px;
  background: var(--borde);
  overflow: hidden;
  margin-bottom: 2px;
}
.aliados-progreso-relleno {
  height: 100%;
  width: 0%;
  background: var(--primario);
  border-radius: 3px;
}
@media (prefers-reduced-motion: reduce) {
  .aliados-progreso-pista { display: none; }
}

.aliado-banner-wrap {
  position: relative;
}

.aliado-banner {
  display: block;
  border-radius: 6px;
  overflow: hidden;
  line-height: 0;
  background: var(--claro);
}
.aliado-banner img {
  width: 100%;
  height: auto;
  transition: opacity 200ms ease;
}
.aliado-banner.is-cambiando img { opacity: 0; }

/* Fase 2: badge del banner activo — arranca en modo "texto" (nombre/etiqueta
   del aliado) y, si ese banner trae un CTA configurado, cambia solo a modo
   "botón" pasado el 40% de su duración (ver mostrarAliado() en app.js).
   Colores por tipo de CTA, mismo criterio que usa Platinium. */
.aliado-badge {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 10px;
  border-radius: 20px;
  font-family: var(--fuente-mono);
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: #fff;
  background: var(--secundario);
  border: 1px solid rgba(255, 255, 255, 0.3);
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.25);
  transition: opacity 200ms ease, background 200ms ease;
  cursor: default;
}
.aliado-badge[hidden] { display: none; }
.aliado-badge.is-cambiando { opacity: 0; }
.aliado-badge--cta {
  cursor: pointer;
}
.aliado-badge--cta:hover { filter: brightness(1.1); }
.aliado-badge--whatsapp { background: #25D366; }
.aliado-badge--llamar { background: var(--primario); }
.aliado-badge--link { background: var(--secundario); }

/* --- YouTube (Fase 13/15/16): lite-embed — miniatura real + botón play en
   CSS, el <iframe> pesado de Google solo se crea al hacer clic (ver
   app.js). Fase 16: la sección entera es una tarjeta de color --primario
   (color de marca de marca.json), con el video incrustado adentro — mismo
   tratamiento visual que .hero-card (fondo de marca + radio-borde +
   sombra), no una franja suelta en la página. --- */
.youtube-section[hidden] { display: none; }

.youtube-section {
  background: var(--primario);
  border-radius: var(--radio-borde);
  padding: var(--space-3);
  box-shadow: var(--sombra-suave);
}

/* Sobre fondo --primario (cian), el título necesita el mismo contraste
   invertido que ya usa .btn-primary (texto --secundario sobre fondo
   --primario) — el border-left por defecto usa --primario, que sobre este
   fondo quedaría invisible, así que aquí se fuerza a --secundario. */
.youtube-section .section-title {
  color: var(--secundario);
  border-left-color: var(--secundario);
}

.youtube-embed-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radio-borde);
  overflow: hidden;
  background: var(--secundario);
  box-shadow: var(--sombra-suave);
  margin-bottom: var(--space-2);
}

.youtube-facade {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: none;
  padding: 0;
  cursor: pointer;
  background: var(--secundario);
}
.youtube-facade[hidden] { display: none; }

.youtube-facade-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* La miniatura 480x360 de hqdefault.jpg no es 16:9 real (le sobran franjas
     negras arriba/abajo); escalarla un poco y recortar con object-fit
     disimula esas franjas sin distorsionar el video. */
  transform: scale(1.08);
  transition: transform 220ms ease, filter 220ms ease;
}
.youtube-facade:hover .youtube-facade-img,
.youtube-facade:focus-visible .youtube-facade-img {
  transform: scale(1.14);
  filter: brightness(0.85);
}

.youtube-facade-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 68px;
  height: 48px;
  filter: drop-shadow(0 4px 14px rgba(0, 0, 0, 0.45));
  transition: transform 180ms ease;
}
.youtube-facade:hover .youtube-facade-play,
.youtube-facade:focus-visible .youtube-facade-play {
  transform: translate(-50%, -50%) scale(1.08);
}
.youtube-facade-play svg { width: 100%; height: 100%; }

.youtube-iframe-wrap {
  position: absolute;
  inset: 0;
}
.youtube-iframe-wrap[hidden] { display: none; }
.youtube-iframe-wrap iframe {
  width: 100%;
  height: 100%;
  border: none;
}

.youtube-boton-canal[hidden] { display: none; }

/* .btn-primary por defecto es fondo --primario + texto --secundario — aquí
   el botón ya vive DENTRO de una tarjeta --primario, así que se invierte
   (fondo --secundario + texto --claro) para que siga leyéndose como botón
   y no se funda con el fondo de la sección. */
.youtube-boton-canal {
  background: var(--secundario);
  color: var(--claro);
}
.youtube-boton-canal:hover {
  background: var(--secundario-claro);
  color: var(--claro);
  transform: translateY(-1px);
}

/* --- En vivo (Fase 18): transmisión propia OBS Studio + Owncast, sin
   YouTube. Oculta casi siempre — solo aparece cuando app.js detecta que
   Owncast está transmitiendo (ver iniciarTransmisionEnVivo()). --- */
.en-vivo-section[hidden] { display: none; }

.en-vivo-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--fuente-mono);
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: 1.5px;
  color: var(--acento-vivo);
  margin-right: var(--space-1);
}

.en-vivo-embed-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radio-borde);
  overflow: hidden;
  background: var(--secundario);
  box-shadow: 0 0 0 3px rgba(255, 59, 48, 0.25), var(--sombra-suave);
}

.en-vivo-iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: none;
}

/* --- Programación (sidebar en escritorio) --- Fase 16: tarjeta completa
   de color --secundario (mismo tratamiento que .youtube-section con
   --primario) — no una franja blanca suelta, sino un bloque de marca. */
.schedule {
  background: var(--secundario);
  color: var(--claro);
  border-radius: var(--radio-borde);
  padding: var(--space-3);
  box-shadow: var(--sombra-suave);
}

/* Sobre fondo --secundario (azul oscuro), el título con su tratamiento
   por defecto (color --secundario, border-left --primario) quedaría
   invisible — se fuerza texto claro y el acento --primario como borde,
   mismo criterio que .youtube-section usa a la inversa. */
.schedule .section-title {
  color: var(--claro);
  border-left-color: var(--primario);
}

/* Fase 25 terdecies: grid en vez de flex simple — la columna de la hora
   queda con ancho FIJO ("6:5em"), así todas las horas alinean igual sin
   importar si son "6:00 AM" o "12:00 PM" (con flex, el ancho de cada hora
   dependía de su propio texto, se veía "escalonado"). Solo se usa en el
   modal de programación completa (la tarjeta "al aire ahora" ya no
   repite la lista del día, ver Fase 25 terdecies más abajo). */
.schedule-item {
  display: grid;
  grid-template-columns: 4.5em 1fr;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  border-bottom: 1px solid rgba(245, 250, 251, 0.15);
  transition: background var(--transicion);
}
.schedule-item:last-child { border-bottom: none; }

.schedule-time {
  font-family: var(--fuente-mono);
  font-weight: 700;
  font-size: var(--fs-sm);
  color: var(--primario);
}

.schedule-info {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.schedule-program {
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: var(--fs-base);
  color: var(--claro);
}

.schedule-locutor {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
}

.schedule-locutor-foto {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  border: 1px solid rgba(245, 250, 251, 0.3);
}

.schedule-locutor-nombre {
  font-size: var(--fs-xs);
  color: rgba(245, 250, 251, 0.75);
}

/* Fase 25 terdecies: ícono redondo oficial de cada red (antes iniciales de
   texto "IG"/"TikTok") — mismo lenguaje visual que los botones de redes
   del footer (Fase 25 septies). 24px: más chico que los del footer porque
   conviven con el nombre del locutor en una fila angosta. */
.schedule-locutor-red {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  color: var(--claro);
  background: rgba(245, 250, 251, 0.15);
  transition: transform var(--transicion), opacity var(--transicion);
}
.schedule-locutor-red svg { width: 13px; height: 13px; }
.schedule-locutor-red:hover { transform: translateY(-1px) scale(1.08); opacity: 0.9; }
.schedule-locutor-red--instagram { background: linear-gradient(135deg, #f58529, #dd2a7b 45%, #8134af 75%, #515bd4); }
.schedule-locutor-red--tiktok { background: #000; }

.schedule-locutor-cumple {
  font-size: var(--fs-xs);
  color: var(--acento-vivo);
  font-weight: 600;
}

.schedule-item--vacio {
  color: rgba(245, 250, 251, 0.7);
  font-size: var(--fs-sm);
  font-style: italic;
  padding: var(--space-1) 0;
}

/* --- Fase 20: tarjeta "al aire ahora" dentro de .schedule --- */
.programa-ahora[hidden] { display: none; }

.programa-ahora {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  background: rgba(4, 184, 220, 0.12);
  border: 1.5px solid rgba(4, 184, 220, 0.4);
  border-radius: var(--radio-borde);
  padding: var(--space-2);
  margin-bottom: var(--space-2);
}

.programa-ahora-radar {
  position: relative;
  flex-shrink: 0;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--acento-vivo);
}
.programa-ahora-radar::before {
  content: '';
  position: absolute;
  inset: -7px;
  border-radius: 50%;
  border: 1.5px solid var(--acento-vivo);
  animation: destacados-radar-ping 1.6s ease-out infinite;
}

.programa-ahora-foto {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  border: 2px solid var(--primario);
}
.programa-ahora-foto[hidden] { display: none; }

.programa-ahora-info { min-width: 0; }

.programa-ahora-eyebrow {
  font-family: var(--fuente-mono);
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 1.5px;
  color: var(--primario);
  margin-bottom: 2px;
}

.programa-ahora-nombre {
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: var(--fs-base);
  color: var(--claro);
}

.programa-ahora-horario {
  font-family: var(--fuente-mono);
  font-size: var(--fs-xs);
  color: rgba(245, 250, 251, 0.75);
}

/* Fase 25 terdecies: íconos de redes del/los locutor(es) al aire ahora —
   mismos círculos que .schedule-locutor-red, solo con un poco más de
   margen arriba para separarlos del horario. */
.programa-ahora-redes {
  display: flex;
  gap: 6px;
  margin-top: var(--space-1);
}
.programa-ahora-redes:empty { display: none; }

/* "A continuación" — texto discreto, no compite con el programa actual. */
.programa-siguiente {
  font-size: var(--fs-xs);
  color: rgba(245, 250, 251, 0.6);
  margin-top: var(--space-1);
}
.programa-siguiente:empty { display: none; }

/* Estado sin programa en vivo (hueco entre bloques) — en vez de un mensaje
   genérico, la propia identidad de marca toma protagonismo: logo, nombre,
   slogan, cuándo vuelve el próximo bloque y un CTA comercial suave. Fondo
   con el logo de la emisora desenfocado (misma lógica visual que la
   carátula/fallback del reproductor ampliado), para que se sienta como un
   estado de marca, no como un error. */
.programa-vacio {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  text-align: center;
  padding: var(--space-4) var(--space-3);
  background: var(--secundario);
  border: 1.5px solid rgba(4, 184, 220, 0.3);
  border-radius: var(--radio-borde);
  margin-bottom: var(--space-2);
}
.programa-vacio[hidden] { display: none; }

.programa-vacio-fondo {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.programa-vacio-fondo-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.2);
  filter: blur(24px) brightness(0.4) saturate(1.3);
}
.programa-vacio-fondo::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(2, 20, 27, 0.75), rgba(2, 20, 27, 0.9));
}

.programa-vacio-contenido {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.programa-vacio-logo-wrap {
  width: 64px;
  height: 64px;
  flex-shrink: 0;
  box-sizing: border-box;
  padding: 8px;
  border-radius: 50%;
  background: var(--claro);
  border: 2px solid var(--primario);
  margin-bottom: var(--space-2);
}
.programa-vacio-logo,
.programa-vacio-logo-fallback {
  width: 100%;
  height: 100%;
  border-radius: 50%;
}
.programa-vacio-logo {
  object-fit: contain;
}
.programa-vacio-logo[hidden] { display: none; }
.programa-vacio-logo-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--primario), var(--secundario));
  color: var(--claro);
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: 1.4rem;
}
.programa-vacio-logo:not([hidden]) ~ .programa-vacio-logo-fallback { display: none; }

.programa-vacio-eyebrow {
  font-family: var(--fuente-mono);
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 2.5px;
  color: var(--primario);
  margin-bottom: 4px;
}

.programa-vacio-nombre {
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: var(--fs-lg);
  color: var(--claro);
}

.programa-vacio-slogan {
  font-family: var(--fuente-mono);
  font-size: var(--fs-xs);
  font-style: italic;
  color: rgba(245, 250, 251, 0.75);
  margin-top: 2px;
}
.programa-vacio-slogan[hidden] { display: none; }

.programa-vacio-proximo {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-xs);
  color: rgba(245, 250, 251, 0.85);
  background: rgba(4, 184, 220, 0.12);
  border: 1px solid rgba(4, 184, 220, 0.3);
  padding: 6px 14px;
  border-radius: 20px;
  margin-top: var(--space-2);
}
.programa-vacio-proximo[hidden] { display: none; }
.programa-vacio-proximo b { color: var(--primario); font-weight: 700; }

.programa-vacio-cta {
  display: inline-block;
  margin-top: var(--space-2);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--primario);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 150ms ease;
}
.programa-vacio-cta:hover,
.programa-vacio-cta:focus-visible {
  border-color: var(--primario);
}
.programa-vacio-cta[hidden] { display: none; }

.btn-semana-completa {
  display: block;
  width: 100%;
  text-align: center;
  margin-top: var(--space-2);
}

/* --- Fase 20 (rediseño Fase 25 terdecies): modal de programación completa,
   estilo "glass" moderno — mismo lenguaje visual que el reproductor
   ampliado (Fase 21), para que se sienta parte del mismo sistema y no un
   modal genérico de formulario. */
.modal-programacion-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(2, 20, 27, 0.72);
  backdrop-filter: blur(6px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-2);
  animation: modal-programacion-fade 200ms ease;
}
.modal-programacion-overlay[hidden] { display: none; }
@keyframes modal-programacion-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-programacion-entrada {
  from { opacity: 0; transform: translateY(12px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

.modal-programacion-caja {
  background: var(--superficie);
  border-radius: 20px;
  padding: var(--space-3);
  max-width: 480px;
  width: 100%;
  max-height: 80vh;
  overflow-y: auto;
  box-shadow: 0 30px 70px -12px rgba(2, 20, 27, 0.6);
  border: 1px solid rgba(4, 184, 220, 0.15);
  animation: modal-programacion-entrada 220ms cubic-bezier(0.16, 1, 0.3, 1);
}

.modal-programacion-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}
.modal-programacion-header h3 {
  font-family: var(--fuente-display);
  font-size: var(--fs-xl);
  font-weight: 800;
  color: var(--secundario);
}

.modal-programacion-cerrar {
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 50%;
  background: var(--claro);
  color: var(--texto-suave);
  font-size: 1.1rem;
  cursor: pointer;
  transition: background var(--transicion), color var(--transicion), transform var(--transicion);
}
.modal-programacion-cerrar:hover { background: var(--acento-vivo); color: var(--claro); transform: rotate(90deg); }

/* Tabs tipo "segmented control" (iOS/Android moderno) — una sola pista con
   fondo, el tab activo se resalta con su propia caja en vez de bordes
   sueltos como antes. */
.modal-programacion-tabs {
  display: flex;
  gap: 4px;
  margin-bottom: var(--space-3);
  padding: 4px;
  background: var(--claro);
  border-radius: 12px;
}
.tab-dia {
  flex: 1;
  font-family: var(--fuente-cuerpo);
  font-weight: 600;
  font-size: var(--fs-sm);
  padding: 0.55rem 0.75rem;
  border: none;
  border-radius: 9px;
  background: transparent;
  color: var(--texto-suave);
  cursor: pointer;
  transition: background var(--transicion), color var(--transicion), box-shadow var(--transicion);
}
.tab-dia.is-activo {
  background: var(--superficie);
  color: var(--primario-oscuro);
  box-shadow: 0 2px 8px rgba(4, 63, 83, 0.15);
}
.tab-dia:hover:not(.is-activo) { color: var(--texto); }

.modal-programacion-lista {
  background: var(--claro);
  border-radius: 14px;
  padding: var(--space-2) var(--space-2) 2px;
}
.modal-programacion-lista .schedule-item { border-bottom-color: var(--borde); border-radius: 10px; }
.modal-programacion-lista .schedule-item:hover { background: rgba(4, 184, 220, 0.06); }
.modal-programacion-lista .schedule-time { color: var(--primario-oscuro); }
.modal-programacion-lista .schedule-program { color: var(--texto); }
.modal-programacion-lista .schedule-locutor-nombre { color: var(--texto-suave); }
.modal-programacion-lista .schedule-locutor-red { background: rgba(4, 63, 83, 0.1); color: var(--secundario); }
.modal-programacion-lista .schedule-locutor-foto { border-color: var(--borde); }

/* ---------- 4a-bis. Fase 3: PANEL LATERAL (Dedícala, Anuncia, Aliados, Créditos) ---------- */

.sidebar-toggle {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  border: 1px solid var(--borde);
  background: var(--superficie);
  color: var(--secundario);
  font-size: 1.2rem;
  font-weight: 800;
  cursor: pointer;
  transition: border-color var(--transicion), color var(--transicion), transform var(--transicion);
  margin-left: var(--space-1);
}
.sidebar-toggle:hover { border-color: var(--primario); color: var(--primario); transform: translateY(-1px); }

.sidebar-overlay {
  position: fixed;
  inset: 0;
  z-index: 220;
  background: rgba(2, 20, 27, 0.55);
  backdrop-filter: blur(4px);
  display: flex;
  justify-content: flex-end;
  animation: modal-programacion-fade 180ms ease;
}
.sidebar-overlay[hidden] { display: none; }

.sidebar-panel {
  width: min(340px, 90vw);
  height: 100%;
  background: var(--superficie);
  box-shadow: -12px 0 40px rgba(2, 20, 27, 0.3);
  display: flex;
  flex-direction: column;
  transform: translateX(0);
  animation: sidebar-entrada 220ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes sidebar-entrada {
  from { transform: translateX(100%); }
  to { transform: translateX(0); }
}

.sidebar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--borde);
  flex-shrink: 0;
}
.sidebar-header h3 {
  font-family: var(--fuente-display);
  font-size: var(--fs-lg);
  font-weight: 800;
  color: var(--secundario);
}
.sidebar-cerrar {
  width: 32px;
  height: 32px;
  border: none;
  border-radius: 50%;
  background: var(--claro);
  color: var(--texto-suave);
  cursor: pointer;
  transition: background var(--transicion), color var(--transicion), transform var(--transicion);
}
.sidebar-cerrar:hover { background: var(--acento-vivo); color: var(--claro); transform: rotate(90deg); }

.sidebar-cuerpo {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-2) var(--space-3) var(--space-4);
}

/* Navegación dentro del sidebar (Inicio/Noticias/Programación/Contacto).
   Antes vivía como <ul> horizontal en el header; se movió acá para tener
   una sola puerta de entrada al menú. */
.sidebar-nav {
  padding: var(--space-1) 0 var(--space-2);
  border-bottom: 1px solid var(--borde);
  margin-bottom: var(--space-2);
}
.sidebar-nav-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.sidebar-nav-link {
  display: block;
  padding: 0.7rem 0.5rem;
  font-family: var(--fuente-display);
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--texto);
  border-radius: 8px;
  transition: background var(--transicion), color var(--transicion);
}
.sidebar-nav-link:hover,
.sidebar-nav-link:focus-visible {
  background: rgba(4, 184, 220, 0.08);
  color: var(--primario);
}

/* Redes sociales del sidebar — pills alineados horizontal, con el mismo
   ICONOS_REDES + colores por red que ya usa el footer, para que el
   usuario reconozca al instante cada plataforma. */
.sidebar-redes-lista {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: var(--space-1);
}
.sidebar-red-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  border-radius: 50%;
  background: var(--claro);
  border: 1px solid var(--borde);
  color: var(--texto);
  transition: transform var(--transicion), background var(--transicion), color var(--transicion), border-color var(--transicion);
}
.sidebar-red-link:hover,
.sidebar-red-link:focus-visible {
  transform: translateY(-2px);
  background: var(--primario);
  color: var(--claro);
  border-color: var(--primario);
}
.sidebar-red-link svg { width: 20px; height: 20px; }

.sidebar-seccion {
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--borde);
}
.sidebar-seccion:last-child { border-bottom: none; }
.sidebar-seccion-titulo {
  font-family: var(--fuente-display);
  font-size: var(--fs-base);
  font-weight: 800;
  color: var(--texto);
  margin-bottom: 4px;
}
.sidebar-seccion-ayuda {
  font-size: var(--fs-xs);
  color: var(--texto-suave);
  line-height: 1.4;
  margin-bottom: var(--space-1);
}

.sidebar-form {
  display: grid;
  gap: 4px;
  margin-top: var(--space-1);
}
/* Fase C ter: labels visibles (antes .visually-hidden) — mismo patrón que
   el formulario de Dedícala/Anuncia de Platinium, con varios campos por
   formulario es más claro que placeholders solos. */
.sidebar-form label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--texto-suave);
  margin-top: 6px;
}
.sidebar-form label:first-child { margin-top: 0; }
.sidebar-form-contador {
  font-family: var(--fuente-mono);
  font-weight: 400;
  color: var(--texto-suave);
  opacity: 0.75;
}
.sidebar-form input,
.sidebar-form textarea {
  width: 100%;
  border: 1px solid var(--borde);
  border-radius: 8px;
  padding: 0.6rem 0.7rem;
  font-family: var(--fuente-cuerpo);
  font-size: var(--fs-sm);
  color: var(--texto);
  background: var(--claro);
  resize: vertical;
}
.sidebar-form input:focus,
.sidebar-form textarea:focus {
  outline: 2px solid var(--primario);
  outline-offset: 1px;
}

.sidebar-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  padding: 0.65rem 1rem;
  border: none;
  border-radius: 8px;
  font-family: var(--fuente-cuerpo);
  font-size: var(--fs-sm);
  font-weight: 700;
  cursor: pointer;
  transition: filter var(--transicion), transform var(--transicion);
}
.sidebar-btn:hover { filter: brightness(1.08); transform: translateY(-1px); }
.sidebar-btn--whatsapp { background: #25D366; color: #fff; }
.sidebar-btn--secundario {
  background: var(--claro);
  color: var(--secundario);
  border: 1px solid var(--borde);
}

.sidebar-creditos { text-align: center; }
.sidebar-creditos-texto {
  font-family: var(--fuente-mono);
  font-size: var(--fs-xs);
  color: var(--texto-suave);
  letter-spacing: 0.5px;
}
.sidebar-creditos-suave { opacity: 0.75; margin-bottom: var(--space-1); }
.sidebar-version-btn {
  margin-top: 6px;
  background: none;
  border: none;
  color: var(--primario-oscuro);
  font-family: var(--fuente-mono);
  font-size: 0.7rem;
  text-decoration: underline;
  cursor: pointer;
}

/* ---------- 4b. ARTÍCULO INDIVIDUAL (noticia.html — Fase 10, Capa 2) ---------- */
.articulo-main {
  display: block;
  max-width: 760px;
}
.articulo-titulo {
  font-family: var(--fuente-display);
  font-size: var(--fs-2xl);
  font-weight: 800;
  color: var(--secundario);
  line-height: 1.1;
  margin-bottom: var(--space-1);
}
.articulo-meta {
  font-family: var(--fuente-mono);
  font-size: var(--fs-xs);
  color: var(--texto-suave);
  letter-spacing: 0.5px;
  margin-bottom: var(--space-3);
}
.articulo-imagen {
  width: 100%;
  max-height: 420px;
  object-fit: cover;
  border-radius: var(--radio-borde);
  margin-bottom: var(--space-3);
}
.articulo-imagen[hidden] { display: none; }

/* Fase 25: compartir en redes — pills de texto simples, sin iconos SVG/fuente
   de íconos (cero peso extra). Colores de marca de cada red, solo como
   acento — el resto del look sigue el sistema de diseño del sitio. */
.compartir-redes {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: var(--space-3);
}
.compartir-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--claro);
  text-decoration: none;
  transition: transform var(--transicion), opacity var(--transicion);
}
.compartir-btn:hover { transform: translateY(-2px); opacity: 0.9; }
.compartir-btn--x { background: #000000; }
.compartir-btn--telegram { background: #229ed9; }
.compartir-btn--whatsapp { background: #25d366; }
.compartir-btn--facebook { background: #1877f2; }

.articulo-acciones {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-top: var(--space-3);
  padding-top: var(--space-2);
  border-top: 1px solid var(--borde);
}

/* ---------- 5. FOOTER ---------- */
.site-footer {
  background: var(--secundario);
  color: var(--claro);
}
.footer-inner {
  max-width: var(--ancho-contenido);
  margin: 0 auto;
  padding: var(--space-4) var(--space-2);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  text-align: center;
}
.footer-brand {
  font-family: var(--fuente-display);
  font-size: var(--fs-lg);
  font-weight: 700;
}
.social-nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
}
/* Fase 25 quater: color de marca por red (antes contorno gris uniforme).
   Fase 25 septies: redondos en vez de pills de texto — a pedido del
   cliente ("quiero que sean redondos"), estilo íconos de app/FAB. Solo
   texto corto (sin librería de íconos), centrado dentro del círculo. */
.social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.2px;
  color: var(--claro);
  text-align: center;
  line-height: 1;
  transition: transform var(--transicion), opacity var(--transicion);
}
.social-link:hover {
  transform: translateY(-2px) scale(1.05);
  opacity: 0.88;
  color: var(--claro);
}
.social-link--whatsapp { background: #25d366; }
.social-link--instagram {
  background: linear-gradient(135deg, #f58529, #dd2a7b 45%, #8134af 75%, #515bd4);
}
.social-link--facebook { background: #1877f2; }
.social-link--telegram { background: #229ed9; }
.social-link--web { background: var(--primario); color: var(--secundario); }
.footer-copy {
  font-size: var(--fs-xs);
  color: rgba(245, 250, 251, 0.6);
}

/* ---------- 6. REPRODUCTOR PERSISTENTE (STICKY) ---------- */
/* Fase 21: tratamiento "glass" oscuro a propósito distinto del resto de
   tarjetas del sitio — desde la Fase 16, Programación y YouTube también
   usan --secundario como fondo sólido, así que el player necesitaba un
   acabado propio para seguir leyéndose como el elemento de acción
   principal (siempre visible, siempre al alcance) y no una tarjeta más.
   backdrop-filter + gradiente + opacidad da el efecto "panel de vidrio
   flotante" (mismo lenguaje visual que Spotify/Apple Music en escritorio),
   con degradado en vez de rgba(0,0,0,x) para que se difumine el contenido
   real detrás sin perder legibilidad del texto blanco. */
.player-sticky {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 150;
  height: var(--altura-player);
  /* Fase 22: --player-tinte lo fija app.js muestreando el color promedio de
     la carátula actual (canvas) — con fallback transparente si todavía no
     hay carátula o si el host de la imagen bloquea la lectura por CORS
     (fallo silencioso, nunca rompe el degradado base). */
  background:
    linear-gradient(135deg, var(--player-tinte, transparent), transparent 100%),
    linear-gradient(135deg, rgba(4, 63, 83, 0.9), rgba(2, 20, 27, 0.95));
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border-top: 1px solid rgba(4, 184, 220, 0.22);
  box-shadow: 0 -16px 40px var(--player-glow, rgba(0, 0, 0, 0.35)), inset 0 1px 0 rgba(245, 250, 251, 0.06);
  transition: background 700ms ease, box-shadow 700ms ease;
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

/* Sin soporte de backdrop-filter (navegadores viejos): cae a un fondo
   sólido en vez de quedar semitransparente sobre contenido sin difuminar
   (ilegible). @supports evita esto sin tener que detectar el navegador. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .player-sticky { background: var(--secundario); }
}

.player-inner {
  max-width: var(--ancho-contenido);
  height: 100%;
  margin: 0 auto;
  padding: 0 var(--space-2);
  display: grid;
  /* Fase 9: + carátula (opcional) + acciones (compartir/expandir).
     Cada control se fija a su columna explícitamente (ver abajo) para que
     ocultar la carátula en móvil no corra al resto del layout. */
  grid-template-columns: auto auto 1fr auto auto;
  align-items: center;
  gap: var(--space-2);
}
.player-art-toggle { grid-column: 1; }
.player-play { grid-column: 2; }
.player-info { grid-column: 3; }
.player-volume { grid-column: 4; }
.player-actions { grid-column: 5; }

.player-play {
  width: 48px; height: 48px;
  border-radius: 50%;
  border: none;
  background: linear-gradient(135deg, var(--primario), var(--primario-oscuro));
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 18px rgba(4, 184, 220, 0.4);
  transition: transform var(--transicion), box-shadow var(--transicion);
}
.player-play:hover { transform: scale(1.06); box-shadow: 0 6px 26px rgba(4, 184, 220, 0.55); }
/* Halo extra mientras suena — refuerza que hay algo "vivo" pasando, sin
   ser una animación en loop (evita distraer la vista permanentemente). */
.player-play[aria-pressed="true"] {
  box-shadow: 0 0 0 5px rgba(4, 184, 220, 0.16), 0 4px 20px rgba(4, 184, 220, 0.5);
}

/* Ícono de play dibujado en CSS puro (triángulo) */
.play-icon {
  width: 0; height: 0;
  border-style: solid;
  border-width: 8px 0 8px 14px;
  border-color: transparent transparent transparent var(--secundario);
  margin-left: 3px;
}
/* Cuando el botón indica "reproduciendo" (app.js alterna esta clase) */
.player-play[aria-pressed="true"] .play-icon {
  width: 12px; height: 14px;
  border-style: solid;
  border-width: 0;
  background:
    linear-gradient(90deg, var(--secundario) 4px, transparent 4px 6px, var(--secundario) 6px);
  border: none;
  margin-left: 0;
}

/* Fase C bis: el play/pausa del panel ampliado vive ENCIMA de la carátula
   (mismo patrón que Platinium) — antes era un botón grande aparte, debajo
   del bloque de programa/locutor. .player-expanded-art-wrap ya tiene
   position:relative, así que este botón se centra ahí con position:absolute. */
.player-play--sobre-caratula {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 64px;
  height: 64px;
  z-index: 2; /* por encima de la carátula y del visualizador */
  background: rgba(2, 20, 27, 0.55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border: 2px solid rgba(245, 250, 251, 0.75);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
  transition: transform var(--transicion), background var(--transicion);
}
.player-play--sobre-caratula:hover {
  transform: translate(-50%, -50%) scale(1.06);
  background: rgba(4, 184, 220, 0.35);
}
.player-play--sobre-caratula .play-icon {
  border-width: 11px 0 11px 18px;
  border-color: transparent transparent transparent var(--claro);
  margin-left: 4px;
}
.player-play--sobre-caratula[aria-pressed="true"] .play-icon {
  width: 16px;
  height: 18px;
  background: linear-gradient(90deg, var(--claro) 5px, transparent 5px 8px, var(--claro) 8px);
}

/* ---------- Fase 9: carátula miniatura en el reproductor ---------- */
.player-art-toggle {
  /* Antes solo aparecía desde tablet (640px) — visible también en móvil
     ahora, un poco más chica ahí para no apretar el resto de controles. */
  display: block;
  width: 36px; height: 36px;
  padding: 0;
  border: none;
  border-radius: 8px;
  overflow: hidden;
  position: relative;
  cursor: pointer;
  background: var(--secundario-claro);
  flex-shrink: 0;
}
.player-art-mini {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: opacity 300ms ease;
}
.player-art-mini[hidden] { display: none; }
/* Marca de agua de respaldo mientras no hay carátula real (ninguna canción
   trae "art" o AzuraCast aún no responde) — nunca un ícono de imagen rota */
.player-art-fallback {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--fuente-mono);
  font-size: 0.6rem;
  letter-spacing: 1px;
  color: var(--primario);
  background:
    repeating-linear-gradient(135deg, rgba(4,184,220,0.14) 0 6px, transparent 6px 12px);
}
.player-art-fallback::after { content: 'FM'; }
.player-art-mini:not([hidden]) ~ .player-art-fallback { display: none; }
.player-art-toggle:focus-visible { outline: 3px solid var(--primario); outline-offset: 2px; }

.player-info { min-width: 0; }
.player-station {
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: var(--fs-base);
  color: var(--claro);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Texto "now playing" real, alimentado por la API de AzuraCast */
.player-nowplaying {
  font-size: var(--fs-xs);
  color: rgba(245, 250, 251, 0.75);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin: 2px 0;
}

.player-live {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--fuente-mono);
  font-size: var(--fs-xs);
  letter-spacing: 1px;
  color: var(--acento-vivo);
}

/* Contador de oyentes reales (solo se llena si oyentes_config.modo === "real") */
.player-oyentes {
  color: rgba(245, 250, 251, 0.6);
  font-weight: 400;
  letter-spacing: 0;
  margin-left: 4px;
}
.player-oyentes:empty { display: none; }

/* Indicador EN VIVO: punto con animación sutil de pulso */
.live-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--acento-vivo);
  animation: pulso 1.6s ease-in-out infinite;
}
@keyframes pulso {
  0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(255, 59, 48, 0.5); }
  50% { opacity: 0.6; box-shadow: 0 0 0 5px rgba(255, 59, 48, 0); }
}

/* Ecualizador de barras: refuerza la firma visual del dial de frecuencia */
.live-eq {
  display: inline-flex;
  align-items: flex-end;
  gap: 2px;
  height: 12px;
}
.live-eq span {
  width: 2px;
  background: var(--primario);
  animation: eq 1s ease-in-out infinite;
}
.live-eq span:nth-child(1) { height: 40%; animation-delay: 0s; }
.live-eq span:nth-child(2) { height: 100%; animation-delay: 0.2s; }
.live-eq span:nth-child(3) { height: 60%; animation-delay: 0.4s; }
.live-eq span:nth-child(4) { height: 80%; animation-delay: 0.1s; }
@keyframes eq {
  0%, 100% { transform: scaleY(0.4); }
  50% { transform: scaleY(1); }
}

/* Estados del reproductor controlados por app.js vía [data-estado] */
.player-live[data-estado="pausado"] .live-eq span,
.player-live[data-estado="pausado"] .live-dot {
  animation-play-state: paused;
  opacity: 0.4;
}
.player-live[data-estado="conectando"],
.player-live[data-estado="reconectando"] {
  color: var(--primario);
}
.player-live[data-estado="error"],
.player-live[data-estado="sin-configuracion"] {
  color: var(--texto-suave);
}
.player-live[data-estado="error"] .live-dot,
.player-live[data-estado="sin-configuracion"] .live-dot {
  animation: none;
  background: var(--texto-suave);
}

.player-volume { display: none; } /* se activa desde tablet en adelante */
.player-volume input[type="range"] { width: 100px; accent-color: var(--primario); }

/* ---------- Fase 9: acciones extra (compartir / expandir) ---------- */
.player-actions {
  display: flex;
  align-items: center;
  gap: 4px;
}
.player-action-btn {
  width: 36px; height: 36px;
  border-radius: 50%;
  border: 1px solid rgba(245, 250, 251, 0.25);
  background: transparent;
  color: var(--claro);
  font-size: 1rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transicion), border-color var(--transicion), transform var(--transicion);
}
.player-action-btn:hover { background: rgba(245, 250, 251, 0.08); border-color: var(--primario); }
.player-action-btn[hidden] { display: none; }

.expand-chevron {
  width: 8px; height: 8px;
  border-right: 2px solid var(--claro);
  border-bottom: 2px solid var(--claro);
  transform: rotate(-45deg);
  transition: transform var(--transicion);
}
.player-action-btn--expand[aria-expanded="true"] .expand-chevron {
  transform: rotate(135deg);
}

/* ---------- Fase 9: barra de progreso — hilo superior del player sticky ---------- */
.player-progress-mini {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: rgba(245, 250, 251, 0.12);
}
.player-progress-fill-mini {
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, var(--primario-oscuro), var(--primario));
  box-shadow: 0 0 8px rgba(4, 184, 220, 0.65);
  transition: width 250ms linear;
}
/* Mientras no hay duración conocida (stream 100% en vivo sin dato de AzuraCast),
   se muestra un pulso ambiguo en vez de una barra vacía y confusa */
.player-progress-mini[data-indeterminado="true"] .player-progress-fill-mini {
  width: 30%;
  animation: progreso-indeterminado 1.8s ease-in-out infinite;
}
@keyframes progreso-indeterminado {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(333%); }
}

/* ==========================================================================
   Fase 9: MODO EXPANDIDO — tarjeta estilo Spotify/Apple Music
   ========================================================================== */
.player-expanded {
  position: absolute;
  left: var(--space-2);
  right: var(--space-2);
  bottom: calc(var(--altura-player) + var(--space-2));
  max-width: 560px;
  margin: 0 auto;
  /* Mismo acabado "glass" que .player-sticky (Fase 21) — consistencia
     entre la barra siempre visible y su versión ampliada. */
  background:
    linear-gradient(160deg, var(--player-tinte, transparent), transparent 100%),
    linear-gradient(160deg, rgba(4, 63, 83, 0.92), rgba(2, 20, 27, 0.96));
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid rgba(4, 184, 220, 0.25);
  border-radius: var(--radio-borde);
  box-shadow: 0 -8px 48px var(--player-glow, rgba(0, 0, 0, 0.4)), inset 0 1px 0 rgba(245, 250, 251, 0.06);
  color: var(--claro);
  max-height: min(70vh, 620px);
  overflow-y: auto;
}
.player-expanded[hidden] { display: none; }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .player-expanded { background: var(--secundario); }
}

.player-expanded-inner {
  padding: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  position: relative;
}

.player-expanded-close {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  width: 32px; height: 32px;
  border-radius: 50%;
  border: 1px solid rgba(245, 250, 251, 0.25);
  background: transparent;
  color: var(--claro);
  cursor: pointer;
  line-height: 1;
}
.player-expanded-close:hover { border-color: var(--primario); color: var(--primario); }

/* Fase C: layout centrado y vertical (antes: carátula a la izquierda +
   info apilada a la derecha, en dos columnas) — mismo lenguaje visual que
   el reproductor Platinium: carátula grande centrada arriba, y todo lo
   demás (título, progreso, programa/locutor, controles) apilado debajo
   centrado, en vez de repartido en columnas. */
.player-expanded-main {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-2);
}

.player-expanded-art-wrap {
  position: relative;
  width: 180px; height: 180px;
  flex-shrink: 0;
  border-radius: 14px;
  overflow: hidden;
  background: var(--secundario-claro);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
}
.player-expanded-art {
  width: 100%; height: 100%;
  object-fit: cover;
}
.player-expanded-art[hidden] { display: none; }
.player-expanded-art-fallback {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--fuente-display);
  font-weight: 800;
  font-size: 1.4rem;
  letter-spacing: 1px;
  color: var(--primario);
  background:
    repeating-linear-gradient(135deg, rgba(4,184,220,0.16) 0 8px, transparent 8px 16px);
}
.player-expanded-art-fallback::after { content: 'SOLÍS FM'; }
.player-expanded-art:not([hidden]) ~ .player-expanded-art-fallback { display: none; }

/* Visualizador de audio (Web Audio API): franja de barras superpuesta al
   pie de la carátula. Solo se activa en desktop y fuera de reduced-motion;
   app.js controla display via [data-activo]. */
.player-visualizer {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  width: 100%; height: 36px;
  display: none;
  pointer-events: none;
}
.player-visualizer[data-activo="true"] { display: block; }

/* Fase 22: botón secundario del panel ampliado — antes usaba clases de
   admin.css (.btn-admin), que index.html/noticia.html no cargan, así que
   quedaba sin estilo. Dedicado al sitio público, mismo lenguaje "glass"
   que el resto del reproductor. */
.player-btn-secundario {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--fuente-cuerpo);
  font-weight: 600;
  font-size: var(--fs-sm);
  padding: 0.55rem 1rem;
  border: 1.5px solid rgba(245, 250, 251, 0.25);
  border-radius: 8px;
  background: rgba(245, 250, 251, 0.06);
  color: var(--claro);
  cursor: pointer;
  transition: background var(--transicion), border-color var(--transicion), color var(--transicion);
}
.player-btn-secundario:hover {
  border-color: var(--primario);
  color: var(--primario);
  background: rgba(4, 184, 220, 0.1);
}

.player-expanded-acciones {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  position: relative;
}

/* Fase C: programa al aire ahora + locutor + redes, dentro del reproductor
   ampliado — mismo dato que ya calcula actualizarProgramaAlAire() para la
   tarjeta de la portada (#programa-ahora), reflejado también acá. */
.player-expanded-programa {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
.player-expanded-programa[hidden] { display: none; }
.player-expanded-programa-nombre {
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: var(--fs-base);
  color: var(--primario);
}
.player-expanded-locutor {
  display: flex;
  align-items: center;
  gap: 8px;
}
.player-expanded-locutor-foto {
  width: 28px; height: 28px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}
.player-expanded-locutor-foto[hidden] { display: none; }
.player-expanded-locutor-nombre {
  font-size: var(--fs-sm);
  color: rgba(245, 250, 251, 0.85);
}
.player-expanded-locutor-redes {
  display: flex;
  justify-content: center;
  gap: 6px;
}
.player-expanded-locutor-redes:empty { display: none; }
.player-expanded-locutor-redes svg { width: 16px; height: 16px; }

/* --- Fase 22: temporizador para apagar --- */
.player-sleep-timer { position: relative; }

.player-sleep-badge {
  font-family: var(--fuente-mono);
  font-size: var(--fs-xs);
  color: var(--primario);
}
.player-sleep-badge[hidden] { display: none; }

.player-sleep-menu {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 0;
  z-index: 10;
  display: flex;
  flex-direction: column;
  min-width: 170px;
  background: rgba(2, 20, 27, 0.97);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(4, 184, 220, 0.25);
  border-radius: 10px;
  padding: 6px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
}
.player-sleep-menu[hidden] { display: none; }

.player-sleep-opcion {
  font-family: var(--fuente-cuerpo);
  font-size: var(--fs-sm);
  text-align: left;
  padding: 0.5rem 0.7rem;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--claro);
  cursor: pointer;
  transition: background var(--transicion);
}
.player-sleep-opcion:hover { background: rgba(4, 184, 220, 0.15); }
.player-sleep-opcion--cancelar {
  color: var(--acento-vivo);
  border-top: 1px solid rgba(245, 250, 251, 0.12);
  margin-top: 4px;
  padding-top: 0.6rem;
}
.player-sleep-opcion--cancelar[hidden] { display: none; }

/* --- Fase 22: toast público "Ahora suena" — vive arriba del player sticky
   (no en la esquina como los del panel admin) para no taparse con los
   controles de reproducción, que es lo primero que la persona quiere tocar. --- */
.toast-container-publico {
  position: fixed;
  left: var(--space-2);
  right: var(--space-2);
  bottom: calc(var(--altura-player) + var(--space-2));
  z-index: 140;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  pointer-events: none;
}

.toast-publico {
  max-width: 360px;
  font-size: var(--fs-sm);
  color: var(--claro);
  background: rgba(2, 20, 27, 0.9);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(4, 184, 220, 0.3);
  border-radius: 10px;
  padding: 0.65rem 1rem;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  animation: toast-publico-in 220ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.toast-publico.is-saliendo { animation: toast-publico-out 200ms ease forwards; }
@keyframes toast-publico-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes toast-publico-out {
  to { opacity: 0; transform: translateY(10px); }
}

.player-expanded-title {
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: var(--fs-lg);
  color: var(--claro);
  margin: 4px 0 var(--space-2);
}
.player-expanded-eyebrow { margin-bottom: 0; }

.player-expanded-progress { width: 100%; margin-bottom: var(--space-2); }
.player-progress-track {
  height: 4px;
  border-radius: 2px;
  background: rgba(245, 250, 251, 0.15);
  overflow: hidden;
  margin-bottom: 6px;
}
.player-progress-fill {
  height: 100%;
  width: 0%;
  background: var(--primario);
  transition: width 250ms linear;
}
.player-expanded-times {
  display: flex;
  justify-content: space-between;
  font-family: var(--fuente-mono);
  font-size: var(--fs-xs);
  color: rgba(245, 250, 251, 0.7);
}

/* Fase C: "Sonó antes" quedó como único bloque debajo (antes competía en
   una grilla de 2 columnas con "Sigue en la programación", que se quitó
   por redundante con la tarjeta "al aire ahora" de la portada). */
.player-history {
  border-top: 1px solid var(--secundario-claro);
  padding-top: var(--space-2);
}
.player-expanded-subtitle {
  font-family: var(--fuente-mono);
  font-size: var(--fs-xs);
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--primario);
  margin-bottom: var(--space-1);
}
/* Fase 23: listas rediseñadas — antes eran filas planas con separador
   punteado; ahora son filas tipo "tarjeta" con hover, y el historial
   suma una miniatura de carátula por canción (o un marcador ♪ si esa
   canción no trae "art"). Scroll propio con tope de alto para que una
   estación con historial largo no estire el panel ampliado sin límite. */
.player-history-list {
  display: flex;
  flex-direction: column;
  gap: 3px;
  max-height: 220px;
  overflow-y: auto;
}
.player-history-item {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: var(--fs-sm);
  color: rgba(245, 250, 251, 0.85);
  padding: 6px 8px;
  border-radius: 8px;
  transition: background 150ms ease;
}
.player-history-item:hover { background: rgba(245, 250, 251, 0.06); }

.player-history-item-art {
  width: 32px;
  height: 32px;
  border-radius: 6px;
  object-fit: cover;
  flex-shrink: 0;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
}
.player-history-item-art--vacio {
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(4, 184, 220, 0.12);
  color: var(--primario);
  font-size: 0.9rem;
}

.player-history-item-info { min-width: 0; flex: 1; }
.player-history-item-texto {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.player-history-item-meta {
  font-family: var(--fuente-mono);
  font-size: var(--fs-xs);
  color: rgba(245, 250, 251, 0.55);
  white-space: nowrap;
  flex-shrink: 0;
}
.lista-vacia-mini {
  font-size: var(--fs-sm);
  font-style: italic;
  color: rgba(245, 250, 251, 0.55);
  padding: 6px 8px;
}

@media (prefers-reduced-motion: reduce) {
  .player-progress-mini[data-indeterminado="true"] .player-progress-fill-mini { animation: none; width: 30%; }
}

/* ==========================================================================
   7. BREAKPOINTS — de móvil a layout tipo revista
   ========================================================================== */

/* Tablet: aparece control de volumen */
@media (min-width: 640px) {
  .player-volume { display: block; }
  .player-art-toggle { width: 44px; height: 44px; }
}

/* Escritorio: navegación horizontal + grid tipo revista */
@media (min-width: 960px) {
  /* El hamburguesa sigue visible en escritorio también: ahora es el único
     acceso al menú unificado (navegación + Dedícala + Anuncia + Redes +
     Aliados + PWA), no un fallback móvil. Antes se ocultaba en ≥960px
     porque convivía con una barra horizontal en el header. */
  .nav-link { font-size: var(--fs-base); padding: 0; }

  /* Layout "revista": hero + sidebar de programación en la misma fila
     (Fase 25 decies: ya no hay "noticias secundarias" en cuadrícula debajo
     — el hero pasó a ser el carrusel automático de las últimas 5).
     Fase 25 undecies: columna del hero un poco más ancha a pedido del
     cliente (antes 2fr:1fr ≈ 67%/33%, ahora 5fr:2fr ≈ 71%/29%) — con
     títulos largos, dejaba "mucho aire" y el texto se veía muy angosto
     (muchas líneas verticales) en vez de aprovechar el ancho disponible. */
  .site-main {
    grid-template-columns: 5fr 2fr;
    grid-template-areas:
      "hero      programacion"
      "aliados   programacion";
  }

  .hero { grid-area: hero; }
  .aliados-strip { grid-area: aliados; }
  .schedule { grid-area: programacion; align-self: start; position: sticky; top: calc(var(--altura-header) + var(--space-2)); }

  /* Fase 25 undecies: el "max-width: 22ch" de antes angostaba el título a
     la fuerza sin importar cuánto espacio real hubiera disponible — era
     la causa real del texto "vertical"/con mucho aire alrededor. Se saca
     del todo: ahora el título usa el ancho completo de la columna
     (menos el padding de .hero-card-texto). */
}

/* Escritorio grande: más aire y densidad de bento */
@media (min-width: 1280px) {
  .hero-card-texto { padding: var(--space-5); }
}

/* Escritorio: modo expandido en dos columnas + visualizador de audio activo
   (en móvil el visualizador se omite a propósito por costo de batería/CPU) */
@media (min-width: 768px) {
  .player-expanded { left: auto; right: var(--space-3); width: 480px; }
}
