/* ==========================================================================================
   KHC Message Center — motion.css (2026-09-06)
   THE MOTION LAYER. Loaded LAST (after production.css) so plain selectors win cascade ties.
   Result of a whole-site audit against Emil Kowalski's design-engineering standards
   (animations.dev): strong ease-out curves on every entrance, dialogs that ARRIVE instead of
   teleporting, press feedback on every pressable, no `transition: all`, hover motion only
   where a hover exists, exits faster than entrances — and all of it collapsing to a quiet
   fade under prefers-reduced-motion.
   Nothing here targets the station kiosks. Every selector that could reach a kiosk element is
   wrapped in :where(body:not(.water-kiosk):not(.provider-kiosk)) — :where() weighs nothing, so
   each rule keeps exactly the specificity of its own selector and wins only by loading last.
   ========================================================================================== */

/* ---- 0 · Motion tokens ----------------------------------------------------------------------
   styles.css defines --ease (a mild ease-out) and --dur (160ms). Those stay for hover and colour
   changes, where a gentle curve is right. These three are for MOVEMENT. */
:root {
  --ease-out:    cubic-bezier(.23, 1, .32, 1);     /* strong ease-out — entrances, exits, presses */
  --ease-in-out: cubic-bezier(.77, 0, .175, 1);    /* something moving between two on-screen places */
  --ease-drawer: cubic-bezier(.32, .72, 0, 1);     /* iOS drawer / sheet curve (from Ionic) */
  --dur-press: 120ms;   /* button press */
  --dur-pop:   160ms;   /* popovers, menus, scrims */
  --dur-card:  180ms;   /* dialog cards */
  --dur-exit:  140ms;   /* anything leaving — always faster than it arrived */
}

/* ---- 1 · Entrance keyframes, re-declared with a strong ease-out --------------------------------
   The last @keyframes of a given name in document order wins, everywhere it is used. A timing
   function written INSIDE a keyframe governs that segment, so every element that already uses
   one of these gets the new curve without listing a single selector. Shapes are unchanged. */
@keyframes eg-rise      { from { opacity: 0; transform: translateY(6px);  animation-timing-function: cubic-bezier(.23, 1, .32, 1); } to { opacity: 1; transform: none; } }
@keyframes eg-fadein    { from { opacity: 0;                              animation-timing-function: cubic-bezier(.23, 1, .32, 1); } to { opacity: 1; } }
@keyframes eg-bubble-in { from { opacity: 0; transform: translateY(4px);  animation-timing-function: cubic-bezier(.23, 1, .32, 1); } to { opacity: 1; transform: none; } }
@keyframes eg-sheetin   { from { transform: translateY(24px); opacity: 0; animation-timing-function: cubic-bezier(.32, .72, 0, 1); } to { transform: none; opacity: 1; } }
@keyframes toast-in     { from { transform: translateY(-8px); opacity: 0; animation-timing-function: cubic-bezier(.23, 1, .32, 1); } to { transform: translateY(0); opacity: 1; } }
@keyframes prHfIn       { from { opacity: 0; transform: translateY(-4px); animation-timing-function: cubic-bezier(.23, 1, .32, 1); } }
@keyframes tourPop      { from { opacity: 0; transform: translateY(4px);  animation-timing-function: cubic-bezier(.23, 1, .32, 1); } to { opacity: 1; } }
@keyframes apMemoWarnIn { from { opacity: 0; transform: translateY(-4px); animation-timing-function: cubic-bezier(.23, 1, .32, 1); } to { opacity: 1; transform: none; } }
@keyframes coachFade    { from { opacity: 0;                              animation-timing-function: cubic-bezier(.23, 1, .32, 1); } to { opacity: 1; } }
@keyframes coachRise    { from { opacity: 0; transform: translateY(14px) scale(.98); animation-timing-function: cubic-bezier(.23, 1, .32, 1); } to { opacity: 1; transform: none; } }
/* Nothing appears from nothing: the "all clear" pop started at scale(.5). It now starts at .8 and
   keeps its small overshoot — a reward moment is allowed a little bounce. */
@keyframes eg-pop       { 0% { transform: scale(.8); opacity: 0; animation-timing-function: cubic-bezier(.23, 1, .32, 1); } 70% { transform: scale(1.06); } 100% { transform: scale(1); opacity: 1; } }

/* ---- 2 · Dialogs arrive instead of teleporting -------------------------------------------------
   Every fixed scrim + card pair in the app appeared in one frame. Scrim fades 160ms; the card
   rises 6px from 98% over 180ms. Modals keep transform-origin: center (they are not anchored to a
   trigger). Deliberately NOT animated: .cmdk-overlay (⌘K — keyboard-triggered, used all day) and
   .shortcuts-overlay (the ? key). `both` = start invisible before the first frame paints. */
@keyframes mo-scrim { from { opacity: 0; } }
@keyframes mo-card  { from { opacity: 0; transform: translateY(6px) scale(.98); } }
@keyframes mo-pop   { from { opacity: 0; transform: translateY(-4px) scale(.98); } }
@keyframes mo-rise  { from { opacity: 0; transform: translateY(8px); } }

:where(body:not(.water-kiosk):not(.provider-kiosk)) :is(.chooser-overlay, .att-overlay, .modal-overlay, .ap-cmp-overlay, .ccm-overlay, .nl-overlay, .docs-page-overlay, .rc-lightbox, .wtr-modal) {
  animation: mo-scrim var(--dur-pop) var(--ease-out) both;
}
:where(body:not(.water-kiosk):not(.provider-kiosk)) :is(.chooser-card, .att-card, .modal, .ap-cmp-card, .ccm-box, .nl-player, .docs-page-card) {
  animation: mo-card var(--dur-card) var(--ease-out) both;
  transform-origin: center;
}

