/* SMAU FILE
 * Path: css/smau-motion.css
 * Owns:
 *   - App launch/close zoom motion visuals. Classes and --app-zoom-ox/oy
 *     vars are applied by js/smau.appMotion.js; every class self-removes on
 *     animationend (+ JS timer fallback).
 * Invariants:
 *   - Truth (data-state / inert / aria-hidden) is NEVER written here.
 *   - .app-zoom-out deliberately overrides the closed-screen display
 *     baseline while its exit animation runs — input stays dead the whole
 *     time (pointer-events: none here, inert from the router).
 *   - All motion is disabled under prefers-reduced-motion.
 * DOM Roots:
 *   - #screen-app, #screen-home
 * Depends:
 *   - Tokens: none required (self-contained timings; eases mirror the
 *     drawer's sheet curve family)
 * No:
 *   - z-index escalation (paint order comes from DOM order: #screen-home
 *     precedes #screen-app, so the app always zooms above home)
 */

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

  /* Compositor-only: keyframes animate transform + opacity ONLY. border-radius
   * used to animate alongside transform on this full-screen layer, which is
   * paint-heavy (radius changes force a repaint of the clip every frame) and
   * read as a flash/pop rather than a smooth zoom. A static radius for the
   * duration gets nearly the same look for a fraction of the cost — the
   * screen already carries a 24px radius from chrome, so 28px reads as a
   * negligible bump, not a shape change. */
  #screen-app.app-zoom-in,
  #screen-app.app-zoom-out {
    overflow: hidden;
    will-change: transform, opacity;
    transform-origin: var(--app-zoom-ox, 50%) var(--app-zoom-oy, 82%);
    border-radius: 28px;
  }

  /* Launch: the app grows out of the tapped icon. The default screen
   * opacity fade is suppressed for the duration — the keyframes own it.
   * Starts at a less extreme scale (0.25, not 0.1) so there's real content
   * to animate instead of a flash-in once opacity catches up, and opacity
   * ramps in over the first quarter so the icon-to-screen growth reads as
   * continuous rather than a delayed pop. Decisive decelerating curve: fast
   * out of the gate, gentle landing. */
  /* The declared opacity/transform below are the animation's own first frame,
   * and they exist so THE SCREEN CANNOT PAINT ITSELF ALREADY-OPEN BEFORE THE
   * ZOOM RUNS. `both` fill means the running animation overrides them
   * immediately, so on a healthy open they are never seen. They matter on a
   * slow one: the class lands in the same tick as data-state="open", but the
   * browser cannot create the animation until it gets a style recalc, and the
   * heaviest app in the phone blocks the main thread through several frames
   * after the truth flip. Without these, `[data-state="open"]` painted the
   * screen full-size and fully opaque in that window, and the zoom then reset
   * it to a quarter-scale and grew it in — the app visibly opening a SECOND
   * time (G38c, the symptom four earlier fixes chased through the open path
   * while the app was only ever opening once). js/smau.appMotion.js abandons
   * the zoom outright if it has not started within its grace window, so this
   * can never leave a screen stuck invisible. */
  #screen-app.app-zoom-in {
    animation: smau-app-zoom-in 400ms cubic-bezier(0.32, 0.72, 0, 1) both;
    transition: none;
    transform: scale(0.25);
    opacity: 0;
  }

  @keyframes smau-app-zoom-in {
    0% {
      transform: scale(0.25);
      opacity: 0;
    }
    25% {
      opacity: 1;
    }
    100% {
      transform: scale(1);
      opacity: 1;
    }
  }

  /* Close-to-home: the app collapses back into its icon. The screen is
   * already data-state="closed"; #screen-app keeps its own display:flex
   * (appShell ID rule beats the screen baseline) and hides via visibility,
   * so forcing visibility back on is all the linger needs — never touch
   * display or the shell's flex layout collapses mid-exit. Inert +
   * pointer-events keep the lingering screen untouchable. Opacity holds
   * near-full until well into the shrink (60%) so the collapse reads as the
   * screen folding into its icon, not fading out first; the curve
   * accelerates into the collapse and settles at the very end instead of
   * accelerating all the way to nothing. */
  #screen-app.app-zoom-out {
    visibility: visible !important;
    pointer-events: none !important;
    animation: smau-app-zoom-out 320ms cubic-bezier(0.4, 0, 0.2, 1) both;
    transition: none;
  }

  @keyframes smau-app-zoom-out {
    0% {
      transform: scale(1);
      opacity: 1;
    }
    60% {
      opacity: 1;
    }
    100% {
      transform: scale(0.25);
      opacity: 0;
    }
  }

  /* Home stays painted (and gently fades via its own closed-state opacity
   * transition) beneath a launching app, so the zoom reads as depth instead
   * of a cut to black. A subtle scale-down while lingering reinforces that
   * depth (home recedes as the app comes forward). Compositor-only
   * (transform + opacity); the class self-removes on a timer
   * (js/smau.appMotion.js HOME_LINGER_MS), which drops the transition too,
   * so home can never get stuck scaled down. */
  #screen-home.motion-linger {
    display: block !important;
    visibility: visible !important;
    pointer-events: none !important;
    transform: scale(0.96);
    opacity: 0.7;
    transition: transform 360ms cubic-bezier(0.32, 0.72, 0, 1), opacity 360ms ease;
  }
}

