:root {
  --bg: #14151a;
  --bg-carte: #1b1c22;
  --bg-carte-hover: #21232a;
  --bordure: #2b2d35;
  --texte: #ececec;
  --texte-discret: #93949e;
  --accent: #ff4655;
  --accent-hover: #ff5c6a;
  --oui: #3ddc84;
  --non: #ff5c6a;
  --idk: #2a2b32;
  --complet: #f5c518;
  --mention-bg: rgba(88, 101, 242, .3);
  --mention-texte: #c9cdfb;
  --strie-table: rgba(255, 255, 255, .025);
  --accent-rgb: 255, 70, 85;
  --non-rgb: 255, 92, 106;
  --bg-carte-rgb: 27, 28, 34;
  --rayon: 12px;
  color-scheme: dark;
}

/* Thème clair (cf. Juste terminé 78) : opt-in explicite via le bouton du
   pied de page, jamais automatique selon les préférences OS - le site
   s'est construit sombre par défaut depuis le début (identité visuelle
   assumée), le clair est une bascule volontaire, mémorisée par appareil
   (localStorage), pas un mode "système". Posé sur <html data-theme="light">
   par app.js. */
:root[data-theme="light"] {
  --bg: #f6f6f8;
  --bg-carte: #ffffff;
  --bg-carte-hover: #eceef2;
  --bordure: #dcdfe4;
  --texte: #1c1d22;
  --texte-discret: #6b6d78;
  --accent: #e0303f;
  --accent-hover: #c92634;
  --oui: #1f9d5c;
  --non: #c92634;
  --idk: #e4e5e9;
  --complet: #c99400;
  --mention-bg: rgba(88, 101, 242, .15);
  --mention-texte: #3b3fb0;
  --strie-table: rgba(0, 0, 0, .03);
  --accent-rgb: 224, 48, 63;
  --non-rgb: 201, 38, 52;
  --bg-carte-rgb: 255, 255, 255;
  color-scheme: light;
}

* { box-sizing: border-box; }

/* Doit rester au-dessus de toute règle posant un display explicite (.bouton,
   .lien-nav, etc.), sinon l'attribut hidden ne cache plus rien. */
[hidden] { display: none !important; }

/* --- Mouvement (Juste terminé 82, rendu décochable sur le site en 128) --
   Historiquement tout vivait dans `@media (prefers-reduced-motion:
   no-preference)`. Problème découvert à l'usage : une media query ne peut
   QUE vérifier l'état réel du système - impossible de la faire dépendre
   d'un attribut posé par app.js, donc le bouton "Réduire les animations"
   du pied de page (Juste terminé 127) n'avait strictement aucun effet
   pour qui avait déjà `prefers-reduced-motion: reduce` au niveau OS (le
   bloc ne s'activait jamais, quoi que dise le site) - **et à l'inverse,
   impossible pour quelqu'un dans ce cas de choisir de VOIR les animations
   via le site**, alors que c'était explicitement demandé ("pas une
   option de l'OS"). Chaque bloc @media a donc été remplacé par un
   sélecteur `html[data-motion="normal"]`, calculé une seule fois en JS
   (app.js, `appliquerPreferenceMouvement()`) à partir du choix explicite
   du site s'il existe (mémorisé en localStorage), sinon de
   `prefers-reduced-motion` comme valeur de départ - mais une fois posé,
   le choix du site est SEUL maître, dans les deux sens (peut aussi bien
   réduire que réactiver malgré l'OS). Les `@keyframes` elles-mêmes restent
   globales (inertes tant que rien ne les référence) ; seul le `animation:`/
   `transition:` qui les déclenche est conditionné au sélecteur. */
@keyframes entree-vue {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
html[data-motion="normal"] .vue:not([hidden]) { animation: entree-vue .3s cubic-bezier(.16, 1, .3, 1); }

/* Sortie de l'ANCIENNE vue juste avant le switch (afficherVue() dans
   app.js retarde le basculement effectif de la durée de cette animation)
   - évite que le changement de vue paraisse instantané/brutal. */
@keyframes sortie-vue {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(-8px); }
}
/* Spécificité (1,3,0), volontairement supérieure à .vue:not([hidden])
   (1,2,0) juste au-dessus (même préfixe `html[data-motion="normal"]` sur
   les deux, l'écart de spécificité entre elles reste donc identique à
   avant) : sans ça, cette dernière règle gagne quand même (l'ancienne vue
   reste "non hidden" pendant les 140ms de sortie, donc les deux
   sélecteurs la matchent) et son animation entree-vue écrase
   silencieusement sortie-vue - c'était le bug "la transition ne marche
   pas" (Juste terminé 85) : la sortie ne jouait jamais, seule l'entrée
   (déjà terminée) se réappliquait sans effet visible. */
html[data-motion="normal"] .vue:not([hidden]).vue-sortie { animation: sortie-vue .14s ease-in forwards; pointer-events: none; }

/* Apparition douce pour un élément créé dynamiquement en JS (message de
   chat, ligne...) - appliqué au cas par cas via la classe .entree-douce,
   jamais sur une liste entièrement reconstruite à chaque rafraîchissement
   (sondages/événements/membres, cf. Juste terminé 18) : ça rejouerait
   l'animation toutes les 8s sur du contenu qui n'a pourtant pas changé,
   l'effet inverse de "dynamiser" recherché ici. Réservé aux endroits où
   seul le contenu VRAIMENT nouveau est ajouté (nouveaux messages de chat,
   déjà ajoutés en incrémental via messages_get.php?apres_id=).  */
@keyframes entree-douce {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
html[data-motion="normal"] .entree-douce { animation: entree-douce .22s ease-out; }

/* Pulsation sur une case qui vient de passer à "complet" (Juste terminé
   91) - appliquée/retirée via JS (crenauxCompletsConnus dans
   chargerDispos()), jamais sur les cases déjà complètes au premier
   affichage (même principe que .entree-douce ci-dessus : uniquement un
   VRAI changement détecté, pas un rejeu à chaque poll). */
@keyframes pulse-complet {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.18); }
  100% { transform: scale(1); }
}
html[data-motion="normal"] .pulse-complet { animation: pulse-complet .7s ease-out; z-index: 2; }

/* Micro-interactions : léger soulèvement au survol sur les surfaces
   cliquables les plus courantes (boutons, cartes de la galerie Valoplant),
   cohérent avec le feedback de pression déjà en place
   (.bouton:active { transform: scale(.96) }, non touché ici). */
html[data-motion="normal"] .bouton,
html[data-motion="normal"] .bouton-carre,
html[data-motion="normal"] .bouton-vote:not(:disabled),
html[data-motion="normal"] .carte-map {
  transition: transform .15s ease, box-shadow .15s ease;
}
html[data-motion="normal"] .bouton:hover,
html[data-motion="normal"] .bouton-carre:hover,
html[data-motion="normal"] .bouton-vote:hover:not(:disabled),
html[data-motion="normal"] .carte-map:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(0, 0, 0, .22);
}
html[data-motion="normal"] .bouton-carre:active,
html[data-motion="normal"] .bouton-vote:active:not(:disabled) { transform: translateY(0) scale(.96); }

/* Filet de sécurité pour tout ce qui n'a PAS été explicitement converti
   ci-dessus (quelques transitions jugées "assez discrètes" pour rester
   actives même en mode réduit à l'origine, cf. Juste terminé 82) : quand
   le site force `data-motion="reduit"`, on coupe quand même tout le
   reste au cas où - `!important` + sélecteur universel pour battre
   n'importe quelle règle plus spécifique définie ailleurs dans ce
   fichier. `animation-duration`/`transition-duration` à quasi-zéro plutôt
   que `animation: none`/`transition: none` : préserve l'état final visé
   par l'animation (ex. un badge qui doit finir opaque) - elle joue quand
   même, juste quasi instantanément, au lieu d'être supprimée platement. */
html[data-motion="reduit"] *,
html[data-motion="reduit"] *::before,
html[data-motion="reduit"] *::after {
  animation-duration: .01ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: .01ms !important;
  scroll-behavior: auto !important;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--texte);
  font-family: 'Rubik', system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.5;
}

h1, h2, .logo, .bouton { font-family: 'Rajdhani', system-ui, sans-serif; }

/* --- En-tête --- */
.entete-site {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .6rem 1rem;
  padding: 1rem 1.5rem;
  background: linear-gradient(180deg, rgba(var(--accent-rgb), .14), transparent 85%);
  border-bottom: 1px solid var(--bordure);
}

/* Wordmark en deux tons (cf. Juste terminé 65) : "Le" discret, "Planning"
   dans l'accent du site — même principe qu'un logotype de marque plutôt
   qu'un simple texte uniforme, sans dépendre d'une image. */
.logo {
  flex-shrink: 0;
  display: inline-flex;
  align-items: baseline;
  gap: .22em;
  font-size: 1.2rem;
  letter-spacing: .02em;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}
.logo-le {
  font-weight: 600;
  color: var(--texte-discret);
}
.logo-planning {
  font-weight: 700;
  color: var(--accent);
}

/* Écran de chargement (Juste terminé 84, vidéo d'intro ajoutée en 90) :
   masque le "envers du décor" du tout premier chargement (page qui se
   construit, identité qui se vérifie) derrière l'animation d'intro plutôt
   que de le laisser transparaître. Visible par défaut - c'est du HTML brut,
   rendu avant même que app.js ne s'exécute, donc rien à faire pour qu'il
   apparaisse immédiatement. app.js le masque une fois l'identité connue ET
   la vidéo terminée (cf. tenterMasquageEcranChargement, avec un filet de
   sécurité si jamais quelque chose bloque). */
.ecran-chargement {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  transition: opacity .4s ease;
}
.ecran-chargement.masque { opacity: 0; pointer-events: none; }
.video-intro { width: 100%; height: 100%; object-fit: cover; }
.logo-chargement { font-size: 1.8rem; letter-spacing: .02em; }
@keyframes pouls-chargement {
  0%, 100% { opacity: 1; }
  50%      { opacity: .55; }
}
html[data-motion="normal"] .logo-chargement { animation: pouls-chargement 1.3s ease-in-out infinite; }

.separateur-vertical { width: 1px; height: 18px; background: var(--bordure); }

