/* motion.css — chuyển động HIG cho thietbi.gmm.vn (/, /app, /2FA). Thứ tự: tokens → keyframes → shared → index → app → 2FA → reduced-motion. */

/* ===== 1. Tokens ===== */
:root{
  --m-out:cubic-bezier(.2,0,0,1);
  --m-in:cubic-bezier(.4,0,1,1);
  --m-inout:cubic-bezier(.45,0,.15,1);
  --m-sheet:cubic-bezier(.32,.72,0,1);
  --m-spring:cubic-bezier(.34,1.45,.64,1);
  --m-pop:cubic-bezier(.2,.9,.3,1.15);
  --m-80:80ms;--m-120:120ms;--m-180:180ms;--m-240:240ms;--m-320:320ms;--m-420:420ms;--m-520:520ms;
  --m-stagger:40ms;--m-delay-base:0ms;
  --m-press:.97;--m-press-sm:.92;--m-lift:-2px;
  --m-rise:8px;--m-rise-sm:4px;
  --m-sheet-y:24px;--m-sheet-scale:.96;--m-alert-scale:1.08;
  --m-shake:6px;--m-blur:8px;--m-code-scale:.96;
  --m-toast-y:16px;--m-toast-scale:.96;
}
@media(max-width:720px){:root{--m-sheet-y:40px;--m-sheet-scale:1;--m-lift:0px}}
@media(prefers-reduced-motion:reduce){:root{
  --m-rise:0px;--m-rise-sm:0px;--m-sheet-y:0px;--m-sheet-scale:1;--m-alert-scale:1;
  --m-shake:0px;--m-blur:0px;--m-code-scale:1;--m-lift:0px;--m-press:1;--m-press-sm:1;
  --m-toast-y:0px;--m-toast-scale:1;--m-stagger:0ms;--m-delay-base:0ms;
  --m-spring:ease-out;--m-pop:ease-out;--m-sheet:ease-out;
  --m-320:160ms;--m-420:180ms;--m-520:200ms;
}}

/* ===== 2. Keyframes (from-only: trạng thái nghỉ là style của chính phần tử) ===== */
@keyframes m-fade{from{opacity:0}}
@keyframes m-undim{to{opacity:0}}
@keyframes m-rise{from{opacity:0;transform:translateY(var(--m-rise))}}
@keyframes m-rise-sm{from{opacity:0;transform:translateY(var(--m-rise-sm))}}
@keyframes m-sheet-in{from{opacity:0;transform:translateY(var(--m-sheet-y)) scale(var(--m-sheet-scale))}}
@keyframes m-sheet-out{to{opacity:0;transform:translateY(calc(var(--m-sheet-y)/2)) scale(.98)}}
@keyframes m-alert-in{from{opacity:0;transform:scale(var(--m-alert-scale))}}
@keyframes m-alert-out{to{opacity:0;transform:scale(.97)}}
@keyframes m-xfade{from{opacity:0;transform:scale(.985)}}
@keyframes m-shake{10%,90%{transform:translateX(calc(var(--m-shake)*-.33))}20%,80%{transform:translateX(calc(var(--m-shake)*.66))}30%,50%,70%{transform:translateX(calc(var(--m-shake)*-1))}40%,60%{transform:translateX(var(--m-shake))}}
@keyframes m-bump{40%{transform:scale(1.22)}}
@keyframes m-bump-sm{50%{transform:scale(1.06)}}
@keyframes m-pop{from{opacity:0;transform:scale(.4)}}
@keyframes m-bar{from{transform:scaleX(0)}}
@keyframes m-code-in{from{opacity:0;transform:translateY(var(--m-rise-sm)) scale(var(--m-code-scale));filter:blur(var(--m-blur))}to{filter:blur(0)}}
@keyframes m-code-clear{from{opacity:0}}
@keyframes m-toast-in{from{opacity:0;transform:translate(-50%,var(--m-toast-y)) scale(var(--m-toast-scale))}to{opacity:1;transform:translate(-50%,0) scale(1)}}
@keyframes gmm-switcher-in{from{opacity:0;transform:translateY(6px) scale(.94)}}