/* ===========================================================================
 * DIRECTIONAL SCREEN TRANSITIONS
 * When html[data-smau-nav-dir] is set by the router, incoming screens slide
 * from the appropriate direction instead of a flat opacity fade. This adds
 * the spatial awareness real phones have — you feel where you're going.
 * Direction is cleared after the transition completes (via JS timer).
 * ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  /* Outgoing screen: slide out in the opposite direction */
  html[data-smau-nav-dir] .smau-screen[data-state="closed"],
  html[data-smau-nav-dir] [id^="screen-"][data-state="closed"] {
    transition:
      opacity 0.28s cubic-bezier(0.4, 0, 1, 1),
      transform 0.28s cubic-bezier(0.4, 0, 1, 1),
      visibility 0s linear 0.28s;
  }

  html[data-smau-nav-dir="right"] .smau-screen[data-state="closed"],
  html[data-smau-nav-dir="right"] [id^="screen-"][data-state="closed"],
  html[data-smau-nav-dir="up"] .smau-screen[data-state="closed"],
  html[data-smau-nav-dir="up"] [id^="screen-"][data-state="closed"] {
    transform: translateX(-18%) scale(0.96);
    opacity: 0;
  }

  html[data-smau-nav-dir="left"] .smau-screen[data-state="closed"],
  html[data-smau-nav-dir="left"] [id^="screen-"][data-state="closed"],
  html[data-smau-nav-dir="down"] .smau-screen[data-state="closed"],
  html[data-smau-nav-dir="down"] [id^="screen-"][data-state="closed"] {
    transform: translateX(18%) scale(0.96);
    opacity: 0;
  }

  /* Incoming screen: slide in from its direction */
  html[data-smau-nav-dir] .smau-screen[data-state="open"],
  html[data-smau-nav-dir] [id^="screen-"][data-state="open"] {
    transition:
      opacity 0.32s cubic-bezier(0, 0.2, 0.2, 1),
      transform 0.32s cubic-bezier(0, 0.2, 0.2, 1),
      visibility 0s linear 0s;
  }

  html[data-smau-nav-dir="right"] .smau-screen[data-state="open"],
  html[data-smau-nav-dir="right"] [id^="screen-"][data-state="open"] {
    transform: translateX(18%) scale(0.96);
    animation: smau-slide-in-right 0.32s cubic-bezier(0, 0.2, 0.2, 1) both;
  }

  html[data-smau-nav-dir="left"] .smau-screen[data-state="open"],
  html[data-smau-nav-dir="left"] [id^="screen-"][data-state="open"] {
    transform: translateX(-18%) scale(0.96);
    animation: smau-slide-in-left 0.32s cubic-bezier(0, 0.2, 0.2, 1) both;
  }

  html[data-smau-nav-dir="down"] .smau-screen[data-state="open"],
  html[data-smau-nav-dir="down"] [id^="screen-"][data-state="open"] {
    transform: translateY(12%) scale(0.98);
    animation: smau-slide-in-down 0.32s cubic-bezier(0, 0.2, 0.2, 1) both;
  }

  html[data-smau-nav-dir="up"] .smau-screen[data-state="open"],
  html[data-smau-nav-dir="up"] [id^="screen-"][data-state="open"] {
    transform: translateY(-12%) scale(0.98);
    animation: smau-slide-in-up 0.32s cubic-bezier(0, 0.2, 0.2, 1) both;
  }

  @keyframes smau-slide-in-right {
    from { transform: translateX(18%) scale(0.96); opacity: 0; }
    to   { transform: translateX(0) scale(1); opacity: 1; }
  }
  @keyframes smau-slide-in-left {
    from { transform: translateX(-18%) scale(0.96); opacity: 0; }
    to   { transform: translateX(0) scale(1); opacity: 1; }
  }
  @keyframes smau-slide-in-down {
    from { transform: translateY(12%) scale(0.98); opacity: 0; }
    to   { transform: translateY(0) scale(1); opacity: 1; }
  }
  @keyframes smau-slide-in-up {
    from { transform: translateY(-12%) scale(0.98); opacity: 0; }
    to   { transform: translateY(0) scale(1); opacity: 1; }
  }

  /* Exclude app-zoom screens from directional transitions — they own their own motion */
  html[data-smau-nav-dir] #screen-app.app-zoom-in,
  html[data-smau-nav-dir] #screen-app.app-zoom-out {
    animation: none !important;
    transition: none !important;
    transform: none !important;
  }
}

