/* ===========================================================================
   motion.css — site-wide motion layer for the Green site
   Additive only. Adds no layout, no colour, no typography. Safe to delete.

   Design rules this file holds itself to:
     · Hover/press feedback is <= 180ms. Anything slower reads as lag.
     · Entrance reveals run ONCE per element, then the observer detaches.
       Nothing re-animates on scroll-back — that is the distracting kind.
     · Only opacity and transform are animated (compositor-only, no reflow).
     · No parallax, no auto-playing loops in the viewport except the loading
       shimmer, which stops the moment real content replaces it.
     · prefers-reduced-motion: reduce disables all of it. Not "reduces" —
       disables. Content must be fully visible and usable with zero motion.
   =========================================================================== */

:root{
  --mo-fast:120ms;
  --mo-base:180ms;
  --mo-reveal:420ms;
  --mo-ease:cubic-bezier(.2,.6,.2,1);
  --mo-ease-out:cubic-bezier(.16,1,.3,1);
  --mo-lift:-2px;
  --mo-shadow:0 6px 22px rgba(0,0,0,.34);
}

/* ---------------------------------------------------------------- hover ---
   Applied by class so nothing animates by accident. Add .mo-card to any
   card/tile, .mo-press to any button or CTA, .mo-link to inline links.      */

.mo-card{
  transition:
    transform var(--mo-base) var(--mo-ease-out),
    border-color var(--mo-base) ease,
    box-shadow var(--mo-base) ease;
  will-change:transform;
}
.mo-card:hover,
.mo-card:focus-visible{
  transform:translateY(var(--mo-lift));
  box-shadow:var(--mo-shadow);
}
.mo-card:active{ transform:translateY(0); transition-duration:var(--mo-fast); }

.mo-press{
  transition:
    background-color var(--mo-fast) ease,
    border-color var(--mo-fast) ease,
    transform var(--mo-fast) var(--mo-ease-out);
}
.mo-press:hover{ transform:translateY(-1px); }
.mo-press:active{ transform:translateY(0) scale(.995); }

/* arrow nudge — only for elements that end in a directional glyph */
.mo-nudge span.arrow{ display:inline-block; transition:transform var(--mo-base) var(--mo-ease-out); }
.mo-nudge:hover span.arrow{ transform:translateX(3px); }

.mo-link{ transition:color var(--mo-fast) ease, border-color var(--mo-fast) ease; }

/* focus is never animated away — keyboard users must always see the ring */
.mo-card:focus-visible,
.mo-press:focus-visible,
.rcard:focus-visible{ outline:2px solid var(--brand,#7ac85e); outline-offset:2px; }

/* --------------------------------------------------------------- reveal ---
   Elements marked .mo-reveal start slightly down and transparent; the
   observer adds .is-in once, then stops watching them.                      */

/* Gated on html.mo-js, which the page sets inline. If JS never runs, or the
   script errors before the observer attaches, content stays fully visible. */
html.mo-js .mo-reveal{
  opacity:0;
  transform:translateY(10px);
  transition:opacity var(--mo-reveal) ease, transform var(--mo-reveal) var(--mo-ease-out);
}
html.mo-js .mo-reveal.is-in{ opacity:1; transform:none; }

/* stagger inside a group, capped at 6 so a long list never crawls */
.mo-stagger > *:nth-child(1){ transition-delay:0ms }
.mo-stagger > *:nth-child(2){ transition-delay:50ms }
.mo-stagger > *:nth-child(3){ transition-delay:100ms }
.mo-stagger > *:nth-child(4){ transition-delay:150ms }
.mo-stagger > *:nth-child(5){ transition-delay:200ms }
.mo-stagger > *:nth-child(n+6){ transition-delay:250ms }

/* ------------------------------------------------------------- skeleton ---
   Placeholder shown while an async block (a rendered diagram, a fetched
   panel) is still building. Replace the node's innerHTML to remove it.      */

.mo-skeleton{
  position:relative;
  overflow:hidden;
  border-radius:10px;
  background:var(--surface-2,rgba(255,255,255,.045));
  min-height:180px;
}
.mo-skeleton::after{
  content:"";
  position:absolute; inset:0;
  transform:translateX(-100%);
  background:linear-gradient(90deg,
    transparent 0%,
    rgba(255,255,255,.05) 45%,
    rgba(255,255,255,.08) 50%,
    rgba(255,255,255,.05) 55%,
    transparent 100%);
  animation:mo-sweep 1.5s ease-in-out infinite;
}
@keyframes mo-sweep{ to{ transform:translateX(100%); } }

.mo-skeleton-label{
  position:absolute; left:0; right:0; top:50%; transform:translateY(-50%);
  text-align:center;
  font-family:var(--mono,ui-monospace,monospace);
  font-size:11px; letter-spacing:.12em; text-transform:uppercase;
  color:var(--muted,#8a8a8a);
}

/* modal: opens quickly, never bounces */
.backdrop{ opacity:0; transition:opacity var(--mo-base) ease; }
.backdrop.open{ opacity:1; }
.backdrop .modal{
  transform:translateY(6px) scale(.995);
  transition:transform var(--mo-base) var(--mo-ease-out);
}
.backdrop.open .modal{ transform:none; }

/* =====================================================================
   The switch. Everything above is off under reduced motion.
   Reveals resolve to fully visible — never leave content at opacity 0.
   ===================================================================== */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
  html.mo-js .mo-reveal{ opacity:1 !important; transform:none !important; }
  .mo-card:hover, .mo-press:hover, .mo-card:active, .mo-press:active{ transform:none !important; }
  .mo-card:focus-visible{ transform:none !important; box-shadow:none !important; }
  .mo-nudge:hover span.arrow, .mo-nudge span.arrow{ transform:none !important; }
  .mo-skeleton::after{ animation:none !important; transform:none !important;
                       background:rgba(255,255,255,.05); }
  .backdrop .modal{ transform:none !important; }
}