/* ===== 3. Shared (cả 3 trang) ===== */
/* S1: giữ scroll tức thời (live-sync scrollTo, catalog scrollIntoView) */
html{scroll-behavior:auto}
/* S2 */
button,a,summary,[role=button]{-webkit-tap-highlight-color:transparent}
/* S3: transform guard — tổ tiên của #book-summary (fixed) và các wrapper glass, không bao giờ transform */
.panel,#app,main,body,#booking-list,#stats,#device-list,#pick-list,#log-list,#user-list,#selected-list,.book-filter-track,.book-summary-track,#app-grid{transform:none!important;will-change:auto!important}
/* S4 */
.stat b,.stepper b,#notice-dot,.twofa-code,#get,#validity{font-variant-numeric:tabular-nums}
/* S5: popover switcher */
.gmm-switcher-panel{transform-origin:22px 100%;animation:gmm-switcher-in var(--m-240) var(--m-out) both}
/* S6 */
.gmm-switcher summary,.gmm-folder-button{transition:transform var(--m-240) var(--m-out),background-color var(--m-180) ease,border-color var(--m-180) ease,box-shadow var(--m-240) ease}
.gmm-switcher summary:active,.gmm-folder-button:active{transform:scale(var(--m-press-sm));transition-duration:var(--m-80)}
/* S7 */
.gmm-switcher a{transition:background-color var(--m-180) ease,transform var(--m-240) var(--m-out)}
.gmm-switcher a:active{transform:scale(var(--m-press));transition-duration:var(--m-80)}
@media(hover:none){.gmm-switcher a:hover{transform:none}}
/* S8: <dialog> mở */
dialog[open]{animation:m-sheet-in var(--m-420) var(--m-sheet) both}
dialog[open]::backdrop{animation:m-fade 240ms ease-out both}   /* giá trị literal: ::backdrop chưa kế thừa custom property trên Safari <17.4 / Chromium <122 */
/* S9: <dialog> đóng (.m-out từ close() override) — phải đứng sau S8 */
dialog[open].m-out{animation:m-sheet-out var(--m-180) var(--m-in) both;pointer-events:none}
dialog[open].m-out::backdrop{animation:m-undim 180ms cubic-bezier(.4,0,1,1) both}

