/*
  Layout animation styles — applied globally to both desktop and mobile.

  Strategy: give specific elements a CSS transition + @starting-style so
  they animate when shown/hidden by JS. We NEVER override .hidden (display:none)
  or touch anything that has its own animation or must not move.
*/

/* ── Shared enter/exit transition ─────────────────────────────────────────
   Every element listed here gets an opacity+transform transition.
   @starting-style defines the "from" state when the element first becomes
   visible (either .hidden removed, display changed, or added to DOM).
   transition-behavior: allow-discrete lets the browser run the transition
   even when display is changing.
*/

/* manage.ejs — daemon warning */
#daemonOfflineWarning,
#daemonOfflineWarningRow,

/* manage.ejs — install banner */
#installBanner,

/* manage.ejs — server page body and stats cards */
#server-page-body,
.console-wrap,

/* dashboard — folder popup, new folder dialog */
.folder-popup-overlay .folder-popup,
.dialog-overlay .dialog-box,

/* overview.ejs — update check results */
#updateStatus,
#performUpdateBtn,
#updateInfo,

/* servers.ejs — radar modal phases and scan mode toggle */
#scanModeToggle,
#builtinPickerSection,
#vtScanSection,
#radarPickerPhase,
#radarResultsPhase,
#radarRescanBtn,
#radarScanModal,
#radarServerTabs,
#radarSummaryBar,
#radarResultsBody,

/* files.ejs — upload zone / preview swap, path hint */
#filePreview,
#dropZone,
#fileNamePreview,
#renamePreview,

/* apikeys.ejs — create modal, panel accordion */
#createApiKeyModal,

/* apikeys/docs.ejs — response panel */
#responseContainer,

/* template.ejs — search dropdown */
#searchResults,

/* sftp.ejs — sftp state panels */
#sftpLoading,
#sftpError,
#sftpCredentials,

/* store.ejs / addons — loading/grid/empty/error states */
#storeLoading,
#storeGrid,
#storeEmpty,
#storeError,

/* analytics.ejs — chart loading state */
#chartLoading,
#chartContainer,

/* analytics.ejs — player details modal */
#serverDetailsModal,

/* create server — variables section */
#variablesSection,

/* worlds.ejs — table / empty message */
#serverTable,
#noWorldsMessage,

/* serverHeader.ejs — uptime container */
[data-server-started-container],

/* account.ejs — inline feedback */
#username-feedback,
#current-password-feedback,

/* loading-state.ejs / error-state.ejs */
#loading-state,
#error-state,

/* tab panels (analytics, addons store, apikeys docs) */
.tab-content,
.m-pane {
  transition:
    opacity   0.38s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.38s cubic-bezier(0.16, 1, 0.3, 1);
  transition-behavior: allow-discrete;
}

/* Enter state — what the element looks like the instant it becomes visible */
@starting-style {
  #daemonOfflineWarning,
  #daemonOfflineWarningRow,
  #installBanner,
  #server-page-body,
  .console-wrap,
  .folder-popup-overlay .folder-popup,
  .dialog-overlay .dialog-box,
  #updateStatus,
  #performUpdateBtn,
  #updateInfo,
  #scanModeToggle,
  #builtinPickerSection,
  #vtScanSection,
  #radarPickerPhase,
  #radarResultsPhase,
  #radarRescanBtn,
  #radarScanModal,
  #radarServerTabs,
  #radarSummaryBar,
  #radarResultsBody,
  #filePreview,
  #dropZone,
  #fileNamePreview,
  #renamePreview,
  #createApiKeyModal,
  #responseContainer,
  #searchResults,
  #sftpLoading,
  #sftpError,
  #sftpCredentials,
  #storeLoading,
  #storeGrid,
  #storeEmpty,
  #storeError,
  #chartLoading,
  #chartContainer,
  #serverDetailsModal,
  #variablesSection,
  #serverTable,
  #noWorldsMessage,
  [data-server-started-container],
  #username-feedback,
  #current-password-feedback,
  #loading-state,
  #error-state,
  .tab-content,
  .m-pane {
    opacity: 0;
    transform: translateY(10px);
  }
}

/* ── Page-content children — layout shift transitions ─────────────────────
   When a warning banner or section appears/disappears, sibling elements
   below it need to shift position smoothly. This transition lets the
   JS FLIP in layout-animations.js animate them.
*/

#page-content > *,
#server-page-body > * {
  transition:
    transform 0.36s cubic-bezier(0.4, 0, 0.2, 1),
    opacity   0.36s cubic-bezier(0.16, 1, 0.3, 1);
}

/* ── Server & folder card load-in ─────────────────────────────────────────
   Cards animate in on page load with a stagger driven by CSS custom
   properties set inline. Each card gets --i: N where N is its index.
*/
.server-card,
.folder-card {
  animation: card-enter 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: calc(var(--i, 0) * 50ms);
}

@keyframes card-enter {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ── All table rows load-in ──────────────────────────────────────────────*/
.img-row,
.addon-row,
.file-row,
.world-row,
.user-row,
.server-row,
.node-row,
.apikey-row,
.image-row,
.player-row,
.login-row,
.backup-row,
.table-row-animate,
tbody tr {
  animation: row-enter 0.3s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: calc(var(--i, 0) * 30ms);
}

@keyframes row-enter {
  from { opacity: 0; transform: translateX(-4px); }
  to   { opacity: 1; transform: translateX(0); }
}

/* ── All grid items load-in ─────────────────────────────────────────────*/
.grid-item-animate {
  animation: card-enter 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: calc(var(--i, 0) * 40ms);
}

/* ── Skeleton shimmer ───────────────────────────────────────────────────*/
@keyframes skeleton-shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

.skeleton {
  background: linear-gradient(
    90deg,
    var(--theme-bg-input, #f3f4f6) 25%,
    var(--theme-bg-hover, #e5e7eb) 50%,
    var(--theme-bg-input, #f3f4f6) 75%
  );
  background-size: 200% 100%;
  animation: skeleton-shimmer 1.8s ease-in-out infinite;
  border-radius: 8px;
}

.dark .skeleton {
  background: linear-gradient(
    90deg,
    rgba(255,255,255,0.04) 25%,
    rgba(255,255,255,0.08) 50%,
    rgba(255,255,255,0.04) 75%
  );
  background-size: 200% 100%;
}

.skeleton-text     { height: 12px; width: 60%; }
.skeleton-text-sm  { height: 10px; width: 40%; }
.skeleton-title    { height: 16px; width: 80%; }
.skeleton-avatar   { width: 36px; height: 36px; border-radius: 50%; }
.skeleton-card     { height: 80px; width: 100%; }
.skeleton-row      { height: 48px; width: 100%; margin-bottom: 4px; }

/* ── Stats cards load-in ──────────────────────────────────────────────────*/
.stats-card {
  animation: card-enter 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: calc(var(--i, 0) * 60ms);
}

/* ── Never animate these ──────────────────────────────────────────────────*/

canvas,
#terminal,
#terminal *,
[class*="xterm"],
.animate-spin,
.animate-ping,
.mobile-top-bar,
.mobile-top-bar *,
.mobile-bottom-nav,
.mobile-bottom-nav *,
.mobile-more-sheet,
.mobile-more-sheet *,
#pl-overlay,
#pl-overlay *,
#active-background,
svg,
img {
  transition: none !important;
}

/* Respect user's motion preference */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
