/* 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: 640px;
  line-height: 1.4;
}

/* espacement genereux et regulier (comme sur Spooky Bingo) : une capture OBS
   centree sur la seule grille ne "mange" jamais la barre du haut ou le texte
   d'aide en dessous */
.box{
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 32px;
}

/* =========================
   TOOLBAR
========================= */
.boxToolbar{
  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);
}

.boxToolbar__count{
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  letter-spacing: .06em;
  color: rgba(219,219,219,.65);
}
.boxToolbar__count label{ cursor: default; }
.boxToolbar__colsLabel{ margin-left: 4px; }

/* champ libre : nombre de boites / nombre de colonnes — aucune limite a un
   preset, l'utilisateur tape ce qu'il veut (borne juste a une plage raisonnable) */
.boxNumberInput{
  width: 64px;
  height: 32px;
  padding: 0 8px;
  border-radius: 8px;
  border: 1px solid rgba(219,219,219,.16);
  background: rgba(12,15,16,.55);
  color: rgba(219,219,219,.92);
  font-family: "LazyDog", system-ui, sans-serif;
  font-size: 13px;
  text-align: center;
}
.boxNumberInput:focus{
  outline: none;
  border-color: rgba(61,206,97,.55);
}

.boxCountBtn{
  width: 52px;
  height: 32px;
  border-radius: 8px;
  border: 1px solid rgba(219,219,219,.16);
  background: rgba(12,15,16,.55);
  color: rgba(219,219,219,.80);
  font-family: "LazyDog", system-ui, sans-serif;
  font-size: 12px;
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease, color .15s ease;
}
.boxCountBtn:hover{ border-color: rgba(61,206,97,.35); }
.boxCountBtn.is-active{
  border-color: rgba(61,206,97,.55);
  background: rgba(61,206,97,.16);
  color: var(--green);
}

/* selecteur de couleur natif pour la teinte des boites fermees */
.boxColorInput{
  width: 36px;
  height: 32px;
  padding: 2px;
  border-radius: 8px;
  border: 1px solid rgba(219,219,219,.16);
  background: rgba(12,15,16,.55);
  cursor: pointer;
}
.boxColorInput::-webkit-color-swatch-wrapper{ padding: 0; }
.boxColorInput::-webkit-color-swatch{ border: none; border-radius: 6px; }
.boxColorInput::-moz-color-swatch{ border: none; border-radius: 6px; }

.boxToolbar__actions{ display: flex; gap: 8px; }

.boxBtn{
  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;
}
.boxBtn:hover{ border-color: rgba(255,190,90,.45); }

/* =========================
   GRILLE DE BOITES
========================= */
/* meme largeur max que la grille de Spooky Bingo (560px) : peu importe le
   nombre de boites choisi, la zone a capturer dans OBS garde une largeur
   coherente d'un mini-jeu a l'autre.
   La disposition (nombre de colonnes) est pilotee par --box-cols/--box-min,
   mis a jour en JS via le bouton "DISPOSITION" — permet a une streameuse de
   recadrer ses boites (ex: 5 colonnes x 2 rangees au lieu de 4 x 3) pour que
   la capture OBS ait la forme qu'elle veut. */
.boxGrid{
  --box-accent: #9664d7;
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--box-cols, auto-fill), minmax(var(--box-min, 122px), 1fr));
  gap: 8px;
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
}

.boxCell{
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1 / 1;
  padding: 10px;
  border-radius: 14px;
  border: 2px solid color-mix(in srgb, var(--box-accent) 45%, transparent);
  background:
    linear-gradient(155deg, color-mix(in srgb, var(--box-accent) 40%, rgba(12,10,18,.55)), rgba(12,10,18,.75));
  cursor: pointer;
  text-align: center;
  overflow: hidden;
  color: rgba(219,219,219,.90);

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

.boxCell:hover{
  border-color: color-mix(in srgb, var(--box-accent) 75%, transparent);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--box-accent) 25%, transparent), 0 14px 30px rgba(0,0,0,.35);
}
.boxCell:focus-visible{
  outline: 2px solid rgba(61,206,97,.70);
  outline-offset: 2px;
}

/* boite fermee : juste le numero, en gros, centre — pas d'image dans ce jeu
   donc autant profiter de toute la place disponible */
.boxCell__number{
  font-family: "ZombiesBrainless","LazyDog",system-ui,sans-serif;
  font-size: 34px;
  color: color-mix(in srgb, var(--box-accent) 65%, white);
  line-height: 1;
  pointer-events: none;
}
.boxCell.is-revealed .boxCell__number{ display: none; }

/* boite ouverte : le defi occupe toute la case. La taille de police est
   ajustee dynamiquement (voir fitText() dans spooky-box.js) pour que le
   texte ne deborde jamais et ne soit jamais coupe/tronque par "..." — un
   defi tres long affiche juste un texte plus petit plutot que d'etre cache. */
.boxCell__text{
  display: none;
  width: 100%;
  height: 100%;
  align-items: center;
  justify-content: center;
  font-family: "LazyDog", system-ui, sans-serif;
  font-size: 15px;
  line-height: 1.16;
  letter-spacing: .01em;
  color: rgba(219,219,219,.95);
  pointer-events: none;
  white-space: normal;
  overflow-wrap: break-word;
  word-break: break-word;
  overflow: hidden;
}
.boxCell.is-revealed .boxCell__text{ display: flex; }