/* ===== 4. index.html ===== */
/* Login I1–I3 */
.login-box{animation:m-sheet-in var(--m-520) var(--m-out) both}
.login-box.m-shake{animation:m-sheet-in var(--m-520) var(--m-out) both,m-shake var(--m-420) var(--m-inout)}
.error.show{animation:m-rise-sm var(--m-240) var(--m-out) both}
/* App entrance I4–I6 */
#app.m-app-in>header{animation:m-rise var(--m-420) var(--m-out) both}
#app.m-app-in>nav{animation:m-rise var(--m-420) var(--m-out) both;animation-delay:calc(var(--m-stagger)*1)}
#app.m-app-in{--m-delay-base:120ms}
/* Tab switch I7–I12 */
.panel.m-tab-in>:nth-child(2){--m-i:1}
.panel.m-tab-in>:nth-child(3){--m-i:2}
.panel.m-tab-in>:nth-child(4){--m-i:3}
.panel.m-tab-in>:nth-child(n+5){--m-i:4}
.panel.m-tab-in>.card,.panel.m-tab-in>.alert,.panel.m-tab-in>.grid>.stat,#panel-book.m-tab-in>.book-filter-track>#book-filters,#panel-bookings.m-tab-in>#booking-list>:nth-child(-n+5){animation:m-rise var(--m-320) var(--m-out) both;animation-delay:calc(var(--m-delay-base) + var(--m-stagger)*var(--m-i,0))}
.panel.m-tab-in>.grid>.stat:nth-child(1){--m-i:0}
.panel.m-tab-in>.grid>.stat:nth-child(2){--m-i:1}
.panel.m-tab-in>.grid>.stat:nth-child(3){--m-i:2}
.panel.m-tab-in>.grid>.stat:nth-child(4){--m-i:3}
#panel-bookings.m-tab-in>#booking-list>:nth-child(1){--m-i:1}
#panel-bookings.m-tab-in>#booking-list>:nth-child(2){--m-i:2}
#panel-bookings.m-tab-in>#booking-list>:nth-child(3){--m-i:3}
#panel-bookings.m-tab-in>#booking-list>:nth-child(4){--m-i:4}
#panel-bookings.m-tab-in>#booking-list>:nth-child(5){--m-i:5}
#panel-book.m-tab-in>.book-summary-track>#book-summary{animation:m-sheet-in var(--m-420) var(--m-sheet) both;animation-delay:calc(var(--m-delay-base) + var(--m-stagger)*2)}
#panel-dashboard.m-tab-in .bar span{transform-origin:left center;animation:m-bar var(--m-420) var(--m-out) both;animation-delay:calc(var(--m-delay-base) + var(--m-stagger)*1)}   /* kết thúc ≤580 ms, trước khi gate 600 ms đóng */
/* Nav pill I13–I16 (giá trị active copy từ champagne nav button.active) */
nav.m-has-pill>.m-nav-pill{position:absolute;left:0;top:0;width:0;height:0;opacity:0;pointer-events:none;z-index:0;border-radius:15px;border:1px solid rgba(255,240,215,.32);background:linear-gradient(145deg,rgba(244,221,185,.25),rgba(184,175,193,.11));box-shadow:inset 0 1px 0 rgba(255,250,240,.42),0 7px 20px rgba(35,25,22,.27);will-change:transform;transition:transform var(--m-420) var(--m-out),width var(--m-420) var(--m-out),height var(--m-420) var(--m-out),opacity var(--m-180) ease}
nav.m-has-pill>.m-nav-pill.m-jump{transition:none}
nav.m-has-pill>button{position:relative;z-index:1;transition:color var(--m-180) ease,background-color var(--m-180) ease,transform var(--m-240) var(--m-out)}
nav.m-has-pill>button.active{background:transparent;border-color:transparent;box-shadow:none;transform:none}
nav.m-has-pill>button:not(.active):active{transform:scale(var(--m-press-sm));transition-duration:var(--m-80)}
@media(hover:none){nav.m-has-pill>button:hover{background:none}}
nav{transition:box-shadow var(--m-240) ease}
nav.m-scrolled{box-shadow:inset 0 1px 0 rgba(255,250,240,.3),inset 0 -1px 0 rgba(255,255,255,.035),0 14px 36px rgba(32,23,20,.42)}
/* Buttons, inputs, steppers I17–I24 */
.btn,.icon-btn,.ghost,.admin-btn,.category-filter,.stepper button{transition:transform var(--m-240) var(--m-out),filter var(--m-180) ease,box-shadow var(--m-240) ease,background-color var(--m-180) ease,border-color var(--m-180) ease,color var(--m-180) ease,opacity var(--m-180) ease}
@media(hover:hover){.btn:hover:not(:disabled):not(.loading),.icon-btn:hover:not(:disabled),.ghost:hover:not(:disabled){transform:translateY(var(--m-lift))}}
@media(hover:none){.btn:hover,.icon-btn:hover,.ghost:hover{transform:none;filter:none;box-shadow:inset 0 1px 0 rgba(255,255,255,.42),inset 0 -1px 0 rgba(255,255,255,.05),0 8px 20px rgba(0,13,60,.2)}.category-filter:hover:not([aria-pressed="true"]){background:transparent}}
.btn:active:not(:disabled):not(.loading),.ghost:active:not(:disabled),.admin-btn:active:not(:disabled),.category-filter:active{transform:scale(var(--m-press));transition-duration:var(--m-80);filter:brightness(.96)}
.icon-btn:active:not(:disabled),.stepper button:active:not(:disabled){transform:scale(var(--m-press-sm));transition-duration:var(--m-80)}
.btn:disabled,.icon-btn:disabled,.btn.loading{transform:none}
.btn.loading:after,.icon-btn.loading:after{animation:btn-spin .7s linear infinite,m-fade var(--m-180) ease-out both}
input,select,textarea{transition:border-color var(--m-180) ease,box-shadow var(--m-240) var(--m-out),background-color var(--m-180) ease}
input[type=checkbox],.available-filter input{transition:none}
.stepper b{display:inline-block;min-width:1.2em;text-align:center}
.stepper b.m-bump{animation:m-bump var(--m-240) var(--m-out)}
.selected-item.m-rise-once{animation:m-rise var(--m-320) var(--m-out) both}
/* Modals I25–I29 */
#modal-root>.modal.m-in{animation:m-fade var(--m-240) ease-out both}
#modal-root>.modal.m-in>.modal-box{animation:m-sheet-in var(--m-420) var(--m-sheet) both}
#modal-root>.modal.m-swap>.modal-box{animation:m-xfade var(--m-240) var(--m-out) both}
#modal-root>.modal.m-out{animation:m-undim var(--m-180) var(--m-in) both;pointer-events:none}
#modal-root>.modal.m-out>.modal-box{animation:m-sheet-out var(--m-180) var(--m-in) both}
#modal-root>.modal:not(.m-settled) .notice-item:nth-child(-n+6){animation:m-rise-sm var(--m-240) var(--m-out) both;animation-delay:calc(var(--m-stagger)*var(--m-i,0))}
#notification-list>:nth-child(2){--m-i:1}
#notification-list>:nth-child(3){--m-i:2}
#notification-list>:nth-child(4){--m-i:3}
#notification-list>:nth-child(5){--m-i:4}
#notification-list>:nth-child(6){--m-i:5}
#modal-root>.modal:not(.m-settled) [data-report-photo],#return-preview>img{animation:m-fade var(--m-320) ease-out both}
body>.modal.m-alert.m-in{animation:m-fade var(--m-240) ease-out both}
body>.modal.m-alert.m-in>.modal-box{animation:m-alert-in var(--m-320) var(--m-pop) both}
body>.modal.m-alert.m-out{animation:m-undim var(--m-120) var(--m-in) both;pointer-events:none}
body>.modal.m-alert.m-out>.modal-box{animation:m-alert-out var(--m-120) ease-in both}
/* Toast & badge I30–I31 */
#toast.toast:not([role]){transform:translate(-50%,var(--m-toast-y)) scale(var(--m-toast-scale));transition:opacity var(--m-180) var(--m-in),transform var(--m-240) var(--m-in)}
#toast.toast:not([role]).show{transform:translate(-50%,0) scale(1);transition:opacity var(--m-180) ease-out,transform var(--m-420) var(--m-spring)}
#notice-dot{display:inline-block;transform-origin:center}
#notice-dot.m-pop{animation:m-pop var(--m-420) var(--m-spring)}
#notice-dot.m-bump{animation:m-bump var(--m-320) var(--m-out)}

