/* Subsprint 8.7 — Celebration motions: tree-burst on transitions.

   Three intensities (small / medium / large) drive the JS-side
   tree count and lift; the keyframes here are shared. The visual
   model is Messenger-style long-press hjärtan: elements pop:as
   from a trigger-punkt, drift outward, fade out.

   File-layout note: like motion.css this is plain CSS outside the
   Tailwind pipeline (loaded after dist/tailwind.css from
   base.html) so the keyframes win without specificity gymnastics.
   Keeping celebrations in their own file rather than appending to
   motion.css means a future tweak to bursts doesn't risk a typo
   in the page-load fade or the swap-flash 8.6 painted there.

   Reduced-motion contract: every @keyframes lives inside @media
   (prefers-reduced-motion: no-preference). The reduced-motion
   fallback is a 200 ms static ``✓`` near origin (see the
   ``.metod-reduced-check`` block at the bottom). The win-banner
   for SKYDD / AVA_AK still appears in reduced-motion mode (it's
   text, not motion) so the user still gets the verbal kvittens. */


/* -------------------------------------------------------------------------
   Burst container — fixed full-viewport overlay so bursts can drift
   off-screen without clipping at any container's overflow:hidden.

   z-index 100 sits above the app-shell and modals' backdrops but
   below the toast-region (which is z-index 200 in input.css). A
   modal that's already open when a burst fires *should* keep the
   modal interactive — pointer-events: none on the burst container
   guarantees that.
   ----------------------------------------------------------------------- */
.metod-tree-burst {
  position: fixed;
  inset: 0;
  z-index: 100;
  pointer-events: none;
  overflow: hidden;
}

/* Each tree positions itself absolutely within the burst container
   at a given (left, top) and animates outward. ``will-change``
   nudges the compositor to promote the layer; without it the
   first burst on a fresh page can stutter while the GPU layer
   spins up. */
.metod-tree-burst__tree {
  position: absolute;
  width: 32px;
  height: 42px;
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
  /* Default rest state — translated by -50% so the (left,top)
     coordinate is the *center* of the tree. The keyframes below
     re-apply the same -50% translate so the lift / drift values
     stay readable as absolute pixel offsets. */
  transform: translate3d(-50%, -50%, 0);
}


/* -------------------------------------------------------------------------
   Burst keyframes — three variants so adjacent trees don't drift
   in unison. The JS picks one per tree by appending the variant
   number to the animation-name CSS variable.

   Each variant uses the same ``--drift`` / ``--lift`` / ``--scale``
   / ``--spin`` / ``--duration`` custom-property contract so the JS
   only has to set values; the curve diversity comes from
   variant-specific cubic-béziers and intermediate stops.
   ----------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {

  /* Variant 1 — straight rise + fade. Most common, used for
     ~50 % of trees. */
  @keyframes metod-tree-rise-1 {
    0%   {
      opacity: 0;
      transform: translate3d(-50%, -50%, 0) scale(0.4) rotate(0deg);
    }
    18%  { opacity: 1; }
    100% {
      opacity: 0;
      transform:
        translate3d(
          calc(-50% + var(--drift, 0px)),
          calc(-50% - var(--lift, 80px)),
          0
        )
        scale(var(--scale, 1))
        rotate(var(--spin, 0deg));
    }
  }

  /* Variant 2 — small overshoot + settle. Reads as "leaping
     forward then catching breath". Used for ~30 %. */
  @keyframes metod-tree-rise-2 {
    0%   {
      opacity: 0;
      transform: translate3d(-50%, -50%, 0) scale(0.3) rotate(0deg);
    }
    20%  { opacity: 1; transform:
            translate3d(calc(-50% + var(--drift, 0px) * 0.4),
                        calc(-50% - var(--lift, 80px) * 0.45),
                        0)
            scale(calc(var(--scale, 1) * 1.08));
    }
    65%  { opacity: 0.85; }
    100% {
      opacity: 0;
      transform:
        translate3d(
          calc(-50% + var(--drift, 0px)),
          calc(-50% - var(--lift, 80px) * 0.95),
          0
        )
        scale(var(--scale, 1))
        rotate(var(--spin, 0deg));
    }
  }

  /* Variant 3 — heavier drift, used sparingly for visual rhythm. */
  @keyframes metod-tree-rise-3 {
    0%   {
      opacity: 0;
      transform: translate3d(-50%, -50%, 0) scale(0.5) rotate(0deg);
    }
    25%  { opacity: 1; }
    100% {
      opacity: 0;
      transform:
        translate3d(
          calc(-50% + var(--drift, 0px) * 1.3),
          calc(-50% - var(--lift, 80px) * 1.05),
          0
        )
        scale(var(--scale, 1))
        rotate(calc(var(--spin, 0deg) * -1));
    }
  }

  .metod-tree-burst__tree--v1 {
    animation: metod-tree-rise-1 var(--duration, 1000ms)
               cubic-bezier(0.22, 1, 0.36, 1) forwards;
  }
  .metod-tree-burst__tree--v2 {
    animation: metod-tree-rise-2 var(--duration, 1000ms)
               cubic-bezier(0.32, 0.72, 0, 1) forwards;
  }
  .metod-tree-burst__tree--v3 {
    animation: metod-tree-rise-3 var(--duration, 1000ms)
               cubic-bezier(0.16, 1, 0.3, 1) forwards;
  }
}


