/* =============================================================
   Renzo Motion System v1.0
   GPU-accelerated only (transform + opacity). Zero layout thrash.
   Timing reference:
     --rz-ease-out-expo  : cubic-bezier(0.16, 1, 0.3, 1)   — entrances
     --rz-ease-in-expo   : cubic-bezier(0.7, 0, 0.84, 0)   — exits
     --rz-ease-spring    : cubic-bezier(0.34, 1.56, 0.64, 1) — bouncy pick-up
     --rz-ease-standard  : cubic-bezier(0.4, 0, 0.2, 1)    — state changes
   ============================================================= */

:root {
  --rz-ease-out-expo:  cubic-bezier(0.16, 1, 0.3, 1);
  --rz-ease-in-expo:   cubic-bezier(0.7, 0, 0.84, 0);
  --rz-ease-spring:    cubic-bezier(0.34, 1.56, 0.64, 1);
  --rz-ease-standard:  cubic-bezier(0.4, 0, 0.2, 1);
  --rz-ease-decel:     cubic-bezier(0, 0, 0.2, 1);
}

/* ============================================================
   1. CHART TILE ENTRY
   New tiles materialize with a staggered scale-fade.
   Each tile gets --rz-tile-index (set via JS) for stagger.
   ============================================================ */
@keyframes rz-tile-enter {
  from {
    opacity: 0;
    transform: scale(0.94) translateY(8px);
  }
  to {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

.cs-tile.rz-entering,
.rzde-widget.rz-entering {
  animation: rz-tile-enter 0.45s var(--rz-ease-out-expo) both;
  animation-delay: calc(var(--rz-tile-index, 0) * 55ms);
}

/* ============================================================
   2. DATA TRANSITION — bar/line morph shimmer
   Applied to the canvas wrapper while Chart.js re-renders.
   Pure opacity pulse; JS triggers the class for 300ms.
   ============================================================ */
@keyframes rz-data-pulse {
  0%   { opacity: 1; }
  40%  { opacity: 0.45; }
  100% { opacity: 1; }
}

.cs-tile-body.rz-data-updating,
.rzde-w-body.rz-data-updating {
  animation: rz-data-pulse 0.38s var(--rz-ease-standard) both;
  will-change: opacity;
}

/* ============================================================
   3. DRAG AND DROP
   Ghost: the tile being dragged floats at 0.65 opacity + scale up.
   Drop target: a magnetic placeholder pulses into view.
   ============================================================ */

/* Source tile while dragging */
.cs-tile.rz-drag-source,
.rzde-widget.rz-drag-source {
  opacity: 0.4;
  transform: scale(0.97);
  transition: opacity 0.18s var(--rz-ease-standard),
              transform 0.18s var(--rz-ease-standard);
  will-change: opacity, transform;
}

/* The floating ghost clone created by JS */
.rz-drag-ghost {
  position: fixed;
  pointer-events: none;
  z-index: 99999;
  border-radius: 12px;
  box-shadow: 0 24px 60px rgba(0,0,0,0.45),
              0 0 0 2px var(--primary, #6366f1);
  transform: scale(1.04) rotate(1.2deg);
  opacity: 0.92;
  transition: transform 0.12s var(--rz-ease-spring),
              box-shadow 0.12s var(--rz-ease-standard);
  will-change: transform, opacity;
}

/* Magnetic snap — ghost snaps to a drop zone */
.rz-drag-ghost.rz-snapping {
  transform: scale(1.01) rotate(0deg);
  box-shadow: 0 12px 32px rgba(0,0,0,0.3),
              0 0 0 2px var(--primary, #6366f1);
  transition: transform 0.14s var(--rz-ease-spring),
              box-shadow 0.14s var(--rz-ease-standard);
}

@keyframes rz-drop-target-pulse {
  0%   { opacity: 0; transform: scale(0.96); }
  60%  { opacity: 1; transform: scale(1.01); }
  100% { opacity: 1; transform: scale(1); }
}

.rz-drop-target {
  animation: rz-drop-target-pulse 0.22s var(--rz-ease-spring) both;
  outline: 2px dashed var(--primary, #6366f1);
  outline-offset: 3px;
  border-radius: 12px;
  will-change: opacity, transform;
}

/* ============================================================
   4. PANEL TRANSITIONS — properties panel, config panel
   Slide in from right with expo ease. Slide out with in-expo.
   ============================================================ */
@keyframes rz-panel-in {
  from {
    opacity: 0;
    transform: translateX(22px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes rz-panel-out {
  from {
    opacity: 1;
    transform: translateX(0);
  }
  to {
    opacity: 0;
    transform: translateX(22px);
  }
}

/* Properties panel (chart-studio) */
.cs-props {
  transition: none; /* use animation instead */
}
.cs-props.rz-panel-entering {
  animation: rz-panel-in 0.32s var(--rz-ease-out-expo) both;
}
.cs-props.rz-panel-exiting {
  animation: rz-panel-out 0.22s var(--rz-ease-in-expo) both;
}

/* Config side panel (dashboard editor) */
.rzde-config {
  /* override the existing simple keyframe */
  animation: rz-panel-in 0.32s var(--rz-ease-out-expo) both;
}
.rzde-config.rz-panel-exiting {
  animation: rz-panel-out 0.2s var(--rz-ease-in-expo) both;
}

/* Tab cross-fade inside a panel */
@keyframes rz-tab-in {
  from { opacity: 0; transform: translateX(10px); }
  to   { opacity: 1; transform: translateX(0); }
}
.rz-tab-content.rz-tab-entering {
  animation: rz-tab-in 0.2s var(--rz-ease-out-expo) both;
}

/* ============================================================
   5. SELECTION / PICK-UP STATE
   Selected chart tile feels "lifted": subtle scale + ring glow.
   Spring curve gives the snap-to feeling.
   ============================================================ */
@keyframes rz-select-lift {
  0%   { transform: scale(1); }
  50%  { transform: scale(1.022); }
  100% { transform: scale(1.015); }
}

.cs-tile-selected,
.rzde-widget.rz-selected {
  animation: rz-select-lift 0.35s var(--rz-ease-spring) both;
  box-shadow: 0 0 0 2px var(--primary, #6366f1),
              0 8px 32px color-mix(in srgb, var(--primary, #6366f1) 18%, transparent);
  will-change: transform;
}

/* De-select spring-back */
@keyframes rz-deselect {
  from { transform: scale(1.015); }
  to   { transform: scale(1); }
}
.cs-tile.rz-deselecting,
.rzde-widget.rz-deselecting {
  animation: rz-deselect 0.28s var(--rz-ease-spring) both;
}

/* ============================================================
   6. SUCCESS / SAVE CELEBRATION
   The save button does a quick scale-pop then a ripple ring
   radiates outward from it. JS adds .rz-success to the button.
   ============================================================ */
@keyframes rz-success-pop {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.18); }
  65%  { transform: scale(0.94); }
  100% { transform: scale(1); }
}

@keyframes rz-success-ring {
  from {
    opacity: 0.7;
    transform: scale(0.6);
  }
  to {
    opacity: 0;
    transform: scale(2.4);
  }
}

.rz-success-btn {
  position: relative;
  animation: rz-success-pop 0.52s var(--rz-ease-spring) both;
}

/* The pseudo-ring. Actual ring is a span.rz-success-ring injected by JS */
.rz-success-ring {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 2px solid var(--success, #34d399);
  pointer-events: none;
  animation: rz-success-ring 0.6s var(--rz-ease-out-expo) both;
}

/* Checkmark swap: the button icon briefly becomes a check */
@keyframes rz-check-in {
  from { opacity: 0; transform: scale(0.5) rotate(-15deg); }
  to   { opacity: 1; transform: scale(1) rotate(0deg); }
}
.rz-check-icon {
  animation: rz-check-in 0.28s var(--rz-ease-spring) both;
  color: var(--success, #34d399);
}

/* ============================================================
   7. LOADING / SKELETON SHIMMER
   Skeleton blocks shimmer with a diagonal highlight sweep.
   No layout properties touched — background-position on a
   GPU-composited background-image.
   ============================================================ */
@keyframes rz-shimmer {
  from { background-position: -200% center; }
  to   { background-position: 200% center; }
}

.rz-skeleton {
  border-radius: 6px;
  background: linear-gradient(
    90deg,
    rgba(148, 163, 184, 0.06) 0%,
    rgba(148, 163, 184, 0.14) 40%,
    rgba(148, 163, 184, 0.06) 80%
  );
  background-size: 200% 100%;
  animation: rz-shimmer 1.6s var(--rz-ease-standard) infinite;
  will-change: background-position;
}

[data-theme="light"] .rz-skeleton {
  background: linear-gradient(
    90deg,
    rgba(15, 23, 42, 0.05) 0%,
    rgba(15, 23, 42, 0.12) 40%,
    rgba(15, 23, 42, 0.05) 80%
  );
  background-size: 200% 100%;
}

/* Skeleton tile layout — matches rzde-widget proportions */
.rz-skeleton-tile {
  border-radius: 12px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 16px;
  border: 1px solid rgba(148, 163, 184, 0.06);
}
.rz-skeleton-title  { height: 12px; width: 48%; }
.rz-skeleton-chart  { height: 140px; border-radius: 8px; }
.rz-skeleton-line   { height: 10px; }
.rz-skeleton-line.short { width: 65%; }

/* AI insight loading dots */
@keyframes rz-dot-bounce {
  0%, 80%, 100% { transform: translateY(0); opacity: 0.4; }
  40%            { transform: translateY(-5px); opacity: 1; }
}
.rz-typing-dot {
  display: inline-block;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--primary-light, #818cf8);
  animation: rz-dot-bounce 1.2s var(--rz-ease-standard) infinite;
  will-change: transform, opacity;
}
.rz-typing-dot:nth-child(2) { animation-delay: 0.15s; }
.rz-typing-dot:nth-child(3) { animation-delay: 0.30s; }

/* ============================================================
   8. KPI NUMBER COUNTER
   The value element is hidden until JS runs the counter;
   a brief fade+slide-up entrance plays once counting ends.
   ============================================================ */
@keyframes rz-kpi-land {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.92);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.rzde-kpi-value.rz-kpi-counting {
  /* Hide raw value while JS counts */
  opacity: 0;
  transform: translateY(10px) scale(0.92);
  will-change: opacity, transform;
}

.rzde-kpi-value.rz-kpi-done {
  animation: rz-kpi-land 0.48s var(--rz-ease-spring) both;
}

/* ============================================================
   BONUS: Hover depth on tiles
   Avoids box-shadow (layout) — uses filter:drop-shadow
   which is compositor-only on most browsers.
   ============================================================ */
.cs-tile,
.rzde-widget {
  will-change: transform;
  transition: transform 0.18s var(--rz-ease-standard),
              border-color 0.15s, box-shadow 0.15s;
}
.cs-tile:hover:not(.cs-tile-selected):not(.rz-drag-source),
.rzde-widget:hover:not(.rz-selected):not(.rz-drag-source) {
  transform: translateY(-2px);
}

/* ============================================================
   REDUCED MOTION — honor prefers-reduced-motion globally
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
