/* Shared motion contract. Keep theme colors in the existing theme stylesheets. */
:root {
    --motion-press: 90ms;
    --motion-state: 140ms;
    --motion-panel: 180ms;
    --motion-marketing: 320ms;
    --motion-distance: 4px;
    --motion-ease: cubic-bezier(.2, 0, .2, 1);
}
body :is(.btn, .page-link, .nav-link, .dropdown-item, .form-check-input) {
    transition: color var(--motion-state) var(--motion-ease), background-color var(--motion-state) var(--motion-ease), border-color var(--motion-state) var(--motion-ease);
}
body .btn:active { transition-duration: var(--motion-press); }
body :is(.form-control, .form-select) {
    transition: border-color var(--motion-state) var(--motion-ease), background-color var(--motion-state) var(--motion-ease);
}
/* Focus is immediate, including the Bootstrap field focus ring. */
body :is(button, a, input, select, textarea, summary, [tabindex]):focus-visible {
    transition-duration: 0s;
    outline: 3px solid var(--ui-focus, #1d4ed8);
    outline-offset: 3px;
}
body .fade { transition: opacity var(--motion-state) var(--motion-ease); }
body .modal.fade .modal-dialog {
    transform: scale(.99);
    transition: transform var(--motion-panel) var(--motion-ease);
}
body .modal.show .modal-dialog { transform: none; }
body .modal-backdrop, body .offcanvas-backdrop { transition-duration: var(--motion-panel); }
body .offcanvas { --bs-offcanvas-transition: transform var(--motion-panel) var(--motion-ease); }
body .collapsing { transition: height var(--motion-panel) var(--motion-ease); }
body .collapsing.collapse-horizontal { transition-property: width; }
body .accordion-button::after { transition: transform var(--motion-panel) var(--motion-ease); }
/* Bootstrap owns visibility, placement, keyboard handling and dismissal. The
   individual translate property leaves Popper's positioning transform intact. */
body .dropdown-menu.show, .nav.is-open .links {
    animation: motion-menu-enter var(--motion-panel) var(--motion-ease);
}
body .tab-pane.fade { transition-duration: var(--motion-state); }
.register-panel.is-active { animation: motion-content-enter var(--motion-state) var(--motion-ease); }
dialog[open] { animation: motion-panel-enter var(--motion-panel) var(--motion-ease); }
dialog[open]::backdrop { animation: motion-backdrop-enter var(--motion-panel) var(--motion-ease); }
/* Native details stays functional without JS. Supporting browsers interpolate
   intrinsic height; others switch immediately, with no fixed-height clipping. */
@supports (interpolate-size: allow-keywords) and (transition-behavior: allow-discrete) {
    details:not(.tutorial-step, .tutorial-transcript)::details-content {
        interpolate-size: allow-keywords;
        block-size: 0;
        overflow: clip;
        transition: block-size var(--motion-panel) var(--motion-ease), content-visibility var(--motion-panel) allow-discrete;
    }
    details:not(.tutorial-step, .tutorial-transcript)[open]::details-content {
        block-size: auto;
        /* Open content must not clip focus rings or positioned menus. */
        overflow: visible;
    }
}
/* Opt-in only: static marketing cards and the hero never move. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
    a.landing-card { transition: translate var(--motion-state) var(--motion-ease); }
    a.landing-card:hover { translate: 0 -2px; }
}
@keyframes motion-menu-enter {
    from { opacity: .65; translate: 0 calc(-1 * var(--motion-distance)); }
    to { opacity: 1; translate: 0 0; }
}
@keyframes motion-panel-enter {
    from { opacity: .65; scale: .99; }
    to { opacity: 1; scale: 1; }
}
@keyframes motion-backdrop-enter { from { opacity: 0; } to { opacity: 1; } }
@keyframes motion-content-enter { from { opacity: .8; } to { opacity: 1; } }
/* Legacy attendance welcomes become a compact, dismissible corner message. */
.attendance-display-welcome {
    inset: auto 1rem 1rem auto;
    width: min(30rem, calc(100vw - 2rem));
    padding: 0;
    background: none;
}
.attendance-display-welcome-card {
    grid-template-columns: 3rem minmax(0, 1fr);
    gap: .75rem;
    padding: 1rem;
    max-height: 40vh;
}
.attendance-display-welcome-copy h2 { font-size: 1.25rem; }
.attendance-display-welcome-copy p, .attendance-display-welcome-exam { font-size: 1rem; }
/* A busy label can wrap naturally in every locale, without swapping its width. */
.motion-busy-label { display: inline-grid; }
.motion-busy-label > span { grid-area: 1 / 1; }
.motion-busy-label > [aria-hidden="true"] { visibility: hidden; }
.motion-busy-icon { display: inline-grid; width: 1em; height: 1em; vertical-align: -.125em; margin-inline-end: .5em; }
.motion-busy-icon > * { grid-area: 1 / 1; margin: 0 !important; }
@media (prefers-reduced-motion: reduce) {
    :root { --motion-press: 0ms; --motion-state: 0ms; --motion-panel: 0ms; --motion-marketing: 0ms; }
    *, *::before, *::after, details::details-content {
        scroll-behavior: auto !important;
        transition-duration: 0s !important;
        transition-delay: 0s !important;
        animation: none !important;
    }
    body .modal.fade .modal-dialog { transform: none; }
}
