/* FitGrocery Animation System - Health & Nutrition Focused */

:root {
  /* Timing System - Calm, trustworthy animations for health apps */
  --animation-instant: 100ms;
  --animation-fast: 200ms;
  --animation-normal: 400ms;
  --animation-slow: 600ms;
  --animation-extra-slow: 1000ms;

  /* Easing - Natural, organic curves for health/wellness */
  --ease-organic: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --ease-bounce-soft: cubic-bezier(0.68, -0.55, 0.265, 1.55);
  --ease-nutrition: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-smooth: cubic-bezier(0.37, 0, 0.63, 1);

  /* Shadow System */
  --shadow-soft: 0 2px 8px rgba(0, 0, 0, 0.08);
  --shadow-medium: 0 4px 12px rgba(0, 0, 0, 0.1);
  --shadow-strong: 0 6px 20px rgba(0, 0, 0, 0.15);
}

/* Base Animation Classes - Performance Optimized */
.fade-animation {
  opacity: 0;
  transform: translateZ(0); /* Force GPU layer */
  transition: opacity var(--animation-normal) var(--ease-nutrition);
  will-change: opacity;
  contain: layout;
}

.fade-animation.show {
  opacity: 1;
  will-change: auto; /* Remove after animation */
}

.fade-animation.delay-200 {
  transition-delay: 200ms;
}
.fade-animation.delay-400 {
  transition-delay: 400ms;
}
.fade-animation.delay-600 {
  transition-delay: 600ms;
}
.fade-animation.delay-800 {
  transition-delay: 800ms;
}

/* Slide Animations - GPU Optimized */
.slide-up {
  opacity: 0;
  transform: translate3d(0, 50px, 0);
  transition:
    opacity var(--animation-slow) var(--ease-nutrition),
    transform var(--animation-slow) var(--ease-nutrition);
  will-change: transform, opacity;
  contain: layout;
}

.slide-up.show {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  will-change: auto;
}

.slide-left {
  opacity: 0;
  transform: translate3d(50px, 0, 0);
  transition:
    opacity var(--animation-slow) var(--ease-nutrition),
    transform var(--animation-slow) var(--ease-nutrition);
  will-change: transform, opacity;
  contain: layout;
}

.slide-left.show {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  will-change: auto;
}

/* Scale Animations - GPU Optimized */
.scale-in {
  opacity: 0;
  transform: translate3d(0, 0, 0) scale(0.7);
  transition:
    opacity var(--animation-slow) var(--ease-bounce-soft),
    transform var(--animation-slow) var(--ease-bounce-soft);
  will-change: transform, opacity;
  contain: layout;
}

.scale-in.show {
  opacity: 1;
  transform: translate3d(0, 0, 0) scale(1);
  will-change: auto;
}

/* Macro-Specific Animations */
.macro-reveal {
  opacity: 0;
  transform: scale(0.8) translateY(20px);
  animation: macroReveal var(--animation-slow) var(--ease-organic) forwards;
}

.macro-reveal.protein {
  animation-delay: 0ms;
}
.macro-reveal.carbs {
  animation-delay: 200ms;
}
.macro-reveal.fats {
  animation-delay: 400ms;
}

@keyframes macroReveal {
  to {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

/* Macro Selection Animation */
.macro-selected {
  animation: macroSelect var(--animation-slow) var(--ease-bounce-soft);
}

@keyframes macroSelect {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.1);
  }
  100% {
    transform: scale(1);
  }
}

/* Food Item Animations */
.food-item-enter {
  opacity: 0;
  transform: translateX(-30px);
  animation: slideInLeft var(--animation-normal) var(--ease-nutrition) forwards;
}

@keyframes slideInLeft {
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

/* Loading States - Performance Optimized */
.calculation-pulse {
  position: relative;
  transform: translateZ(0);
  contain: layout;
}

.calculation-pulse::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: inherit;
  opacity: 0.3;
  transform: scale(1);
  animation: nutritionPulse 2s var(--ease-organic) infinite;
  pointer-events: none;
}

@keyframes nutritionPulse {
  0%,
  100% {
    transform: scale(1);
    opacity: 0.3;
  }
  50% {
    transform: scale(1.05);
    opacity: 0.1;
  }
}

/* Progress Indicators */
.progress-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #e0e0e0;
  transition: all var(--animation-fast) var(--ease-nutrition);
}

.progress-dot.completed {
  background: var(--fs-primary);
  transform: scale(1.2);
  animation: dotComplete var(--animation-normal) var(--ease-bounce-soft);
}

