/* ─────────────────────────────────────────────────────────────────────────────────────────────────
   Dashboard motion — FND-1088 PR 8b (DEC-045, playbook §4.6). Classes and variables are written ONLY by dashboard_motion.jsx:
     [data-dm-motion]           on the tile root ('off' = reduced motion / pixel motion off / editing ⇒ everything static) — an attribute,
                                because React owns the root's className (8a rewrites it when the size or the editing state changes)
     .dm-kb                     Ken-Burns target (--kb-z0/x0/y0 → --kb-z1/x1/y1 over --kb-d, alternate, endless)
     .dm-anim + .dm-in-* .dm-out-* .dm-loop-* .dm-cycle   entry / exit / loop presets; .dm-pending → .dm-play once ≥ 50 % visible
     .dm-ph-in / .dm-ph-out     the two phases of a `cycle` (switched on animationend, no timers)
     .dm-paused                 tile invisible, tab hidden or over the running-animation budget
   Every keyframe animates transform and opacity only (compositor work, no layout, no repaint of the content).
   ───────────────────────────────────────────────────────────────────────────────────────────────── */

/* Ken-Burns: scale about the centre, then shift the focus point toward the centre (bounded so no edge shows). */
.dm-kb {
  transform-origin: 50% 50%;
  animation-name: dm-k-kb;
  animation-duration: var(--kb-d, 18s);
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-direction: alternate;
  animation-fill-mode: both;
}
@keyframes dm-k-kb {
  from { transform: translate(var(--kb-x0, 0%), var(--kb-y0, 0%)) scale(var(--kb-z0, 1)); }
  to   { transform: translate(var(--kb-x1, 0%), var(--kb-y1, 0%)) scale(var(--kb-z1, 1.15)); }
}

/* Presets → keyframe names (custom properties, so one animation rule serves every combination). */
.dm-anim { --dm-k-in: none; --dm-k-out: none; --dm-k-loop: none; --dm-period: 4s; }
.dm-in-fade        { --dm-k-in: dm-k-in-fade; }
.dm-in-fade-up     { --dm-k-in: dm-k-in-fade-up; }
.dm-in-fade-down   { --dm-k-in: dm-k-in-fade-down; }
.dm-in-slide-left  { --dm-k-in: dm-k-in-slide-left; }
.dm-in-slide-right { --dm-k-in: dm-k-in-slide-right; }
.dm-in-zoom-in     { --dm-k-in: dm-k-in-zoom-in; }
.dm-in-zoom-out    { --dm-k-in: dm-k-in-zoom-out; }
.dm-out-fade        { --dm-k-out: dm-k-out-fade; }
.dm-out-fade-up     { --dm-k-out: dm-k-out-fade-up; }
.dm-out-fade-down   { --dm-k-out: dm-k-out-fade-down; }
.dm-out-slide-left  { --dm-k-out: dm-k-out-slide-left; }
.dm-out-slide-right { --dm-k-out: dm-k-out-slide-right; }
.dm-out-zoom-in     { --dm-k-out: dm-k-out-zoom-in; }
.dm-out-zoom-out    { --dm-k-out: dm-k-out-zoom-out; }
.dm-loop-pulse { --dm-k-loop: dm-k-pulse; --dm-period: 3s; }
.dm-loop-float { --dm-k-loop: dm-k-float; --dm-period: 5s; }
.dm-loop-sway  { --dm-k-loop: dm-k-sway;  --dm-period: 6s; }

/* Waiting for the entry (tile not yet ≥ 50 % visible): the start state of every entry preset is invisible. */
.dm-anim.dm-pending { opacity: 0; }

/* Entry (once) followed by an endless loop. */
.dm-anim.dm-play:not(.dm-cycle) {
  animation-name: var(--dm-k-in), var(--dm-k-loop);
  animation-duration: var(--dm-dur, 0.8s), var(--dm-period);
  animation-delay: var(--dm-delay, 0s), var(--dm-loop-delay, 0s);
  animation-timing-function: cubic-bezier(0.2, 0.7, 0.2, 1), ease-in-out;
  animation-iteration-count: 1, infinite;
  animation-fill-mode: both, none;
}
/* cycle: in → hold → out → pause (= hold) → in … */
.dm-anim.dm-cycle.dm-play.dm-ph-in {
  animation-name: var(--dm-k-in);
  animation-duration: var(--dm-dur, 0.8s);
  animation-delay: var(--dm-phase-delay, 0s);
  animation-timing-function: cubic-bezier(0.2, 0.7, 0.2, 1);
  animation-iteration-count: 1;
  animation-fill-mode: both;
}
.dm-anim.dm-cycle.dm-play.dm-ph-out {
  animation-name: var(--dm-k-out);
  animation-duration: var(--dm-dur, 0.8s);
  animation-delay: var(--dm-hold, 4s);
  animation-timing-function: cubic-bezier(0.5, 0, 0.8, 0.3);
  animation-iteration-count: 1;
  animation-fill-mode: both;
}