/* boite deja ouverte : teinte verte */
.boxCell.is-revealed{
  border-color: rgba(61,206,97,.55);
  background: linear-gradient(155deg, rgba(20,70,45,.55), rgba(10,16,12,.80));
}

/* indice discret : au survol d'une boite deja ouverte, on rappelle qu'on peut retenter */
.boxCell.is-revealed::after{
  content: "RECLIQUER POUR UN AUTRE DEFI";
  position: absolute;
  inset: auto 0 0 0;
  padding: 4px 6px;
  font-size: 8px;
  letter-spacing: .04em;
  text-align: center;
  color: rgba(163,255,183,.90);
  background: rgba(6,10,7,.85);
  opacity: 0;
  transform: translateY(100%);
  transition: opacity .15s ease, transform .15s ease;
  pointer-events: none;
}
.boxCell.is-revealed:hover::after{
  opacity: 1;
  transform: translateY(0);
}

/* secousse d'anticipation juste avant l'envol des fantomes */
.boxCell.is-shaking{
  animation: boxShake .42s ease-in-out;
}
@keyframes boxShake{
  0%, 100%{ transform: translate(0,0) rotate(0deg); }
  20%{ transform: translate(-3px, 1px) rotate(-2deg); }
  40%{ transform: translate(3px, -1px) rotate(2deg); }
  60%{ transform: translate(-2px, 0) rotate(-1.5deg); }
  80%{ transform: translate(2px, 0) rotate(1.5deg); }
}

/* petit "pop" au moment ou le defi se pose dans la case */
.boxCell.is-popped{
  animation: boxPop .5s cubic-bezier(.34,1.56,.64,1);
}
@keyframes boxPop{
  0%{ transform: scale(.85); }
  60%{ transform: scale(1.05); }
  100%{ transform: scale(1); }
}

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

/* =========================
   FANTOMES VOLANTS (convergent vers la boite cliquee)
========================= */
.boxGhost{
  position: fixed;
  top: 0;
  left: 0;
  width: 46px;
  height: 46px;
  object-fit: contain;
  opacity: 0;
  pointer-events: none;
  z-index: 60;
  transition: transform .55s ease-in, opacity .3s ease-in;
  filter: drop-shadow(0 6px 14px rgba(0,0,0,.5));
}

/* =========================
   REVELATION DU DEFI
========================= */
/* confinee a la zone de la grille (pas plein ecran) : spooky-box.js reparente
   cet element dans #boxGrid (position:relative). Important pour un stream —
   si OBS capture uniquement la zone des boites, un message plein ecran ne
   serait pas visible dans le retour ; centre sur la grille, il l'est toujours. */
.boxReveal{
  position: absolute;
  inset: 0;
  z-index: 90;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
  border-radius: 14px;
}
.boxReveal__backdrop{
  position: absolute;
  inset: 0;
  background: rgba(4,3,8,.80);
  backdrop-filter: blur(4px);
  cursor: pointer;
}
.boxReveal__box{
  position: relative;
  width: min(560px, 100%);
  max-height: 100%;
  overflow-y: auto;
  padding: 24px 22px;
  border-radius: 20px;
  border: 1px solid color-mix(in srgb, var(--box-accent) 55%, transparent);
  background: rgba(14,10,18,.96);
  box-shadow: 0 30px 90px rgba(0,0,0,.60);
  text-align: center;
  transform: scale(.85);
  opacity: 0;
  transition: opacity .25s ease, transform .25s ease;
}
.boxReveal.is-visible .boxReveal__box{
  opacity: 1;
  transform: scale(1);
}
.boxReveal.is-visible .boxReveal__backdrop{ opacity: 1; }

.boxReveal__label{
  margin: 0 0 10px;
  font-size: 12px;
  letter-spacing: .16em;
  color: color-mix(in srgb, var(--box-accent) 75%, white);
}
.boxReveal__text{
  margin: 0;
  font-family: "ZombiesBrainless","LazyDog",system-ui,sans-serif;
  font-size: 26px;
  line-height: 1.25;
  letter-spacing: .01em;
  color: var(--green);
  text-shadow: 0 0 30px rgba(61,206,97,.35);
}

/* [hidden] doit gagner sur le display:flex de .boxReveal, sinon la modale
   reste visible en permanence (meme piege que sur le quiz du Bingo) */
.boxReveal[hidden]{ display: none; }

/* =========================
   RESPONSIVE
========================= */
@media (max-width: 720px){
  .box{ padding: 12px; gap: 20px; }
  .boxGrid{ grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 6px; }
  .boxToolbar{ flex-direction: column; align-items: stretch; }
  .boxToolbar__count{ justify-content: center; }
  .boxToolbar__actions{ justify-content: center; }
}

@media (prefers-reduced-motion: reduce){
  .boxCell{ transition: opacity .01s linear, transform .01s linear; }
  .boxCell.is-shaking, .boxCell.is-popped{ animation: none; }
  .boxGhost{ transition: opacity .01s linear; }
}
