/* ==========================================================================
   JUSTAI NEWS — habillage d'antenne
   Grammaire visuelle des chaînes d'info françaises (bandeau titre, bandeau
   déroulant, pastille de rubrique, horloge, mention « EN DIRECT »), déclinée
   dans la charte de justai.fr.

   Tout est composé dans une scène fixe de 1920 × 1080, mise à l'échelle par
   transformation. C'est ainsi que travaillent les régies : la maquette est
   dessinée une fois en pixels réels, puis adaptée à n'importe quel écran sans
   qu'aucune proportion ne bouge.
   ========================================================================== */

@import url('/static/fonts.css');

:root {
  /* Charte justai.fr */
  --ink:            #1a1d44;
  --ink-light:      #2a2d54;
  --ink-deep:       #343764;
  --blue:           #229bdd;
  --blue-dark:      #006493;
  --gold:           #ffc940;
  --gold-dark:      #d4922a;
  --creme:          #faf7f2;
  --creme-dark:     #f5f0e8;
  --muted:          #6b6358;
  --urgent:         #d92b2b;

  --font: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* Marges de sécurité titre : 5 % du cadre, comme en diffusion. */
  --safe-x: 64px;
  --safe-y: 44px;

  --ticker-h: 72px;
  --strip-h: 108px;
  --sub-h: 56px;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  height: 100%;
  background: #0b0d22;
  color: var(--creme);
  font-family: var(--font);
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

/* --------------------------------------------------------------- la scène -- */
#viewport {
  position: fixed;
  inset: 0;
  overflow: hidden;
  background: #000;
}

#stage {
  position: absolute;
  width: 1920px;
  height: 1080px;
  overflow: hidden;
  background: var(--ink);
  /* L'échelle et la position sont posées par le script : la boîte de mise en
     page conserve ses 1920 × 1080, que la transformation ne modifie pas. */
}

/* ------------------------------------------------------------- le fond ----- */
.backdrop {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: var(--ink);
}

.backdrop__layer {
  position: absolute;
  inset: -4%;
  background-size: cover;
  background-position: center;
  opacity: 0;
  transition: opacity 700ms ease;
  will-change: transform, opacity;
}
.backdrop__layer.is-live { opacity: 1; }

/* Le lent mouvement d'appareil sur une image fixe : sans lui, une photo
   affichée quarante secondes fige toute l'antenne. */
@keyframes kenburns {
  from { transform: scale(1.04) translate3d(0, 0, 0); }
  to   { transform: scale(1.16) translate3d(-1.4%, -1.2%, 0); }
}
.backdrop__layer.is-live { animation: kenburns 46s ease-out forwards; }
/* Le calque qui s'efface conserve sa transformation le temps du fondu :
   sans cela l'image sortante saute à sa position initiale en plein
   enchaînement, ce qui se voit immédiatement. */
.backdrop__layer:not(.is-live) { animation-play-state: paused; }

