/* ============ Admin — motion ============
   Every animation here runs only when the user has not asked for reduced motion (the kill switch at
   the end of admin.css stops the rest). Only transform and opacity move. Infinite animations (and only
   those: a paused entrance would stay on its invisible first frame) pause while a TV video is encoded
   (body.is-encoding). Never animate #app, .admin, #view or .a-wrap: their
   children are animated instead, so the fixed bottom navigation stays put. */

/* ---------- shared names: the header and the bottom bar stay still while pages swap ---------- */
.admin-page .abar{view-transition-name:abar}
.admin-page .toast{view-transition-name:toast}
.admin-page #netBanner{view-transition-name:net-banner}
.admin-page #updateBar{view-transition-name:update-bar}
@media(max-width:640px){
  .admin-page .tabs,.admin-page .skel-tabs{view-transition-name:nav}
}

/* ---------- the dialog that is leaving (a hidden copy, see ui.js closeModal) ---------- */
.admin-page .modal-ghost{display:flex;z-index:var(--z-ghost);pointer-events:none}

body.is-encoding.admin-page :is(.skel,#loginBtn.is-loading)::after,
body.is-encoding.admin-page :is(.save-state[data-state=saving] .save-dot,.boot .login-mark,.thumb-drop .prev.is-loading){animation-play-state:paused!important}

@media (prefers-reduced-motion: no-preference){
  /* View Transitions: forward slides the page left, back slides it right, none crossfades. */
  ::view-transition-group(*){animation-duration:var(--dur-med);animation-timing-function:var(--ease-out)}
  html[data-nav=forward]::view-transition-old(root){animation:vt-out-left var(--dur-med) var(--ease-in) both}
  html[data-nav=forward]::view-transition-new(root){animation:vt-in-right var(--dur-med) var(--ease-out) both}
  html[data-nav=back]::view-transition-old(root){animation:vt-out-right var(--dur-med) var(--ease-in) both}
  html[data-nav=back]::view-transition-new(root){animation:vt-in-left var(--dur-med) var(--ease-out) both}
  html[data-nav=none]::view-transition-old(root){animation:vt-fade-out var(--dur-fast) var(--ease-in) both}
  html[data-nav=none]::view-transition-new(root){animation:vt-fade-in var(--dur-med) var(--ease-out) both}

  /* The same moves without View Transitions: the new children of #view (never #view, never the bar). */
  #view.view-enter-forward > :not(.tabs):not(.skel-tabs){animation:vt-in-right var(--dur-med) var(--ease-out) backwards}
  #view.view-enter-back > :not(.tabs):not(.skel-tabs){animation:vt-in-left var(--dur-med) var(--ease-out) backwards}
  #view.view-enter-none > :not(.tabs):not(.skel-tabs){animation:vt-fade-in var(--dur-med) var(--ease-out) backwards}

  /* Dialogs: a card that springs up on wide screens, a sheet that slides up on phones. */
  .admin-page .modal-bg.show{animation:fade-in var(--dur-med) var(--ease-out)}
  .admin-page .modal-bg.show .modal{animation:modal-in var(--dur-slow) var(--ease-spring)}
  .admin-page .modal-bg.is-swapping,.admin-page .modal-bg.is-swapping .modal{animation:none}
  .admin-page .modal-ghost{animation:fade-out var(--dur-fast) var(--ease-in) forwards}
  .admin-page .modal-ghost .modal{animation:modal-out var(--dur-fast) var(--ease-in) forwards}

  /* Login: the card shakes on a refused password; the button spins while checking. */
  .admin-page .login-card.shake{animation:login-shake 420ms var(--ease-out)}
  .admin-page #loginBtn.is-loading::after{content:"";width:16px;height:16px;border-radius:50%;border:2px solid rgba(255,255,255,.4);
    border-top-color:#fff;animation:spin 700ms linear infinite}

  /* Skeleton shimmer */
  .admin-page .skel::after{animation:shimmer 1.3s ease-in-out infinite}

  /* Save chip: a pulsing dot while saving, a tick that pops in when saved */
  .admin-page .save-state:not([hidden]){animation:fade-in var(--dur-fast) var(--ease-out)}
  .admin-page .save-state[data-state=saving] .save-dot{animation:pulse 1s ease-in-out infinite}
  .admin-page .save-state[data-state=saved] .save-dot{animation:pop-in var(--dur-med) var(--ease-spring)}

  /* Notices drop in from the top edge; the install button pops in when the browser offers it. */
  .admin-page .top-notice:not([hidden]){animation:drop-in var(--dur-med) var(--ease-out)}
  .admin-page .top-notice.is-leaving{animation:lift-out var(--dur-fast) var(--ease-in) forwards}
  .admin-page .install-btn:not([hidden]){animation:pop-in var(--dur-med) var(--ease-spring)}
  .admin-page .net-banner{transition:background var(--dur-med) var(--ease-out),color var(--dur-med) var(--ease-out)}

  /* Press feedback. Each list repeats the property's existing transitions, then adds transform. */
  .admin-page .btn{transition:background .15s,border-color .15s,color .15s,box-shadow .15s,transform var(--dur-instant) var(--ease-out)}
  .admin-page .icon-btn{transition:background .15s,color .15s,transform var(--dur-instant) var(--ease-out)}
  .admin-page [role=tab]{transition:color .15s,transform var(--dur-instant) var(--ease-out)}
  .admin-page .stat{transition:border-color .15s,box-shadow .15s,transform var(--dur-instant) var(--ease-out)}
  .admin-page .chip-opt{transition:background .15s,border-color .15s,color .15s,transform var(--dur-instant) var(--ease-out)}
  .admin-page .layout-opt,.admin-page .skin-card{transition:border-color .15s,background .15s,transform var(--dur-instant) var(--ease-out)}
  .admin-page .picker-button{transition:border-color .15s,box-shadow .15s,transform var(--dur-instant) var(--ease-out)}
  .admin-page .seg button{transition:background .15s,color .15s,box-shadow .15s,transform var(--dur-instant) var(--ease-out)}
  .admin-page .item-list .item-row{transition:background var(--dur-fast) var(--ease-out)}
  @media (hover:hover){
    .admin-page :is(.stat,.skin-card,.layout-opt):hover{transform:translateY(-1px)}
  }
  .admin-page :is(.btn,.icon-btn,[role=tab],.stat,.chip-opt,.layout-opt,.skin-card,.picker-button,.seg button):active:not([disabled]):not([aria-disabled=true]){transform:scale(.97)}
  .admin-page .item-list .item-row:active:not(.is-dragging){background:var(--bg)}
}

@keyframes vt-out-left{to{opacity:0;transform:translateX(-24px)}}
@keyframes vt-out-right{to{opacity:0;transform:translateX(24px)}}
@keyframes vt-in-right{from{opacity:0;transform:translateX(24px)}}
@keyframes vt-in-left{from{opacity:0;transform:translateX(-24px)}}
@keyframes vt-fade-out{to{opacity:0}}
@keyframes vt-fade-in{from{opacity:0}}
@keyframes fade-in{from{opacity:0}}
@keyframes fade-out{to{opacity:0}}
@keyframes modal-in{from{opacity:0;transform:translateY(8px) scale(.96)}}
@keyframes modal-out{to{opacity:0;transform:scale(.97)}}
@keyframes sheet-in{from{transform:translateY(100%)}}
@keyframes sheet-out{to{transform:translateY(100%)}}
@keyframes login-shake{0%,100%{transform:none}15%{transform:translateX(-8px)}30%{transform:translateX(8px)}45%{transform:translateX(-6px)}60%{transform:translateX(6px)}75%{transform:translateX(-3px)}}
@keyframes spin{to{transform:rotate(360deg)}}
@keyframes shimmer{from{transform:translateX(-100%)}to{transform:translateX(100%)}}
@keyframes pulse{50%{opacity:.35;transform:scale(.8)}}
@keyframes pop-in{from{opacity:0;transform:scale(.6)}}
@keyframes drop-in{from{transform:translateY(-100%)}}
@keyframes lift-out{to{opacity:0;transform:translateY(-100%)}}

@media (prefers-reduced-motion: no-preference) and (max-width:640px){
  .admin-page .modal-bg.show .modal{animation:sheet-in var(--dur-slow) var(--ease-emph)}
  .admin-page .modal-bg.is-swapping .modal{animation:none}
  .admin-page .modal-ghost .modal{animation:sheet-out var(--dur-fast) var(--ease-in) forwards}
}
