/* ================================================================
   ANIMATIONS - subtle, professional. All respect prefers-reduced-motion.
   ================================================================ */

.reveal {
  opacity: 0; transform: translateY(26px);
  transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
}
.reveal.in { opacity: 1; transform: none; }

/* directional variants: add alongside .reveal for a from-the-side or
   zoom entrance instead of the default fade-up, used sparingly for variety */
.reveal-left { transform: translateX(-32px); }
.reveal-left.in { transform: none; }
.reveal-right { transform: translateX(32px); }
.reveal-right.in { transform: none; }
.reveal-zoom { transform: scale(0.92); }
.reveal-zoom.in { transform: none; }

.stagger > * {
  opacity: 0; transform: translateY(20px);
  transition: opacity 0.65s var(--ease), transform 0.65s var(--ease);
}
.stagger.in > *:nth-child(1) { transition-delay: 0.02s; }
.stagger.in > *:nth-child(2) { transition-delay: 0.08s; }
.stagger.in > *:nth-child(3) { transition-delay: 0.14s; }
.stagger.in > *:nth-child(4) { transition-delay: 0.20s; }
.stagger.in > *:nth-child(5) { transition-delay: 0.26s; }
.stagger.in > *:nth-child(6) { transition-delay: 0.32s; }
.stagger.in > *:nth-child(7) { transition-delay: 0.38s; }
.stagger.in > *:nth-child(8) { transition-delay: 0.44s; }
.stagger.in > * { opacity: 1; transform: none; }
.stagger:not(.in) > * { opacity: 0; transform: translateY(20px); }

/* left/right stagger variants: for two-column layouts where each side
   should visibly arrive from its own edge rather than just rising */
.stagger-side > *:nth-child(odd)  { opacity: 0; transform: translateX(-28px); transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); }
.stagger-side > *:nth-child(even) { opacity: 0; transform: translateX(28px);  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); }
.stagger-side.in > * { opacity: 1; transform: none; }

@keyframes fadeIn {
  from { opacity: 0; } to { opacity: 1; }
}
@keyframes gentlePulse {
  0%, 100% { opacity: 1; } 50% { opacity: 0.5; }
}
.pulse-dot { animation: gentlePulse 2.4s ease-in-out infinite; }

@keyframes marquee {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
.marquee-track { animation: marquee 32s linear infinite; }
.marquee-wrap {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.hover-lift { transition: transform 0.35s var(--ease), border-color 0.35s var(--ease), box-shadow 0.35s var(--ease); }
.hover-lift:hover { transform: translateY(-6px); box-shadow: 0 18px 40px -20px rgba(0,0,0,0.55); }

.tilt-card { position: relative; overflow: hidden; transition: transform 0.35s var(--ease), border-color 0.35s var(--ease); transform-style: preserve-3d; will-change: transform; }

/* glass-glare sweep that tracks the cursor, layered inside tilt-card via JS */
.tilt-glare {
  position: absolute; inset: 0; pointer-events: none; opacity: 0; z-index: 2;
  background: radial-gradient(circle at var(--gx, 50%) var(--gy, 50%), rgba(255,255,255,0.10), transparent 55%);
  transition: opacity 0.3s var(--ease);
}
.tilt-card:hover .tilt-glare { opacity: 1; }

.link-arrow { display: inline-flex; align-items: center; gap: 6px; padding: 5px 0; }
.link-arrow svg { transition: transform 0.3s var(--ease); }
.link-arrow:hover svg { transform: translate(3px, -3px); }

/* progress bar fill (skills page) */
.bar-fill { width: 0; transition: width 1.1s var(--ease-in-out); }
.bar-fill.animated { width: var(--target-w, 80%); }

/* page load fade */
.page-enter { animation: fadeIn 0.5s var(--ease) both; }

/* guaranteed hero entrance: plays on load, not scroll-dependent */
@keyframes heroUp {
  from { opacity: 0; transform: translateY(22px); }
  to { opacity: 1; transform: none; }
}
.hero-in > * {
  opacity: 0;
  animation: heroUp 0.85s var(--ease) forwards;
}
.hero-in > *:nth-child(1) { animation-delay: 0.05s; }
.hero-in > *:nth-child(2) { animation-delay: 0.15s; }
.hero-in > *:nth-child(3) { animation-delay: 0.25s; }
.hero-in > *:nth-child(4) { animation-delay: 0.35s; }
.hero-in > *:nth-child(5) { animation-delay: 0.45s; }

/* nav link underline sweep */
.nav-links a { position: relative; }
.nav-links a::after {
  content: ""; position: absolute; left: 16px; right: 16px; bottom: 4px; height: 1px;
  background: var(--accent); transform: scaleX(0); transform-origin: left;
  transition: transform 0.3s var(--ease);
}
.nav-links a:hover::after { transform: scaleX(1); }
.nav-links a.active::after { display: none; }

/* gentle float for the hero mark */
@keyframes floatY {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-10px); }
}
.float-mark { animation: floatY 5s ease-in-out infinite; }

