/* =========================================================
   PHASE 7 FRONT-END / P0.5 — gx-motion.css
   The shared MOTION grammar for the 2030 chat-first surfaces (the shell, the Stage, the glyphs). ONE documented
   hierarchy so micro-interactions stay coherent across chat <-> Stage <-> studio instead of each file reinventing a
   rise. Every transition duration comes from a TOKEN (the global --dur-* in styles.css, or the motion-local
   --gx-dur-shimmer for the looped cadence) — no bare ms literals — and ALL motion is wrapped in ONE
   prefers-reduced-motion guard that drops to the static end-state.

   NAMESPACE: every @keyframes is prefixed `gxm-` (gxm-enter/settle/exit/shimmer/skeleton/toast) so it can NEVER collide
   with a production keyframe (CSS keyframes are a single global namespace, last-load-wins — e.g. feed.css owns a
   different `gx-pulse`). The CLASS selectors stay `.gx-*` (utility convention); only the keyframe NAMES are namespaced.

   ADDITIVE + INERT: nothing consumes these classes until P5 adoption, so flag-off / pre-adoption is byte-identical. The
   today-divergent gx-rise(.42s) / cv-rise(.28s) / fd-rise(.42s) keyframes are deliberately left UNTOUCHED for
   back-compat; gx-motion provides the canonical TARGET vocabulary and P5 migrates each surface onto it (no cross-file
   aliases are shipped here — that would couple gx-motion to other files' selectors + risk a specificity/byte change).
   ========================================================= */

:root {
  /* the in-flight breathing + skeleton sweep cadence — a LOOP, not a UI transition, so distinct from --dur-*.
     Tokenized so the contract stays "durations from a token, never a bare literal". */
  --gx-dur-shimmer: 1.6s;
}

/* ---- keyframes (all gxm- namespaced) ---- */
@keyframes gxm-enter    { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }   /* entrance */
@keyframes gxm-settle   { from { opacity: .5; transform: scale(.965); }    to { opacity: 1; transform: none; } }   /* secured media: one confident scale-in */
@keyframes gxm-exit     { from { opacity: 1; transform: none; }            to { opacity: 0; transform: translateY(6px); } }
@keyframes gxm-shimmer  { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }                                          /* in-flight (●-making) breathing */
@keyframes gxm-skeleton { 0% { background-position: -150% 0; } 100% { background-position: 150% 0; } }              /* loading sweep */
@keyframes gxm-toast    { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }  /* slide-in */

/* ---- the hierarchy: entrance (--dur-slow) -> emphasis (--dur) -> exit (--dur-fast) ---- */
.gx-enter    { animation: gxm-enter   var(--dur-slow) var(--ease-out)    both; }
.gx-settle   { animation: gxm-settle  var(--dur)      var(--ease-spring) both; }   /* emphasis — a settled scale-in for a secured artifact */
.gx-exit     { animation: gxm-exit    var(--dur-fast) var(--ease-in-out) both; }
.gx-shimmer  { animation: gxm-shimmer var(--gx-dur-shimmer) var(--ease-in-out) infinite; }   /* loop on an in-flight node (the plan's in-flight primitive) */
.gx-toast    { animation: gxm-toast   var(--dur-slow) var(--ease-out)    both; }   /* a dock/Stage toast or "reconnecting" pill slide-in */

/* skeleton-loading placeholder (the Stage's pending media + chat skeletons) — a token-coloured sheen sweep. */
.gx-skeleton {
  background: linear-gradient(90deg, var(--void-2) 25%, var(--card-alt) 37%, var(--void-2) 63%);
  background-size: 300% 100%;
  animation: gxm-skeleton var(--gx-dur-shimmer) ease-in-out infinite;
}

/* opt-in premium texture — a faint scanline/grid over a void surface. OFF by default (premium-calm); a surface adds
   .gx-canvas-grid only where it wants the "lab at night" texture. Pure paint, no motion. */
.gx-canvas-grid {
  background-image:
    linear-gradient(var(--hairline-neon) 1px, transparent 1px),
    linear-gradient(90deg, var(--hairline-neon) 1px, transparent 1px);
  background-size: 28px 28px;
  background-position: center;
  opacity: .06;
}

/* ONE reduced-motion guard for the whole motion grammar — drop to the static end-state (the edge comes from contrast +
   glow, never from forced motion). */
@media (prefers-reduced-motion: reduce) {
  .gx-enter, .gx-settle, .gx-exit, .gx-shimmer, .gx-skeleton, .gx-toast {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}
