/* Adapted from https://transitions.dev/: modal, panel reveal, menu dropdown, icon swap,
   accordion and toast. Shared by Rails, the player, offline and Lesson Studio.
   Native surfaces progressively enhance; Radix uses keyframes so Presence can
   retain the DOM through exit. No motion is applied to audio or timeline data. */
:root {
  --motion-open: 250ms;
  --motion-close: 150ms;
  --motion-panel-open: 400ms;
  --motion-panel-close: 350ms;
  --motion-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --motion-modal-scale: 0.96;
  --motion-menu-scale: 0.97;
}

/* Scale is independent of translate, preserving each dialog's positioning. */
[data-slot="dialog-content"][data-state="open"] {
  animation: ui-modal-in var(--motion-open) var(--motion-ease) both;
}
[data-slot="dialog-content"][data-state="closed"] {
  animation: ui-modal-out var(--motion-close) var(--motion-ease) both;
  pointer-events: none;
}
:is([data-slot="dialog-overlay"], [data-slot="sheet-overlay"])[data-state="open"] {
  animation: ui-fade-in var(--motion-open) var(--motion-ease) both;
}
:is([data-slot="dialog-overlay"], [data-slot="sheet-overlay"])[data-state="closed"] {
  animation: ui-fade-out var(--motion-close) var(--motion-ease) both;
}
[data-slot="sheet-content"] { --panel-x: 0; --panel-y: 0; }
[data-slot="sheet-content"][data-side="right"] { --panel-x: 2rem; }
[data-slot="sheet-content"][data-side="left"] { --panel-x: -2rem; }
[data-slot="sheet-content"][data-side="top"] { --panel-y: -2rem; }
[data-slot="sheet-content"][data-side="bottom"] { --panel-y: 2rem; }
[data-slot="sheet-content"][data-state="open"] {
  animation: ui-panel-in var(--motion-panel-open) var(--motion-ease) both;
}
[data-slot="sheet-content"][data-state="closed"] {
  animation: ui-panel-out var(--motion-panel-close) var(--motion-ease) both;
  pointer-events: none;
}

@keyframes ui-modal-in { from { opacity: 0; scale: var(--motion-modal-scale); } to { opacity: 1; scale: 1; } }
@keyframes ui-modal-out { from { opacity: 1; scale: 1; } to { opacity: 0; scale: var(--motion-modal-scale); } }
@keyframes ui-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes ui-fade-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes ui-panel-in { from { opacity: 0; translate: var(--panel-x) var(--panel-y); } to { opacity: 1; translate: 0 0; } }
@keyframes ui-panel-out { from { opacity: 1; translate: 0 0; } to { opacity: 0; translate: var(--panel-x) var(--panel-y); } }

/* showModal()/close() keep native focus management, Escape and form behavior.
   Discrete display/overlay transitions retain the surface in the top layer. */
@supports (transition-behavior: allow-discrete) {
  dialog {
    opacity: 0;
    scale: var(--motion-modal-scale);
    transition: opacity var(--motion-close) var(--motion-ease), scale var(--motion-close) var(--motion-ease), display var(--motion-close) allow-discrete, overlay var(--motion-close) allow-discrete;
  }
  dialog[open] { opacity: 1; scale: 1; transition-duration: var(--motion-open); }
  dialog:not([open]) { pointer-events: none; interactivity: inert; }
  dialog::backdrop {
    opacity: 0;
    transition: opacity var(--motion-close) var(--motion-ease), display var(--motion-close) allow-discrete, overlay var(--motion-close) allow-discrete;
  }
  dialog[open]::backdrop { opacity: 1; transition-duration: var(--motion-open); }
  @starting-style {
    dialog[open] { opacity: 0; scale: var(--motion-modal-scale); }
    dialog[open]::backdrop { opacity: 0; }
  }
  /* A visually retained native dialog must not retain keyboard interaction. */
  @supports not (interactivity: inert) {
    dialog:not([open]), dialog:not([open])::backdrop { transition: none; }
  }
}

