/* ECRAN DE GAIN — le coffre, sa lueur, le butin qui flotte.

   Huitieme feuille, chargee en dernier : toutes ses regles sont portees par
   #screen-gain, donc sa place dans la cascade ne peut rien deranger ailleurs.
   Comme les sept autres, elle doit rester alignee entre frontend/index.html
   et SHELL_FILES dans frontend/sw.js.

   Une seule regle de fabrication tient toute la feuille : on n'anime que
   `transform` et `opacity`, que le compositeur traite sans repeindre. La
   seule exception est le defilement des frames du coffre — six repeints en
   sept cents millisecondes, ce qui est exactement le cout d'un sprite. */

/* La colonne est un flex, pas un bloc : le corps doit prendre EXACTEMENT ce
   que l'entete lui laisse. En `height: 100%` il debordait de la hauteur de
   l'entete, et les boutons passaient sous le bord de l'ecran — la seule
   chose qu'on ne voyait pas etait justement celle sur laquelle on appuie. */
#screen-gain {
  padding: 0;
  overflow: hidden;
}

#screen-gain.active {
  display: flex;
  flex-direction: column;
}

/* ------------------------------------------------------------------ fond */

/* Le sous-bois et le socle de pierre. Sa source est posee par gain.js a
   l'ouverture et retiree a la fermeture : un fond plein ecran pese quatre
   megaoctets decodes, et l'ecran ne se voit que quelques secondes. */
.gain-bg,
.gain-veil {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.gain-bg {
  background: #0a1a12 center bottom / cover no-repeat;
  /* Une lente derive, comme l'accueil : le decor respire sans que rien ne se
     repeigne. Periode premiere avec celle de la lueur, sinon les deux
     repasseraient ensemble par leur point de depart. */
  animation: gain-drift 29s ease-in-out infinite alternate;
}

/* Le voile : le texte doit se lire sur une photo, et le bas de l'ecran porte
   trois boutons. Deux degrades plutot qu'un aplat, qui eteindrait la foret. */
.gain-veil {
  background:
    linear-gradient(180deg, rgba(7, 21, 16, 0.82) 0%, rgba(7, 21, 16, 0.15) 26%,
                    rgba(7, 21, 16, 0.10) 50%, rgba(7, 21, 16, 0.78) 82%,
                    rgba(7, 21, 16, 0.94) 100%),
    radial-gradient(120% 60% at 50% 62%, rgba(255, 214, 130, 0.10), transparent 70%);
}

@keyframes gain-drift {
  from { transform: scale(1.06) translate3d(-8px, 0, 0); }
  to   { transform: scale(1.06) translate3d(8px, -6px, 0); }
}

/* ---------------------------------------------------------------- colonne */

.gain-head,
.gain-body {
  position: relative;
  z-index: 2;
}

.gain-head {
  flex: none;
  padding: calc(var(--safe-top) + 10px) 14px 4px;
}

.gain-body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
  padding: 0 14px calc(var(--safe-bot) + 14px);
  gap: 10px;
}

/* Le bandeau d'annonce, meme grammaire que la note de la zone de jeu. */
.gain-note {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  border-radius: var(--radius);
  background: var(--glass-2);
  border: var(--line);
  box-shadow: var(--shadow-2), var(--bevel);
  backdrop-filter: blur(8px);
  flex: none;
}

.gain-note .brick-txt { min-width: 0; }

/* ----------------------------------------------------------------- scene */

/* La scene prend tout ce qui reste : c'est le coffre qu'on regarde, pas les
   boutons. `min-height: 0` parce qu'un enfant de flex refuse sinon de
   retrecir sous son contenu, et la colonne partirait sous l'ecran. */
/* Le coffre se CENTRE dans ce qui reste. Amarre en bas, il se retrouvait sous
   le pouce avec un tiers d'ecran vide au-dessus : c'est l'objet du geste, il
   se pose au milieu du regard, pas au ras des boutons. */
.gain-stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

/* La plaque « +1 diamant ». Elle arrive apres l'ouverture, jamais avant :
   annoncer le gain sur un coffre ferme retire tout l'interet de l'ouvrir. */
.gain-plaque {
  position: relative;
  z-index: 4;
  margin-bottom: -14px;
  padding: 9px 26px;
  border-radius: 14px;
  background: linear-gradient(180deg, rgba(37, 84, 58, 0.95), rgba(12, 38, 26, 0.95));
  border: 1px solid rgba(226, 201, 141, 0.45);
  box-shadow: var(--shadow-2), var(--glow-gold), var(--bevel);
  font-family: var(--display, inherit);
  font-weight: 900;
  font-size: 1.5rem;
  color: var(--gold);
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.6);
  opacity: 0;
  transform: translate3d(0, 14px, 0) scale(0.9);
  transition: opacity 0.32s ease, transform 0.42s cubic-bezier(0.22, 1.4, 0.36, 1);
}

