/* ==========================================================
   Ulia.Radio — Hero « En direct » (accueil)

   Attribution typographique :
     Pills ............ Clash Display Bold 700
     Artiste .......... Clash Display Bold 700
     Titre morceau .... Clash Display Regular 400
     Boutons .......... Albert Sans Bold 700
     Horaires ......... Clash Display Bold 700, deux tailles

   Clash Display plafonne à 700 : aucune règle ne doit demander
   800 ou 900, le navigateur fabriquerait un faux gras.
   ========================================================== */

/* ==========================================================
   Entrée au chargement

   Cascade : le fond apparaît en premier, puis les blocs de
   contenu montent l'un après l'autre. `both` en fill-mode fait
   respecter l'état initial pendant le délai — sans lui, chaque
   élément clignoterait à pleine opacité avant de démarrer.
   ========================================================== */

@keyframes hero-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes hero-rise {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Le conteneur est animé plutôt que les plans eux-mêmes :
   leur opacité propre est pilotée par is-active, une animation
   dessus entrerait en conflit au changement de morceau. */
.hero-media {
  animation: hero-fade 1.1s ease backwards;
}

/* `backwards` et non `both` : `both` conserve l'état final de
   l'animation en priorité sur la cascade, ce qui neutraliserait
   ensuite la classe .is-out du changement de morceau. Ici l'état
   final coïncide avec l'état naturel, il n'y a donc rien à retenir
   — seul l'état initial doit tenir pendant le délai. */
.live-badge   { animation: hero-rise 0.62s cubic-bezier(0.22, 0.8, 0.3, 1) 0.08s backwards; }
.live-swap    { animation: hero-rise 0.62s cubic-bezier(0.22, 0.8, 0.3, 1) 0.16s backwards; }
.live-actions { animation: hero-rise 0.62s cubic-bezier(0.22, 0.8, 0.3, 1) 0.28s backwards; }
.current-show { animation: hero-rise 0.70s cubic-bezier(0.22, 0.8, 0.3, 1) 0.38s backwards; }

/* ==========================================================
   Structure
   ========================================================== */

.hero {
  /* ---- Réglages du fond ----
     Portées par la section, pas par :root — elles ne concernent
     que le hero et n'ont rien à faire dans l'espace global.

     Ces valeurs arbitrent entre lisibilité du texte et présence
     du média. La vidéo est volontairement moins floutée et plus
     opaque que la pochette : un clip traité comme une pochette
     deviendrait une bouillie grise.

     Le voile (.hero-overlay, deux dégradés superposés) reste dense en
     bas — c'est lui qui raccorde le hero au gris de la page. L'alléger
     ferait apparaître une coupure nette au bas de la section. */
  --hero-cover-opacity: 0.55;
  --hero-cover-blur:    18px;
  --hero-video-opacity: 0.82;
  --hero-video-blur:    6px;

  /* Agrandissement de l'iframe, pour évacuer l'habillage YouTube
     hors du cadre visible. Voir .hero-video iframe. */
  --hero-video-crop:    1.6;

  position: relative;
  width: 100%;
  min-height: 100vh;
  display: flex;
  align-items: center;
  overflow: hidden;
  /* Haut légèrement réduit par rapport au bas : rapproche .hero-container
     du haut du site. Côtés alignés sur --u-gutter (header, sections) —
     un padding propre au hero créait un grand vide sur les côtés,
     .hero-container semblant ne pas aller aussi loin que le header. */
  padding: clamp(28px, 4vw, 70px) var(--u-gutter) clamp(40px, 6vw, 100px);
}

.hero-media {
  position: absolute;
  inset: 0;
  z-index: var(--z-hero-media);
  overflow: hidden;
}

/* ---------- Pochette ----------
   Deux plans superposés permettent le fondu croisé : le nouveau
   monte en opacité pendant que l'ancien descend, sans passage
   par un fond vide.

   L'inset négatif compense le flou : sans lui, les bords adoucis
   laisseraient apparaître le fond de page sur le pourtour. */

.hero-bg {
  position: absolute;
  inset: -60px;
  /* Repli si l'image de fond (pochette ou ULIA_COVER_FALLBACK) est
     absente/en échec de chargement : le hero garde une base de
     marque au lieu de laisser transparaître le gris de page. */
  background-color: var(--u-blue-deep);
  background-position: center;
  background-size: cover;
  filter: blur(var(--hero-cover-blur));
  transform: scale(1.08);
  opacity: 0;
  transition: opacity 0.9s ease;
  will-change: opacity;
}

.hero-bg.is-active { opacity: var(--hero-cover-opacity); }

/* ---------- Fichier vidéo hébergé ----------
   Pas d'habillage à masquer ici : la balise native n'affiche rien
   sans attribut controls. Le recadrage reste donc à 1, on ne perd
   aucun bord de l'image. */

.hero-file {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100vw;
  height: 56.25vw;
  min-width: 177.78vh;
  min-height: 100vh;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.1s ease;
  pointer-events: none;
  filter: blur(var(--hero-video-blur));
  will-change: opacity;
}

.hero-file.is-active { opacity: var(--hero-video-opacity); }

/* ---------- Clip YouTube ----------
   Recouvre la pochette quand un youtube_id est disponible.
   pointer-events: none — aucune interaction n'est possible avec
   le lecteur, y compris le clic droit sur l'iframe. */

.hero-video {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1.1s ease;
  pointer-events: none;
  filter: blur(var(--hero-video-blur));
  transform: scale(1.12);
  will-change: opacity;
}

.hero-video.is-active { opacity: var(--hero-video-opacity); }

/* L'habillage YouTube — titre et logo en haut, barre et écran de
   fin en bas — vit sur les bords de l'iframe. Aucun paramètre ne
   permet de le supprimer de façon fiable (modestbranding est
   déprécié depuis 2023). On agrandit donc l'iframe au-delà du
   conteneur : les bords, et l'interface avec, sortent du cadre.

   1.6 rogne environ 19 % en haut et en bas. Descendre sous 1.4
   laisse réapparaître le titre sur les écrans larges. */
.hero-video iframe {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: calc(100vw * var(--hero-video-crop));
  height: calc(56.25vw * var(--hero-video-crop));
  min-width: calc(177.78vh * var(--hero-video-crop));
  min-height: calc(100vh * var(--hero-video-crop));
  border: 0;
  pointer-events: none;
}

/* Deux voiles superposés : le second (listé en premier, donc au-dessus)
   est un dégradé vertical monochrome qui raccorde le hero au gris de la
   page ; le premier (listé en second, donc en dessous) est un dégradé
   diagonal qui apporte la variation de teinte/opacité. */
.hero-overlay {
  position: absolute;
  inset: 0;
  z-index: var(--z-hero-veil);
  background:
    linear-gradient(
      to top,
      rgba(241, 241, 241, 1.00) 0%,
      rgba(241, 241, 241, 0.92) 30%,
      rgba(241, 241, 241, 0.47) 64%,
      rgba(241, 241, 241, 0.70) 100%
    ),
    linear-gradient(
      to top right,
      rgba(241, 241, 241, 0.40) 0%,
      rgba(218, 218, 218, 0.74) 30%,
      rgba(205, 205, 205, 0.29) 64%,
      rgba(196, 196, 196, 0.40) 100%
    );
}

.hero-container {
  position: relative;
  z-index: var(--z-hero-body);
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(400px, 560px);
  align-items: center;
}

/* ==========================================================
   Colonne gauche
   ========================================================== */

/* min-width: 0 est requis pour l'ellipse : sans lui, un élément
   de grille refuse de rétrécir sous la largeur de son contenu et
   le texte déborde au lieu d'être tronqué. */
.live-content { min-width: 0; }

.live-badge {
  display: inline-flex;
  align-items: center;
  background: linear-gradient(135deg, var(--u-blue-deep), var(--u-blue-lite));
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 12px;
  line-height: 1;
  text-transform: uppercase;
  padding: 9px 12px;
  border-radius: 9px;
  margin-bottom: 12px;
  box-shadow: 0 4px 16px rgba(0, 89, 235, 0.15);
}

/* Bloc animé au changement de morceau. La durée doit rester
   alignée sur SWAP_OUT dans now-playing.js. */
.live-swap {
  transition: opacity 0.34s ease, transform 0.34s ease, filter 0.34s ease;
  will-change: opacity, transform;
}

.live-swap.is-out {
  opacity: 0;
  transform: translateY(14px);
  filter: blur(4px);
}

.live-artist {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(38px, 4vw, 62px);
  line-height: 0.98;
  /* En em plutôt qu'en px : un crénage de -3px correct à 62px
     écrase les lettres à 38px. */
  background: linear-gradient(to top right, #0080FF 0%, #072DC5 28%, #017CFC 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;

  /* Une seule ligne, tronquée par un fondu (pas une ellipse) : le texte
     dégradé se termine en douceur plutôt que sur "…".
     Le padding vertical est indispensable : avec line-height à
     0.98, le pavé de texte est plus court que les glyphes, et
     overflow: hidden rognerait les jambages (le J de « J Balvin »).
     La marge négative annule l'effet du padding sur la mise en page. */
  white-space: nowrap;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 48px), transparent 100%);
  mask-image: linear-gradient(to right, #000 calc(100% - 48px), transparent 100%);
  padding-top: 0.1em;
  padding-bottom: 0.14em;
  margin-top: -0.1em;
  margin-bottom: -0.14em;
}

.live-track {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(23px, 2.3vw, 34px);
  line-height: 1.15;
  background: linear-gradient(to top right, #0080FF 0%, #072DC5 28%, #017CFC 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;

  /* Même traitement que l'artiste (fondu plutôt qu'ellipse). La
     line-height est ici plus confortable (1.15), le padding de
     sécurité reste faible. */
  white-space: nowrap;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent 100%);
  mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent 100%);
  padding-bottom: 0.08em;
  margin-top: 2px;
  margin-bottom: -0.08em;
}