/* Sur desktop : une seule rangée, nav-liens et nav-compte étalés dans
   l'espace restant entre le logo et l'identité (avatar/connexion). Sur
   mobile, cf. le média-query plus bas : bascule en menu déroulant. */
.nav-principale {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-width: 0;
}
.nav-liens, .nav-compte { display: flex; align-items: center; gap: 1.1rem; flex-wrap: wrap; font-size: .95rem; }

.entete-droite { display: flex; align-items: center; gap: 1rem; flex-shrink: 0; }

.bouton-menu-mobile {
  display: none;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  color: var(--texte);
  padding: .3rem;
  cursor: pointer;
}

/* En dessous de 860px, trop d'onglets pour tenir sur une seule ligne
   (Calendrier/Valoplant/Chat/Premier/Coach + Teams + Create...) : bascule
   en menu déroulant ouvert par le bouton hamburger, plutôt que de laisser
   la rangée déborder et casser toute la largeur de la page. */
@media (max-width: 860px) {
  .bouton-menu-mobile { display: inline-flex; }
  .nav-principale {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--bg);
    border-bottom: 1px solid var(--bordure);
    padding: .5rem 1.5rem 1rem;
    z-index: 30;
    max-height: 80vh;
    overflow-y: auto;
  }
  .nav-principale.ouvert { display: flex; }
  .nav-liens, .nav-compte { flex-direction: column; align-items: stretch; gap: 0; }
  .nav-liens .lien-nav,
  .nav-compte .lien-nav,
  .nav-compte .lien-discret,
  .nav-compte .bouton-carre {
    width: 100%;
    padding: .8rem 0;
    border-bottom: 1px solid var(--bordure);
    justify-content: flex-start;
    font-size: 1.05rem;
  }
  .nav-compte { margin-top: .4rem; }
  .nav-compte a.lien-discret { display: block; }
}

@media (max-width: 420px) {
  /* Marge de sécurité sur les très petits écrans : "Se connecter avec
     Discord" à côté du logo + hamburger peut serrer, réduit le bouton
     plutôt que de compter sur le retour à la ligne. */
  #lien-login { padding: .45rem .9rem; font-size: .9rem; }
  .logo { font-size: 1rem; }
}

button.lien-discret {
  background: none;
  border: none;
  font: inherit;
  padding: 0;
}

.lien-nav {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  background: none;
  border: none;
  color: var(--texte);
  font-family: 'Rajdhani', system-ui, sans-serif;
  font-weight: 600;
  font-size: 1rem;
  padding: 0;
  cursor: pointer;
  opacity: .85;
}
.lien-nav:hover { opacity: 1; }

#lien-docs { color: var(--texte); }

.avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--bordure);
  cursor: pointer;
}

/* --- Boutons / liens --- */
.bouton {
  display: inline-block;
  padding: .55rem 1.2rem;
  border-radius: 999px;
  border: 1px solid var(--bordure);
  background: var(--bg-carte);
  color: var(--texte);
  font: inherit;
  font-weight: 600;
  font-size: 1rem;
  cursor: pointer;
  text-decoration: none;
  transition: background .15s, transform .1s;
}
.bouton:hover { background: var(--bg-carte-hover); }
.bouton:active { transform: scale(.96); }
.bouton-accent { background: var(--accent); border-color: var(--accent); color: #fff; }
.bouton-accent:hover { background: var(--accent-hover); border-color: var(--accent-hover); }

.bouton-carre {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .45rem .9rem;
  border-radius: 8px;
  border: 1px solid var(--bordure);
  background: var(--bg-carte-hover);
  color: var(--texte);
  font: inherit;
  font-weight: 600;
  font-size: .9rem;
  cursor: pointer;
  transition: background .15s;
}
.bouton-carre:hover { background: var(--bordure); }

.lien-discret { color: var(--texte-discret); text-decoration: none; font-size: .9rem; font-weight: 500; }
.lien-discret:hover { color: var(--texte); }

/* --- Layout principal --- */
main { max-width: 1200px; margin: 0 auto; padding: 1.8rem 1.5rem; }

/* --- Accueil (visiteur non connecté) --- */
.accueil-hero {
  text-align: center;
  padding: 3rem 1rem 2.5rem;
}
.accueil-hero h1 {
  margin: 0 0 1rem;
  font-size: 2.6rem;
  letter-spacing: .05em;
}
.accueil-hero h1 span { color: var(--accent); }
.accueil-accroche {
  max-width: 34rem;
  margin: 0 auto 1.8rem;
  color: var(--texte-discret);
  font-size: 1.05rem;
  line-height: 1.6;
}
.bouton-discord {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  font-size: 1.05rem;
  padding: .75rem 1.5rem;
}

.accueil-features {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1rem;
  margin-top: 1rem;
}
.feature {
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: 1.3rem;
  text-align: center;
}
.feature-icone { font-size: 1.6rem; margin-bottom: .6rem; }
.feature h3 { margin: 0 0 .4rem; font-size: 1rem; }
.feature p { margin: 0; color: var(--texte-discret); font-size: .85rem; line-height: 1.5; }

/* --- Zone équipe (gate) --- */
#zone-equipe h1 { margin: 0 0 .3rem; font-size: 2rem; }
.sous-titre { color: var(--texte-discret); margin: 0 0 1.5rem; }
.erreur { color: var(--non); font-weight: 600; }

.options-equipe {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 1.5rem;
  align-items: stretch;
}
.carte-option {
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: .9rem;
}
.carte-option h2 { margin: 0; font-size: 1.15rem; }
.carte-option input {
  padding: .65rem .8rem;
  border-radius: 8px;
  border: 1px solid var(--bordure);
  background: var(--bg);
  color: var(--texte);
  font: inherit;
}
.carte-option input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.champ-code {
  text-transform: uppercase;
  letter-spacing: .35em;
  font-family: 'Courier New', monospace;
  text-align: center;
}
.carte-option .bouton { margin-top: auto; }
.separateur { align-self: center; color: var(--texte-discret); font-weight: 600; }

@media (max-width: 640px) {
  .options-equipe { grid-template-columns: 1fr; }
  .separateur { display: none; }
}

/* --- Bannière d'équipe (haut de #app-equipe) --- */
.banniere-equipe {
  background-color: var(--bg-carte);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  overflow: hidden;
  margin-bottom: 1.2rem;
}
.banniere-overlay {
  background: linear-gradient(180deg, rgba(20, 21, 26, .25), rgba(20, 21, 26, .85));
  padding: 1.2rem 1.5rem .9rem;
}
.salutation { margin: 0 0 .2rem; color: var(--texte-discret); font-size: .85rem; font-weight: 600; transition: color .15s; }
.banniere-claire .salutation { color: var(--bg); }
.entete-nom-equipe { display: flex; align-items: center; gap: .7rem; }
.banniere-overlay h1 { margin: 0; font-size: 1.5rem; }
.icone-equipe {
  width: 34px;
  height: 34px;
  border-radius: 10px;
  object-fit: cover;
  border: 1px solid var(--bordure);
}

/* --- Contrôles d'upload d'image (bannière/icône équipe, avatar profil) --- */
.controle-banniere,
.controle-avatar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .8rem;
  margin-top: 1.5rem;
}
.controle-banniere label.bouton,
.controle-avatar label.bouton { margin: 0; }

/* --- Webhook Discord (vue Équipe, owner/admin) --- */
.carte-webhook {
  margin-top: 1.5rem;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: 1.1rem 1.3rem;
}
.carte-webhook label { display: block; font-size: .85rem; color: var(--texte-discret); margin-bottom: .6rem; }
.ligne-webhook { display: flex; flex-wrap: wrap; gap: .6rem; }
.ligne-webhook input,
.ligne-webhook select {
  flex: 1;
  min-width: 220px;
  padding: .55rem .7rem;
  border-radius: 8px;
  border: 1px solid var(--bordure);
  background: var(--bg);
  color: var(--texte);
  font: inherit;
}
.ligne-webhook select { flex: 0 1 auto; min-width: 160px; }
.ligne-webhook-verticale { flex-direction: column; align-items: stretch; }
/* Lien généré (spectateur, Juste terminé 114) - même style que les champs
   de .ligne-webhook, juste hors de cette rangée (affiché en dessous, sur
   toute la largeur, une fois le lien produit). */
.champ-lien-genere {
  display: block;
  width: 100%;
  margin-top: .8rem;
  padding: .55rem .7rem;
  border-radius: 8px;
  border: 1px solid var(--bordure);
  background: var(--bg);
  color: var(--texte-discret);
  font: inherit;
  font-size: .8rem;
}

/* --- Vue spectateur (lecture seule, Juste terminé 114) --- */
.entete-spectateur { margin-bottom: 1.5rem; }
.entete-spectateur h1 { margin: 0 0 .3rem; font-size: 1.6rem; }

/* --- Checklist "Premiers pas" (Juste terminé 114) --- */
.liste-onboarding { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .5rem; }
.ligne-onboarding { font-size: .88rem; color: var(--texte); }
.ligne-onboarding.fait { color: var(--texte-discret); text-decoration: line-through; }
.ligne-webhook-verticale input { min-width: 0; }
.ligne-webhook-verticale .bouton { align-self: flex-start; }

.liste-notif-prefs { display: flex; flex-direction: column; gap: .5rem; margin-bottom: .8rem; }
.carte-webhook .liste-notif-prefs .case-notif-pref {
  display: flex;
  align-items: center;
  gap: .6rem;
  font-size: .9rem;
  color: var(--texte);
  margin-bottom: 0;
  cursor: pointer;
}
.case-notif-pref input { flex: 0 0 auto; width: auto; min-width: 0; }

.liste-notifs-programmees { display: flex; flex-direction: column; gap: .5rem; margin-top: 1rem; }
.ligne-notif-programmee {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .8rem;
  background: var(--bg);
  border: 1px solid var(--bordure);
  border-radius: 8px;
  padding: .6rem .8rem;
}
.notif-programmee-titre { font-weight: 600; font-size: .9rem; }
.notif-programmee-meta { color: var(--texte-discret); font-size: .78rem; margin-top: .1rem; }
#statut-webhook { display: block; margin-top: .5rem; }