/* Processing menus stay mounted; hidden/inert remove their closed contents
   from keyboard navigation while the browser finishes the visual exit. */
.ui-motion-menu {
  transform-origin: top right;
  opacity: 1;
  scale: 1;
  transition: opacity var(--motion-open) var(--motion-ease), scale var(--motion-open) var(--motion-ease), display var(--motion-open) allow-discrete;
}
.ui-motion-menu[hidden] {
  display: none;
  opacity: 0;
  scale: 0.99;
  pointer-events: none;
  transition-duration: var(--motion-close);
}
@starting-style {
  .ui-motion-menu:not([hidden]) { opacity: 0; scale: var(--motion-menu-scale); }
}

/* Native details preserve keyboard, find-in-page and no-JavaScript behavior.
   Animate the reveal; hide immediately on close, since delaying
   content-visibility would leave closed controls focusable.
   Keep dropdown content overflow visible; only in-flow accordions clip height. */
@supports selector(details::details-content) and (transition-behavior: allow-discrete) {
  .library-menu::details-content {
    opacity: 0;
    transition: opacity var(--motion-close) var(--motion-ease), content-visibility 0s allow-discrete;
  }
  .library-menu[open]::details-content { opacity: 1; transition-duration: var(--motion-open); }
  .library-menu__items {
    transform-origin: top right;
    scale: var(--motion-menu-scale);
    transition: scale var(--motion-close) var(--motion-ease);
  }
  .library-menu[open] > .library-menu__items { scale: 1; transition-duration: var(--motion-open); }
  .library-menu:not([open]) > .library-menu__items { pointer-events: none; }
}
@supports (interpolate-size: allow-keywords) and selector(details::details-content) {
  :is(.track-simple-settings, .form-section, .stemming-disclosure, .pricing-faq details, .admin-query-help, .rhythm-focused__advanced)::details-content {
    interpolate-size: allow-keywords;
    block-size: 0;
    opacity: 0;
    overflow: clip;
    transition: block-size var(--motion-close) var(--motion-ease), opacity var(--motion-close) var(--motion-ease), content-visibility 0s allow-discrete;
  }
  :is(.track-simple-settings, .form-section, .stemming-disclosure, .pricing-faq details, .admin-query-help, .rhythm-focused__advanced)[open]::details-content {
    block-size: auto;
    opacity: 1;
    transition-duration: var(--motion-open);
  }
}

/* Both glyphs occupy the same cell: interrupted toggles reverse naturally. */
.ui-icon-swap { display: inline-grid; place-items: center; flex-shrink: 0; vertical-align: middle; }
.ui-icon-swap > svg {
  grid-area: 1 / 1;
  opacity: 0;
  scale: 0.25;
  filter: blur(4px);
  transition: opacity var(--motion-open) cubic-bezier(0.2, 0, 0, 1), scale var(--motion-open) cubic-bezier(0.2, 0, 0, 1), filter var(--motion-open) cubic-bezier(0.2, 0, 0, 1);
}
.ui-icon-swap[data-active="false"] > :first-child,
.ui-icon-swap[data-active="true"] > :last-child { opacity: 1; scale: 1; filter: blur(0); }

/* A notification enters once, without delaying its live-region announcement. */
:is(.flash, .admin-flash) { animation: ui-notice-in var(--motion-open) var(--motion-ease) both; }
@keyframes ui-notice-in { from { opacity: 0; translate: 0 8px; } to { opacity: 1; translate: 0 0; } }

@media (prefers-reduced-motion: reduce) {
  :is([data-slot="dialog-content"], [data-slot="dialog-overlay"], [data-slot="sheet-content"], [data-slot="sheet-overlay"], .flash, .admin-flash) { animation: none !important; }
  dialog, dialog::backdrop, .ui-motion-menu, .library-menu__items, .ui-icon-swap > svg { transition: none !important; }
  details::details-content { transition: none !important; }
}
