/* =====================================================================
   Tongue — motion language
   ---------------------------------------------------------------------
   One vocabulary of movement for the public website, the dashboards,
   Messages and the live classroom. Loaded after the area stylesheet.

   What motion is for here: hierarchy (what to read first), state
   (open, closed, done, unread), feedback (pressed, sending, saved),
   progress (roadmap, bars, counts) and depth (what floats above what).
   Nothing loops for decoration, nothing bounces, nothing slows a click.

   Rules of the system
   - Only transform and opacity move. No width/height/top/left animation.
   - Timing: micro 140ms · UI 220ms · cards 280ms · page 260ms · hero 700ms.
   - Entrances ease out (--m-out); state changes use --m-ease.
   - Everything in this file sits under (prefers-reduced-motion: no-preference).
     With reduced motion, states still change — they just do not travel.
   - Closing is animated with `transition-behavior: allow-discrete` on the
     [hidden] attribute, so the scripts stay untouched; a browser without it
     closes instantly, exactly as before.

   Vocabulary (keyframes)       Used for
   m-fade-in                    backdrops, quiet content swaps
   m-fade-up                    headings, text, list rows, tab panels
   m-fade-down                  alerts, field errors, accordion bodies
   m-slide-start / m-slide-end  editorial copy / visuals, drawer items
   m-scale-in                   large mockups, modals, cards
   m-pop                        badges, checks, counters (state changed)
   m-draw                       underlines and progress lines
   ===================================================================== */

:root {
    --m-ease: cubic-bezier(.2, .7, .2, 1);
    --m-out: cubic-bezier(.16, 1, .3, 1);
    --m-micro: 140ms;
    --m-ui: 220ms;
    --m-card: 280ms;
    --m-page: 260ms;
    --m-hero: 700ms;
    --m-x: -22px;            /* "from the start side"; flipped in RTL */
}
[dir="rtl"] { --m-x: 22px; }

@keyframes m-fade-in { from { opacity: 0; } }
@keyframes m-fade-up { from { opacity: 0; transform: translate3d(0, 14px, 0); } }
@keyframes m-fade-down { from { opacity: 0; transform: translate3d(0, -6px, 0); } }
@keyframes m-slide-start { from { opacity: 0; transform: translate3d(var(--m-x), 0, 0); } }
@keyframes m-slide-end { from { opacity: 0; transform: translate3d(calc(var(--m-x) * -1), 0, 0); } }
@keyframes m-scale-in { from { opacity: 0; transform: translate3d(0, 22px, 0) scale(.965); } }
@keyframes m-card-in { from { opacity: 0; transform: translate3d(0, 16px, 0) scale(.985); } }
@keyframes m-pop { 0% { transform: scale(.6); opacity: 0; } 60% { transform: scale(1.08); opacity: 1; } 100% { transform: none; } }
@keyframes m-bump { 0% { transform: scale(.7); } 60% { transform: scale(1.12); } 100% { transform: none; } }
@keyframes m-draw { from { transform: scaleX(0); } }
@keyframes m-draw-y { from { transform: scaleY(0); } }
@keyframes m-ping { 0% { box-shadow: 0 0 0 0 rgba(240, 90, 151, .45); } 70%, 100% { box-shadow: 0 0 0 9px rgba(240, 90, 151, 0); } }
@keyframes m-mark { from { background-size: 0% 100%; } }
@keyframes m-parallax { from { transform: translate3d(0, 18px, 0); } to { transform: translate3d(0, -18px, 0); } }
@keyframes m-vt-out { to { opacity: 0; } }
@keyframes m-vt-in { from { opacity: 0; transform: translate3d(0, 6px, 0); } }