/* ===== 5. app/index.html ===== */
/* A1–A3 login */
#login-panel.m-in>.dialog-form{animation:m-sheet-in var(--m-520) var(--m-out) both;animation-delay:80ms}
#login-panel .dialog-form.m-shake{animation:m-shake var(--m-420) var(--m-inout)}
#login-panel.m-in>.dialog-form.m-shake{animation:m-sheet-in var(--m-520) var(--m-out) both,m-shake var(--m-420) var(--m-inout);animation-delay:80ms,0ms}
.form-error:not([hidden]){animation:m-rise-sm var(--m-240) var(--m-out) both}
/* A4 shell */
#app-shell.m-in>.site-header{animation:m-rise var(--m-420) var(--m-out) both}
#app-shell.m-in>main>.intro{animation:m-rise var(--m-420) var(--m-out) both;animation-delay:calc(var(--m-stagger)*1)}
#app-shell.m-in>main>.admin-bar,#app-shell.m-in>main>.catalog>.toolbar{animation:m-rise var(--m-420) var(--m-out) both;animation-delay:calc(var(--m-stagger)*2)}
#app-shell.m-in>main>.catalog>.list-heading{animation:m-fade var(--m-320) var(--m-out) both;animation-delay:calc(var(--m-stagger)*3)}
/* A5 grid fill (tối đa 9 thẻ) */
.app-grid.m-fill>.app-card{animation:m-rise var(--m-420) var(--m-out) both;animation-delay:calc(160ms + var(--m-stagger)*var(--m-i,0))}
.app-grid.m-fill>.app-card:nth-child(2){--m-i:1}
.app-grid.m-fill>.app-card:nth-child(3){--m-i:2}
.app-grid.m-fill>.app-card:nth-child(4){--m-i:3}
.app-grid.m-fill>.app-card:nth-child(5){--m-i:4}
.app-grid.m-fill>.app-card:nth-child(6){--m-i:5}
.app-grid.m-fill>.app-card:nth-child(7){--m-i:6}
.app-grid.m-fill>.app-card:nth-child(8){--m-i:7}
.app-grid.m-fill>.app-card:nth-child(9){--m-i:8}
.app-grid.m-fill>.app-card:nth-child(n+10){animation:none}
/* A6–A10 cards, buttons, inputs */
.app-card{transition:transform var(--m-320) var(--m-out),box-shadow var(--m-320) ease}
@media(hover:none){.app-card:hover{transform:none;box-shadow:var(--glass-shadow)}}
.primary-button,.secondary-button,.danger-button,.download-link,.categories button,.card-admin button,.empty-state button,.close-dialog,.image-preview button,.toast button{transition:transform var(--m-240) var(--m-out),background-color var(--m-180) ease,color var(--m-180) ease,border-color var(--m-180) ease,filter var(--m-180) ease,box-shadow var(--m-240) ease,opacity var(--m-180) ease}
@media(hover:hover){.download-link:hover,.primary-button:hover:not(:disabled),.empty-state button:hover{transform:translateY(var(--m-lift))}}
@media(hover:none){.download-link:hover,.primary-button:hover,.empty-state button:hover{filter:none}.secondary-button:hover,.card-admin button:not(:last-child):hover{background:linear-gradient(145deg,rgba(255,245,230,.17),rgba(255,255,255,.065))}.categories button:hover:not([aria-pressed=true]){background:transparent;color:var(--muted)}}
.primary-button:active:not(:disabled),.secondary-button:active:not(:disabled),.danger-button:active:not(:disabled),.download-link:active,.categories button:active,.card-admin button:active,.empty-state button:active,.toast button:active{transform:scale(var(--m-press));transition-duration:var(--m-80)}
.close-dialog:active,.image-preview button:active{transform:scale(var(--m-press-sm));transition-duration:var(--m-80)}
.search{transition:box-shadow var(--m-240) var(--m-out),border-color var(--m-180) ease}
.dialog-form input,.dialog-form textarea,.dialog-form select{transition:border-color var(--m-180) ease,box-shadow var(--m-240) var(--m-out)}
/* A11–A12 toast, trạng thái */
#toast.toast[role=status]:not([hidden]){animation:m-toast-in var(--m-420) var(--m-spring) both}   /* chỉ toast /app (role=status, dùng hidden); toast / dùng .show + opacity */
#empty-state:not([hidden]),#load-error:not([hidden]),#image-preview-box:not([hidden]){animation:m-rise-sm var(--m-240) var(--m-out) both}