/* --- Code d'équipe en spoiler (vue Équipe uniquement) --- */
.spoiler {
  font-family: 'Courier New', monospace;
  font-size: .9rem;
  letter-spacing: .2em;
  background: var(--bg-carte-hover);
  border: 1px solid var(--bordure);
  color: transparent;
  text-shadow: 0 0 8px var(--texte);
  padding: .3rem .7rem;
  border-radius: 8px;
  cursor: pointer;
}
.spoiler.revele { color: var(--texte); text-shadow: none; }
.spoiler:hover { background: var(--bordure); }

/* --- Actions du planning (au-dessus de la grille) --- */
.actions-planning {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .8rem;
  margin-bottom: 1.2rem;
}
.infos-semaine { display: flex; flex-direction: column; gap: .2rem; }
.infos-semaine .sous-titre { margin: 0; }
.resume-semaine { font-size: .8rem; color: var(--texte-discret); }

.nav-semaine { display: flex; align-items: center; gap: .5rem; }
.bouton-icone {
  border: 1px solid var(--bordure);
  background: var(--bg-carte);
  color: var(--texte);
  border-radius: 6px;
  width: 26px;
  height: 26px;
  line-height: 1;
  cursor: pointer;
  font-size: .9rem;
}
.bouton-icone:hover { background: var(--bg-carte-hover); }
.badge-lecture-seule {
  display: inline-block;
  margin-top: .2rem;
  font-size: .75rem;
  color: var(--non);
}

.boutons-planning { display: flex; flex-wrap: wrap; gap: .6rem; }
.boutons-planning .bouton { padding: .4rem .9rem; font-size: .85rem; }

.statut-export { margin: -.6rem 0 1rem; font-size: .8rem; color: var(--oui); }

.etat-vide {
  text-align: center;
  color: var(--texte-discret);
  border: 1px dashed var(--bordure);
  border-radius: var(--rayon);
  padding: 1.5rem;
  margin-bottom: 1.2rem;
}
.etat-vide p { margin: 0 0 .3rem; }
.etat-vide p:last-child { margin-bottom: 0; }

/* --- Planning en 3 colonnes : membres | grille | sondages --- */
.planning-layout {
  display: grid;
  grid-template-columns: 190px 1fr 260px;
  gap: 1.2rem;
  align-items: start;
}
.colonne-membres,
.colonne-sondages {
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: 1rem;
}
.colonne-grille { min-width: 0; }   /* laisse .grille-scroll gérer son propre débordement */
.titre-colonne {
  margin: 0 0 .8rem;
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--texte-discret);
}

@media (max-width: 1100px) {
  .planning-layout { grid-template-columns: 1fr; }
}

/* --- Colonne Membres : qui a rempli ses dispos cette semaine --- */
.statut-membres { display: flex; flex-direction: column; gap: .7rem; }
.bouton-relance { display: block; margin-top: .8rem; }

.liste-abonnes-notifs { display: flex; flex-direction: column; gap: .5rem; }
.ligne-abonne-notif { display: flex; align-items: center; gap: .5rem; font-size: .88rem; }
.ligne-abonne-notif .avatar { width: 22px; height: 22px; }
.puce-abonne { flex: 0 0 auto; font-size: .8rem; }
.puce-abonne.oui { color: var(--oui); }
.puce-abonne.non { color: var(--texte-discret); }

.liste-journal-activite {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  max-height: 320px;
  overflow-y: auto;
}
.ligne-journal {
  display: flex;
  flex-wrap: wrap;
  gap: .1rem .6rem;
  font-size: .82rem;
  padding-bottom: .5rem;
  border-bottom: 1px solid var(--bordure);
}
.ligne-journal:last-child { border-bottom: none; padding-bottom: 0; }
.date-journal { flex: 0 0 auto; color: var(--texte-discret); font-variant-numeric: tabular-nums; }
.statut-membre {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .88rem;
  font-weight: 600;
  color: var(--texte);
}
.statut-membre img {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--bordure);
}
/* Grisé UNIQUEMENT pour un joueur suivi qui n'a pas encore rempli - jamais
   par défaut : un coach/gestion listé à part (hors suivi, cf. Juste
   terminé 88) n'a rien à "remplir", le griser laisserait croire à tort
   qu'il est en retard sur quelque chose. */
.statut-membre.non-rempli { color: var(--texte-discret); opacity: .45; }

.panel-colonne {
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: 1rem 1.1rem;
}
.panel-colonne + .panel-colonne { margin-top: 1rem; }
.panel-colonne .titre-colonne { margin-bottom: .6rem; }
.apercu-evenements { display: flex; flex-direction: column; gap: .5rem; }
.ligne-event-apercu {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  font-size: .82rem;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: 8px;
  padding: .5rem .7rem;
}
.event-apercu-titre { font-weight: 600; }
.event-apercu-meta { color: var(--texte-discret); font-size: .78rem; }

/* --- Sondages rapides --- */
.colonne-sondages .form-sondage { flex-direction: column; }
.form-sondage { display: flex; flex-wrap: wrap; gap: .6rem; margin-bottom: 1rem; }
.form-sondage input {
  flex: 1;
  min-width: 220px;
  padding: .55rem .8rem;
  border-radius: 8px;
  border: 1px solid var(--bordure);
  background: var(--bg);
  color: var(--texte);
  font: inherit;
}
.liste-options-sondage { display: flex; flex-direction: column; gap: .5rem; width: 100%; }
.ligne-option-sondage { display: flex; gap: .5rem; align-items: center; }
.ligne-option-sondage input { flex: 1; }
.retirer-option-sondage {
  background: none;
  border: none;
  color: var(--texte-discret);
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  padding: .2rem .5rem;
}
.retirer-option-sondage:hover { color: var(--non); }

.liste-sondages { display: flex; flex-direction: column; gap: .8rem; }
/* Raccourci vers le wizard Scrims depuis l'accueil (Juste terminé 124) -
   demandé en accès direct depuis la vue Dispos, pas seulement depuis
   l'onglet Scrims - réutilise `ouvrirAssistantAnalyserScrim()` telle
   quelle (app.js), le wizard est un élément global du DOM, pas scopé à la
   vue Scrims. */
.bouton-pleine-largeur { display: block; width: 100%; text-align: center; margin-top: 1rem; }
.carte-sondage {
  background: var(--bg);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: 1rem 1.2rem;
}
.sondage-question { font-weight: 600; margin-bottom: .7rem; }
.sondage-votes { display: flex; flex-wrap: wrap; gap: .6rem; }
.bouton-vote {
  position: relative;
  overflow: hidden;
  padding: .4rem 1rem;
  border-radius: 999px;
  border: 1px solid var(--bordure);
  background: transparent;
  color: var(--texte);
  font: inherit;
  font-weight: 600;
  font-size: .85rem;
  cursor: pointer;
}
/* Barre de progression en fond (Juste terminé 92) : largeur pilotée par
   --pourcentage-vote (posée en JS par option), une seule couche plutôt que
   dupliquer la logique de résultat côté CSS. Le texte reste au-dessus
   grâce à .bouton-vote-texte (position relative + z-index), sans quoi
   l'ordre de peinture d'un ::before positionné n'est pas garanti passer
   sous un texte non positionné. Exclue de l'option déjà votée (.actif) :
   son fond plein accent rendrait la barre invisible/redondante. */
.bouton-vote:not(.actif)::before {
  content: '';
  position: absolute;
  inset: 0;
  width: var(--pourcentage-vote, 0%);
  background: rgba(var(--accent-rgb), .18);
  transition: width .3s ease;
}
.bouton-vote-texte { position: relative; z-index: 1; }
.bouton-vote.actif { background: var(--accent); border-color: var(--accent); color: #fff; }
.bouton-vote:disabled { opacity: .5; cursor: not-allowed; }

.champ-date-limite-sondage {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .8rem;
  font-weight: 600;
  color: var(--texte-discret);
  width: 100%;
}
.champ-date-limite-sondage input { flex: 1; min-width: 0; }

.sondage-date-limite { margin: -.4rem 0 .6rem; font-size: .78rem; color: var(--texte-discret); }
.sondage-date-limite.ferme { color: var(--non); font-weight: 600; }
.sondage-pied {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: .8rem;
  padding-top: .6rem;
  border-top: 1px solid var(--bordure);
  font-size: .8rem;
  color: var(--texte-discret);
}
.sondage-relances { display: flex; flex-wrap: wrap; gap: .3rem 1rem; margin-top: .4rem; font-size: .8rem; }

.bouton-danger {
  background: transparent;
  border-color: var(--non);
  color: var(--non);
}
.bouton-danger:hover { background: rgba(var(--non-rgb), .12); }
.bouton:disabled {
  opacity: .4;
  cursor: not-allowed;
}
.bouton:disabled:hover { background: var(--bg-carte); }

/* --- Placeholder "bientôt" --- */
.carte-bientot {
  border: 1px dashed var(--bordure);
  border-radius: var(--rayon);
  padding: 3rem 1.5rem;
  text-align: center;
  color: var(--texte-discret);
}
.emoji-bientot { font-size: 2.5rem; margin-bottom: .5rem; }
.carte-bientot h2 { color: var(--texte); margin: 0 0 .4rem; }
.carte-bientot p { margin: 0; max-width: 32rem; margin-inline: auto; }

/* --- Calendrier --- */
.entete-vue {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .8rem;
  margin-bottom: 1.2rem;
}
.entete-vue .sous-titre { margin: 0; }
.actions-entete-vue { display: flex; flex-wrap: wrap; gap: .6rem; }

.liste-evenements { display: flex; flex-direction: column; gap: .8rem; }

.carte-event {
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: 1.1rem 1.3rem;
}
.carte-event-titre { font-family: 'Rajdhani', system-ui, sans-serif; font-weight: 700; font-size: 1.15rem; }
.carte-event-meta { color: var(--texte-discret); font-size: .9rem; margin-top: .2rem; text-transform: capitalize; }
.carte-event-badges { display: flex; gap: .4rem; margin-top: .5rem; }
.badge {
  display: inline-block;
  font-size: .75rem;
  font-weight: 600;
  padding: .15rem .55rem;
  border-radius: 999px;
  background: var(--bg-carte-hover);
  border: 1px solid var(--bordure);
  color: var(--texte-discret);
}
.carte-event-note { margin: .6rem 0 0; font-size: .9rem; }
.carte-event-pied {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: .8rem;
  padding-top: .6rem;
  border-top: 1px solid var(--bordure);
  font-size: .8rem;
  color: var(--texte-discret);
}

.note-bientot { margin-top: 1.5rem; font-size: .85rem; }

/* --- Valoplant : galerie de maps --- */
.galerie-maps {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 1rem;
}
.carte-map {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--rayon);
  border: 1px solid var(--bordure);
  overflow: hidden;
  padding: 0;
  cursor: pointer;
  background: var(--bg-carte);
}
.carte-map img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .2s; }
.carte-map:hover img { transform: scale(1.06); }
/* Tuile "Map inconnue" de la galerie Scrims (Juste terminé 100) - pas
   d'image dédiée (l'IA n'a pas pu lire la map sur le screenshot), contenu
   centré plutôt que le dégradé bas-de-photo habituel qui n'aurait rien à
   assombrir. */
