/* Chat vocal de groupe — bouton haut-droite, panneau déroulant, bandeau des
   voix actives, bouton Parler flottant déplaçable. Voir public/shared/
   voice.js et VOICE_CHAT.md.

   Couleurs routées par les variables partagées (--surface/--text/--border/
   --primary/--danger/--shadow, ou --bg/--ink pour 8-americain) : hérite
   automatiquement du mode AAH comme le reste du chrome (AAH_MODE.md).
   `.voice-panel` contient volontairement "panel" dans son nom : la règle
   générique [class*="panel"] du mode AAH lui donne fond noir + bordure
   blanche sans rien avoir à dupliquer ici. Les boutons de ce fichier sont
   tous des <button> natifs (jamais des <div> cliquables) : la règle
   générique `button { ... }` du mode AAH les agrandit/borde automatiquement.

   z-index choisis pour cohabiter avec l'existant (voir hub-back.css et les
   feuilles de style de chaque jeu) : le bouton retour et ce bouton vocal
   sont à 25/26 (les deux coins hauts), le FAB "Réagir" + son popup sont à
   45/46 (bas-droite), le bouton Parler est juste au-dessus (47) pour ne
   jamais être recouvert par le popup de réaction, les toasts restent au
   sommet (80). */

.voice-fab {
  position: fixed;
  top: calc(14px + env(safe-area-inset-top, 0px));
  right: env(safe-area-inset-right, 0px);
  z-index: 26;
  width: 26px;
  height: 40px;
  border-radius: 10px 0 0 10px;
  border: 1px solid var(--border, #e0e0e0);
  border-right: none;
  background: var(--surface, var(--bg, #fff));
  color: var(--text, var(--ink, #222));
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: -2px 3px 10px rgba(0,0,0,.14);
  cursor: pointer;
  padding: 0;
  transition: transform .08s ease;
}
.voice-fab:active { transform: scale(0.94); }
.voice-fab.hidden { display: none !important; }
.voice-fab-dot {
  position: absolute;
  top: 3px; right: 3px;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--text-dim, #999);
  box-shadow: 0 0 0 1.5px var(--surface, #fff);
}
.voice-fab-joined .voice-fab-dot { background: var(--success, #2ecc71); }
.voice-fab-muted .voice-fab-dot { background: var(--danger, #e74c3c); }
.voice-fab-live { color: var(--success, #2ecc71); }
.voice-fab-live .voice-fab-dot {
  background: var(--success, #2ecc71);
  animation: voice-fab-pulse 1s ease-in-out infinite;
}
@keyframes voice-fab-pulse {
  0%, 100% { box-shadow: 0 0 0 1.5px var(--surface, #fff), 0 0 0 0 rgba(46,204,113,.6); }
  50% { box-shadow: 0 0 0 1.5px var(--surface, #fff), 0 0 0 4px rgba(46,204,113,0); }
}

.voice-panel {
  position: fixed;
  top: calc(58px + env(safe-area-inset-top, 0px));
  right: calc(6px + env(safe-area-inset-right, 0px));
  z-index: 26;
  width: min(84vw, 270px);
  max-height: min(74vh, 520px);
  overflow-y: auto;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e0e0e0);
  border-radius: 16px;
  box-shadow: var(--shadow, 0 8px 24px rgba(0,0,0,.18));
  padding: 14px;
  text-align: left;
  color: var(--text, #222);
}
.voice-panel.hidden { display: none !important; }
.voice-panel-title { margin: 0 0 10px; font-size: 15px; }
.voice-panel .hint { font-size: 12.5px; color: var(--text-dim, #777); margin: 0 0 10px; }
.voice-panel .btn { width: 100%; margin-bottom: 8px; }

.voice-members {
  list-style: none;
  margin: 0 0 12px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.voice-member {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 10px;
  background: var(--bg-1, rgba(127,127,127,.08));
  font-size: 13.5px;
}
.voice-member-ring {
  width: 9px; height: 9px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--border, #ccc);
}
.voice-member-talking .voice-member-ring {
  background: var(--success, #2ecc71);
  box-shadow: 0 0 0 3px rgba(46,204,113,.35);
  animation: voice-fab-pulse 1s ease-in-out infinite;
}
.voice-member-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.voice-member-mic { flex-shrink: 0; font-size: 13px; opacity: .85; }
.voice-member-muted .voice-member-name { opacity: .7; }
/* Même traitement que .group-members li.disconnected (public/style.css,
   panneau de groupe du hub) : un membre dont le socket /groups est coupé
   (page fermée, réseau perdu — la grâce de 10 min de groups.js le garde
   dans le groupe mais pas connecté) ne peut ni entendre ni être entendu
   maintenant, quel que soit ce qu'affichait son icône micro avant la
   coupure. */
.voice-member-offline { opacity: .5; }
.voice-member-offline .voice-member-ring { background: var(--border, #ccc); box-shadow: none; animation: none; }
.voice-member-empty { font-size: 12.5px; color: var(--text-dim, #777); background: none; padding: 4px 2px; }

.voice-mute-btn { font-weight: 700; }
.voice-mute-btn.is-on { background: var(--primary, #6d5bd0); color: var(--primary-contrast, #fff); border-color: var(--primary, #6d5bd0); }

.voice-mode-row {
  display: flex;
  gap: 6px;
  margin-bottom: 10px;
}
.voice-mode-btn {
  flex: 1;
  min-width: 0;
  border: 1px solid var(--border, #e0e0e0);
  border-radius: 10px;
  background: var(--surface, #fff);
  color: var(--text, #222);
  font-size: 11px;
  font-weight: 600;
  padding: 8px 4px;
  cursor: pointer;
  line-height: 1.2;
}
.voice-mode-btn.is-on { background: var(--primary, #6d5bd0); color: var(--primary-contrast, #fff); border-color: var(--primary, #6d5bd0); }

.voice-vumeter {
  position: relative;
  height: 10px;
  border-radius: 999px;
  background: var(--bg-1, rgba(127,127,127,.15));
  overflow: hidden;
  margin-bottom: 10px;
}
.voice-vumeter-fill {
  height: 100%;
  width: 0%;
  background: var(--success, #2ecc71);
  transition: width .05s linear;
}
/* Repère du seuil de détection de voix, sur le même axe que la jauge
   ci-dessus (même formule levelToPct() côté JS pour les deux) — sans lui,
   rien ne reliait visuellement "voici le son qui arrive" (la jauge) et
   "voici à partir d'où le micro se déclenche" (le curseur de sensibilité),
   signalé par un utilisateur comme "on ne voit pas le volume pendant le
   réglage de la jauge". */
.voice-vumeter-threshold {
  position: absolute;
  top: -2px;
  bottom: -2px;
  width: 2px;
  background: var(--text, #222);
  opacity: .6;
}

.voice-vad-row {
  display: block;
  font-size: 12px;
  margin-bottom: 10px;
}
.voice-vad-row span { display: block; margin-bottom: 4px; color: var(--text-dim, #777); }
.voice-vad-row input[type="range"] { width: 100%; accent-color: var(--primary, #6d5bd0); }

/* Interrupteur "Sons" — arrivée/départ/micro, voir voice.js playChime(). */
.voice-sound-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--text-dim, #777);
  margin-bottom: 10px;
  cursor: pointer;
}
.voice-sound-toggle input[type="checkbox"] { accent-color: var(--primary, #6d5bd0); width: 15px; height: 15px; flex-shrink: 0; }

/* Curseur « Volume du jeu » — mêmes proportions que .voice-vad-row. N'est
   rendu que si la page a un module son de jeu actif (voice.js, drapeau
   window.__JEL_GAME_SOUND__). */
.voice-gamevol-row {
  display: block;
  font-size: 12px;
  margin-bottom: 10px;
  color: var(--text-dim, #777);
}
.voice-gamevol-row span { display: block; margin-bottom: 4px; }
.voice-gamevol-row input[type="range"] { width: 100%; accent-color: var(--primary, #6d5bd0); }

/* Bandeau des voix actives — visible EN JEU sans ouvrir le panneau, sous le
   bouton vocal. pointer-events:none : ne doit jamais gêner un clic de jeu. */
.voice-speakers {
  position: fixed;
  top: calc(58px + env(safe-area-inset-top, 0px));
  right: calc(6px + env(safe-area-inset-right, 0px));
  z-index: 24;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  pointer-events: none;
  max-width: min(60vw, 220px);
}
.voice-speaker-chip {
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e0e0e0);
  color: var(--text, #222);
  font-size: 11.5px;
  font-weight: 600;
  padding: 4px 10px;
  border-radius: 999px;
  box-shadow: 0 2px 8px rgba(0,0,0,.12);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Bouton Parler (push-to-talk) — flottant, déplaçable par sa poignée.
   z-index 47 : au-dessus du FAB Réagir/popup (45/46), sous les toasts (80).
   touch-action:none indispensable : sans ça, un doigt maintenu dessus fait
   défiler la page au lieu de tenir le bouton enfoncé.

   user-select/-webkit-touch-callout répétés à la fois ici ET sur le libellé
   texte ci-dessous (`.voice-ptt-label`, `.voice-ptt-handle`) — pas une
   simple prudence : `.hub-back-btn`/`.aah-toggle-btn` n'avaient jamais eu ce
   souci malgré une CSS quasi identique parce qu'ils ne contiennent qu'un
   SVG, rien à sélectionner. Ce bouton-ci a un vrai texte ("Parler") : sur
   Safari/WebKit iOS (donc aussi Firefox iOS — Apple impose WebKit comme
   moteur à TOUS les navigateurs iOS), un appui maintenu déclenchait la
   sélection de ce texte + le menu contextuel de copie EN MÊME TEMPS que le
   micro s'activait, alors que `user-select:none` était déjà posé sur le
   bouton parent — `preventDefault()` sur pointerdown (voir voice.js) ne
   suffit pas seul sur cette plateforme pour ce cas précis. Signalé par un
   utilisateur réel sur Firefox iOS, jamais reproduit par Playwright/Chromium
   headless (qui n'a pas ce comportement). */
.voice-ptt {
  position: fixed;
  z-index: 47;
  width: 76px;
  height: 76px;
  border-radius: 50%;
  border: none;
  background: var(--surface, #fff);
  color: var(--text, #222);
  box-shadow: 0 6px 18px rgba(0,0,0,.25);
  display: flex;
  align-items: center;
  justify-content: center;
  touch-action: none;
  -webkit-user-drag: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  padding: 0;
  cursor: pointer;
}
.voice-ptt.hidden { display: none !important; }
.voice-ptt-label {
  font-size: 10.5px;
  font-weight: 700;
  line-height: 1.3;
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.voice-ptt-active {
  background: var(--success, #2ecc71);
  color: #fff;
  transform: scale(1.06);
}
.voice-ptt-handle {
  position: absolute;
  top: -4px;
  left: 50%;
  transform: translateX(-50%);
  width: 34px;
  height: 18px;
  border-radius: 999px;
  background: var(--border, #ccc);
  color: var(--text, #222);
  font-size: 11px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
.voice-ptt-handle:active { cursor: grabbing; }

.voice-toast {
  position: fixed;
  top: calc(14px + env(safe-area-inset-top, 0px));
  left: 50%;
  transform: translateX(-50%) translateY(-140%);
  z-index: 80;
  background: var(--surface, #222);
  color: var(--text, #fff);
  border: 1px solid var(--border, transparent);
  padding: 10px 18px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  box-shadow: var(--shadow, 0 6px 18px rgba(0,0,0,.25));
  opacity: 0;
  transition: opacity .2s ease, transform .2s ease;
  pointer-events: none;
  max-width: min(86vw, 360px);
  text-align: center;
}
.voice-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* Gouttières : sous 620px, la colonne de jeu (max-width: 560px la plupart du
   temps) touche les bords de l'écran et croise le bouton retour (gauche,
   hub-back.css) et le bouton vocal (droite, ci-dessus) — tous deux 26px de
   large + décalage. Au-delà de 620px la colonne centrée ne les croise plus :
   aucune gouttière n'y est appliquée pour ne pas abîmer la mise en page sur
   grand écran. S'aggrave en mode AAH (titres à 2.1em, ces deux boutons ne
   grandissent pas) — c'est justement le cas signalé (bouton retour cachant
   le titre de plusieurs jeux). */
@media (max-width: 620px) {
  .topbar, .game-top, .table-toolbar { padding-left: 30px; padding-right: 44px; }
}

/* Le bouton vocal (z-index 26) partage le coin haut-droite avec deux widgets
   déjà existants — décalés d'une hauteur de bouton (40px + marge) pour ne
   pas se superposer :
   - le menu réglages du hub (.settings-menu, public/style.css, z-index 20) */
.settings-menu { top: calc(58px + env(safe-area-inset-top, 0px)) !important; }
