/* StarKid perf guard (styles) — loaded after cosmetics.css / cosmetics-shop.css.
   ---------------------------------------------------------------------------
   Companion to assets/perf-guard.js. Three jobs, all invisible on screen:

   1. PAUSE WHAT ISN'T VISIBLE.  .cx-perf-rest is added by the JS to anything that
      scrolled out of view (or is over the concurrent-animation budget), and
      html.cx-perf-hidden to the whole page while the tab is in the background.
      Pausing (not removing) keeps the exact frame, so scrolling back looks right.

   2. STOP PAINTING WHAT ISN'T VISIBLE.  content-visibility:auto skips layout and
      paint for off-screen list items, cards and tiles entirely.
      contain-intrinsic-size keeps the scrollbar honest so nothing jumps.
      Applied only to list-ish elements (never to a generic container): both
      pop-ups mount on <body>, so nothing inside them is ever contained.

   3. ANIMATE THE CHEAP WAY.  A few keyframes moved a full-screen background with
      background-position (the browser re-paints the whole viewport every frame) or
      animated filter:brightness()/blur() (re-blurring every frame). Those are
      redefined below to move/scale the layer with transform instead — same look,
      but the GPU can do it on its own while the main thread stays free.
      Redefining a @keyframes name later in the cascade replaces it, so the
      originals in cosmetics.css are untouched and easy to restore. */

/* ---------- 1. pause what isn't visible ---------- */
.cx-perf-rest,
.cx-perf-rest *,
.cx-perf-rest *::before,
.cx-perf-rest *::after { animation-play-state: paused !important; }

html.cx-perf-hidden *,
html.cx-perf-hidden *::before,
html.cx-perf-hidden *::after { animation-play-state: paused !important; }

/* ---------- 2. don't paint what isn't visible ---------- */
.cxs-tile,
.cx-card,
.sr-post {
  content-visibility: auto;
  contain-intrinsic-size: auto 320px;   /* roughly a tile tall: keeps scrolling stable */
}
.leaderboard-row { content-visibility: auto; contain-intrinsic-size: auto 68px; }
.cxs-hero { contain: content; }         /* always on screen, but keep its paint contained */

/* ---------- 3. cheap animations ---------- */
/* Only the patterns that are pure tiles are converted, and each of those gets an
   overscan so the drift can never reveal an edge. Themes whose look depends on
   where a gradient sits (Inferno's glow, Gold Rush's sweep) are deliberately left
   exactly as they are — the guard still pauses them when they scroll away. */

/* Tiled full-screen patterns: overscan once, then drift with transform. Moving a
   background meant the browser repainted the whole viewport every frame. */
body[data-cx-theme="theme_neon_brick"]::after,
body[data-cx-theme="theme_cyber_grid"]::after,
body[data-cx-theme="theme_sakura"]::after {
  inset: -30% !important;
  will-change: transform;
  backface-visibility: hidden;
}
@keyframes cxBrickDrift { to { transform: translate3d(96px, 64px, 0); } }
@keyframes cxGridScroll { to { transform: translate3d(0, 56px, 0); } }
@keyframes cxPetals { to { transform: translate3d(-60px, 160px, 0); } }

/* Aurora: the same soft drift, done by moving the layer instead of the gradient.
   The 18px blur is rasterised once and the compositor moves it — no per-frame
   re-blur. Sized 140% by the theme itself, so a 2% shift cannot expose an edge. */
body[data-cx-theme="theme_aurora"]::after { will-change: transform; }
@keyframes cxAurora {
  0% { transform: translate3d(-2%, -1.5%, 0) scale(1); }
  100% { transform: translate3d(2%, 2%, 0) scale(1.06); }
}

/* Elements that must never be paused (the page's own hero, if a page marks one). */
.cx-perf-always, .cx-perf-always * { animation-play-state: running !important; }

/* Reduce work further for people who ask for less motion — same as the existing
   reduced-motion rules, restated here so this file alone is self-sufficient. */
@media (prefers-reduced-motion: reduce) {
  .cx-prev::before, .cx-prev::after,
  .cx-banner::before, .cx-banner::after,
  body[data-cx-theme]::after { animation: none !important; }
}


/* ---------- 4. low-end devices: stop paying for decoration ---------- */
/* html.cx-perf-lite is set by perf-guard.js when the device reports few cores,
   little memory, a save-data connection, or a touch-only small screen. These rules
   only ever touch full-screen decoration, never the interface. */

/* The ambient glow behind the Stick Revelation hero: a 23px blur over the whole
   viewport, blended with mix-blend-mode every frame. Replaced by a flat, still
   wash -- the same colours, none of the per-frame cost. */
html.cx-perf-lite .sr-ambient-lights {
  filter: none !important;
  mix-blend-mode: normal !important;
  animation: none !important;
  opacity: .34 !important;
  will-change: auto !important;
}

/* The same idea for an equipped UI theme's full-screen layer. */
html.cx-perf-lite body[data-cx-theme]::after {
  filter: none !important;
  animation-duration: 0s !important;
  animation-iteration-count: 1 !important;
  will-change: auto !important;
}

/* Glass panels: the blur is what makes them expensive, because everything behind
   them is re-sampled on every paint. A near-opaque panel reads the same. */
html.cx-perf-lite .cxs-chip,
html.cx-perf-lite .cxs-modal-bg,
html.cx-perf-lite .cxb-bg,
html.cx-perf-lite .gx-pack-tiers .gx-tier-chip,
html.cx-perf-lite .gx-hero,
html.cx-perf-lite .gx-pack {
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
}
html.cx-perf-lite .cxs-modal-bg,
html.cx-perf-lite .cxb-bg { background: rgba(2, 4, 9, .94) !important; }
html.cx-perf-lite .gx-hero,
html.cx-perf-lite .gx-pack { background: rgba(6, 9, 15, .96) !important; }

/* Cosmetic previews: keep the tile, drop the animated sheen sweeping it. */
html.cx-perf-lite .cxs-pv-art,
html.cx-perf-lite .cx-prev { animation: none !important; }

/* Layer promotion is a promise of GPU memory; on a weak device it is a liability. */
html.cx-perf-lite .sr-ambient-lights,
html.cx-perf-lite .sr-grid,
html.cx-perf-lite .sr-hero-art { will-change: auto !important; }
/* On phones the video background already disables glass blur; also stop promoting
   layers we no longer need, so the compositor keeps a small layer tree. */
@media (max-width: 900px) {
  body[data-cx-theme]::after { will-change: auto; }
}