/* Reduced motion: strip directional transitions */
@media (prefers-reduced-motion: reduce) {
  html[data-smau-nav-dir] .smau-screen,
  html[data-smau-nav-dir] [id^="screen-"] {
    animation: none !important;
    transform: none !important;
    transition: none !important;
  }
}

/* ===========================================================================
 * PERF: suppress heavy backdrop-filters while anything is moving.
 * js/smau.gestures.js sets html[data-smau-motion="1"] for the duration of a
 * gesture (page swipe,
drawer/QS/pill/notify) and around app open/close +
 * folder zoom (via SMAU.gestures.markMotion). Frosted layers (the dock is
 * blur(24px)) re-rasterize the content behind them every single frame while
 * pages or screens slide underneath — the dominant cause of "page swipe
 * laggy" / "tapping takes forever" on real phones. The blur only matters when
 * static,
so dropping it for the ~300–400ms of motion is imperceptible while
 * removing the per-frame reblur. NOT gated on reduced-motion: this is a paint
 * optimization,
not an animation. Each surface keeps its own translucent
 * background,
so nothing turns transparent — it just loses the frost briefly.
 * ======================================================================== */
html[data-smau-motion="1"] :where(
  .home-dock,
.home-dock-wrap,
.home-grid-page,
.home-icon-label,
.smau-statusbar,
#screen-app,
.app-view,
.smau-phone-inner,
.smau-shell,
#home-folder-backdrop,
.home-folder-backdrop,
#home-folder-panel,
.home-folder-panel,
#home-drawer-backdrop,
.home-drawer-backdrop,
.home-drawer-panel,
#recents-root,
.recents-backdrop,
.smau-recents-dim,
#notify-banner,
.notify-banner,
.notify-shade-inner,
.notify-item,
.smau-overlay-root,
#smau-overlay-root,
.smau-sheet-panel,
.smau-sheet-scrim,
.smau-scrim,
#screen-lock .lock-clock-block,
#lock-notify,
.lock-nowplaying,
.lock-incoming .call-card,
.lock-pin,
.sb-call-pill
) {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}

/* Also suppress during directional transitions */
html[data-smau-nav-dir] :where(
  .home-dock,
.home-dock-wrap,
.home-grid-page,
.home-icon-label,
.smau-statusbar,
#screen-app,
.app-view,
.smau-phone-inner,
.smau-shell,
#home-folder-backdrop,
.home-folder-backdrop,
#home-folder-panel,
.home-folder-panel,
#home-drawer-backdrop,
.home-drawer-backdrop,
.home-drawer-panel,
#recents-root,
.recents-backdrop,
.smau-recents-dim,
#notify-banner,
.notify-banner,
.notify-shade-inner,
.notify-item,
.smau-overlay-root,
#smau-overlay-root,
.smau-sheet-panel,
.smau-sheet-scrim,
.smau-scrim,
#screen-lock .lock-clock-block,
#lock-notify,
.lock-nowplaying,
.lock-incoming .call-card,
.lock-pin,
.sb-call-pill
) {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}
