/* Wrapped in @layer m3e — the layer order is declared as the first style in
   base.html: @layer properties, theme, base, m3e, components, utilities.
   This makes Tailwind utilities (@layer utilities) win over M3E component
   rules at equal specificity, which is the intended semantics. */
@layer m3e {
/* ═══════════════════════════════════════════════════════════════════════════
 * M3E Motion Tokens
 * Reference: docs/m3e/guidelines/motion.md
 *
 * 12 easing curves (4 categories × 3 speeds) + 1 general spring
 * 16 duration tokens (short1-4, medium1-4, long1-4, extra-long1-4)
 * ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Expressive Spatial (bouncy, for position/size/shape) ── */
  --md-sys-motion-easing-expressive-spatial-fast: cubic-bezier(0.42, 1.85, 0.21, 0.90);
  --md-sys-motion-easing-expressive-spatial-default: cubic-bezier(0.38, 1.21, 0.22, 1.00);
  --md-sys-motion-easing-expressive-spatial-slow: cubic-bezier(0.39, 1.29, 0.35, 0.98);

  /* ── Expressive Effects (no overshoot, for color/opacity) ── */
  --md-sys-motion-easing-expressive-effects-fast: cubic-bezier(0.31, 0.94, 0.34, 1.00);
  --md-sys-motion-easing-expressive-effects-default: cubic-bezier(0.34, 0.80, 0.34, 1.00);
  --md-sys-motion-easing-expressive-effects-slow: cubic-bezier(0.34, 0.88, 0.34, 1.00);

  /* ── Standard Spatial (subtle, for system-initiated motion) ── */
  --md-sys-motion-easing-standard-spatial-fast: cubic-bezier(0.27, 1.06, 0.18, 1.00);
  --md-sys-motion-easing-standard-spatial-default: cubic-bezier(0.27, 1.06, 0.18, 1.00);
  --md-sys-motion-easing-standard-spatial-slow: cubic-bezier(0.27, 1.06, 0.18, 1.00);

  /* ── Standard Effects (functional, for color/opacity) ── */
  --md-sys-motion-easing-standard-effects-fast: cubic-bezier(0.31, 0.94, 0.34, 1.00);
  --md-sys-motion-easing-standard-effects-default: cubic-bezier(0.34, 0.80, 0.34, 1.00);
  --md-sys-motion-easing-standard-effects-slow: cubic-bezier(0.34, 0.88, 0.34, 1.00);

  /* ── General spring approximation ── */
  --md-sys-motion-easing-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* ── Duration tokens ── */
  /* Short — micro-interactions, tooltips, ripples */
  --md-sys-motion-duration-short1: 50ms;
  --md-sys-motion-duration-short2: 100ms;
  --md-sys-motion-duration-short3: 150ms;
  --md-sys-motion-duration-short4: 200ms;

  /* Medium — buttons, chips, small component transitions */
  --md-sys-motion-duration-medium1: 250ms;
  --md-sys-motion-duration-medium2: 300ms;
  --md-sys-motion-duration-medium3: 350ms;
  --md-sys-motion-duration-medium4: 400ms;

  /* Long — cards, dialogs, navigation transitions */
  --md-sys-motion-duration-long1: 450ms;
  --md-sys-motion-duration-long2: 500ms;
  --md-sys-motion-duration-long3: 550ms;
  --md-sys-motion-duration-long4: 600ms;

  /* Extra Long — page transitions, complex orchestrations */
  --md-sys-motion-duration-extra-long1: 700ms;
  --md-sys-motion-duration-extra-long2: 800ms;
  --md-sys-motion-duration-extra-long3: 900ms;
  --md-sys-motion-duration-extra-long4: 1000ms;

  /* Constant-motion loaders. The only durations allowed past 450ms (motion
     spec "Durations": "never >450ms except skeleton shimmer"); their easing is
     `linear` (spinners) or the effects curve (shimmer) — never an overshoot. */
  --md-sys-motion-duration-spinner: 800ms;          /* one turn of a ring spinner */
  --md-sys-motion-duration-spinner-long: 1400ms;    /* circular arc, M3 indeterminate */
  --md-sys-motion-duration-shimmer: 1500ms;         /* skeleton sweep, wavy wave */
  --md-sys-motion-duration-loader-cycle: 1800ms;    /* page loading bar traverse */
  --md-sys-motion-duration-morph: 2000ms;           /* shape-morph loading indicator */
  /* The htmx indicator waits this long before it shows, so a fast navigation
     never paints a flash of the bar (A8-60). */
  --md-sys-motion-delay-indicator: 140ms;

  /* Tailwind's `transition-*` utilities read these two variables (defined in
     tailwind.css `@layer theme`). This file's `@layer m3e` comes later in the
     declared layer order, so the house tokens win without a Tailwind rebuild
     and every `transition-colors`/`-opacity`/`-transform` in a template runs
     on the motion tokens (review P2-5). */
  --default-transition-duration: var(--md-sys-motion-duration-short3);
  --default-transition-timing-function: var(--md-sys-motion-easing-standard-effects-default);
}


