/* ============================================================
   VIDNEXA LOADING-STATE KIT — vx-skeletons.css
   Design Parity Wave 2 (2026-10-27): skeletons, poster-first
   media placeholders, and designed empty states.

   Token contract: every colour below reads the theme variables
   (--glass-border, --glass-bg-soft, --text-*, --accent,
   --card-radius / --vx-radius, --thumb-ratio). The theme file
   redefines those variables under body.dark-mode / body.grey-mode,
   so this kit follows light/dark automatically and inherits any
   future token convergence (Wave 1) with no edits here.
   ============================================================ */
:root{
  --vxsk-base: var(--glass-border, #e2e8f0);
  --vxsk-hi: color-mix(in srgb, var(--vxsk-base) 52%, #ffffff);
  --vxsk-shine: rgba(255,255,255,.55);
  --vxsk-radius: var(--card-radius, var(--vx-radius, 12px));
}
body.dark-mode, body.grey-mode{
  --vxsk-hi: color-mix(in srgb, var(--vxsk-base) 78%, #ffffff);
  --vxsk-shine: rgba(255,255,255,.09);
}

@keyframes vxsk-sweep{
  from{ transform:translateX(-100%); }
  to  { transform:translateX(100%); }
}
@keyframes vxsk-pan{
  from{ background-position:120% 0; }
  to  { background-position:-80% 0; }
}

/* ---- Base shimmer block ------------------------------------ */
.vxsk{
  position:relative;
  overflow:hidden;
  background:var(--vxsk-base);
  display:block;
}
.vxsk::after{
  content:"";
  position:absolute; inset:0;
  background:linear-gradient(100deg, transparent 25%, var(--vxsk-shine) 50%, transparent 75%);
  transform:translateX(-100%);
  animation:vxsk-sweep 1.4s ease-in-out infinite;
  pointer-events:none;
}

/* ---- Media underlay -----------------------------------------
   For media boxes whose poster/thumbnail is still in flight
   (hero frame, vidlet stage): a panning placeholder that paints
   UNDER the media (generated as the first child) so the wait is
   a designed surface, never a black void. The media itself is
   server-rendered and covers this the moment it paints. */
.vxsk-underlay{ position:relative; background:var(--vxsk-base); }
.vxsk-underlay::before{
  content:"";
  position:absolute; inset:0; z-index:0;
  background:linear-gradient(100deg, var(--vxsk-base) 40%, var(--vxsk-hi) 50%, var(--vxsk-base) 60%);
  background-size:200% 100%;
  animation:vxsk-pan 1.6s ease-in-out infinite;
  pointer-events:none;
}

/* Static placeholder for image containers (many instances on a
   page — no animation cost; the image covers it when loaded). */
.vxsk-media{ background:var(--vxsk-base); }

/* Home hero (poster-first): the media elements hard-code a black
   background, which paints over the poster layer while the player
   is still in flight. Transparent lets the server-rendered poster
   (and, before it arrives, the underlay shimmer) show instead.
   Once the player paints frames, its background is never visible,
   so the settled state is unchanged. */
.vx-hero-media.vxsk-underlay iframe,
.vx-hero-media.vxsk-underlay video{ background:transparent; }
/* Poster-link hero variant: keep the in-flow poster image above
   the underlay's panning layer. */
a.vx-hero-thumb.vxsk-underlay > img{ position:relative; z-index:1; }

/* ---- Atomic pieces ------------------------------------------ */
.vxsk-thumb{ aspect-ratio:var(--thumb-ratio, 16 / 9); border-radius:var(--vxsk-radius); }
.vxsk-thumb--vertical{ aspect-ratio:9 / 16; }
.vxsk-line{ height:12px; border-radius:6px; }
.vxsk-line--sm{ height:10px; }
.vxsk-line--lg{ height:16px; border-radius:8px; }
.vxsk-avatar{ width:36px; height:36px; border-radius:50%; flex:0 0 auto; }
.vxsk-lines{ flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:8px; padding-top:2px; }

/* ---- Card skeleton (mirrors .video-card-box geometry) ------- */
.vxsk-card{ display:block; }
.vxsk-card .vxsk-meta{ display:flex; gap:10px; padding-top:10px; padding-bottom:12px; }
.vxsk-card--rail{ width:var(--card-width-xs, 240px); flex:0 0 auto; }
.vxsk-card--rail .vxsk-thumb{ border-radius:var(--vxsk-radius); }

/* ---- Rail skeleton (horizontal shelf) ------------------------ */
.vxsk-rail{ display:flex; gap:var(--card-gap, 20px); overflow:hidden; }
.vxsk-rail .vxsk-card{ flex:0 0 auto; width:var(--card-width-xs, 240px); }

/* ---- Chip-row skeleton --------------------------------------- */
.vxsk-chiprow{ display:flex; gap:12px; overflow:hidden; padding:8px 0; }
.vxsk-chip{ height:44px; border-radius:20px; flex:0 0 auto; }

/* ---- Player-block skeleton ----------------------------------- */
.vxsk-player{ aspect-ratio:16 / 9; border-radius:var(--vxsk-radius); width:100%; }

/* ---- List-row skeleton (search rows: 360px thumb + lines) ---- */
.vxsk-row{ display:flex; gap:16px; padding-bottom:28px; width:100%; box-sizing:border-box; }
.vxsk-row .vxsk-thumb{ flex:0 0 360px; width:360px; max-width:42%; }
.vxsk-row .vxsk-lines{ padding-top:4px; gap:10px; }
@media (max-width:768px){
  .vxsk-row{ flex-direction:column; gap:10px; }
  .vxsk-row .vxsk-thumb{ flex:none; width:100%; max-width:100%; }
}

/* ---- Poster-first hooks into existing surfaces ---------------
   These only change what a surface looks like WHILE its image
   is in flight; the loaded state is untouched (the image covers
   the placeholder). Higher specificity is deliberate: several
   surfaces hard-code a black media background in late <style>
   blocks, and a loading state must win over that. */
/* Home / channel / search video cards (shared component). */
.video-card-box .thumb-container{ background:var(--vxsk-base); }
/* Search result rows: replace the black thumb box while loading. */
.sr-list .sr-thumb, #video-container .sr-thumb{ background:var(--vxsk-base); }
.sr-vidlet-thumb{ background:var(--vxsk-base); }
/* Channel featured-video thumbnail while its poster is in flight. */
.yt-featured-thumbnail{ background:var(--vxsk-base); }
/* Vidlets stage: shimmer under the poster, and the poster image
   itself must not paint its own black background over it. */
.card .vxp-stage{ isolation:isolate; }
.card .vxp-stage::before{
  content:"";
  position:absolute; inset:0; z-index:0;
  background:linear-gradient(100deg, #1b1b1f 40%, #2c2c33 50%, #1b1b1f 60%);
  background-size:200% 100%;
  animation:vxsk-pan 1.6s ease-in-out infinite;
  pointer-events:none;
}
.card .vxp-stage img.v-poster{ background:transparent; }
/* Same treatment for the media element itself (playerx paints it
   black); the poster layer above it carries the wait, and frames
   cover the background once playing. */
.card .vxp-stage .v{ background:transparent; }

/* ---- Designed empty state -------------------------------------
   One component: icon in a soft circle, one title, one line,
   one optional action. Matches the pattern the playlists tab and
   the library/history pages already use. */
.vxsk-empty{
  text-align:center;
  padding:56px 20px;
  display:flex; flex-direction:column; align-items:center;
  width:100%; box-sizing:border-box;
}
.vxsk-empty-icon{
  width:72px; height:72px; border-radius:50%;
  background:var(--vxsk-base);
  color:var(--text-muted, #64748b);
  display:flex; align-items:center; justify-content:center;
  margin-bottom:16px; flex:0 0 auto;
}
.vxsk-empty-icon svg{ width:34px; height:34px; fill:currentColor; display:block; }
.vxsk-empty h3{
  font-size:17px; font-weight:600; line-height:1.35;
  color:var(--text-primary, #0f172a);
  margin:0 0 6px;
}
.vxsk-empty p{
  font-size:14px; line-height:1.5;
  color:var(--text-secondary, #475569);
  margin:0; max-width:440px;
}
.vxsk-empty-btn{
  margin-top:18px;
  display:inline-flex; align-items:center; justify-content:center;
  min-height:40px; padding:0 18px;
  border-radius:999px;
  background:var(--accent, #2563eb); color:#fff;
  font-size:14px; font-weight:600; text-decoration:none;
  border:0; cursor:pointer;
}
.vxsk-empty-btn:hover{ filter:brightness(.93); color:#fff; text-decoration:none; }
/* On-dark variant (vidlets stage, dark shelves). */
.vxsk-empty--dark h3{ color:#fff; }
.vxsk-empty--dark p{ color:rgba(255,255,255,.65); }
.vxsk-empty--dark .vxsk-empty-icon{ background:rgba(255,255,255,.10); color:rgba(255,255,255,.75); }

/* ---- Loading error row (infinite scroll failure) ------------- */
.vxsk-loaderror{
  display:flex; align-items:center; justify-content:center; gap:12px;
  flex:0 0 100%; width:100%; padding:18px 12px; box-sizing:border-box;
  color:var(--text-secondary, #475569); font-size:14px;
}
.vxsk-loaderror button{
  min-height:40px; padding:0 16px; border-radius:999px;
  border:1px solid var(--glass-border, #e2e8f0);
  background:var(--glass-bg, #fff); color:var(--text-primary, #0f172a);
  font-size:14px; font-weight:600; cursor:pointer;
}

@media (prefers-reduced-motion: reduce){
  .vxsk::after{ animation:none; }
  .vxsk-underlay::before{ animation:none; }
  .card .vxp-stage::before{ animation:none; }
}