.gain-plaque.in {
  opacity: 1;
  transform: none;
}

.gain-scene {
  position: relative;
  width: 100%;
  max-width: 460px;
  aspect-ratio: 1134 / 1060;      /* l'enveloppe commune aux six frames */
  margin: 0 auto;
}

/* ----------------------------------------------------------------- coffre */

/* Les deux couches se superposent au pixel pres : prepare_coffre.py rogne les
   six frames sur la MEME enveloppe, donc la planche en demi-resolution et
   l'image finale ont le meme cadrage. C'est ce qui permet de passer de l'une
   a l'autre par un simple fondu sans que le coffre bouge d'un cheveu. */
.gain-anim,
.gain-open {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.gain-anim {
  background: no-repeat 0 0 / 100% 600%;      /* six frames empilees */
  filter: drop-shadow(0 18px 26px rgba(0, 0, 0, 0.55));
}

/* steps(6) sur 0 -> 120 % donne exactement 0, 20, 40, 60, 80, 100 % :
   les six frames, la derniere comprise. Sur 0 -> 100 % la sixieme ne serait
   jamais atteinte. */
.gain-anim.run {
  animation: gain-frames 0.708s steps(6, end) forwards;
}

@keyframes gain-frames {
  from { background-position-y: 0%; }
  to   { background-position-y: 120%; }
}

.gain-open {
  object-fit: contain;
  opacity: 0;
  transition: opacity 0.26s ease;
  filter: drop-shadow(0 18px 26px rgba(0, 0, 0, 0.55));
}

.gain-open.lit { opacity: 1; }

/* Le tremblement d'avant l'ouverture : le couvercle resiste. Quatre cents
   millisecondes, pas plus — au-dela cela ressemble a une panne. */
#screen-gain.shaking .gain-scene {
  animation: gain-shake 0.42s ease-in-out;
}

@keyframes gain-shake {
  0%, 100% { transform: translate3d(0, 0, 0) rotate(0); }
  15% { transform: translate3d(-4px, 0, 0) rotate(-0.7deg); }
  32% { transform: translate3d(5px, -1px, 0) rotate(0.8deg); }
  52% { transform: translate3d(-5px, 1px, 0) rotate(-0.9deg); }
  74% { transform: translate3d(4px, 0, 0) rotate(0.6deg); }
  88% { transform: translate3d(-2px, 0, 0) rotate(-0.3deg); }
}

/* ------------------------------------------------------------------ lueur */

/* Le faisceau qui sort du coffre. Un degrade conique aurait donne des rayons
   nets et reguliers, donc mecaniques ; deux degrades radiaux superposes et
   respirant a des cadences differentes font une lumiere qui palpite. */
.gain-rays {
  position: absolute;
  left: 50%;
  bottom: 34%;
  width: 150%;
  aspect-ratio: 1;
  transform: translate3d(-50%, 0, 0) scale(0.4);
  opacity: 0;
  pointer-events: none;
  background:
    radial-gradient(closest-side, rgba(255, 236, 170, 0.55), rgba(255, 210, 110, 0.16) 45%, transparent 72%),
    radial-gradient(closest-side, rgba(255, 255, 225, 0.45), transparent 38%);
  transition: opacity 0.5s ease, transform 0.7s cubic-bezier(0.2, 0.9, 0.3, 1);
  z-index: 1;
}

#screen-gain.lit .gain-rays {
  opacity: 1;
  transform: translate3d(-50%, 0, 0) scale(1);
}

#screen-gain.opened .gain-rays {
  animation: gain-pulse 2.6s ease-in-out infinite alternate;
}

@keyframes gain-pulse {
  from { opacity: 0.72; }
  to   { opacity: 1; }
}

/* ------------------------------------------------------------------ butin */

/* Les objets sont poses des l'ouverture de l'ecran, invisibles : les creer au
   moment ou ils jaillissent ferait decoder leur image pile pendant
   l'animation, donc un a-coup a l'instant precis ou l'on regarde. */
.gain-loot {
  --rise: -66px;                   /* le vol des objets, hors du coffre */
  --bob: -84px;                    /* le haut du flottement */
  position: absolute;
  left: 50%;
  bottom: 38%;
  z-index: 3;
  display: flex;
  align-items: flex-end;
  transform: translateX(-50%);
  pointer-events: none;
}

