/* PAGE
   (.page/.page__card/.page__header/.page__title/.page__back
   vivent dans main.css — ici juste la largeur specifique) */
.page{ --page-w: 1080px; }

.page__meta{
  max-width: 620px;
  line-height: 1.4;
}

.bingo{
  padding: 18px;
  display: grid;
  gap: 16px;
}

/* =========================
   TOOLBAR
========================= */
.bingoToolbar{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  padding: 12px 16px;
  border-radius: 16px;
  border: 1px solid rgba(219,219,219,.12);
  background: rgba(12,15,16,.44);
  box-shadow: 0 16px 44px rgba(0,0,0,.30);
}

/* personnalisation des couleurs de case (cote joueur, hors menu troll) */
.bingoColorsPanel{
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
  flex-wrap: wrap;
  padding: 12px 16px;
  margin-top: -4px;
  border-radius: 16px;
  border: 1px solid rgba(219,219,219,.12);
  background: rgba(12,15,16,.44);
}
.bingoColorsPanel__field{
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 10.5px;
  letter-spacing: .06em;
  color: rgba(219,219,219,.70);
}
.bingoColorsPanel__field input[type="color"]{
  width: 34px;
  height: 28px;
  padding: 2px;
  border-radius: 8px;
  border: 1px solid rgba(219,219,219,.20);
  background: rgba(255,255,255,.04);
  cursor: pointer;
}

.bingoToolbar__seed{
  font-size: 12px;
  letter-spacing: .08em;
  color: rgba(219,219,219,.65);
}
.bingoToolbar__seed strong{
  color: var(--green);
  font-family: "ZombiesBrainless","LazyDog",system-ui,sans-serif;
  font-size: 15px;
  letter-spacing: .12em;
}
.bingoToolbar__mode{
  margin-left: 8px;
  color: rgba(255,190,90,.85);
  font-size: 11px;
  letter-spacing: .04em;
}
.bingoToolbar__title{
  margin-left: 8px;
  color: rgba(219,219,219,.75);
  font-size: 12px;
  letter-spacing: .02em;
  font-style: italic;
}

/* =========================
   ETAPE 1 : CHOIX DU MODE
========================= */
.bingoTitleField{
  display: grid;
  gap: 6px;
  max-width: 320px;
  margin: 0 auto 18px;
  text-align: center;
  font-size: 10px;
  letter-spacing: .08em;
  color: rgba(219,219,219,.55);
}
.bingoTitleField input{
  padding: 10px 14px;
  border-radius: 10px;
  border: 1px solid rgba(219,219,219,.18);
  background: rgba(12,15,16,.55);
  color: rgba(219,219,219,.92);
  font-family: "LazyDog", system-ui, sans-serif;
  font-size: 14px;
  text-align: center;
}
.bingoTitleField input:focus{
  outline: none;
  border-color: rgba(61,206,97,.50);
}
.bingoModes__intro{
  margin: 0 0 14px;
  text-align: center;
  font-family: "LazyDog", system-ui, sans-serif;
  font-size: 13px;
  letter-spacing: .06em;
  color: rgba(219,219,219,.65);
}
.bingoModes__grid{
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  max-width: 680px;
  margin: 0 auto;
}
.bingoModeCard{
  display: grid;
  gap: 8px;
  padding: 22px 20px;
  border-radius: 16px;
  border: 1px solid rgba(219,219,219,.14);
  background: rgba(12,15,16,.44);
  text-align: left;
  cursor: pointer;
  transition: border-color .18s ease, background .18s ease, transform .18s ease, box-shadow .18s ease;
}
.bingoModeCard:hover{
  border-color: rgba(61,206,97,.45);
  background: rgba(61,206,97,.08);
  transform: translateY(-2px);
  box-shadow: 0 16px 40px rgba(0,0,0,.35);
}
.bingoModeCard__title{
  font-family: "ZombiesBrainless","LazyDog",system-ui,sans-serif;
  font-size: 18px;
  letter-spacing: .08em;
  color: var(--green);
}
.bingoModeCard__desc{
  font-family: "LazyDog", system-ui, sans-serif;
  font-size: 12px;
  line-height: 1.4;
  letter-spacing: .02em;
  color: rgba(219,219,219,.65);
}

/* =========================
   ETAPE 1B : CREATION D'UNE GRILLE PERSONNALISEE
========================= */
.bingoCustomGrid{
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 6px;
  max-width: 620px;
  margin: 0 auto;
}
.bingoCustomCell{
  aspect-ratio: 1 / 1;
  padding: 6px;
  border-radius: 8px;
  border: 2px solid rgba(219,219,219,.16);
  background: rgba(12,15,16,.45);
  color: rgba(219,219,219,.92);
  font-family: "LazyDog", system-ui, sans-serif;
  font-size: 11px;
  text-align: center;
  resize: none;
}
.bingoCustomCell:focus{
  outline: none;
  border-color: rgba(61,206,97,.55);
}
.bingoCustomCell::placeholder{
  color: rgba(219,219,219,.30);
}
.bingoCustomEditor__actions{
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-top: 16px;
  flex-wrap: wrap;
}

