/* Stage motion (0.9). Everything in this file is decorative and
   client-configured: the idle prompt and logo effects (idle.prompt_fx,
   idle.logo_fx), the text lines' entrance (per line, data-enter), the
   review screen settling in, and the guest filter chips. The stage is
   correct with all of it removed: prefers-reduced-motion (theme.css) or
   the Still stage switch (ui.motion false -> #stage[data-still]) do that.
   Nothing here reaches the saved photo. */

#stage[data-still] #idle-prompt, #stage[data-still] #idle-logo, #stage[data-still] .text-line, #stage[data-still] #layer-idle,
#stage[data-still] #review-img, #stage[data-still] #review-actions button, #stage[data-still] #review-strip,
#stage[data-still] #layer-filters button, #stage[data-still] #banner { animation: none !important; }

/* Idle: the layer fades up on every return, the prompt has its effect. */
#stage[data-state="idle"] #layer-idle { animation: fade-up .6s var(--ease, ease) both; }
@keyframes fade-up { from { opacity: 0; translate: 0 1.5vh; } to { opacity: 1; translate: 0 0; } }
#idle-prompt[data-fx="pulse"] { animation: idle-pulse 2.4s ease-in-out infinite; }
@keyframes idle-pulse { 0%, 100% { opacity: .85; } 50% { opacity: 1; } }
#idle-prompt[data-fx="float"] { animation: idle-float 3.2s ease-in-out infinite alternate; }
@keyframes idle-float { from { translate: 0 0; } to { translate: 0 -1.4vh; } }
#idle-prompt[data-fx="glow"] { animation: idle-glow 2.2s ease-in-out infinite alternate; }
@keyframes idle-glow {
  from { text-shadow: 0 2px 18px rgba(0, 0, 0, .6), 0 0 .15em var(--prompt-color, #fff); }
  to { text-shadow: 0 2px 18px rgba(0, 0, 0, .6), 0 0 .5em var(--prompt-color, #fff), 0 0 1.1em var(--prompt-color, #fff); }
}
/* Shimmer: a light band sweeps the letters. At rest (no animation) either
   end of the gradient is the plain prompt colour. */
#idle-prompt[data-fx="shimmer"] {
  background: linear-gradient(110deg, var(--prompt-color, #fff) 0 42%, #fff 50%, var(--prompt-color, #fff) 58% 100%);
  background-size: 250% 100%; background-position: 100% 0; -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; animation: idle-shimmer 3.6s ease-in-out infinite;
}
@keyframes idle-shimmer { 0%, 35% { background-position: 100% 0; } 65%, 100% { background-position: 0% 0; } }
#stage[data-contrast] #idle-prompt[data-fx="shimmer"] { -webkit-text-fill-color: currentColor; background: rgba(0, 0, 0, .85); }
#idle-logo[data-fx="float"] { animation: idle-float 3.6s ease-in-out infinite alternate; }
#idle-logo[data-fx="pulse"] { animation: logo-pulse 2.8s ease-in-out infinite; }
@keyframes logo-pulse { 0%, 100% { scale: 1; } 50% { scale: 1.05; } }

/* Mood loop (idle.ambient): a bundled clip screened over the idle stage,
   under the logo and prompt. Shown only while idle.js says it plays; a
   still stage or reduced motion shows no clip at all. */
#idle-clip {
  display: none; position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  mix-blend-mode: screen; opacity: var(--idle-clip-opacity, .6); pointer-events: none;
}
#stage[data-state="idle"] #idle-clip[data-on="1"][src] { display: block; animation: clip-in 1.2s ease both; }
@keyframes clip-in { from { opacity: 0; } to { opacity: var(--idle-clip-opacity, .6); } }
/* The layer's own fade would isolate it and the screen blend would see
   black, not the camera; with a loop playing the clip does the fading. */
#stage[data-state="idle"] #layer-idle:has(#idle-clip[data-on="1"][src]) { animation: none; }
#stage[data-still] #idle-clip { display: none !important; }
@media (prefers-reduced-motion: reduce) { #idle-clip { display: none !important; } }
#layer-idle > #idle-logo, #layer-idle > #idle-prompt { position: relative; }

/* Text lines: entrance per line, staggered by index (--i), replayed each
   time the stage is idle again. Individual translate / scale properties so
   the alignment transform on the line is untouched. */
#stage[data-state="idle"] .text-line[data-enter="fade"] { animation: text-fade .7s var(--ease, ease) both; animation-delay: calc(var(--i, 0) * 120ms); }
#stage[data-state="idle"] .text-line[data-enter="rise"] { animation: text-rise .7s var(--ease, ease) both; animation-delay: calc(var(--i, 0) * 120ms); }
#stage[data-state="idle"] .text-line[data-enter="pop"] { animation: text-pop .6s cubic-bezier(.34, 1.56, .64, 1) both; animation-delay: calc(var(--i, 0) * 120ms); }
#stage[data-state="idle"] .text-line[data-enter="slide"] { animation: text-slide .7s var(--ease, ease) both; animation-delay: calc(var(--i, 0) * 120ms); }
@keyframes text-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes text-rise { from { opacity: 0; translate: 0 2.5vh; } to { opacity: 1; translate: 0 0; } }
@keyframes text-pop { from { opacity: 0; scale: .5; } to { opacity: 1; scale: 1; } }
@keyframes text-slide { from { opacity: 0; translate: -5vw 0; } to { opacity: 1; translate: 0 0; } }

/* Guest filter chips fade in one after another and lift under the finger. */
#layer-filters button { animation: chip-in .35s ease-out both; transition: transform .15s var(--ease, ease); }
#layer-filters button:hover { transform: translateY(-.4vh); }
#layer-filters button:active { transform: scale(.96); }
#layer-filters button:nth-child(2) { animation-delay: 60ms; }
#layer-filters button:nth-child(3) { animation-delay: 120ms; }
#layer-filters button:nth-child(4) { animation-delay: 180ms; }
#layer-filters button:nth-child(5) { animation-delay: 240ms; }
#layer-filters button:nth-child(6) { animation-delay: 300ms; }
#layer-filters button:nth-child(7) { animation-delay: 360ms; }
@keyframes chip-in { from { opacity: 0; translate: 0 -1.5vh; } to { opacity: 1; translate: 0 0; } }

/* Review: the picture develops and settles onto a shadow; the buttons rise
   after it. The shadow is a filter on the review element, so the saved
   photo never has it. */
#stage[data-state="review"] #review-img { animation: review-in .6s ease-out both; }
@keyframes review-in {
  from { opacity: 0; scale: .96; translate: 0 1.5vh; filter: drop-shadow(0 0 0 rgba(0, 0, 0, 0)); }
  to { opacity: 1; scale: 1; translate: 0 0; filter: drop-shadow(0 1.6vh 3vh rgba(0, 0, 0, .45)); }
}
#stage[data-state="review"] #review-strip { animation: text-fade .5s .25s ease both; }
#stage[data-state="review"] #review-actions button { animation: button-rise .4s ease-out both; animation-delay: .35s; }
#stage[data-state="review"] #review-actions button:nth-child(2) { animation-delay: .45s; }
#stage[data-state="review"] #review-actions button:nth-child(3) { animation-delay: .55s; }
@keyframes button-rise { from { opacity: 0; translate: 0 3vh; } to { opacity: 1; translate: 0 0; } }
#review-actions button { transition: transform .15s var(--ease, ease), box-shadow .15s; }
#review-actions button:hover { transform: translateY(-.4vh); box-shadow: 0 1vh 3vh rgba(0, 0, 0, .35); }
#review-actions button:active { transform: scale(.97); }

#banner:not([hidden]) { animation: banner-in .35s var(--ease, ease) both; }
@keyframes banner-in { from { opacity: 0; translate: 0 -2vh; } to { opacity: 1; translate: 0 0; } }