.loot {
  position: relative;
  margin: 0;
  width: 0;                        /* le decalage se fait par --dx */
  display: flex;
  flex-direction: column;
  align-items: center;
  opacity: 0;
  transform: translate3d(var(--dx), 30px, 0) scale(0.3);
}

/* Deux animations enchainees et non une seule : la sortie est un elan unique,
   le flottement une boucle. Les fondre aurait oblige a repeter le decalage
   horizontal dans chaque image cle de la boucle. */
.gain-loot.out .loot {
  animation:
    gain-rise 0.62s cubic-bezier(0.2, 1.25, 0.35, 1) forwards,
    gain-float 3.1s ease-in-out infinite alternate;
  animation-delay: calc(var(--i) * 170ms), calc(var(--i) * 170ms + 0.62s);
}

@keyframes gain-rise {
  from { opacity: 0; transform: translate3d(var(--dx), 30px, 0) scale(0.3); }
  60%  { opacity: 1; }
  to   { opacity: 1; transform: translate3d(var(--dx), var(--rise), 0) scale(1); }
}

@keyframes gain-float {
  from { transform: translate3d(var(--dx), var(--rise), 0) scale(1); }
  to   { transform: translate3d(var(--dx), var(--bob), 0) scale(1.03); }
}

.loot img {
  width: 96px;
  height: 96px;
  object-fit: contain;
  filter:
    drop-shadow(0 0 18px rgba(255, 226, 150, 0.75))
    drop-shadow(0 10px 16px rgba(0, 0, 0, 0.55));
}

.gain-loot.many .loot img { width: 68px; height: 68px; }

.loot figcaption {
  margin-top: 4px;
  padding: 2px 9px;
  border-radius: 999px;
  white-space: nowrap;
  font-size: 0.68rem;
  font-weight: 800;
  color: var(--parchment);
  background: rgba(7, 21, 16, 0.72);
  border: var(--line);
}

/* Recuperer : le butin plonge vers la besace, en bas. Un objet qui disparait
   sur place ne dit pas ou il est parti. */
#screen-gain.taking .loot {
  animation: none;
  opacity: 0;
  transform: translate3d(var(--dx), 190px, 0) scale(0.24);
  transition: opacity 0.42s ease 0.06s, transform 0.5s cubic-bezier(0.5, 0, 0.9, 0.4);
}

#screen-gain.taking .gain-plaque { opacity: 0; transform: translate3d(0, -10px, 0); }

/* ---------------------------------------------------------------- boutons */

.gain-acts {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
  opacity: 0;
  transform: translate3d(0, 12px, 0);
  transition: opacity 0.3s ease, transform 0.36s ease;
  pointer-events: none;
}

.gain-acts.in {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

/* ---------------------------------------------------------------- paysage */

/* En paysage la colonne devient deux : le coffre a gauche, le texte et les
   boutons a droite. Empilee, la scene ne laissait que soixante pixels de
   haut au coffre, et l'animation ne se voyait plus. */
@media (orientation: landscape) and (max-height: 560px) {
  .gain-body {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    align-items: center;
    gap: 8px 16px;
    max-width: none;
  }
  /* La scene se borne par sa HAUTEUR et non par sa largeur : bornee en
     largeur, elle depassait du bas de l'ecran et le coffre sortait du cadre —
     ce qui est exactement ce qu'on vient regarder. */
  .gain-stage {
    grid-column: 1;
    grid-row: 1 / span 2;
    justify-content: center;
    height: 100%;
  }
  .gain-scene {
    width: auto;
    height: 100%;
    max-width: 100%;
    max-height: 100%;
  }
  .gain-plaque {
    position: absolute;
    top: 0;
    margin: 0;
    font-size: 1.15rem;
    padding: 5px 16px;
  }
  .gain-note { grid-column: 2; grid-row: 1; align-self: end; }
  .gain-acts { grid-column: 2; grid-row: 2; align-self: start; max-width: 320px; }
  .gain-loot { --rise: -34px; --bob: -44px; bottom: 42%; }
  .loot img { width: 60px; height: 60px; }
  .gain-loot.many .loot img { width: 46px; height: 46px; }
  .gain-head { padding-bottom: 0; }
}

/* -------------------------------------------------------- moins de mouvement */

@media (prefers-reduced-motion: reduce) {
  .gain-bg { animation: none; }
  #screen-gain.shaking .gain-scene { animation: none; }
  .gain-anim.run { animation-duration: 0.36s; }
  .gain-loot.out .loot {
    animation: gain-rise 0.3s ease forwards;
    animation-delay: calc(var(--i) * 90ms);
  }
  #screen-gain.opened .gain-rays { animation: none; }
}