/* Entry keyframes: from the preset's start state to the layer's own state. */
@keyframes dm-k-in-fade        { from { opacity: 0; } to { opacity: 1; } }
@keyframes dm-k-in-fade-up     { from { opacity: 0; transform: translate3d(0, var(--dm-shift, 12px), 0); } to { opacity: 1; transform: none; } }
@keyframes dm-k-in-fade-down   { from { opacity: 0; transform: translate3d(0, calc(-1 * var(--dm-shift, 12px)), 0); } to { opacity: 1; transform: none; } }
@keyframes dm-k-in-slide-left  { from { opacity: 0; transform: translate3d(var(--dm-slide, 40px), 0, 0); } to { opacity: 1; transform: none; } }
@keyframes dm-k-in-slide-right { from { opacity: 0; transform: translate3d(calc(-1 * var(--dm-slide, 40px)), 0, 0); } to { opacity: 1; transform: none; } }
@keyframes dm-k-in-zoom-in     { from { opacity: 0; transform: scale(0.85); } to { opacity: 1; transform: none; } }
@keyframes dm-k-in-zoom-out    { from { opacity: 0; transform: scale(1.15); } to { opacity: 1; transform: none; } }
/* Exit keyframes: the movement continues in the preset's direction. */
@keyframes dm-k-out-fade        { from { opacity: 1; } to { opacity: 0; } }
@keyframes dm-k-out-fade-up     { from { opacity: 1; transform: none; } to { opacity: 0; transform: translate3d(0, calc(-1 * var(--dm-shift, 12px)), 0); } }
@keyframes dm-k-out-fade-down   { from { opacity: 1; transform: none; } to { opacity: 0; transform: translate3d(0, var(--dm-shift, 12px), 0); } }
@keyframes dm-k-out-slide-left  { from { opacity: 1; transform: none; } to { opacity: 0; transform: translate3d(calc(-1 * var(--dm-slide, 40px)), 0, 0); } }
@keyframes dm-k-out-slide-right { from { opacity: 1; transform: none; } to { opacity: 0; transform: translate3d(var(--dm-slide, 40px), 0, 0); } }
@keyframes dm-k-out-zoom-in     { from { opacity: 1; transform: none; } to { opacity: 0; transform: scale(1.15); } }
@keyframes dm-k-out-zoom-out    { from { opacity: 1; transform: none; } to { opacity: 0; transform: scale(0.85); } }
/* Loops (periods 3–6 s, playbook §4.6): pulse 1 → 1.04, float ±1.5 % of the edge, sway ±2°. */
@keyframes dm-k-pulse { 0%, 100% { transform: none; } 50% { transform: scale(1.04); } }
@keyframes dm-k-float { 0%, 100% { transform: none; } 25% { transform: translate3d(0, calc(-1 * var(--dm-float, 3px)), 0); } 75% { transform: translate3d(0, var(--dm-float, 3px), 0); } }
@keyframes dm-k-sway  { 0%, 100% { transform: none; } 25% { transform: rotate(-2deg); } 75% { transform: rotate(2deg); } }

/* Invisible tile, hidden tab, over budget: keep the frame, stop the clock. */
.dm-kb.dm-paused, .dm-anim.dm-paused { animation-play-state: paused; }

/* Motion not allowed (reduced motion, pixel motion off, editing): static — entries show their end state, Ken-Burns its start. */
[data-dm-motion="off"] .dm-kb,
[data-dm-motion="off"] .dm-anim { animation: none !important; }   /* beats the more specific phase rules */
[data-dm-motion="off"] .dm-anim.dm-pending { opacity: 1 !important; }
@media (prefers-reduced-motion: reduce) {
  .dm-kb, .dm-anim { animation: none !important; }
  .dm-anim.dm-pending { opacity: 1 !important; }
}
