/* ============================================================================
   POWER DIALER DESIGN SYSTEM — motion.css
   Every keyframe in the product, plus the roll/tick machinery.
   The rules live in MOTION.md; this file is their implementation.
   All keyframes are ds-* namespaced. Only transform/opacity/background are
   animated. Reduced motion is neutralized globally in core.css.
   ========================================================================== */

/* ---- The one permitted loop: the live-call dot ------------------------- */
@keyframes ds-live-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: .35; }
}

/* ---- Spinners (buttons + owner panel only) ----------------------------- */
@keyframes ds-spin { to { transform: rotate(360deg); } }

/* ---- Skeleton shimmer (owner panel only) ------------------------------- */
@keyframes ds-shimmer { to { transform: translateX(100%); } }

/* ---- Generic entries ---------------------------------------------------- */
@keyframes ds-row-in {          /* rows, feed entries, cascades: 4px rise    */
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes ds-row-out {         /* leaving rows: collapse + fade             */
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(-4px); }
}
@keyframes ds-pane-in {         /* tab pane arrival — directional: JS sets   */
  from { opacity: 0; transform: translate(var(--pane-dx, 0px), 4px); }
  to   { opacity: 1; transform: translate(0, 0); }  /* --pane-dx ±6px from
                                                       the travel direction  */
}
@keyframes ds-item-in {         /* dropdown items (staggered by --i)         */
  from { opacity: 0; transform: translateY(3px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes ds-fade-out {
  from { opacity: 1; }
  to   { opacity: 0; }
}

/* ---- Banners: collapse-open in place ------------------------------------ */
@keyframes ds-banner-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---- Contact advance (the signature move) ------------------------------- */
@keyframes ds-contact-out {     /* finished lead: up and away                */
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(-12px); }
}
@keyframes ds-contact-in {      /* next lead: in from below                  */
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---- Status flash: one 300ms wash when an async update lands ------------ */
@keyframes ds-status-flash {
  0%   { box-shadow: 0 0 0 0 transparent; background-color: transparent; }
  30%  { background-color: var(--accent-wash); }
  100% { background-color: transparent; }
}

/* ---- The odometer (timers + live counters) -------------------------------
   Structure built by DialerUI.odometer(): one clipped cell per character;
   ONLY a digit that changed rolls — old glyph streaks up with a touch of
   motion blur, new glyph rises in. Everything else holds perfectly still.
   The blur is the one texture flourish in the system, reserved for mono
   digits (it reads as a real odometer, not decoration).                    */
@keyframes ds-odo-out {
  from { transform: translateY(0);     opacity: 1;  filter: blur(0); }
  to   { transform: translateY(-60%);  opacity: 0;  filter: blur(1.5px); }
}
@keyframes ds-odo-in {
  from { transform: translateY(60%);   opacity: 0;  filter: blur(1.5px); }
  to   { transform: translateY(0);     opacity: 1;  filter: blur(0); }
}

/* ---- The vertical roll (state labels + ticking numbers) ------------------
   Structure built by DialerUI.roll():
     <span class="roll"><span class="roll-old">A</span>
                        <span class="roll-new">B</span></span>
   Old rolls up and out; new rolls in from below. 140ms, one vocabulary
   for every in-place value change.                                         */
.roll { position: relative; display: inline-block; vertical-align: bottom; }
.roll .roll-old {
  position: absolute;
  inset: 0;
  animation: ds-roll-out var(--t-state) var(--ease) both;
}
.roll .roll-new {
  display: inline-block;
  animation: ds-roll-in var(--t-state) var(--ease) both;
}
@keyframes ds-roll-out {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(-4px); }
}
@keyframes ds-roll-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---- One-shot utility classes (JS attaches, animationend removes) ------- */
.anim-rise-in  { animation: ds-row-in  var(--t-panel) var(--ease) both; }
.anim-fade-out { animation: ds-fade-out var(--t-panel) var(--ease-exit) both; }

/* Stagger helper: JS sets --i on children (cap: menus 6, cascades 8). */
[data-stagger] > * { animation-delay: calc(var(--i, 0) * 20ms); }

/* ---- Theme crossfade helper ---------------------------------------------
   DialerUI.theme() adds .theme-switching to <html> for one panel-tick so
   surfaces crossfade instead of flash-cutting; core.css already transitions
   body. This extends it to the big component surfaces.                     */
.theme-switching .btn,
.theme-switching .panel,
.theme-switching .card,
.theme-switching .input,
.theme-switching .menu,
.theme-switching .modal,
.theme-switching .toast,
.theme-switching .sidebar,
.theme-switching .table td,
.theme-switching .table th {
  transition: background-color var(--t-panel) var(--ease),
              color var(--t-panel) var(--ease),
              box-shadow var(--t-panel) var(--ease),
              border-color var(--t-panel) var(--ease) !important;
}