/* ---------- Boutons ---------- */

.live-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 36px;
}

.action-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  min-height: 42px;
  padding: 0 17px;
  border: 0;
  border-radius: 999px;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 14px;
  color: var(--u-blue);
  background: rgba(255, 255, 255, 0.87);
  text-decoration: none;
  cursor: pointer;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.025);
  transition: transform 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}

.action-button--secondary { background: rgba(225, 228, 234, 0.60); }

.action-button:hover {
  transform: translateY(-2px);
  background: #fff;
  box-shadow: 0 10px 25px rgba(0, 65, 170, 0.10);
}

.action-button:focus-visible {
  outline: 3px solid var(--u-blue-deep);
  outline-offset: 3px;
}

.action-button i {
  font-size: 14px;
  flex: 0 0 auto;
}

/* ==========================================================
   Colonne droite
   ========================================================== */

.current-show {
  position: relative;
  width: 80%;
  height: 140px;
  /* Cellule de grille toujours pleine largeur (minmax(400px, 560px)) :
     la carte, plus étroite, se colle donc à droite au lieu de rester
     collée à gauche par défaut. Sans effet en layout flex (mobile, voir
     plus bas où align-self prend le relais). */
  justify-self: end;
  border-radius: 16px;
  /* --show-accent : première couleur du thème de l'émission en cours,
     posée en inline-style par index.php (repli sur la teinte de marque
     si l'émission n'a pas de couleur définie). */
  background: linear-gradient(to top right,
    color-mix(in srgb, var(--show-accent, var(--u-blue-deep)) 60%, transparent) 0%,
    color-mix(in srgb, var(--show-accent, var(--u-blue-deep)) 10%, transparent) 100%);
  /* Dégradé partiellement transparent : floute ce qui se devine derrière
     (fond du hero) plutôt que de laisser un aperçu net et brouillon.
     backdrop-filter plutôt que filter : pas de débordement à gérer malgré
     overflow: visible ci-dessous (contrairement à un filter classique). */
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
  /* visible : la photo de l'animateur dépasse la carte. */
  overflow: visible;
  box-shadow: 0 20px 50px rgba(57, 75, 100, 0.05);
  text-decoration: none;
}

