/* ─── Motion layer ─────────────────────────────────────
   Companion to assets/js/motion.js. Loaded after style.css so it can
   layer on top without editing any existing rule. Uses theme tokens
   only, so light and dark both work unchanged. */

/* ─── Skeletons ─────────────────────────────────────────
   .is-skeleton is set on #content-canvas by motion.js while the page is
   still showing app.js's hardcoded sample DATA (first visit, no cache).
   Text goes transparent but keeps its box, so the layout doesn't jump
   when the real numbers land. */
@keyframes odin-skeleton-sweep {
  0%   { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}

.content-canvas.is-skeleton .kpi-value,
.content-canvas.is-skeleton .kpi-delta,
.content-canvas.is-skeleton .kpi-driver,
.content-canvas.is-skeleton .kpi-meta {
  color: transparent !important;
  background: linear-gradient(90deg, var(--bg-hover) 25%, var(--border) 50%, var(--bg-hover) 75%) !important;
  background-size: 200% 100% !important;
  animation: odin-skeleton-sweep 1.3s ease-in-out infinite;
  border-radius: var(--radius-sm);
  user-select: none;
}
.content-canvas.is-skeleton .kpi-value { width: 60%; }
/* .kpi-delta keeps its natural inline-flex width — narrowing it wraps
   the sample text onto two lines and the card jumps on real data. */
.content-canvas.is-skeleton .kpi-driver *,
.content-canvas.is-skeleton .kpi-meta * { visibility: hidden; }
.content-canvas.is-skeleton .kpi-spark { visibility: hidden; }

/* Card bodies (tables, charts): hide the sample content and sweep a
   single block across its footprint. */
.content-canvas.is-skeleton .card-body { position: relative; }
.content-canvas.is-skeleton .card-body > * { visibility: hidden; }
.content-canvas.is-skeleton .card-body::after {
  content: '';
  position: absolute;
  inset: 14px;
  border-radius: var(--radius-md);
  background: linear-gradient(90deg, var(--bg-hover) 25%, var(--border) 50%, var(--bg-hover) 75%);
  background-size: 200% 100%;
  animation: odin-skeleton-sweep 1.3s ease-in-out infinite;
}
.content-canvas.is-skeleton .kpi-card-clickable { pointer-events: none; } /* no drill-down into sample numbers */

/* ─── Press feedback ────────────────────────────────────
   Hover states already exist in style.css; this adds the missing
   "it registered" squeeze on click. */
.segment-btn,
.btn-icon,
.kpi-mover-tab,
.daterange-preset-btn,
.multiselect-apply-btn,
.card-fullscreen-btn {
  transition-property: background, color, border-color, box-shadow, transform;
}
.segment-btn:active,
.btn-icon:active,
.kpi-mover-tab:active,
.daterange-preset-btn:active,
.multiselect-apply-btn:active,
.card-fullscreen-btn:active {
  transform: scale(0.96);
}
.kpi-card-clickable:active {
  transform: translateY(0) scale(0.985);
  box-shadow: var(--shadow-card, none);
}

/* ─── Reduced motion ────────────────────────────────────
   motion.js already skips its entrance/count-up; this covers the CSS
   side (skeleton sweep, loading bounce, live pulse, hover lifts). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .kpi-card:hover,
  .kpi-card-clickable:active,
  .segment-btn:active,
  .btn-icon:active,
  .kpi-mover-tab:active,
  .daterange-preset-btn:active,
  .multiselect-apply-btn:active,
  .card-fullscreen-btn:active { transform: none; }
}
