/* ============================================================
   Base Industries — animations.css
   Layer 3: reusable motion primitives.
   Driven by data attributes:
     [data-reveal="fade-up" | "image" | "heading"]
     [data-parallax]
     [data-stagger]
     [data-counter]
   Reduced-motion disables all of it and shows content instantly.
   ============================================================ */

/* ---------- Fade-up reveal ---------- */
[data-reveal="fade-up"] {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
}
[data-reveal="fade-up"].is-visible { opacity: 1; transform: none; }

/* ---------- Image reveal (fade + scale).
   NOTE: no full-collapse clip-path here — a zero-area clip makes
   IntersectionObserver report ratio 0 and never fire. ---------- */
[data-reveal="image"] {
  opacity: 0;
  transform: translateY(18px) scale(0.97);
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-cine) var(--ease-out);
}
[data-reveal="image"].is-visible { opacity: 1; transform: translateY(0) scale(1); }

/* ---------- Heading reveal (line mask) ---------- */
[data-reveal="heading"] {
  display: block;
  overflow: hidden;
}
[data-reveal="heading"] > * {
  display: block;
  transform: translateY(110%);
  transition: transform var(--dur-cine) var(--ease-out);
}
[data-reveal="heading"].is-visible > * { transform: translateY(0); }

/* Wrap the heading text in a span so the mask can slide it. */
[data-reveal="heading"] { position: relative; }

/* ---------- Parallax (JS sets --parallax-offset) ---------- */
[data-parallax] { transform: translateY(calc(var(--parallax-offset, 0px) * -0.06)); will-change: transform; }

/* ---------- Stagger children ---------- */
[data-stagger] > * {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
}
[data-stagger].is-visible > * { opacity: 1; transform: none; }
[data-stagger].is-visible > *:nth-child(1) { transition-delay: 0ms; }
[data-stagger].is-visible > *:nth-child(2) { transition-delay: 90ms; }
[data-stagger].is-visible > *:nth-child(3) { transition-delay: 180ms; }
[data-stagger].is-visible > *:nth-child(4) { transition-delay: 270ms; }
[data-stagger].is-visible > *:nth-child(5) { transition-delay: 360ms; }
[data-stagger].is-visible > *:nth-child(6) { transition-delay: 450ms; }
[data-stagger].is-visible > *:nth-child(n+7) { transition-delay: 540ms; }

/* ---------- Counter (numbers) ---------- */
[data-counter] { font-variant-numeric: tabular-nums; }

/* ---------- Hero entrance (cinematic, on load) ---------- */
.hero [data-hero-reveal] {
  opacity: 0;
  transform: translateY(30px);
  transition: opacity var(--dur-cine) var(--ease-out), transform var(--dur-cine) var(--ease-out);
}
.hero.is-loaded [data-hero-reveal] { opacity: 1; transform: none; }
.hero.is-loaded [data-hero-reveal="1"] { transition-delay: 120ms; }
.hero.is-loaded [data-hero-reveal="2"] { transition-delay: 260ms; }
.hero.is-loaded [data-hero-reveal="3"] { transition-delay: 400ms; }
.hero.is-loaded [data-hero-reveal="4"] { transition-delay: 540ms; }

/* Slow Ken-Burns breathing on hero image */
.hero__media img { animation: kenburns 24s ease-in-out infinite alternate; }
@keyframes kenburns {
  from { transform: scale(1.02) translateY(0); }
  to   { transform: scale(1.1) translateY(-1.5%); }
}

/* ---------- Reduced motion: show everything instantly ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
  [data-reveal], [data-stagger] > *, .hero [data-hero-reveal] { opacity: 1 !important; transform: none !important; clip-path: none !important; }
  [data-reveal="heading"] > * { transform: none !important; }
  [data-parallax] { transform: none !important; }
  .hero__media img { animation: none !important; }
  .hero__scroll-line::after { animation: none !important; }
}

/* ---------- Page transition (soft crossfade) ----------
   Understated dissolve: the outgoing page fades out, the incoming page fades
   in. No sliding panel. The incoming page starts hidden via the pre-paint
   guard (html.bi-enter) so the swap never flashes. */
body { transition: opacity 220ms var(--ease-io); }
html.bi-enter body { opacity: 0; }
body.bi-leave { opacity: 0; }

/* ---------- Custom cursor dot (fine pointers only) ---------- */
.cursor-dot {
  position: fixed; top: 0; left: 0; z-index: 9998; width: 8px; height: 8px;
  margin: -4px 0 0 -4px; border-radius: 50%; background: var(--color-accent);
  pointer-events: none; mix-blend-mode: difference; opacity: 0;
  transition: opacity 200ms var(--ease-out), width 260ms var(--ease-out), height 260ms var(--ease-out), margin 260ms var(--ease-out), background 260ms var(--ease-out);
  display: flex; align-items: center; justify-content: center;
}
.cursor-dot.is-on { opacity: 1; }
/* Contextual state — grows into a labelled chip (e.g. VIEW on projects) */
.cursor-dot__label { font-family: var(--font-display); font-size: 0.62rem; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: #fff; opacity: 0; transition: opacity 180ms var(--ease-out); white-space: nowrap; }
.cursor-dot.is-label { width: 74px; height: 74px; margin: -37px 0 0 -37px; background: var(--color-accent); mix-blend-mode: normal; }
.cursor-dot.is-label .cursor-dot__label { opacity: 1; }
@media (pointer: coarse) { .cursor-dot { display: none; } }