/* ===== 6. 2FA/index.html (CSP style-src 'self' — mọi rule nằm ở đây) ===== */
/* T1 page load */
.twofa-card{animation:m-sheet-in var(--m-520) var(--m-out) both}
.twofa-brand{animation:m-fade var(--m-520) var(--m-out) both;animation-delay:80ms}
/* T2–T3 login / content reveal */
#login.m-in{animation:m-rise var(--m-320) var(--m-out) both}
#content.m-in>*{animation:m-rise var(--m-320) var(--m-out) both;animation-delay:calc(var(--m-stagger)*var(--m-i,0))}
#content.m-in>:nth-child(2){--m-i:1}
#content.m-in>:nth-child(3){--m-i:2}
#content.m-in>:nth-child(4){--m-i:3}
/* T4 login shake */
#login-form.twofa-form.m-shake{animation:m-shake var(--m-420) var(--m-inout)}   /* scope /2FA: không đè I2 .login-box.m-shake trên / */
/* T5 code reveal / clear */
.twofa-code.m-reveal{animation:m-code-in var(--m-520) var(--m-out) both}
.twofa-code.m-clear{animation:m-code-clear var(--m-240) ease-out both}
/* T6 buttons */
.twofa-primary,.twofa-copy,.twofa-link-button,.twofa-setup summary,.twofa-back{transition:transform var(--m-240) var(--m-out),opacity var(--m-240) ease,filter var(--m-180) ease,background-color var(--m-180) ease,color var(--m-180) ease}
.twofa-primary:active:not(:disabled),.twofa-copy:active:not(:disabled){transform:scale(var(--m-press));transition-duration:var(--m-80)}
.twofa-link-button:active{transform:scale(var(--m-press-sm));transition-duration:var(--m-80)}
@media(hover:hover){.twofa-primary:hover:not(:disabled){filter:brightness(1.06)}}
/* T7 copy pop */
.twofa-copy.m-bump{animation:m-bump-sm var(--m-240) var(--m-out)}
/* T8 status + inputs */
.twofa-status:not(:empty){animation:m-rise-sm var(--m-240) var(--m-out) both}
.twofa-form input{transition:border-color var(--m-180) ease,box-shadow var(--m-240) var(--m-out)}
/* T9 validity bar (--p qua style.setProperty) */
.m-code-progress{display:block;height:3px;margin:8px auto 10px;width:min(100%,220px);border-radius:2px;background:rgba(255,243,224,.12);overflow:hidden}
.m-code-progress>i{display:block;height:100%;background:linear-gradient(90deg,#f4d8aa,#c6aa86);transform-origin:0 50%;transform:scaleX(var(--p,0));transition:transform 1s linear}

/* ===== 7. Reduced-motion overrides ===== */
@media(prefers-reduced-motion:reduce){
  nav.m-has-pill>.m-nav-pill{transition:opacity var(--m-180) ease}
  .gmm-switcher-panel{animation:m-fade var(--m-120) ease-out both}
  #notice-dot.m-pop,#notice-dot.m-bump,.stepper b.m-bump,.twofa-copy.m-bump{animation:none}
  .m-code-progress>i{transition:none}
}
