/* =============================================================
   PRONOSPORTS — couche scénique
   ------------------------------------------------------------
   Chargée APRÈS `pronosports.css`, qu'elle ne remplace pas : elle
   ajoute la profondeur, la lumière et le mouvement.

   Aucun média externe. Tout ce qui bouge ici — aurore, faisceaux
   de projecteurs, pelouse en perspective, grain — est produit par
   des dégradés et des transformations. Une vidéo de stade pèserait
   plusieurs mégaoctets, mettrait deux secondes à démarrer et
   afficherait un rectangle noir en attendant ; ceci s'affiche avec
   la page et pèse ce que pèse le texte.

   Le mouvement est décoratif et se coupe entièrement sous
   `prefers-reduced-motion` — voir la fin du fichier.
   ============================================================= */

:root {
  /* Profondeurs — la scène est éclairée par le haut, comme un stade. */
  --deep: #05070A;
  --deep-2: #080C11;
  --glass: rgba(255, 255, 255, 0.045);
  --glass-hi: rgba(255, 255, 255, 0.085);
  --glass-line: rgba(255, 255, 255, 0.1);

  /* Lumières — la marque reste le lime, le cyan sert de contre-jour. */
  --glow: #FFFFFF;
  --glow-2: #BEC3CD;
  --glow-3: #9696A2;
  --pitch: #0E2818;

  /* Rythme du mouvement */
  --t-fast: 240ms;
  --t: 520ms;
  --t-slow: 900ms;
  --ease: cubic-bezier(.22, 1, .36, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
}

/* ------------------------------------------------------------------ */
/* Fond de scène : aurore + grain                                      */
/* ------------------------------------------------------------------ */

body {
  background: var(--deep);
  position: relative;
}

/* Trois taches de lumière qui dérivent lentement. Le flou est obtenu par
   des dégradés radiaux très étalés plutôt que par `filter: blur()`, qui
   forcerait la composition d'une couche plein écran à chaque image. */
.aurora {
  position: fixed;
  inset: -20vh -10vw;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(38vw 38vw at 18% 12%, rgba(255, 255, 255, 0.0858), transparent 60%),
    radial-gradient(42vw 42vw at 82% 8%,  rgba(190, 195, 205, 0.066), transparent 62%),
    radial-gradient(46vw 46vw at 50% 96%, rgba(150, 150, 162, 0.0594), transparent 64%);
  animation: derive 26s var(--ease) infinite alternate;
}

@keyframes derive {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  50%  { transform: translate3d(-2.5%, 2%, 0) scale(1.06); }
  100% { transform: translate3d(2%, -2.5%, 0) scale(1.02); }
}

/* Grain : casse le banding des grands dégradés, qui sur un fond sombre
   se voit sous forme d'anneaux concentriques. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: .30;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}

.nav, .hero, .sec, .density, .leagues, .cta-band, .foot, .crestwall, .proof { position: relative; z-index: 2; }

/* ------------------------------------------------------------------ */
/* Héros : projecteurs, pelouse, constellation                         */
/* ------------------------------------------------------------------ */

.hero { overflow: clip; padding-block: clamp(64px, 9vw, 132px) clamp(48px, 7vw, 96px); }

.stage { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: clip; }

/* Voile sur la colonne de texte.
   Les points de foule de l'image passent juste derrière le paragraphe
   d'introduction et le rendaient pénible à lire — un fond qui grouille sous
   du texte gris, c'est du texte qu'on saute. Le voile éteint l'image du côté
   gauche et la laisse intacte derrière le téléphone, où elle sert. */
.stage::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(96deg,
    rgba(10, 10, 11, .94) 0%,
    rgba(10, 10, 11, .86) 30%,
    rgba(10, 10, 11, .45) 52%,
    transparent 68%);
}
@media (max-width: 900px) {
  /* Sur une colonne, le texte occupe toute la largeur : le voile aussi. */
  .stage::after { background: linear-gradient(180deg, rgba(10, 10, 11, .9), rgba(10, 10, 11, .72)); }
}

/* Le stade de nuit. Image calculée par `scripts/visuels.py` — foule, brume,
   faisceaux, grain —, pas une photographie : rien à créditer, rien qui puisse
   être retiré, et 128 Ko au lieu de plusieurs mégaoctets de vidéo.

   Le masque l'efface avant la colonne de texte. Un fond photographique plein
   cadre derrière un titre, c'est un titre qu'on ne lit plus. */
.stade {
  position: absolute;
  inset: -6% -4%;
  /* `object-fit` cadre la vidéo ; `background` sert de fond au poster et au
     repli image. Les deux cohabitent sans se gêner. */
  width: 108%; height: 112%;
  object-fit: cover;
  background: url('/assets/scene/stade-nuit.webp') center/cover no-repeat;
  opacity: .78;
  -webkit-mask-image: radial-gradient(120% 92% at 50% 34%, #000 24%, rgba(0, 0, 0, 0.35) 62%, transparent 88%);
  mask-image: radial-gradient(120% 92% at 50% 34%, #000 24%, rgba(0, 0, 0, 0.35) 62%, transparent 88%);
  /* Dérive très lente, façon travelling : l'image respire au lieu d'être une
     affiche collée derrière le texte. */
  animation: travelling 42s ease-in-out infinite alternate;
}
@keyframes travelling {
  from { transform: scale(1.03) translate3d(-.6%, .4%, 0); }
  to   { transform: scale(1.10) translate3d(.8%, -.7%, 0); }
}

/* Faisceaux de projecteurs : deux cônes qui balaient très lentement. */
.beam {
  position: absolute;
  top: -32vh;
  width: 46vw;
  height: 130vh;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.1056), transparent 68%);
  filter: blur(28px);
  transform-origin: 50% 0;
}
.beam-l { left: -6vw;  clip-path: polygon(42% 0, 58% 0, 100% 100%, 0 100%); animation: balaye 19s var(--ease) infinite alternate; }
.beam-r { right: -6vw; clip-path: polygon(42% 0, 58% 0, 100% 100%, 0 100%);
          background: linear-gradient(180deg, rgba(190, 195, 205, 0.0858), transparent 68%);
          animation: balaye 23s var(--ease) infinite alternate-reverse; }

@keyframes balaye {
  from { transform: rotate(-7deg); opacity: .55; }
  to   { transform: rotate(7deg);  opacity: .95; }
}

/* Pelouse en perspective — un damier qui fuit vers l'horizon. Le masque
   l'efface avant qu'il n'atteigne le texte, sinon la grille concurrence
   le titre au lieu de le porter. */
.pitch {
  position: absolute;
  left: 50%;
  bottom: -18vh;
  width: 190vw;
  height: 78vh;
  transform: translateX(-50%) perspective(760px) rotateX(64deg);
  /* Grille très effacée, et c'est délibéré : depuis que l'image du stade porte
     une vraie pelouse tracée en perspective, cette grille n'a plus à figurer
     un terrain — elle ne sert qu'à faire glisser quelque chose sous le pied du
     héros. Aux anciennes valeurs les deux tracés se superposaient et l'on
     voyait un quadrillage posé sur une pelouse. */
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.032) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.032) 1px, transparent 1px);
  background-size: 88px 88px;
  -webkit-mask-image: radial-gradient(58% 78% at 50% 100%, #000 12%, transparent 62%);
  mask-image: radial-gradient(58% 78% at 50% 100%, #000 12%, transparent 62%);
  animation: avance 7.5s linear infinite;
}

@keyframes avance {
  from { background-position: 0 0, 0 0; }
  to   { background-position: 0 88px, 0 0; }
}

/* Ligne de balayage : ce que l'œil lit comme « le modèle calcule ». */
.scan {
  position: absolute;
  left: 0; right: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--glow), transparent);
  opacity: .5;
  filter: blur(1px);
  animation: descend 6s cubic-bezier(.4, 0, .2, 1) infinite;
}
@keyframes descend {
  0%   { top: 6%;  opacity: 0; }
  12%  { opacity: .55; }
  88%  { opacity: .55; }
  100% { top: 94%; opacity: 0; }
}

