/* ============================================================
 * APEX SALES OS · ROUTE + RUNNER + TAB TRANSITIONS
 *
 * Owner: Worker done-18 (transitions lane). Loaded after the
 * primitives + layout sheets so its opacity/transform deltas
 * always win the cascade for the brief animation window.
 *
 * Three transition families live here. Every value is opt-in
 * via class — nothing animates unless the router / runner /
 * topbar adds the class. Reduced-motion users get zero motion
 * (handled at the bottom of this file).
 *
 *   1) ROUTE CROSS-FADE — default 200ms fade-out + fade-in on
 *      every hash route change. The router applies
 *      `route-leaving` before swapping rootEl content, removes
 *      it after `replaceChildren()`, then adds `route-entering`
 *      for the in-curve. Composited (opacity only) so the
 *      transition stays at 60fps on the 1440x900 viewport even
 *      when the next page mounts a 4-card KPI row or a
 *      hash-chained ledger.
 *
 *   2) RUNNER STAGE-CROSS — 150ms slide-left + fade for the
 *      video -> test -> voice -> result state machine inside
 *      module-runner.js. The runner adds `stage-cross` on the
 *      stage wrapper, flips state, then removes the class. The
 *      in-curve is shorter and tighter than a route swap because
 *      the rail/header stays put. This is the ONLY internal
 *      transition the runner uses; never call the router CSS for
 *      step changes (the rail would flicker).
 *
 *   3) CELEBRATION HEAVY-FADE — 400ms cross-fade on the three
 *      emotional-payoff routes: #/onboarding/complete,
 *      #/training-complete (and any *-complete page), and the
 *      Phase 7 #/floor-graduation page. The longer curve gives
 *      the celebration confetti / orb intro time to land. The
 *      router auto-detects these hashes; pages don't opt in.
 *
 *   4) TAB-SHAKE — 200ms horizontal nudge on a soft-locked
 *      topbar tab when the user clicks it (router does NOT
 *      navigate because the tab is `aria-disabled` + href="#").
 *      Pair with toast.warning("Unlocks at Phase X"). The shake
 *      lives on the tab itself; no layout shift on neighbours.
 *
 * NEVER add transitions to the html/body element here — those
 * live in 00-tokens.css for theme cross-fade only. NEVER use
 * red anywhere (Apex zero-red rule). NEVER introduce new colors;
 * opacity + translate only.
 * ============================================================ */

/* ------------------------------------------------------------
 * 1. ROUTE CROSS-FADE (default · 200ms)
 *
 * The router toggles these classes on #app-root. We animate
 * opacity only — translateY is intentionally tiny (2px) so the
 * fade reads as a calm dissolve, not a slide. Stripe-tier.
 * ------------------------------------------------------------ */
#app-root {
  transition: opacity 200ms cubic-bezier(.2,.6,.3,1);
  will-change: opacity;
}

#app-root.route-leaving {
  opacity: 0;
}

#app-root.route-entering {
  /* tiny in-curve overshoot so the page lands instead of "pops" */
  animation: route-fade-in 200ms cubic-bezier(.2,.6,.3,1) both;
}

@keyframes route-fade-in {
  from { opacity: 0; transform: translateY(2px); }
  to   { opacity: 1; transform: translateY(0);   }
}

/* ------------------------------------------------------------
 * 3. CELEBRATION HEAVY-FADE (400ms · #/onboarding/complete,
 *    #/training-complete, #/floor-graduation)
 *
 * Router swaps the duration by adding `route-celebration` on
 * #app-root alongside the route-leaving / route-entering class.
 * Longer curve so the confetti + hero number have room to land.
 * ------------------------------------------------------------ */
#app-root.route-celebration {
  transition: opacity 400ms cubic-bezier(.2,.6,.3,1);
}

#app-root.route-celebration.route-entering {
  animation: route-celebration-in 400ms cubic-bezier(.2,.6,.3,1) both;
}

@keyframes route-celebration-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0);   }
}

/* ------------------------------------------------------------
 * 2. RUNNER STAGE-CROSS (150ms slide-left + fade)
 *
 * Used inside module-runner.js for video -> mc -> apex -> result.
 * The runner adds `.stage-cross` on the .runner-stage-wrap element
 * RIGHT BEFORE re-rendering its children, then removes it on the
 * next frame so the new stage fades in from the right.
 * ------------------------------------------------------------ */
.runner-stage-wrap {
  transition: opacity 150ms cubic-bezier(.2,.6,.3,1),
              transform 150ms cubic-bezier(.2,.6,.3,1);
  will-change: opacity, transform;
}

.runner-stage-wrap.stage-cross {
  opacity: 0;
  transform: translateX(-12px);
}

.runner-stage-wrap.stage-cross-in {
  animation: stage-cross-in 150ms cubic-bezier(.2,.6,.3,1) both;
}

@keyframes stage-cross-in {
  from { opacity: 0; transform: translateX(12px); }
  to   { opacity: 1; transform: translateX(0);    }
}

/* ------------------------------------------------------------
 * 4. TAB-SHAKE (soft-locked topbar tab · 200ms)
 *
 * Topbar wires this on click: if the tab carries `.is-soft-locked`,
 * we call e.preventDefault(), add `.shake`, fire a warning toast,
 * and remove `.shake` on animationend.
 * ------------------------------------------------------------ */
.topbar-tab.shake {
  animation: tab-shake 200ms cubic-bezier(.36,.07,.19,.97) both;
}

@keyframes tab-shake {
  10%, 90% { transform: translateX(-1px); }
  20%, 80% { transform: translateX(2px);  }
  30%, 50%, 70% { transform: translateX(-3px); }
  40%, 60% { transform: translateX(3px);  }
}

/* ------------------------------------------------------------
 * REDUCED MOTION — kill every transition above. Per WCAG 2.3.3.
 * Theme cross-fade and other base transitions are out of scope.
 * ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  #app-root,
  #app-root.route-celebration,
  .runner-stage-wrap {
    transition: none !important;
    animation: none !important;
  }
  #app-root.route-leaving { opacity: 1 !important; }
  #app-root.route-entering,
  #app-root.route-celebration.route-entering,
  .runner-stage-wrap.stage-cross,
  .runner-stage-wrap.stage-cross-in {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  .topbar-tab.shake { animation: none !important; }
}