@keyframes dotComplete {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.4);
  }
  100% {
    transform: scale(1.2);
  }
}

/* Success Celebrations - Performance Optimized */
.success-celebration {
  position: relative;
  transform: translateZ(0);
  contain: layout;
}

.success-celebration::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(
    circle at center,
    rgba(76, 175, 80, 0.3) 0%,
    rgba(76, 175, 80, 0.1) 50%,
    transparent 100%
  );
  opacity: 0;
  transform: scale(1.1);
  animation: successPulse 1.5s var(--ease-organic);
  pointer-events: none;
}

@keyframes successPulse {
  0% {
    transform: scale(1.1);
    opacity: 0;
  }
  25% {
    transform: scale(1);
    opacity: 1;
  }
  50% {
    transform: scale(1.02);
    opacity: 0.8;
  }
  100% {
    transform: scale(1);
    opacity: 0;
  }
}

/* MudBlazor Component Enhancements */
.mud-button.nutrition-primary {
  transition: all var(--animation-fast) var(--ease-nutrition);
  position: relative;
  overflow: hidden;
}

.mud-button.nutrition-primary::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  background: rgba(255, 255, 255, 0.2);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  transition:
    width var(--animation-normal),
    height var(--animation-normal);
}

.mud-button.nutrition-primary:hover::before {
  width: 120%;
  height: 120%;
}

/* Dropdown Animations */
.dropdown-slide {
  animation: dropdownSlide var(--animation-fast) var(--ease-nutrition);
  transform-origin: top center;
}

@keyframes dropdownSlide {
  from {
    opacity: 0;
    transform: scaleY(0.8) translateY(-10px);
  }
  to {
    opacity: 1;
    transform: scaleY(1) translateY(0);
  }
}

/* Card Reveal Animations */
.card-reveal {
  opacity: 0;
  transform: translateY(30px) scale(0.98);
  transition: all var(--animation-slow) var(--ease-organic);
}

.card-reveal.show {
  opacity: 1;
  transform: translateY(0) scale(1);
}

/* Stagger Animation Classes */
.stagger-item {
  opacity: 0;
  transform: translateY(20px);
  transition: all var(--animation-normal) var(--ease-nutrition);
}

.stagger-item.show {
  opacity: 1;
  transform: translateY(0);
}

.stagger-item:nth-child(1) {
  transition-delay: 0ms;
}
.stagger-item:nth-child(2) {
  transition-delay: 100ms;
}
.stagger-item:nth-child(3) {
  transition-delay: 200ms;
}
.stagger-item:nth-child(4) {
  transition-delay: 300ms;
}
.stagger-item:nth-child(5) {
  transition-delay: 400ms;
}

/* Nutrition Value Animations */
.nutrition-value-update {
  animation: valueUpdate var(--animation-fast) var(--ease-bounce-soft);
}

@keyframes valueUpdate {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.15);
    color: var(--fs-primary);
  }
  100% {
    transform: scale(1);
  }
}

