.mo_reveal-on-scroll {
  opacity: 0;
  transform: translateY(16px);
  will-change: opacity, transform;
}

.mo_slide-up {
  opacity: 0;
  transform: translateY(100px);
  will-change: transform, opacity;
}

/* --- Reveal presets (start state) --- */
.mo_reveal-up   { opacity:0; transform: translateY(100px); }
.mo_reveal-left { opacity:0; transform: translateX(-100px); }
.mo_reveal-right{ opacity:0; transform: translateX(100px); }

/* Let revealed items keep opacity, but do NOT force transform for tilt cards */
.revealed { opacity: 1 !important; will-change: auto; }

/* Only flatten transforms for non-tilt items */
.revealed:not(.mo_tilt-element) { transform: none !important; }

/* Start hidden for typical direct-children AND for explicit item class */
.mo_stagger > *,
.mo_stagger .mo_stagger-item {
  opacity: 0;
  transform: translateY(12px);
  will-change: opacity, transform;
}

/* Count-up numbers (style only; value comes from JS) */
.mo_count-up { font-variant-numeric: tabular-nums; }

/* “Neo node ping” target should be circular; glow handled by JS/CSS combo */
.mo_neo-node-ping {
  position: relative;
  border-radius: 9999px;
  box-shadow: 0 0 0 0 rgba(0,122,204,0.25);
}

/* Card lift baseline */
.mo_lift-on-hover {
  transition: box-shadow .2s ease;
  box-shadow: 0 6px 16px rgba(0,0,0,0.06);
}

/* Link underline slide (CSS-only microinteraction) */
.mo_link-underline {
  position: relative; text-decoration: none; color: inherit;
}
.mo_link-underline::after {
  content:""; position:absolute; left:0; right:100%; bottom:-2px; height:2px;
  background: currentColor; transition: right .25s ease;
}
.mo_link-underline:hover::after { right:0; }

/* SVG draw helper (optional default stroke) */
/* Keep SVG hidden until JS primes it (prevents the flash) */
.mo_draw-on-view,
.mo_draw-on-view svg { visibility: hidden; }

/* JS adds this when primed so it becomes visible (but still “empty”) */
.mo_draw-prepped { visibility: visible; }

/* Optional: consistent stroke width if SVG scales */
.mo_draw-on-view *, .mo_draw-on-view svg * { vector-effect: non-scaling-stroke; }

/* Respect reduced motion: show art immediately */
@media (prefers-reduced-motion: reduce) {
  .mo_draw-on-view, .mo_draw-on-view svg { visibility: visible !important; }
}

/* Reduce motion: just show final state */
@media (prefers-reduced-motion: reduce) {
  .mo_draw-on-view * { stroke-dasharray: none !important; stroke-dashoffset: 0 !important; }
}

.mo_tilt{
  transform-style: preserve-3d;
  transform-origin: center center;
  will-change: transform;
}

/* Keep transforms off the hover target; inner gets the 3D work */
.mo_tilt-element { position: relative; contain: paint; transition: box-shadow .2s ease; }
.mo_tilt-inner   { transform-style: preserve-3d; will-change: transform; }

/* Don’t flatten tilt transforms when revealed */
.revealed:not(.mo_tilt-element):not(.mo_tilt-inner) { transform: none !important; }

/* Optional glare overlay */
.mo_tilt-element .mo_tilt-glare {
  position: absolute; left:50%; top:50%; width:140%; height:140%;
  pointer-events:none; border-radius:inherit; mix-blend-mode:screen; opacity:0;
  background: radial-gradient(closest-side, rgba(255,255,255,0.4), rgba(255,255,255,0) 60%);
  transform: translate(-50%, -50%) translateZ(60px);
  will-change: transform, opacity;
}

/* Optional: keeps GPU warm and prevents layout thrash */
.mo_follow-mouse {
  will-change: transform;
  transform: translate3d(0,0,0);
  transform-origin: center center;
}

/* The chars get wrapped in <span class="mo_wave-ch"> … */
.mo_wave-ch {
  display:inline-block;
  will-change: transform;
  /* backface-visibility:hidden; */
  transform-origin: 50% 100%;
}


