/*
 * This is a manifest file that'll be compiled into application.css.
 *
 * With Propshaft, assets are served efficiently without preprocessing steps. You can still include
 * application-wide styles in this file, but keep in mind that CSS precedence will follow the standard
 * cascading order, meaning styles declared later in the document or manifest will override earlier ones,
 * depending on specificity.
 *
 * Consider organizing styles into separate files for maintainability.
 */

/* Custom animations for live price updates */
@keyframes ping-once {
  0% {
    transform: scale(1);
    opacity: 1;
  }
  75%, 100% {
    transform: scale(2);
    opacity: 0;
  }
}

@keyframes bounce-once {
  0%, 100% {
    transform: translateY(-25%);
    animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
  }
  50% {
    transform: translateY(0);
    animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
  }
}

.animate-ping-once {
  animation: ping-once 1s cubic-bezier(0, 0, 0.2, 1) forwards;
}

.animate-bounce-once {
  animation: bounce-once 0.5s ease-out 1;
}

/* Fast ping animation for urgent countdowns */
@keyframes ping-fast {
  0% {
    transform: scale(1);
    opacity: 1;
  }
  50%, 100% {
    transform: scale(2);
    opacity: 0;
  }
}

.animate-ping-fast {
  animation: ping-fast 0.75s cubic-bezier(0, 0, 0.2, 1) infinite;
}

/* Price alert triggered glow - pulses briefly when recently triggered */
@keyframes alert-glow {
  0%, 100% {
    box-shadow: 0 0 0 0 rgba(99, 102, 241, 0);
  }
  50% {
    box-shadow: 0 0 12px 4px rgba(99, 102, 241, 0.3);
  }
}

.animate-alert-glow {
  animation: alert-glow 2s ease-in-out 3;
}

/* SortableJS drag-and-drop styles */
.sortable-chosen {
  outline: 2px solid var(--color-brand-500, oklch(70% 0.17 65));
  outline-offset: 2px;
  border-radius: 0.5rem;
}

.sortable-drag {
  cursor: grabbing !important;
}

.sortable-ghost {
  opacity: 0.5;
}

.sortable-swap-highlight {
  outline: 2px dashed var(--color-brand-400, oklch(75% 0.15 65));
  outline-offset: 2px;
  border-radius: 0.5rem;
  background-color: oklch(70% 0.17 65 / 0.1);
}

/* Gold shimmer for XP reward badges (B13) */
@keyframes gold-shimmer {
  0% { transform: translateX(-100%) rotate(-15deg); }
  100% { transform: translateX(200%) rotate(-15deg); }
}

.gold-shimmer {
  position: relative;
  overflow: hidden;
}

.gold-shimmer::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    105deg,
    transparent 35%,
    rgba(251, 191, 36, 0.3) 45%,
    rgba(254, 240, 138, 0.2) 50%,
    transparent 60%
  );
  animation: gold-shimmer 2s ease-in-out infinite;
  pointer-events: none;
  z-index: 1;
  border-radius: inherit;
}

/* AI shimmer for market briefing card */
@keyframes ai-shimmer {
  0% { background-position: -200% center; }
  100% { background-position: 200% center; }
}

.ai-shimmer {
  background: linear-gradient(90deg, transparent, rgba(251, 191, 36, 0.15), transparent);
  background-size: 200% 100%;
  animation: ai-shimmer 3s ease-in-out infinite;
}

/* Alert glow for time-sensitive items (B4) */
.alert-row-urgent .alert-accent-bar {
  animation: alert-glow 2s ease-in-out 3;
}

/* Stagger hidden — initial state for push-destination section reveals.
   iOS-native curve: short duration with a spring on transform for the subtle
   overshoot Apple uses on widget reveals; standard ease on opacity to keep
   the fade clean. Translate + scale gives the "popping into existence" feel.

   The gate matches via `~=` (token-list) so combined identifiers
   (`"card-detail-tabs stagger-reveal"`, `"alert-dashboard stagger-reveal"`)
   still arm, and via existential ancestor matching so nested stagger-reveal
   containers (e.g. portfolio's outer + per-tab inner) each disarm independently.

   ADDITIVE-REVEAL (2026-07-21): the hidden state is armed ONLY on a live
   stagger-reveal container that has NOT been disarmed. Sections are therefore
   VISIBLE BY DEFAULT — on a Turbo cache restore (native back navigation), on a
   revisit, and if JS never runs. Disarm is the `data-stagger-restored`
   attribute the controller writes on `turbo:before-cache` (so the cached
   snapshot restores visible) and on any skip path. Keying on the
   server-rendered `data-controller` attribute means the hidden state is present
   at first paint on a genuine fresh load (no flash) yet absent on restore (the
   bug: the cascade replayed after the native pop, reading as a double
   back-animation — the opacity:0 sections re-animated in). */
[data-controller~="stagger-reveal"]:not([data-stagger-restored]) .stagger-section {
  opacity: 0;
  transform: translateY(12px) scale(0.98);
  transition: opacity var(--motion-quick) var(--motion-ease-standard),
              transform var(--motion-quick) var(--motion-ease-spring);
}

[data-controller~="stagger-reveal"]:not([data-stagger-restored]) .stagger-section.revealed {
  opacity: 1;
  transform: translateY(0) scale(1);
}

/* Skip animations on cache restore or reduced motion */
.stagger-skip .stagger-section {
  opacity: 1 !important;
  transform: none !important;
  transition: none !important;
}

@media (prefers-reduced-motion: reduce) {
  .gold-shimmer::after {
    animation: none;
  }

  .ai-shimmer {
    animation: none;
  }

  .stagger-section {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

/* Set page: dim unowned cards for visual differentiation */
.set-card-unowned img[data-fly-to-collection-target="image"],
.set-card-unowned img[data-image-load-target="image"] {
  opacity: 0.7;
  filter: saturate(0.85);
}

/* Don't dim the shimmer placeholder */
.set-card-unowned .skeleton-shimmer {
  opacity: 1;
  filter: none;
}

/* Set page: chase card gold glow */
.set-card-chase > .group {
  box-shadow: 0 0 0 2px rgb(251 191 36 / 0.30), 0 0 12px 2px rgb(251 191 36 / 0.15);
  border-radius: 0.75rem;
}
