/* La Pachanguera 95.1 FM — https://www.lapachanguera951.com
 * Código desarrollado y mantenido por Pragmatic Business Solutions.
 * Contacto: Johnny Gonzalez <info@pragmaticsolutions.app>
 */
/* ===========================================================================
   La Pachanguera 95.1 FM
   Type: Ubuntu. Scale: large — this is a party station, not a bank.
   Player: fixed bottom bar, the pattern every major Latin American station
   uses (Tropicana, Olímpica, Exa), so it reads as a radio immediately.
   =========================================================================== */
/* `hidden` tiene que esconder. NO es una regla de más: `[hidden]{display:none}`
   la pone el NAVEGADOR, y cualquier regla de autor con `display` le gana sin
   error y sin aviso — el código pone `hidden = true`, el elemento se queda en
   pantalla y nadie se entera. Ya mordió dos veces: el contador decía
   «0 ESCUCHANDO POR LA WEB» con nadie conectado, y la barra de progreso del
   programa al aire se veía en las 14 vistas del sitio con el relleno en 0.
   Medido el 16/09 en Chromium, elemento por elemento: de los 18 que el código
   esconde de verdad, a 4 no les funcionaba. Va GLOBAL y no acotada a cada uno
   porque a la cuarta vez acotar deja de ser prudencia: se midió qué cambia en
   las 7 páginas por 2 anchos y lo único que se mueve es #ahora-barra y su hijo.
   ANTES DE PONER ESTO hubo que sacar el reloj de adentro de #clima (build.py):
   con la regla puesta y /api/clima caído, esconder el clima se llevaba el reloj
   y la fecha, y el cintillo quedaba vacío. Si algún día hace falta un elemento
   que lleve `hidden` y aun así se vea, el arreglo no es aflojar esto: es no
   usar `hidden` para eso. */
[hidden]{display:none !important}

:root{
  --amarillo:#FFF100; --rosa:#FF3C77; --azul:#00418B;
  --campo:#00489C; --rayo:#1068C2; --halo:#B3E0FF;
  --rosa-fuerte:#C2185B;   /* pink that passes AA behind body text */
  --hondo:#012A62; --hondo2:#01214E;
  --pad: clamp(20px, 4.5vw, 56px);
  --borde: max(var(--pad), calc((100vw - var(--max)) / 2));  /* the one content edge */
  --max: 1180px;
  --rep: 86px;                     /* height of the fixed player bar */
  /* El botón «Saludos y pedidos», que flota ARRIBA de la barra. Su alto
     vive acá y no suelto en la regla porque el `padding-bottom` del body
     lo necesita: si no, el botón taparía el final del contenido de cada
     página y nadie lo notaría salvo justo al final de un scroll. */
  --fab: 48px;
  --fab-sep: 14px;                 /* hueco entre el botón y la barra */
  --fab-gap: 8px;                  /* hueco entre «Al aire» y «Saludos» */
  --fabs: var(--fab);              /* una fila en escritorio */
  --hoja: 88svh;                   /* alto máximo de la hoja del diálogo */
}
*{box-sizing:border-box}
html{scroll-behavior:smooth; -webkit-text-size-adjust:100%}
body{
  margin:0; min-height:100svh; color:#fff; background:var(--campo);
  font-family:Ubuntu, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size:17px; line-height:1.6; -webkit-font-smoothing:antialiased;
  overflow-x:clip; display:flex; flex-direction:column;
  /* `clip` Y NO `hidden`, POR EL MISMO MOTIVO QUE `html` — y acá se tardó 26
     renglones más en aprender. Medido el 16/09 contra el sitio vivo, a 390 px:
     con `hidden` el `.cabezal` daba `top = -scrollY` en las OCHO rutas, o sea
     que el encabezado que tiene que acompañar al rodar se iba con la página.
     `overflow-x:hidden` en el `body` lo vuelve su propio contenedor de
     desplazamiento, y un `position:sticky` de adentro se pega a algo que no
     rueda. Es exactamente lo que el comentario de `html`, unos renglones más
     abajo, explica que hay que evitar: el arreglo se hizo allá y este `hidden`
     quedó acá haciendo el daño que aquel texto vino a prevenir.
     `clip` recorta igual —comprobado: sigue sin desborde horizontal— sin crear
     el contenedor.

     Este `overflow-x` NO alcanza solo, y conviene saber por qué antes de
     agregarle otro: `.rays` es `position:fixed`, así que se ubica contra el
     VIEWPORT y no contra el body — el recorte del body no lo toca. El recorte
     que sirve está en `html`, más abajo. */
  padding-bottom: calc(var(--rep) + var(--fabs) + var(--fab-sep) +
                       env(safe-area-inset-bottom, 0px));

  /* Una sola palabra larguísima —una URL pegada, un nombre sin espacios—
     no puede estirar la página. Sin esto, un texto del panel con un token
     de 70 caracteres desbordaba /locutores/ en 9000 px. `overflow-wrap`
     `anywhere` y no `break-word`: los dos parten la palabra al pintar,
     pero solo `anywhere` reduce el ancho mínimo intrínseco, que es lo
     que hace que un contenedor flex o grid deje de estirarse. Con
     `break-word` el desborde de 9000 px seguía igual. */
  overflow-wrap:anywhere}
img{max-width:100%; height:auto}
a{color:inherit}
h1,h2,h3{line-height:1.05; margin:0}

/* ---- backdrop -------------------------------------------------------- */
/* EL SITIO DESBORDABA EN HORIZONTAL ENTRE 810 Y 870 px, en producción, y nadie
   lo había medido. Medido el 16/09 barriendo de 360 a 1000 de a 10: el culpable
   no era la barra de navegación sino `.rays`, un adorno de 240vmax que a ciertas
   proporciones se pasa del borde y deja barra de desplazamiento lateral.

   Va `clip` y no `hidden` A PROPÓSITO: `overflow-x:hidden` en `html` crea un
   contenedor de desplazamiento y **rompe `position:sticky`** — y esta hoja lo
   usa en dos lugares, `.cabezal` (el encabezado que acompaña al rodar) y
   `.trafico-mapa`. `clip` recorta sin crear ese contenedor, así que los dos
   siguen pegados donde tienen que estar.

   Y se descubrió por el lado largo: se pidió medir si entraba un séptimo enlace
   en la barra. El comentario de `build.py` nombraba 1280 y 360 — y el defecto
   vive en el medio. Una lista de anchos a medir es una lista blanca de
   preguntas: lo que no está en la lista, no se pregunta. */
html{overflow-x:clip}

