/* ============================================================
   animations.css — keyframes & transition utility classes
   ============================================================ */

@keyframes pageEnter {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes slideInLeft {
  from { opacity: 0; transform: translateX(-16px); }
  to   { opacity: 1; transform: translateX(0); }
}

@keyframes pulseGlow {
  0%, 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0.4); }
  50%      { box-shadow: 0 0 0 6px rgba(239,68,68,0); }
}

/* Page entrance — applied on .content-area.
   NOTE: no `both`/`forwards` fill-mode on purpose. The pageEnter keyframe ends at
   `transform: translateY(0)`, and a retained (non-none) transform on .content-area
   makes it the containing block + stacking context for any position:fixed descendant —
   which traps Bootstrap modals BEHIND their backdrop (screen dims, nothing clickable).
   Letting the transform revert to `none` at rest keeps modals on top. */
.content-area {
  animation: pageEnter 0.42s var(--ease-out, ease);
}
/* Hard guard: while any modal is open, force-clear transforms on the modal's
   ancestors so it can never be trapped behind the backdrop (covers the brief
   entrance window and any future transform added to these wrappers). */
body.modal-open .content-area,
body.modal-open .main-wrapper,
body.modal-open .app-shell { transform: none !important; }
.animate-fade-in { animation: fadeIn 0.35s var(--ease-out, ease) forwards; }
.animate-slide-up { animation: fadeInUp 0.4s var(--ease-out, ease) forwards; }

/* Staggered entrance for stat cards */
.stat-card { animation: fadeInUp 0.42s var(--ease-out, ease) both; }
.stat-grid .stat-card:nth-child(1) { animation-delay: 0.04s; }
.stat-grid .stat-card:nth-child(2) { animation-delay: 0.09s; }
.stat-grid .stat-card:nth-child(3) { animation-delay: 0.14s; }
.stat-grid .stat-card:nth-child(4) { animation-delay: 0.19s; }

/* Staggered entrance for project cards */
.projects-grid .project-card { animation: fadeInUp 0.42s var(--ease-out, ease) both; }
.projects-grid .project-card:nth-child(1) { animation-delay: 0.03s; }
.projects-grid .project-card:nth-child(2) { animation-delay: 0.07s; }
.projects-grid .project-card:nth-child(3) { animation-delay: 0.11s; }
.projects-grid .project-card:nth-child(4) { animation-delay: 0.15s; }
.projects-grid .project-card:nth-child(5) { animation-delay: 0.19s; }
.projects-grid .project-card:nth-child(6) { animation-delay: 0.23s; }
.projects-grid .project-card:nth-child(7) { animation-delay: 0.27s; }
.projects-grid .project-card:nth-child(8) { animation-delay: 0.31s; }

/* Milestone timeline items cascade in */
.milestone-timeline .milestone-item { animation: fadeInUp 0.4s var(--ease-out, ease) both; }
.milestone-timeline .milestone-item:nth-child(1) { animation-delay: 0.04s; }
.milestone-timeline .milestone-item:nth-child(2) { animation-delay: 0.09s; }
.milestone-timeline .milestone-item:nth-child(3) { animation-delay: 0.14s; }
.milestone-timeline .milestone-item:nth-child(4) { animation-delay: 0.19s; }
.milestone-timeline .milestone-item:nth-child(5) { animation-delay: 0.24s; }

/* Overdue alert pulse */
.pulse-alert { animation: pulseGlow 2s ease-in-out infinite; }

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}