/* Accessibility Support */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .fade-animation,
  .slide-up,
  .slide-left,
  .scale-in {
    opacity: 1 !important;
    transform: none !important;
  }
  /* Loading indicators are EXEMPT from the catch-all above. Reduced motion means "remove gratuitous
     motion", not "remove the only evidence the app is working" — and for a spinner those are the same
     thing. MQ Level 5 defines `reduce` as removing NON-ESSENTIAL movement. WCAG 2.2 SC 2.2.2 Note 4 is
     adjacent support rather than direct authority (it governs pause mechanisms, not this media feature),
     but it describes #259 exactly: an animation in a preload phase "can be considered essential if
     interaction cannot occur during that phase for all users AND if not indicating progress could
     confuse users or cause them to think that content was frozen or broken".

     The catch-all was doing exactly that. `animation-iteration-count: 1` overrides `infinite`, so every
     Bootstrap spinner completed a single rotation in 0.01ms and stopped. Bootstrap ships its own
     reduced-motion value (1.5s, via --bs-spinner-animation-speed) but consumes it through a
     non-!important shorthand, so ours always won. 1.5s here is Bootstrap's number, not one invented.

     .spinner-grow is included because freezing it renders LITERALLY NOTHING — Bootstrap rests it at
     opacity 0 and the animation is what reveals it.

     .loading-spinner is matched ONLY when empty, and that is not fussiness. The class is used two ways:
     as the ring itself (TomSelectDropdown.razor:9, an empty div) and as a WRAPPER around the loading
     text (LoadingIndicators.razor:4). Exempting it unconditionally spins a block of prose forever for
     the one cohort that asked for less motion; excluding it entirely leaves TomSelect's bare ring frozen
     beside an sr-only label a sighted user cannot read. :empty separates the two by what they contain.

     ⚠️ `html` is load-bearing, not decoration. Blazor rewrites a scoped `*` to `*[b-xxxxxxx]`, which is
     specificity (0,1,0) — an exact TIE with a bare `.spinner-border`, and six .razor.css files ship
     exactly that freeze (SignUp, Login, FoodSelection, PasswordGenerationModal, MobileBottomSheetList,
     ReconnectionModal). At a tie the cascade falls through to source order, and the scoped bundle only
     happens to link before this file (App.razor:111 vs :133). `html .spinner-border` is (0,1,1) and wins
     outright, so moving a <link> cannot silently reintroduce #259. An earlier version of this comment
     claimed specificity settled it "from any file at any position"; that was true only of the GLOBAL
     freezes, and false for the scoped ones. Verified in Chromium with the scoped freeze loading last.

     Guarded by ReducedMotionSpinnerGuardTests. */
  html .spinner-border,
  html .spinner-border-sm,
  html .spinner-grow,
  html .spinner-grow-sm,
  html .spinner,
  html .loading-spinner:empty {
    animation-duration: 1.5s !important;
    animation-iteration-count: infinite !important;
  }

  /* The dashboard's indeterminate bar. This entry does NOT inherit the spinner argument above — that
     one turns on "freezing it removes the only evidence the app is working", and this bar sits beside
     a title and a status line, so that clause does not apply. The case for it is narrower and stands
     on its own: unlike the spinners, this element does NOT keep its motion under reduced motion. The
     horizontal sweep is dropped entirely (that IS the gratuitous, vestibular part); what survives is
     an in-place opacity fade. Without this exemption the catch-all clamps that fade to a single 0.01ms
     cycle and the bar rests STATIC at 45% width — which reads as a determinate bar stuck partway, the
     "stuck at N%" failure indeterminate mode was introduced to prevent. So the choice is not
     motion-vs-none; it is "a bar that breathes" vs "a bar that lies about its position".

     2s, not the spinners' 1.5s, because a slow fade reads as breathing rather than blinking. This
     declaration OWNS the duration — the component's own 2s (ProgressIndicator.razor) is overridden by
     this !important and is inert; retune here.

     `html` here is defensive rather than load-bearing: unlike the scoped `*[b-xxxxx]` freezes that
     forced the prefix above, nothing ships a (0,1,0) rule that can match this class, so the bare
     selector would already beat the three universal catch-alls (this file, mobile-utilities.css,
     auth-shared.css). Kept for consistency with the block above and to survive a future scoped freeze.

     Guarded by ReducedMotionSpinnerGuardTests — .pp-indeterminate-bar is in its LoadingClasses, so
     deleting this rule fails the suite rather than silently refreezing the bar. */
  html .pp-indeterminate-bar {
    animation-duration: 2s !important;
    animation-iteration-count: infinite !important;
  }
}

/* High Contrast Mode Support */
@media (prefers-contrast: high) {
  .macro-reveal,
  .card-reveal,
  .stagger-item {
    border: 2px solid currentColor;
    outline-offset: 2px;
  }

  .progress-dot {
    border: 2px solid currentColor;
  }

  .progress-dot.completed {
    background: currentColor;
  }
}

/* Smooth Scrolling for Nutrition Apps */
.smooth-scroll {
  scroll-behavior: smooth;
  scroll-padding-top: 80px;
}

/* Error State Animations */
.error-shake {
  animation: errorShake var(--animation-fast) var(--ease-bounce-soft);
}

@keyframes errorShake {
  0%,
  100% {
    transform: translateX(0);
  }
  25% {
    transform: translateX(-10px);
  }
  75% {
    transform: translateX(10px);
  }
}

/* Nutrition Result Celebration */
.nutrition-result-celebrate {
  animation: resultCelebrate 2s var(--ease-organic);
}

@keyframes resultCelebrate {
  0% {
    transform: scale(1) rotate(0deg);
    opacity: 1;
  }
  25% {
    transform: scale(1.1) rotate(1deg);
  }
  50% {
    transform: scale(1.05) rotate(-1deg);
  }
  75% {
    transform: scale(1.08) rotate(0.5deg);
  }
  100% {
    transform: scale(1) rotate(0deg);
    opacity: 1;
  }
}