/* ═══════════════════════════════════════════════════════════════════════════
 * Reduced Motion
 *
 * Part 1: Kill all keyframe animations and transitions globally.
 * Part 2: Re-enable short opacity transitions on state-layer pseudo-elements
 *         so hover/focus feedback remains visible (non-vestibular).
 *         Class selectors (0-1-1) beat universal selector (0-0-0) in
 *         specificity, so these override Part 1 even with !important on both.
 * Part 3: Ensure elements that start at opacity:0 become visible instantly.
 * Part 4: Loading indicators show as static circles.
 * ═══════════════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  /* Part 1: Kill everything globally */
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  /* Part 2: Re-enable opacity transitions on state-layer elements */
  .m3e-state-layer::before,
  .m3e-button::before,
  .m3e-chip::before,
  .m3e-fab::before,
  .m3e-toolbar__action::before,
  .m3e-nav-drawer__item::before,
  .m3e-tabs__tab::before,
  .m3e-card--interactive::before,
  .m3e-card[href]::before,
  .m3e-list__item::before {
    transition-duration: 150ms !important;
    transition-property: opacity !important;
  }

  /* Part 3: Ensure animated elements that start at opacity:0 become visible */
  .field-error-animate {
    opacity: 1 !important;
  }

  /* Part 4: Loading indicators show as static circles */
  .m3e-loading-inline,
  .m3e-loading-indicator {
    animation: none !important;
    border-radius: 50% !important;
    opacity: 0.7;
  }

  /* Part 5: Wavy progress bar falls back to flat rectangle */
  .m3e-progress--wavy .m3e-progress__bar {
    clip-path: none !important;
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
 * Global Keyframes (extracted from base.html)
 *
 * These are referenced by utility classes in components.css and by
 * animation declarations across the shell and page templates.
 * ═══════════════════════════════════════════════════════════════════════════ */

/* ── HTMX loading bar ── */
@keyframes loading-slide {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}

/* ── View Transitions ── */
@keyframes vt-fade-out {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(-4px); }
}
@keyframes vt-fade-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ── Sheet / modal ── */
@keyframes sheet-slide-up {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}
@keyframes sheet-slide-down {
  from { transform: translateY(0); }
  to   { transform: translateY(100%); }
}
@keyframes modal-scale-in {
  from { opacity: 0; transform: scale(0.95); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes modal-scale-out {
  from { opacity: 1; transform: scale(1); }
  to   { opacity: 0; transform: scale(0.95); }
}

/* ── Mobile menu entrance / exit ── */
@keyframes menu-backdrop-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes menu-backdrop-out {
  from { opacity: 1; }
  to   { opacity: 0; }
}
@keyframes menu-panel-in {
  from { transform: translateX(-100%); }
  to   { transform: translateX(0); }
}
@keyframes menu-panel-out {
  from { transform: translateX(0); }
  to   { transform: translateX(-100%); }
}

/* ── Badge pulse on appear ── */
@keyframes badge-pop {
  0%   { transform: scale(0.8); opacity: 0; }
  60%  { transform: scale(1.1); }
  100% { transform: scale(1); opacity: 1; }
}

/* ── Form error slide-in ── */
@keyframes error-slide-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ── Page content entrance ── */
@keyframes page-enter {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
/* No fill mode, on purpose. The `to` keyframe IS the element's resting state,
   so nothing snaps when the animation ends — and `forwards` would keep the
   keyframe's `transform: translateY(0)` applied for the life of the page. A
   transformed element is the containing block for its `position: fixed`
   descendants, which sent every dropdown menu inside #page-content to
   (trigger + #page-content's own viewport offset). See
   core/tests_menu_positioning.py. */
#page-content {
  animation: page-enter var(--md-sys-motion-duration-medium1)
             var(--md-sys-motion-easing-standard-effects-default);
  /* The loading dim (components.css `.nav-loading`) fades in AND out: the
     transition lives on the base rule so removing the class is continuous,
     never a snap from 0.55 to 1. */
  transition: opacity var(--md-sys-motion-duration-short2) var(--easing-effects);
}
/* One entrance per navigation (P1-10). A cross-document navigation that the
   browser animated with the root view transition (vt-fade-in, components.css)
   must not run page-enter on top of it. base.html's `pagereveal` listener
   stamps this class when e.viewTransition exists. The class stays for the
   life of the document (removing it would START page-enter late), and
   `:where()` keeps this at the base rule's specificity so the later boosted
   cross-fade classes (motion-roles.css) still win. */
:where(html.m3e-vt-reveal) #page-content { animation: none; }
}
