/* Brooklyn City College digital campus: motion. Linked last.

   Contract: this sheet never sets a value you can see at rest. It only says how a change happens.
   Colours, fills, shapes and focus styles belong to portal.css, classroom.css and forms.css; what is
   here are transitions on the properties they set, and short keyframes that start from "not yet" and
   end on whatever those sheets declare. Where a fill has to travel, motion.js reads its colour and
   shape from the page as rendered. Delete this file and every state still works, instantly.

   What moves, and how:
   - Anything you can press eases between the states its own sheet gives it; pressed arrives fastest.
   - A selection inside a track (segmented tabs, the phone dock) slides to where you chose. In the
     sidebar, where items are grouped and far apart, it hands over: it fades where you were and fills
     where you are.
   - The frame stays and the content changes: on a real route change the content area dissolves in.
     Cards do not arrive one by one, and nothing moves because a render happened.
   - A completion mark lands. Changed text re-inks. Messages that answer you dissolve in place.
   - Overlays (dialog, toast) are the only things that travel: 8px up into place. They leave by fading.
   - One orchestrated moment: after sign-in the programme timeline is drawn, phase by phase, to Now.
   Three durations, two curves. One thing loops, and only while it is true: the arc in a busy button.
   Everything sits inside prefers-reduced-motion: no-preference, so reduced motion gets instant
   state changes only.

   motion.js sets short-lived flags on <html> for what CSS cannot see:
     data-m-enter            the first signed-in render after sign-in (1200ms)
     data-m-route            a render under a new hash, not a clock or action re-render (400ms)
     data-m-side="fwd|back"  the sidebar's current item changed (400ms); the item left carries data-m-left
     data-m-dock="fwd|back"  the dock's current item changed (400ms)
     data-m-tab="fwd|back"   a tab was chosen (400ms)
     data-m-thumb="tab|dock" a sliding fill has been measured; its geometry is in --m-thumb-* (400ms);
                             the item left carries data-m-left
     data-m-done="1|0"       a lesson was marked complete or not complete (700ms)
     data-m-check            a practice answer was checked (500ms)
     data-m-saved            typing in a draft paused (600ms)
     data-m-alert="a|b"      a form was submitted and still shows an error (alternates, stays) */
:root{
  --m-quick:120ms;  /* hover, press, anything leaving */
  --m-mark:180ms;   /* a selection filling in, a mark landing, content, a message or overlay arriving */
  --m-slow:240ms;   /* a change across a distance or a large area: a sliding fill, sign-in, poster to video */
  --m-out:cubic-bezier(.2,.7,.2,1);  /* arriving: quick start, soft landing */
  --m-in:cubic-bezier(.4,0,1,1);     /* leaving: gets out of the way */
  --m-rise:8px;     /* how far an overlay travels */
  --m-step:70ms;    /* the gap between phases when the timeline is drawn */
}

/* The poster veil is built by motion.js only when motion is allowed. Its geometry stays outside the
   media query so it can never render unstyled. */
.m-veil{position:absolute;inset:0;pointer-events:none}
.m-veil img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}