.current-show {
  transition: transform .24s cubic-bezier(.2, .7, .2, 1), box-shadow .24s ease;
}
@media (hover: hover) and (pointer: fine) {
  .current-show:hover {
    transform: translateY(-4px);
    box-shadow: 0 24px 54px rgba(57, 75, 100, .14);
  }
}
a.current-show:focus-visible {
  transform: translateY(-4px);
  box-shadow: 0 24px 54px rgba(57, 75, 100, .14);
}
@media (prefers-reduced-motion: reduce) {
  .current-show { transition: none; }
  .current-show:hover, a.current-show:focus-visible { transform: none; }
}

a.current-show:focus-visible {
  outline: 3px solid var(--u-blue-deep);
  outline-offset: 4px;
}

.current-badge {
  position: absolute;
  top: -11px;
  left: 25px;
  z-index: 5;
  display: inline-flex;
  align-items: center;
  height: 24px;
  padding: 0 9px;
  border-radius: 7px;
  background: var(--show-accent, #343b48);
  /* --show-on-accent : basculé sur une teinte sombre par
     ulia_show_accent_style() (includes/api.php) quand --show-accent est une
     couleur claire (jaune, gris clair...) sur laquelle du blanc se lit mal. */
  color: var(--show-on-accent, #fff);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 10px;
  text-transform: uppercase;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.current-content {
  position: relative;
  z-index: 2;
  height: 100%;
  display: flex;
  align-items: center;
  /* La réserve à droite empêche le logo de passer sous la photo. */
  padding: 23px 131px 18px 29px;
}

/* ---------- Horaires ---------- */

.show-time {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 1px;
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--show-on-accent, #fff);
  line-height: 0.9;
}

.show-time__slot {
  display: flex;
  align-items: baseline;
}

/* Deux tailles : chiffres dominants, unité en retrait.
   tabular-nums fige la largeur — sinon la colonne bouge entre
   « 11H » et « 21H » au changement d'émission. */
.show-time__num {
  font-size: 31px;
  font-variant-numeric: tabular-nums;
}

.show-time__unit {
  font-size: 22px;
  margin-left: 1px;
}

.show-divider {
  flex: 0 0 2px;
  width: 2px;
  height: 56px;
  background: color-mix(in srgb, var(--show-on-accent, #fff) 15%, transparent);
  margin: 0 21px;
}

/* ---------- Logo ---------- */

/* brightness(0) invert(1) force n'importe quel logo en blanc plein, quelle
   que soit sa couleur d'origine (suppose un PNG détouré). --show-logo-invert
   passe à 0 sur fond clair (ulia_show_accent_style()) : brightness(0) seul
   donne alors un logo noir plein plutôt que blanc invisible. */
.show-logo {
  max-width: 123px;
  max-height: 70px;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: brightness(0) invert(var(--show-logo-invert, 1));
  opacity: 0.98;
}

/* Repli si aucun logo n'est fourni. */
.show-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 20px;
  line-height: 1.1;
  color: var(--show-on-accent, #fff);
}

/* ---------- Photo animateur ---------- */

.host-image {
  position: absolute;
  z-index: 4;
  right: 0px;
  bottom: 0;
  height: 160px;
  max-width: 156px;
  object-fit: contain;
  object-position: bottom right;
  pointer-events: none;
  border-radius: 0px 0px 16px 0px;
}

/* ==========================================================
   Adaptations
   ========================================================== */

@media (max-width: 950px) {
  .hero {
    min-height: 100svh;
    padding: 76px var(--u-gutter) 70px;
  }
  .hero-container {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 80px;
  }
  .live-content { max-width: 620px; }
  .current-show {
    /* Pleine largeur, comme le reste du contenu (.live-content) — plus de
       plafond à 600px/80% qui le laissait plus étroit que le reste de la
       page sur mobile. */
    width: 100%;
    max-width: none;
    align-self: stretch;
  }
}

@media (max-width: 600px) {
  .hero { padding: 52px var(--u-gutter) 50px; }
  .hero-container { gap: 60px; }

  .live-artist { font-size: 39px; }
  .live-track  { font-size: 24px; }
  .live-actions { margin-top: 26px; }

  .current-show { height: 127px; }
  .current-content { padding: 22px 98px 16px 18px; }

  .show-time__num  { font-size: 23px; }
  .show-time__unit { font-size: 16px; }
  .show-divider { margin: 0 13px; }

  .show-logo { max-width: 90px; max-height: 57px; }
  .show-name { font-size: 16px; }

  .host-image {
    right: 0px;
    height: 143px;
    max-width: 119px;
  }

  .current-badge { left: 16px; }
}

/* Une vidéo en lecture automatique est un déclencheur vestibulaire
   connu : on la supprime et on reste sur la pochette. Le script
   applique la même règle et ne charge même pas l'API YouTube. */
@media (prefers-reduced-motion: reduce) {
  .action-button { transition: none; }
  .action-button:hover { transform: none; }

  .hero-bg,
  .live-swap { transition: none; }

  .hero-video,
  .hero-file { display: none; }

  /* Les entrées sont supprimées, pas raccourcies : une animation
     de 10 ms reste une animation. */
  .hero-media,
  .live-badge,
  .live-swap,
  .live-actions,
  .current-show { animation: none; }
}