/* Constellation d'écussons : de vrais clubs, en orbite lente derrière la
   carte. Ils flottent hors du champ de lecture et restent volontairement
   discrets — ce sont des figurants, pas le sujet. */
/* Les écussons passent AU-DESSUS du voile : sous lui ils s'éteignaient, et
   c'est justement eux qui doivent flotter autour du téléphone. */
.orbit { position: absolute; inset: 0; z-index: 1; }
.orbit-crest {
  position: absolute;
  width: 46px; height: 46px;
  border-radius: 12px;
  display: grid; place-items: center;
  background: var(--glass);
  border: 1px solid var(--glass-line);
  backdrop-filter: blur(9px);
  box-shadow: 0 16px 40px -18px rgba(0, 0, 0, 0.9);
  opacity: 0;
  animation: apparait .9s var(--ease-out) forwards, flotte 9s ease-in-out infinite;
}
.orbit-crest img { width: 26px; height: 26px; object-fit: contain; }
.orbit-crest span { font: 700 11px/1 var(--sans); color: var(--muted); letter-spacing: .04em; }

@keyframes apparait { to { opacity: .62; } }

/* Sous 1280 px les gouttières disparaissent : la constellation viendrait
   se poser sur le texte. On la retire plutôt que de la rétrécir. */
@media (max-width: 1279px) { .orbit { display: none; } }
@keyframes flotte {
  0%, 100% { transform: translateY(0) rotate(0); }
  50%      { transform: translateY(-14px) rotate(1.5deg); }
}

/* ------------------------------------------------------------------ */
/* Titre : dégradé animé + arrivée par masque                          */
/* ------------------------------------------------------------------ */

/* Le dégradé se pose sur l'élément qui PORTE le texte, jamais sur un
   ancêtre : `background-clip: text` ne découpe que son propre contenu, et
   `color: transparent` s'hérite. Poser les deux sur le `h1` alors que le
   texte vit dans un enfant rendait le titre entièrement invisible. */