.carte-map-inconnue { background: var(--bg-carte); display: flex; align-items: center; justify-content: center; }
.carte-map-inconnue .carte-map-overlay { position: static; background: none; padding: 0; align-items: center; text-align: center; }
.carte-map-overlay {
  position: absolute;
  inset: auto 0 0 0;
  background: linear-gradient(180deg, transparent, rgba(20, 21, 26, .92));
  padding: 1.6rem .8rem .6rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .1rem;
}
.carte-map-nom { font-family: 'Rajdhani', system-ui, sans-serif; font-weight: 700; font-size: 1.05rem; color: var(--texte); }
.carte-map-compte { font-size: .75rem; color: var(--texte-discret); }
/* Badge "contient un scrim épinglé" (Juste terminé 112) - coin haut-droit,
   au-dessus du dégradé bas-de-photo utilisé par le nom/compte. */
.badge-map-epingle {
  position: absolute;
  top: .5rem;
  right: .5rem;
  font-size: 1.1rem;
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, .6));
}

/* --- Valoplant : strats d'une map, filtrées par side --- */
.entete-map-strats {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1.2rem;
}
.entete-map-strats h2 { margin: 0; font-size: 1.3rem; flex: 1; }
.toggle-side { display: flex; gap: .4rem; }
.bouton-side {
  padding: .4rem 1.1rem;
  border-radius: 999px;
  border: 1px solid var(--bordure);
  background: transparent;
  color: var(--texte-discret);
  font: inherit;
  font-weight: 600;
  font-size: .85rem;
  cursor: pointer;
}
.bouton-side.actif { background: var(--texte); color: var(--bg); border-color: var(--texte); }

.liste-strats-map {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(420px, 1fr));
  gap: 1rem;
}

.carte-strat {
  display: flex;
  align-items: stretch;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  overflow: hidden;
}
.strat-capture {
  width: 160px;
  flex-shrink: 0;
  display: block;
  height: auto;
  object-fit: cover;
  cursor: zoom-in;
}
.strat-infos {
  flex: 1;
  min-width: 0;
  padding: 1rem 1.1rem;
}
.strat-titre { font-weight: 700; }
.strat-composition { font-size: .8rem; color: var(--texte-discret); margin-top: .2rem; }
.strat-badges { display: flex; gap: .4rem; margin-top: .5rem; }
.badge-testee { color: var(--oui); border-color: var(--oui); }
.badge-approuvee { color: var(--complet); border-color: var(--complet); }
.badge-individuel { color: var(--complet); border-color: var(--complet); }
.strat-note { font-size: .85rem; margin: .6rem 0 0; overflow-wrap: break-word; }
.strat-pied {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  margin-top: .8rem;
  padding-top: .6rem;
  border-top: 1px solid var(--bordure);
  font-size: .78rem;
  color: var(--texte-discret);
}
.strat-actions { display: flex; flex-wrap: wrap; gap: .6rem .8rem; }

@media (max-width: 640px) {
  /* Sans ça, minmax(420px, 1fr) force chaque carte à au moins 420px de
     large — plus large que l'écran lui-même sur un téléphone, ce qui fait
     déborder toute la page horizontalement. */
  .liste-strats-map { grid-template-columns: 1fr; }
  .carte-strat { flex-direction: column; }
  .strat-capture { width: 100%; max-height: 180px; }
}

/* --- Scrims : screenshot de scoreboard analysé par IA (Juste terminé 95) --- */
.liste-scrims { display: flex; flex-direction: column; gap: 1rem; }
.carte-scrim {
  display: flex;
  align-items: stretch;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-left: 3px solid var(--bordure);
  border-radius: var(--rayon);
  overflow: hidden;   /* la miniature respecte les coins arrondis de la carte */
}
/* Miniature du screenshot (Juste terminé 118), même principe que
   .strat-capture pour Valoplant - juste plus étroite, cette carte reste
   avant tout une ligne de stats compacte, pas une vignette. */
.scrim-miniature {
  width: 100px;
  flex-shrink: 0;
  display: block;
  height: auto;
  object-fit: cover;
  cursor: zoom-in;
}
.scrim-contenu {
  flex: 1;
  min-width: 0;
  padding: 1rem 1.2rem;
}
@media (max-width: 640px) {
  .carte-scrim { flex-direction: column; }
  .scrim-miniature { width: 100%; max-height: 140px; }
}
/* Résultat (Juste terminé 100, façon Premier - cf. .carte-match) : calculé
   côté serveur (scrims_get.php), jamais deviné ici - repose entièrement
   sur notre_equipe (Juste terminé 99), absent si inconnu. */
.carte-scrim.scrim-victoire { border-left-color: var(--oui); }
.carte-scrim.scrim-defaite { border-left-color: var(--non); }
/* Épinglé (Juste terminé 110) : coexiste avec la couleur de résultat
   ci-dessus (qui reste sur border-left) - un léger fond teinté accent
   plutôt qu'une 2e bordure qui entrerait en conflit visuel. */
.carte-scrim.scrim-epingle {
  background: rgba(var(--accent-rgb), .06);
  border-color: rgba(var(--accent-rgb), .35);
}
.bouton-epingle-scrim {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  padding: 0;
  opacity: .3;
  filter: grayscale(1);
}
.bouton-epingle-scrim:hover { opacity: .7; }
.bouton-epingle-scrim.actif { opacity: 1; filter: none; }
.resultat-scrim { font-weight: 700; font-size: .85rem; }
.scrim-victoire .resultat-scrim { color: var(--oui); }
.scrim-defaite .resultat-scrim { color: var(--non); }
.entete-scrim {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: .6rem;
  font-weight: 600;
  margin-bottom: .7rem;
}
.corps-scrim { display: flex; gap: 1rem; align-items: flex-start; flex-wrap: wrap; }
.miniature-scrim {
  width: 160px;
  border-radius: 8px;
  border: 1px solid var(--bordure);
  object-fit: cover;
}
.corps-scrim > .defilement-horizontal { flex: 1; min-width: 260px; }
.defilement-horizontal { overflow-x: auto; }
@media (max-width: 640px) {
  .miniature-scrim { width: 100%; max-height: 200px; }
}
/* Formulaire de correction manuelle d'un scrim (Juste terminé 99) - plus
   large que la boîte de dialogue par défaut (32rem, cf. règle générique
   dialog{}), le tableau de 8 colonnes par joueur a besoin de place. Classe
   partagée `.table-joueurs-editable` (Juste terminé 103) : la même table
   (mêmes classes de champs `.champ-joueur-*`) sert à la fois au formulaire
   "Modifier" (post-enregistrement) et à l'étape de vérification du nouvel
   assistant d'analyse (avant tout enregistrement), pour ne pas dupliquer la
   fonction JS qui construit une ligne. */
#dialogue-modifier-scrim { max-width: 60rem; }
.table-joueurs-editable input,
.table-joueurs-editable select {
  width: 100%;
  min-width: 3.2rem;
  padding: .3rem .4rem;
  border-radius: 6px;
  border: 1px solid var(--bordure);
  background: var(--bg);
  color: var(--texte);
  font: inherit;
  font-size: .82rem;
}
.table-joueurs-editable .champ-joueur-pseudo,
.table-joueurs-editable .champ-joueur-agent { min-width: 7rem; }
/* Confirmation visuelle du fichier choisi avant l'envoi (Juste terminé 97,
   bouton de retrait ajouté en 103) : l'input de fichier est caché (label
   stylé en bouton à la place, cf. plus haut), donc rien ne montrait qu'une
   sélection avait bien eu lieu - aperçu + nom de fichier posés au `change`
   de l'input, cf. app.js. */
.apercu-scrim-conteneur { display: flex; align-items: center; gap: .6rem; margin-top: .6rem; }
.apercu-scrim-conteneur img { width: 70px; height: 70px; object-fit: cover; border-radius: 8px; border: 1px solid var(--bordure); }
.bouton-retirer-fichier {
  margin-left: auto;
  background: none;
  border: 1px solid var(--bordure);
  border-radius: 6px;
  color: var(--texte-discret);
  cursor: pointer;
  padding: .3rem .55rem;
  font-size: .9rem;
  line-height: 1;
}
.bouton-retirer-fichier:hover { color: var(--non); border-color: var(--non); }

.bouton-miniature-scrim {
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  flex-shrink: 0;
}
.bouton-miniature-scrim .miniature-scrim { display: block; }

/* Deux miniatures côte à côte dans le détail d'un scrim (Juste terminé 101)
   quand le screenshot Overview optionnel a été fourni en plus du leaderboard
   obligatoire - repasse à la ligne sur petit écran comme le reste du projet. */
.images-detail-scrim { display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem; }

/* Bouton "+ Analyser un scrim" au-dessus de la galerie par map (Juste
   terminé 103) - remplace l'ancien onglet "Ajouter un scrim" séparé, la
   vue Historique/galerie est maintenant la seule vue de la page, l'upload
   se fait dans un assistant modal dédié (.dialogue-analyser-scrim). */
.entete-scrims-historique {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .8rem 1.2rem;
  margin-bottom: 1rem;
}

/* Assistant "Analyser un scrim" (Juste terminé 103) - remplace l'ancien
   formulaire simple qui écrivait directement en base : ici RIEN n'est
   enregistré tant que l'étape de vérification n'est pas confirmée
   (scrim_analyser.php ne fait plus qu'analyser, scrim_enregistrer.php
   écrit) - une analyse ratée/mal reconnue ne laisse donc plus jamais de
   scrim buggé dans l'historique à devoir retrouver et corriger après coup. */