/* one-time premium text-shine sweep, used sparingly (hero H1 only) so it
   reads as a special reveal moment rather than a repeated gimmick.
   Combined into a single animation (see .hero-in > .text-shine below) so
   it doesn't fight the hero-in fade-up animation for the same element:
   two separate rules both setting the `animation` shorthand on the same
   element only ever let ONE of them win, which was silently cancelling
   the fade-in and leaving the heading stuck at opacity:0. */
.text-shine {
  background: linear-gradient(100deg, var(--text) 40%, #b9c6ff 50%, var(--text) 60%);
  background-size: 250% 100%;
  background-position: 100% 0;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  opacity: 0;
}
.hero-in > .text-shine {
  animation: heroTextShineIn 1.6s var(--ease) 0.15s both;
}
@keyframes heroTextShineIn {
  0%   { opacity: 0; transform: translateY(22px); background-position: 160% 0; }
  40%  { opacity: 1; transform: none; }
  100% { opacity: 1; transform: none; background-position: -60% 0; }
}
@keyframes spinIn {
  from { opacity: 0; transform: rotate(-25deg) scale(0.7); }
  to { opacity: 1; transform: none; }
}
.brand img { animation: spinIn 0.7s var(--ease) both; }

/* pause the marquee while the user is reading it */
.marquee-wrap:hover .marquee-track { animation-play-state: paused; }

/* button sheen sweep on hover */
.btn-primary { position: relative; overflow: hidden; }
.btn-primary::after {
  content: ""; position: absolute; top: 0; left: -60%; width: 40%; height: 100%;
  background: linear-gradient(120deg, transparent, rgba(255,255,255,0.35), transparent);
  transform: skewX(-20deg);
  transition: left 0.55s var(--ease);
}
.btn-primary:hover::after { left: 130%; }

/* creative scroll indicator: a mouse-shaped outline with a dot that slides and fades */
.scroll-cue-link { color: var(--text-faint); transition: color 0.3s var(--ease); cursor: pointer; }
.scroll-cue-link:hover { color: var(--accent); }
.scroll-cue-mouse {
  position: relative; display:block; width: 24px; height: 38px;
  border: 1.5px solid currentColor; border-radius: 14px;
}
.scroll-cue-dot {
  position: absolute; top: 7px; left: 50%; width: 4px; height: 4px;
  margin-left: -2px; border-radius: 50%; background: currentColor;
  animation: scrollDotSlide 1.8s ease-in-out infinite;
}
@keyframes scrollDotSlide {
  0%   { transform: translateY(0); opacity: 1; }
  70%  { transform: translateY(14px); opacity: 0; }
  71%  { transform: translateY(0); opacity: 0; }
  100% { transform: translateY(0); opacity: 1; }
}

/* cursor-following spotlight glow in the hero, set via --mx/--my custom properties in JS */
.hero-glow {
  position: absolute; inset: 0; pointer-events: none; z-index: 0;
  background: radial-gradient(480px circle at var(--mx, 50%) var(--my, 10%), var(--accent-soft), transparent 65%);
  opacity: 0; transition: opacity 0.4s var(--ease);
}
#hero:hover .hero-glow { opacity: 1; }
@media (hover: none) { .hero-glow { display: none; } }
#hero .wrap { position: relative; z-index: 1; }

/* magnetic pull on primary buttons */
.btn-magnetic { transition: transform 0.25s var(--ease-in-out); }

/* slow rotating conic ring behind the hero visual */
@keyframes ringSpin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
.spin-ring {
  position: absolute; inset: -1px; border-radius: inherit;
  background: conic-gradient(from 0deg, transparent 0%, var(--accent-line) 12%, transparent 24%, transparent 100%);
  animation: ringSpin 9s linear infinite;
  opacity: 0.6;
  pointer-events: none;
}

/* skills page: chip pop-in cascade once the parent card has revealed */
.chip-row .tag {
  opacity: 0; transform: translateY(8px) scale(0.94);
  transition: opacity 0.45s var(--ease), transform 0.45s var(--ease), border-color 0.25s var(--ease), color 0.25s var(--ease);
}
.stagger.in .chip-row .tag, .stagger-side.in .chip-row .tag { opacity: 1; transform: none; }
.chip-row .tag:hover { border-color: var(--accent-line); color: var(--text); }
.chip-row .tag:nth-child(1)  { transition-delay: 0.04s; }
.chip-row .tag:nth-child(2)  { transition-delay: 0.08s; }
.chip-row .tag:nth-child(3)  { transition-delay: 0.12s; }
.chip-row .tag:nth-child(4)  { transition-delay: 0.16s; }
.chip-row .tag:nth-child(5)  { transition-delay: 0.20s; }
.chip-row .tag:nth-child(6)  { transition-delay: 0.24s; }
.chip-row .tag:nth-child(7)  { transition-delay: 0.28s; }
.chip-row .tag:nth-child(8)  { transition-delay: 0.32s; }
.chip-row .tag:nth-child(9)  { transition-delay: 0.36s; }
.chip-row .tag:nth-child(10) { transition-delay: 0.40s; }
.chip-row .tag:nth-child(11) { transition-delay: 0.44s; }
.chip-row .tag:nth-child(12) { transition-delay: 0.48s; }

/* skills page: category icon settles in with a light rotation, then reacts on hover */
.skill-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: var(--r-md);
  background: var(--accent-soft); color: var(--accent);
  transform: rotate(-8deg) scale(0.8); opacity: 0;
  transition: transform 0.5s var(--ease), opacity 0.5s var(--ease), background 0.3s var(--ease);
}
.stagger.in .skill-icon, .stagger-side.in .skill-icon { transform: none; opacity: 1; }
.card:hover .skill-icon { transform: rotate(6deg); background: var(--accent); color: var(--on-accent); }

/* number badges (about page strengths) grow slightly on card hover */
.num-badge { display: inline-block; transition: transform 0.3s var(--ease), color 0.3s var(--ease); }
.hover-lift:hover .num-badge { transform: scale(1.15); }

@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;
  }
  .reveal, .stagger > *, .hero-in > *, .chip-row .tag, .skill-icon { opacity: 1 !important; transform: none !important; }
  .float-mark, .spin-ring, .scroll-cue-dot { animation: none !important; }
  .text-shine {
    animation: none !important;
    background: none !important;
    -webkit-background-clip: initial !important;
    background-clip: initial !important;
    color: var(--text) !important;
  }
  .reveal-left, .reveal-right, .reveal-zoom,
  .stagger-side > * { transform: none !important; }
  .btn-primary::after { display: none; }
  .hero-glow { display: none; }
}