/* -------------------------------------------------------------------------
   Banners — amber for win events (SKYDD, AVA_AK), gråbrun for the
   sober RIP-fallback. Both use position:fixed so they drop in
   from the top centred-of-viewport regardless of scroll position.

   pointer-events:auto on the banner only — the burst container
   stays click-through so a banner-click still routes to the
   banner's own dismiss handler.
   ----------------------------------------------------------------------- */
.metod-celebrate-banner {
  position: fixed;
  top: 24px;
  left: 50%;
  z-index: 110;
  padding: 12px 22px;
  border-radius: 999px;
  font-weight: 500;
  font-size: 15px;
  letter-spacing: 0.01em;
  pointer-events: auto;
  cursor: pointer;
  /* Initial state for the keyframe-less reduced-motion path. */
  transform: translateX(-50%);
  opacity: 1;
  /* Glass recipe — same family as .surface-card so the banner
     reads as part of the same surface system. */
  background: var(--glass-bg);
  backdrop-filter: blur(18px) saturate(1.05);
  -webkit-backdrop-filter: blur(18px) saturate(1.05);
  border: 1px solid var(--glass-border);
  box-shadow: var(--shadow-active);
  color: var(--text-strong);
}

/* Amber accent for the SKYDD / AVA_AK win-banner. Not a token
   in input.css because amber is a one-time-use accent (8.7 only);
   if a second amber surface appears we promote it then. */
.metod-celebrate-banner--amber {
  border-color: #c79854;
  box-shadow:
    0 24px 56px rgba(199, 152, 84, 0.30),
    0 0 0 1px #c79854;
}

/* Sober gråbrun for RIP. Deliberately *opaque* (no glass) — the
   message is "skogen är borta", and translucent decoration would
   contradict the gravity. */
.metod-celebrate-banner--gray {
  background: #cdc7be;
  border-color: #8a8377;
  color: #3a3530;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.12);
}

@media (prefers-reduced-motion: no-preference) {
  /* Slide in from -12px, hold 2.5 s, fade up + out 0.5 s.
     ``forwards`` keeps the final hidden state so the banner DOM
     can be removed by the JS without a flash of the start state. */
  @keyframes metod-banner-in {
    0%   { opacity: 0; transform: translateX(-50%) translateY(-12px); }
    15%  { opacity: 1; transform: translateX(-50%) translateY(0); }
    85%  { opacity: 1; transform: translateX(-50%) translateY(0); }
    100% { opacity: 0; transform: translateX(-50%) translateY(-6px); }
  }
  .metod-celebrate-banner {
    animation: metod-banner-in 3000ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
  }
}


/* -------------------------------------------------------------------------
   Reduced-motion fallback — static ``✓`` at origin, fade in 200 ms,
   removed after 600 ms total. No drift, no spin, no banner-slide
   (the banner above already drops the slide via the @media gate).
   ----------------------------------------------------------------------- */
.metod-reduced-check {
  position: fixed;
  z-index: 100;
  pointer-events: none;
  font-size: 36px;
  line-height: 1;
  color: var(--accent);
  text-shadow: 0 0 24px var(--accent-glow);
  transform: translate3d(-50%, -50%, 0);
  opacity: 0;
  transition: opacity 200ms ease-out;
}
.metod-reduced-check.is-visible { opacity: 1; }
