/* Loading motion — skeleton shimmer, route progress, busy buttons and the sign-in handoff.
   Transform + opacity (and one background sweep) only. Every loop stops under prefers-reduced-motion: skeletons and busy indicators hold still at their resting tint. */

/* ---------- skeleton shimmer: one light sweep across the whole screen (fixed attachment keeps every bar in phase) ---------- */
.sk,.ska,.skq,.skd,.route-loading .route-loading-bar{
  background-color:var(--track);
  background-image:linear-gradient(100deg,transparent 30%,rgb(255 255 255/.75) 46%,rgb(124 188 240/.35) 50%,transparent 66%);
  background-size:200vw 100%;background-repeat:no-repeat;background-attachment:fixed;
  animation:sk-sweep 1.5s cubic-bezier(.4,0,.2,1) infinite}
.route-loading .route-loading-bar{opacity:1;color:transparent}
@keyframes sk-sweep{from{background-position:-200vw 0}to{background-position:200vw 0}}
/* the route shell's cards and rows settle in, one after another */
.route-loading-cards>.pane,.route-loading-content>.pane .route-loading-row,.ld-cards>.pane,.ld>.skc{animation:sk-rise 420ms cubic-bezier(.23,1,.32,1) both}
.route-loading-cards>.pane:nth-child(2),.ld-cards>.pane:nth-child(2){animation-delay:50ms}
.route-loading-cards>.pane:nth-child(3),.ld-cards>.pane:nth-child(3){animation-delay:100ms}
.route-loading-cards>.pane:nth-child(4),.ld-cards>.pane:nth-child(4){animation-delay:150ms}
.route-loading-row:nth-child(1),.ld>.skc:nth-child(1){animation-delay:140ms}
.route-loading-row:nth-child(2),.ld>.skc:nth-child(2){animation-delay:180ms}
.route-loading-row:nth-child(3),.ld>.skc:nth-child(3){animation-delay:220ms}
.route-loading-row:nth-child(4),.ld>.skc:nth-child(4){animation-delay:260ms}
.route-loading-row:nth-child(n+5),.ld>.skc:nth-child(n+5){animation-delay:300ms}
@keyframes sk-rise{from{opacity:0}to{opacity:1}}   /* no rise: loading placeholders appear in place (owner, 2026-10-13) */
/* the polite status line under a slow read */
.route-loading>[role=status]{font:var(--t-small);color:var(--ink-2);animation:sk-rise 300ms ease 600ms both}