.hero h1 .rise > * {
  background: linear-gradient(96deg, #FFFFFF 8%, var(--glow) 46%, #FFFFFF 78%);
  background-size: 260% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: leve .95s var(--ease-out) forwards, brille 9s ease-in-out infinite;
}
@keyframes brille {
  0%, 100% { background-position: 0% 50%; }
  50%      { background-position: 100% 50%; }
}

/* Chaque ligne monte derrière son propre masque : le titre se « lève » au
   lieu d'apparaître d'un bloc. La marge basse compense le masque, qui
   couperait sinon les jambages du « p » de « shape ». */
.rise { display: block; overflow: hidden; padding-bottom: .12em; margin-bottom: -.12em; }
.rise > * { display: block; transform: translateY(105%); }
.hero h1 .rise:nth-of-type(2) > * { animation-delay: .12s, 0s; }
@keyframes leve { to { transform: translateY(0); } }

/* ------------------------------------------------------------------ */
/* Verre : cartes, surfaces                                            */
/* ------------------------------------------------------------------ */

.sport-card,
.price-card,
.proof-card,
.steps li,
.faq details {
  position: relative;
  background: linear-gradient(168deg, var(--glass-hi), var(--glass));
  border: 1px solid var(--glass-line);
  backdrop-filter: blur(16px);
  box-shadow: 0 34px 90px -40px rgba(0, 0, 0, 0.95), inset 0 1px 0 rgba(255, 255, 255, 0.07);
  transition: transform var(--t) var(--ease), box-shadow var(--t) var(--ease), border-color var(--t) var(--ease);
}

/* Liseré lumineux au survol : un dégradé conique tourne le long du bord.
   Il vit dans un pseudo-élément masqué pour n'éclairer que la bordure.
   `--lueur` laisse chaque carte imposer sa teinte — l'accent du sport sur la
   grille des sports, le lime de la marque partout ailleurs. */
.sport-card::after,
.price-card::before,
.proof-card::before,
.steps li::after {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: conic-gradient(from var(--angle, 0deg), transparent 62%, var(--lueur, var(--glow)), transparent 88%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0;
  transition: opacity var(--t) var(--ease);
  pointer-events: none;
}
.sport-card:hover::after,
.price-card:hover::before,
.proof-card:hover::before,
.steps li:hover::after { opacity: 1; animation: tourne 3.2s linear infinite; }

@property --angle { syntax: '<angle>'; initial-value: 0deg; inherits: false; }
@keyframes tourne { to { --angle: 360deg; } }

.sport-card:hover,
.price-card:hover,
.proof-card:hover {
  transform: translateY(-7px);
  border-color: color-mix(in oklab, var(--lueur, var(--glow)) 30%, transparent);
  box-shadow:
    0 50px 110px -44px rgba(0, 0, 0, 1.0),
    0 0 60px -32px color-mix(in oklab, var(--lueur, var(--glow)) 60%, transparent);
}

/* Inclinaison suivant la souris — pilotée par `motion.js`. */
.tilt { transform-style: preserve-3d; will-change: transform; }

/* ------------------------------------------------------------------ */
/* Mur d'écussons : deux rangées en sens contraires                    */
/* ------------------------------------------------------------------ */

.crestwall {
  padding-block: clamp(40px, 6vw, 76px);
  overflow: clip;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.crestwall-row { display: flex; gap: 16px; width: max-content; }
.crestwall-row + .crestwall-row { margin-top: 16px; }
.crestwall-row.a { animation: defile-g 46s linear infinite; }
.crestwall-row.b { animation: defile-d 52s linear infinite; }
.crestwall:hover .crestwall-row { animation-play-state: paused; }

@keyframes defile-g { to { transform: translateX(-50%); } }
@keyframes defile-d { from { transform: translateX(-50%); } to { transform: translateX(0); } }

.crest-tile {
  flex: 0 0 auto;
  width: 88px; height: 88px;
  border-radius: 18px;
  display: grid; place-items: center;
  background: linear-gradient(168deg, var(--glass-hi), transparent);
  border: 1px solid var(--glass-line);
  transition: transform var(--t-fast) var(--ease), border-color var(--t-fast), box-shadow var(--t-fast);
}
.crest-tile img { width: 46px; height: 46px; object-fit: contain; filter: saturate(.9); transition: filter var(--t-fast); }
.crest-tile:hover {
  transform: translateY(-6px) scale(1.06);
  border-color: rgba(255, 255, 255, 0.0264);
  box-shadow: 0 0 44px -14px rgba(255, 255, 255, 0.0396);
}
.crest-tile:hover img { filter: saturate(1.25); }
/* Blason de repli.
 *
 * Il faut le prendre au sérieux : c'est ce que voient tous les visiteurs
 * derrière un réseau d'entreprise ou un bloqueur de publicité, et ils sont
 * plus nombreux qu'on ne le croit. Un carré coloré signale « image
 * manquante » ; une forme d'écusson signale « club ».
 *
 * La silhouette est celle d'un blason — épaules droites, pointe en bas —
 * obtenue par `clip-path`, donc sans image et sans SVG par équipe. Elle porte
 * les vraies couleurs du club et ses initiales, jamais son emblème : le
 * dessin d'un club est une marque déposée, et un pastiche ressemblant poserait
 * exactement le problème qu'on cherche à éviter.
 */
.mono-badge {
  --c: #8A9481;
  position: relative;
  display: grid; place-items: center;
  width: 44px; height: 50px;
  font: 800 14px/1 var(--sans);
  letter-spacing: .03em;
  color: #fff;
  /* Le chevron clair en travers rappelle les partitions d'héraldique et
     empêche l'aplat de couleur de paraître plat. */
  background:
    linear-gradient(158deg,
      color-mix(in oklab, var(--c) 82%, #fff) 0%,
      var(--c) 34%,
      color-mix(in oklab, var(--c) 62%, #000) 68%,
      color-mix(in oklab, var(--c) 40%, #000) 100%);
  clip-path: polygon(50% 100%, 100% 74%, 100% 0, 0 0, 0 74%);
  text-shadow: 0 1px 3px rgba(0, 0, 0, .65);
  filter: drop-shadow(0 6px 14px rgba(0, 0, 0, .55));
}
/* Le liseré. `clip-path` rogne la bordure d'un élément : on la redessine donc
   à l'intérieur, en pseudo-élément découpé de la même silhouette. */
.mono-badge::before {
  content: '';
  position: absolute;
  inset: 0;
  clip-path: polygon(50% 100%, 100% 74%, 100% 0, 0 0, 0 74%);
  background: linear-gradient(180deg, rgba(255, 255, 255, .5), transparent 42%);
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  padding: 1.5px;
}
/* Une barre sous les initiales : le détail qui fait lire « écusson » plutôt
   que « pastille ». */
.mono-badge::after {
  content: '';
  position: absolute;
  left: 28%; right: 28%;
  bottom: 30%;
  height: 1.5px;
  background: rgba(255, 255, 255, .55);
}

.crest-tile .mono-badge { width: 46px; height: 52px; }
.orbit-crest .mono-badge { width: 26px; height: 30px; font-size: 10px; border-radius: 0; }
.orbit-crest .mono-badge::after { display: none; }
.ticker-item .mono-badge { width: 17px; height: 19px; font-size: 7.5px; letter-spacing: 0; border-radius: 0; }
.ticker-item .mono-badge::after, .ticker-item .mono-badge::before { display: none; }

/* ------------------------------------------------------------------ */
/* Révélation au défilement                                            */
/* ------------------------------------------------------------------ */

/* Le décalage passe par `translate`, pas par `transform`.
   Plusieurs éléments révélés sont aussi des cartes qui se soulèvent au survol
   ou s'inclinent sous le pointeur : avec `transform`, l'état révélé
   (`transform: none`) écraserait ces effets selon l'ordre des règles. Les deux
   propriétés étant distinctes, elles se composent au lieu de se disputer. */
.reveal {
  opacity: 0;
  translate: 0 26px;
  transition: opacity var(--t-slow) var(--ease-out), translate var(--t-slow) var(--ease-out);
}
.reveal.seen { opacity: 1; translate: none; }
.reveal[data-delay="1"] { transition-delay: .09s; }
.reveal[data-delay="2"] { transition-delay: .18s; }
.reveal[data-delay="3"] { transition-delay: .27s; }
.reveal[data-delay="4"] { transition-delay: .36s; }
.reveal[data-delay="5"] { transition-delay: .45s; }

/* ------------------------------------------------------------------ */
/* Compteurs et jauges                                                 */
/* ------------------------------------------------------------------ */

.hstat-n { font-variant-numeric: tabular-nums; }

/* Anneau de calibration : le trait se dessine quand la section entre. */
.ring-gauge { transform: rotate(-90deg); }
.ring-gauge circle { fill: none; stroke-linecap: round; }
.ring-gauge .track { stroke: rgba(255, 255, 255, 0.07); }
.ring-gauge .val {
  stroke: var(--glow);
  stroke-dasharray: var(--len, 264);
  stroke-dashoffset: var(--len, 264);
  filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.363));
  transition: stroke-dashoffset 1.5s var(--ease-out);
}
.seen .ring-gauge .val { stroke-dashoffset: var(--off, 66); }

/* ------------------------------------------------------------------ */
/* Bandeau de rencontres en direct                                     */
/* ------------------------------------------------------------------ */

.ticker {
  position: relative;
  border-block: 1px solid var(--glass-line);
  background: rgba(255, 255, 255, 0.02);
  overflow: clip;
  padding-block: 11px;
}

/* Drapeau de compétition : posé au bord gauche, il ne défile pas. Les affiches
   passent DESSOUS, d'où le fond opaque et le dégradé qui les efface juste
   avant — sans quoi on lirait « NFL » par-dessus un écusson. */
.ticker-flag {
  position: absolute; z-index: 2;
  inset-block: 0; left: 0;
  display: flex; align-items: center;
  /* La marge de droite n'habille pas le texte : elle porte le fondu. Trop
     courte, une affiche réapparaissait en plein milieu d'un mot, juste
     derrière le drapeau — d'où soixante pixels pour la dissoudre. */
  padding-inline: 22px 60px;
  font: 800 11px/1 var(--mono);
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--glow);
  background: linear-gradient(90deg,
    var(--deep) 0%, var(--deep) 58%, color-mix(in srgb, var(--deep) 0%, transparent) 100%);
}
/* Filet vertical au bout du mot : sans lui le drapeau flotte au-dessus de la
   bande au lieu de la commencer. */
.ticker-flag::after {
  content: ''; position: absolute; right: 52px; top: 25%; bottom: 25%;
  width: 1px; background: var(--glass-line);
}
.ticker-flag[hidden] { display: none; }
@media (max-width: 520px) {
  .ticker-flag { padding-inline: 14px 40px; font-size: 10px; letter-spacing: .1em; }
  .ticker-flag::after { right: 34px; }
}

.ticker-track { display: flex; gap: 34px; width: max-content; animation: defile-g 38s linear infinite; }
.ticker:hover .ticker-track { animation-play-state: paused; }
.ticker-item {
  display: inline-flex; align-items: center; gap: 9px;
  font: 600 12.5px/1 var(--mono);
  color: var(--muted);
  letter-spacing: .03em;
  white-space: nowrap;
}
.ticker-item img { width: 17px; height: 17px; object-fit: contain; }
.ticker-item b { color: var(--text); font-weight: 700; }
.ticker-item .pc { color: var(--glow); font-weight: 800; }
.ticker-sep { color: var(--faint); }

/* ------------------------------------------------------------------ */
/* Boutons : lueur et onde                                             */
/* ------------------------------------------------------------------ */

.btn-brass {
  position: relative;
  overflow: hidden;
  box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.033), 0 16px 40px -16px rgba(255, 255, 255, 0.363);
  transition: transform var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.btn-brass:hover { transform: translateY(-2px); box-shadow: 0 0 34px -6px rgba(255, 255, 255, 0.495), 0 20px 48px -18px rgba(255, 255, 255, 0.0396); }
.btn-brass::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(110deg, transparent 32%, rgba(255, 255, 255, 0.55) 50%, transparent 68%);
  transform: translateX(-120%);
  transition: transform .75s var(--ease);
}
.btn-brass:hover::after { transform: translateX(120%); }

/* Pastille de disponibilité : halo qui se propage. */
.pulse { position: relative; }
.pulse::after {
  content: '';
  position: absolute; inset: -4px;
  border-radius: 50%;
  border: 1px solid var(--glow);
  opacity: 0;
  animation: onde 2.4s ease-out infinite;
}
@keyframes onde {
  0%   { transform: scale(.7); opacity: .75; }
  100% { transform: scale(2.5); opacity: 0; }
}

/* ------------------------------------------------------------------ */
/* Section « preuve » : ce que les concurrents ne montrent pas         */
/* ------------------------------------------------------------------ */

.proof { padding-block: clamp(56px, 8vw, 108px); }
.proof-grid {
  display: grid;
  gap: 18px;
  grid-template-columns: repeat(auto-fit, minmax(min(232px, 100%), 1fr));
  margin-top: 34px;
}
.proof-card { border-radius: var(--r-lg); padding: 26px 24px; }
.proof-n {
  font: 800 clamp(30px, 4.4vw, 46px)/1 var(--display);
  background: linear-gradient(180deg, #fff, var(--glow));
  -webkit-background-clip: text; background-clip: text; color: transparent;
  font-variant-numeric: tabular-nums;
}
.proof-l { display: block; margin-top: 9px; color: var(--muted); font-size: 13.5px; line-height: 1.45; }

.proof-note {
  max-width: 68ch;
  margin: 26px auto 0;
  text-align: center;
  color: var(--muted);
  font-size: 14.5px;
  line-height: 1.62;
}

/* Signalement des données de démonstration : volontairement voyant. Un
   palmarès fabriqué qui se donne pour réel est le procédé que cette section
   reproche à la concurrence — le bandeau doit se voir autant que les chiffres. */
/* Mention de démonstration. C'était un encadré ambre pleine largeur, qui
   coupait la section en deux et criait plus fort que les chiffres qu'il
   qualifiait. C'est maintenant une légende : même information, au même
   endroit, mais lue à la suite des chiffres au lieu de leur passer devant. */
.proof-demo {
  margin: 14px auto 0;
  text-align: center;
  font: 500 11px/1.4 var(--mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ------------------------------------------------------------------ */
/* Barre de navigation : se condense au défilement                     */
/* ------------------------------------------------------------------ */

.nav {
  transition: background var(--t) var(--ease), border-color var(--t) var(--ease),
              padding var(--t) var(--ease), backdrop-filter var(--t) var(--ease);
}
/* La classe est posée par `motion.js` dès qu'on quitte le haut de page. Sans
   fond, la barre devient illisible au-dessus des cartes claires ; avec un fond
   permanent, elle ampute le héros d'une bande opaque. D'où l'état double. */
.nav.compact {
  background: rgba(6, 9, 13, 0.72);
  backdrop-filter: blur(18px) saturate(1.3);
  border-bottom: 1px solid var(--glass-line);
  box-shadow: 0 18px 40px -30px rgba(0, 0, 0, 1.0);
}

/* Soulignement qui se déploie depuis le centre, plutôt qu'un simple
   changement de couleur : le survol devient repérable en vision périphérique. */
.nav-links a { position: relative; transition: color var(--t-fast) var(--ease); }
.nav-links a::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -6px;
  height: 1.5px;
  background: linear-gradient(90deg, transparent, var(--glow), transparent);
  transform: scaleX(0);
  transition: transform var(--t) var(--ease);
}
.nav-links a:hover::after { transform: scaleX(1); }

/* ------------------------------------------------------------------ */
/* En-têtes de section                                                 */
/* ------------------------------------------------------------------ */

.sec-head { max-width: 720px; }

/* Le sur-titre gagne un filet lumineux : il annonce la section au lieu de
   flotter seul au-dessus du titre. */
.eyebrow { display: inline-flex; align-items: center; gap: 10px; }
.eyebrow::before {
  content: '';
  width: 26px; height: 1px;
  background: linear-gradient(90deg, transparent, var(--glow));
}
/* La descente s'arrête à 82 % d'opacité : plus bas, la deuxième ligne d'un
   titre qui passe à la ligne devient nettement plus pâle que la première et se
   lit comme une erreur de rendu. */
.sec-head h2 {
  background: linear-gradient(180deg, #FFFFFF 55%, rgba(242, 245, 238, 0.9));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
/* `em` porte l'accent : il doit garder sa couleur propre, que le dégradé
   ci-dessus effacerait s'il en héritait. */
.sec-head h2 em { -webkit-text-fill-color: var(--glow); color: var(--glow); }

/* ------------------------------------------------------------------ */
/* Grille des sports : un module par discipline                        */
/* ------------------------------------------------------------------ */

.sport-grid { gap: 18px; }

.sport-card {
  --lueur: var(--sc, var(--glow));
  border-radius: var(--r-lg);
  padding: 24px 22px 22px;
  overflow: hidden;
  /* L'aura est une image calculée aux couleurs du sport (`scripts/visuels.py`,
     2 Ko par fichier). Elle se pose SOUS le verre : trois foyers décalés qui
     donnent à chaque carte une lumière propre, là où un dégradé CSS ferait
     six fois le même fond. `--aura` est posée par `app.js`. */
  background-image: var(--aura, none), linear-gradient(168deg, var(--glass-hi), var(--glass));
  background-size: cover, auto;
  background-position: center, center;
}
/* Le rail coloré de la feuille de base laisse place à un halo d'angle : la
   teinte du sport se lit sans découper la carte en deux. */
.sport-card::before {
  content: '';
  position: absolute;
  inset: auto auto -40% -30%;
  width: 70%; aspect-ratio: 1;
  background: radial-gradient(circle, color-mix(in oklab, var(--sc) 26%, transparent), transparent 70%);
  opacity: .5;
  transition: opacity var(--t) var(--ease), transform var(--t) var(--ease);
  pointer-events: none;
}
.sport-card:hover::before { opacity: 1; transform: scale(1.25); }

.sport-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }

/* Le pictogramme prend un socle : un disque teinté cerclé d'un anneau qui
   tourne au survol. Un émoji nu sur fond sombre paraît collé là par accident. */
.sport-orb {
  position: relative;
  display: grid; place-items: center;
  width: 52px; height: 52px;
  border-radius: 16px;
  background: linear-gradient(155deg, color-mix(in oklab, var(--sc) 22%, transparent), transparent);
  border: 1px solid color-mix(in oklab, var(--sc) 30%, transparent);
}
.sport-orb::after {
  content: '';
  position: absolute; inset: -5px;
  border-radius: 20px;
  border: 1px dashed color-mix(in oklab, var(--sc) 42%, transparent);
  opacity: 0;
  transition: opacity var(--t) var(--ease);
}
.sport-card:hover .sport-orb::after { opacity: 1; animation: rotation 14s linear infinite; }
@keyframes rotation { to { transform: rotate(360deg); } }
.sport-card .sport-em { font-size: 25px; filter: drop-shadow(0 3px 8px rgba(0, 0, 0, 0.6)); }

/* Pastille de disponibilité : le point clignote tant qu'il y a des rencontres. */
.sport-live {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 10px;
  border-radius: 100px;
  font: 700 10.5px/1 var(--mono);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--sc) 82%, #fff);
  background: color-mix(in oklab, var(--sc) 12%, transparent);
  border: 1px solid color-mix(in oklab, var(--sc) 26%, transparent);
}
.sport-live i {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--sc);
  box-shadow: 0 0 0 0 color-mix(in oklab, var(--sc) 70%, transparent);
  animation: battement 2.2s ease-out infinite;
}
@keyframes battement {
  0%   { box-shadow: 0 0 0 0 color-mix(in oklab, var(--sc) 70%, transparent); }
  70%  { box-shadow: 0 0 0 7px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

.sport-card h3 { margin-top: 18px; }
.sport-card .sport-engine { color: color-mix(in oklab, var(--sc) 85%, #fff); }
.sport-card .sport-leagues { margin-bottom: 16px; min-height: 2.6em; }

/* Silhouette de la loi du score, propre à chaque discipline. Ce n'est pas un
   ornement : c'est la forme que le moteur calcule, en miniature. Les barres
   poussent quand la carte entre dans le champ. */
.sport-spark {
  display: flex; align-items: flex-end; gap: 3px;
  height: 40px;
  margin-bottom: 16px;
}
.sport-spark i {
  flex: 1;
  height: 0;
  border-radius: 3px 3px 1px 1px;
  background: linear-gradient(180deg, var(--sc), color-mix(in oklab, var(--sc) 18%, transparent));
  transition: height .85s var(--ease-out);
}
.seen .sport-spark i, .sport-card.seen .sport-spark i { height: var(--h, 20%); }
.sport-spark i:nth-child(1) { transition-delay: .02s; }
.sport-spark i:nth-child(2) { transition-delay: .05s; }
.sport-spark i:nth-child(3) { transition-delay: .08s; }
.sport-spark i:nth-child(4) { transition-delay: .11s; }
.sport-spark i:nth-child(5) { transition-delay: .14s; }
.sport-spark i:nth-child(6) { transition-delay: .17s; }
.sport-spark i:nth-child(7) { transition-delay: .20s; }
.sport-spark i:nth-child(8) { transition-delay: .23s; }
.sport-spark i:nth-child(9) { transition-delay: .26s; }
.sport-spark i:nth-child(10) { transition-delay: .29s; }
.sport-spark i:nth-child(11) { transition-delay: .32s; }
.sport-spark i:nth-child(12) { transition-delay: .35s; }

.sport-foot {
  display: flex; align-items: baseline; gap: 9px;
  padding-top: 15px;
  border-top: 1px solid var(--glass-line);
}
.sport-card .sport-count { font-size: 27px; font-variant-numeric: tabular-nums; }
.sport-card .sport-count-lbl { margin-top: 0; }

/* ------------------------------------------------------------------ */
/* Méthode : quatre stations reliées                                   */
/* ------------------------------------------------------------------ */

.steps { position: relative; gap: 18px; }

/* Le fil qui relie les stations. Il se remplit au défilement — `--fil` est
   posé par `motion.js` — pour matérialiser la chaîne flux → écran. */
.steps::before {
  content: '';
  position: absolute;
  top: 34px; left: 4%; right: 4%;
  height: 1px;
  background: linear-gradient(90deg, var(--glow) 0 var(--fil, 0%), var(--glass-line) var(--fil, 0%));
  transition: background .5s linear;
}
@media (max-width: 960px) { .steps::before { display: none; } }

.steps li {
  border-radius: var(--r-lg);
  padding: 26px 22px 24px;
  overflow: hidden;
}
/* Le numéro en très grand, effacé, derrière le texte : il donne l'ordre de
   lecture sans occuper de place. */
.steps li > .step-ghost {
  position: absolute;
  top: 10px; right: 16px;
  font: 800 62px/.8 var(--display);
  color: rgba(255, 255, 255, 0.05);
  pointer-events: none;
  user-select: none;
}
.step-n {
  display: inline-grid; place-items: center;
  width: 32px; height: 32px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.066);
  border: 1px solid rgba(255, 255, 255, 0.2112);
  font-size: 11.5px;
  position: relative;
  z-index: 1;
}
.steps li:hover .step-n {
  background: var(--glow);
  color: #14180C;
  box-shadow: 0 0 22px -4px rgba(255, 255, 255, 0.0528);
}
.steps h3 { margin-top: 16px; }

/* ------------------------------------------------------------------ */
/* Aperçu : la section sombre du milieu                                */
/* ------------------------------------------------------------------ */

.sec-dark { position: relative; overflow: clip; }
/* Voûte lumineuse au-dessus de l'aperçu : la carte semble posée sous un
   projecteur plutôt que collée sur un rectangle noir. */
.sec-dark::before {
  content: '';
  position: absolute;
  inset: -30% 0 auto;
  height: 70%;
  background: radial-gradient(60% 100% at 50% 0, rgba(255, 255, 255, 0.066), transparent 70%);
  pointer-events: none;
}
.preview {
  position: relative;
  background: linear-gradient(168deg, var(--glass-hi), var(--glass));
  border-color: var(--glass-line);
  backdrop-filter: blur(16px);
  box-shadow: 0 44px 110px -46px rgba(0, 0, 0, 1.0), inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
/* Équerres d'angle : le vocabulaire des interfaces de mesure — c'est ce que
   le produit prétend être. */
.preview::before,
.preview::after {
  content: '';
  position: absolute;
  width: 22px; height: 22px;
  border: 1px solid rgba(255, 255, 255, 0.2244);
  pointer-events: none;
}
.preview::before { top: 12px; left: 12px; border-right: 0; border-bottom: 0; border-radius: 6px 0 0 0; }
.preview::after { bottom: 12px; right: 12px; border-left: 0; border-top: 0; border-radius: 0 0 6px 0; }

/* ------------------------------------------------------------------ */
/* Tarifs                                                              */
/* ------------------------------------------------------------------ */

.price-grid { gap: 20px; align-items: stretch; }

/* Pas de `overflow: hidden` ici : la pastille « Recommandé » est posée en
   débord au-dessus du bord supérieur, et serait tranchée en deux. */
.price-card { border-radius: 22px; padding: 30px 26px; }

/* La formule recommandée est surélevée et éclairée par en dessous. Sur la
   grille à une colonne (mobile) le décalage vertical n'a plus de sens : trois
   cartes empilées, la deuxième « surélevée » paraîtrait mal alignée. */
@media (min-width: 901px) {
  .price-card.featured { transform: translateY(-14px); }
  .price-card.featured:hover { transform: translateY(-21px); }
}
.price-card.featured {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.0858), var(--glass) 58%);
  border-color: rgba(255, 255, 255, 0.0198);
  box-shadow: 0 50px 120px -46px rgba(0, 0, 0, 1.0), 0 0 90px -46px rgba(255, 255, 255, 0.0462);
}
.price-badge {
  top: -11px; left: 26px;
  box-shadow: 0 8px 22px -8px rgba(255, 255, 255, 0.0594);
}

/* Le bandeau de l'offre gratuite emprunte le verre du reste de la scène :
   posé sur le même fond, un aplat opaque aurait fait tache. */
.price-free {
  background: var(--glass);
  border-color: rgba(255, 255, 255, 0.0858);
  backdrop-filter: blur(var(--blur));
}

.price-name { display: flex; align-items: center; gap: 9px; }
.price-amt b {
  background: linear-gradient(180deg, #fff, rgba(255, 255, 255, 0.561));
  -webkit-background-clip: text; background-clip: text; color: transparent;
  font-variant-numeric: tabular-nums;
}
.price-card.featured .price-amt b { font-size: 48px; }

.price-list li { border-top-color: var(--glass-line); align-items: center; }
/* La coche prend un jeton : les items se lisent en balayage vertical, la
   colonne de pastilles servant de repère. */
.price-list li::before {
  content: '✓';
  display: grid; place-items: center;
  width: 19px; height: 19px;
  border-radius: 50%;
  font-size: 11px;
  background: rgba(255, 255, 255, 0.0858);
  border: 1px solid rgba(255, 255, 255, 0.0198);
}

/* ------------------------------------------------------------------ */
/* FAQ : deux colonnes de panneaux                                     */
/* ------------------------------------------------------------------ */

.faq {
  max-width: none;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
  align-items: start;
  counter-reset: q;
}
@media (max-width: 860px) { .faq { grid-template-columns: 1fr; } }

.faq details {
  border-radius: var(--r);
  border-top: 1px solid var(--glass-line);
  padding: 4px 20px;
}
.faq details:last-child { border-bottom: 1px solid var(--glass-line); }
.faq details[open] {
  border-color: rgba(255, 255, 255, 0.1716);
  background: linear-gradient(168deg, rgba(255, 255, 255, 0.0462), var(--glass));
}

.faq summary { padding: 18px 0; gap: 14px; counter-increment: q; }
.faq summary::before {
  content: counter(q, decimal-leading-zero);
  font: 700 11px/1 var(--mono);
  color: var(--glow);
  opacity: .7;
  letter-spacing: .06em;
  flex-shrink: 0;
}
.faq summary span { flex: 1; }

/* Une croix qui pivote plutôt qu'un caractère remplacé : le « + » qui devient
   « – » saute, la rotation raconte l'ouverture. */
.faq summary::after {
  content: '';
  width: 13px; height: 13px;
  flex-shrink: 0;
  background:
    linear-gradient(var(--muted), var(--muted)) center/13px 1.5px no-repeat,
    linear-gradient(var(--muted), var(--muted)) center/1.5px 13px no-repeat;
  transition: transform var(--t) var(--ease), background-size var(--t) var(--ease);
}
.faq details[open] summary::after { transform: rotate(135deg); }
.faq p { padding-bottom: 18px; }

/* ------------------------------------------------------------------ */
/* Bandeau d'appel : la scène revient pour la sortie                   */
/* ------------------------------------------------------------------ */

.cta-band {
  position: relative;
  overflow: clip;
  /* Fond volontairement plus sombre que dans la feuille de base : la boucle
     animée s'ajoute en « screen », il lui faut du noir pour exister. */
  background:
    radial-gradient(70% 120% at 50% 0%, rgba(45, 212, 167, 0.1), transparent 62%),
    linear-gradient(180deg, #05140F, #030A07);
}
.cta-scene { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.cta-in { position: relative; z-index: 2; }
.cta-in h2 {
  background: linear-gradient(180deg, #fff 35%, rgba(255, 255, 255, 0.5412));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* Même grammaire qu'au héros — pelouse et halo — pour que la page se referme
   sur l'image qui l'a ouverte. */
.cta-pitch {
  position: absolute;
  left: 50%; bottom: -30%;
  width: 200vw; height: 90%;
  transform: translateX(-50%) perspective(700px) rotateX(66deg);
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.2244) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.2244) 1px, transparent 1px);
  background-size: 76px 76px;
  -webkit-mask-image: radial-gradient(56% 74% at 50% 100%, #000 8%, transparent 74%);
  mask-image: radial-gradient(56% 74% at 50% 100%, #000 8%, transparent 74%);
  animation: avance 8.5s linear infinite;
}
/* Boucle animée : 24 images calculées, encodées en WebP animé (42 Ko). Une
   vraie séquence, pas une animation CSS — la nappe de lumière dérive et se
   déforme, ce qu'aucun dégradé ne sait faire. Le navigateur la joue seul, sans
   balise `video` ni script. */
.cta-boucle {
  position: absolute;
  inset: -10%;
  background: url('/assets/scene/lumiere.webp') center/cover no-repeat;
  opacity: .9;
  mix-blend-mode: screen;
  -webkit-mask-image: radial-gradient(90% 100% at 50% 60%, #000 30%, transparent 82%);
  mask-image: radial-gradient(90% 100% at 50% 60%, #000 30%, transparent 82%);
}

.cta-halo {
  position: absolute;
  inset: -40% 20% auto;
  height: 90%;
  background: radial-gradient(50% 50% at 50% 50%, rgba(255, 255, 255, 0.1056), transparent 68%);
  animation: respire 11s ease-in-out infinite;
}
@keyframes respire {
  0%, 100% { opacity: .55; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.12); }
}

/* ------------------------------------------------------------------ */
/* Pied de page                                                        */
/* ------------------------------------------------------------------ */

.foot {
  position: relative;
  overflow: clip;
  border-top: 1px solid var(--glass-line);
  padding: 0;
  background: linear-gradient(180deg, transparent, rgba(255, 255, 255, 0.1452));
}
.foot-in {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr 1fr;
  gap: 40px;
  align-items: start;
  padding: 58px 24px 30px;
  text-align: left;
}
@media (max-width: 900px) { .foot-in { grid-template-columns: 1fr 1fr; gap: 32px; } }
@media (max-width: 520px) { .foot-in { grid-template-columns: 1fr; } }

.foot-tag { color: var(--muted); font-size: 13.5px; line-height: 1.6; margin: 14px 0 0; max-width: 34ch; }
.foot-col h4 {
  font: 700 11px/1 var(--mono);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0 0 14px;
}
.foot-col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.foot-col a { font-size: 13.5px; color: var(--muted); transition: color var(--t-fast) var(--ease); }
.foot-col a:hover { color: var(--glow); }

.foot-bar {
  position: relative;
  z-index: 1;
  display: flex; flex-wrap: wrap; gap: 10px 22px;
  justify-content: space-between; align-items: center;
  max-width: 1200px;
  margin: 0 auto;
  padding: 18px 24px 26px;
  border-top: 1px solid var(--glass-line);
}
.foot-bar p { font-size: 12px; color: var(--faint); margin: 0; }

/* Mention de jeu responsable. Elle n'est pas décorative : un produit qui parle
   de probabilités sportives doit dire, visiblement, qu'il n'invite pas à
   parier. Le ton reste sobre — un bandeau d'alerte serait de l'esbroufe. */
.foot-care {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 12px;
  color: var(--warn);
}
.foot-care::before {
  content: '';
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--warn);
  box-shadow: 0 0 10px rgba(255, 194, 77, 0.8);
}

/* Le nom en très grand, presque effacé, tenu par le bas de page. */
.foot-word {
  position: absolute;
  left: 50%; bottom: -.28em;
  transform: translateX(-50%);
  font: 800 clamp(42px, 11.5vw, 158px)/1 var(--display);
  letter-spacing: .04em;
  white-space: nowrap;
  color: transparent;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.055), transparent 78%);
  -webkit-background-clip: text; background-clip: text;
  pointer-events: none;
  user-select: none;
}

/* ------------------------------------------------------------------ */
/* Accès : la scène traverse la porte d'entrée                         */
/* ------------------------------------------------------------------ */

.auth-wrap { position: relative; z-index: 2; overflow: clip; }
/* Une pelouse lointaine derrière le formulaire. Le visiteur vient d'une page
   qui en est couverte : la voir disparaître d'un coup au moment de s'inscrire
   donne l'impression d'avoir changé de site. */
.auth-wrap::before {
  content: '';
  position: absolute;
  left: 50%; bottom: -22%;
  width: 200vw; height: 62%;
  transform: translateX(-50%) perspective(720px) rotateX(66deg);
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.1056) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.1056) 1px, transparent 1px);
  background-size: 82px 82px;
  -webkit-mask-image: radial-gradient(52% 72% at 50% 100%, #000 6%, transparent 74%);
  mask-image: radial-gradient(52% 72% at 50% 100%, #000 6%, transparent 74%);
  animation: avance 8s linear infinite;
  pointer-events: none;
}

.auth-card {
  position: relative;
  background: linear-gradient(168deg, var(--glass-hi), var(--glass));
  border-color: var(--glass-line);
  backdrop-filter: blur(20px);
  box-shadow: 0 50px 120px -44px rgba(0, 0, 0, 1.0), inset 0 1px 0 rgba(255, 255, 255, 0.07);
  animation: monte .6s var(--ease-out) both;
}
@keyframes monte { from { opacity: 0; transform: translateY(18px); } }

/* Trait lumineux au sommet de la carte : le point d'entrée du produit mérite
   d'être signalé autrement que par un rectangle de plus. */
.auth-card::before {
  content: '';
  position: absolute;
  top: -1px; left: 12%; right: 12%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--glow), transparent);
  box-shadow: 0 0 14px rgba(255, 255, 255, 0.0462);
}

.field input, .field select {
  background: rgba(255, 255, 255, 0.035);
  border-color: var(--glass-line);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.plan-pill { transition: transform var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease); }
.plan-pill:hover { transform: translateY(-2px); border-color: var(--glass-line); }
.plan-pill.sel { box-shadow: 0 0 26px -10px rgba(255, 255, 255, 0.0528); }

/* ------------------------------------------------------------------ */
/* Application : le tableau de bord hérite du même vocabulaire         */
/* ------------------------------------------------------------------ */

/* La barre du tableau de bord est déjà translucide ; elle gagne la saturation
   et l'ombre portée du reste, pour que le contenu qui passe dessous se voie
   sans brouiller le texte. */
.appbar {
  background: rgba(6, 9, 13, 0.72);
  backdrop-filter: blur(18px) saturate(1.3);
  border-bottom: 1px solid var(--glass-line);
  box-shadow: 0 18px 40px -34px rgba(0, 0, 0, 1.0);
}
.app-main { position: relative; z-index: 2; }

.account-badge { box-shadow: 0 0 20px -8px rgba(255, 255, 255, 0.0462); }

.sport-tab, .league-chip {
  transition: transform var(--t-fast) var(--ease), color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.sport-tab:hover, .league-chip:hover { transform: translateY(-2px); }
.sport-tab.active { box-shadow: 0 10px 26px -12px rgba(255, 255, 255, 0.0594); }
/* Le cadenas des sports non inclus ne doit pas se soulever : il n'y a rien à
   ouvrir derrière, et l'effet promettrait le contraire. */
.sport-tab.locked:hover { transform: none; }

/* Les cartes de rencontre reprennent le verre de la vitrine. C'est la surface
   que l'abonné regarde tous les jours : elle ne doit pas être la plus pauvre
   du produit. */
.match {
  position: relative;
  background: linear-gradient(168deg, var(--glass-hi), var(--glass));
  border-color: var(--glass-line);
  backdrop-filter: blur(14px);
  box-shadow: 0 26px 70px -40px rgba(0, 0, 0, 0.95), inset 0 1px 0 rgba(255, 255, 255, 0.05);
  transition: transform var(--t) var(--ease), border-color var(--t) var(--ease), box-shadow var(--t) var(--ease);
}
.match:hover {
  transform: translateY(-4px);
  border-color: rgba(255, 255, 255, 0.1716);
  box-shadow: 0 40px 90px -44px rgba(0, 0, 0, 1.0), 0 0 48px -30px rgba(255, 255, 255, 0.033);
}
.match.featured {
  background: linear-gradient(168deg, rgba(255, 255, 255, 0.0462), var(--glass) 60%);
  border-color: rgba(255, 255, 255, 0.0132);
}
/* Une rencontre en cours mérite d'être signalée par autre chose qu'un liseré :
   la pulsation attire l'œil dans une grille de vingt cartes. */
.match.live { animation: enDirect 2.6s ease-in-out infinite; }
@keyframes enDirect {
  0%, 100% { box-shadow: 0 26px 70px -40px rgba(0, 0, 0, 0.95), 0 0 0 0 rgba(255, 122, 69, 0.0); }
  50%      { box-shadow: 0 26px 70px -40px rgba(0, 0, 0, 0.95), 0 0 34px -14px rgba(255, 122, 69, 0.85); }
}

.grid-heading { position: relative; padding-left: 16px; }
.grid-heading::before {
  content: '';
  position: absolute;
  left: 0; top: .28em; bottom: .28em;
  width: 3px;
  border-radius: 3px;
  background: linear-gradient(180deg, var(--glow), transparent);
}

/* Panneau d'analyse : c'est le produit livré, il doit se poser comme tel. */
.sheet-overlay { background: rgba(4, 6, 9, 0.8); backdrop-filter: blur(14px); }
.sheet {
  background: linear-gradient(168deg, rgba(255, 255, 255, 0.07), rgba(16, 19, 14, 0.96));
  border-color: var(--glass-line);
  backdrop-filter: blur(24px);
  box-shadow: 0 60px 140px -46px rgba(0, 0, 0, 1.0), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

/* Le voile du verrou doit finir sur le fond RÉEL de la fiche. Ici c'est un
   verre sombre, pas `--surface` : garder l'aplat par défaut aurait dessiné un
   rectangle plus clair au bas de la zone floutée. */
.verrou { --verrou-fond: rgb(16, 19, 14); }
.verrou-appel {
  background: linear-gradient(168deg, rgba(255, 255, 255, 0.085), rgba(16, 19, 14, 0.985));
  border-color: var(--glass-line);
  backdrop-filter: blur(var(--blur));
}

/* ------------------------------------------------------------------ */
/* Petits écrans                                                       */
/* ------------------------------------------------------------------ */

@media (max-width: 760px) {
  /* La carte estompée derrière la carte du héros suppose une gouttière qui
     n'existe plus ici : elle vient dépasser au-dessus et son texte se lit
     par-dessus le vrai contenu. */

  /* Le nom en filigrane est calé sur la largeur du pied ; sur une colonne il
     recouvre la mention légale au lieu de la porter. */
  .foot-word { display: none; }

  /* Les faisceaux sont dimensionnés en `vw` : à cette largeur ils couvrent
     tout l'écran et le fond vire au vert uni derrière le titre. */
  .beam { width: 78vw; opacity: .6; }

  .foot-in { padding: 44px 24px 24px; }
  .crest-tile { width: 68px; height: 68px; border-radius: 15px; }
  .crest-tile img, .crest-tile .mono-badge { width: 36px; height: 36px; }
  .sport-leagues { min-height: 0; }
}

/* ------------------------------------------------------------------ */
/* Barre de progression de lecture                                     */
/* ------------------------------------------------------------------ */

.progress {
  position: fixed; top: 0; left: 0;
  height: 2px; width: 0;
  background: linear-gradient(90deg, var(--glow), var(--glow-2));
  box-shadow: 0 0 12px rgba(255, 255, 255, 0.0528);
  z-index: 60;
  transition: width 90ms linear;
}

/* ------------------------------------------------------------------ */
/* Respect du réglage système                                          */
/* ------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  .aurora, .beam-l, .beam-r, .pitch, .scan, .orbit-crest,
  .crestwall-row, .ticker-track, .hero h1, .rise > *,
  .cta-pitch, .cta-halo, .sport-live i, .sport-orb::after,
  .sport-card:hover::after, .price-card:hover::before,
  .proof-card:hover::before, .steps li:hover::after,
  .auth-wrap::before, .auth-card, .match.live, .stade {
    animation: none !important;
  }
  /* La vidéo de fond est du mouvement permanent : `animation: none` ne
     l'arrête pas. On la masque et on affiche son image fixe à la place —
     `motion.js` met la lecture en pause pour ne pas décoder dans le vide. */
  video.stade { visibility: hidden; }
  .stage .stade-fixe { display: block; }
  /* Le WebP animé se joue tout seul : le seul moyen de l'arrêter est de ne
     pas l'afficher. La teinte du bandeau est portée par le halo, qui reste. */
  .cta-boucle { display: none; }
  .match:hover, .sport-tab:hover, .league-chip:hover, .plan-pill:hover { transform: none; }
  /* Une rencontre en cours reste signalée, sans pulsation. */
  .match.live { border-color: color-mix(in srgb, var(--bad) 55%, var(--line)); }
  .rise > * { transform: none; }
  .orbit-crest { opacity: .85; }
  .reveal { opacity: 1; translate: none; transition: none; }
  .sport-card:hover, .price-card:hover, .proof-card:hover { transform: none; }
  .seen .ring-gauge .val { transition: none; }
  /* Les barres de distribution restent affichées : elles portent de
     l'information, seule leur croissance est supprimée. */
  .sport-spark i { height: var(--h, 20%); transition: none; }
  .steps::before { transition: none; }
  .btn-brass::after { display: none; }
}

/* Repli fixe du plan vidéo, affiché seulement en mouvement réduit. */
.stade-fixe {
  display: none;
  position: absolute;
  inset: -6% -4%;
  background: url('/assets/scene/stade-nuit.webp') center/cover no-repeat;
  opacity: .78;
  -webkit-mask-image: radial-gradient(120% 92% at 50% 34%, #000 24%, rgba(0, 0, 0, .35) 62%, transparent 88%);
  mask-image: radial-gradient(120% 92% at 50% 34%, #000 24%, rgba(0, 0, 0, .35) 62%, transparent 88%);
}

/* ------------------------------------------------------------------ */

/*
 * Une tuile par compétition, en grille. Le bandeau défilant qui la suit dit
 * « il y en a beaucoup » ; la grille dit « voici lesquelles ». Ce n'est pas
 * la même information, et la seconde est celle qu'on vient chercher.
 *
 * Chaque tuile porte l'accent de son sport en filet supérieur : les six
 * disciplines se repèrent d'un balayage vertical, sans avoir à lire.
 */
.league-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 10px;
  margin-bottom: 34px;
}
@media (max-width: 560px) { .league-grid { grid-template-columns: repeat(2, 1fr); gap: 8px; } }

.league-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 16px 15px 15px;
  border-radius: 14px;
  overflow: hidden;
  background: linear-gradient(168deg, var(--glass-hi), var(--glass));
  border: 1px solid var(--glass-line);
  transition: transform var(--t) var(--ease), border-color var(--t) var(--ease),
              box-shadow var(--t) var(--ease);
}
/* Le filet de sport, en haut. Un trait plutôt qu'un fond teinté : treize
   tuiles à fond coloré feraient une mosaïque, treize filets font un index. */
.league-tile::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: var(--lg, var(--glow));
  opacity: .8;
}
.league-tile:hover {
  transform: translateY(-4px);
  border-color: color-mix(in oklab, var(--lg, var(--glow)) 34%, transparent);
  box-shadow: 0 26px 60px -34px rgba(0, 0, 0, .9);
}

.league-tile-sport {
  font: 700 9.5px/1 var(--mono);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--lg, var(--glow));
}
.league-tile-mark { display: flex; align-items: center; min-height: 30px; }
.league-tile-mark .league-crest img { width: 30px; height: 30px; object-fit: contain; }
.league-tile-mark .league-mark {
  display: inline-grid; place-items: center;
  min-width: 38px; height: 30px;
  padding: 0 9px;
  border-radius: 8px;
  background: color-mix(in oklab, var(--lg, var(--glow)) 16%, transparent);
  border: 1px solid color-mix(in oklab, var(--lg, var(--glow)) 30%, transparent);
  font: 700 11.5px/1 var(--mono);
  letter-spacing: .05em;
  color: var(--text);
}
.league-tile-nom {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.35;
}

@media (prefers-reduced-motion: reduce) { .league-tile:hover { transform: none; } }

/* Le blason dessiné prend la place de la pastille dans les trois endroits où
   des écussons de club apparaissent en nombre. Les tailles diffèrent : un mur
   veut des blasons lisibles, un bandeau des vignettes. */
.crest-tile .crest-badge svg { width: 54px; height: 54px; display: block; }
.orbit-crest .crest-badge svg { width: 28px; height: 28px; display: block; }
.ticker-item .crest-badge svg { width: 18px; height: 18px; display: block; }

/* ------------------------------------------------------------------ */
/* Avis                                                                */
/* ------------------------------------------------------------------ */

.avis-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
}
@media (max-width: 900px) { .avis-grid { grid-template-columns: 1fr; max-width: 560px; } }

.avis-carte {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin: 0;
  padding: 26px 24px;
  border-radius: var(--r-lg);
  background: linear-gradient(168deg, var(--glass-hi), var(--glass));
  border: 1px solid var(--glass-line);
  transition: transform var(--t) var(--ease), border-color var(--t) var(--ease);
}
.avis-carte:hover { transform: translateY(-4px); border-color: var(--brass-line); }

.avis-notes { display: flex; gap: 3px; }
/* Les étoiles sont dessinées et non écrites : le caractère « ★ » dépend de la
   police installée et devient un carré vide sur certains systèmes. */
.avis-etoile { fill: var(--warn); }
.avis-etoile.vide { fill: var(--line); }

.avis-texte {
  margin: 0;
  font-size: 15px;
  line-height: 1.62;
  color: var(--text);
}
/* Guillemets typographiques, posés par la feuille : le texte reste propre
   dans le dictionnaire et se traduit sans emporter sa ponctuation. */
.avis-texte::before { content: '« '; color: var(--faint); }
.avis-texte::after  { content: ' »'; color: var(--faint); }

.avis-qui { display: flex; flex-direction: column; gap: 2px; margin-top: auto; }
.avis-nom { font-size: 13.5px; font-weight: 700; color: var(--text); }
.avis-ou { font-size: 12.5px; color: var(--faint); }

@media (prefers-reduced-motion: reduce) { .avis-carte:hover { transform: none; } }

/* ------------------------------------------------------------------ */
/* Trame d'écussons, en fond de site                                   */
/* ------------------------------------------------------------------ */

/*
 * Le mur défilant occupait une bande entière pour dire une seule chose. Les
 * mêmes écussons servent maintenant de trame derrière l'ensemble du site :
 * on les devine plus qu'on ne les lit.
 *
 * `fixed` et non `absolute` : la couche ne défile pas avec le contenu, ce qui
 * évite de repeindre cent SVG à chaque image de défilement. `pointer-events:
 * none` la rend transparente au clic — sans quoi elle intercepterait tout.
 */
.fond-clubs {
  position: fixed;
  inset: -4vh -4vw;
  z-index: 0;
  pointer-events: none;
  opacity: .5;
}

.fond-crest {
  position: absolute;
  display: block;
  /* Très effacés, et légèrement désaturés : une trame ne doit pas rivaliser
     avec le contenu qu'elle accompagne. Les couleurs de club restent
     reconnaissables, mais en sourdine. */
  opacity: .09;
  filter: saturate(.6);
  animation: respireCrest 14s ease-in-out infinite alternate;
}
/*
 * La trame porte désormais de VRAIES images d'écusson, pas seulement des SVG
 * dessinés. Les deux formes doivent remplir leur case de la même façon : sans
 * cette règle, une image gardait sa taille naturelle — souvent 500 px — et
 * crevait la trame.
 *
 * `object-fit: contain` plutôt que `cover` : un écusson n'est pas une photo,
 * le rogner le mutile.
 */
.fond-crest svg,
.fond-crest img,
.fond-crest .crest-badge { display: block; width: 100%; height: 100%; }
.fond-crest img { object-fit: contain; }

@keyframes respireCrest {
  from { opacity: .05; }
  to   { opacity: .11; }
}

/* Sur fond clair, un écusson à 7 % disparaît complètement : la trame a besoin
   d'un peu plus de présence, et d'un mélange qui la pose sur le papier. */
html:not([data-theme="sombre"]) .fond-crest { opacity: .10; mix-blend-mode: multiply; }
html:not([data-theme="sombre"]) .fond-clubs { opacity: .65; }

@media (max-width: 760px) {
  /* Sur mobile la trame se resserre au point de faire du bruit derrière le
     texte : on la réduit plutôt que de la supprimer. */
  .fond-clubs { opacity: .3; }
}

@media (prefers-reduced-motion: reduce) {
  .fond-crest { animation: none; }
}

/* ------------------------------------------------------------------ */
/* Bandeau des disciplines                                             */
/* ------------------------------------------------------------------ */

.sportband {
  position: relative;
  z-index: 2;
  padding-block: 56px 64px;
  overflow: hidden;
}
.sportband-h { max-width: 1200px; margin: 0 auto 34px; padding-inline: 24px; }
.sportband-h h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(28px, 3.4vw, 40px);
  line-height: 1.12;
  letter-spacing: -.025em;
  margin: 0;
}
.sportband-h h2 em { font-style: normal; color: var(--brass); }

.sportband-piste {
  display: flex;
  width: max-content;
  gap: 14px;
  /* Sens INVERSE du bandeau des compétitions, plus bas. Deux rubans qui
     glissent dans le même sens se lisent comme un seul bloc qui bouge ;
     en sens contraires, chacun garde son identité. */
  animation: defile-sports 34s linear infinite;
}
@keyframes defile-sports {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
.sportband:hover .sportband-piste { animation-play-state: paused; }

.sportband-tuile {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 18px 24px;
  border-radius: var(--r-lg);
  background: linear-gradient(168deg, var(--glass-hi), var(--glass));
  border: 1px solid var(--glass-line);
  white-space: nowrap;
}
/* Filet coloré à gauche : l'accent du sport se lit sans teinter la tuile. */
.sportband-tuile { border-left: 3px solid var(--sc, var(--brass)); }

.sportband-em { font-size: 30px; line-height: 1; }
.sportband-txt { display: flex; flex-direction: column; gap: 3px; }
.sportband-txt b { font-family: var(--display); font-size: 19px; font-weight: 700; letter-spacing: -.02em; }
.sportband-txt i { font-style: normal; font-size: 12.5px; font-weight: 600; color: var(--sc, var(--brass)); }

.sportband-n {
  margin-left: 8px;
  padding-left: 16px;
  border-left: 1px solid var(--line);
  font: 700 22px/1 var(--mono);
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
  .sportband-piste { animation: none; }
}
