/* ============================================================
   Custom polish on top of Tailwind utilities.
   Tailwind via CDN handles the bulk of styling — this file
   carries the bits that are tedious or impossible inline.
   ============================================================ */

/* Hide pre-mount Vue templates so we never get a flash of
   unprocessed {{ mustaches }} during initial paint. */
[v-cloak] { display: none !important; }

html { scroll-padding-top: 5rem; }
body { -webkit-font-smoothing: antialiased; }

/* --- Reusable section heading + kicker. We use these in
   templates as @apply replacements (Tailwind CDN doesn't
   compile @apply, so we expand them by hand). --- */
.section-heading {
  font-size: 1.875rem;       /* text-3xl  */
  line-height: 2.25rem;
  font-weight: 800;          /* font-extrabold */
  letter-spacing: -0.025em;  /* tracking-tight */
  color: #ffffff;
}
@media (min-width: 640px) {
  .section-heading { font-size: 2.25rem; line-height: 2.5rem; } /* sm:text-4xl */
}
.section-heading::after {
  content: '';
  display: block;
  margin-top: 0.75rem;
  height: 3px;
  width: 3.5rem;
  border-radius: 9999px;
  background: linear-gradient(90deg, #818cf8 0%, #c084fc 50%, #22d3ee 100%);
}
.section-kicker {
  margin-top: 1rem;
  color: #94a3b8;            /* slate-400 */
  font-size: 0.95rem;
  line-height: 1.7;
}

/* --- Soft card surface used everywhere --- */
.card-soft {
  background-color: rgba(17, 24, 39, 0.6);     /* ink-800/60 */
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 1rem;
  backdrop-filter: blur(4px);
  transition: border-color 0.25s ease, transform 0.25s ease, background-color 0.25s ease;
}

/* --- Custom scrollbar (subtle, on-brand) --- */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: #070a13; }
::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, #4338ca, #6366f1);
  border-radius: 9999px;
  border: 2px solid #070a13;
}
::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(180deg, #6366f1, #a855f7);
}

/* --- Image fade-in once loaded (avoids harsh swaps) --- */
img { opacity: 1; transition: opacity 0.3s ease; }
img[loading="lazy"] { opacity: 0; }
img[loading="lazy"].is-loaded,
img[loading="lazy"][src] { opacity: 1; }

/* --- Modal scroll lock (toggled from JS) --- */
body.modal-open { overflow: hidden; }

/* --- Reveal-on-scroll (driven by IntersectionObserver in app.js) --- */
.reveal { opacity: 0; transform: translateY(24px); transition: opacity 0.6s ease, transform 0.6s ease; }
.reveal.is-visible { opacity: 1; transform: translateY(0); }

/* --- Project description honors line breaks from the JSON --- */
.prose-block p { white-space: pre-line; }

/* --- Print: hide nav and decorative blobs (so the resume can be saved) --- */
@media print {
  header, footer, .pointer-events-none { display: none !important; }
  body { background: #fff; color: #000; }
  .card-soft { border-color: #ddd; background: #fff; }
}

/* ============================================================
   Animated Intro Overlay
   ============================================================ */

/* Progress segment fill — duration is supplied per-scene via inline
   style (animationDuration), so the same animation drives every scene. */
@keyframes intro-progress-fill {
  from { width: 0%; }
  to   { width: 100%; }
}
.intro-progress {
  animation-name: intro-progress-fill;
  animation-timing-function: linear;
  animation-fill-mode: forwards;
  width: 0%;
}

/* Tag pop-in — stagger handled via inline animationDelay in template. */
@keyframes intro-tag-in {
  0%   { opacity: 0; transform: translateY(8px) scale(0.95); }
  100% { opacity: 1; transform: translateY(0)   scale(1);    }
}
.intro-tag {
  opacity: 0;
  animation: intro-tag-in 0.5s ease-out forwards;
}

/* Respect users who'd rather not see motion. */
@media (prefers-reduced-motion: reduce) {
  .intro-progress, .intro-tag,
  .animate-float, .animate-spin-slow, .animate-fade-up, .animate-fade-in {
    animation: none !important;
  }
}
