/* ===========================================================================
   SEAVEN — fond animé
   ---------------------------------------------------------------------------
   Repris du portfolio, transposé dans la palette Seaven : le jaune acide
   d'origine (#e8ff47) cède la place au vert #5ee08a, et les blancs sont
   abaissés pour ne pas éclaircir l'encre.

   Cinq couches, toutes purement décoratives et sans interception du pointeur :
     ::before      un plan incliné qui dérive lentement
     ::after       une dalle basculée en 3D
     .grid-layer   la grille en perspective, qui défile à l'infini
     .beam         deux halos flous, en fondu additif
     .spark        cinq points lumineux qui respirent

   EMPILEMENT — le point délicat.
   Le fond est en `z-index: -1`, donc derrière le contenu. Pour qu'il reste
   visible, `body` doit être transparent : c'est `html` qui porte l'encre.
   Sans cela, le fond du body le recouvrirait entièrement.
   =========================================================================== */

/* html porte la couleur, body la laisse passer. */
body{ background: transparent !important; }

.motion-bg{
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  perspective: 1100px;
}

.motion-bg::before,
.motion-bg::after{
  content: "";
  position: absolute;
  pointer-events: none;
}

/* Plan incliné, en haut à gauche. */
.motion-bg::before{
  left: -14vw;
  top: -10vh;
  width: 62vw;
  height: 128vh;
  background:
    linear-gradient(115deg, rgba(255,255,255,.030), transparent 28%),
    linear-gradient(180deg, rgba(94,224,138,.075), rgba(13,23,16,.12));
  clip-path: polygon(26% 0, 100% 0, 72% 100%, 0 100%);
  opacity: .52;
  animation: fondPlan 24s ease-in-out infinite;
}

/* Dalle basculée, en bas à droite. */
.motion-bg::after{
  right: -16vw;
  bottom: -30vh;
  width: 76vw;
  height: 86vh;
  background:
    radial-gradient(circle at 32% 20%, rgba(94,224,138,.10), transparent 34%),
    linear-gradient(130deg, rgba(255,255,255,.032), rgba(255,255,255,.008) 46%, transparent 72%);
  clip-path: polygon(14% 0, 100% 18%, 84% 100%, 0 76%);
  opacity: .46;
  transform: rotateX(62deg) rotateZ(-8deg) translate3d(0, 0, -160px);
  animation: fondDalle 28s ease-in-out infinite;
}

/* Grille en perspective. Le masque la fait disparaître vers le haut, sinon
   elle formerait une ligne d'horizon nette et artificielle. */
.grid-layer{
  position: absolute;
  left: -14%;
  right: -14%;
  bottom: -34%;
  height: 92%;
  background-image:
    linear-gradient(rgba(94,224,138,.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(94,224,138,.040) 1px, transparent 1px);
  background-size: 68px 68px;
  mask-image: linear-gradient(to top, rgba(0,0,0,.88), transparent 80%);
  -webkit-mask-image: linear-gradient(to top, rgba(0,0,0,.88), transparent 80%);
  transform-origin: 50% 100%;
  transform: rotateX(68deg) translate3d(0, 10vh, -120px);
  opacity: .6;
  animation: fondGrille 22s linear infinite;
}

/* Halos. `screen` additionne la lumière au lieu de la peindre par-dessus :
   sur un fond sombre, c'est ce qui donne l'impression d'une source. */
.beam{
  position: absolute;
  width: 48vw;
  height: 48vw;
  border-radius: 50%;
  filter: blur(72px);
  opacity: .30;
  mix-blend-mode: screen;
}
.beam-a{
  background: rgba(94,224,138,.24);
  top: -18vw;
  right: 4vw;
  animation: fondHaloA 17s ease-in-out infinite;
}
.beam-b{
  background: rgba(38,120,80,.30);
  bottom: -8vh;
  left: -18vw;
  animation: fondHaloB 21s ease-in-out infinite;
}

/* Étincelles. */
.spark{
  position: absolute;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--accent, #5ee08a);
  box-shadow: 0 0 18px rgba(94,224,138,.8);
  animation: fondEtincelle 11s ease-in-out infinite;
}
.spark.s1{ left:  8%; top: 20%; animation-delay: -1s; }
.spark.s2{ left: 82%; top: 14%; animation-delay: -4s; }
.spark.s3{ left: 64%; top: 52%; animation-delay: -7s; }
.spark.s4{ left: 22%; top: 74%; animation-delay: -2s; }
.spark.s5{ left: 91%; top: 78%; animation-delay: -6s; }

/* Grain. Il vit DANS le fond, pas en surcouche : à z-index 9999 comme dans
   le portfolio, il passerait au-dessus des modales de l'administration. */
.motion-bg .grain{
  position: absolute;
  inset: -50%;
  opacity: .028;
  pointer-events: none;
  background-repeat: repeat;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ------------------------------------------------------------ ANIMATIONS */
@keyframes fondPlan{
  0%, 100% { transform: translate3d(0, 0, -120px) rotateX(0deg); }
  50%      { transform: translate3d(2vw, 2vh, -90px) rotateX(2deg); }
}
@keyframes fondDalle{
  0%, 100% { transform: rotateX(62deg) rotateZ(-8deg) translate3d(0, 0, -160px); }
  50%      { transform: rotateX(60deg) rotateZ(-5deg) translate3d(-2vw, -3vh, -130px); }
}
@keyframes fondGrille{
  0%   { background-position: 0 0; }
  100% { background-position: 68px 68px; }
}
@keyframes fondHaloA{
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(-10vw, 10vh, 0) scale(1.12); }
}
@keyframes fondHaloB{
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(12vw, -8vh, 0) scale(1.1); }
}
@keyframes fondEtincelle{
  0%, 100% { transform: translate3d(0, 0, 0); opacity: .4; }
  50%      { transform: translate3d(18px, -26px, 0); opacity: 1; }
}

/* ------------------------------------------------------------ RESPONSIVE */
@media (max-width: 720px){
  /* Sur téléphone, les flous plein écran coûtent cher pour un fond que
     l'on ne regarde pas : on garde les halos, on retire le reste. */
  .motion-bg::after,
  .grid-layer,
  .spark{ display: none; }
  .beam{ filter: blur(56px); opacity: .26; }
}

@media (prefers-reduced-motion: reduce){
  .motion-bg::before,
  .motion-bg::after,
  .grid-layer,
  .beam,
  .spark{ animation: none !important; }
}