@media(prefers-reduced-motion:no-preference){

/* ---------- keyframes: each starts from "not yet" and ends on the declared style ---------- */
@keyframes m-select{from{background-color:transparent;color:inherit}}                     /* a selection fills in */
@keyframes m-leave{from{background-color:var(--m-sel-fill);color:var(--m-sel-ink)}}       /* the selection you left fades */
@keyframes m-leave-ink{from{color:var(--m-thumb-ink)}}                                     /* the label you left keeps its ink until the fill has gone */
@keyframes m-thumb{from{translate:var(--m-thumb-x0) var(--m-thumb-y0);width:var(--m-thumb-w0)}}  /* a fill slides along its track */
@keyframes m-ride{from{background-color:transparent;color:inherit}to{background-color:transparent}}  /* the chosen item lets the sliding fill show through */
@keyframes m-draw{from{clip-path:inset(0 100% 0 0)}to{clip-path:inset(0)}}                /* a bar is drawn from its start */
@keyframes m-land{from{opacity:0;scale:.6}}                                                /* a mark lands */
@keyframes m-reink{from{opacity:.3}}                                                       /* changed text re-inks */
@keyframes m-note-a{from{opacity:0}}                                                       /* a message dissolves in place */
@keyframes m-note-b{from{opacity:0}}                                                       /* same, second name so a repeat restarts it */
@keyframes m-arrive{from{opacity:0}}
@keyframes m-ring{from{outline-offset:0}}
@keyframes m-give-way{to{opacity:0;scale:.96}}
@keyframes m-turn{to{rotate:360deg}}

/* ---------- anything you can press ---------- */
a,button,summary,.cl-option,.choice-card{transition:background-color var(--m-quick) var(--m-out),color var(--m-quick) var(--m-out),border-color var(--m-quick) var(--m-out),box-shadow var(--m-quick) var(--m-out)}
/* The glyph cell forms.css builds inside a button inverts under the pointer; it eases with the body. */
.btn::before,.btn::after,.btn>.icon{transition:background-color var(--m-quick) var(--m-out),color var(--m-quick) var(--m-out)}
/* Pressed is the one state that should not wait: it arrives in half the time and releases at the usual pace. */
:is(a,button,summary):active{transition-duration:60ms}
/* Busy: forms.css puts the arc in the cell, this turns it. The only loop here; it stops with the state. */
.btn[aria-busy=true]::before,.btn[type=submit]:disabled:not([aria-busy=false])::before{animation:m-turn .8s linear infinite}
/* The focus ring opens outward from the edge of the control. It is fully visible from the first frame. */
:focus-visible:not([tabindex="-1"]){animation:m-ring var(--m-quick) var(--m-out)}
/* Fields: transitions only. forms.css owns every resting, focus, invalid and disabled value.
   A switch draws its thumb as a background, so its position is eased as well and the thumb slides. */
input,select,textarea{transition:border-color var(--m-quick) var(--m-out),box-shadow var(--m-quick) var(--m-out),background-color var(--m-quick) var(--m-out)}
input[role=switch]{transition:border-color var(--m-quick) var(--m-out),box-shadow var(--m-quick) var(--m-out),background-color var(--m-mark) var(--m-out),background-position var(--m-mark) var(--m-out)}

/* ---------- rows ---------- */
/* A row eases its fill through the rule above. Its chevron leans the way the row goes, further while
   the row is held. The round icon chip follows its row's state at the same pace. */
.chev,.back-link .icon{transition:translate var(--m-quick) var(--m-out),transform var(--m-mark) var(--m-out)}
.row-icon{transition:background-color var(--m-quick) var(--m-out),color var(--m-quick) var(--m-out)}
@media(hover:hover){
  li>a:hover .chev{translate:3px 0}
  .back-link:hover .icon{translate:-3px 0}
}
li>a:focus-visible .chev{translate:3px 0}
li>a:active .chev{translate:5px 0}
.back-link:focus-visible .icon{translate:-3px 0}
.back-link:active .icon{translate:-5px 0}

/* ---------- selection ---------- */
/* Inside a track the fill slides. motion.js measures where it was and where it is, and takes its
   colour and corner from the chosen item, so the travelling fill is the track's own, whatever it
   looks like. While it travels the chosen item shows it through; when the flag clears the item's
   own fill is in exactly the same place. */
html[data-m-thumb=tab] :is(.cl-tabs,.subnav){position:relative}
html[data-m-thumb=tab] :is(.cl-tabs,.subnav)::before,
html[data-m-thumb=dock] .mobile-dock::before{content:"";position:absolute;z-index:0;left:0;top:0;width:var(--m-thumb-w);height:var(--m-thumb-h);border-radius:var(--m-thumb-r);background:var(--m-thumb-fill);translate:var(--m-thumb-x) var(--m-thumb-y);pointer-events:none;animation:m-thumb var(--m-slow) var(--m-out) backwards}
html[data-m-thumb=tab] :is(.cl-tabs,.subnav)>*,
html[data-m-thumb=dock] .mobile-dock>*{position:relative;z-index:1}
html[data-m-thumb=tab] :is(.cl-tabs,.subnav)>[aria-pressed=true],
html[data-m-thumb=dock] .mobile-dock>[aria-current]{animation:m-ride var(--m-slow) var(--m-out) both}
html[data-m-thumb] :is(.cl-tabs,.subnav,.mobile-dock)>[data-m-left]{animation:m-leave-ink var(--m-quick) var(--m-out)}
/* If the fill could not be measured, the chosen item simply fills in. */
html[data-m-tab]:not([data-m-thumb]) :is(.cl-tabs,.subnav)>[aria-pressed=true],
html[data-m-dock]:not([data-m-thumb]) .mobile-dock>[aria-current]{animation:m-select var(--m-mark) var(--m-out)}
/* Sidebar: hand over. */
html[data-m-side] .side-nav a[aria-current]{animation:m-select var(--m-mark) var(--m-out)}
html[data-m-side] .side-nav a[data-m-left]{animation:m-leave var(--m-quick) var(--m-in)}

/* ---------- content on a real route change ---------- */
/* The sidebar, top bar and dock stay put; the content area dissolves in as one sheet. No travel. */
html[data-m-route] .main{animation:m-arrive var(--m-mark) var(--m-out)}

/* ---------- completion ---------- */
/* The mark on a lesson eases its ink when it changes in place, and lands once when the lesson is
   marked complete, in the button and on the lesson's row. The count beside it, and the save line
   under a draft, re-ink when they become true. */
[data-cl-status]{transition:color var(--m-mark) var(--m-out),background-color var(--m-mark) var(--m-out)}
html[data-m-done="1"] .cl-complete>:first-child,html[data-m-done="1"] .is-current [data-cl-status]{animation:m-land var(--m-mark) var(--m-out)}
html[data-m-done] #cl-course-progress,html[data-m-saved] #cl-save-status{animation:m-reink var(--m-slow) var(--m-out)}

/* ---------- messages that answer you ---------- */
.error,.cl-video-error,#modal-status.notice,[data-capslock-for]{animation:m-note-a var(--m-mark) var(--m-out)}
html[data-m-alert=b] .error{animation-name:m-note-b}
html[data-m-check] .cl-feedback{animation:m-note-a var(--m-mark) var(--m-out)}

/* ---------- overlays: up into place, fade to leave ---------- */
#toast{transition:opacity var(--m-quick) var(--m-in),transform 0s linear var(--m-quick)}
#toast.visible{transition:opacity var(--m-mark) var(--m-out),transform var(--m-mark) var(--m-out)}
/* app.js empties the toast when a dialog opens. An empty toast goes at once instead of fading as a blank shape. */
#toast:empty{transition:none}
dialog#modal{opacity:0;translate:0 var(--m-rise);transition:opacity var(--m-quick) var(--m-in),translate 0s linear var(--m-quick),overlay var(--m-quick) allow-discrete,display var(--m-quick) allow-discrete}
dialog#modal[open]{opacity:1;translate:none;transition:opacity var(--m-mark) var(--m-out),translate var(--m-mark) var(--m-out),overlay var(--m-mark) allow-discrete,display var(--m-mark) allow-discrete}
dialog#modal:not([open]){pointer-events:none}
/* The backdrop keeps the colour the system sheet gives it and fades as a whole. */
dialog#modal::backdrop{opacity:0;transition:opacity 120ms cubic-bezier(.4,0,1,1),overlay 120ms allow-discrete,display 120ms allow-discrete}
dialog#modal[open]::backdrop{opacity:1;transition:opacity 240ms cubic-bezier(.2,.7,.2,1),overlay 240ms allow-discrete,display 240ms allow-discrete}
@starting-style{
  dialog#modal[open]{opacity:0;translate:0 var(--m-rise)}
  dialog#modal[open]::backdrop{opacity:0}
}

/* ---------- disclosures ---------- */
@supports selector(::details-content){
  details{interpolate-size:allow-keywords}
  details::details-content{block-size:0;overflow-y:clip;opacity:0;transition:block-size var(--m-mark) var(--m-out),opacity var(--m-mark) var(--m-out),content-visibility var(--m-mark) allow-discrete}
  details[open]::details-content{block-size:auto;opacity:1}
}

/* ---------- Play: the button gives way, then the poster dissolves into the picture ---------- */
.m-veil img{transition:opacity var(--m-slow) ease-in-out}
.m-veil.is-lifting img{opacity:0}
.m-veil .cl-play{animation:m-give-way var(--m-quick) var(--m-in) forwards}

/* ---------- sign-in, and the one orchestrated moment ---------- */
/* Leaving: app.js holds "Signing in…" for 350ms and the view dissolves inside that wait.
   Arriving: the shell dissolves in once, as one sheet. Then the programme timeline is drawn from its
   first phase to its last, each bar from its own start with its dates, and the Now label lands on
   the phase the student is in. It happens once per sign-in, never on a later visit to the page. */
.signin{transition:opacity var(--m-slow) var(--m-in) 60ms}
.signin:has(#login-form [type=submit]:disabled){opacity:0}
html[data-m-enter] #app{animation:m-arrive var(--m-slow) var(--m-out)}
html[data-m-enter] .plan-bar{animation:m-draw var(--m-slow) var(--m-out) backwards;animation-delay:calc(200ms + var(--m-i,0)*var(--m-step))}
html[data-m-enter] .plan-dates{animation:m-arrive var(--m-mark) var(--m-out) backwards;animation-delay:calc(200ms + var(--m-i,0)*var(--m-step))}
html[data-m-enter] .plan-now{animation:m-land var(--m-mark) var(--m-out) backwards;animation-delay:calc(360ms + var(--m-i,0)*var(--m-step))}
.plan-phase:nth-child(2){--m-i:1}
.plan-phase:nth-child(3){--m-i:2}
.plan-phase:nth-child(4){--m-i:3}
.plan-phase:nth-child(5){--m-i:4}
.plan-phase:nth-child(6){--m-i:5}
.plan-phase:nth-child(7){--m-i:6}
.plan-phase:nth-child(8){--m-i:7}

}