/* Juste terminé (123) : le wizard forçait à scroller TOUTE la boîte de
   dialogue pour atteindre les boutons Enregistrer/Recommencer une fois la
   table de 10 joueurs (étape vérification) ou la liste de parties Riot ID
   (étape upload) pleinement affichées. Passé en flex column plutôt que
   `overflow-y: auto` sur toute la boîte : titre/champs généraux/boutons
   restent toujours visibles, seule la zone qui peut grandir sans borne
   (table des joueurs, liste de parties Riot ID) défile dans son propre
   espace contenu - "tout sur un écran" quand ça tient, un scroll localisé
   à cette zone précise sinon (les deux pistes demandées, pas l'une ou
   l'autre : la première quand le contenu est court, la seconde sinon). */
.dialogue-analyser-scrim {
  max-width: 900px;
  width: 92vw;
  max-height: 90vh;
  overflow: hidden;
  padding: 1.5rem;
  /* Fond légèrement transparent + flou plutôt que la carte pleinement
     opaque héritée de la règle générique `dialog{}` - demandé pour un
     rendu moins "bloc plein" une fois le vrai centrage restauré ci-dessus
     (cf. Juste terminé 124). `backdrop-filter` s'applique à ce qui est
     DERRIÈRE la boîte de dialogue (le fond de page assombri par
     `dialog::backdrop`), pas au contenu du formulaire lui-même. */
  background: rgba(var(--bg-carte-rgb), .9);
  backdrop-filter: blur(6px);
}
/* Bug réel corrigé (Juste terminé 125) : `display: flex` posé directement
   sur `.dialogue-analyser-scrim` (sans le conditionner à `[open]`) restait
   actif MÊME dialog fermée - une règle d'auteur l'emporte toujours sur la
   règle du navigateur `dialog:not([open]) { display: none; }` (l'origine
   de la règle prime sur la spécificité dans la cascade, cf. Juste terminé
   124 pour la même mécanique côté `position`). Résultat concret confirmé
   par capture d'écran : le wizard restait visible en permanence, sur
   toutes les vues, impossible à fermer. `display: flex` doit donc être
   conditionné à `[open]` pour ne s'appliquer QUE quand la dialog est
   réellement ouverte - fermée, elle retombe sur `display: none` du
   navigateur, plus jamais écrasé. */
.dialogue-analyser-scrim[open] {
  display: flex;
  flex-direction: column;
}
#etape-analyser-upload,
#etape-analyser-verification {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1;
}
#etape-analyser-upload h2 { margin-top: 0; }
#liste-riot-scrims { flex: 1; min-height: 0; overflow-y: auto; }
#etape-analyser-upload > *:not(#liste-riot-scrims) { flex-shrink: 0; }
#etape-analyser-verification .defilement-horizontal {
  flex: 1;
  min-height: 6rem;
  overflow-y: auto;
}
.contenu-verification-scrim > *:not(.defilement-horizontal) { flex-shrink: 0; }

/* Récupération directe via Riot ID, sans screenshot (Juste terminé 120). */
.separateur-ou {
  text-align: center;
  color: var(--texte-discret);
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  margin: 1.2rem 0 .8rem;
}
#liste-riot-scrims { display: flex; flex-direction: column; gap: .5rem; margin-top: .8rem; }
.ligne-match-riot-scrim {
  display: block;
  width: 100%;
  text-align: left;
  padding: .6rem .9rem;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  color: var(--texte);
  font-family: inherit;
  font-size: .85rem;
  cursor: pointer;
}
.ligne-match-riot-scrim:hover:not(:disabled) { background: var(--bg-carte-hover); }
.ligne-match-riot-scrim:disabled { opacity: .5; cursor: not-allowed; }

/* Étape de vérification : image du leaderboard tout juste analysé en fond,
   assombrie, derrière le formulaire éditable - donne le contexte visuel
   sans reprendre toute la largeur avec l'image comme dans le détail d'un
   scrim déjà enregistré. */
#etape-analyser-verification { position: relative; }
.fond-verification-scrim {
  position: absolute;
  inset: -1.5rem;
  background-size: cover;
  background-position: center;
  z-index: 0;
}
.fond-verification-scrim::after {
  content: '';
  position: absolute;
  inset: 0;
  /* Assombrit toujours vers le sombre, peu importe le thème actif - même
     convention que les overlays de bannière (Juste terminé 78) : ça
     assombrit une photo, pas une surface de page, donc pas theme-aware. */
  background: rgba(20, 21, 26, .88);
  backdrop-filter: blur(2px);
}
.contenu-verification-scrim {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1;
}
.contenu-verification-scrim h2 { margin-top: 0; }
.avertissement-scrim {
  background: rgba(var(--non-rgb), .12);
  border: 1px solid var(--non);
  border-radius: var(--rayon);
  padding: .7rem .9rem;
  font-size: .85rem;
  margin: 0 0 1rem;
}

/* Lightbox dédiée au screenshot d'un scrim (Juste terminé 96) - remplace un
   ancien target="_blank" qui laissait sans moyen évident de "sortir" de
   l'image, surtout en PWA installée (pas de barre d'onglets à fermer). Plus
   simple que la lightbox "page" de Valoplant (juste l'image + un bouton
   fermer) : pas besoin du bloc d'infos qu'a une strat. */
.dialogue-lightbox-scrim {
  max-width: 95vw;
  max-height: 90vh;
  padding: 0;
  border: none;
  background: transparent;
}
.dialogue-lightbox-scrim::backdrop { background: rgba(0, 0, 0, .75); }
.dialogue-lightbox-scrim img { display: block; max-width: 95vw; max-height: 90vh; border-radius: var(--rayon); }
.bouton-fermer-lightbox {
  position: absolute;
  top: -2.2rem;
  right: 0;
  background: none;
  border: none;
  color: #fff;
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
}
.bouton-fermer-lightbox:hover { color: var(--non); }

/* Barre de progression de l'upload/analyse d'un scrim (Juste terminé 96) :
   largeur réelle pendant l'envoi (pilotée par xhr.upload.onprogress, un
   vrai pourcentage) ; passe en "indéterminée" (balayage animé) une fois
   l'envoi fini, le temps de l'appel à l'IA - qui n'expose aucun signal de
   progression réel à afficher. */
.barre-progression {
  height: 6px;
  border-radius: 999px;
  background: var(--idk);
  overflow: hidden;
  margin-top: .6rem;
}
.remplissage-progression {
  height: 100%;
  width: 0;
  background: var(--accent);
  transition: width .2s ease;
}
@keyframes balayage-progression-indeterminee {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(400%); }
}
html[data-motion="normal"] .remplissage-progression.indeterminee {
  width: 25% !important;
  transition: none;
  animation: balayage-progression-indeterminee 1.1s ease-in-out infinite;
}
/* Pas d'animation de balayage en mode réduit : reste simplement plein, le
   texte de statut à côté ("Analyse par IA en cours...") porte déjà
   l'information. */
html[data-motion="reduit"] .remplissage-progression.indeterminee { width: 100%; }

/* --- Lightbox : vue "page" plein écran d'une strat (screenshot + infos) --- */
.dialogue-lightbox {
  max-width: 1100px;
  width: 90vw;
  padding: 0;
  overflow: visible;
}
.fermer-lightbox {
  position: absolute;
  top: .5rem;
  right: .7rem;
  background: none;
  border: none;
  color: var(--texte);
  font-size: 1.8rem;
  line-height: 1;
  cursor: pointer;
  z-index: 2;
}
.fermer-lightbox:hover { color: var(--non); }
.lightbox-contenu {
  display: flex;
  align-items: stretch;
  max-height: 85vh;
}
.lightbox-contenu img {
  max-width: 58%;
  max-height: 85vh;
  object-fit: contain;
  display: block;
  background: var(--bg);
  border-radius: var(--rayon) 0 0 var(--rayon);
}
.lightbox-infos {
  flex: 1;
  min-width: 280px;
  max-height: 85vh;
  overflow-y: auto;
}
@media (max-width: 800px) {
  .lightbox-contenu { flex-direction: column; max-height: 90vh; overflow-y: auto; }
  .lightbox-contenu img { max-width: 100%; max-height: 50vh; border-radius: var(--rayon) var(--rayon) 0 0; }
  .lightbox-infos { max-height: none; overflow-y: visible; }
}

.liste-versions { display: flex; flex-direction: column; gap: .6rem; max-height: 50vh; overflow-y: auto; }
.ligne-version {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: .8rem;
  padding: .6rem 0;
  border-bottom: 1px solid var(--bordure);
  font-size: .85rem;
}
.ligne-version:last-child { border-bottom: none; }

/* --- Profil --- */
.carte-profil {
  display: flex;
  align-items: center;
  gap: 1.3rem;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: 1.3rem;
}
.avatar-grand { width: 72px; height: 72px; border-radius: 50%; object-fit: cover; border: 1px solid var(--bordure); }
.infos-profil h2 { margin: 0 0 .6rem; font-size: 1.3rem; }
.champ-role-valorant {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  font-size: .8rem;
  font-weight: 600;
  color: var(--texte-discret);
}
.champ-role-valorant select {
  padding: .5rem .7rem;
  border-radius: 8px;
  border: 1px solid var(--bordure);
  background: var(--bg);
  color: var(--texte);
  font: inherit;
  font-weight: 400;
  width: fit-content;
}
.confirmation { margin: .5rem 0 0; color: var(--oui); font-size: .85rem; font-weight: 600; }
.stats-presence { margin: .5rem 0 0; color: var(--texte-discret); font-size: .85rem; }
/* Chiffres animés en comptage (Juste terminé 91, Profil) - largeur stable
   pendant l'animation, les chiffres n'ont pas tous la même largeur en
   proportionnel (évite un léger tremblement du texte qui suit). */
.valeur-comptage { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--texte); }

.champ-joue-aussi {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .8rem;
  font-weight: 600;
  color: var(--texte-discret);
  margin-top: .5rem;
  cursor: pointer;
}
.champ-joue-aussi input { width: auto; }

.puce-joue-aussi {
  display: inline-block;
  margin-top: .2rem;
  padding: .1rem .5rem;
  border-radius: 999px;
  background: rgba(var(--accent-rgb), .12);
  color: var(--accent);
  font-size: .7rem;
  font-weight: 600;
}