/* Numbers that count or change keep their width. */
.stat-value, .progress-label, [data-count] { font-variant-numeric: tabular-nums; }

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

    /* ================================================================
       1. PAGE TRANSITIONS — every navigation is a quick cross-fade
       ================================================================ */
    @view-transition { navigation: auto; }
    ::view-transition-old(root) { animation: m-vt-out 120ms ease-in both; }
    ::view-transition-new(root) { animation: m-vt-in var(--m-page) var(--m-out) both; }
    /* The frame of the app stays put: only the page inside it changes. */
    body.app .sidebar { view-transition-name: app-sidebar; }
    body.app .bottombar { view-transition-name: app-bottombar; }
    body.app .topbar { view-transition-name: app-topbar; }
    .site-header { view-transition-name: site-header; }
    ::view-transition-group(app-sidebar), ::view-transition-group(app-bottombar), ::view-transition-group(app-topbar), ::view-transition-group(site-header) { animation-duration: 0s; }
    ::view-transition-old(app-sidebar), ::view-transition-old(app-bottombar), ::view-transition-old(app-topbar) { display: none; }
    ::view-transition-new(app-sidebar), ::view-transition-new(app-bottombar), ::view-transition-new(app-topbar) { animation: none; }

    /* ================================================================
       2. APP SHELL
       ================================================================ */
    body.app .nav-link.is-active::before { transform-origin: center; animation: m-draw-y 320ms var(--m-out) backwards; }
    body.app .nav-link .icon { transition: transform var(--m-ui) var(--m-ease), color var(--m-ui), opacity var(--m-ui); }
    body.app .nav-link:hover .icon { transform: translate3d(1px, 0, 0) scale(1.06); }
    body.app .bottombar-link .icon { transition: transform var(--m-ui) var(--m-out), color var(--m-micro); }
    body.app .bottombar-link.is-active .icon { animation: m-pop 320ms var(--m-out) backwards; }
    /* a badge that appears or changes says so once */
    .nav-badge, .dot-badge { animation: m-pop 320ms var(--m-out) backwards; }
    .nav-badge.is-bumped, .dot-badge.is-bumped { animation: m-bump 320ms var(--m-out); }
    .badge { transition: background-color var(--m-ui), color var(--m-ui); }

    /* off-canvas sidebar (phones) and its scrim */
    body.app .sidebar-scrim { transition: opacity var(--m-ui) ease, display var(--m-ui) allow-discrete; }
    body.app .sidebar-scrim[hidden] { opacity: 0; }
    @starting-style { body.app .sidebar-scrim:not([hidden]) { opacity: 0; } }

    /* ================================================================
       3. OVERLAYS — open with the existing entrances, close with these
       ================================================================ */
    /* (scoped to the app: the public site has its own .drawer, driven by a class) */
    body.app .modal, body.app .drawer, body.app .palette {
        transition: opacity 180ms ease, display 180ms allow-discrete, overlay 180ms allow-discrete;
    }
    body.app .modal[hidden], body.app .drawer[hidden], body.app .palette[hidden] { opacity: 0; pointer-events: none; }
    body.app .modal-dialog, body.app .palette-dialog { transition: transform 180ms var(--m-ease); }
    body.app .modal[hidden] .modal-dialog, body.app .palette[hidden] .palette-dialog { transform: translate3d(0, 10px, 0) scale(.98); }
    body.app .drawer-panel { transition: transform var(--m-ui) var(--m-ease); }
    body.app .drawer[hidden] .drawer-panel { transform: translate3d(100%, 0, 0); }
    [dir="rtl"] body.app .drawer[hidden] .drawer-panel { transform: translate3d(-100%, 0, 0); }

    .dropdown-menu { transform-origin: top; transition: opacity 110ms ease, transform 110ms var(--m-ease), display 110ms allow-discrete; }
    .dropdown-menu[hidden] { opacity: 0; transform: translate3d(0, -4px, 0) scale(.98); pointer-events: none; }
    /* menu rows arrive just behind the menu itself */
    .dropdown-menu:not([hidden]) > * { animation: m-fade-up 200ms var(--m-out) backwards; }
    .dropdown-menu:not([hidden]) > :nth-child(2) { animation-delay: 20ms; }
    .dropdown-menu:not([hidden]) > :nth-child(3) { animation-delay: 40ms; }
    .dropdown-menu:not([hidden]) > :nth-child(4) { animation-delay: 60ms; }
    .dropdown-menu:not([hidden]) > :nth-child(n+5) { animation-delay: 80ms; }

    /* toasts: in from the edge, out the same way */
    .toast { animation: m-slide-end 260ms var(--m-out) backwards; }
    .toast.is-leaving { opacity: 0; transform: translate3d(calc(var(--m-x) * -.6), 0, 0) scale(.98); transition: opacity 200ms ease, transform 200ms var(--m-ease); }

    /* ================================================================
       4. APP COMPONENTS — feedback and state
       ================================================================ */
    /* buttons: a trailing icon leans the way the action goes */
    body.app .btn > .icon, body.app a > .icon, body.guest .btn > .icon { transition: transform var(--m-ui) var(--m-ease); }
    body.app .btn:hover > .icon:last-child:not(:only-child),
    body.app :is(.card-head, .card-foot, .section-title, .list-item, .attention-foot) a:hover > .icon:last-child:not(:only-child),
    body.app a.list-item:hover > .icon:last-child { transform: translate3d(3px, 0, 0); }
    [dir="rtl"] body.app .btn:hover > .icon:last-child:not(:only-child) { transform: translate3d(-3px, 0, 0); }
    body.app .btn:hover > .icon:first-child:not(:only-child) { transform: scale(1.08); }
    .btn.is-loading { transition: none; }

    /* cards and rows respond, but stay where they are */
    body.app .card, body.app .stat, body.app .attention-group { transition: box-shadow var(--m-card) var(--m-ease), border-color var(--m-card), transform var(--m-card) var(--m-ease); }
    body.app .table tbody tr { transition: background-color var(--m-micro); }
    body.app .session-time, body.app .level-chip, body.app .avatar { transition: transform var(--m-ui) var(--m-ease); }
    body.app a.session:hover .session-time, body.app .session:hover .session-time { transform: scale(1.04); }

    /* tabs: the panel that opens rises into place */
    [data-tab-panel]:not([hidden]) { animation: m-fade-up var(--m-card) var(--m-out) backwards; }
    body.app .tab { position: relative; }

    /* switches, checkboxes, radios */
    .switch span::after { transition: transform var(--m-ui) var(--m-out), width var(--m-micro); }
    .switch:active span::after { width: 22px; }
    input[type="checkbox"], input[type="radio"] { transition: transform var(--m-micro) var(--m-ease); }
    input[type="checkbox"]:active, input[type="radio"]:active { transform: scale(.88); }
    .segmented span { transition: background-color var(--m-ui), color var(--m-ui), box-shadow var(--m-ui); }

    /* forms: errors and notices arrive, they do not blink */
    .field-error { animation: m-fade-down var(--m-ui) var(--m-out) backwards; }
    body.app .alert, body.guest .alert { animation: m-fade-down 260ms var(--m-out) backwards; }
    .input, .select, .textarea { transition: border-color var(--m-ui), box-shadow var(--m-ui), background-color var(--m-ui); }

    /* empty states: icon first, then the words */
    .empty .empty-icon { animation: m-scale-in 420ms var(--m-out) backwards; }
    .empty h3 { animation: m-fade-up 420ms var(--m-out) 70ms backwards; }
    .empty p { animation: m-fade-up 420ms var(--m-out) 120ms backwards; }
    .empty .btn { animation: m-fade-up 420ms var(--m-out) 170ms backwards; }

    /* notifications list */
    .notif-item { transition: background-color var(--m-ui); }

    /* ================================================================
       5. DASHBOARDS, PROGRESS, ROADMAP
       ================================================================ */
    /* the next action lands first, its button last */
    body.app .hero .hero-kicker { animation: m-fade-up 420ms var(--m-out) 60ms backwards; }
    body.app .hero h2 { animation: m-fade-up 460ms var(--m-out) 110ms backwards; }
    body.app .hero .hero-meta { animation: m-fade-up 460ms var(--m-out) 170ms backwards; }
    body.app .hero .btn { animation: m-fade-up 460ms var(--m-out) 230ms backwards; }

    /* figures arrive one after another */
    body.app .grid-4 > .stat { animation: m-card-in 420ms var(--m-out) backwards; }
    body.app .grid-4 > .stat:nth-child(2) { animation-delay: 50ms; }
    body.app .grid-4 > .stat:nth-child(3) { animation-delay: 100ms; }
    body.app .grid-4 > .stat:nth-child(4) { animation-delay: 150ms; }

    /* roadmap: stages open in order, done items tick, the current step is marked */
    body.app .check-item.is-done .check-box .icon { animation: m-pop 300ms var(--m-out) backwards; }
    body.app .check-item { transition: background-color var(--m-ui); }
    body.app .check-item .check-title { transition: color var(--m-ui); }
    body.app .stu-step { transition: border-color var(--m-card), box-shadow var(--m-card), transform var(--m-card) var(--m-ease); animation: m-card-in 420ms var(--m-out) backwards; }
    body.app .stu-step:nth-child(2) { animation-delay: 70ms; }
    body.app .stu-step:nth-child(3) { animation-delay: 140ms; }
    body.app .stu-step.is-done .stu-step-mark .icon { animation: m-pop 320ms var(--m-out) 200ms backwards; }

    /* ================================================================
       6. PUBLIC WEBSITE
       ================================================================ */

    /* inner pages: the head reads itself in — eyebrow, title, lead, actions */
    body.is-inner .page-head > .wrap > *, body.is-inner .page-head .page-head-split > :first-child > * { animation: m-fade-up 560ms var(--m-out) backwards; }
    body.is-inner .page-head > .wrap > :nth-child(2), body.is-inner .page-head .page-head-split > :first-child > :nth-child(2) { animation-delay: 70ms; }
    body.is-inner .page-head > .wrap > :nth-child(3), body.is-inner .page-head .page-head-split > :first-child > :nth-child(3) { animation-delay: 130ms; }
    body.is-inner .page-head > .wrap > :nth-child(n+4), body.is-inner .page-head .page-head-split > :first-child > :nth-child(n+4) { animation-delay: 190ms; }
    body.is-inner .page-head-code { animation: m-fade-in 900ms ease 200ms backwards; }

    /* scroll reveals: one family, four gestures.
       text blocks read in line by line · copy slides from its side ·
       mockups scale up · cards rise in sequence */
    .js :is(.section-head, .editorial-head, .sub-head, .feature-copy)[data-reveal].is-in { animation: none; }
    .js :is(.section-head, .editorial-head, .sub-head)[data-reveal].is-in > * { animation: m-fade-up 620ms var(--m-out) backwards; animation-delay: calc(var(--d, 0) * 70ms); }
    .js .feature-copy[data-reveal].is-in > * { animation: m-slide-start 620ms var(--m-out) backwards; animation-delay: calc(var(--d, 0) * 70ms); }
    .js :is(.section-head, .editorial-head, .sub-head, .feature-copy)[data-reveal].is-in > :nth-child(2) { animation-delay: calc(var(--d, 0) * 70ms + 80ms); }
    .js :is(.section-head, .editorial-head, .sub-head, .feature-copy)[data-reveal].is-in > :nth-child(3) { animation-delay: calc(var(--d, 0) * 70ms + 150ms); }
    .js :is(.section-head, .editorial-head, .sub-head, .feature-copy)[data-reveal].is-in > :nth-child(4) { animation-delay: calc(var(--d, 0) * 70ms + 210ms); }
    .js :is(.section-head, .editorial-head, .sub-head, .feature-copy)[data-reveal].is-in > :nth-child(n+5) { animation-delay: calc(var(--d, 0) * 70ms + 260ms); }

    .js .mock-figure[data-reveal].is-in { animation: m-scale-in 820ms var(--m-out) backwards; animation-delay: calc(var(--d, 0) * 70ms); }
    .js .feature-visual[data-reveal].is-in { animation-name: m-slide-end; animation-duration: 760ms; }
    .js :is(.program, .card, .bento-cell, .group-card, .person-card, .type-card, .level-row)[data-reveal].is-in { animation: m-card-in 560ms var(--m-out) backwards; animation-delay: calc(var(--d, 0) * 80ms); }
    .js :is(.type-strip, .faq-list)[data-reveal].is-in { animation: m-fade-in 700ms ease backwards; }
    .js .faq-list[data-reveal].is-in > * { animation: m-fade-up 480ms var(--m-out) backwards; }
    .js .faq-list[data-reveal].is-in > :nth-child(2) { animation-delay: 50ms; }
    .js .faq-list[data-reveal].is-in > :nth-child(3) { animation-delay: 100ms; }
    .js .faq-list[data-reveal].is-in > :nth-child(4) { animation-delay: 150ms; }
    .js .faq-list[data-reveal].is-in > :nth-child(n+5) { animation-delay: 200ms; }

    /* FAQ: the answer unfolds under its question */
    .faq-item[open] > :not(summary) { animation: m-fade-down 260ms var(--m-out) backwards; }
    .faq-item summary i::after { transition: transform var(--m-ui) var(--m-ease), background-color var(--m-ui); }
    .faq-item[open] summary i::after { transform: rotate(0deg); }

    /* drawer: links follow the panel in */
    .drawer.is-open .drawer-nav li, .drawer:target .drawer-nav li { animation: m-slide-end 360ms var(--m-out) backwards; animation-delay: 90ms; }
    .drawer.is-open .drawer-nav li:nth-child(2), .drawer:target .drawer-nav li:nth-child(2) { animation-delay: 125ms; }
    .drawer.is-open .drawer-nav li:nth-child(3), .drawer:target .drawer-nav li:nth-child(3) { animation-delay: 160ms; }
    .drawer.is-open .drawer-nav li:nth-child(4), .drawer:target .drawer-nav li:nth-child(4) { animation-delay: 195ms; }
    .drawer.is-open .drawer-nav li:nth-child(5), .drawer:target .drawer-nav li:nth-child(5) { animation-delay: 230ms; }
    .drawer.is-open .drawer-nav li:nth-child(6), .drawer:target .drawer-nav li:nth-child(6) { animation-delay: 265ms; }
    .drawer.is-open .drawer-nav li:nth-child(n+7), .drawer:target .drawer-nav li:nth-child(n+7) { animation-delay: 300ms; }
    .drawer.is-open :is(.drawer-meta, .drawer-foot), .drawer:target :is(.drawer-meta, .drawer-foot) { animation: m-fade-up 420ms var(--m-out) 260ms backwards; }

    /* public buttons while a form is being sent */
    :is(body.is-home, body.is-inner) .btn.is-loading { position: relative; color: transparent !important; pointer-events: none; }
    :is(body.is-home, body.is-inner) .btn.is-loading::after { content: ""; position: absolute; inset: 50% auto auto 50%; width: 18px; height: 18px; margin: -9px 0 0 -9px; border-radius: 50%; border: 2px solid rgba(4, 27, 45, .25); border-top-color: var(--navy-950, #041B2D); animation: m-spin 700ms linear infinite; }

    /* footer links */
    .site-footer a { transition: color var(--m-ui), opacity var(--m-ui); }

    /* depth on scroll: large mockups drift a few pixels against the page.
       Driven by the scroll position itself (no script, runs on the compositor);
       desktop only, and only where the browser supports it. */
    @supports (animation-timeline: view()) {
        @media (min-width: 1040px) and (hover: hover) {
            .mock-figure[data-reveal] > :not(figcaption) { animation: m-parallax linear both; animation-timeline: view(); animation-range: entry 0% exit 100%; }
        }
    }

    /* ================================================================
       7. LIVE CLASSROOM — panels and menus close as calmly as they open.
       Video elements are never animated.
       ================================================================ */
    .cr .cr-panel { transition: opacity 180ms ease, transform 200ms var(--m-ease), display 200ms allow-discrete; }
    .cr .cr-panel[hidden] { opacity: 0; transform: translate3d(calc(var(--m-x) * -1), 0, 0); pointer-events: none; }
    .cr .cr-more { transition: opacity 140ms ease, display 140ms allow-discrete; }
    .cr .cr-more[hidden] { opacity: 0; pointer-events: none; }
    .cr .cr-overlay { transition: opacity 200ms ease, display 200ms allow-discrete; }
    .cr .cr-overlay[hidden] { opacity: 0; pointer-events: none; }
    .cr .cr-banner { transition: opacity 180ms ease, display 180ms allow-discrete; }
    .cr .cr-banner[hidden] { opacity: 0; }
}

@keyframes m-spin { to { transform: rotate(360deg); } }

/* Loops (typing dots, drifting cards, glows) stop while their block is off screen. */
.is-resting *, .is-resting *::before, .is-resting *::after { animation-play-state: paused !important; }

/* Phones: keep what explains state, drop what is only depth. */
@media (max-width: 640px) {
    .js .mock-figure[data-reveal].is-in, .js .feature-visual[data-reveal].is-in { animation-name: m-fade-up; animation-duration: 560ms; }
    .js .feature-copy[data-reveal].is-in > * { animation-name: m-fade-up; }
    .cr .cr-panel[hidden] { transform: translate3d(0, 24px, 0); }
    body.app .modal[hidden] .modal-dialog { transform: translate3d(0, 100%, 0); }
}

@media (prefers-reduced-motion: reduce) {
    .nav-badge, .dot-badge, .toast, .empty *, [data-tab-panel] { animation: none !important; }
}