/* Trigger-anchored menus drop from their trigger (top edge), 160ms. NOT .suggest-pop — it re-shows
   on every keystroke of the address box, and typing must never animate. */
:where(body:not(.water-kiosk):not(.provider-kiosk)) :is(.canned-menu, .ap-colmenu) {
  animation: mo-pop var(--dur-pop) var(--ease-out) both;
  transform-origin: top left;
}

/* The "just updated — Refresh" banner is rare and worth a small rise. */
.update-nudge { animation: mo-rise .24s var(--ease-out) both; }

/* ---- 3 · No `transition: all` ---------------------------------------------------------------
   `all` animates whatever changes — width, padding, layout — off the GPU. Name the properties. */
.pk-hchip, .docs-cut, .docs-pill, .docs-dtile {
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease), transform var(--dur-press) var(--ease-out), scale var(--dur-press) var(--ease-out);
}

/* ---- 4 · Press feedback on every pressable ----------------------------------------------------
   mobile.css already scales the main buttons on :active. These were missed. `scale` is the
   standalone property, so it composes with any transform an element already uses to position
   itself instead of replacing it. Presses are 120ms; the release rides the same curve. */
@media (prefers-reduced-motion: no-preference) {
  :where(body:not(.water-kiosk):not(.provider-kiosk)) :is(.chooser-opt, .mode-toggle button, .pr-hf-sbtn, .lb-head, .update-nudge button) {
    transition: scale var(--dur-press) var(--ease-out);
  }
  /* These two already transition other properties — restate those so nothing is lost. */
  :where(body:not(.water-kiosk):not(.provider-kiosk)) .resolve-chip { transition: border-color .12s ease, background .12s ease, scale var(--dur-press) var(--ease-out); }
  :where(body:not(.water-kiosk):not(.provider-kiosk)) .hud { transition: box-shadow var(--dur) var(--ease), scale var(--dur-press) var(--ease-out); }
  :where(body:not(.water-kiosk):not(.provider-kiosk)) :is(.chooser-opt, .mode-toggle button, .pr-hf-sbtn, .lb-head, .update-nudge button, .resolve-chip, .hud, .pk-hchip, .docs-cut, .docs-pill, .docs-dtile):active:not(:disabled) {
    scale: .97;
  }
}

/* ---- 5 · Hover motion only where a hover exists -----------------------------------------------
   A finger tap fires :hover and leaves it stuck, so the rail row that nudges 2px right on hover
   was jumping under every tap on a tablet. Colour and shadow hovers are left alone; only
   MOVEMENT is gated. :not(:active) keeps the press feedback while the finger is down. */
@media (hover: none), (pointer: coarse) {
  .tab:hover:not(:active), .tab.active:hover:not(:active), .compose-ch:hover:not(:active),
  .uni-card:hover:not(:active), .wtr-strip-shot:hover:not(:active), .bday-cake:hover:not(:active) { transform: none; }
}

/* ---- 6 · Toasts: strong entrance, faster exit --------------------------------------------------
   Enter 200ms ease-out (keyframe above); leave 140ms. app.js toast() now adds .leaving before it
   removes the node, so a "Saved" no longer blinks out of existence. */
:where(body:not(.water-kiosk):not(.provider-kiosk)) .toast {
  animation-duration: .2s;
  animation-timing-function: var(--ease-out);
  transition: opacity var(--dur-exit) var(--ease-out), transform var(--dur-exit) var(--ease-out);
}

/* ---- 7 · Reader pane: iOS drawer curve, and it closes faster than it opens ---------------------
   Opening a message is the most frequent action in the building, so the slide is short. A CSS
   transition uses the timing of the state being entered: .open governs opening, the base rule
   governs closing. */
.detail      { transition: transform .18s var(--ease-drawer); }
.detail.open { transition: transform .24s var(--ease-drawer); }

/* ---- 8 · Drawers, sheets, tooltips, leaving scrims: the right curve ----------------------------- */
.ecw-chart-drawer, .ap-bill-drawer, .ap-tour-tip { transition-timing-function: var(--ease-out); }
.mc-sheet { transition: transform .22s var(--ease-drawer), opacity .18s var(--ease-out); }
.eg-overlay.leaving, .coach-overlay.coach-leaving { transition-duration: var(--dur-exit); transition-timing-function: var(--ease-out); }

/* ---- 9 · Spinners spin faster — the same wait feels shorter ------------------------------------ */
.apv-spin, .rc-inline-spin { animation-duration: .8s; }

/* ---- 10 · Reduced motion: keep the fades, drop the movement ------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  :where(body:not(.water-kiosk):not(.provider-kiosk)) :is(.chooser-card, .att-card, .modal, .ap-cmp-card, .ccm-box, .nl-player, .docs-page-card, .canned-menu, .ap-colmenu) { animation: mo-scrim var(--dur-pop) ease both; }
  .update-nudge { animation: mo-scrim .2s ease both; }
  .detail, .detail.open { transition-duration: 0s; }
  .mc-sheet { transition: opacity .18s ease; }
  :where(body:not(.water-kiosk):not(.provider-kiosk)) .toast { animation: none; transition: opacity var(--dur-exit) ease; }
}