.bingoToolbar__actions{
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.bingoBtn{
  padding: 10px 18px;
  border-radius: 999px;
  border: 1px solid rgba(219,219,219,.16);
  background: rgba(12,15,16,.55);
  color: rgba(219,219,219,.88);
  font-family: "LazyDog",system-ui,sans-serif;
  letter-spacing: .05em;
  font-size: 13px;
  cursor: pointer;
  transition: border-color .15s ease, color .15s ease, box-shadow .15s ease;
}
.bingoBtn:hover{ border-color: rgba(61,206,97,.35); }
.bingoBtn--primary{
  background: rgba(61,206,97,.14);
  border-color: rgba(61,206,97,.50);
  color: var(--green);
}
.bingoBtn--primary:hover{
  border-color: rgba(61,206,97,.75);
  box-shadow: 0 0 0 1px rgba(61,206,97,.16);
}

/* =========================
   GRILLE
   (volontairement compacte : pensee pour tenir en incrustation
   sur un stream, pas pour remplir toute la largeur de la page)
========================= */
/* etape 2 (grille de jeu) : espacement genereux et regulier entre la barre du
   haut / la grille / le texte d'aide, pour qu'une capture OBS centree sur la
   seule grille ne "mange" jamais le texte au-dessus ou en dessous */
.bingoPlay{
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.bingoGrid{
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 6px;
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
  perspective: 900px;
}

.bingoCell{
  position: relative;
  display: grid;
  grid-template-rows: auto 1fr;
  align-items: center;
  justify-items: center;
  row-gap: 1px;
  aspect-ratio: 1 / 1;
  padding: 5px 4px 4px;
  border-radius: 10px;
  border: 2px solid rgba(219,219,219,.14);
  background: rgba(12,15,16,.45);
  cursor: pointer;
  text-align: center;
  overflow: hidden;

  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity .3s ease,
    transform .3s ease,
    border-color .18s ease,
    background .18s ease,
    box-shadow .18s ease;
}
.bingoCell.is-in{ opacity: 1; transform: translateY(0); }

.bingoCell:hover{ filter: brightness(1.12); }

.bingoCell__img{
  width: 78%;
  max-width: 68px;
  height: auto;
  max-height: 68px;
  object-fit: contain;
  pointer-events: none;
}
.bingoCell__label{
  width: 100%;
  min-height: 0;
  font-family: "LazyDog", system-ui, sans-serif;
  font-size: 13px;
  letter-spacing: .01em;
  line-height: 1.14;
  color: rgba(219,219,219,.85);
  pointer-events: none;

  /* protection anti-debordement : coupe proprement avec "..." plutot
     que de deborder de la case si le texte est trop long */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* grille personnalisee (pas d'image) : le texte seul doit occuper toute la
   case et etre parfaitement centre, pas colle en haut comme quand il ne
   remplit que la premiere des deux rangees prevues pour image+texte */
.bingoCell--noimg .bingoCell__label{
  grid-row: 1 / -1;
}

/* couleurs par categorie (memes 9 types que la banque de cases) */
/* les 9 couleurs par categorie servent de valeur par defaut ; des qu'un
   joueur choisit sa propre couleur "case non validee" (voir bingoColorsPanel),
   --bingo-unchecked-color est definie sur .bingoGrid et prend le dessus
   uniformement sur toutes les categories */
.bingoCell--fantomes{ border-color: var(--bingo-unchecked-color, rgba(150,100,215,.45)); }
.bingoCell--maps{ border-color: var(--bingo-unchecked-color, rgba(60,150,255,.45)); }
.bingoCell--tarot{ border-color: var(--bingo-unchecked-color, rgba(255,215,90,.45)); }
.bingoCell--divers{ border-color: var(--bingo-unchecked-color, rgba(80,220,210,.45)); }
.bingoCell--os{ border-color: var(--bingo-unchecked-color, rgba(219,219,219,.40)); }
.bingoCell--skins{ border-color: var(--bingo-unchecked-color, rgba(255,120,190,.45)); }
.bingoCell--photo{ border-color: var(--bingo-unchecked-color, rgba(61,206,97,.45)); }
.bingoCell--video{ border-color: var(--bingo-unchecked-color, rgba(255,90,90,.45)); }
.bingoCell--audio{ border-color: var(--bingo-unchecked-color, rgba(255,165,70,.45)); }

/* =========================
   LEGENDE DES COULEURS
========================= */
.bingoLegend{
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px 16px;
  max-width: 560px;
  margin: 0 auto;
}
.bingoLegend__item{
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 10.5px;
  letter-spacing: .05em;
  color: rgba(219,219,219,.65);
}
.bingoLegend__dot{
  width: 10px;
  height: 10px;
  border-radius: 999px;
  flex: none;
}
.bingoLegend__dot--maps{ background: rgb(60,150,255); }
.bingoLegend__dot--fantomes{ background: rgb(150,100,215); }
.bingoLegend__dot--tarot{ background: rgb(255,215,90); }
.bingoLegend__dot--divers{ background: rgb(80,220,210); }
.bingoLegend__dot--os{ background: rgb(219,219,219); }
.bingoLegend__dot--skins{ background: rgb(255,120,190); }
.bingoLegend__dot--photo{ background: rgb(61,206,97); }
.bingoLegend__dot--video{ background: rgb(255,90,90); }
.bingoLegend__dot--audio{ background: rgb(255,165,70); }

/* case cochee — personnalisable via --bingo-checked-color (voir bingoColorsPanel) */
.bingoCell.is-checked{
  background: color-mix(in srgb, var(--bingo-checked-color, #3dce61) 16%, transparent);
  border-color: var(--bingo-checked-color, #3dce61);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--bingo-checked-color, #3dce61) 20%, transparent), inset 0 0 30px color-mix(in srgb, var(--bingo-checked-color, #3dce61) 15%, transparent);
}
.bingoCell.is-checked::after{
  content: "";
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--bingo-checked-color, #3dce61) 10%, transparent);
  pointer-events: none;
}
.bingoCell.is-checked .bingoCell__label{ color: rgba(219,219,219,.98); }

/* petit eclat lumineux au moment ou une case passe cochee (pas juste un
   changement de couleur statique) */
.bingoCell.is-shining{ animation: bingoCellShinePulse .55s ease; }
@keyframes bingoCellShinePulse{
  0%{ box-shadow: 0 0 0 0 color-mix(in srgb, var(--bingo-checked-color, #3dce61) 65%, transparent); }
  45%{ box-shadow: 0 0 26px 8px color-mix(in srgb, var(--bingo-checked-color, #3dce61) 85%, transparent); }
  100%{ box-shadow: 0 0 0 1px color-mix(in srgb, var(--bingo-checked-color, #3dce61) 20%, transparent), inset 0 0 30px color-mix(in srgb, var(--bingo-checked-color, #3dce61) 15%, transparent); }
}
.bingoCell.is-shining::before{
  content: "";
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  background: linear-gradient(115deg, transparent 30%, rgba(255,255,255,.80) 48%, transparent 66%);
  background-size: 260% 260%;
  background-position: -120% -120%;
  animation: bingoCellShineSweep .55s ease;
}
@keyframes bingoCellShineSweep{
  0%{ background-position: -120% -120%; opacity: 1; }
  100%{ background-position: 120% 120%; opacity: 0; }
}

/* ligne gagnante */
.bingoCell.is-winning{
  animation: bingoWinPulse 1s ease-in-out 3;
}
@keyframes bingoWinPulse{
  0%, 100%{ box-shadow: 0 0 0 1px rgba(255,190,90,.30), 0 0 20px rgba(255,190,90,.25); }
  50%{ box-shadow: 0 0 0 4px rgba(255,190,90,.55), 0 0 30px rgba(255,190,90,.45); }
}

.bingoHint{
  margin: 0;
  text-align: center;
  font-size: 11px;
  letter-spacing: .05em;
  color: rgba(219,219,219,.45);
}

/* =========================
   TOAST
========================= */
.bingoToast{
  position: fixed;
  left: 50%;
  bottom: 28px;
  transform: translate(-50%, 20px);
  padding: 12px 20px;
  border-radius: 999px;
  border: 1px solid rgba(61,206,97,.40);
  background: rgba(12,15,16,.92);
  color: var(--green);
  font-size: 12px;
  letter-spacing: .06em;
  box-shadow: 0 16px 40px rgba(0,0,0,.45);
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease, transform .2s ease;
  z-index: 80;
}
.bingoToast.is-visible{
  opacity: 1;
  transform: translate(-50%, 0);
}

/* =========================
   BANNIERE BINGO
========================= */
/* positionnee par-dessus la grille (pas plein ecran) : spooky-bingo.js reparente cet
   element dans #bingoGrid (position:relative) une fois au demarrage */
.bingoWinBanner{
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 8%;
  border-radius: 14px;
  background: rgba(6,4,10,.55);
  transform: scale(.85);
  font-family: "ZombiesBrainless","LazyDog",system-ui,sans-serif;
  font-weight: lighter;
  letter-spacing: .10em;
  line-height: 1.15;
  color: rgba(255,190,90,.95);
  text-shadow: 0 0 40px rgba(255,190,90,.55), 0 0 80px rgba(255,190,90,.30);
  word-break: break-word;
  overflow-wrap: anywhere;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  transition: opacity .3s ease, transform .3s ease;
  z-index: 20;
}
.bingoWinBanner.is-visible{
  opacity: 1;
  transform: scale(1);
}

/* =========================
   EFFETS TROLL (declenches via le menu admin cache)
   Modele persistant : chaque effet reste actif jusqu'a ce que l'admin
   le desactive explicitement (plus d'auto-retour en arriere sur un timer).
========================= */
.troll-shake{
  animation: trollShake var(--shake-speed, 180ms) ease-in-out infinite;
}
@keyframes trollShake{
  0%, 100%{ transform: translate(0,0) rotate(0deg); }
  20%{ transform: translate(calc(var(--shake-intensity, 22px) * -1), calc(var(--shake-intensity, 22px) * .4)) rotate(-1.4deg); }
  40%{ transform: translate(var(--shake-intensity, 22px), calc(var(--shake-intensity, 22px) * -.35)) rotate(1.4deg); }
  60%{ transform: translate(calc(var(--shake-intensity, 22px) * -.7), calc(var(--shake-intensity, 22px) * .2)) rotate(-.8deg); }
  80%{ transform: translate(calc(var(--shake-intensity, 22px) * .6), 0) rotate(.8deg); }
}

.troll-fog{
  filter: blur(var(--fog-intensity, 6px));
}

/* miroir (horizontal ou vertical selon le reglage) — la transition vit sur la
   regle de base pour que l'activation ET la desactivation soient animees */
.bingoGrid{ transition: transform .4s ease, filter .4s ease; }
.bingoGrid.troll-mirror-h{ transform: scaleX(-1); }
.bingoGrid.troll-mirror-v{ transform: scaleY(-1); }

/* disco : toutes les cases recoivent une couleur a chaque cycle (JS), aucune ne reste neutre.
   transition-delay force a 0 pour eviter que le decalage d'entree en grille (transition-delay
   inline pose a l'affichage initial) ne retarde encore les changements de couleur. */
.bingoGrid.troll-disco .bingoCell{
  transition: background .12s ease;
  transition-delay: 0s !important;
}

/* curseur fou : transition rapide pour que la case semble fuir avant que le curseur l'atteigne.
   on reprend toutes les transitions de base (pas juste transform) pour ne pas perdre
   les autres effets de survol/coche pendant que l'effet est actif */
.bingoGrid.troll-fleeing .bingoCell{
  transition:
    opacity .3s ease,
    transform var(--flee-speed, 70ms) ease-out,
    border-color .18s ease,
    background .18s ease,
    box-shadow .18s ease;
}

/* lampe de poche : rayon et durete du bord reglables (JS met a jour --troll-x/--troll-y/--flash-radius/--flash-blur) */
.trollFlashlight{
  position: fixed;
  inset: 0;
  z-index: 85;
  pointer-events: none;
  background: radial-gradient(
    circle var(--flash-radius, 150px) at var(--troll-x, 50%) var(--troll-y, 50%),
    transparent 0%,
    transparent calc(100% - var(--flash-blur, 6%)),
    rgba(0,0,0,.96) 100%
  );
}

/* glitch : uniquement le scramble de texte (JS), plus aucune animation CSS de
   secousse/decoupe sur la grille elle-meme. */

/* explosion : compte a rebours CENTRE SUR LA GRILLE (pas plein ecran), flash
   "BOOM", puis fragments (contenu reel des cases : image + texte) qui tombent
   et s'empilent en bas de la grille. spooky-bingo.js place cet overlay dans #bingoGrid. */
.trollExplodeOverlay{
  position: absolute;
  inset: 0;
  z-index: 22;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 14px;
  font-family: "ZombiesBrainless","LazyDog",system-ui,sans-serif;
  font-size: 100px;
  color: rgba(255,90,90,.95);
  text-shadow: 0 0 40px rgba(255,90,90,.60), 0 0 90px rgba(255,90,90,.30);
  background: rgba(0,0,0,.35);
  pointer-events: none;
  animation: trollCountdownPulse var(--countdown-speed, 800ms) ease-in-out infinite;
}
@keyframes trollCountdownPulse{
  0%, 100%{ transform: scale(1); opacity: .85; }
  50%{ transform: scale(1.15); opacity: 1; }
}
.trollExplodeOverlay.is-boom{
  color: rgba(255,70,40,.98);
  font-size: clamp(90px, 24vw, 190px);
  text-shadow: 0 0 70px rgba(255,90,40,.90), 0 0 140px rgba(255,90,40,.55);
  background: rgba(255,90,40,.28);
  animation: trollBoomFlash .26s ease-out;
}
@keyframes trollBoomFlash{
  0%{ transform: scale(.7); opacity: .4; }
  60%{ transform: scale(1.25); opacity: 1; }
  100%{ transform: scale(1.1); opacity: 1; }
}

.troll-explode-impact{
  animation: trollShake 90ms ease-in-out 4;
  --shake-intensity: 16px;
  --shake-speed: 90ms;
}

.bingoGrid{ position: relative; }

/* image derriere la grille (effet troll) : deborde legerement du cadre,
   reste sous les cases (z-index negatif) donc visible surtout dans les
   espaces entre les cases et sur le pourtour */
.trollBgImage{
  position: absolute;
  inset: -16px;
  z-index: -1;
  border-radius: 18px;
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
  opacity: 0;
  pointer-events: none;
  transition: opacity .4s ease, filter .3s ease;
}

/* message chuchote (effet troll) : reste affiche tant que l'admin ne le
   desactive pas, contrairement au jumpscare qui est un declencheur ponctuel */
.trollWhisper{
  position: absolute;
  inset: 0;
  z-index: 15;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10%;
  text-align: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity .8s ease;
}
.trollWhisper.is-visible{ opacity: 1; }
.trollWhisper span{
  font-family: "LazyDog","ZombiesBrainless",system-ui,sans-serif;
  font-style: italic;
  font-size: clamp(16px, 4vw, 26px);
  line-height: 1.25;
  color: rgba(219,219,219,.92);
  text-shadow: 0 0 20px rgba(82,56,119,.75), 0 0 40px rgba(82,56,119,.40);
  word-break: break-word;
}

/* fantome voleur de case (effet troll) */
/* =========================
   SYSTEME DE FANTOME "VIVANT" — partage par tous les effets troll a base de
   fantome (trollGhost, trollGhostSign, moonwalk, voleur de curseur...) :
   bras qui ondulent en continu (CSS pure), yeux (pupilles) qui regardent
   dans une direction pilotee par JS via --eye-x/--eye-y, et une legere
   posture (inclinaison) qui change de temps en temps.
========================= */
.ghostSvg{ width: 100%; height: 100%; display: block; overflow: visible; }
.ghostBody{
  transition: transform .5s ease;
  transform-box: fill-box;
  transform-origin: 50% 50%;
}
.ghostBody.pose-lean-l{ transform: rotate(-5deg) scaleY(.97); }
.ghostBody.pose-lean-r{ transform: rotate(5deg) scaleY(.97); }
.ghostBody.pose-perk{ transform: translateY(-2px) scaleY(1.03); }

.ghostArm{
  transform-box: fill-box;
  animation: ghostArmWaveL 1.7s ease-in-out infinite;
}
.ghostArm--l{ transform-origin: 100% 0%; animation-name: ghostArmWaveL; }
.ghostArm--r{ transform-origin: 0% 0%; animation-name: ghostArmWaveR; animation-delay: .25s; }
@keyframes ghostArmWaveL{
  0%, 100%{ transform: rotate(0deg); }
  50%{ transform: rotate(16deg); }
}
@keyframes ghostArmWaveR{
  0%, 100%{ transform: rotate(0deg); }
  50%{ transform: rotate(-16deg); }
}

.ghostPupil{
  transition: transform .4s ease;
  transform-box: fill-box;
  transform-origin: 50% 50%;
  transform: translate(calc(var(--eye-x, 0) * 1.8px), calc(var(--eye-y, 0) * 2.4px));
}

.trollGhost{
  position: absolute;
  width: 54px;
  height: 58px;
  z-index: 30;
  pointer-events: none;
  opacity: 0;
  transition: left .9s cubic-bezier(.45,0,.2,1), top .9s cubic-bezier(.45,0,.2,1), opacity .4s ease;
  filter: drop-shadow(0 6px 12px rgba(0,0,0,.55));
  animation: trollGhostBob 1.6s ease-in-out infinite;
}
.trollGhost.is-visible{ opacity: 1; }
@keyframes trollGhostBob{
  0%, 100%{ transform: translateY(0) rotate(-2deg); }
  50%{ transform: translateY(-6px) rotate(2deg); }
}
/* pancarte "ATTRAPE MOI !" du voleur de case, visible seulement pendant qu'il tient une case */
.trollGhost .trollGhostSign__bubble{ opacity: 0; transition: opacity .3s ease; }
.trollGhost.is-holding .trollGhostSign__bubble{ opacity: 1; }

.bingoCell.is-stolen{
  z-index: 25;
  box-shadow: 0 14px 30px rgba(0,0,0,.5), 0 0 0 2px rgba(61,206,97,.55);
  cursor: pointer;
}

/* fantome avec pancarte (effet troll) */
.trollGhostSign{
  position: absolute;
  width: 54px;
  height: 58px;
  z-index: 30;
  pointer-events: none;
  opacity: 0;
  transition: left .9s cubic-bezier(.45,0,.2,1), top .9s cubic-bezier(.45,0,.2,1), opacity .4s ease;
  filter: drop-shadow(0 6px 12px rgba(0,0,0,.55));
  animation: trollGhostBob 1.6s ease-in-out infinite;
}
.trollGhostSign.is-visible{ opacity: 1; }
.trollGhostSign__bubble{
  position: absolute;
  left: 100%;
  top: -4px;
  transform: translateX(4px);
  background: #f2f0ea;
  color: #14191b;
  font-family: "LazyDog","ZombiesBrainless",system-ui,sans-serif;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .02em;
  padding: 5px 8px;
  border-radius: 6px;
  white-space: nowrap;
  box-shadow: 0 6px 14px rgba(0,0,0,.45);
}
.trollGhostSign__bubble::after{
  content: "";
  position: absolute;
  left: -6px;
  top: 10px;
  border: 5px solid transparent;
  border-right-color: #f2f0ea;
}

/* apparition bizarre : le fantome pointe depuis un bord/coin, DECOUPE aux
   dimensions de la case elle-meme (comme s'il en sortait de l'interieur),
   oriente selon le bord (tete a l'envers en haut, couche sur le cote sur
   les bords lateraux). La direction du regard (--eye-x/--eye-y) est
   calculee en JS pour rester correcte malgre la rotation. */
.trollPeekClip{
  position: absolute;
  z-index: 24;
  overflow: hidden;
  border-radius: 10px;
  pointer-events: none;
}
.trollPeekGhost{
  position: absolute;
  width: 62%;
  aspect-ratio: 60 / 66;
  opacity: 0;
  transition: transform .4s cubic-bezier(.34,1.56,.64,1), opacity .3s ease;
}
.trollPeekGhost.is-in{ opacity: 1; }
.trollPeekGhost.edge-top{ left: 50%; top: 0; transform: translate(-50%, -100%) rotate(var(--peek-angle, 0deg)); }
.trollPeekGhost.edge-top.is-in{ transform: translate(-50%, -28%) rotate(var(--peek-angle, 0deg)); }
.trollPeekGhost.edge-bottom{ left: 50%; bottom: 0; transform: translate(-50%, 100%) rotate(var(--peek-angle, 0deg)); }
.trollPeekGhost.edge-bottom.is-in{ transform: translate(-50%, 28%) rotate(var(--peek-angle, 0deg)); }
.trollPeekGhost.edge-left{ left: 0; top: 50%; transform: translate(-100%, -50%) rotate(var(--peek-angle, 0deg)); }
.trollPeekGhost.edge-left.is-in{ transform: translate(-28%, -50%) rotate(var(--peek-angle, 0deg)); }
.trollPeekGhost.edge-right{ right: 0; top: 50%; transform: translate(100%, -50%) rotate(var(--peek-angle, 0deg)); }
.trollPeekGhost.edge-right.is-in{ transform: translate(28%, -50%) rotate(var(--peek-angle, 0deg)); }
.trollPeekGhost.edge-tl{ left: 0; top: 0; transform: translate(-100%, -100%) rotate(var(--peek-angle, 0deg)); }
.trollPeekGhost.edge-tl.is-in{ transform: translate(-20%, -20%) rotate(var(--peek-angle, 0deg)); }
.trollPeekGhost.edge-tr{ right: 0; top: 0; transform: translate(100%, -100%) rotate(var(--peek-angle, 0deg)); }
.trollPeekGhost.edge-tr.is-in{ transform: translate(20%, -20%) rotate(var(--peek-angle, 0deg)); }
.trollPeekGhost.edge-bl{ left: 0; bottom: 0; transform: translate(-100%, 100%) rotate(var(--peek-angle, 0deg)); }
.trollPeekGhost.edge-bl.is-in{ transform: translate(-20%, 20%) rotate(var(--peek-angle, 0deg)); }
.trollPeekGhost.edge-br{ right: 0; bottom: 0; transform: translate(100%, 100%) rotate(var(--peek-angle, 0deg)); }
.trollPeekGhost.edge-br.is-in{ transform: translate(20%, 20%) rotate(var(--peek-angle, 0deg)); }

/* fantome moonwalk (effet troll) */
.trollMoonwalk{
  position: absolute;
  bottom: 14px;
  left: -60px;
  width: 50px;
  z-index: 30;
  pointer-events: none;
  opacity: 0;
}
.trollMoonwalk.is-going{
  animation: trollMoonwalkGo 3.2s linear forwards;
}
@keyframes trollMoonwalkGo{
  0%{ opacity: 0; transform: translateX(0) scaleX(-1); }
  5%{ opacity: 1; }
  95%{ opacity: 1; }
  100%{ opacity: 0; transform: translateX(var(--walk-distance, 720px)) scaleX(-1); }
}
/* les cases flippent sur elles-memes au passage du fantome moonwalk */
.bingoGrid{ perspective: 900px; }
.bingoCell.troll-cell-flip{ animation: trollCellFlip .5s ease; }
@keyframes trollCellFlip{
  0%{ transform: rotateY(0deg); }
  50%{ transform: rotateY(180deg); }
  100%{ transform: rotateY(360deg); }
}

/* fantomes voleurs de curseur (essaim) */
.trollCursorGhost{
  position: absolute;
  z-index: 32;
  pointer-events: none;
}
.trollCursorGhost .ghostBody{ stroke: var(--ghost-accent, #3dce61); }

/* une fois l'essaim au complet, le vrai curseur systeme disparait sur la
   grille (kidnappe) et un curseur factice se balade tout seul */
.bingoGrid.troll-cursor-hidden,
.bingoGrid.troll-cursor-hidden *{
  cursor: none !important;
}
.trollFakeCursor{
  position: absolute;
  z-index: 33;
  width: 22px;
  height: 22px;
  pointer-events: none;
  opacity: 0;
  transition: opacity .3s ease;
  filter: drop-shadow(0 3px 6px rgba(0,0,0,.5));
}
.trollFakeCursor.is-visible{ opacity: 1; }
.trollFakeCursor svg{ width: 100%; height: 100%; display: block; }
.trollMoonwalkStar{
  position: absolute;
  bottom: 26px;
  z-index: 29;
  font-size: 12px;
  color: #ffce6b;
  pointer-events: none;
  animation: trollStarFade 1s ease forwards;
}
@keyframes trollStarFade{
  0%{ opacity: 1; transform: translateY(0) scale(1); }
  100%{ opacity: 0; transform: translateY(10px) scale(.4); }
}

/* confettis (effet troll) */
.trollConfetti{
  position: absolute;
  top: -10px;
  width: 8px;
  height: 14px;
  z-index: 26;
  opacity: .95;
  pointer-events: none;
  animation: trollConfettiFall linear forwards;
}
@keyframes trollConfettiFall{
  to{ transform: translateY(560px) rotate(540deg); opacity: 0; }
}

/* ballons qui montent (effet troll) */
.trollBalloon{
  position: absolute;
  bottom: -40px;
  width: 30px;
  height: 38px;
  z-index: 26;
  border-radius: 50% 50% 50% 50% / 55% 55% 45% 45%;
  pointer-events: none;
  animation: trollBalloonRise 3.6s ease-in forwards;
}
.trollBalloon::after{
  content: "";
  position: absolute;
  left: 50%;
  top: 100%;
  width: 1px;
  height: 24px;
  background: rgba(255,255,255,.4);
}
@keyframes trollBalloonRise{
  0%{ transform: translate(0,0); }
  100%{ transform: translate(var(--sway,20px), -540px); opacity: 0; }
}

/* tout devient rose paillete (effet troll, version kawaii) */
.bingoGrid.troll-kawaii{ filter: hue-rotate(300deg) saturate(1.6) brightness(1.1); }
.trollKawaiiLayer{
  position: absolute;
  inset: 0;
  z-index: 27;
  pointer-events: none;
  opacity: 0;
  transition: opacity .5s ease;
  background:
    radial-gradient(circle at 30% 20%, rgba(255,143,214,.25), transparent 60%),
    radial-gradient(circle at 80% 80%, rgba(255,200,240,.20), transparent 55%);
}
.trollKawaiiLayer.is-visible{ opacity: 1; }
.trollKawaiiSparkle{
  position: absolute;
  pointer-events: none;
  animation: trollKawaiiTwinkle 1.4s ease-in-out infinite;
}
@keyframes trollKawaiiTwinkle{
  0%, 100%{ opacity: .2; transform: scale(.6); }
  50%{ opacity: 1; transform: scale(1.3); }
}
.trollKawaiiHeart{
  position: absolute;
  z-index: 28;
  pointer-events: none;
  opacity: 0;
  animation: trollHeartFloat 3.6s ease-in forwards;
}
@keyframes trollHeartFloat{
  0%{ opacity: 0; transform: translateY(0) scale(.6); }
  10%{ opacity: 1; }
  90%{ opacity: 1; }
  100%{ opacity: 0; transform: translateY(-140px) scale(1.1); }
}

/* vague mexicaine (effet troll, plus de mouvement) */
.bingoCell.troll-wave-hop{
  animation: trollWaveHop .6s cubic-bezier(.34,1.56,.64,1);
}
@keyframes trollWaveHop{
  0%, 100%{ transform: translateY(0) scale(1) rotate(0deg); }
  35%{ transform: translateY(-18px) scale(1.12) rotate(-4deg); }
  65%{ transform: translateY(-10px) scale(1.06) rotate(3deg); }
}

/* respiration de la grille (effet troll) */
@keyframes trollBreathe{
  0%, 100%{ transform: scale(1); }
  50%{ transform: scale(var(--breathe-scale, 1.035)); }
}
.bingoGrid.troll-breathe{
  animation: trollBreathe var(--breathe-speed, 4500ms) ease-in-out infinite;
}

.trollDebris{
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 5;
}
/* chaque fragment reutilise le gabarit .bingoCell (image + texte au meme endroit
   que l'originale) mais decoupe en petit morceau via clip-path : illusion d'un
   vrai morceau arrache. Deux phases : eclatement rapide vers l'exterieur (radial
   depuis le centre de la case), puis chute plus lente qui s'empile en bas de la grille. */
.trollFragment.bingoCell{
  position: absolute;
  cursor: default;
  pointer-events: none;
  opacity: 1;
  overflow: hidden;
  box-shadow: 0 6px 14px rgba(0,0,0,.45);
  transform: translate(0,0) rotate(0deg);
}
.trollFragment.is-bursting{ transition: transform 320ms cubic-bezier(.18,.9,.32,1); }
.trollFragment.is-falling{ transition: transform 2000ms cubic-bezier(.36,.15,.4,1); }

/* positionnee par-dessus la grille (pas plein ecran) : spooky-bingo.js reparente cet
   element dans #bingoGrid (position:relative) une fois au demarrage */
.bingoJumpscare{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: rgba(0,0,0,.85);
  border-radius: 14px;
  opacity: 0;
  pointer-events: none;
  transition: opacity .08s ease-out;
  z-index: 21;
}
.bingoJumpscare.is-visible{ opacity: 1; }

/* =========================
   MODALE DE QUIZ (mode Normal+Quiz / Personnalisee+Quiz) — partagee en temps
   reel : tous les joueurs sur le lien voient la meme question et le meme
   resultat.
========================= */
.bingoQuizModal{
  position: fixed;
  inset: 0;
  z-index: 98;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
/* le HTML pilote l'ouverture/fermeture via l'attribut natif "hidden" (spooky-bingo.js
   fait quizModal.hidden = true/false) — sans cette regle, ".bingoQuizModal{
   display:flex }" a exactement la meme specificite que la regle par defaut du
   navigateur "[hidden]{ display:none }" et gagne car chargee apres, donc la
   modale restait visible (vide) en permanence, par-dessus n'importe quel ecran */
.bingoQuizModal[hidden]{ display: none; }
.bingoQuizModal__backdrop{
  position: absolute;
  inset: 0;
  background: rgba(4,3,8,.78);
  backdrop-filter: blur(4px);
}
.bingoQuizModal__box{
  position: relative;
  width: min(560px, 100%);
  max-height: 88vh;
  overflow-y: auto;
  padding: 22px 22px 18px;
  border-radius: 18px;
  border: 1px solid rgba(255,190,90,.30);
  background: rgba(12,10,16,.96);
  box-shadow: 0 30px 80px rgba(0,0,0,.55);
}
.bingoQuizModal__target{
  margin: 0 0 4px;
  font-size: 11px;
  letter-spacing: .08em;
  color: var(--green);
}
.bingoQuizModal__hint{
  margin: 0 0 12px;
  font-size: 10px;
  letter-spacing: .10em;
  color: rgba(219,219,219,.45);
}
.bingoQuizModal__question{
  margin: 0 0 16px;
  font-family: "LazyDog", system-ui, sans-serif;
  font-size: 18px;
  line-height: 1.3;
  letter-spacing: .01em;
  color: rgba(219,219,219,.95);
}
.bingoQuizModal__answers{
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}
.bingoQuizAnswer{
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px solid rgba(219,219,219,.16);
  background: rgba(255,255,255,.03);
  font-size: 13px;
  color: rgba(219,219,219,.88);
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.bingoQuizAnswer:hover{ border-color: rgba(255,190,90,.40); }
.bingoQuizAnswer input{ accent-color: var(--green); width: 16px; height: 16px; flex: none; }
.bingoQuizAnswer.is-correct{
  border-color: rgba(61,206,97,.65);
  background: rgba(61,206,97,.14);
  color: rgba(163,255,183,.98);
}
.bingoQuizAnswer.is-wrong{
  border-color: rgba(255,90,90,.65);
  background: rgba(255,90,90,.14);
  color: rgba(255,180,180,.98);
}
.bingoQuizModal__result{
  margin: 0 0 14px;
  font-size: 12px;
  letter-spacing: .02em;
  color: rgba(255,140,140,.95);
}
.bingoQuizModal__actions{
  display: flex;
  justify-content: flex-end;
}
.bingoQuizModal__actions button{
  padding: 10px 22px;
  border-radius: 999px;
  border: 1px solid rgba(61,206,97,.50);
  background: rgba(61,206,97,.14);
  color: var(--green);
  font-family: "LazyDog", system-ui, sans-serif;
  letter-spacing: .05em;
  font-size: 13px;
  cursor: pointer;
}
.bingoQuizModal__actions button:hover{
  border-color: rgba(61,206,97,.75);
  box-shadow: 0 0 0 1px rgba(61,206,97,.16);
}

/* =========================
   RESPONSIVE
========================= */
@media (max-width: 720px){
  .bingo{ padding: 12px; gap: 12px; }
  .bingoPlay{ gap: 20px; }
  .bingoGrid{ gap: 5px; }
  .bingoCell{ border-radius: 9px; padding: 4px 3px 3px; }
  .bingoCell__img{ max-width: 52px; max-height: 52px; }
  .bingoCell__label{ font-size: 10.5px; -webkit-line-clamp: 3; }
  .bingoLegend{ gap: 6px 12px; }
  .bingoLegend__item{ font-size: 9.5px; }
  .bingoToolbar{ flex-direction: column; align-items: stretch; }
  .bingoToolbar__actions{ justify-content: center; }
  .trollExplodeOverlay{ font-size: 64px; }
  .bingoModes__grid{ grid-template-columns: 1fr; }
  .bingoCustomGrid{ grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (prefers-reduced-motion: reduce){
  .bingoCell{ transition: opacity .01s linear, transform .01s linear; }
  .bingoCell.is-winning{ animation: none; }
  .bingoGrid{ transition: none; }
  .troll-shake, .troll-explode-impact, .troll-breathe{ animation: none; }
  .trollWhisper{ transition: none; }
  .trollGhost, .trollGhostSign{ animation: none; transition: opacity .2s ease; }
  .ghostArm, .ghostBody{ animation: none; transition: none; }
  .ghostPupil{ transition: none; }
  .trollPeekGhost{ transition: opacity .2s ease; }
  .trollMoonwalk.is-going{ animation: none; opacity: 0; }
  .bingoCell.troll-cell-flip{ animation: none; }
  .bingoCell.is-shining, .bingoCell.is-shining::before{ animation: none; }
  .trollConfetti, .trollBalloon, .trollKawaiiSparkle, .trollKawaiiHeart, .bingoCell.troll-wave-hop{ animation: none; }
  .trollExplodeOverlay, .trollExplodeOverlay.is-boom{ animation: none; }
  .trollFragment.is-bursting, .trollFragment.is-falling{ transition: none; }
}