/* --- Équipe --- */
.composition-equipe {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
  margin-bottom: 1.2rem;
}
.bloc-assiduite { margin-bottom: 1.2rem; }
.bloc-assiduite .titre-colonne { margin-bottom: .5rem; }
.role-comp {
  display: flex;
  align-items: center;
  gap: .4rem;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: 999px;
  padding: .35rem .8rem;
  font-size: .85rem;
}
.role-comp-nombre { font-family: 'Rajdhani', system-ui, sans-serif; font-weight: 700; font-size: 1rem; color: var(--oui); }
.role-comp-manquant { border-color: var(--complet); }
.role-comp-manquant .role-comp-nombre { color: var(--complet); }
.role-comp-discret { color: var(--texte-discret); font-size: .8rem; }

.liste-membres-equipe { display: flex; flex-direction: column; gap: .6rem; margin-bottom: 1.5rem; }
.ligne-membre {
  display: flex;
  align-items: center;
  gap: .9rem;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: .7rem 1rem;
}
.infos-membre { flex: 1; }
.pseudo-membre { font-weight: 600; }
.role-valorant-membre { font-size: .8rem; color: var(--texte-discret); }
.champ-riot-pseudo-membre {
  margin-top: .3rem;
  padding: .25rem .5rem;
  border-radius: 6px;
  border: 1px solid var(--bordure);
  background: var(--bg);
  color: var(--texte);
  font: inherit;
  font-size: .78rem;
  max-width: 10rem;
}
.stats-presence-membre { font-size: .75rem; color: var(--texte-discret); }
.serie-membre { color: var(--complet); font-weight: 600; }
.controle-role select {
  padding: .35rem .6rem;
  border-radius: 8px;
  border: 1px solid var(--bordure);
  background: var(--bg);
  color: var(--texte);
  font: inherit;
  font-size: .85rem;
}

.carte-code-equipe {
  display: flex;
  align-items: center;
  gap: .7rem;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: 1rem 1.2rem;
}
.carte-code-equipe .sous-titre { margin: 0; }

/* --- Dispos --- */
.legende {
  display: flex;
  flex-wrap: wrap;
  gap: 1.2rem;
  margin-bottom: 1.2rem;
  font-size: .85rem;
  color: var(--texte-discret);
}
.legende span { display: inline-flex; align-items: center; gap: .4rem; }

/* --- Vue Coach : dispos détaillées par joueur, groupées par jour --- */
.tableau-coach { display: flex; flex-direction: column; gap: 1.5rem; }
/* Une table à 6-8 colonnes joueurs ne rentre pas sur un téléphone : elle
   défile horizontalement dans son propre bloc plutôt que de faire déborder
   toute la page (même logique que .grille-scroll pour le planning). */
.jour-coach { overflow-x: auto; }
.jour-coach h3 {
  font-family: 'Rajdhani', system-ui, sans-serif;
  font-size: 1rem;
  margin: 0 0 .5rem;
  color: var(--texte-discret);
}
.table-coach { border-collapse: collapse; width: 100%; }
.table-coach th, .table-coach td {
  padding: .3rem .5rem;
  text-align: center;
  border-bottom: 1px solid var(--bordure);
}
.table-coach thead th { padding-bottom: .5rem; }
.table-coach tbody th {
  text-align: left;
  font-weight: 400;
  color: var(--texte-discret);
  font-size: .8rem;
  white-space: nowrap;
}
.avatar-coach { width: 24px; height: 24px; border-radius: 50%; object-fit: cover; }
.table-coach .pastille { margin: 0 auto; }
.cellule-coach-cliquable { cursor: pointer; border-radius: 6px; transition: background .12s; }
.cellule-coach-cliquable:hover { background: var(--bg-carte-hover); }
.pastille-entretien { box-shadow: 0 0 0 2px var(--complet); }
.pastille { width: .8rem; height: .8rem; border-radius: 3px; display: inline-block; background: var(--idk); }
.pastille.oui { background: var(--oui); }
.pastille.non { background: var(--non); }
.pastille.complet { background: var(--idk); position: relative; }
.pastille.complet::after {
  content: '★';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .6rem;
  color: var(--complet);
}
.pastille.quasi-complet { background: var(--idk); position: relative; }
.pastille.quasi-complet::after {
  content: '☆';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .6rem;
  color: var(--complet);
}

/* --- Vue Premier : équipe, classement, matchs récents --- */
.apercu-premier { display: flex; flex-direction: column; gap: .3rem; }
.entete-premier { display: flex; align-items: center; gap: .6rem; margin-bottom: 1rem; }
.icone-premier { width: 32px; height: 32px; border-radius: 8px; object-fit: cover; }
.apercu-premier h3 {
  font-family: 'Rajdhani', system-ui, sans-serif;
  font-size: 1.3rem;
  margin: 0;
}
.titre-colonne-suite { margin: 1.4rem 0 .6rem; }

.stats-premier-grille { display: flex; flex-wrap: wrap; gap: .6rem; margin: .3rem 0 .2rem; }
.stat-premier {
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: .5rem .9rem;
  min-width: 84px;
  text-align: center;
}
.stat-premier-valeur {
  display: block;
  font-family: 'Rajdhani', system-ui, sans-serif;
  font-weight: 700;
  font-size: 1.15rem;
}
.stat-premier-label {
  display: block;
  font-size: .7rem;
  color: var(--texte-discret);
  text-transform: uppercase;
  letter-spacing: .03em;
  margin-top: .1rem;
}

.liste-agents-joueurs { display: flex; flex-direction: column; gap: .5rem; margin-top: .6rem; }
.carte-agents-joueur {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .6rem;
  padding: .55rem .8rem;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
}
.carte-agents-joueur .nom-joueur-agents {
  font-family: 'Rajdhani', system-ui, sans-serif;
  font-weight: 700;
  min-width: 100px;
}
.puces-agents-joueur { display: flex; flex-wrap: wrap; gap: .4rem; }
.puce-agent-joueur {
  display: inline-flex;
  align-items: baseline;
  gap: .3rem;
  padding: .15rem .65rem;
  border-radius: 999px;
  font-size: .8rem;
  font-weight: 600;
  background: rgba(var(--accent-rgb), .12);
  color: var(--accent);
}
.puce-agent-joueur.secondaire {
  background: var(--bg);
  color: var(--texte-discret);
  border: 1px solid var(--bordure);
}
.puce-agent-joueur .compte-agent-joueur { font-weight: 400; opacity: .8; }