/* Fonds de repli, dans la charte, quand aucune image n'est disponible. */
.backdrop__layer[data-palette="ink"]  { background-image: radial-gradient(120% 90% at 22% 18%, #343764 0%, #1a1d44 55%, #12142f 100%); }
.backdrop__layer[data-palette="blue"] { background-image: radial-gradient(120% 90% at 78% 22%, #229bdd 0%, #006493 45%, #10233c 100%); }
.backdrop__layer[data-palette="gold"] { background-image: radial-gradient(120% 90% at 30% 80%, #d4922a 0%, #2a2d54 55%, #1a1d44 100%); }
.backdrop__layer[data-palette="deep"] { background-image: radial-gradient(120% 90% at 60% 40%, #2a2d54 0%, #1a1d44 50%, #0b0d22 100%); }

/* Quand aucune photo n'est disponible, le fond ne doit pas rester vide :
   on pose le nom de la rubrique en très grand, fantomatique, comme le font
   les plateaux virtuels. L'écran reste habité. */
.backdrop__motif {
  position: absolute; inset: 0; pointer-events: none;
  display: grid; place-items: center;
  opacity: 0; transition: opacity 600ms ease;
}
.backdrop__motif.is-live { opacity: 1; }
.backdrop__motif span {
  font-size: 300px; font-weight: 800; letter-spacing: -8px;
  line-height: .9; text-transform: uppercase; white-space: nowrap;
  color: transparent;
  -webkit-text-stroke: 2px rgba(250,247,242,.085);
  transform: translateY(-40px);
}
.backdrop__motif::before {
  content: ''; position: absolute;
  width: 1100px; height: 1100px; border-radius: 50%;
  border: 1px solid rgba(34,155,221,.16);
  box-shadow: 0 0 0 190px rgba(34,155,221,.05) inset,
              0 0 140px rgba(34,155,221,.10);
  transform: translate(-8%, -14%);
}

/* Trame fine : casse l'aplat et donne du grain, comme une vraie image. */
.backdrop__grid {
  position: absolute; inset: 0; pointer-events: none; opacity: .16;
  background-image:
    linear-gradient(rgba(255,255,255,.09) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.09) 1px, transparent 1px);
  background-size: 96px 96px;
  mask-image: radial-gradient(90% 70% at 50% 40%, #000 30%, transparent 100%);
}

/* Assombrissement bas et gauche : sans lui, le bandeau blanc sur photo claire
   devient illisible. C'est la première chose que fait une régie. */
.backdrop__scrim {
  position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(to top, rgba(11,13,34,.96) 0%, rgba(11,13,34,.74) 22%, rgba(11,13,34,0) 46%),
    linear-gradient(to right, rgba(11,13,34,.72) 0%, rgba(11,13,34,.12) 38%, rgba(11,13,34,0) 62%),
    linear-gradient(to bottom, rgba(11,13,34,.66) 0%, rgba(11,13,34,0) 24%);
}

/* --------------------------------------------------------- barre du haut --- */
.topbar {
  position: absolute;
  top: var(--safe-y); left: var(--safe-x); right: var(--safe-x);
  display: flex; align-items: flex-start; justify-content: space-between;
  z-index: 30;
}

.brand { display: flex; align-items: center; gap: 16px; }

.brand__mark {
  width: 62px; height: 62px; border-radius: 15px;
  background: linear-gradient(145deg, var(--blue) 0%, var(--blue-dark) 100%);
  display: grid; place-items: center;
  box-shadow: 0 10px 30px rgba(0,0,0,.45), inset 0 1px 0 rgba(255,255,255,.28);
  position: relative; overflow: hidden;
}
.brand__mark::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(160deg, rgba(255,255,255,.32), transparent 55%);
}
/* Le tracé passe au-dessus du reflet de la tuile, sinon il serait délavé. */
.brand__logo {
  position: relative; z-index: 1;
  /* Le point du « i » flotte seul en haut du tracé : centrer la boîte
     géométriquement fait descendre les lettres. On remonte de trois pixels
     pour que ce soit la masse des lettres qui soit centrée, pas le vide. */
  height: 40px; width: auto; margin-top: -3px;
  fill: #fff;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.35));
}
/* Les deux points en or : c'est l'accent de la chaîne, déjà porté par
   « NEWS » juste à côté. */
.brand__logo-dot { fill: var(--gold); }

.brand__text { display: flex; flex-direction: column; gap: 3px; }
.brand__name {
  font-size: 31px; font-weight: 800; letter-spacing: 1.4px; line-height: 1;
  text-shadow: 0 2px 12px rgba(0,0,0,.6);
}
.brand__name em { font-style: normal; color: var(--gold); }
.brand__tag {
  font-size: 13px; font-weight: 600; letter-spacing: 2.6px;
  color: rgba(250,247,242,.72); text-transform: uppercase;
}
/* Discrète mais permanente, comme une mention légale d'antenne. */
.brand__auto {
  margin-top: 3px;
  font-size: 11px; font-weight: 600; letter-spacing: 1.4px;
  color: rgba(250,247,242,.42); text-transform: uppercase;
}

.status { display: flex; align-items: center; gap: 14px; }

.live {
  display: inline-flex; align-items: center; gap: 9px;
  background: var(--urgent); color: #fff;
  padding: 9px 16px 9px 13px; border-radius: 6px;
  font-size: 17px; font-weight: 800; letter-spacing: 1.6px;
  box-shadow: 0 8px 24px rgba(217,43,43,.45);
}
.live__dot {
  width: 11px; height: 11px; border-radius: 50%; background: #fff;
  animation: livepulse 1.9s ease-in-out infinite;
}
@keyframes livepulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: .35; transform: scale(.82); }
}

.clock {
  text-align: right; display: flex; flex-direction: column; align-items: flex-end;
  gap: 2px;
  background: rgba(11,13,34,.55);
  border: 1px solid rgba(250,247,242,.14);
  border-radius: 10px; padding: 8px 16px;
  backdrop-filter: blur(6px);
}
.clock__time {
  font-size: 33px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums; letter-spacing: .5px;
}
.clock__date {
  font-size: 12.5px; font-weight: 600; letter-spacing: 1.5px;
  color: rgba(250,247,242,.68); text-transform: uppercase;
}

/* ------------------------------------------------- colonne « à suivre » ---- */
.upnext {
  position: absolute;
  right: var(--safe-x); top: 168px; width: 392px;
  z-index: 25;
  background: linear-gradient(180deg, rgba(26,29,68,.90) 0%, rgba(26,29,68,.72) 100%);
  border: 1px solid rgba(250,247,242,.13);
  border-radius: 14px; overflow: hidden;
  backdrop-filter: blur(9px);
  box-shadow: 0 20px 50px rgba(0,0,0,.42);
}
.upnext__head {
  background: rgba(34,155,221,.20);
  border-bottom: 1px solid rgba(250,247,242,.13);
  padding: 12px 18px;
  font-size: 14px; font-weight: 800; letter-spacing: 2.4px;
  color: var(--gold); text-transform: uppercase;
}
.upnext__list { list-style: none; padding: 8px 0; }
.upnext__item {
  display: flex; gap: 12px; padding: 10px 18px;
  text-transform: uppercase;
  font-size: 17.5px; font-weight: 600; line-height: 1.28;
  color: rgba(250,247,242,.90);
  border-left: 3px solid transparent;
}
.upnext__item span {
  color: var(--blue); font-weight: 800; font-variant-numeric: tabular-nums;
  min-width: 22px;
}
.upnext__item.is-current {
  border-left-color: var(--gold);
  background: rgba(255,201,64,.10);
  color: #fff;
}

/* --------------------------------------------------------- bloc central ---- */
.slate {
  position: absolute;
  left: var(--safe-x);
  bottom: calc(var(--ticker-h) + var(--strip-h) + var(--sub-h) + 42px);
  width: 1020px;
  z-index: 20;
}

.slate__bullets { list-style: none; display: flex; flex-direction: column; gap: 12px; }
.slate__bullets li {
  display: flex; align-items: flex-start; gap: 14px;
  font-size: 27px; font-weight: 600; line-height: 1.3;
  color: rgba(250,247,242,.95);
  text-shadow: 0 2px 14px rgba(0,0,0,.75);
  opacity: 0; transform: translateY(14px);
  animation: bulletin 520ms cubic-bezier(.22,.9,.28,1) forwards;
}
.slate__bullets li:nth-child(1) { animation-delay: 260ms; }
.slate__bullets li:nth-child(2) { animation-delay: 460ms; }
.slate__bullets li:nth-child(3) { animation-delay: 660ms; }
.slate__bullets li:nth-child(4) { animation-delay: 860ms; }
.slate__bullets li:nth-child(5) { animation-delay: 1060ms; }
.slate__bullets li:nth-child(6) { animation-delay: 1260ms; }
.slate__bullets li::before {
  content: ''; flex: none; width: 10px; height: 10px; margin-top: 11px;
  background: var(--gold); transform: rotate(45deg);
  box-shadow: 0 0 14px rgba(255,201,64,.75);
}
@keyframes bulletin {
  to { opacity: 1; transform: translateY(0); }
}

/* Les titres de l'ouverture : plus gros, plus aérés. */
.slate.is-opening { width: 1280px; bottom: calc(var(--ticker-h) + var(--strip-h) + var(--sub-h) + 78px); }
.slate.is-opening .slate__bullets li { font-size: 34px; font-weight: 700; }

/* ------------------------------------------------------------ le bandeau --- */
.lower { position: absolute; left: 0; right: 0; bottom: var(--ticker-h); z-index: 28; }

.strip {
  display: flex; align-items: stretch; height: var(--strip-h);
  box-shadow: 0 -6px 26px rgba(0,0,0,.42);
}

/* La coupe en biais est une signature graphique des bandeaux d'info. Elle est
   découpée dans la boîte elle-même, et non ajoutée en pseudo-élément : un
   pseudo-élément aurait beau hériter du dégradé, il le repeindrait depuis son
   propre coin, donc à sa propre échelle — le dégradé recommencerait au jaune
   clair juste avant la pointe et laisserait une marche visible. Une seule
   boîte, un seul dégradé, aucun raccord. */
.strip__kicker {
  flex: none; display: flex; align-items: center; gap: 0;
  padding: 0 34px 0 var(--safe-x);
  margin-right: -21px;
  background: linear-gradient(135deg, var(--gold) 0%, var(--gold-dark) 100%);
  clip-path: polygon(0 0, 100% 0, calc(100% - 21px) 100%, 0 100%);
  color: var(--ink);
  font-size: 29px; font-weight: 800; letter-spacing: 2.2px;
  text-transform: uppercase;
  /* Au-dessus du titre, sur lequel la pointe mord. */
  position: relative; z-index: 1;
}

.strip__title {
  flex: 1; display: flex; align-items: center;
  padding: 0 var(--safe-x) 0 63px;
  background: linear-gradient(90deg, var(--ink) 0%, var(--ink-light) 100%);
  font-size: 62px; font-weight: 800; line-height: 1.02;
  letter-spacing: -1px; text-transform: uppercase;
  color: #fff;
  overflow: hidden;
}
.strip__title span {
  display: block; width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  /* Le corps est réduit par le script quand le titre déborde : c'est le
     comportement des générateurs de bandeaux, qui ne coupent jamais un titre.
     Aucune transition ici : le script mesure juste après avoir posé la taille,
     et une animation en cours lui renverrait une largeur périmée. */
}

.subline {
  display: flex; align-items: center; height: var(--sub-h);
  padding: 0 var(--safe-x);
  background: linear-gradient(90deg, var(--blue-dark) 0%, var(--blue) 100%);
  color: #fff;
  font-size: 27px; font-weight: 600; letter-spacing: .2px;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.subline__credit {
  margin-left: auto; padding-left: 28px;
  font-size: 14.5px; font-weight: 600; letter-spacing: 1.4px;
  color: rgba(255,255,255,.78); text-transform: uppercase;
  white-space: nowrap;
}

/* Le mode urgent : rouge, et le bandeau bat. */
.lower.is-urgent .strip__kicker {
  background: #fff;
  color: var(--urgent);
  animation: urgentflash 1.15s steps(1) infinite;
}
@keyframes urgentflash {
  0%, 55%  { filter: brightness(1); }
  56%,100% { filter: brightness(1.42); }
}
.lower.is-urgent .strip__title {
  background: linear-gradient(90deg, #4a1111 0%, #7a1c1c 100%);
}

/* Transition du bandeau à chaque changement de sujet. */
.lower.is-swapping .strip, .lower.is-swapping .subline {
  animation: stripswap 460ms cubic-bezier(.4,0,.2,1);
}
@keyframes stripswap {
  0%   { transform: translateX(0); opacity: 1; }
  42%  { transform: translateX(-38px); opacity: 0; }
  43%  { transform: translateX(38px); opacity: 0; }
  100% { transform: translateX(0); opacity: 1; }
}

/* --------------------------------------------------- bandeau déroulant ----- */
.ticker {
  position: absolute; left: 0; right: 0; bottom: 0; height: var(--ticker-h);
  display: flex; align-items: stretch; z-index: 29;
  background: #10122c;
  border-top: 2px solid rgba(34,155,221,.55);
}

.ticker__label {
  flex: none; display: flex; align-items: center;
  padding: 0 26px 0 var(--safe-x);
  background: linear-gradient(135deg, var(--blue) 0%, var(--blue-dark) 100%);
  font-size: 22px; font-weight: 800; letter-spacing: 2.2px;
  text-transform: uppercase; color: #fff;
  position: relative; z-index: 2;
  box-shadow: 6px 0 18px rgba(0,0,0,.55);
}

.ticker__viewport { flex: 1; overflow: hidden; position: relative; }

/* Défilement continu : deux copies du contenu se suivent, et la piste
   translate de exactement la largeur d'une copie. Le raccord est alors
   invisible et la boucle ne « saute » jamais. */
.ticker__track {
  display: flex; align-items: center; height: 100%;
  width: max-content;
  will-change: transform;
  animation: tickerscroll linear infinite;
}
@keyframes tickerscroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
.ticker__run { display: flex; align-items: center; height: 100%; }
.ticker__item {
  display: flex; align-items: center; gap: 24px;
  text-transform: uppercase;
  padding: 0 26px; height: 100%;
  font-size: 30px; font-weight: 600; letter-spacing: .3px;
  color: rgba(250,247,242,.94); white-space: nowrap;
}
.ticker__item::after {
  content: ''; width: 9px; height: 9px; background: var(--gold);
  transform: rotate(45deg); flex: none;
}

/* ------------------------------------------------ progression du sujet ----- */
.progress {
  position: absolute; left: 0; bottom: calc(var(--ticker-h) + var(--strip-h) + var(--sub-h));
  height: 4px; background: var(--gold); z-index: 30;
  box-shadow: 0 0 14px rgba(255,201,64,.85);
  transition: width 260ms linear;
}

/* ------------------------------------------------------------ le portail --- */
/* Les navigateurs interdisent le son sans geste de l'internaute : on assume
   l'entrée en direct comme un élément d'habillage plutôt que comme une gêne. */
.gate {
  position: absolute; inset: 0; z-index: 60;
  display: grid; place-items: center;
  background: radial-gradient(90% 80% at 50% 40%, rgba(26,29,68,.90), rgba(11,13,34,.97));
  backdrop-filter: blur(4px);
  transition: opacity 420ms ease, visibility 420ms;
}
.gate.is-hidden { opacity: 0; visibility: hidden; pointer-events: none; }
.gate__inner { text-align: center; max-width: 900px; padding: 0 40px; }
.gate__title {
  font-size: 74px; font-weight: 800; letter-spacing: 2px; margin-bottom: 14px;
}
.gate__title em { font-style: normal; color: var(--gold); }
.gate__sub {
  font-size: 25px; font-weight: 500; color: rgba(250,247,242,.76);
  margin-bottom: 44px; line-height: 1.45;
}
.gate__btn {
  font-family: var(--font);
  display: inline-flex; align-items: center; gap: 16px;
  padding: 22px 52px; border: 0; border-radius: 10px; cursor: pointer;
  background: linear-gradient(135deg, var(--gold) 0%, var(--gold-dark) 100%);
  color: var(--ink); font-size: 28px; font-weight: 800; letter-spacing: 2px;
  text-transform: uppercase;
  box-shadow: 0 16px 44px rgba(255,201,64,.34);
  transition: transform 180ms ease, box-shadow 180ms ease;
}
.gate__btn:hover { transform: translateY(-2px); box-shadow: 0 22px 54px rgba(255,201,64,.44); }
.gate__btn::before {
  content: ''; width: 0; height: 0; flex: none;
  border-left: 20px solid var(--ink);
  border-top: 12px solid transparent; border-bottom: 12px solid transparent;
}
.gate__note { margin-top: 26px; font-size: 15px; color: rgba(250,247,242,.5); letter-spacing: 1.2px; }

/* --------------------------------------------------------- l'attente ------- */
.standby {
  position: absolute; inset: 0; z-index: 55;
  display: grid; place-items: center; text-align: center;
  background: radial-gradient(90% 80% at 50% 45%, #2a2d54, #0b0d22);
}
.standby.is-hidden { display: none; }
.standby__title { font-size: 46px; font-weight: 800; letter-spacing: 3px; margin-bottom: 16px; }
.standby__sub { font-size: 21px; color: rgba(250,247,242,.66); }
.standby__bar {
  margin: 38px auto 0; width: 320px; height: 4px; border-radius: 2px;
  background: rgba(250,247,242,.14); overflow: hidden;
}
.standby__bar i {
  display: block; width: 38%; height: 100%; background: var(--gold);
  animation: standbyslide 1.5s ease-in-out infinite;
}
@keyframes standbyslide {
  0%   { transform: translateX(-110%); }
  100% { transform: translateX(370%); }
}

/* ---------------------------------------------------------- commandes ------ */
.controls {
  position: absolute; top: 0; right: 0; z-index: 70;
  display: flex; gap: 8px; padding: 10px;
  opacity: 0; visibility: hidden;
  transition: opacity 220ms ease, visibility 220ms;
}
/* `visibility` en plus de l'opacité : sinon les boutons restent cliquables et
   atteignables au clavier alors qu'ils sont invisibles. */
#viewport:hover .controls,
.controls:focus-within { opacity: 1; visibility: visible; }
.controls button {
  font-family: var(--font);
  background: rgba(11,13,34,.72); color: var(--creme);
  border: 1px solid rgba(250,247,242,.2); border-radius: 8px;
  padding: 9px 14px; font-size: 13px; font-weight: 700; letter-spacing: 1.2px;
  cursor: pointer; text-transform: uppercase;
}
.controls button:hover { background: rgba(34,155,221,.4); }

/* --------------------------------------------- téléphone à la verticale --- */
/* En portrait, une scène 16/9 n'occupe qu'un bandeau : plutôt que de laisser
   les deux tiers de l'écran vides, on y déroule la conduite en clair. */
.portrait {
  display: none;
  position: fixed; left: 0; right: 0; bottom: 0;
  padding: 22px 20px calc(22px + env(safe-area-inset-bottom));
  background: linear-gradient(180deg, #12142f 0%, #0b0d22 100%);
  color: var(--creme);
  overflow-y: auto;
}
.portrait__hint {
  display: flex; align-items: center; gap: 9px;
  font-size: 12px; font-weight: 700; letter-spacing: 1.6px;
  color: rgba(250,247,242,.5); text-transform: uppercase;
  margin-bottom: 18px;
}
.portrait__hint::before {
  content: ''; width: 15px; height: 24px; flex: none;
  border: 2px solid rgba(250,247,242,.42); border-radius: 4px;
  animation: tilt 2.6s ease-in-out infinite;
}
@keyframes tilt {
  0%, 45%, 100% { transform: rotate(0deg); }
  60%, 85%      { transform: rotate(90deg); }
}
.portrait__note {
  font-size: 12.5px; line-height: 1.5; color: rgba(250,247,242,.52);
  margin-bottom: 22px; padding-bottom: 18px;
  border-bottom: 1px solid rgba(250,247,242,.09);
}

.portrait__head {
  font-size: 13px; font-weight: 800; letter-spacing: 2.4px;
  color: var(--gold); text-transform: uppercase; margin-bottom: 12px;
}
.portrait__list { list-style: none; }
.portrait__list li {
  display: flex; gap: 12px; padding: 11px 0;
  border-bottom: 1px solid rgba(250,247,242,.09);
  font-size: 15px; font-weight: 600; line-height: 1.35;
}
.portrait__list li b { color: var(--blue); font-variant-numeric: tabular-nums; }
.portrait__list li.is-current { color: var(--gold); }

@media (orientation: portrait) {
  /* `--shown-bottom` est le bas réel de l'image, calculé par le script. */
  .portrait { display: block; top: var(--shown-bottom, 60vh); }
  /* La colonne « à suivre » ferait doublon avec la liste du dessous. */
  .upnext { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .backdrop__layer.is-live { animation: none; }
  .ticker__track { animation-duration: 240s !important; }
  .slate__bullets li { animation: none; opacity: 1; transform: none; }
}