.rays{
  position:fixed; left:50%; top:20%; width:240vmax; height:240vmax;
  transform:translate(-50%,-50%); z-index:0; pointer-events:none; opacity:.40;
  background:repeating-conic-gradient(from 0deg at 50% 50%,
    var(--rayo) 0deg 2.6deg, transparent 2.6deg 7.5deg);
  -webkit-mask-image:radial-gradient(closest-side,#000 6%,rgba(0,0,0,.5) 30%,transparent 68%);
          mask-image:radial-gradient(closest-side,#000 6%,rgba(0,0,0,.5) 30%,transparent 68%);
  animation:turn 260s linear infinite;
}
@keyframes turn{to{transform:translate(-50%,-50%) rotate(360deg)}}
.glow{
  position:fixed; left:50%; top:18%; width:min(160vw,1240px); aspect-ratio:1;
  transform:translate(-50%,-50%); z-index:0; pointer-events:none;
  background:radial-gradient(circle,rgba(150,210,255,.40) 0%,rgba(0,72,156,0) 62%);
}

/* ---- header ---------------------------------------------------------- */
.cabezal{
  position:sticky; top:0; z-index:40;
  background:rgba(1,36,88,.82); backdrop-filter:blur(14px);
  border-bottom:1px solid rgba(255,255,255,.16);
  padding-top:env(safe-area-inset-top,0px);
}
.cabezal-fila{display:flex; align-items:center; gap:18px;
              padding-block:12px; padding-inline:var(--borde)}

/* ---- Septiembre, Mes de la Patria -------------------------------------- */
/* the top band: weather on the left, the seasonal message centred. It stays
   after September, carrying the weather on its own. */
/* EL RENGLÓN RESERVA SU ALTO, Y ESO ES UN CLS DE 0,136 A 1024x768.
   Ver `parches/cintillo-sin-salto.aplicar-estilo-css.py`.

   `#clima` nace visible (para no meter 298 px de golpe cuando llega el dato) y
   `pintarClima(null)` lo esconde si `/api/clima` no contesta. Al esconderlo el
   renglón perdía 4,80 px de alto —`.clima` mide 27,19 y es su hijo más alto—
   y la página entera se corría para arriba. Medido en las NUEVE rutas: 40,19
   con clima y 35,39 sin él, idéntico en todas.

   NO ES UN `min-width`: `hidden` es `display:none` y a una caja que no se
   dibuja no se le aplica ningún ancho. Medido, un `min-width:374px` en `.clima`
   subía el CLS del camino de error de 0,1005 a 0,2679, porque agranda la caja
   mientras se ve y el reloj salta más lejos cuando desaparece.

   A/B de 7 corridas por lado, camino de error: mediana 0,0318 -> 0,0066 a
   1440x900 y 0,1356 -> 0,0081 a 1024x768. El número es bimodal y las dos modas
   bajan; a 1024x768 la alta cruza el umbral de 0,1 (0,136 -> 0,098). Con el
   clima puesto es un no-op.

   EL NÚMERO ES UNA MEDICIÓN Y TIENE QUIEN LO VIGILE: si alguien cambia la
   tipografía del cintillo, el alto natural se pasa de éste y deja de reservar
   lo suficiente **sin quejarse**. Lo atrapa `pruebas/medir-cintillo-salto.mjs`,
   que compara el renglón con `#clima` y sin él. */
.cintillo{display:flex; align-items:center; gap:14px; flex-wrap:nowrap;
  padding:6px var(--borde); background:#fff; color:#0A2A5E;
  min-height:40.19px;
  border-bottom:1px solid rgba(1,36,88,.18)}
.patria{display:flex; align-items:center; gap:10px; min-width:0;
  margin-left:auto; text-align:right}

/* ---- the "this is not live traffic" notice ----------------------------- */
.aclaracion{background:rgba(255,241,0,.12); border:1.5px solid rgba(255,241,0,.5);
  border-left-width:6px; border-radius:16px; padding:clamp(18px,2.2vw,26px);
  font-size:16.5px; line-height:1.6; color:#EAF4FF; max-width:78ch}
.aclaracion strong{color:var(--amarillo); display:block; margin-bottom:6px; font-size:17.5px}
.aclaracion a{color:var(--amarillo); font-weight:700; display:inline-flex;
  align-items:center; min-height:44px}

/* ---- El Tráfico: avisos on the left, map on the right ------------------ */
.trafico-grid{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);
              gap:clamp(18px,2.6vw,34px); align-items:start}
.trafico-mapa{position:sticky; top:150px}
@media (max-width:920px){
  .trafico-grid{grid-template-columns:1fr}
  .trafico-mapa{position:static; order:-1}   /* map first on a phone */
}

/* ---- map band above the footer ----------------------------------------- */
.mapa-franja{position:relative; z-index:2; padding:clamp(30px,4vw,56px) 0 clamp(20px,3vw,36px)}
.mapa-titulo{font-size:clamp(24px,3.2vw,38px); margin-bottom:clamp(16px,2vw,26px)}
.mapa-mas{margin-left:auto; text-decoration:none; font-size:14px; font-weight:700;
  color:var(--amarillo); display:inline-flex; align-items:center; min-height:44px}
.mapa-mas:hover{text-decoration:underline}

/* ---- map ---------------------------------------------------------------- */
.mapa-caja{position:relative; border-radius:22px; overflow:hidden;
  border:1px solid rgba(255,255,255,.24); box-shadow:0 18px 44px rgba(0,8,36,.34)}
.mapa{height:clamp(300px,50vh,520px); width:100%; background:#04306F}
.mapa-controles{display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  padding:12px 16px; background:rgba(1,36,88,.9); border-top:1px solid rgba(255,255,255,.18)}
.mapa-check{display:inline-flex; align-items:center; gap:9px; min-height:44px;
  font-size:14.5px; font-weight:700; cursor:pointer}
.mapa-check input{width:20px; height:20px; accent-color:var(--rosa); cursor:pointer}
.mapa-nota{font-size:13px; color:var(--halo)}
.mapa-credito{margin:10px 0 0; font-size:12.5px; color:#AFCCEE}
.leaflet-container{font-family:inherit}
.leaflet-control-zoom a{width:44px; height:44px; line-height:44px; font-size:20px}
.leaflet-control-attribution{display:none}   /* credited below the map instead */
.mapa-credito a{color:var(--halo); display:inline-flex; align-items:center; min-height:44px}
.leaflet-popup-content{font-size:14px; line-height:1.5; margin:12px 14px}
.leaflet-popup-content b{display:block; font-size:15.5px; margin-bottom:4px}

/* ---- servicio list ------------------------------------------------------ */
.reportes{list-style:none; margin:0 0 26px; padding:0; display:grid; gap:12px}
.reporte{display:grid; grid-template-columns:auto 1fr; gap:14px; align-items:start;
  background:rgba(1,36,88,.5); border:1px solid rgba(255,255,255,.2);
  border-radius:18px; padding:18px 20px; cursor:pointer;
  transition:border-color .15s ease, transform .15s ease}
.reporte:hover{border-color:rgba(255,255,255,.5); transform:translateY(-2px)}
.reporte.activo{border-color:var(--amarillo)}
.rep-tipo{display:inline-flex; align-items:center; align-self:start;
  background:var(--c); color:var(--t,#fff); font-size:11px; font-weight:700;
  letter-spacing:.12em; text-transform:uppercase; padding:6px 11px; border-radius:999px;
  white-space:nowrap}
.reporte h3{font-size:18px; font-weight:700; margin-bottom:5px; line-height:1.25}
.reporte p{margin:0 0 6px; font-size:15px; color:#CFE6FF; line-height:1.5}
.rep-meta{font-size:13px; color:var(--halo)}

@media (max-width:560px){ .reporte{grid-template-columns:1fr} }

/* ---- weather ----------------------------------------------------------- */
.clima{display:inline-flex; align-items:center; gap:8px; flex:none}
.clima-ico{display:inline-flex; width:20px; height:20px; color:#0A2A5E}
.clima-ico svg{width:20px; height:20px}
.clima-temp{font-size:15px; font-weight:700; line-height:1}
.clima-desc{font-size:12.5px; color:#3C5F96; white-space:nowrap}
.reloj-sep{color:rgba(10,42,94,.32); font-weight:400}
.reloj{display:inline-flex; align-items:baseline; gap:7px; white-space:nowrap}
.reloj b{font-size:14px; font-weight:700; font-variant-numeric:tabular-nums;
         letter-spacing:.01em}
.reloj span{font-size:12.5px; color:#3C5F96}
/* The band must stay one line. Drop detail in order of importance as it
   narrows: the date, then the forecast text, then the celebration subtitle. */
@media (max-width:1100px){ .reloj span{display:none} }
@media (max-width:1000px){ .clima-desc{display:none} }
@media (max-width:900px){ .patria-txt em{display:none} }
@media (max-width:600px){ .patria-txt b{font-size:11.5px} }
@media (max-width:620px){ .reloj, .reloj-sep{display:none} }
/* Y el alto del renglón sigue el MISMO corte, porque es el mismo hecho: acá
   `.reloj-sep` deja de existir, y con él la caja de línea que hacía los 27,19
   px de `.clima`, que baja a los 20 del icono. Medido: el renglón mide 33,00
   con clima y 30,00 sin él. El corte no es un aparato, es esta regla. */
@media (max-width:620px){ .cintillo{min-height:33px} }
.patria-bandera{display:inline-flex; flex-direction:column; width:26px; height:17px;
  border-radius:2px; overflow:hidden; flex:none; box-shadow:0 0 0 1px rgba(10,42,94,.25)}
.patria-bandera i{display:block; height:33.34%}
.patria-bandera i:nth-child(1),.patria-bandera i:nth-child(3){background:#0067C6}
.patria-bandera i:nth-child(2){background:#fff}
.patria-txt{display:flex; flex-wrap:nowrap; align-items:baseline; justify-content:flex-end;
            gap:4px 10px; line-height:1.3; min-width:0}
.patria-txt b,.patria-txt em{white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.patria-txt b{font-size:14px; font-weight:700; letter-spacing:.01em}
.patria-txt em{font-style:normal; font-size:13px; color:#3C5F96}
@media (max-width:560px){
  .cintillo{padding:6px 12px; gap:10px}
  .patria{gap:9px}
  .patria-txt b{font-size:12.5px}
  .patria-txt em{font-size:11.5px}
}
.marca{display:flex; align-items:center; gap:15px; text-decoration:none;
       margin-right:auto; min-height:56px}
.marca img{width:clamp(88px,7.4vw,124px); height:auto; aspect-ratio:1; object-fit:contain;
           filter:drop-shadow(0 5px 14px rgba(0,10,40,.55))}
.nav{display:flex; gap:6px}
.nav a{display:flex; align-items:center; min-height:48px; padding:0 18px;
       text-decoration:none; font-size:14.5px; font-weight:700; letter-spacing:.04em;
       text-transform:uppercase; border-radius:999px; white-space:nowrap}
.nav a:hover{background:rgba(255,255,255,.14)}
.nav a[aria-current="page"]{background:var(--amarillo); color:#04306F}
.nav a:focus-visible,.marca:focus-visible{outline:3px solid var(--amarillo); outline-offset:3px}
.menu{display:none; width:52px; height:52px; padding:0; cursor:pointer; background:none;
      border:1px solid rgba(255,255,255,.4); border-radius:14px}
.menu span{display:block; width:21px; height:2.5px; background:#fff; margin:4.5px auto; border-radius:2px}

/* ---- on-air strip ------------------------------------------------------ */
.alaire{position:relative; z-index:30; background:linear-gradient(90deg,#04306F,#0A54AE 55%,#04306F);
        border-bottom:1px solid rgba(255,255,255,.18)}
.alaire-in{width:100%; padding:14px var(--borde);
           display:flex; align-items:center; gap:16px}
.alaire-foto{width:70px; height:70px; flex:none; border-radius:16px; object-fit:cover;
             border:2.5px solid var(--amarillo); background:#04306F;
             box-shadow:0 6px 18px rgba(0,10,40,.45)}
.alaire-txt{display:flex; flex-direction:column; gap:3px; min-width:0; margin-right:auto}
.alaire-badge{display:inline-flex; align-items:center; gap:7px; align-self:flex-start;
  background:var(--rosa-fuerte); color:#fff; font-size:10.5px; font-weight:700; letter-spacing:.18em;
  text-transform:uppercase; padding:4px 10px; border-radius:999px}
.alaire-badge .dot{width:7px; height:7px; border-radius:50%; background:#fff}
body.playing .alaire-badge .dot{animation:blip 1.6s ease-out infinite}
.alaire-nom{font-size:clamp(18px,2.2vw,25px); font-weight:700; font-style:italic;
            letter-spacing:-.02em; line-height:1.12;
            white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.alaire-det{font-size:14px; color:var(--halo); white-space:nowrap; overflow:hidden;
            text-overflow:ellipsis}
.alaire-sig{font-size:13.5px; color:#CFE6FF; text-align:right; line-height:1.4;
            padding-left:16px; border-left:1px solid rgba(255,255,255,.22)}
.alaire-sig b{display:block; color:#fff; font-weight:700; font-size:15px}
.alaire-btn{flex:none; display:inline-flex; align-items:center; gap:10px; cursor:pointer;
  min-height:52px; padding:0 22px 0 18px; border-radius:999px; border:none;
  background:var(--amarillo); color:#04306F; font-family:inherit; font-size:15.5px;
  font-weight:700; transition:transform .14s ease}
.alaire-btn:hover{transform:scale(1.04)}
.alaire-btn:focus-visible{outline:3px solid #fff; outline-offset:3px}
.alaire-btn svg{width:22px; height:22px; fill:#04306F}
.alaire-btn .pause{display:none}
body.playing .alaire-btn .play{display:none}
body.playing .alaire-btn .pause{display:block}
.alaire > .progreso{height:5px; background:rgba(255,255,255,.2); display:block}
.alaire > .progreso > span{display:block; height:5px; width:0;
  background:linear-gradient(90deg,var(--amarillo),var(--rosa)); transition:width .6s linear}

@media (max-width:860px){
  .alaire-sig{display:none}
  .alaire-btn span{display:none}
  .alaire-btn{padding:0; width:52px; justify-content:center}
}
@media (max-width:520px){
  .alaire-in{gap:12px; padding:11px var(--pad)}
  .alaire-foto{width:54px; height:54px; border-radius:13px}
}

/* ---- live listener count ---------------------------------------------- */
/* La regla acotada `.oyentes[hidden]{display:none !important}` que vivía acá
   se fue: la cubre la regla global `[hidden]` del principio del archivo, que
   se puso el 16/09 después de medir las consecuencias que esta misma nota
   decía que no se habían mirado. Un remiendo que sobrevive a su motivo tapa
   el próximo. El display de autor de abajo es el que hacía falta ganarle. */
.oyentes{display:inline-flex; align-items:center; gap:7px; flex:none;
  padding:7px 13px; border-radius:999px; white-space:nowrap;
  background:rgba(255,255,255,.14); border:1px solid rgba(255,255,255,.3)}
.oyentes-punto{width:8px; height:8px; border-radius:50%; background:#5BE38B; flex:none;
  box-shadow:0 0 0 0 rgba(91,227,139,.7); animation:blip 2s ease-out infinite}
.oyentes b{font-size:16px; font-weight:700; line-height:1}
.oyentes-t{font-size:11.5px; letter-spacing:.09em; text-transform:uppercase;
           font-weight:700; color:var(--halo)}
@media (max-width:1024px){ .oyentes-t{display:none} }
/* in the player bar it sits just left of the play button */
.reproductor .oyentes{margin-right:4px}
@media (max-width:1024px){ .alaire .oyentes .oyentes-t{display:none} }
@media (max-width:520px){ .alaire .oyentes{padding:6px 10px} }
/* on phones it keeps just the dot and the number — the label is the first
   thing to go, never the count itself */
@media (max-width:860px){
  .reproductor .oyentes .oyentes-t{display:none}
  .reproductor .oyentes{padding:6px 11px; margin-right:2px}
}

/* ---- layout ---------------------------------------------------------- */
main{position:relative; z-index:2; flex:1; width:100%}
.wrap{width:100%; padding-inline:var(--borde)}
.franja{padding:clamp(38px,5vw,76px) 0}
.eyebrow{margin:0 0 12px; font-size:13px; letter-spacing:.22em; text-transform:uppercase;
         font-weight:700; color:var(--amarillo)}
h1{font-size:clamp(36px,5.1vw,68px); font-weight:700; font-style:italic;
   letter-spacing:-.035em; line-height:1.18; text-shadow:0 6px 30px rgba(0,12,48,.55)}
h2{font-size:clamp(30px,4.4vw,58px); font-weight:700; font-style:italic;
   letter-spacing:-.025em; line-height:1.14}
.titulo{margin-bottom:clamp(24px,3vw,44px)}
/* the highlight block, straight off the station's own key art */
.resalte{background:var(--rosa); color:#fff; padding:.02em .14em; border-radius:8px;
         box-decoration-break:clone; -webkit-box-decoration-break:clone;
         text-shadow:none}
h2 .resalte{background:var(--amarillo); color:#04306F}
.lede{margin:22px 0 0; color:#E8F3FF; font-size:clamp(17px,2.1vw,22px);
      line-height:1.58; max-width:44ch}
.eyebrow{margin:0 0 16px; font-size:clamp(12px,1.3vw,15px); letter-spacing:.26em;
         text-transform:uppercase; font-weight:700; color:var(--amarillo)}

/* ---- hero ------------------------------------------------------------ */
.hero{position:relative; overflow:hidden; display:grid; grid-template-columns:1.02fr .98fr;
      align-items:center; gap:clamp(6px,1.2vw,20px);
      min-height:min(62vh,660px);
      /* right gutter matches --borde so the art stops on the same grid as the
         nav and the on-air strip; the text column supplies its own left pad */
      padding:clamp(24px,3vw,44px) var(--borde) clamp(32px,4vw,60px)}
.hero-txt{width:100%; padding-right:clamp(16px,2vw,28px)}
.cta{display:flex; flex-wrap:wrap; gap:14px; margin-top:28px}
.btn-play{display:inline-flex; align-items:center; justify-content:center; gap:14px;
  min-height:72px; cursor:pointer; border:none; border-radius:999px; padding:0 32px 0 24px;
  background:var(--rosa); color:#fff; font-family:inherit; font-size:20px; font-weight:700;
  box-shadow:0 16px 38px rgba(255,60,119,.4); transition:transform .15s ease}
.btn-play:hover{transform:translateY(-3px)}
.btn-play:focus-visible{outline:3px solid var(--amarillo); outline-offset:4px}
.btn-play svg{width:34px; height:34px; fill:#fff; flex:none}
.btn-play .pause{display:none}
body.playing .btn-play .play{display:none}
body.playing .btn-play .pause{display:block}
.btn-ghost{display:inline-flex; align-items:center; justify-content:center; min-height:72px;
  text-decoration:none; border:3px solid rgba(255,255,255,.6); border-radius:999px;
  padding:0 28px; font-size:18px; font-weight:700}
.btn-ghost-oscuro{border-color:#04306F; color:#04306F}
.btn-ghost-oscuro:hover{background:#04306F; color:#fff; border-color:#04306F}
.btn-ghost:hover{background:rgba(255,255,255,.15); border-color:#fff}
.btn-ghost:focus-visible{outline:3px solid var(--amarillo); outline-offset:4px}
.hero-img{position:relative; margin:0; display:flex; align-items:center;
          justify-content:center}
/* LA IMAGEN CUBRE TODA SU CAJA. Pedido del dueño 2026-09-16: «ensure the
   image cover all of the original high and width». Con `contain` y el carrusel
   estirando las diapositivas a la misma altura, una banda ancha (2048x1037)
   quedaba flotando con azul vacío arriba y abajo. */
.hero-img img{position:relative; display:block; width:100%; max-width:none; height:100%;
  max-height:min(58vh,650px); object-fit:cover; border-radius:5px;
  margin-inline:0; box-shadow:0 18px 44px rgba(0,8,36,.34)}

/* ---- destacados -------------------------------------------------------- */
.destacados{display:grid; grid-template-columns:repeat(3,1fr); gap:clamp(14px,1.8vw,24px)}
.dest{position:relative; display:block; text-decoration:none; overflow:hidden;
  border-radius:28px; padding:clamp(26px,3vw,40px); min-height:clamp(240px,26vw,320px);
  background:#04306F; border:1px solid rgba(255,255,255,.22);
  transition:transform .18s ease, box-shadow .18s ease}
.dest:hover{transform:translateY(-6px); box-shadow:0 26px 54px rgba(0,8,36,.5)}
.dest:focus-visible{outline:4px solid var(--amarillo); outline-offset:4px}
.dest-n{position:absolute; right:.04em; bottom:-.24em; font-size:clamp(96px,12vw,168px);
  font-weight:700; font-style:italic; line-height:1; color:rgba(255,255,255,.13);
  pointer-events:none}
.dest h3{position:relative; font-size:clamp(25px,2.8vw,36px); font-weight:700; font-style:italic;
  letter-spacing:-.02em; line-height:1.02; margin-bottom:16px}
.dest p{position:relative; margin:0; font-size:17px; line-height:1.5; color:#CFE6FF}
.dest p b{display:inline-block; margin-top:4px; font-size:21px; color:var(--amarillo)}
.dest-rosa{background:var(--rosa-fuerte); border-color:rgba(255,255,255,.45)}
.dest-rosa p{color:#fff} .dest-rosa p b{color:var(--amarillo)}
.dest-amarillo{background:var(--amarillo); border-color:rgba(4,48,111,.3); color:#04306F}
.dest-amarillo .dest-n{color:rgba(4,48,111,.14)}
.dest-amarillo p{color:#0B3A7C} .dest-amarillo p b{color:#04306F}

/* ---- eventos y dinámicas ---------------------------------------------- */
.agenda{display:grid; grid-template-columns:repeat(auto-fit,minmax(300px,1fr));
        gap:clamp(14px,1.8vw,22px)}
/* EN LA PORTADA, `auto-fit` NO SIRVE. Con UNA sola tarjeta —el caso normal el
   día que la emisora publique su primer boletín— `auto-fit` colapsa las
   columnas vacías y esa tarjeta se estira a todo el ancho: medido, 1100 px de
   alto en la portada. `auto-fill` conserva las columnas, así que una tarjeta
   sola queda del tamaño de una tarjeta. En `/boletin/`, `/eventos/` y
   `/chismes/` se deja `auto-fit` como estaba: ahí la grilla ES la página. */
#lo-ultimo .agenda{grid-template-columns:repeat(auto-fill,minmax(300px,1fr))}

/* LO QUE SUENA, en la barra del aire. Va ARRIBA del nombre del programa y con
   el mismo peso: es lo que la persona vino a saber. En amarillo de marca
   porque tiene que distinguirse del programa sin leerlo — y `[hidden]` manda,
   que es cómo el sitio vuelve solo a la parrilla cuando la consola calla. */
.alaire-suena{display:block; font-weight:800; color:var(--amarillo,#FFE000);
  font-size:clamp(15px,1.5vw,18px); line-height:1.2; margin:0 0 2px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:46ch}
.alaire-suena[hidden]{display:none}

/* «Sigue · …» en el reproductor de abajo. Más chico que el renglón de arriba:
   es contexto, no el dato principal, y en un teléfono no puede empujar al
   botón de play fuera de la pantalla. */
.rep-sig{display:block; font-size:12px; line-height:1.25; opacity:.82;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:42ch}
.rep-sig[hidden]{display:none}
.evento{background:#04306F; border:1px solid rgba(255,255,255,.22); border-radius:26px;
        overflow:hidden; display:flex; flex-direction:column;
        transition:transform .18s ease, box-shadow .18s ease}
.evento:hover{transform:translateY(-5px); box-shadow:0 24px 50px rgba(0,8,36,.46)}
.evento-img{position:relative; margin:0; aspect-ratio:3/2; background:#02265C}
.evento-img img{width:100%; height:100%; object-fit:cover; display:block}
.evento-cuerpo{padding:clamp(22px,2.4vw,30px); display:flex; flex-direction:column; gap:10px}
.ejemplo{position:absolute; top:12px; left:12px; z-index:2;
  background:rgba(2,26,64,.86); color:var(--amarillo); border:1px solid var(--amarillo);
  font-size:10.5px; font-weight:700; letter-spacing:.18em; text-transform:uppercase;
  padding:5px 11px; border-radius:999px; backdrop-filter:blur(4px)}
.evento .fecha{font-size:13px; font-weight:700; letter-spacing:.18em; text-transform:uppercase;
               color:var(--amarillo)}
.evento h3{font-size:clamp(22px,2.4vw,30px); font-weight:700; font-style:italic;
           letter-spacing:-.02em; line-height:1.1}
.evento p{margin:0; font-size:16.5px; color:#CFE6FF; line-height:1.55}
.evento .lugar{font-size:14.5px; color:var(--halo)}
.vacio-agenda{background:#04306F; border:2px dashed rgba(255,255,255,.34); border-radius:26px;
  padding:clamp(28px,4vw,48px); text-align:center}
.vacio-agenda h3{font-size:clamp(23px,2.6vw,32px); font-weight:700; font-style:italic;
                 margin-bottom:12px}
.vacio-agenda p{margin:0 auto 22px; max-width:46ch; font-size:17px; color:#CFE6FF; line-height:1.6}

/* ---- closing colour block --------------------------------------------- */
.cierre{background:var(--amarillo); color:#04306F; padding:clamp(52px,8vw,110px) 0;
        text-align:center; position:relative; z-index:2}
.cierre-k{margin:0 0 18px; font-size:clamp(12px,1.3vw,15px); letter-spacing:.26em;
          text-transform:uppercase; font-weight:700}
.cierre-h{margin:0; font-size:clamp(52px,11vw,150px); font-weight:700; font-style:italic;
  letter-spacing:-.04em; line-height:.88; text-transform:uppercase}
.cierre-l{margin:22px auto 34px; max-width:40ch; font-size:clamp(17px,2vw,21px); line-height:1.5}

/* ---- programación: one compact table, one line per programme ----------- */
.visualmente-oculto{position:absolute; width:1px; height:1px; overflow:hidden;
  clip:rect(0 0 0 0); white-space:nowrap}
.tabla-caja{border-radius:22px; overflow:hidden; border:1px solid rgba(255,255,255,.22);
  background:rgba(1,36,88,.5)}
.parrilla-tabla{width:100%; border-collapse:collapse; font-size:16px}
.parrilla-tabla th{text-align:left; font-size:11.5px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--halo); font-weight:700;
  padding:14px 18px; background:rgba(1,22,56,.6);
  border-bottom:1px solid rgba(255,255,255,.2)}
.parrilla-tabla td{padding:14px 18px; border-bottom:1px solid rgba(255,255,255,.12);
  vertical-align:middle}
.parrilla-tabla tr:last-child td{border-bottom:none}
.fila{transition:background .2s ease}
.fila:hover{background:rgba(255,255,255,.06)}

/* the time of day colours the row — a stripe on the left and the dot */
.punto{display:inline-block; width:10px; height:10px; border-radius:50%;
  background:var(--franja); margin-right:10px; vertical-align:middle;
  box-shadow:0 0 0 3px color-mix(in srgb, var(--franja) 28%, transparent)}
.fila td:first-child{box-shadow:inset 4px 0 0 var(--franja)}
.col-hora{white-space:nowrap; font-weight:700; font-variant-numeric:tabular-nums;
          font-size:15px; color:#EAF4FF}
.col-prog b{font-weight:700; font-size:17px}
.col-loc,.col-dias{color:#CFE6FF; white-space:nowrap}
.pill-franja{display:inline-block; padding:5px 11px; border-radius:999px;
  font-size:11px; font-weight:700; letter-spacing:.12em; text-transform:uppercase;
  background:color-mix(in srgb, var(--franja) 26%, transparent);
  border:1px solid color-mix(in srgb, var(--franja) 60%, transparent);
  color:var(--franja-txt, #fff); white-space:nowrap}

.franja-madrugada{--franja:#7C6BFF; --franja-txt:#D6D0FF}
.franja-manana   {--franja:#FFC44D; --franja-txt:#FFE1A3}
.franja-tarde    {--franja:#FF8A5B; --franja-txt:#FFD0BC}
.franja-noche    {--franja:#4FA8FF; --franja-txt:#C4E2FF}

/* the programme on air right now */
.al-aire{display:none}
.fila.live{background:var(--rosa-fuerte)}
.fila.live td{border-bottom-color:rgba(255,255,255,.3)}
.fila.live .col-hora,.fila.live .col-loc,.fila.live .col-dias{color:#fff}
.fila.live .al-aire{display:inline-block; margin-left:10px; vertical-align:middle;
  background:var(--amarillo); color:#04306F; font-size:10px; font-weight:700;
  letter-spacing:.14em; text-transform:uppercase; padding:4px 9px; border-radius:999px}
/* EL LAVADO BAJA DE .22 A .16, Y NO ES LA PÍLDORA QUE DECÍA EL INFORME.
   Ver `parches/contraste-aa.aplicar-estilo-css.py`. La «Tarde» común mide
   6,06:1 y está bien; la que quedaba en 4,25:1 es ÉSTA, la de la fila al
   aire, blanco sobre blanco-al-22% encima de `--rosa-fuerte`. Coincidió
   con «Tarde» porque ésa era la franja del programa al aire en ese
   momento. Con .16 mide 4,70:1, medido por píxeles. El borde al 50 % es
   el que dibuja la píldora; el relleno sólo la separa de la fila. */
.fila.live .pill-franja{background:rgba(255,255,255,.16); border-color:rgba(255,255,255,.5);
  color:#fff}

@media (max-width:760px){
  .parrilla-tabla, .parrilla-tabla tbody{display:block}
  .parrilla-tabla thead{display:none}
  .fila{display:grid; grid-template-columns:auto 1fr; gap:2px 10px;
        padding:13px 16px; border-bottom:1px solid rgba(255,255,255,.14);
        box-shadow:inset 4px 0 0 var(--franja); align-items:baseline}
  .parrilla-tabla td{padding:0; border:none; display:block}
  .fila td:first-child{box-shadow:none}
  .col-hora{grid-column:1; font-size:13.5px}
  .col-franja{grid-column:2; justify-self:end}
  .col-prog{grid-column:1 / -1; margin-top:3px}
  .col-prog b{font-size:17px}
  .col-loc{grid-column:1 / -1; font-size:13.5px; color:var(--halo)}
  .col-loc::before{content:"con "}
  .col-dias{grid-column:1 / -1; font-size:13.5px; color:var(--halo); margin-top:-2px}
  .pill-franja{font-size:10px; padding:4px 9px}
}

/* ---- programación ---------------------------------------------------- */
.cabecera{padding:clamp(36px,4.6vw,68px) 0 clamp(8px,1vw,18px)}
.ejemplo.ejemplo-fila{position:static; display:inline-block; margin-left:8px;
                      vertical-align:middle; backdrop-filter:none}
.nota{margin-top:36px; border-radius:20px; padding:22px 26px;
      background:rgba(1,36,88,.5); border:1px solid rgba(255,255,255,.2); font-size:16.5px}
.nota p{margin:0}
.nota a{color:var(--amarillo); font-weight:700; display:inline-block; padding:10px 4px;
        min-height:44px; line-height:24px}

/* ---- locutores ------------------------------------------------------- */
.perfil{display:grid; grid-template-columns:minmax(300px,460px) 1fr; gap:clamp(24px,4vw,46px); align-items:start;
  background:rgba(1,36,88,.5); border:1px solid rgba(255,255,255,.22); border-radius:28px;
  padding:clamp(22px,3.4vw,38px)}
.perfil figure{margin:0; position:relative}
.perfil figure img{border-radius:26px; display:block; width:100%}
.perfil p{margin:0; font-size:clamp(17.5px,1.9vw,21px); line-height:1.6; color:#E8F3FF}
.shows{list-style:none; margin:26px 0; padding:0; display:flex; flex-direction:column; gap:12px}
.shows li{display:flex; flex-wrap:wrap; gap:6px 16px; align-items:baseline;
          border-bottom:1px solid rgba(255,255,255,.18); padding-bottom:12px}
.shows span{font-weight:700; font-size:clamp(19px,2vw,24px)}
.shows em{font-style:normal; font-size:14.5px; color:var(--amarillo); font-weight:700}

/* ---- locutor list ------------------------------------------------------ */
.perfiles{display:flex; flex-direction:column; gap:clamp(18px,2.4vw,30px);
          padding-bottom:clamp(30px,4vw,56px)}

/* ---- contacto -------------------------------------------------------- */
.tarjetas{display:grid; grid-template-columns:repeat(auto-fit,minmax(282px,1fr)); gap:18px}
.tarjeta{background:rgba(1,36,88,.5); border:1px solid rgba(255,255,255,.22);
         border-radius:24px; padding:28px}
.tarjeta h2{font-size:22px; margin-bottom:12px}
.tarjeta p{margin:0 0 12px; font-size:16.5px; color:#E8F3FF}
.tarjeta a{color:var(--amarillo); font-weight:700}
/* .tarjeta a would otherwise paint the WhatsApp button's label yellow on yellow */
.tarjeta .wa{color:#04306F}
.tarjeta p > a,.tarjeta a[href^="mailto"]{display:inline-block; padding:10px 4px;
         min-height:44px; line-height:24px; word-break:break-word}
.redes{list-style:none; margin:12px 0 0; padding:0; display:flex; flex-wrap:wrap; gap:6px 16px}
.redes a{text-decoration:none; font-weight:700; color:var(--amarillo);
         display:inline-flex; align-items:center; min-height:44px; min-width:44px}
.wa{display:inline-flex; align-items:center; justify-content:center; gap:12px; min-height:56px;
    text-decoration:none; background:var(--amarillo); color:#04306F; font-weight:700;
    font-size:17px; padding:0 26px; border-radius:999px; box-shadow:0 12px 30px rgba(0,14,48,.42)}
.wa:hover{filter:brightness(1.07)}

/* ---- contact form ------------------------------------------------------ */
.formulario{background:rgba(1,36,88,.55); border:1px solid rgba(255,255,255,.24);
  border-radius:28px; padding:clamp(24px,3.4vw,44px); margin-bottom:clamp(18px,2.4vw,30px)}
.formulario h2{font-size:clamp(26px,3.4vw,40px); margin-bottom:10px}
.form-intro{margin:0 0 26px; font-size:17px; color:#E8F3FF; max-width:48ch; line-height:1.55}
.campos{display:grid; grid-template-columns:1fr 1fr; gap:16px}
.campo{display:flex; flex-direction:column; gap:8px}
.campo-ancho{grid-column:1 / -1}
.campo > span{font-size:13px; font-weight:700; letter-spacing:.12em; text-transform:uppercase;
              color:var(--amarillo)}
.campo input,.campo select,.campo textarea{
  font-family:inherit; font-size:16.5px; color:#fff; min-height:54px;
  background:rgba(1,22,56,.72); border:1.5px solid rgba(255,255,255,.3);
  border-radius:14px; padding:14px 16px; width:100%}
.campo textarea{min-height:140px; resize:vertical; line-height:1.55}
.campo select{appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,#B3E0FF 50%),
                   linear-gradient(135deg,#B3E0FF 50%,transparent 50%);
  background-position:calc(100% - 22px) 24px, calc(100% - 15px) 24px;
  background-size:7px 7px,7px 7px; background-repeat:no-repeat}
.campo select option{background:#04306F; color:#fff}
.campo input::placeholder,.campo textarea::placeholder{color:rgba(199,225,255,.5)}
.campo input:focus,.campo select:focus,.campo textarea:focus{
  outline:none; border-color:var(--amarillo); box-shadow:0 0 0 3px rgba(255,241,0,.25)}
.form-nota{margin:14px 0 0; font-size:14px; color:var(--halo)}
.trampa{position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden}
.form-pie{display:flex; flex-wrap:wrap; gap:14px; align-items:center; margin-top:26px}
.form-pie .btn-play{padding:0 36px}
.form-estado{margin:18px 0 0; font-size:16px; font-weight:700; min-height:1.4em}
.form-estado.ok{color:var(--amarillo)}
.form-estado.mal{color:#FFD2DF}
.formulario.enviando{opacity:.75; pointer-events:none}

/* ---- nota de voz ------------------------------------------------------ */
/* Acá mucha gente manda audio y no escribe. Este bloque tiene que verse tan
   importante como la caja del mensaje, no como un extra escondido abajo. */
.grabar{margin:22px 0 0; padding:18px 20px; border-radius:16px;
  background:rgba(255,255,255,.07); border:1px solid rgba(255,255,255,.22)}
.grabar-cab{display:flex; gap:13px; align-items:flex-start; margin-bottom:14px}
.grabar-icono{font-size:26px; line-height:1.1; flex:0 0 auto}
.grabar-cab b{display:block; font-size:16.5px; margin-bottom:3px}
.grabar-ayuda{display:block; font-size:13.5px; color:var(--halo); line-height:1.45}
.grabar-fila{display:flex; gap:13px; align-items:center; flex-wrap:wrap}
.btn-grabar,.btn-borrar{font-family:inherit; font-size:15px; font-weight:700;
  border-radius:999px; cursor:pointer; min-height:44px; padding:0 22px;
  border:2px solid var(--amarillo); background:transparent; color:var(--amarillo)}
.btn-grabar:hover,.btn-borrar:hover{background:var(--amarillo); color:#04306F}
.btn-grabar.grabando{background:var(--rosa); border-color:var(--rosa); color:#fff}
.btn-borrar{border-color:rgba(255,255,255,.35); color:var(--halo); font-size:14px;
  padding:0 16px}
.grabar-reloj{font-variant-numeric:tabular-nums; font-weight:700; font-size:17px;
  min-width:3.2em}
/* El reproductor no puede estirar la página en un teléfono. */
.grabar-oir{flex:1 1 200px; min-width:0; max-width:100%; height:40px}
.grabar-estado{margin:12px 0 0; font-size:14px; color:var(--halo); min-height:1.3em}
.grabar-estado.mal{color:#FFD2DF}

@media (max-width:640px){
  .campos{grid-template-columns:1fr}
  .grabar{padding:15px}
  .grabar-fila{gap:10px}
  .grabar-oir{flex-basis:100%}
}

/* ---- footer ---------------------------------------------------------- */
.pie{position:relative; z-index:2; margin-top:clamp(24px,3vw,48px);
     background:var(--hondo2); border-top:1px solid rgba(255,255,255,.14)}
.pie-deco{position:relative; height:clamp(120px,15vw,180px); margin-top:-1px;
          overflow:hidden; pointer-events:none}
.pie-deco .cinta{position:absolute; left:0; bottom:0; width:100%; height:100%}
.pie-deco .flor{position:absolute; left:-10px; bottom:0; width:clamp(126px,17vw,200px);
                filter:drop-shadow(0 10px 24px rgba(0,20,60,.5))}
.pie-cuerpo{width:100%; padding:clamp(18px,2.4vw,32px) var(--borde) clamp(16px,2vw,24px);
  display:grid; grid-template-columns:1.5fr 1fr 1.3fr 1.3fr; gap:clamp(16px,2.4vw,32px)}
.pie-logo{width:clamp(140px,12vw,188px); height:auto; display:block; margin-bottom:8px;
          filter:drop-shadow(0 6px 18px rgba(0,10,40,.5))}
.pie-col h3{font-size:12px; letter-spacing:.18em; text-transform:uppercase; color:var(--amarillo);
            font-weight:700; margin:0 0 6px}
.pie-col ul{list-style:none; margin:0; padding:0}
.pie-col li{margin:0; line-height:1.2}
.pie-col li a{display:inline; text-decoration:none; font-size:15px; line-height:1.2;
              color:#E4F1FF}
.pie-col li a:hover{color:var(--amarillo)}
.pie-nota,.pie-dir{margin:6px 0 0; font-size:13.5px; color:#A9C8EC; line-height:1.4}
.social{display:flex; gap:8px; flex-wrap:wrap; margin-top:10px}
.social a{display:inline-flex; align-items:center; justify-content:center;
  width:44px; height:44px; flex:none; text-decoration:none; color:#fff;
  border:1.5px solid rgba(255,255,255,.4); border-radius:50%;
  transition:background .15s ease, border-color .15s ease, transform .15s ease}
.social a:hover{transform:translateY(-2px)}
.social a:hover{background:rgba(255,255,255,.17); border-color:#fff}
.social a:focus-visible{outline:3px solid var(--amarillo); outline-offset:3px}
.pie-legal{width:100%; padding:12px var(--borde) 18px;
  border-top:1px solid rgba(255,255,255,.14); font-size:13px; color:#9FC0E8}
.pie-legal-fila{display:flex; flex-wrap:wrap; gap:4px 20px; justify-content:space-between}
.pie-credito{margin:8px 0 0; text-align:center; font-size:13px; color:#9FC0E8}
.pie-credito a{color:var(--halo); font-weight:700; text-decoration:underline;
               text-underline-offset:3px; display:inline; padding:0}
.pie-credito a:hover{color:var(--amarillo)}
/* Acceso al panel: solo en el pie, y deliberadamente discreto — es para el
   equipo de la estación, no para el oyente. */
.pie-sep{margin:0 4px; opacity:.55}
.pie-credito a.pie-panel{font-weight:400; text-decoration-thickness:1px;
  text-underline-offset:3px; opacity:.85}
.pie-credito a.pie-panel:hover{opacity:1}
.pie-legal-links{display:flex; flex-wrap:wrap; gap:0 10px; justify-content:center;
  margin:6px 0 0; font-size:13px; line-height:1.2}
.pie-legal-links a{color:var(--halo); font-weight:700; text-decoration:underline;
  text-underline-offset:3px; padding:0; display:inline}
.pie-legal-links a:hover{color:var(--amarillo)}

.legal-cab .wrap{max-width:40rem; margin-inline:auto; text-align:center}
.legal-franja .wrap{display:flex; justify-content:center}
.legal{
  width:100%; max-width:40rem; margin-inline:auto; color:#F4F9FF;
  background:rgba(1,22,56,.5); border:1px solid rgba(255,255,255,.14);
  border-radius:22px; padding:clamp(18px,2.4vw,36px) clamp(16px,2.4vw,36px);
  text-align:left}
.legal-nav{display:flex; flex-wrap:wrap; align-items:baseline; gap:2px 10px;
  margin:0 0 12px; font-size:14px; font-weight:700; line-height:1.35}
.legal-nav a{color:var(--amarillo); text-decoration:underline; text-underline-offset:3px;
  padding:0; min-height:0; display:inline}
.legal-nav a[aria-current="page"]{color:#fff; text-decoration:none}
.legal-meta{margin:0 0 18px; color:var(--halo); font-size:14px; line-height:1.45}
.legal h2{font-size:clamp(20px,2.2vw,26px); line-height:1.3; margin:26px 0 10px;
  color:#fff; letter-spacing:0}
.legal h2:first-of-type{margin-top:8px}
.legal p{margin:0 0 14px; line-height:1.7; font-size:17px; color:#EAF3FF}
.legal ul{margin:0 0 16px; padding-left:1.25em}
.legal li{margin:0 0 8px; line-height:1.6}
.legal strong{color:#fff}
.legal a{color:var(--amarillo); font-weight:700}
.legal-indice{list-style:none; padding:0; display:grid;
  grid-template-columns:repeat(auto-fit, minmax(240px, 1fr)); gap:12px}
.legal-indice li{margin:0; padding:12px 14px; border-radius:14px;
  background:rgba(1,22,56,.35); border:1px solid rgba(255,255,255,.14)}
.legal-indice a{color:var(--amarillo); font-weight:700}
.legal-cierre{margin-top:24px; padding-top:16px; border-top:1px solid rgba(255,255,255,.16);
  color:var(--halo); font-size:14.5px; line-height:1.55}
.acepto{margin:16px 0 10px; padding:14px 16px; border-radius:16px;
  border:1px solid rgba(255,241,0,.5); background:rgba(1,22,56,.45)}
.acepto-txt{margin:0 0 10px; font-size:14.5px; color:#EAF3FF; line-height:1.45}
.acepto-txt a{color:var(--amarillo); font-weight:700}
.acepto-btn{min-height:48px; padding:0 18px; font-weight:800}
.acepto-btn[aria-pressed="true"]{background:var(--amarillo); color:#01214E;
  border-color:var(--amarillo)}
.acepto .form-estado{margin:8px 0 0}
.mk-legal{margin:0 0 22px; color:var(--halo); font-size:14.5px; max-width:42em}
.mk-legal a{color:var(--amarillo); font-weight:700}
.mk-descargo{margin:0 0 18px; padding:14px 16px; border-radius:16px;
  background:rgba(1,22,56,.55); border:1px solid rgba(255,241,0,.55); max-width:52em}
.mk-descargo p{margin:0 0 8px; color:#fff; font-size:15px; line-height:1.45}
.mk-descargo p:last-child{margin:0}
.mk-descargo a{color:var(--amarillo); font-weight:700}

/* ---- the fixed player bar -------------------------------------------- */
.reproductor{
  position:fixed; left:0; right:0; bottom:0; z-index:60;
  background:linear-gradient(180deg, rgba(1,33,78,.96), rgba(1,25,60,.99));
  border-top:2px solid var(--amarillo);
  backdrop-filter:blur(16px);
  padding-bottom:env(safe-area-inset-bottom,0px);
  box-shadow:0 -12px 34px rgba(0,8,30,.42);
}
.rep-caja{width:100%; height:var(--rep);
          padding:0 var(--borde); display:flex; align-items:center; gap:16px}
.rep-logo{width:58px; height:58px; flex:none; object-fit:contain;
          filter:drop-shadow(0 3px 10px rgba(0,10,40,.5))}
.rep-txt{display:flex; flex-direction:column; min-width:0; margin-right:auto; line-height:1.25}
.rep-k{font-size:11.5px; letter-spacing:.18em; text-transform:uppercase; font-weight:700;
       white-space:nowrap;
       color:var(--halo); display:inline-flex; align-items:center; gap:8px}
.rep-k .dot{width:9px; height:9px; border-radius:50%; background:rgba(255,241,0,.42); flex:none}
body.playing .rep-k .dot{background:var(--amarillo); animation:blip 1.6s ease-out infinite}
@keyframes blip{0%{box-shadow:0 0 0 0 rgba(255,241,0,.75)}100%{box-shadow:0 0 0 13px rgba(255,241,0,0)}}
.rep-v{font-size:18px; font-weight:700; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.rep-btn{flex:none; width:62px; height:62px; border-radius:50%; cursor:pointer; padding:0;
  border:4px solid var(--amarillo); background:var(--rosa); color:#fff; display:grid;
  place-items:center; transition:transform .15s ease;
  box-shadow:0 10px 26px rgba(255,60,119,.42)}
.rep-btn:hover{transform:scale(1.06)}
.rep-btn:focus-visible{outline:4px solid var(--amarillo); outline-offset:4px}
.rep-btn svg{width:26px; height:26px; fill:#fff; pointer-events:none}
.rep-btn .pause{display:none}
body.playing .rep-btn .play{display:none}
body.playing .rep-btn .pause{display:block}
body.loading .rep-btn{animation:latir 1.1s ease-in-out infinite}
/* interrupted by another app: the button invites a tap back rather than
   looking like an ordinary stopped state */
body.interrumpido .rep-btn,
body.interrumpido .alaire-btn{box-shadow:0 0 0 3px rgba(255,241,0,.55)}
body.interrumpido .rep-k .dot{background:var(--amarillo)}
@keyframes latir{50%{transform:scale(.93); opacity:.75}}

/* ---- fallbacks ------------------------------------------------------- */
.sin-js{width:100%; padding:16px var(--borde); text-align:center;
        background:rgba(255,241,0,.15); font-size:16px}
.sin-js a{color:var(--amarillo); font-weight:700}
.directo{display:inline-flex; align-items:center; min-height:44px; margin-top:12px;
         color:var(--amarillo); font-weight:700; font-size:16px}

/* ---- responsive ------------------------------------------------------ */
@media (max-width:1040px){
  .pie-cuerpo{grid-template-columns:1fr 1fr}
}
@media (max-width:920px){
  .parrilla{grid-template-columns:1fr}
  .dias-tabs{display:flex}
  .dia{display:none}
  .dia.activo{display:block}
  .perfil{grid-template-columns:1fr}
  .perfil figure{max-width:320px}
}
@media (max-width:980px){
  .destacados{grid-template-columns:1fr}
  .dest{min-height:0}
}
@media (max-width:800px){
  .hero{grid-template-columns:1fr; min-height:0; padding-top:0; gap:0; padding-right:0}
  .hero-txt{padding:clamp(28px,6vw,44px) var(--pad) 0}
  .hero-img{order:-1}
  .hero-img img{width:100%; margin-inline:0; max-height:none; border-radius:5px}
  .nav{position:absolute; top:100%; right:var(--pad); flex-direction:column; gap:3px;
    background:#04306F; border:1px solid rgba(255,255,255,.24); border-radius:18px;
    padding:9px; min-width:212px; box-shadow:0 20px 46px rgba(0,8,34,.55)}
  .nav:not(.abierto){display:none}
  .menu{display:block}
}
@media (max-width:640px){
  :root{--rep:78px}
  .pie-cuerpo{grid-template-columns:1fr; gap:16px}
  .pie-legal{flex-direction:column; gap:6px}
  .marca img{width:74px}
}
@media (max-width:480px){
  .rep-logo{width:50px; height:50px}
  .rep-btn{width:56px; height:56px}
  .rep-v{font-size:16px}
  .social a span{display:none}
  .social a{padding:0; width:52px; height:52px; border-radius:50%}
}
@media (prefers-reduced-motion:reduce){*{animation:none!important; transition:none!important}}

/* Mapa de /eventos/. Reusa la caja del mapa de El Tráfico, pero más bajo:
   acá el mapa acompaña a las tarjetas, no es el contenido principal. */
.mapa-eventos-caja{margin-top:26px}
.mapa-eventos-caja .mapa{height:min(46vh,380px)}
.evento[data-i]{cursor:pointer}
.evento.activo{outline:3px solid var(--amarillo); outline-offset:3px}
@media (max-width:700px){ .mapa-eventos-caja .mapa{height:300px} }

/* ------------------------------------------------------------- pauta ----- */
/* Los espacios de publicidad. Cuando no hay anuncio el contenedor va `hidden`
   y no ocupa nada: el sitio no debe verse "con huecos" sin pauta vendida. */
.pauta{position:relative; min-width:0}
.pauta img{display:block; width:100%; height:auto; border-radius:10px}
.pauta a{display:block; text-decoration:none}
.pauta-tag{position:absolute; top:5px; right:7px; font-size:10px; letter-spacing:.06em;
  text-transform:uppercase; padding:2px 7px; border-radius:99px;
  background:rgba(2,18,48,.62); color:#E7EFFA; pointer-events:none}
.pauta-banda{width:100%; margin:0 0 6px}
.pauta-banda img{border-radius:0; max-height:110px; object-fit:cover}
.pauta-chica{flex:0 0 auto; max-width:190px}
.pauta-chica img{max-height:52px; object-fit:contain}
.pauta-chica .pauta-tag{font-size:9px; top:2px; right:3px; padding:1px 5px}
.pauta-pagina{margin:8px 0 22px}
.pauta-pagina img{max-height:220px; object-fit:cover}
.pauta-popup{border:0; border-radius:16px; padding:10px; max-width:min(92vw,460px);
  box-shadow:0 30px 80px rgba(0,8,30,.55)}
.pauta-popup::backdrop{background:rgba(2,12,34,.62)}
.pauta-cerrar{position:absolute; top:-10px; right:-10px; width:34px; height:34px;
  border-radius:50%; border:2px solid #fff; background:var(--azul, #00418B); color:#fff;
  cursor:pointer; display:grid; place-items:center; box-shadow:0 6px 18px rgba(0,0,0,.35)}
@media (max-width:760px){
  .pauta-chica{max-width:120px}
  .pauta-chica img{max-height:40px}
  .pauta-banda img{max-height:74px}
}

/* LA BANDA ANCHA, entre el encabezado y «Al aire» (ver site/build.py).
   Alto FIJO a propósito, que es lo único que la distingue de `.pauta-banda`:
   así el hueco crece UNA sola vez y de un tamaño conocido cuando aparece el
   anuncio, en vez de crecer dos —una al mostrarse y otra al cargar la imagen—.
   Sin anuncio no ocupa nada, y eso lo hace el `hidden` del marcado con la
   regla global de arriba; acá NO hay ningún `min-height`. */
.pauta-ancha{width:100%; margin:0; height:110px}
.pauta-ancha img{border-radius:0; width:100%; height:100%; object-fit:cover}
@media (max-width:760px){ .pauta-ancha{height:78px} }


/* =======================================================================
   BOTÓN SIEMPRE VISIBLE + DIÁLOGO PARA ESCRIBIRLE A LA RADIO
   =======================================================================
   Por qué el botón está acá y no adentro de la barra del reproductor:
   MEDIDO en navegador, a 320 px quedan 16 px libres entre el texto
   «En vivo · 95.1 FM» y el botón de play (26 px a 390 px). No cabe nada.
   Así que flota justo encima, alineado al mismo borde derecho que el play.

   Las tres cosas que lo mantienen honesto:
   1. Se cuelga de `--rep`, la MISMA variable de la que cuelga el alto de la
      barra. Si la barra cambia de alto, el botón se mueve con ella; no hay
      dos números que se puedan desincronizar.
   2. `z-index` 55 contra 60 de la barra, A PROPÓSITO. La geometría ya los
      separa; esto es el seguro: si algún día se cruzan, gana la barra, que
      es lo que el dueño dijo que no se puede tapar.
   3. Su alto entra en el `padding-bottom` del body (arriba), así que no
      tapa el final del contenido de ninguna página.
   ======================================================================= */
.fabs{
  position:fixed; z-index:55;
  right:var(--borde);
  bottom:calc(var(--rep) + env(safe-area-inset-bottom, 0px) + var(--fab-sep));
  display:flex; flex-direction:row; align-items:center; gap:var(--fab-gap);
}
.fab-escribir, .fab-aire{
  display:inline-flex; align-items:center; gap:9px;
  min-height:var(--fab); padding:0 18px;
  font-family:inherit; font-size:15px; font-weight:700; line-height:1.15;
  cursor:pointer; border-radius:999px;
  box-shadow:0 10px 26px rgba(0,8,30,.5);
  transition:transform .15s ease;
}
.fab-escribir{
  /* `--rosa-fuerte` Y NO `--rosa`: con #FF3C77 el rótulo de 15 px mide
     3,41:1 y AA pide 4,5 (18,66 px sería texto grande y pediría 3,0, pero
     ensanchar el botón rompe el cálculo de 320 px de `.kick-nuevo`). Con
     #C2185B mide 5,68:1, medido por píxeles en el sitio público. Es el
     mismo rosa que `:root` declara como el que pasa AA, no uno nuevo.
     Ver `parches/contraste-aa.aplicar-estilo-css.py`. */
  color:#fff; background:var(--rosa-fuerte);
  border:2.5px solid var(--amarillo);
}
.fab-aire{
  color:var(--azul); background:var(--amarillo);
  border:2.5px solid #fff; font-weight:800;
}
.fab-escribir:hover, .fab-aire:hover{transform:translateY(-2px)}
.fab-escribir:focus-visible, .fab-aire:focus-visible{
  outline:4px solid var(--amarillo); outline-offset:3px}
.fab-aire:focus-visible{outline-color:#fff}
.fab-escribir svg, .fab-aire svg{flex:none}
/* Con el diálogo abierto los botones sobran: el foco está adentro y la
   página de atrás es inerte. Se esconden para que no asomen por debajo. */
body:has(.dlg-escribir[open]) .fabs{opacity:0; pointer-events:none}
@media (max-width: 620px){
  :root{ --fabs: calc(var(--fab) * 2 + var(--fab-gap)); }
  .fabs{flex-direction:column; align-items:flex-end}
}
/* Y la página de atrás no se desplaza mientras se escribe. */
body:has(.dlg-escribir[open]){overflow:hidden}

/* ---- «Kick acaba de ponerse en vivo» -----------------------------------
   Ver `parches/kick-nuevo.aplicar-estilo-css.py`. Acá está SÓLO la geometría y
   la tinta; el comportamiento vive en `app.js` y lo escribe otro parche.

   NO PUEDE TAPAR NINGÚN CONTROL, y abajo hay dos fijos: la barra del
   reproductor (`--rep`, donde vive el botón de escuchar) y el botón flotante
   «Saludos y pedidos» (`.fab-escribir`, 198x48, a `--fab-sep` de la barra).

   A 320 px no entran los dos a lo ancho: el ancho utilizable es 280 px y el
   botón flotante se lleva 198. Por eso hasta 620 px este aviso se apila ARRIBA
   del botón, y de ahí para arriba va a su izquierda. El corte es el ancho en
   que los dos entran, no el nombre de un aparato.

   Las medidas salen de las variables que ya existen y no de números copiados:
   el día que la barra cambie de alto, esto se mueve solo. */
.kick-nuevo{
  position:fixed; z-index:56;          /* sobre el `.fab-escribir` (55), bajo el
                                          reproductor (60): nunca lo tapa */
  left:var(--borde);
  bottom:calc(var(--rep) + env(safe-area-inset-bottom, 0px) + var(--fab-sep)
              + var(--fabs) + 10px);
  max-width:min(380px, calc(100vw - 2 * var(--borde)));
  display:flex; align-items:center; gap:10px;
  padding:10px 10px 10px 14px;
  background:linear-gradient(180deg,#04306F,#01214E);
  border:1.5px solid rgba(83,252,24,.55); border-radius:14px;
  box-shadow:0 10px 26px rgba(0,8,30,.5);
  /* UNA INVITACIÓN, NO UNA ALARMA: entra despacio y no salta. */
  opacity:1; transform:none;
  transition:opacity .18s ease, transform .18s ease;
}
.kick-nuevo[hidden]{display:none}
@starting-style{
  .kick-nuevo{opacity:0; transform:translateY(6px)}
}
@media (prefers-reduced-motion: reduce){
  .kick-nuevo{transition:none}
}
.kick-nuevo-txt{margin:0; font-size:14.5px; line-height:1.3; color:#E8F3FF}
.kick-nuevo-txt b{color:#53FC18}
.kick-nuevo-btn{
  flex:none; min-height:44px; padding:0 16px;
  font:inherit; font-weight:700; font-size:14.5px; line-height:1.15;
  color:#04306F; background:#53FC18; border:0; border-radius:999px;
  cursor:pointer}
.kick-nuevo-btn:hover{filter:brightness(1.08)}
.kick-nuevo-btn:focus-visible{outline:3px solid var(--amarillo); outline-offset:2px}
.kick-nuevo-cerrar{
  flex:none; min-width:44px; min-height:44px; padding:0;
  display:inline-flex; align-items:center; justify-content:center;
  font:inherit; font-size:20px; line-height:1;
  color:#BFD8F5; background:transparent; border:0; border-radius:10px;
  cursor:pointer}
.kick-nuevo-cerrar:hover{color:#fff; background:rgba(255,255,255,.12)}
.kick-nuevo-cerrar:focus-visible{outline:3px solid var(--amarillo); outline-offset:-2px}
/* Desde 620 px los dos entran a lo ancho: el aviso baja al renglón del botón
   flotante y se le queda a la izquierda, sin llegar nunca hasta él. */
@media (min-width: 620px){
  .kick-nuevo{
    bottom:calc(var(--rep) + env(safe-area-inset-bottom, 0px) + var(--fab-sep));
    max-width:min(380px, calc(100vw - 2 * var(--borde) - 198px - 16px));
  }
}
/* Con el diálogo de «Saludos y pedidos» abierto, el aviso sobra: el foco está
   adentro y la página de atrás es inerte. Misma regla que el botón flotante. */
body:has(.dlg-escribir[open]) .kick-nuevo{opacity:0; pointer-events:none}

/* ---- el diálogo: hoja que sube en el teléfono, panel centrado en pantalla -- */
.dlg-escribir{
  border:0; padding:0; background:transparent; color:#fff;
  width:100%; max-width:560px; max-height:var(--hoja);
  margin:auto auto 0;              /* pegado abajo: ahí está el pulgar */
  overscroll-behavior:contain;
}
.dlg-escribir::backdrop{background:rgba(1,14,40,.74)}
.dlg-escribir-in{
  max-height:var(--hoja); overflow-y:auto; -webkit-overflow-scrolling:touch;
  background:linear-gradient(180deg,#04306F,#01214E);
  border:1px solid rgba(255,255,255,.22);
  border-top:3px solid var(--amarillo);
  border-radius:22px 22px 0 0;
  padding:16px 16px calc(20px + env(safe-area-inset-bottom, 0px));
}
.dlg-escribir-cab{display:flex; align-items:flex-start; gap:12px; margin-bottom:16px}
.dlg-escribir-cab h2{font-size:clamp(20px,5.2vw,26px); margin:0; line-height:1.2}
.dlg-escribir-lede{margin:6px 0 0; font-size:14px; color:var(--halo); line-height:1.45}
.dlg-escribir-x{
  flex:none; margin-left:auto; width:44px; height:44px; border-radius:50%;
  display:grid; place-items:center; cursor:pointer; color:#fff;
  background:rgba(255,255,255,.12); border:1.5px solid rgba(255,255,255,.34);
}
.dlg-escribir-x:hover{background:rgba(255,255,255,.22)}
.dlg-escribir-x:focus-visible{outline:3px solid var(--amarillo); outline-offset:2px}

/* Adentro del diálogo el formulario no lleva su propia caja: la caja es el
   diálogo. Y una sola columna, siempre: el panel mide 560 px como mucho. */
.dlg-escribir .formulario{background:none; border:0; border-radius:0; padding:0; margin:0}
.dlg-escribir .campos{grid-template-columns:1fr}
.dlg-escribir .form-pie{margin-top:20px}
.dlg-escribir .form-pie .btn-play{width:100%}

@media (min-width:760px){
  .dlg-escribir{margin:auto}
  .dlg-escribir-in{border-radius:22px; border-top-width:3px; padding:24px}
}

/* ---- los tres motivos --------------------------------------------------
   Son `<input type="radio">` de verdad, tapados con .visualmente-oculto y NO
   con display:none — que los sacaría del orden de tabulación. Así el valor
   viaja en `asunto` sin JavaScript, las flechas navegan entre ellos y el
   lector de pantalla los anuncia como grupo. */
.motivos{border:0; padding:0; margin:0 0 18px; min-width:0}
.motivos legend{padding:0; margin-bottom:10px; font-size:13px; font-weight:700;
  letter-spacing:.12em; text-transform:uppercase; color:var(--amarillo)}
/* auto-fit y no un número: hoy son dos motivos y ayer eran tres. La fila se
   acomoda sola a los que haya, sin que agregar uno sea rehacer la regla. */
.motivos-fila{display:grid; grid-template-columns:repeat(auto-fit,minmax(84px,1fr));
  gap:8px}
.motivo{display:block; min-width:0}
.motivo-cara{
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:7px; min-height:78px; padding:10px 5px; text-align:center;
  font-size:13px; font-weight:700; line-height:1.22; color:#fff;
  background:rgba(1,22,56,.72); border:1.5px solid rgba(255,255,255,.3);
  border-radius:14px; cursor:pointer; transition:background .12s ease;
}
.motivo-cara svg{flex:none}
.motivo:hover .motivo-cara{background:rgba(255,255,255,.14)}
.motivo input:checked + .motivo-cara{
  background:var(--rosa); border-color:var(--amarillo);
  box-shadow:0 6px 18px rgba(255,60,119,.35)}
.motivo input:focus-visible + .motivo-cara{outline:3px solid var(--amarillo); outline-offset:3px}


/* ---- videos: la fachada ------------------------------------------------
   Ver `parches/videos-portada.aplicar-estilo-css.py` para qué se reusa, por
   qué `.evento-img` no, y por qué los tres huecos miden 16/9. */
.vid{padding:0; overflow:hidden; display:flex; flex-direction:column}
/* La caja es un <button> (o un <a> cuando no reconocemos la URL): hay que
   apagarle el borde y el relleno que le pone el navegador, o la miniatura sale
   con un marco gris. */
.vid-caja{display:block; position:relative; width:100%; aspect-ratio:16/9;
  margin:0; padding:0; border:0; background:#02265C; color:inherit;
  font:inherit; text-align:left; cursor:pointer; overflow:hidden}
.vid-cara{position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; display:block; border:0}
.vid-play{position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  display:flex; align-items:center; justify-content:center;
  width:64px; height:64px; border-radius:50%; background:var(--rosa);
  box-shadow:0 6px 20px rgba(0,0,0,.45); transition:transform .12s ease}
.vid-play svg{width:30px; height:30px; fill:#fff; margin-left:4px}
/* Abajo a la izquierda porque `.ejemplo` ya ocupa arriba a la izquierda. */
.vid-red{position:absolute; left:12px; bottom:12px; padding:5px 10px;
  border-radius:999px; background:rgba(1,22,56,.86); color:#fff;
  font-size:12px; font-weight:700; letter-spacing:.04em; line-height:1.2}
.vid-caja:hover .vid-play{transform:translate(-50%,-50%) scale(1.08)}
.vid-caja:focus-visible{outline:3px solid var(--amarillo); outline-offset:-3px}
.vid-cuerpo{padding:16px 20px 20px; display:flex; flex-direction:column; gap:6px}
.vid-t{font-size:19px; line-height:1.28; margin:0}
.vid-aviso{margin:0; font-size:13.5px; color:#BFD8F5}
/* El reproductor del tercero, ya montado. Mismo alto que la fachada que
   reemplaza: la tarjeta no salta cuando ella toca. */
.vid-marco{display:block; width:100%; aspect-ratio:16/9; border:0; background:#000}
.vid-cerrar{display:block; width:100%; min-height:48px; margin-top:auto;
  padding:12px 16px; border:0; border-top:1px solid rgba(255,255,255,.22);
  background:rgba(255,255,255,.12); color:#fff; font:inherit; font-weight:700;
  cursor:pointer}
.vid-cerrar:hover{background:rgba(255,255,255,.22)}
.vid-cerrar:focus-visible{outline:3px solid var(--amarillo); outline-offset:-3px}
.vid-mas{margin-top:clamp(22px,2.6vw,32px)}

/* ---- KICK: el video en vivo de la emisora ------------------------------
   Ver `parches/kick.aplicar-estilo-css.py` para por qué «a todo el ancho» son
   dos líneas y por qué el video lleva techo de altura. */
.franja-kick{background:rgba(1,22,56,.55);
  border-block:1px solid rgba(83,252,24,.35)}
/* A TODO EL ANCHO: esta franja NO se encierra en los 1180 px del resto. */
.kick-wrap{padding-inline:var(--pad);
  /* EL RELLENO DE LA TARJETA SE DECLARA ACÁ, NO EN `.kick-vid`, porque el
     rótulo tiene que saber cuánto mide para alinearse con ella. Una copia
     del `clamp` en cada lado son dos verdades esperando divergir. */
  --kick-relleno:clamp(10px,1vw,16px)}
.kick-k{display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:0 0 6px;
  font-size:13px; letter-spacing:.2em; text-transform:uppercase; font-weight:700;
  color:#BFD8F5}
.kick-vivo{display:inline-flex; align-items:center; gap:7px;
  padding:5px 11px; border-radius:999px; background:#53FC18; color:#04306F;
  font-size:12px; font-weight:700; letter-spacing:.14em; line-height:1.2}
.kick-vivo::before{content:""; width:8px; height:8px; border-radius:50%;
  background:#04306F; animation:kick-late 1.6s ease-in-out infinite}
@keyframes kick-late{0%,100%{opacity:1} 50%{opacity:.25}}
/* La información nunca vive sólo en el movimiento: el rótulo dice EN VIVO. */
@media (prefers-reduced-motion: reduce){
  .kick-vivo::before{animation:none}
}
/* El techo es de ALTURA, expresado en ancho, porque el video es 16/9. */
/* LA TARJETA RESPIRA Y ABRAZA. Pedido del dueño 2026-09-16:
     · `padding` adentro, porque el video y el chat quedaban pegados al borde;
     · y el fondo del tamaño del contenido, no más ancho. Medido a 1440: la
       tarjeta media 1328 px y lo de adentro 1066 —el video 712 y el chat 340—,
       así que sobraban 131 px de fondo a cada lado, vacíos. */
.kick-vid{max-width:min(100%, calc(76svh * 16 / 9)); margin-inline:auto;
  padding:var(--kick-relleno);
  margin-top:clamp(16px,2vw,24px)}
.kick-vid .vid-caja{background:#0B0F0A}
.kick-n{margin:0; font-size:14px; font-weight:700; color:#53FC18}

/* ---- KICK EN ESCRITORIO: que la franja entre en la ventana útil ---------
   Ver `parches/kick-alto.aplicar-estilo-css.py` para las mediciones completas
   y `pruebas/medir-kick-escritorio.mjs` para la vigilancia.

   EL TELÉFONO NO ENTRA ACÁ. Nada de este bloque alcanza a 360 ni a 390 px, y
   está comprobado midiendo los dos antes y después: 521 y 513 px, al píxel.

   LA UNIDAD ES LA VENTANA ÚTIL. Arriba hay un cabezal pegajoso y abajo la barra
   fija del reproductor: entre las dos se llevan entre 209 y 272 px que el
   contenido nunca tiene. Medido contra el viewport, la franja decía 128 %; con-
   tra lo que la persona realmente ve, 183 %. */
@media (min-width: 900px){
  /* 128 px de relleno son la proporción de una sección de portada, no la de una
     franja que compite con la ventana. */
  .franja-kick{padding-block:40px}
  .franja-kick .titulo{font-size:clamp(26px,2.2vw,34px); margin-bottom:16px}

  /* EL TECHO SE VA DE LA TARJETA. Cuando lo tenía ella, achicar el video
     angostaba también la ficha y el texto se envolvía: medido, la ficha saltaba
     de 135 a 212 px: el alto que se ahorraba volvía como renglones. */
  .kick-vid{margin-top:12px; max-width:none}

  /* LA FACHADA Y EL IFRAME, JUNTOS Y CON EL MISMO TECHO. No es simetría: es la
     condición. `.vid-marco` es el iframe que reemplaza a `.vid-caja` al tocar;
     achicar sólo la fachada haría que el video SALTE de tamaño al tocarlo y se
     mueva todo lo de abajo.

     Una RESTA y no un porcentaje: lo que hay que descontar —cabezal, barra,
     ficha— es un costo en píxeles que no encoge cuando encoge la ventana.
     El `* 16 / 9` convierte el alto que queremos en el ancho que se limita,
     porque la caja es `aspect-ratio:16/9`.

     EL PISO DE 280 px NO ES DECORACIÓN: SIN ÉL EL VIDEO DESAPARECE. En una
     ventana más baja que 610 px el `calc` da negativo; un negativo que sale de
     un `min()/calc()` no es inválido —eso sería un negativo literal— sino que
     se computa y SE ACOTA A CERO. Medido: `min(100%, calc((100svh-610px)*16/9))`
     a 560 px de ventana computa -88.9px y la caja queda en 0x0. El video no
     está, y no hay un solo error en ningún lado. */
  .kick-vid .vid-caja,
  .kick-vid .vid-marco{
    /* EL PISO SUBE DE 280 A 560 px. Con 280 el techo se cumplía a costa de la
       única cosa que la franja existe para mostrar: a 1280x800 la fachada
       quedaba en 338x190 —una estampilla en medio de una tarjeta de 1168— y el
       dueño lo vio en cuanto se desplegó. 560 es el mismo mínimo que se fijó
       para la forma de dos columnas: debajo de eso el video no se mira, se
       adivina. La sección queda algo más alta que el techo; entre una franja
       un poco larga y un video ilegible, se elige la franja. */
    max-width:min(100%, max(560px, calc((100svh - 610px) * 16 / 9)));
    margin-inline:auto}

  .kick-vid .vid-cuerpo{padding:12px 18px 14px; gap:4px}
}

/* ---- KICK EN TABLET: la franja entra debajo de la cabecera --------------
   Ver `parches/kick-tablet.aplicar-estilo-css.py` para las mediciones
   completas y `pruebas/medir-kick-tablet.mjs` para la vigilancia.

   EL DEFECTO, MEDIDO: a 768x1024 la franja medía 724 px y la cabecera 692. La
   franja era LO MÁS GRANDE DE LA PORTADA: empujaba la cara de la radio y se
   quedaba con la pantalla. A 820x1180 eran 759 contra 707.

   POR QUÉ, Y POR QUÉ EL TECHO DE ESCRITORIO NO LO ALCANZA. El techo de arriba
   —`calc((100svh - 610px) * 16 / 9)`— crece con el ALTO de la ventana, y un
   tablet es alto: a 1024, 1180 y 1366 px de alto ese `calc` da 736, 907 y 1344
   px, así que nunca muerde y el video se queda en el 100 % del ancho. La
   cabecera, en cambio, deja de crecer (`min-height:min(62vh,660px)` y el resto
   es contenido): medida de 768 a 1009 px de ancho da 692 · 707 · 708 · 721.
   Uno crece con el ancho, la otra no, y en tablet se cruzan.

   LA REGLA: en tablet el techo del video es FIJO, no una fracción de la
   ventana. 560 px es el mismo número que el escritorio usa como PISO —el ancho
   más chico que esta casa considera mirable—; acá es el techo, o sea que el
   video se queda en el tamaño más chico que sigue siendo mirable, y ése es el
   precio de que la cabecera siga siendo la cara de la radio.

   EL LUGAR DE ESTE BLOQUE ES LA MITAD DE LA REGLA, Y ESTÁ MEDIDO. Va DESPUÉS
   del bloque de escritorio —entre 900 y 1009 px los dos alcanzan a
   `.kick-vid .vid-caja` con la misma especificidad y ahí manda el orden— y
   ANTES del bloque del chat: `.kick-col-video .vid-caja` tiene la MISMA
   especificidad (0,2,0) que `.kick-vid .vid-caja`, así que el chat gana por
   estar después. Puesto al revés, a 1440x900 el video cae de 712x401 a 560x315
   y la franja de 625 a 540, sin un solo error en ningún lado.

   Y el `min-width` es el que deja afuera al teléfono: sin él, a 390x844 la
   franja pasa de 546 a 496 px porque la ficha en renglón le baja. Medido antes
   y después, al píxel: 390x844 546 · 360x640 556 · 320x568 594 · 1280x800 533 ·
   1440x900 625 · 1024x1366 572, todos iguales.

   EL CHAT NO ENTRA ACÁ Y NO SE TOCA: nace a 1010 px, así que este bloque
   termina en 1009, un píxel antes.

   NADA DE ACÁ LLEVA `width`: ni porcentaje ni `fit-content`. El cartel de
   `kick-abraza`, más abajo, explica con números —tarjeta 851,78 · video 470—
   por qué un ancho circular saca el chat. Acá sólo se limita un `max-width`
   con una longitud fija, que no puede depender de nadie. */
@media (min-width: 700px) and (max-width: 1009px){
  /* 77 px de relleno son la proporción de una sección de portada, no la de una
     franja que compite con la ventana. 26 es el mismo número que `kick-aire`
     eligió para la forma de dos columnas. */
  .franja-kick{padding-block:26px}
  .franja-kick .titulo{font-size:clamp(26px,2.2vw,34px); margin-bottom:16px}

  /* El techo se va de la tarjeta, igual que en escritorio: cuando lo tenía
     ella, achicar el video angostaba también la ficha y el alto que se ahorraba
     volvía como renglones. */
  .kick-vid{margin-top:12px; max-width:none}

  /* LA FACHADA Y EL IFRAME, CON EL MISMO TECHO. No es simetría: es la
     condición. `.vid-marco` es el `<iframe>` que reemplaza a `.vid-caja` al
     tocar; con el techo en una sola de las dos el video SALTA de 560 a 677 px
     al tocarlo —medido a 768— y se mueve todo lo de abajo. */
  .kick-vid .vid-caja,
  .kick-vid .vid-marco{max-width:560px; margin-inline:auto}

  /* LA FICHA EN RENGLÓN, la misma forma que ya se decidió para escritorio.
     Medido a 768: apilada mide 135 px y en renglón 90. No cambia una palabra
     del texto —el aviso «Al reproducirlo se pausa la radio» sigue entero—:
     cambia el acomodo. */
  .kick-vid .vid-cuerpo{padding:8px 16px 10px; gap:12px;
    flex-direction:row; align-items:baseline; flex-wrap:wrap}
  .kick-vid .vid-cuerpo .vid-t{font-size:16px}
}

/* ---- KICK: el video y el chat, lado a lado ------------------------------
   Ver `parches/kick-chat.aplicar-estilo-css.py` para las mediciones y
   `pruebas/medir-kick-chat.mjs` para la vigilancia.

   TODO ESTE BLOQUE VIVE DENTRO DE LA `@media`, Y NO ES ORDEN: es la condición.
   Debajo del umbral el chat NO EXISTE en el documento —lo borra `app.js`, no lo
   esconde el CSS—, así que una regla suelta afuera sería una regla que no puede
   alcanzar a nada. Si algún día alcanzara algo, sería el síntoma de que el chat
   se coló en una pantalla donde no tiene que estar.

   EL CHAT NACE SIN IFRAME. Lo monta `app.js` al tocar el video. Medido:
   embeberlo de entrada cuesta 110 peticiones y 8 cookies de terceros —una de
   Stripe— en la primera pantalla de CADA visita. */
@media (min-width: 1010px) and (min-height: 800px){
  /* LOS 28 px QUE COSTÓ QUE LA TARJETA RESPIRE. El `padding` de `.vid` suma
     arriba y abajo, y con él la franja pasaba de 536 a 561 contra 557 de
     ventana útil: se iba por 4 px. No se le sacan al video —ya está en su piso
     de 560— ni al chat —su caja ya está en 227— ni al `padding` nuevo, que es
     un pedido del dueño. El relleno de la franja es de donde se puede.
     Medido: 40 -> 26 devuelve los 28. Ver kick-aire.aplicar-estilo-css.py. */
  .franja-kick{padding-block:26px}
  .kick-fila{display:flex; gap:14px; align-items:stretch; justify-content:center}

  /* EL ANCHO VA EN LA COLUMNA, NO EN LA CAJA. Con la columna sin ancho
     intrínseco el video colapsa a 0x0 — medido, y por eso está escrito.

     EL DESCUENTO LLEVA UN TÉRMINO EN `vw` PORQUE LO QUE SE DESCUENTA CRECE CON
     EL ANCHO: el cabezal pasa de 155 px a 1280 a 184 px a 1920, y ninguno de los
     dos se puede nombrar en CSS. Es un AJUSTE EMPÍRICO sobre tres ventanas
     medidas, no una derivación: vale de 1010 a 1920 px de ancho y de 800 a 1080
     de alto, y fuera de ahí no está medido.

     EL PISO ES 560 px, el mismo mínimo que el de la forma apilada: debajo de eso
     el video no se mira, se adivina. Y además impide el caso peor: un negativo
     que sale de un `min()/calc()` no es inválido —se acota a cero— y la columna
     quedaría en 0x0 con el video adentro. */
  .kick-col-video{flex:0 0 auto; min-width:0; display:flex; flex-direction:column;
    width:min(calc(100% - 354px),
              max(560px, calc((100svh - 364px - 9.4vw) * 16 / 9)))}
  .kick-col-video .vid-caja,
  .kick-col-video .vid-marco{max-width:none}

  /* ---- EL FONDO ABRAZA EL CONTENIDO -----------------------------------
     Ver `parches/kick-abraza.aplicar-estilo-css.py`.

     EL ANCHO DEL VIDEO NO PUEDE LLEVAR UN PORCENTAJE. Con `calc(100% - 354px)`
     y la tarjeta en `fit-content`, el contenedor mide lo que mide el contenido
     y el contenido mide lo que mide el contenedor: el navegador resuelve esa
     circularidad con la medida intrínseca y **el chat desaparece**. Medido: la
     tarjeta cayó de 1328 a 852 px y el chat no salió a 1280 ni a 1440, sin un
     solo error.

     Acá el ancho sale sólo del ALTO de la ventana, que es una longitud definida
     sin mirar al contenedor. Y no sirve guardarse el porcentaje en una variable:
     una propiedad personalizada se sustituye como TEXTO y el `100%` termina
     resolviéndose contra la fila igual. */
  /* ---- EL TECHO DEL VIDEO SIGUE LA LEY DE LA CABECERA ----------------
     Ver `parches/kick-cabecera.aplicar-estilo-css.py` y
     `pruebas/medir-kick-cabecera.mjs`.

     EL DEFECTO, MEDIDO: a 1920x1080 la franja medía 766,05 px y la cabecera
     730,39; a 1440x900, 625,30 contra 622,78. La franja era LO MÁS GRANDE DE
     LA PORTADA, igual que en tablet pero por el otro eje.

     POR QUÉ. El techo de arriba crece 1,0 px por cada píxel de alto de ventana
     y la cabecera crece 0,58 —es `min(58vh,650px)` de foto más su relleno—.
     Dos rectas de pendiente distinta se cruzan, y arriba del cruce la franja
     gana siempre: a 1920x1200 se pasaba por 132 px y a 2560x1440 por 312.

     LA REGLA: un SEGUNDO techo, que es la ley de la propia cabecera.
     `min(58svh, 650px)` es carácter por carácter lo que `.hero-img img` usa
     para su foto; los 140 px son lo que la franja gasta en lo que la cabecera
     no tiene (rótulo EN VIVO, título, relleno de la tarjeta, ficha), medido.
     Gana el más chico de los dos, así que el techo viejo sigue mandando donde
     ya mandaba: **a 1280x800 no se mueve un solo píxel** (video 561,20 · franja
     533,14), y ahí está el borde de 140 — con más de 148 se movería.

     El `650px` no es adorno: arriba de 1121 px de alto la cabecera DEJA de
     crecer y sin ese tope el video seguiría creciendo solo.

     Y ES `svh` Y NO `vh` a propósito, aunque la cabecera diga `vh`: en una
     ventana con barra que se esconde, `svh` es el más chico de los dos, que es
     el lado seguro. */
  .kick-col-video{flex:0 1 auto;
    width:max(560px, min(calc((100svh - 364px - 9.4vw) * 16 / 9),
                           calc((min(58svh, 650px) * 3 / 4) * 16 / 9)))}

  /* Estos dos `100%` sí se pueden: se resuelven contra `.kick-wrap`, que tiene
     ancho definido y no es `fit-content`. La cadena va en un solo sentido.
     `flex:0 1 auto` arriba es lo que hace que en un escritorio angosto el video
     se ENCOJA en vez de desbordar; el piso de 560 lo vigila la suite. */
  .kick-fila{width:max-content; max-width:100%}
  .kick-vid{width:fit-content; max-width:100%; margin-inline:auto}

  /* LA BARANDA ES EL PORCENTAJE, NO `fit-content` — Y ESTE CARTEL DECÍA OTRA
     COSA. Acá había una advertencia que prohibía `width:fit-content` en
     `.kick-vid` «porque saca el chat». **Era cierta cuando se escribió**: la
     columna del video medía `min(calc(100% - 354px), …)` y contra ese
     porcentaje el `fit-content` cerraba la circularidad. `kick-abraza` le sacó
     el porcentaje ese mismo día y la advertencia caducó. No fue un error de
     quien la escribió: dejó de describir el archivo.

     Y una advertencia caducada no es neutra. Nombra el mecanismo equivocado en
     el lugar exacto donde uno va a leer justo cuando duda: mandaba esquivar
     `fit-content`, que hoy es inofensivo, y dejaba pasar el porcentaje, que es
     lo que duele.

     MEDIDO EL 2026-09-16 con `pruebas/medir-kick-rotulo.mjs` — laboratorio
     armado desde `site/`, Kick encendido, Chromium, a 1440x900 y 1280x800:

       · `.kick-wrap{width:fit-content}` SOLO  ->  19 ok, 0 fallas. Tarjeta
         1097.02 px y chat 340: idéntico a no tocar nada.
       · devolverle el porcentaje al ancho del video (`width:calc(100% - 354px)`)
         Y ADEMÁS hacer que el contenedor mida lo que mide su contenido  ->  la
         tarjeta cae a 851.78 px —el 852 de septiembre, al píxel— y el video se
         encoge a 470, muy por debajo de su piso de 560.

     LO QUE SE CAE PRIMERO ES EL VIDEO, NO EL CHAT. `.kick-col-chat` es
     `flex:0 0 340px`, así que defiende sus 340 mientras el video se achica. El
     síntoma de septiembre —«el chat no sale»— era el final de ese camino, no su
     primer escalón: quien mire sólo el chat puede ver verde con el video en 470.

     LA REGLA, ENTONCES: el `width` que GANA para `.kick-col-video` no puede
     llevar un porcentaje. Lo vigila el testigo de
     `parches/kick-abraza.aplicar-estilo-css.py` y lo fabrica el mutante
     `SIN=envoltura` de `pruebas/medir-kick-rotulo.mjs`, que lo deja ver fallar. */
  .kick-col-chat{flex:0 0 340px; width:340px;
    display:flex; flex-direction:column}
  /* EL RÓTULO SE APRIETA, PERO NO SE VA. Es lo único que el chat tiene arriba y
     cada píxel que ocupa se lo saca a los mensajes: la columna mide lo que mide
     el video, y a 1280x800 eso son 316 px. El texto no cambia — es la condición
     que no se negocia—; lo que cambia es el tamaño. */
  .kick-chat-k{margin:0 0 1px; font-size:11.5px; letter-spacing:.12em;
    text-transform:uppercase; font-weight:700; color:#53FC18}
  .kick-chat-nota{margin:0 0 6px; font-size:11.5px; line-height:1.28; color:#BFD8F5}
  .kick-chat-caja{flex:1 1 auto; min-height:0; position:relative;
    background:#0B0F0A; border-radius:12px; overflow:hidden}
  .kick-chat-caja iframe{display:block; width:100%; height:100%; border:0}
  .kick-chat-espera{margin:0; padding:14px 16px; font-size:13.5px; color:#BFD8F5}

  /* La ficha en un renglón: son 135 px que a 1280x800 son la diferencia entre
     entrar en la ventana útil y no entrar. */
  .kick-vid .vid-cuerpo{padding:8px 16px 10px; gap:12px;
    flex-direction:row; align-items:baseline; flex-wrap:wrap}
  .kick-vid .vid-cuerpo .vid-t{font-size:16px}

  /* ---- EL RÓTULO ARRANCA DONDE ARRANCA LA TARJETA ---------------------
     Ver `parches/kick-rotulo.aplicar-estilo-css.py` y
     `pruebas/medir-kick-rotulo.mjs`.

     Pedido del dueño 2026-09-16: «move the mira la cabina en vivo to the edge
     of the background holder of the video frame.. right now is all the way to
     the left». Medido a 1440x900: el rótulo arrancaba en x=56 —el `--pad` del
     wrap— y la tarjeta en x=171, porque es `fit-content` y va centrada. Son
     115 px de desalineación, y a 1280x800 eran 113.

     NO SE ENVUELVEN RÓTULO Y TARJETA EN UN CONTENEDOR `fit-content`. Es lo
     primero que se le ocurre a cualquiera y es exactamente lo que sacó el chat
     el 16/09 —la tarjeta cayó de 1328 a 852 px, sin un solo error en consola—:
     los `100%` de `.kick-fila` y `.kick-vid` se resuelven contra `.kick-wrap`,
     y si `.kick-wrap` pasa a medir lo que mide su contenido, el cálculo se
     muerde la cola. Está escrito treinta renglones más arriba.

     Acá no se toca ni un ancho: se le pone al RÓTULO el mismo margen que el
     centrado le da a la tarjeta. La tarjeta mide video + separación + chat +
     su relleno a los dos lados + su borde de 1px a cada lado (`box-sizing` es
     `border-box`, así que el borde entra en el ancho).

     TRES DE ESOS NÚMEROS ESTÁN ESPEJADOS, Y SE PROBÓ NO ESPEJARLOS. Lo primero
     que se hizo fue poner `width:var(--kick-video)` en `.kick-col-video`,
     `gap:var(--kick-sep)` en `.kick-fila` y `var(--kick-chat)` en el chat, para
     que hubiera una sola verdad. Medido: eso deja a `kick-abraza` y a
     `kick-chat` en A_MEDIAS —sus centinelas leen esas declaraciones tal cual,
     `kick-abraza` exige que el ancho que gana mencione `svh`—, o sea que el día
     que alguien vuelva a correrlos se niegan sobre un archivo que está bien.
     Un centinela ajeno roto es peor que una copia vigilada, así que la copia se
     queda **y quien la vigila es `pruebas/medir-kick-rotulo.mjs`**: si alguien
     cambia el `14px`, el `340px` o la fórmula del video en un solo lado, el
     rótulo se corre y la suite se pone roja en la misma corrida.

     `--kick-relleno` sí es una sola verdad: se declara arriba, en `.kick-wrap`,
     y `.kick-vid` la usa. Ése no lo lee ningún centinela ajeno.

     LOS `100%` DE ACÁ SÍ SE PUEDEN, y por la misma razón de siempre: el
     selector es HIJO DIRECTO de `.kick-wrap`, que tiene ancho definido. Por eso
     dice `>` y no un descendiente cualquiera — un `.titulo` más adentro
     resolvería su porcentaje contra otra caja y el margen saldría mal.

     El `max(0px, …)` es el caso de escritorio angosto: cuando la tarjeta llega
     a `100%` no sobra nada que repartir y el margen tiene que ser cero, no
     negativo. */
  .kick-wrap{--kick-chat:340px; --kick-sep:14px;
    --kick-video:max(560px, min(calc((100svh - 364px - 9.4vw) * 16 / 9),
                           calc((min(58svh, 650px) * 3 / 4) * 16 / 9)));
    --kick-tarjeta:min(100%, calc(var(--kick-video) + var(--kick-sep)
                       + var(--kick-chat) + var(--kick-relleno) * 2 + 2px));
    --kick-margen:max(0px, calc((100% - var(--kick-tarjeta)) / 2))}
  .kick-wrap > .kick-k,
  .kick-wrap > .titulo{margin-inline:var(--kick-margen)}
}

/* ---- KICK EN LA VENTANA ANCHA Y CORTA: la ficha se pone al lado ---------
   Ver `parches/kick-cabecera.aplicar-estilo-css.py` para las mediciones
   completas y `pruebas/medir-kick-cabecera.mjs` para la vigilancia.

   QUIÉN CAE ACÁ: ancho >= 1010 y alto < 800, o sea la ventana donde el chat NO
   existe —`app.js` lo borra debajo de 1010x800— pero el bloque de ESCRITORIO
   sí la agarra. El iPad acostado (1024x768) y el portátil de 1280x720 viven
   acá.

   EL DEFECTO, MEDIDO: a 1024x768 la franja medía 630,58 px y la cabecera
   535,77. Se pasaba por 94,81.

   POR QUÉ NO SE ARREGLA COMO EN TABLET. En tablet alcanzó con apretar el
   relleno y poner la ficha en renglón. Acá no: el video YA está en su piso de
   560 px —con alto < 800, `calc((100svh - 610px) * 16 / 9)` nunca pasa de 337,
   así que el `max(560px, …)` manda siempre— y bajarlo es lo que el dueño
   prohibió. Con el relleno apretado y la ficha en renglón la franja quedaba en
   574,27: seguía pasándose por 38,50.

   LA REGLA: la ficha se muda AL LADO del video, al hueco que en una ventana
   alta ocupa el chat, con la separación del chat (14 px) y el ancho del chat
   (340 px). Deja de costar alto: la tarjeta pasa a medirla el video.
   Medido: franja 630,58 -> 467,48 contra una cabecera de 535,77.

   Y ES ROBUSTO, que es la mitad del trabajo: con la ficha DEBAJO, el alto de la
   franja dependía del título del programa, que lo escribe Kick. Con un título
   de 130 caracteres la franja se iba a 654,89. Al lado, el mismo título da
   467,48 —el mismo número al píxel—, porque la ficha sigue siendo más baja que
   el video.

   `display:contents` EN LOS DOS ENVOLTORIOS NO ES LIMPIEZA. `app.js` arma
   `.kick-fila` y `.kick-col-video` cuando nace el chat, y `chatSacar()` borra
   el chat pero NO los envoltorios: se quedan para siempre. O sea que hay DOS
   documentos posibles en esta ventana —el que nació acá y el que se achicó
   desde 1024x900— y sin esto el segundo se dibuja distinto. Con esto los dos
   miden idéntico: franja 467,48 · video 560x315 en x=57 · ficha en x=631.

   LA FACHADA Y EL IFRAME, JUNTOS. No es simetría: es la condición. `.vid-marco`
   reemplaza a `.vid-caja` al tocar, y sin el mismo `flex` y el mismo
   `margin-inline` el video se corre al tocarlo. Medido: 560x315 en x=57 antes
   y después de tocar. Es la lección que `kick-tablet` pagó con `SIN=iframe`.

   EL `margin-inline:0` TAMPOCO ES ADORNO: el bloque de escritorio le pone
   `auto`, y un margen automático dentro de una fila se come TODO el espacio
   libre. Con `auto`, a 1920x799 el par quedaba pegado a la derecha en vez de
   centrado — medido: el video arrancaba en x=933 en vez de x=503.

   NADA DE ACÁ LLEVA `width`: el cartel de `kick-abraza`, más arriba, explica
   con números —tarjeta 851,78 · video 470— por qué un ancho circular saca el
   chat, y acá `.vid-caja` es `width:100%`. Se reparte con `flex` y se frena con
   `max-width`, que no pueden morderse la cola. */
@media (min-width: 1010px) and (max-height: 799px){
  /* El mismo relleno que ya usan el bloque del chat y el de tablet: 26. */
  .franja-kick{padding-block:26px}

  /* Los envoltorios que `app.js` deja atrás dejan de dibujar caja. */
  .kick-fila,
  .kick-col-video{display:contents}

  /* EL `wrap` NO ES PRUDENCIA, Y ESTÁ MEDIDO CON EL VIDEO ABIERTO.
     `abrirVideo()` cuelga «Cerrar el video» del ARTÍCULO, o sea que en esta
     fila es un tercer hijo. Con `nowrap`, al tocar el video la ficha se
     aplasta a 0 px de ancho, su texto se apila letra por letra y **la franja
     pasa de 467 a 2619 px** — sin un solo error en ningún lado. Con `wrap` el
     botón baja solo, porque ya es `width:100%`.
     Y no parte el renglón del video: la ficha tiene base 0, así que el renglón
     mide 560 y entra en la ventana más angosta del régimen. */
  .kick-vid{flex-flow:row wrap; align-items:flex-start;
    justify-content:center; gap:14px}

  .kick-vid .vid-caja,
  .kick-vid .vid-marco{flex:0 0 auto; margin-inline:0}

  /* 340 px es el ancho del chat, cuyo lugar ocupa. Con `flex:1 1 0` se achica
     sola en la ventana angosta (a 1010 mide 323) en vez de partir el renglón. */
  .kick-vid .vid-cuerpo{flex:1 1 0; min-width:0; max-width:340px;
    padding:2px 0 0; gap:6px}
}


/* ---- la puerta de El Tráfico -------------------------------------------
   Ver `parches/calle-puerta.aplicar-estilo-css.py` para qué se reusa y por qué
   la banda de confianza se ve distinta de un aviso de la emisora. */
.calle-alta{margin-top:clamp(26px,3vw,40px); background:rgba(1,36,88,.5);
  border:1px solid rgba(255,255,255,.22); border-radius:24px;
  padding:clamp(22px,2.6vw,32px)}
.calle-alta-t{font-size:clamp(22px,2.6vw,30px); margin:0 0 8px}
.calle-alta-l{margin:0 0 22px; font-size:16px; color:#CFE6FF; line-height:1.55}
.calle-alta-l strong{color:var(--amarillo)}
/* El tipo elegido toma SU color, no el rosa de por omisión: es el mismo color
   con el que va a salir el pin, así que ella ve de antemano qué está eligiendo.
   `--c` y `--t` los escribe `build.py` leyéndolos de `TIPOS`, que es la única
   lista de tipos que hay. */
.calle-tipos{margin-bottom:20px}
.calle-tipo input:checked + .motivo-cara{background:var(--c); color:var(--t);
  border-color:#fff; box-shadow:0 6px 18px rgba(0,0,0,.35)}
.calle-punto{display:flex; flex-wrap:wrap; align-items:center; gap:12px 16px;
  margin-top:20px}
/* Más chico que el `.btn-ghost` de la portada: acá es un control de formulario
   y no la llamada principal de una sección. */
.calle-marcar{min-height:52px; font-size:16px; padding:0 22px; border-width:2px;
  background:none; color:#fff; font-family:inherit; cursor:pointer}
.calle-punto-txt{font-size:15px; color:var(--halo); font-weight:700}
.calle-quitar{min-height:44px; padding:0 12px; border:0; background:none;
  color:#FFD2DF; font:inherit; font-weight:700; text-decoration:underline;
  cursor:pointer}
.calle-pie{margin-top:24px}
.calle-enviar{width:100%}
@media (min-width:620px){ .calle-enviar{width:auto; min-width:280px} }
/* En el escritorio, la cruz. En un teléfono no hay cursor: la señal de verdad
   es el texto y el rótulo del botón, que los escribe `app.js`. */
body.calle-apuntando .mapa{cursor:crosshair}
body.calle-apuntando .mapa-caja{outline:3px solid var(--amarillo); outline-offset:3px}

/* ---- cuánto creerle a cada aviso --------------------------------------- */
.calle-banda{display:inline-block; margin-top:8px; padding:4px 10px;
  border-radius:999px; background:rgba(255,255,255,.12);
  border:1px solid rgba(255,255,255,.28); color:#D9E8FA;
  font-size:12.5px; font-weight:700; line-height:1.35}
.calle-banda-conf{background:rgba(79,168,255,.18); border-color:rgba(79,168,255,.5);
  color:#C4E2FF}

/* ---- «yo también lo vi» ------------------------------------------------- */
.calle-conf{margin-top:10px}
.calle-conf-btn{min-height:44px; padding:0 16px; border-radius:999px;
  border:2px solid rgba(255,255,255,.45); background:none; color:#fff;
  font:inherit; font-size:14.5px; font-weight:700; cursor:pointer}
.calle-conf-btn:hover{background:rgba(255,255,255,.16); border-color:#fff}
.calle-conf-btn:focus-visible{outline:3px solid var(--amarillo); outline-offset:2px}
.calle-conf-btn[disabled]{opacity:.6; cursor:default}
.calle-conf-nota{display:inline-block; font-size:13.5px; color:var(--halo);
  font-weight:700; padding:6px 0}
.calle-conf-mal{color:#FFD2DF; margin-left:8px}


/* ---- carrusel de la cabecera -------------------------------------------
   Ver `parches/hero-carrusel.aplicar-estilo-css.py`. Con UNA sola diapositiva
   `build.py` no emite el envoltorio y nada de esto se usa. */
.hero-car{position:relative}
.hero-car-pista{position:relative}

/* ESTA LÍNEA ES LA QUE NO SE PUEDE PERDER.
   `[hidden]` vale `display:none` desde la hoja del NAVEGADOR, y `.hero` trae
   `display:grid` desde la del autor: el autor gana siempre. Sin esto, las
   cinco diapositivas se ven apiladas, con `hidden` puesto y sin un solo error
   en consola. */
.hero-car-d[hidden]{display:none !important}

.hero-car-flecha{
  position:absolute; top:50%; transform:translateY(-50%); z-index:3;
  display:flex; align-items:center; justify-content:center;
  width:44px; height:44px; padding:0; border-radius:50%;
  border:2px solid rgba(255,255,255,.55); background:rgba(1,22,56,.72);
  color:#fff; cursor:pointer; transition:background .12s ease}
.hero-car-flecha:hover{background:var(--rosa); border-color:#fff}
.hero-car-flecha:focus-visible{outline:3px solid var(--amarillo); outline-offset:3px}
.hero-car-antes{left:clamp(4px,1.5vw,14px)}
.hero-car-sig{right:clamp(4px,1.5vw,14px)}

.hero-car-puntos{
  position:absolute; left:0; right:0; bottom:clamp(6px,1.4vw,16px); z-index:3;
  display:flex; justify-content:center; align-items:center; gap:2px}
/* El blanco de TOQUE mide 44; el punto que se VE mide 10. Un punto de 44 px es
   una pelota, y uno de 10 px no se puede tocar en un teléfono. */
.hero-car-punto{
  width:44px; height:44px; padding:0; border:0; background:none;
  display:flex; align-items:center; justify-content:center; cursor:pointer}
.hero-car-punto::before{
  content:""; display:block; width:10px; height:10px; border-radius:50%;
  background:rgba(255,255,255,.45); box-shadow:0 1px 4px rgba(0,0,0,.5);
  transition:background .12s ease, transform .12s ease}
.hero-car-punto[aria-current="true"]::before{background:var(--amarillo); transform:scale(1.35)}
.hero-car-punto:hover::before{background:#fff}
.hero-car-punto:focus-visible{outline:3px solid var(--amarillo); outline-offset:-6px;
  border-radius:50%}

/* ---- el botón de pausa del carrusel -------------------------------------
   Ver `parches/carrusel-pausa.aplicar-estilo-css.py`. El botón lo crea
   `montarPausa()` en `app.js`, no `build.py`: estas reglas sólo se usan cuando
   hay carrusel **y** el carrusel gira. Sin JavaScript, con una sola diapositiva
   o con `prefers-reduced-motion: reduce`, el elemento no existe y nada de esto
   se aplica.

   POR QUÉ ARRIBA A LA DERECHA — fue la única esquina que quedaba libre:
     · abajo viven las flechas y los puntos, y a 1280 px la barra fija del
       reproductor (`.reproductor`, z-index 60) se come el borde inferior;
     · arriba a la izquierda, en escritorio, está la columna de texto: el botón
       taparía el `eyebrow` y el título, y el pedido era no tapar nada.
   Arriba a la derecha cae sobre la foto en los dos anchos, y la foto la elige
   la emisora y puede ser cualquier cosa. Por eso la píldora repite EXACTAMENTE
   el vestido de `.hero-car-flecha` —azul oscuro translúcido con borde blanco y
   marca blanca— que ya está en uso sobre imágenes claras y oscuras. No es una
   pieza de diseño nueva: es la hermana de las flechas, en la otra esquina. */
.hero-car-pausa{
  position:absolute; z-index:3;
  top:clamp(6px,1.4vw,16px); right:clamp(4px,1.5vw,14px);
  display:flex; align-items:center; justify-content:center;
  width:44px; height:44px; padding:0; border-radius:50%;
  border:2px solid rgba(255,255,255,.55); background:rgba(1,22,56,.72);
  color:#fff; cursor:pointer; transition:background .12s ease}
.hero-car-pausa:hover{background:var(--rosa); border-color:#fff}
.hero-car-pausa:focus-visible{outline:3px solid var(--amarillo); outline-offset:3px}

/* LOS DOS ÍCONOS SE TURNAN CON `hidden`, Y ESTA ES LA LÍNEA QUE NO SE PUEDE
   PERDER: es la misma trampa que `.hero-car-d[hidden]` unos renglones más
   arriba. `[hidden]` vale `display:none` desde la hoja del NAVEGADOR y el
   `display:block` de acá viene de la del AUTOR — el autor gana siempre. Sin
   esta regla se verían los DOS íconos encimados, sin un solo error en consola
   y con el botón diciendo las dos cosas a la vez. */
.hero-car-pausa svg{display:block}
.hero-car-pausa svg[hidden]{display:none}


/* ---- la tira de puntos no se come el toque de las flechas ----------------
   Ver `parches/hero-flecha-tocable.aplicar-estilo-css.py`. Medido: a 360 px un
   toque en el centro de `.hero-car-sig` lo recibe `DIV.hero-car-puntos` y la
   diapositiva no cambia. La tira es `left:0;right:0` con el MISMO `bottom` y el
   MISMO `z-index` que las flechas abajo de 760 px, y va después en el DOM.
   No cambia nada de lo que se VE: sólo quién recibe el dedo. */
.hero-car-puntos{pointer-events:none}
.hero-car-punto{pointer-events:auto}


/* En un teléfono la cabecera se apila y las flechas encima de la foto tapan
   media cara. Bajan al borde inferior, al lado de los puntos. */
@media (max-width:760px){
  .hero-car-flecha{top:auto; bottom:clamp(6px,1.4vw,16px); transform:none}
  .hero-car-antes{left:clamp(8px,4vw,20px)}
  .hero-car-sig{right:clamp(8px,4vw,20px)}
}


/* ---- la caja del carrusel no cambia de alto ----------------------------
   Ver `parches/hero-caja-fija.aplicar-estilo-css.py`. Medido: sin esto, pasar
   de diapositiva movía 32 px lo que está debajo del hero, sin ningún error.
   Todo va bajo `.hero-car-d`, que sólo existe con más de una diapositiva: con
   una sola, nada de esto se aplica. */
.hero-car-d .hero-img{height:min(58vh,650px)}
/* LA BANDA ENTERA, SIN RECORTAR. Esta regla es la que MANDA cuando hay
   carrusel: es más específica que `.hero-img img`.
   El 2026-09-16 pasó por los tres estados, y los tres se vieron:
     `height:100%` + `contain` -> la banda flotaba con azul vacío arriba y
        abajo, porque el carrusel estira la diapositiva a la altura de la
        columna del texto y la imagen se encogía DENTRO de esa caja alta.
     `height:100%` + `cover`   -> cubría todo, pero recortaba: se comía el
        nombre del DJ a la derecha y parte del nombre del programa a la
        izquierda. El dueño lo vio y dijo que no.
     `height:auto` + `contain` -> la caja deja de estirarse y toma la forma
        de la imagen: se ve la banda COMPLETA y no queda banda vacía adentro
        del marco. Lo que sobra es de la columna, no de la imagen. */
.hero-car-d .hero-img img{height:auto; max-height:none; object-fit:contain}

/* ---- UN TECHO DE ALTO, QUE NO ES UN ALTO FIJO --------------------------
   Ver `parches/hero-techo-alto.aplicar-estilo-css.py` para las mediciones
   completas y `pruebas/medir-hero-alto.mjs` para la vigilancia.

   EL PEDIDO DEL DUEÑO: «only one high size for home page hero header images…
   xavi shows to high. el cochi is the perfect high, but when we have a
   rectangly photo, its fine about the high, it does not have to be the same».

   EL DEFECTO, MEDIDO EN EL SITIO PÚBLICO. La regla de arriba deja la imagen
   SIN techo, y con `width:100%` el alto sale entero de la relación de la foto.
   A 1440x900, con una columna de 569,75:

       Xavi (349x490)      799,92   <- se pasa 230 px del alto de El Cochi
       Amarilis (768x780)  578,64
       la ANCHA (2048x1037) 288,48
       El Cochi (662x662)  569,75   <- el alto correcto

   LA REGLA, EN DOS TÉRMINOS. `100cqw` es el ancho de la propia columna, o sea
   el alto de El Cochi, en cualquier ventana; no hay un número mágico que se
   quede viejo. Después: 569,75 · 569,75 · 288,48 · 569,75 a 1440; 564,80 a
   1280; 450,59 a 1024; 370 a 390.

   PERO `cqw` NO SABE NADA DEL ALTO DE LA VENTANA, y ahí quedaba vivo el mismo
   síntoma. Ver `parches/hero-techo-ventana.aplicar-estilo-css.py`. Medido en
   el sitio público, El Cochi como tajada del alto de la ventana: 89,09 % a
   1366x640, 71,63 % a 768x1024 y 70,60 % a 1280x800, contra el 63,31 % de
   1440x900 que el dueño aprobó. En una ventana baja o en una tablet vertical
   la foto se seguía comiendo la pantalla.

   POR ESO EL TECHO ES COMPUESTO, y el 64 no se eligió: se midió. El Cochi es
   cuadrada, así que su alto ES el ancho de la columna, y barriendo anchos a
   900 px de alto su mayor tajada es 63,35 % (1366x900). Debajo de eso se la
   achica —con `63svh`, a 1440x900 mide 567,00 en vez de 569,75—, y arriba de
   70,60 % no se arregla nada —con `70svh`, a 768x1024 quedan 716,80 px—. El
   entero más chico que respeta el piso es 64. Nada que hoy esté en 63,35 % o
   menos se mueve un píxel; lo que esté por encima baja a 64 %.

   Y ES `svh` COMO EL TECHO DE LA FRANJA DE KICK: en una ventana con barra que
   se esconde `svh` es el más chico de los dos, que es el lado seguro.

   LA ANCHA SIGUE SIN MOVERSE en las nueve ventanas medidas: 288,70 · 371,38 ·
   185,83 · 288,48 · 285,97 · 228,16 · 187,34 · 288,02 · 287,80, idénticos
   antes y después.

   LO QUE ESTO NO CIERRA: `.hero` tiene `overflow:hidden` y la figura tiene su
   propio alto, así que una foto más alta que su figura se recorta por arriba.
   Medido: 196,72 px a 768x1024 y 15,00 a 390x844 antes; 157,67 y 15,00
   después. Bajó donde bajó la foto y no se persiguió: cerrarlo obliga a tocar
   el alto de la figura, que es la regla de `hero-caja-fija`.

   ES `max-height` Y NO `height`, Y ESA ES LA MITAD QUE PIDIÓ EL DUEÑO. Con
   `height` la banda ancha se subiría a 569,75 y quedaría flotando en azul —
   que es el estado que él ya rechazó el 2026-09-16. Con `max-height` la ancha
   NO cambia ni un píxel: 288,48 antes y después.

   NO RECORTA Y NO DEFORMA: Xavi queda 405,80 x 569,75 dentro de una caja de
   569,75 x 569,75 con el `contain` de arriba, con bandas del azul del hero a
   los costados.

   `container-type` NO ES ADORNO, Y SU FALLA NO AVISA: sin contenedor de
   consulta, `cqw` no da error — cae a la ventana chica, o sea 100svw (1440 px
   en vez de 570), y el techo deja de morder en silencio.

   VA DESPUÉS DE LA LÍNEA DE ARRIBA PORQUE TIENEN LA MISMA ESPECIFICIDAD
   (0,2,1) y entre iguales manda el orden del archivo. Puesta antes, el
   `max-height:none` gana y el arreglo no existe, sin que nada falle.

   MEDIDO Y DESCARTADO: la columna del texto NO se mueve (592,98 · 587,84 ·
   468,97 · 370,00, idéntico antes y después), y `.hero-img` no contiene nada
   más que el `IMG` — las flechas y los puntos cuelgan de `.hero-car`.

   LO QUE ESTO **NO** EMPAREJA: el alto de la SECCIÓN. Con Xavi mide 677,23
   antes y 677,23 después; esos 54 px de más son su `lede`, no su foto. */
.hero-car-d .hero-img{container-type:inline-size}
.hero-car-d .hero-img img{max-height:min(100cqw,64svh)}

/* Y ABAJO DE 800 px TAMBIÉN, que es la parte que no es opcional: ahí
   `estilo.css:693` pone `max-height:none`, o sea que NO hay techo que amortigüe,
   y `order:-1` manda la foto primero — así que el salto empuja el botón de
   escuchar fuera de pantalla justo donde la oyente vino a apretarlo. */
@media (max-width:800px){
  .hero-car-d .hero-img{height:min(46vh,340px)}
}


/* ---- las dos puertas directas, arriba del formulario del diálogo ---------
   Ver `parches/puerta-canales.aplicar-estilo-css.py`. Clases nuevas: no pisan
   ninguna regla existente. Si la emisora no configuró ningún canal, `build.py`
   no emite este bloque y nada de esto llega a aplicarse. */
.puerta-canales{margin:0 0 18px}
.puerta-canales-t{margin:0 0 10px; font-size:14px; color:var(--halo); line-height:1.45}
.puerta-canales-fila{display:flex; gap:10px}
.puerta-canal{
  /* `min-width:0` es lo que impide que la fila desborde a la derecha en la
     pantalla angosta: sin él un hijo de flex no baja de su ancho de contenido. */
  flex:1 1 0; min-width:0;
  display:inline-flex; align-items:center; justify-content:center; gap:9px;
  min-height:52px; padding:0 12px;          /* 52 > los 44 px táctiles mínimos */
  text-decoration:none; background:var(--amarillo); color:#04306F;
  font-family:inherit; font-weight:700; font-size:15px; line-height:1.15;
  border-radius:999px;
}
.puerta-canal svg{flex:none}
.puerta-canal span{overflow-wrap:anywhere}
.puerta-canal:hover{filter:brightness(1.07)}
/* El anillo de foco del sitio es amarillo, y acá el botón YA es amarillo: sobre
   él no se vería. Va blanco, que es lo que contrasta contra los dos. */
.puerta-canal:focus-visible{outline:3px solid #fff; outline-offset:3px}
.puerta-canales-o{margin:14px 0 0; font-size:13px; color:var(--halo); text-align:center}


/* ---- el botón al lado del título ---------------------------------------
   «Del lado opuesto al título»: el `<h1>` a un lado, la acción al otro. El
   markup lo arma `cabecera_accion()` en `build.py` y lo cablea
   `montarAccionCabecera()` en `app.js`. Ver
   `parches/cabecera-accion.aplicar-estilo-css.py`. */
/* `flex-start` Y NO `flex-end`, y se decidió MIDIENDO. Con `flex-end` el botón
   se alineaba al pie de la columna de texto: a 1280 px quedaba en y=420..492
   con el `<h1>` en y=329..406, o sea **al lado del `lede` y no del título**. El
   dueño pidió «on the opposite side of El Tráfico title». Con `flex-start` los
   dos arrancan juntos —el título mide 77 px de alto y el botón 72— y la fila se
   lee como lo que es: título a un lado, acción al otro. */
.cabecera-fila{display:flex; flex-wrap:wrap; align-items:flex-start;
  justify-content:space-between; gap:clamp(14px,2.2vw,32px)}
/* `min-width:0` para que el título pueda encoger: sin eso la fila desborda a
   lo ancho y `html{overflow-x:clip}` lo tapa sin avisar. */
.cabecera-txt{flex:1 1 320px; min-width:0}
/* Ni se encoge ni se estira: es un botón, no una columna. El `padding` vuelve
   a ser simétrico porque acá no hay ícono de play que compensar, y el cuerpo
   baja un punto para que a 360 px el rótulo entre en un renglón. */
.cabecera-accion{flex:0 0 auto; margin-top:4px; padding:0 30px;
  font-size:clamp(17px,1.9vw,20px)}
@media (max-width:719px){
  /* Apilada, la acción toma el ancho entero: un renglón solo y todo el pulgar. */
  .cabecera-accion{width:100%; margin-top:0}
}

/* ══════════════════════════════════ BOLETÍN INFORMATIVO ═══════════════════ */
/* El listado reusa `.agenda` y `.evento` enteros: es la misma tarjeta que ya
   usan Eventos y Chismes, y una cuarta variante del mismo rectángulo sería
   cuatro cosas que mantener. Lo que se agrega acá es lo que el boletín tiene y
   ellas no: la tarjeta ENTERA es un enlace, hay un rótulo de empresa, y hay una
   página de artículo. */

/* TODA LA TARJETA ES EL ENLACE, no un «leer más» al pie. Esto se lee en un
   teléfono: el objetivo táctil es el rectángulo, no un renglón de 18 px. El
   `<a>` es `display:block` y ocupa la tarjeta entera, así que el área que
   atiende el dedo es la que se ve — no hace falta ningún ::after estirado. */
.bol-enlace{display:block; color:inherit; text-decoration:none}
.bol-enlace:focus-visible{outline:3px solid var(--amarillo); outline-offset:3px;
  border-radius:24px}
.bol-tarjeta h3{text-decoration:underline; text-decoration-color:rgba(255,241,0,.45);
  text-underline-offset:4px}
.bol-tarjeta:hover h3{text-decoration-color:var(--amarillo)}

/* El rótulo de la empresa. Va ARRIBA del titular y no adentro: es de qué
   empresa habla el boletín, no parte de lo que pasó. */
.bol-empresa,.bol-art-empresa{display:block; font-size:13px; font-weight:700;
  letter-spacing:.16em; text-transform:uppercase; color:var(--amarillo)}

.bol-img{position:relative; margin:0; aspect-ratio:3/2; background:#02265C;
  overflow:hidden}
.bol-img img{width:100%; height:100%; object-fit:cover; display:block}
/* EL RELLENO CUANDO NO HAY FOTO. No es un hueco ni una caja rota: es la marca
   de la emisora, centrada sobre el azul del sitio, sin recortarse. `contain` y
   no `cover` porque un logo recortado se lee como un error de la página; el
   ancho tope evita que en una tarjeta de 1180 px el logo se vea gigante. */
.bol-img-relleno{background:
  radial-gradient(120% 120% at 50% 0%, #0B4FA8 0%, #02265C 70%)}
.bol-img-relleno img{object-fit:contain; width:auto; max-width:min(46%,190px);
  height:auto; max-height:70%; margin:auto; padding:8%; opacity:.9}

/* ── la página del artículo ── */
.bol-art-cab{max-width:74ch}
.bol-art-cab h1{margin:10px 0 0; font-size:clamp(28px,4.4vw,52px); font-weight:800;
  font-style:italic; line-height:1.1}
/* La fecha, la hora y la firma. Es un solo renglón y tiene que poder partirse
   en dos a 320 px sin empujar nada: por eso no es flex con `nowrap`. */
.bol-firma{margin:16px 0 0; font-size:15px; color:var(--halo)}
.bol-firma time{font-variant-numeric:tabular-nums}

.bol-art-cuerpo{max-width:74ch}
.bol-art-cuerpo .bol-img{border-radius:22px; margin-bottom:clamp(20px,2.4vw,30px)}
.bol-bajada{margin:0 0 22px; font-size:clamp(17px,2vw,21px); line-height:1.55;
  color:#E8F3FF; font-weight:500}

/* EL CUERPO. Los selectores son de DESCENDENCIA (`.bol-texto p`) y no clases
   propias, y es a propósito: este HTML lo genera `cuerpo_boletin()` en
   `build.py` a partir de texto plano, y ese conversor emite etiquetas desnudas.
   Ponerle clases obligaría a que las dos mitades se mantengan de acuerdo, que
   es la forma exacta del renombre a medias — sale prolijo y con un estilo menos.
   El conjunto de etiquetas es CERRADO (p, br, strong, em, a, h2, blockquote):
   lo que no está en esa lista no se puede escribir, así que esto no se queda
   corto sin avisar. */
.bol-texto{font-size:17.5px; line-height:1.7; color:#CFE6FF}
.bol-texto p{margin:0 0 1.15em}
.bol-texto strong{color:#fff; font-weight:700}
.bol-texto em{font-style:italic}
.bol-texto h2{margin:1.7em 0 .6em; font-size:clamp(21px,2.6vw,28px); font-weight:700;
  font-style:italic; color:#fff}
.bol-texto blockquote{margin:1.5em 0; padding:2px 0 2px 20px;
  border-left:4px solid var(--amarillo)}
.bol-texto blockquote p{margin:0; font-size:clamp(18px,2.2vw,22px); font-style:italic;
  color:#E8F3FF}
/* 44 px de alto táctil sin agrandar la letra: el `padding` vertical entra en la
   caja del enlace pero el `line-height` del párrafo no se mueve, porque un
   `inline` no empuja el renglón con su relleno. */
.bol-texto a{color:var(--amarillo); font-weight:600;
  text-decoration:underline; text-underline-offset:3px;
  padding:11px 2px; margin:-11px -2px}

.bol-volver{margin:clamp(28px,3.4vw,44px) 0 0}
.bol-volver a{display:inline-block; min-height:44px; line-height:44px;
  padding:0 4px; color:var(--amarillo); font-weight:700}

/* ======================================================= LA PREGUNTA ======
   El bloque de votar de la portada. El marcado lo pinta `site/app.js` con
   `GET /api/pregunta`; `site/build.py` sólo emite el `div` vacío y `hidden`.

   NO HAY UNA REGLA `.pregunta[hidden]` ACÁ. La global del renglón 22 ya lo
   cubre, y `medir-hidden.mjs` lo comprueba con el display calculado. Lo único
   que hay que no hacer es declararle a `.pregunta` un `display` con
   `!important`: ése sí le ganaría, y el bloque se quedaría en pantalla con la
   pregunta de ayer adentro, sin un solo error.

   Y NO TOCA `.hero`. El bloque es HERMANO de la cabecera, no hijo: su alto no
   entra en la caja de `.hero`, así que las cuatro suites de alto de la portada
   siguen midiendo lo que dicen medir. Lo único que aporta hacia arriba es este
   `margin-top`. */
.pregunta{
  width:100%; padding-inline:var(--borde);
  margin:clamp(18px,2.6vw,30px) 0 0;
}
.pregunta-k{
  margin:0 0 6px; font-size:12px; letter-spacing:.16em; text-transform:uppercase;
  font-weight:700; color:var(--amarillo);
}
.pregunta-h{
  margin:0 0 clamp(14px,1.8vw,20px); font-size:clamp(21px,3.2vw,30px);
  line-height:1.25; font-weight:700; color:#fff;
}

/* ---- antes de votar: las opciones ------------------------------------- */
/* Una columna SIEMPRE, también en escritorio. En dos columnas, dos opciones
   quedan a la misma altura y la oyente tiene que leer las cuatro antes de
   decidir cuál toca; en una columna lee en el orden en que el locutor las dijo
   al aire, que es el orden en que las tiene en la cabeza. */
.pregunta-ops{display:flex; flex-direction:column; gap:10px; max-width:640px}
.pregunta-op{
  display:flex; align-items:center; width:100%;
  /* 48 y no 44: son cuatro botones pegados y se tocan con el pulgar mientras
     alguien camina. 44 es el mínimo absoluto, no un objetivo. */
  min-height:48px; padding:10px 18px;
  border:2px solid rgba(179,224,255,.34); border-radius:14px;
  background:var(--rayo); color:#fff;            /* 5,5:1 — pasa AA */
  font-family:inherit; font-size:17px; font-weight:600; text-align:left;
  cursor:pointer; transition:background .14s ease, border-color .14s ease;
}
.pregunta-op:hover{background:#1576d8; border-color:var(--halo)}
.pregunta-op:focus-visible{outline:3px solid var(--amarillo); outline-offset:3px}
.pregunta-op[disabled]{cursor:default; opacity:.62}
/* MANDANDO: se dice con el color Y con el borde, nunca sólo con el color. */
.pregunta-op-mandando{background:var(--hondo); border-color:var(--amarillo); opacity:1}

/* ---- después de votar: el reparto -------------------------------------- */
.pregunta-rep{list-style:none; margin:0; padding:0; max-width:640px}
.pregunta-fila{margin:0 0 12px}
.pregunta-fila-cab{
  display:flex; align-items:baseline; gap:10px; margin:0 0 5px;
}
.pregunta-t{font-weight:600; color:#fff}
.pregunta-p{margin-left:auto; font-size:20px; font-weight:700; color:var(--amarillo)}
.pregunta-n{font-size:14px; color:var(--halo)}
.pregunta-barra{
  display:block; height:12px; border-radius:99px; overflow:hidden;
  background:rgba(255,255,255,.16); margin:0 0 4px;
}
.pregunta-barra-in{
  display:block; height:100%; border-radius:99px; background:var(--amarillo);
  /* El ancho lo pone `app.js` por CSSOM (`.style.width`), igual que la barra
     del programa al aire. No hay un `style=` en el marcado publicado. */
  min-width:0;
}
/* LA CORRECTA, cuando el locutor ya la reveló. Va con un borde a la izquierda
   además del color: quien no distingue el amarillo tiene que poder verla, y
   `app.js` además le pone un texto sólo para lectores de pantalla. */
.pregunta-fila-ok{border-left:4px solid var(--amarillo); padding-left:10px}

/* SIN PORCENTAJE: conteo pelado. No hay barra que esconder acá porque `app.js`
   directamente no la emite; esto sólo le da a la lista el aire de un conteo y
   no el de un reparto a medio dibujar. */
.pregunta-rep-pelada .pregunta-fila{margin:0 0 7px}
.pregunta-rep-pelada .pregunta-n{color:#fff; font-size:16px; margin-left:auto}

.pregunta-nota{
  margin:8px 0 0; font-size:14.5px; line-height:1.5; color:var(--halo);
  max-width:640px;
}
.pregunta-ya{margin:10px 0 0; font-weight:700; color:var(--amarillo)}
.pregunta-estado{margin:10px 0 0; font-size:15px; color:var(--halo); max-width:640px}
.pregunta-estado.mal{color:#FFD7E2; font-weight:600}

@media (max-width:520px){
  .pregunta-op{font-size:16px; padding:10px 14px}
  .pregunta-p{font-size:18px}
}
/* Quien pidió menos movimiento no recibe transiciones. */
@media (prefers-reduced-motion:reduce){
  .pregunta-op{transition:none}
}

/* ================================================= HOY SE HABLA DE ========
   La banda de tendencias de la portada. El marcado lo pinta `site/app.js` con
   lo que hay en `/tendencias.json`; `site/build.py` sólo emite el `div` vacío
   y `hidden` con la zona de la emisora adentro.

   NO HAY UNA REGLA `.tend[hidden]` ACÁ: la global del renglón 22 ya lo cubre.
   Lo único que no se puede hacer es declararle a `.tend` un `display` propio,
   porque le ganaría a `[hidden]` y una banda VENCIDA se quedaría en pantalla.

   Y NO TOCA `.hero`: la banda es hermana de la cabecera, no hija, así que su
   alto no entra en la caja de `.hero` y las cuatro suites de alto de la portada
   siguen midiendo lo mismo. */
.tend{
  /* DE BORDE A BORDE, que es lo que el contrato llama «banda de ancho
     completo». El `--borde` de los lados es la misma sangría que usa todo el
     contenido, así que las píldoras arrancan alineadas con el resto. */
  width:100%; margin:0; padding:clamp(14px,2.2vw,22px) var(--borde);
  background:var(--hondo);
  border-top:1px solid rgba(179,224,255,.18);
  border-bottom:1px solid rgba(179,224,255,.18);
}
/* EL RÓTULO CORTO. Mismo tratamiento que `.pregunta-k` a propósito: las dos
   bandas de la portada se leen como de la misma emisora. */
.tend-k{
  margin:0 0 10px; font-size:13px; letter-spacing:.16em; text-transform:uppercase;
  font-weight:700; color:var(--amarillo);
}
/* LAS PÍLDORAS ENVUELVEN. `wrap` no es una comodidad: es lo único que impide
   que diez términos hagan rodar la portada en horizontal en un teléfono de
   320 px. Sin marquesina, sin `overflow-x:auto` y sin nada que se mueva solo:
   un texto que se desplaza solo no se puede leer despacio. */
.tend-lista{
  list-style:none; margin:0; padding:0;
  display:flex; flex-wrap:wrap; gap:10px;
}
.tend-i{margin:0; min-width:0}
.tend-p{
  display:inline-flex; align-items:center;
  /* Grandes: se leen de lejos y, cuando alguna lleve enlace, se tocan con el
     pulgar. 40 px de alto mínimo. */
  min-height:40px; padding:8px 16px; border-radius:99px;
  /* EL ACENTO DE LA MARCA. #FFF100 sobre #012A62 da 15,9:1. */
  background:var(--amarillo); color:var(--hondo);
  font-weight:700; font-size:clamp(15px,2.2vw,19px); line-height:1.2;
  text-decoration:none;
  /* Un término puede venir de hasta 160 caracteres. Sin estas dos, uno solo
     estira la página entera — pasó en /locutores/ con 9000 px de ancho. */
  max-width:100%; overflow-wrap:anywhere;
}
a.tend-p:hover{background:#fff}
a.tend-p:focus-visible{outline:3px solid #fff; outline-offset:3px}
/* CUÁNDO SE ACTUALIZÓ, en la hora de la emisora. Chico y abajo: es el dato que
   deja saber si esto es de hoy, no el titular. */
.tend-hora{margin:10px 0 0; font-size:13.5px; color:var(--halo)}

@media (max-width:520px){
  .tend{padding-block:12px}
  .tend-k{font-size:12px; margin-bottom:8px}
  .tend-p{font-size:15px; padding:7px 13px; min-height:36px}
  .tend-lista{gap:8px}
}

/* ================================================= ¿VISTE ALGO? CONTALO ===
   El botón de la portada y el alta cuando vive adentro de `#dlg-calle`.
   El marcado lo emite `site/build.py`; `app.js` abre el diálogo. Los colores
   de tipo siguen saliendo de `--c/--t`, no de acá. */
.contalo{
  width:100%; padding-inline:var(--borde);
  margin:clamp(16px,2.4vw,28px) 0 0;
}
.contalo-btn{
  display:inline-flex; align-items:center; justify-content:center;
  min-height:48px; max-width:100%; padding:10px 22px;
  border-radius:999px; background:var(--amarillo); color:var(--hondo);
  font:inherit; font-weight:700; font-size:clamp(16px,2.4vw,20px);
  line-height:1.25; text-decoration:none; text-align:center;
  overflow-wrap:anywhere;
}
.contalo-btn:hover{background:#fff}
.contalo-btn:focus-visible{outline:3px solid #fff; outline-offset:3px}
.contalo-l{
  margin:8px 0 0; font-size:13.5px; color:var(--halo); line-height:1.45;
  max-width:36em; overflow-wrap:anywhere;
}
@media (max-width:520px){
  .contalo-btn{width:100%}
}

/* Adentro del diálogo el alta no lleva su propia caja: la caja es el diálogo.
   La X flota arriba a la derecha, y el título deja el hueco para no taparse. */
#dlg-calle .dlg-escribir-in{position:relative}
#dlg-calle .dlg-escribir-x{position:absolute; top:12px; right:12px; z-index:1}
#dlg-calle .calle-alta{margin:0; background:none; border:0; padding:0; border-radius:0}
#dlg-calle .calle-alta-t{padding-right:52px}

/* ---- mercado ----------------------------------------------------------- */
.mk-dest .mk-dest-ico{display:flex; width:52px; height:52px; margin:0 0 14px;
  align-items:center; justify-content:center; border-radius:16px;
  background:rgba(255,255,255,.12)}
.dest-amarillo .mk-dest-ico{background:rgba(4,48,111,.14); color:#04306F}
.dest-rosa .mk-dest-ico{background:rgba(255,255,255,.18)}
.mk-portada .cta{margin-top:22px}

.mk-barra{display:flex; flex-wrap:wrap; gap:14px 18px;
  justify-content:space-between; align-items:center; margin:0 0 18px}
.mk-cats{display:flex; flex-wrap:wrap; gap:8px}
.mk-cat{min-height:44px; padding:0 16px; border-radius:999px; cursor:pointer;
  border:2px solid rgba(255,255,255,.4); background:none; color:#fff;
  font:inherit; font-weight:700; font-size:15px}
.mk-cat[aria-current="true"]{background:var(--amarillo); color:#04306F; border-color:var(--amarillo)}
.mk-cat:hover{border-color:#fff}
.mk-cat:focus-visible{outline:3px solid var(--amarillo); outline-offset:3px}
.mk-busca{display:flex; flex-wrap:wrap; gap:8px; align-items:center}
.mk-busca input,.mk-busca select{
  min-height:44px; border-radius:12px; border:1px solid rgba(255,255,255,.28);
  background:rgba(1,22,56,.45); color:#fff; font:inherit; padding:0 12px}
.mk-busca input{min-width:min(260px,100%)}
.mk-cuenta{margin:0 0 14px; color:var(--halo); font-weight:700; min-height:1.2em}
.mk-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(260px,1fr));
  gap:clamp(14px,1.8vw,22px)}
.mk-card{margin:0}
.mk-card-in{display:flex; flex-direction:column; align-items:stretch; width:100%;
  text-align:left; cursor:pointer; border:1px solid rgba(255,255,255,.18);
  background:#04306F; color:#fff; border-radius:22px; overflow:hidden; padding:0;
  font:inherit; min-height:280px; transition:transform .18s ease, box-shadow .18s ease}
.mk-card-in:hover{transform:translateY(-5px); box-shadow:0 22px 48px rgba(0,8,36,.45)}
.mk-card-in:focus-visible{outline:4px solid var(--amarillo); outline-offset:4px}
.mk-card-foto{display:block; aspect-ratio:16/10; background:rgba(0,16,48,.55);
  overflow:hidden}
.mk-card-foto img{width:100%; height:100%; object-fit:cover; display:block}
.mk-card-ph{display:block; width:100%; height:100%;
  background:radial-gradient(circle at 30% 20%, rgba(255,241,0,.18), transparent 55%),
             linear-gradient(160deg, #0A4A9C, #01214E)}
.mk-card-cat{margin:12px 16px 0; font-size:12px; font-weight:700; letter-spacing:.14em;
  text-transform:uppercase; color:var(--amarillo)}
.mk-card-precio{margin:6px 16px 0; font-size:clamp(22px,2.4vw,28px); font-weight:800;
  font-style:italic; letter-spacing:-.03em}
.mk-card-tit{margin:6px 16px 0; font-size:18px; font-weight:700; line-height:1.25}
.mk-card-meta{margin:8px 16px 16px; color:#CFE6FF; font-size:14px}

.mk-card-n{position:absolute; right:10px; bottom:10px; z-index:1;
  background:rgba(1,22,56,.82); color:#fff; font-size:12px; font-weight:800;
  padding:4px 8px; border-radius:999px}
.mk-sello{position:absolute; left:10px; top:10px; z-index:1;
  background:var(--amarillo); color:#01214E; font-size:12px; font-weight:800;
  letter-spacing:.08em; text-transform:uppercase; padding:4px 8px; border-radius:999px}
.mk-card-foto{position:relative}
.mk-ficha-sello{margin:0 0 8px; color:var(--amarillo); font-weight:800;
  letter-spacing:.08em; text-transform:uppercase}
.mk-ficha-foto{display:block; width:100%; max-height:320px; object-fit:cover;
  border-radius:16px; margin:0 0 10px}
.mk-ficha-thumbs{display:flex; flex-wrap:wrap; gap:8px; margin:0 0 14px}
.mk-thumb{padding:0; border:2px solid transparent; border-radius:10px;
  overflow:hidden; width:64px; height:64px; cursor:pointer; background:#01214E}
.mk-thumb img{width:100%; height:100%; object-fit:cover; display:block}
.mk-thumb-on{border-color:var(--amarillo)}
.mk-exito{text-align:center; padding:8px 0 4px}
.mk-exito-ok{margin:0 0 8px; font-size:22px; font-weight:800}
.mk-exito-pin-l{margin:0; color:var(--halo); font-size:14.5px}
.mk-exito-pin{margin:8px 0; font-size:clamp(36px,6vw,52px); font-weight:800;
  letter-spacing:.18em; color:var(--amarillo); font-variant-numeric:tabular-nums;
  user-select:all}
.mk-exito-id, .mk-exito-nota{margin:0 0 8px; color:var(--halo)}
.mk-exito .btn-play{margin-top:12px}
.mk-aire{display:flex; flex-wrap:wrap; align-items:center; gap:12px 18px;
  margin:0 0 18px; padding:14px 16px; border-radius:16px;
  background:rgba(1,22,56,.45); border:1px solid rgba(255,241,0,.4)}
.mk-aire p{margin:0; font-size:16px; font-weight:700; color:#fff}
.mk-aire .btn-play{margin:0}
.mk-exito-aire{margin:14px 0 8px; color:var(--halo); font-size:14.5px}
.mk-share{margin:16px 0 4px}
.mk-share-l{margin:0 0 8px; font-size:13px; font-weight:800; letter-spacing:.12em;
  text-transform:uppercase; color:var(--amarillo)}
.mk-share-fila{display:flex; flex-wrap:wrap; gap:8px; justify-content:center}
.mk-ficha .mk-share-fila{justify-content:flex-start}
.mk-share-a{display:inline-flex; align-items:center; min-height:40px; padding:0 14px;
  border-radius:999px; border:1.5px solid rgba(255,255,255,.4); background:transparent;
  color:#fff; font:inherit; font-size:14.5px; font-weight:700; text-decoration:none;
  cursor:pointer}
.mk-share-a:hover{border-color:#fff; background:rgba(255,255,255,.12); color:#fff}
.mk-ficha-precio{margin:0 0 8px; font-size:clamp(28px,4vw,40px); font-weight:800;
  font-style:italic; color:var(--amarillo)}
.mk-ficha-extra{margin:0 0 10px; color:var(--halo); font-weight:700}
.mk-ficha-txt{margin:0 0 12px; white-space:pre-wrap}
.mk-ficha-meta{margin:0 0 16px; color:#CFE6FF}

.mk-extra-fila{display:grid; grid-template-columns:repeat(auto-fit,minmax(120px,1fr)); gap:8px}
.mk-bajar{margin:40px 0 0; padding:22px; border-radius:22px;
  background:rgba(1,22,56,.4); border:1px solid rgba(255,255,255,.16)}
.mk-bajar-fila{display:flex; flex-wrap:wrap; gap:12px; align-items:flex-end; margin-top:12px}
.mk-bajar-fila label{display:flex; flex-direction:column; gap:6px; font-size:13px;
  font-weight:700; color:var(--halo)}
.mk-bajar-fila input, .mk-bajar-fila select{min-height:44px; border-radius:12px;
  border:1px solid rgba(255,255,255,.28); background:rgba(1,22,56,.45); color:#fff;
  font:inherit; padding:0 12px; width:8rem}
.mk-bajar-fila select{width:auto; min-width:11rem}

@media (max-width:800px){
  .mk-barra{flex-direction:column; align-items:stretch}
  .mk-busca{width:100%}
  .mk-busca input{flex:1; min-width:0}
}
.dlg-mercado .dlg-escribir-in{max-height:min(88svh, 820px); overflow:auto}