/* ---------- route progress: a thin accent bar under the top edge while a page reads its data ---------- */
body::before{content:"";position:fixed;top:0;left:0;right:0;z-index:999;height:2px;pointer-events:none;
  background:linear-gradient(90deg,transparent,var(--accent) 30%,#7cbcf0 60%,transparent);
  transform:scaleX(0);transform-origin:0 50%;opacity:0;transition:opacity 260ms ease 80ms}
body:has(#page[data-loading=true])::before{opacity:1;transition-delay:0s;animation:route-progress 1.8s cubic-bezier(.2,.7,.3,1) infinite}
@keyframes route-progress{0%{transform:translateX(-30%) scaleX(.15)}60%{transform:translateX(40%) scaleX(.6)}100%{transform:translateX(110%) scaleX(.2)}}

/* ---------- busy buttons: a spinner leads the busy label (the width is already held by the page) ---------- */
.btn[aria-busy=true]::before,.bm-load:not([role=alert])::before{content:"";flex:none;width:12px;height:12px;border-radius:50%;
  border:1.75px solid currentColor;border-right-color:transparent;opacity:.85;animation:ld-spin 700ms linear infinite}
.btn[aria-busy=true]{cursor:progress}
.bm-load:not([role=alert]){display:flex;align-items:center;gap:8px;color:var(--ink-2)}
/* the sign-in handoff: the spinner becomes a check while the card makes way for the workspace */
.btn.is-done::before{content:"";flex:none;width:12px;height:7px;margin-top:-3px;border:0;border-left:2px solid currentColor;border-bottom:2px solid currentColor;
  border-radius:1px;transform:rotate(-45deg) scale(.4);opacity:0;animation:auth-check 260ms cubic-bezier(.34,1.56,.64,1) forwards}
@keyframes auth-check{to{transform:rotate(-45deg) scale(1);opacity:1}}
[data-page="access"] .px-card.is-leaving{animation:auth-leave 360ms cubic-bezier(.23,1,.32,1) 140ms forwards}
@keyframes auth-leave{to{opacity:0;transform:translateY(-8px) scale(.985)}}

/* ---------- access: the card and its parts arrive in a short cascade on first paint ---------- */
[data-page="access"] .px-card.is-arriving>*{animation:sk-rise 520ms cubic-bezier(.23,1,.32,1) both}
[data-page="access"] .px-card.is-arriving>:nth-child(2){animation-delay:60ms}
[data-page="access"] .px-card.is-arriving>:nth-child(3){animation-delay:110ms}
[data-page="access"] .px-card.is-arriving>:nth-child(n+4){animation-delay:160ms}
[data-page="access"] .px-panel.is-arriving{animation:auth-panel 620ms cubic-bezier(.23,1,.32,1) both}
@keyframes auth-panel{from{opacity:0;transform:translateX(16px) scale(.99)}to{opacity:1;transform:none}}

@media (prefers-reduced-motion:reduce){
  .sk,.ska,.skq,.skd,.route-loading .route-loading-bar{animation:none;background-image:none}
  .route-loading-cards>.pane,.route-loading-row,.ld-cards>.pane,.ld>.skc,
  [data-page="access"] .px-card.is-arriving>*,[data-page="access"] .px-panel.is-arriving{animation:ld-fade 150ms ease both}
  body:has(#page[data-loading=true])::before{animation:none;transform:none;opacity:.5}
  .btn[aria-busy=true]::before,.bm-load:not([role=alert])::before{animation:none}
  [data-page="access"] .px-card.is-leaving{animation:ld-out 150ms ease forwards}
  .route-loading>[role=status]{animation:ld-fade 150ms ease both}
  .btn.is-done::before{animation:none;transform:rotate(-45deg);opacity:1}
}
@keyframes ld-spin{to{transform:rotate(1turn)}}
@keyframes ld-fade{from{opacity:0}to{opacity:1}}
@keyframes ld-out{to{opacity:0}}

/* ---------- first screen: a spinner and nothing else while the workspace opens (app/landing-boot.js sets the class: recovery-landing on a reset link, startup-splash everywhere) ----------
   Ends when the first page is on screen (html[data-ready]). Applies to the startup/loading status panes only (role=status); a failure pane (role=alert) keeps its words and its reload button. */
html:is(.recovery-landing,.startup-splash):not([data-startup-failed="true"]):not([data-ready="true"]) #page>.live-state .state-view[role=status] .state-view-copy,
html:is(.recovery-landing,.startup-splash):not([data-startup-failed="true"]):not([data-ready="true"]) #page>.live-state .state-view[role=status] .state-view-actions{display:none}
html:is(.recovery-landing,.startup-splash):not([data-startup-failed="true"]):not([data-ready="true"]) #page>.live-state .state-view[role=status]::before{content:"";width:22px;height:22px;border-radius:50%;
  border:2px solid var(--hair-2);border-top-color:var(--accent);animation:ld-spin 700ms linear infinite}
html:is(.recovery-landing,.startup-splash):not([data-startup-failed="true"]):not([data-ready="true"]) #page>.live-state:has(.state-view[role=status]){min-height:100dvh}
html:is(.recovery-landing,.startup-splash):not([data-startup-failed="true"]):not([data-ready="true"]) #page>.live-state>.state-view[role=status]{min-height:inherit}
