/* ══════════════════════════════════════════════════════════════════
   SKELETON LOADING STATES
   ──────────────────────────────────────────────────────────────────
   Shared shimmer placeholders for anything that loads in after first
   paint: proj-table-style tables (Projects grid, Exports grid), the
   sidebar avatar/name, and the index greeting heading.

   Two patterns are used, both zero-JS:
     1. Table rows: static skeleton <tr> markup sits in the tbody on
        page load; the owning render function already does
        `tbody.innerHTML = ''` before drawing real rows, so skeleton
        rows are wiped automatically the moment data arrives.
     2. Single-value fields (sidebar avatar/name, greeting): these
        start genuinely empty in the HTML and are styled via :empty /
        :has(:empty). The moment sidebar.js sets real text/content,
        the element no longer matches :empty and the shimmer is gone
        — no class to add or remove.
══════════════════════════════════════════════════════════════════ */

.skel-row {
  cursor: default;
  pointer-events: none;
}
.skel-row:hover { background: transparent; }

/* Base shimmer bar */
.skel-bar,
.skel-avatar {
  display: inline-block;
  background: linear-gradient(
    90deg,
    var(--bg-elevated) 25%,
    var(--border-hover) 37%,
    var(--bg-elevated) 63%
  );
  background-size: 400% 100%;
  animation: skelShimmer 1.4s ease-in-out infinite;
}

.skel-bar {
  height: 11px;
  border-radius: 5px;
  vertical-align: middle;
}

@keyframes skelShimmer {
  0%   { background-position: 100% 50%; }
  100% { background-position: 0%   50%; }
}

/* Title cell — name bar + owner row (reuses .pt-title-wrap / .pt-owner-badge layout) */
.skel-bar--title { width: 64%; height: 12px; }

.skel-avatar {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  flex-shrink: 0;
}
.skel-bar--owner { width: 70px; height: 9px; }

/* Generic description / text cell */
.skel-bar--desc { width: 80%; }
.skel-bar--date { width: 56px; }

/* Numeric pill cell (Publications / Approved / Awaiting) */
.skel-bar--num { width: 32px; height: 18px; border-radius: 20px; }

/* Status pill cell */
.skel-bar--status { width: 86px; height: 18px; border-radius: 20px; }

/* Action icon cell */
.skel-bar--icon { width: 26px; height: 26px; border-radius: 8px; }

/* Slight width variation row-to-row so the placeholder doesn't look
   like a perfectly uniform stack */
.skel-row:nth-child(2n)   .skel-bar--title { width: 50%; }
.skel-row:nth-child(3n)   .skel-bar--title { width: 72%; }
.skel-row:nth-child(4n+1) .skel-bar--title { width: 58%; }

.skel-row:nth-child(2n)   .skel-bar--desc  { width: 60%; }
.skel-row:nth-child(3n)   .skel-bar--desc  { width: 90%; }
.skel-row:nth-child(4n+1) .skel-bar--desc  { width: 70%; }

.skel-row:nth-child(3n)   .skel-bar--owner { width: 48px; }
.skel-row:nth-child(4n)   .skel-bar--owner { width: 88px; }

/* ──────────────────────────────────────────────────────────────────
   SIDEBAR — avatar + name
   ──────────────────────────────────────────────────────────────────
   #profile-avatar and #profile-label both start empty in the HTML
   (sidebar.js only ever calls .textContent = ..., never clears it
   back to '', so once real data lands these rules stop matching for
   good). Settings-modal fields (#popupAvatar, #popupName, etc.) and
   conversation history are intentionally NOT covered here — they're
   hidden until opened, so there's nothing to show a skeleton for.
─────────────────────────────────────────────────────────────────── */
.sidebar-avatar:has(#profile-avatar:empty) {
  background: linear-gradient(
    90deg,
    var(--bg-elevated) 25%,
    var(--border-hover) 37%,
    var(--bg-elevated) 63%
  );
  background-size: 400% 100%;
  animation: skelShimmer 1.4s ease-in-out infinite;
}

#profile-label:empty {
  flex: 0 0 auto; /* override .sidebar-user-name's flex:1 so it doesn't stretch full-width */
  display: inline-block;
  width: 84px;
  height: 11px;
  border-radius: 5px;
  background: linear-gradient(
    90deg,
    var(--bg-elevated) 25%,
    var(--border-hover) 37%,
    var(--bg-elevated) 63%
  );
  background-size: 400% 100%;
  animation: skelShimmer 1.4s ease-in-out infinite;
}

/* #profile-workspace starts empty in the HTML and only ever gets
   real text once wsd:ready/wsd:changed fires in sidebar.js — same
   self-clearing :empty pattern as #profile-label above. */
#profile-workspace:empty {
  display: inline-block;
  width: 60px;
  height: 9px;
  margin-top: 2px;
  border-radius: 5px;
  background: linear-gradient(
    90deg,
    var(--bg-elevated) 25%,
    var(--border-hover) 37%,
    var(--bg-elevated) 63%
  );
  background-size: 400% 100%;
  animation: skelShimmer 1.4s ease-in-out infinite;
}

/* ──────────────────────────────────────────────────────────────────
   INDEX — greeting heading
   ──────────────────────────────────────────────────────────────────
   #welcomeHeading starts empty; _setPageGreeting() in sidebar.js
   always sets a non-empty textContent ("Good morning, Name."), so
   this clears itself the same way as the sidebar fields above.
─────────────────────────────────────────────────────────────────── */
#welcomeHeading:empty {
  display: inline-block;
  width: 230px;
  height: 28px;
  border-radius: 8px;
  background: linear-gradient(
    90deg,
    var(--bg-elevated) 25%,
    var(--border-hover) 37%,
    var(--bg-elevated) 63%
  );
  background-size: 400% 100%;
  animation: skelShimmer 1.4s ease-in-out infinite;
}

@media (max-width: 480px) {
  #welcomeHeading:empty { width: 190px; height: 22px; }
}

@media (prefers-reduced-motion: reduce) {
  .skel-bar,
  .skel-avatar,
  .sidebar-avatar:has(#profile-avatar:empty),
  #profile-label:empty,
  #profile-workspace:empty,
  #welcomeHeading:empty {
    animation: none;
    background: var(--bg-elevated);
  }
}