.liste-stats-maps { display: flex; flex-direction: column; gap: .7rem; margin-top: .6rem; }
.carte-stat-map {
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: .8rem 1rem;
}
.entete-stat-map {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .6rem;
  margin-bottom: .5rem;
}
.entete-stat-map .nom-map-stat {
  font-family: 'Rajdhani', system-ui, sans-serif;
  font-weight: 700;
  font-size: 1.05rem;
  text-transform: uppercase;
  letter-spacing: .02em;
}
.entete-stat-map .score-map-stat { font-size: .85rem; color: var(--texte-discret); }
.barre-victoire-map {
  height: 8px;
  border-radius: 999px;
  background: rgba(var(--non-rgb), .18);
  overflow: hidden;
  margin-bottom: .6rem;
}
.barre-victoire-map .remplissage-victoire-map {
  height: 100%;
  background: linear-gradient(90deg, var(--accent), #ff8a70);
  border-radius: 999px;
}
.compos-stat-map { display: flex; flex-wrap: wrap; gap: .4rem; margin-bottom: .5rem; }
.puce-compo-map {
  font-size: .75rem;
  padding: .15rem .55rem;
  border-radius: 999px;
  background: var(--bg);
  border: 1px solid var(--bordure);
  color: var(--texte-discret);
}
.clutch-stat-map { font-size: .8rem; color: var(--texte-discret); margin: 0; }
.clutch-stat-map strong { color: var(--texte); }

.leaderboard-premier { display: flex; flex-direction: column; gap: .3rem; }
.ligne-leaderboard {
  display: flex;
  align-items: center;
  gap: .8rem;
  padding: .4rem .7rem;
  border-radius: 8px;
  font-size: .85rem;
}
.ligne-leaderboard.leaderboard-nous { background: var(--bg-carte-hover); font-weight: 700; }
.leaderboard-rang { min-width: 40px; color: var(--texte-discret); }
.leaderboard-nom { flex: 1; }
.leaderboard-points { color: var(--texte-discret); font-size: .8rem; }

.liste-matchs { display: flex; flex-direction: column; gap: .5rem; }
.carte-match {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .6rem .9rem;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-left: 3px solid var(--bordure);
  border-radius: var(--rayon);
  padding: .6rem .9rem;
}
.match-details { min-width: 140px; }
.carte-match.match-victoire { border-left-color: var(--oui); }
.carte-match.match-defaite { border-left-color: var(--non); }
.match-resultat { font-weight: 700; font-size: .85rem; min-width: 70px; }
.match-victoire .match-resultat { color: var(--oui); }
.match-defaite .match-resultat { color: var(--non); }
.match-details { font-size: .85rem; flex: 1; }
.match-meta { color: var(--texte-discret); font-size: .78rem; margin-top: .1rem; }
.carte-match .lien-discret { flex-shrink: 0; }

.groupe-playoff { margin-bottom: 1rem; }
.groupe-playoff .sous-titre { margin: 0 0 .4rem; font-weight: 700; }

.graphique-premier, .graphique-ligne { width: 100%; height: auto; max-width: 560px; display: block; }

/* --- Modale "Détails" d'un match Premier --- */
.dialogue-match-detail {
  max-width: 900px;
  width: 90vw;
  max-height: 85vh;
  overflow-y: auto;
}
.contenu-match-detail h2 { margin: 0 0 .2rem; }
.entete-match-detail { margin-bottom: 1.2rem; }
.score-match-detail {
  font-family: 'Rajdhani', system-ui, sans-serif;
  font-size: 2rem;
  font-weight: 700;
  margin: .1rem 0 .4rem;
  letter-spacing: .02em;
}
.score-match-detail .score-red { color: var(--non); }
.score-match-detail .score-blue { color: #5c9df5; }
/* Les tables Round par round/Spike/Économie ont beaucoup de colonnes :
   chaque panel défile horizontalement dans son coin plutôt que de forcer
   toute la modale (donc la page) à s'élargir sur un téléphone. */
.panel-match-detail { overflow-x: auto; }
.bloc-equipe-match {
  margin-bottom: 1.2rem;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: 1rem 1.1rem;
  border-top: 3px solid var(--bordure);
}
.bloc-equipe-match.equipe-red { border-top-color: var(--non); }
.bloc-equipe-match.equipe-blue { border-top-color: #5c9df5; }
.bloc-equipe-match h4 {
  font-family: 'Rajdhani', system-ui, sans-serif;
  font-size: 1.05rem;
  font-weight: 700;
  margin: 0 0 .7rem;
  color: var(--texte);
  text-transform: uppercase;
  letter-spacing: .03em;
}
.table-match-detail { border-collapse: collapse; width: 100%; font-size: .85rem; }
.table-match-detail th, .table-match-detail td {
  padding: .55rem .7rem;
  text-align: left;
  border-bottom: 1px solid var(--bordure);
}
.table-match-detail th {
  color: var(--texte-discret);
  font-weight: 700;
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .04em;
}
.table-match-detail td:first-child { font-weight: 600; }
.table-match-detail { margin-bottom: 1rem; }
.table-match-detail tbody tr:nth-child(even) { background: var(--strie-table); }
.table-match-detail tbody tr:hover { background: var(--bg-carte-hover); }
.badge-vainqueur-round, .badge-equipe-couleur {
  display: inline-block;
  padding: .15rem .55rem;
  border-radius: 999px;
  font-size: .75rem;
  font-weight: 700;
}
.badge-vainqueur-round.red, .badge-equipe-couleur.red { background: rgba(var(--non-rgb), .15); color: var(--non); }
.badge-vainqueur-round.blue, .badge-equipe-couleur.blue { background: rgba(92, 157, 245, .15); color: #5c9df5; }
.valeur-absente { color: var(--texte-discret); font-style: italic; }

/* Carte des kills (Juste terminé 119) - panel "Carte des kills" du détail
   d'un match Premier : mini-carte + points de kill round par round. */
.select-round-kills {
  display: block;
  width: 100%;
  max-width: 320px;
  margin-bottom: .8rem;
  padding: .5rem .7rem;
  background: var(--bg);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  color: var(--texte);
  font-family: inherit;
}
.conteneur-carte-kills {
  max-width: 480px;
  margin: 0 auto 1rem;
}
.canvas-carte-kills {
  width: 100%;
  height: auto;
  display: block;
  border-radius: var(--rayon);
  border: 1px solid var(--bordure);
}
.legende-carte-kills {
  font-size: .82rem;
  color: var(--texte-discret);
  padding-left: 1.3rem;
  display: flex;
  flex-direction: column;
  gap: .3rem;
}

/* Détail d'un scrim (Juste terminé 116) : un bloc par équipe au lieu d'un
   seul tableau à 11 colonnes, catégories groupées dans l'en-tête, plutôt
   que tout mettre à plat. */
.blocs-equipes-scrim { display: flex; flex-wrap: wrap; gap: 1rem; }
.blocs-equipes-scrim .bloc-equipe-match { flex: 1 1 380px; margin-bottom: 0; }
.table-match-detail th.debut-categorie, .table-match-detail td.debut-categorie {
  border-left: 2px solid var(--bordure);
}
.econ-positif { color: var(--oui); font-weight: 700; }
.econ-negatif { color: var(--non); font-weight: 700; }

/* Axes d'amélioration (Juste terminé 121) - repères heuristiques calculés
   à partir des stats enrichies d'un scrim importé via Riot ID. */
.liste-axes-amelioration {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  margin: .4rem 0 0;
  padding-left: 1.3rem;
  font-size: .85rem;
}
.liste-axes-amelioration strong { color: var(--accent); }

/* Match highlights (ATK/DEF) en cartes avec barre de proportion plutôt
   qu'un tableau de chiffres bruts - demandé explicitement. */
.grille-highlights-scrim {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: .7rem;
  margin-top: .4rem;
}
.carte-highlight-scrim {
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: .6rem .8rem;
}
.label-highlight-scrim { font-size: .78rem; color: var(--texte-discret); margin-bottom: .5rem; }
.barre-highlight-scrim {
  display: flex;
  height: 8px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--bg);
  margin-bottom: .45rem;
}
.barre-highlight-scrim .portion-atk { background: var(--accent); }
.barre-highlight-scrim .portion-def { background: #5c9df5; }
.valeurs-highlight-scrim { display: flex; justify-content: space-between; font-size: .8rem; font-weight: 600; }
.valeurs-highlight-scrim .valeur-atk { color: var(--accent); }
.valeurs-highlight-scrim .valeur-def { color: #5c9df5; }

/* Onglets génériques, partagés entre la modale "Détails" d'un match Premier
   et la page Premier elle-même (cf. Juste terminé 63) — un seul style de
   pilule pour switcher entre panneaux, peu importe le contexte. */
.onglets-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  margin-bottom: 1.2rem;
  border-bottom: 1px solid var(--bordure);
  padding-bottom: .8rem;
}
.bouton-onglet {
  padding: .4rem 1rem;
  border-radius: 999px;
  border: 1px solid var(--bordure);
  background: transparent;
  color: var(--texte-discret);
  font: inherit;
  font-weight: 600;
  font-size: .85rem;
  cursor: pointer;
}
.bouton-onglet.actif { background: var(--texte); color: var(--bg); border-color: var(--texte); }

/* --- Repérage d'un élément visé par un lien direct (#strat=/#match=) --- */
.mis-en-valeur {
  outline: 2px solid var(--complet);
  outline-offset: 2px;
}

/* --- Chat d'équipe --- */
.liste-messages {
  display: flex;
  flex-direction: column;
  gap: .8rem;
  max-height: 60vh;
  overflow-y: auto;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: 1rem;
  margin-bottom: 1rem;
}
.ligne-message { display: flex; align-items: flex-start; gap: .7rem; }
.message-avatar { width: 32px; height: 32px; border-radius: 50%; object-fit: cover; border: 1px solid var(--bordure); flex-shrink: 0; }
.message-corps { flex: 1; min-width: 0; }
.message-entete { display: flex; align-items: baseline; gap: .5rem; }
.message-auteur { font-weight: 600; font-size: .85rem; }
.message-heure { color: var(--texte-discret); font-size: .75rem; }
.message-texte { margin: .15rem 0 0; font-size: .9rem; overflow-wrap: break-word; }
.message-supprimer {
  background: none;
  border: none;
  color: var(--texte-discret);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 .2rem;
}
.message-supprimer:hover { color: var(--non); }
.form-message { display: flex; gap: .6rem; }
.champ-message-wrapper { position: relative; flex: 1; }
.champ-message-wrapper input {
  width: 100%;
  padding: .6rem .9rem;
  border-radius: 8px;
  border: 1px solid var(--bordure);
  background: var(--bg);
  color: var(--texte);
  font: inherit;
}
.mentions-suggestions {
  position: absolute;
  bottom: 100%;
  left: 0;
  right: 0;
  margin-bottom: .4rem;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  max-height: 220px;
  overflow-y: auto;
  box-shadow: 0 4px 16px rgba(0, 0, 0, .3);
  z-index: 5;
}
.suggestion-mention {
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
  padding: .5rem .7rem;
  background: none;
  border: none;
  color: var(--texte);
  font: inherit;
  font-size: .85rem;
  text-align: left;
  cursor: pointer;
}
.suggestion-mention img { width: 22px; height: 22px; border-radius: 50%; object-fit: cover; }
.suggestion-mention.actif, .suggestion-mention:hover { background: var(--bg-carte-hover); }

.mention {
  background: var(--mention-bg);
  color: var(--mention-texte);
  border-radius: 4px;
  padding: 0 .2rem;
  font-weight: 600;
}
.ligne-message-mentionne {
  background: rgba(245, 197, 24, .12);
  border-radius: 8px;
  padding: .3rem .4rem;
  margin: -.3rem -.4rem;
}

.grille-scroll {
  overflow-x: auto;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: 1.1rem;
}

#grille {
  display: grid;
  grid-template-columns: 56px repeat(7, minmax(64px, 1fr));
  gap: 5px;
  min-width: 560px;
  user-select: none;
}

.entete, .heure {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Rajdhani', system-ui, sans-serif;
  font-size: .8rem;
  font-weight: 700;
  color: var(--texte-discret);
  padding: 4px;
}
.heure { justify-content: flex-end; padding-right: 8px; }

.case {
  min-height: 40px;
  border-radius: 6px;
  cursor: pointer;
  background: var(--idk);
  position: relative;
  transition: background .12s;
}
.case.oui { background: var(--oui); }
.case.non { background: var(--non); }
.case:hover { outline: 2px solid var(--texte-discret); outline-offset: -2px; }
#grille.lecture-seule .case { cursor: not-allowed; opacity: .75; }
#grille.lecture-seule .case:hover { outline: none; }
.case.complet::after {
  content: '★';
  position: absolute;
  top: 2px;
  right: 4px;
  font-size: .85rem;
  color: #000;
}
.case.quasi-complet::after {
  content: '☆';
  position: absolute;
  top: 2px;
  right: 4px;
  font-size: .85rem;
  color: #000;
  opacity: .7;
}

/* Grille plus compacte sur mobile (cf. Juste terminé 68) : les cases
   gardaient leur taille desktop (56px + 7×64px min, cases de 40px de haut)
   quel que soit l'écran, forçant un large défilement horizontal en plus
   d'occuper beaucoup de hauteur d'écran sur téléphone. */
@media (max-width: 640px) {
  .grille-scroll { padding: .7rem; }
  #grille { grid-template-columns: 40px repeat(7, minmax(42px, 1fr)); gap: 3px; min-width: 400px; }
  .case { min-height: 30px; border-radius: 4px; }
  .entete, .heure { font-size: .68rem; padding: 2px; }
  .heure { padding-right: 4px; }
}

/* --- Modales (Docs, création d'événement) --- */
dialog {
  background: var(--bg-carte);
  color: var(--texte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: 1.5rem 1.8rem;
  max-width: 32rem;
  width: 90vw;
  /* Légère ombre portée (Juste terminé 126) : sans elle une dialog posée
     sur un fond déjà sombre se distinguait à peine du reste de la page -
     un peu de profondeur pour qu'elle se détache visuellement, plutôt
     qu'un bloc plat au même niveau que tout le reste ("stoïque"). */
  box-shadow: 0 24px 60px -24px rgba(0, 0, 0, .55);
}
/* Flou du fond de page derrière une dialog ouverte (Juste terminé 126,
   demandé explicitement) - s'ajoute à l'assombrissement déjà en place,
   applique un vrai flou visuel plutôt qu'un simple voile sombre plat.
   Statique (pas besoin d'être conditionné à prefers-reduced-motion :
   ce n'est pas une animation, juste un effet visuel figé une fois la
   dialog ouverte). */
dialog::backdrop { background: rgba(0, 0, 0, .6); backdrop-filter: blur(4px); }
dialog h2 { margin-top: 0; }
/* Petit "pop in" à l'ouverture (Juste terminé 126, demandé explicitement -
   "moins stoïque") : léger agrandissement + fondu, appliqué à TOUTE
   `<dialog>` du site via `[open]` (pas juste le wizard Scrims demandé au
   départ) pour un rendu cohérent partout plutôt qu'une seule dialog qui
   s'anime différemment des autres. Même mécanique que `.vue:not([hidden])`
   (Juste terminé 82) : une dialog masquée n'est pas dans le rendu, la
   faire réapparaître (ici via l'attribut `[open]`, posé par `showModal()`)
   relance l'animation comme un élément neuf à chaque ouverture. */
@keyframes apparition-dialog {
  from { opacity: 0; transform: scale(.96); }
  to   { opacity: 1; transform: scale(1); }
}
html[data-motion="normal"] dialog[open] { animation: apparition-dialog .18s cubic-bezier(.16, 1, .3, 1); }
#dialogue-docs ol { padding-left: 1.2rem; display: flex; flex-direction: column; gap: .5rem; }
#dialogue-docs button { margin-top: 1rem; }

/* --- Recherche globale (chat, Valoplant, calendrier), cf. Juste terminé 54 --- */
.dialogue-recherche { max-width: 40rem; padding: 1.2rem; }
.entete-recherche { display: flex; align-items: center; gap: .6rem; margin-bottom: .8rem; }
.fermer-recherche {
  flex: 0 0 auto;
  width: 2rem;
  height: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  border: 1px solid var(--bordure);
  border-radius: 8px;
  color: var(--texte-discret);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
}
.fermer-recherche:hover { color: var(--texte); background: var(--bg-carte-hover); }
#input-recherche {
  flex: 1;
  padding: .6rem .8rem;
  border-radius: 8px;
  border: 1px solid var(--bordure);
  background: var(--bg);
  color: var(--texte);
  font: inherit;
}
.resultats-recherche { display: flex; flex-direction: column; gap: 1rem; max-height: 60vh; overflow-y: auto; }
.groupe-resultats-titre {
  margin: 0 0 .4rem;
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--texte-discret);
}
.ligne-resultat {
  display: block;
  width: 100%;
  text-align: left;
  background: var(--bg);
  border: 1px solid var(--bordure);
  border-radius: 8px;
  padding: .55rem .7rem;
  margin-bottom: .4rem;
  color: var(--texte);
  font: inherit;
  cursor: pointer;
}
.ligne-resultat:hover { background: var(--bg-carte-hover); }
.ligne-resultat-meta { display: block; font-size: .75rem; color: var(--texte-discret); margin-top: .15rem; }

/* --- Modale "Nouvel événement" --- */
#form-creer-event,
#form-strat { display: flex; flex-direction: column; gap: .9rem; }
#form-creer-event label,
#form-strat label {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  font-size: .85rem;
  color: var(--texte-discret);
  font-weight: 600;
}
#form-creer-event input,
#form-creer-event select,
#form-creer-event textarea,
#form-strat input,
#form-strat select,
#form-strat textarea {
  padding: .55rem .7rem;
  border-radius: 8px;
  border: 1px solid var(--bordure);
  background: var(--bg);
  color: var(--texte);
  font: inherit;
  font-weight: 400;
}
#form-creer-event textarea,
#form-strat textarea { resize: vertical; }
#form-creer-event .ligne-champs,
#form-strat .ligne-champs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: .7rem;
}
#form-creer-event .ligne-checkbox,
#form-strat .ligne-checkbox {
  flex-direction: row;
  align-items: center;
  gap: .5rem;
}
#form-creer-event .ligne-checkbox input,
#form-strat .ligne-checkbox input { width: auto; }
.actions-dialogue { display: flex; justify-content: flex-end; gap: .6rem; }

