/* mitec — motion layer
   ──────────────────────────────────────────────────────────────────────────
   Every rule here is scoped to html.motion, which JS sets only when the
   visitor hasn't asked for reduced motion (motion/engine.js). Without it —
   reduced motion, no JS, forced colours — none of this applies and the page
   is the plain static document with everything visible.

   Only transform and opacity move. Reveals are CSS animations with
   fill-mode `backwards`, so once one ends the element is back on its own
   styles and its hover transitions are untouched.
   ────────────────────────────────────────────────────────────────────────── */

@keyframes reveal-rise {
  from { opacity: 0; transform: translateY(var(--reveal-rise)); }
}

html.motion [data-reveal]:not(.is-revealed),
html.motion [data-reveal-stagger]:not(.is-revealed) > * { opacity: 0; }

html.motion [data-reveal].is-revealed,
html.motion [data-reveal-stagger].is-revealed > * {
  animation: var(--reveal, reveal-rise) var(--dur-reveal) var(--ease-entrance) backwards;
  animation-delay: calc(var(--i, 0) * var(--stagger));
}

/* Focus never lands on something invisible: if keyboard focus reaches content
   that has not revealed yet (or is mid-reveal), it shows at once. */
html.motion [data-reveal]:focus-within,
html.motion [data-reveal-stagger] > :focus-within { opacity: 1; animation: none; }

/* Media tiles open from a clipped, slightly small frame instead of fading:
   they are visible (clipped) before they reveal, never blank. */
@keyframes reveal-media {
  from { clip-path: inset(10% round 20px); transform: scale(.96); }
  to { clip-path: inset(0 round 20px); transform: none; }
}
html.motion [data-reveal="media"] { --reveal: reveal-media; --dur-reveal: var(--dur-media); }
html.motion [data-reveal="media"]:not(.is-revealed) { opacity: 1; clip-path: inset(10% round 20px); transform: scale(.96); }

@keyframes reveal-pop {
  from { opacity: 0; transform: scale(var(--pop-from, .8)); }
}
@keyframes reveal-fade {
  from { opacity: 0; }
}

/* Services: each icon chip pops in 100ms after its card rises. */
html.motion .services-grid.is-revealed .service-card__badge {
  animation: reveal-pop var(--dur-reveal) var(--ease-entrance) backwards;
  animation-delay: calc(var(--i, 0) * var(--stagger) + 100ms);
}

/* About: the cards fade in, each photo pops (.9 → 1), then its text rises in. */
html.motion .about-grid { --reveal: reveal-fade; }
html.motion .about-card:nth-child(2) { --i: 1; }
html.motion .about-card__text > :nth-child(2) { --k: 1; }
html.motion .about-card__text > :nth-child(3) { --k: 2; }
html.motion .about-grid.is-revealed .about-card__photo {
  --pop-from: .9;
  animation: reveal-pop var(--dur-reveal) var(--ease-entrance) backwards;
  animation-delay: calc(var(--i, 0) * 120ms + 80ms);
}
html.motion .about-grid.is-revealed .about-card__text > * {
  --reveal-rise: 16px;
  animation: reveal-rise var(--dur-reveal) var(--ease-entrance) backwards;
  animation-delay: calc(var(--i, 0) * 120ms + 160ms + var(--k, 0) * 60ms);
}

/* CTA heading: word by word — never by letter, Persian letters join. */
html.motion .cta-band h2 { --stagger: 90ms; }

/* Scroll-linked layers (motion/effects.js) get their own compositor layer. */
html.motion :is(.work-row__shot, .about-title__line, .cta-band__echo, .process-rail__fill) { will-change: transform; }
html.motion .testimonial { will-change: transform, opacity; }
html.motion .process-rail__fill { transform: scale(0); }
/* Process steps start empty; effects.js scrubs the fill, its edge and the
   numeral from the rail's progress. */
html.motion .process-step__fill { transform: scale(0); will-change: transform; }
html.motion .process-step__line { opacity: 0; will-change: opacity; }
html.motion .process-step__n { opacity: .35; }
