/* ── Wave 6 motion language (2026-06-10, operator-approved live demo).
   Rules: 150-250ms, ONE ease curve (--ez), opacity + transform only,
   motion always communicates state, and prefers-reduced-motion turns
   ALL of it off (clinical a11y requirement). Everything is scoped to
   the sidebar shell (.app-frame); the legacy shell never animates.
   Loaded AFTER app.css so these compose on top. */

/* Cross-page nav morph: the browser animates the active sidebar pill
   between MPA page loads via the View Transitions API where supported;
   everywhere else navigation is a plain swap. Progressive only. */
@view-transition {
  navigation: auto;
}
.app-frame .sb-item.active {
  view-transition-name: sano-nav-pill;
}
.app-frame .admin-seg-item.active {
  view-transition-name: sano-seg-pill;
}

@media (prefers-reduced-motion: no-preference) {
  /* page content entrance: one soft rise, content only, chrome stays */
  .app-frame main > * {
    animation: sano-rise var(--dur-2) var(--ez) both;
  }

  /* dashboard bento: tiles stagger in (caps at 8 children) */
  .app-frame .dash-bento > * { animation: sano-rise var(--dur-2) var(--ez) both; }
  .app-frame .dash-bento > *:nth-child(2) { animation-delay: 50ms; }
  .app-frame .dash-bento > *:nth-child(3) { animation-delay: 100ms; }
  .app-frame .dash-bento > *:nth-child(4) { animation-delay: 150ms; }
  .app-frame .dash-bento > *:nth-child(5) { animation-delay: 200ms; }
  .app-frame .dash-bento > *:nth-child(6) { animation-delay: 250ms; }
  .app-frame .dash-bento > *:nth-child(7) { animation-delay: 300ms; }
  .app-frame .dash-bento > *:nth-child(n + 8) { animation-delay: 350ms; }

  /* interactive lift: cards + buttons respond, gently */
  .app-frame .btn,
  .app-frame .sb-item,
  .app-frame .admin-seg-item,
  .app-frame .dash-thread {
    transition: transform var(--dur-1) var(--ez), box-shadow var(--dur-1) var(--ez),
      background-color var(--dur-1) var(--ez), border-color var(--dur-1) var(--ez),
      color var(--dur-1) var(--ez);
  }
  .app-frame .btn:active { transform: scale(0.97); }

  /* toasts slide up and settle (composes with existing .toast styles) */
  .app-frame .toast {
    animation: sano-rise var(--dur-2) var(--ez) both;
  }

  /* live progress: bars ease to width, the live dot breathes */
  .app-frame .bar i,
  .app-frame .dash-card .bar i {
    transition: width 900ms var(--ez);
  }
  .app-frame .live-dot {
    animation: sano-pulse 1.6s var(--ez) infinite;
  }

  /* skeleton shimmer primitive (used by the fail-soft loading states) */
  .app-frame .skeleton {
    background: linear-gradient(
      90deg,
      var(--rule-soft) 25%,
      color-mix(in srgb, var(--surface-panel) 70%, var(--rule-soft)) 50%,
      var(--rule-soft) 75%
    );
    background-size: 200% 100%;
    animation: sano-shimmer 1.4s linear infinite;
    border-radius: var(--radius);
    color: transparent;
  }
}

@keyframes sano-rise {
  from { opacity: 0; transform: translateY(7px); }
  to { opacity: 1; transform: none; }
}
@keyframes sano-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.45; transform: scale(0.8); }
}
@keyframes sano-shimmer {
  to { background-position: -200% 0; }
}

/* The kill-switch: every animation + transition in this layer dies for
   reduced-motion users. Validator pins this block. */
@media (prefers-reduced-motion: reduce) {
  .app-frame *,
  .app-frame *::before,
  .app-frame *::after {
    animation: none !important;
    transition: none !important;
  }
}