.suggestions-event {
  background: var(--bg);
  border: 1px solid var(--bordure);
  border-radius: 8px;
  padding: .8rem 1rem;
  margin-bottom: 1rem;
}
.suggestions-event .sous-titre { margin: 0 0 .3rem; font-size: .8rem; }
.creneaux-suggeres { display: flex; flex-direction: column; gap: .4rem; }
.creneaux-vide { margin: 0; color: var(--texte-discret); font-size: .85rem; }
.ligne-jour-suggere { display: flex; align-items: center; gap: .6rem; }
.jour-suggere { min-width: 4.5rem; font-size: .8rem; font-weight: 700; color: var(--texte-discret); }
.chips-creneaux { display: flex; flex-wrap: wrap; gap: .35rem; }
.chip-creneau {
  background: var(--bg-carte-hover);
  border: 1px solid var(--bordure);
  border-radius: 999px;
  padding: .15rem .6rem;
  font: inherit;
  font-size: .8rem;
  font-weight: 600;
  color: var(--oui);
  cursor: pointer;
  transition: background .12s, border-color .12s;
}
.chip-creneau:hover { background: var(--oui); border-color: var(--oui); color: var(--bg); }

.compos-map { margin-bottom: 1.2rem; }
.compos-map .titre-colonne { margin-bottom: .5rem; }
.chips-compos { display: flex; flex-wrap: wrap; gap: .4rem; }
.chip-compo {
  background: var(--bg-carte-hover);
  border: 1px solid var(--bordure);
  border-radius: 999px;
  padding: .25rem .7rem;
  font-size: .8rem;
  color: var(--texte);
}

.avertissement {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .35rem;
  margin: .6rem 0 0;
  color: var(--complet);
  font-size: .85rem;
}
.avertissement .badge { color: var(--complet); border-color: var(--complet); }

@media (max-width: 480px) {
  #form-creer-event .ligne-champs,
  #form-strat .ligne-champs { grid-template-columns: 1fr; }
}

/* --- Panels flottants (installer l'appli, activer les notifs, cf. Juste
   terminé (43)/(47)) : empilés dans un conteneur fixe en bas d'écran plutôt
   que chaque panel en position fixed séparée — évite de superposer deux
   panels l'un sur l'autre si les deux sont affichés en même temps, sans
   avoir à calculer leurs hauteurs à la main. --- */
.zone-panels-flottants {
  position: fixed;
  left: 1rem;
  right: 1rem;
  bottom: 1rem;
  z-index: 50;
  max-width: 420px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: .7rem;
  pointer-events: none;   /* la zone elle-même laisse passer les clics entre deux panels */
}
/* Sur assez large (même seuil que .planning-layout ci-dessus) : ancré sur
   le côté droit plutôt que centré pleine largeur en bas — moins intrusif
   sur un grand écran, où un bandeau centré coupe la vue en deux pour rien. */
@media (min-width: 1101px) {
  .zone-panels-flottants {
    left: auto;
    right: 1.5rem;
    bottom: 1.5rem;
    max-width: 340px;
    margin: 0;
  }
}
.panel-flottant {
  position: relative;
  pointer-events: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .7rem;
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .35);
  padding: .9rem 1rem;
}
.fermer-panel-flottant {
  position: absolute;
  top: .3rem;
  right: .5rem;
  background: none;
  border: none;
  color: var(--texte-discret);
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
  padding: .2rem .4rem;
}
.fermer-panel-flottant:hover { color: var(--texte); }
.panel-flottant-texte {
  display: flex;
  flex-direction: column;
  gap: .15rem;
  flex: 1;
  min-width: 180px;
  padding-right: 1.2rem;
  font-size: .85rem;
}
.panel-flottant-texte strong { font-family: 'Rajdhani', system-ui, sans-serif; font-size: 1rem; }
.panel-flottant-texte span { color: var(--texte-discret); }

/* Notif "Nouvelle version disponible" (Juste terminé 102) : affichée juste
   avant le rechargement automatique déclenché par une mise à jour du
   service worker (cf. app.js, controllerchange) - toujours en bas à droite
   (contrairement à .zone-panels-flottants qui bascule à gauche sous
   1101px, cf. Juste terminé 57) : c'est une info système transitoire, pas
   un panel d'action, pas besoin de la même règle de repositionnement. */
.toast-nouvelle-version {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 60;
  max-width: min(320px, calc(100vw - 2rem));
  background: var(--bg-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .35);
  padding: .8rem 1rem;
  font-size: .85rem;
  font-weight: 600;
}
@keyframes entree-toast-version {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}
html[data-motion="normal"] .toast-nouvelle-version { animation: entree-toast-version .25s ease-out; }
/* --- Pied de page permanent (signature + lien d'installation), cf. Juste
   terminé (49) : contrairement aux panels flottants ci-dessus, jamais
   fermable — reste dans le flux normal de la page, en bas de chaque vue,
   et le lien d'installation y réapparaît à chaque rechargement tant que
   l'appli n'est pas installée (pas de mémorisation de fermeture ici). --- */
.pied-de-page {
  max-width: 900px;
  margin: 2rem auto 1rem;
  padding: 1rem 1.5rem 0;
  border-top: 1px solid var(--bordure);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: .8rem;
  font-size: .78rem;
  color: var(--texte-discret);
}
.pied-de-page-credit a { color: var(--texte-discret); text-decoration: underline; }
.pied-de-page-credit a:hover { color: var(--texte); }
.lien-installer-footer {
  background: none;
  border: none;
  color: var(--accent);
  font: inherit;
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
  padding: 0;
}
.lien-installer-footer:hover { color: var(--accent-hover); }
.lien-demo-footer { color: var(--accent); font-weight: 600; text-decoration: underline; }
.lien-demo-footer:hover { color: var(--accent-hover); }

.banniere-demo {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--accent);
  color: #fff;
  text-align: center;
  font-size: .82rem;
  font-weight: 600;
  padding: .5rem 1rem;
}
.banniere-demo a { color: #fff; text-decoration: underline; margin-left: .6rem; }
