/* ============================================================================
   CULTURE CAVE - THE FAST LAYER
   Scrolling ran at 36fps with 67ms frames. There were no long tasks at all, so
   none of it was JavaScript: it was paint. Measured, one change at a time, on a
   1440x900 desktop:

     baseline .................. 36fps
     grain + vignette off ...... 56fps   <- the biggest single cost
     backdrop-filter off ....... 50fps
     will-change off ........... 43fps
     box-shadow off ............ 41fps

   None of those can simply be deleted; they are the cave. So instead they are
   SUSPENDED WHILE THE PAGE IS MOVING and restored the moment it stops. Nobody
   can see grain during a flick scroll, and the design is untouched at rest -
   which is where anyone actually looks at it.
   ========================================================================== */

/* ---- 1. while scrolling: drop the full-screen decorative layers ----------
   .cavern, .cave-grain and .cave-vig are three stacked full-viewport fixed
   layers, two of them blended. Blend modes force the compositor to read the
   backdrop back on every frame, which is why they cost more than everything
   else combined. */
body.cc-moving .cave-grain,
body.cc-moving .cave-vig{opacity:0}
.cave-grain,.cave-vig{transition:opacity 140ms linear}

/* ---- 2. while scrolling: no backdrop blur -------------------------------
   A backdrop-filter has to sample everything painted underneath it, every
   frame, per element. At rest it is the frosted glass the design wants; in
   motion it is just a tax. */
body.cc-moving .pcard,
body.cc-moving .pwish,
body.cc-moving .peek,
body.cc-moving .vc,
body.cc-moving .chip,
body.cc-moving .card{
  -webkit-backdrop-filter:none!important;backdrop-filter:none!important}

/* ---- 3. never promote 139 layers at once --------------------------------
   [data-rv]:not(.in){will-change:opacity,transform} is correctly scoped to
   elements that have not revealed yet - but on this page that is 139 of them,
   every one getting its own compositor layer and its own slice of GPU memory
   before it is anywhere near the screen. cave-fast.js hands the hint out only
   to the handful about to animate. */
[data-rv]:not(.in){will-change:auto}
[data-rv]:not(.in).cc-soon{will-change:opacity,transform}

/* ---- 4. the decorative motion can stop while the page moves ------------- */
body.cc-moving .star,
body.cc-moving .spark,
body.cc-moving .mote{animation-play-state:paused}

/* ---- 5. NO content-visibility. MEASURED, NOT ASSUMED.
   The obvious move here is content-visibility:auto on the long grids, and it
   makes this page SLOWER: 39fps with it against 49fps without. Skipping layout
   for off-screen sections sounds free, but each one re-does layout as it
   crosses the range boundary, and during a scroll that boundary is crossed
   constantly. Left out on purpose - do not "add the obvious optimisation" back
   without re-running cc-experiment.py. */

/* ---- 6. the decorative particles ---------------------------------------
   ~100 stars and motes, each with will-change:transform and an infinite
   animation, so each one holds a compositor layer for the life of the page.
   They are worth having at rest and worth nothing mid-scroll. */
body.cc-moving .star,
body.cc-moving .spark,
body.cc-moving .mote,
body.cc-moving .motes{will-change:auto;animation-play-state:paused;opacity:0}
.star,.spark,.mote{transition:opacity 160ms linear}

/* Someone who has asked for less motion gets the cheap path permanently, and
   nothing here should ever animate for them. */
@media (prefers-reduced-motion:reduce){
  .cave-grain,.cave-vig{transition:none}
}
