/* atlas-showpiece.css — companion to atlas_showpiece.js.
   Attached BY the script at boot, never from the document head: exercises.html
   is inside the render-blocking stylesheet budget and none of these rules apply
   until the driver adds .sp-on. A visitor with JS off, no WebGL, or
   prefers-reduced-motion downloads this file never.

   Everything here is additive and scoped under .sp-on, so removing the script
   restores the page byte-for-byte. */

/* The field sits behind the whole document, not inside the grid: it is a
   backdrop the content floats over, and it must never intercept a click. */
.sp-field{
  position:fixed;
  inset:0;
  width:100%;
  height:100%;
  z-index:0;
  pointer-events:none;
  mix-blend-mode:screen;
  opacity:0;
  animation:spFieldIn 1400ms cubic-bezier(0.16,0.84,0.30,1) 120ms forwards;
}

@keyframes spFieldIn{ to{ opacity:1 } }

/* Content must out-rank the backdrop without a new stacking context fight. */
.sp-on main,
.sp-on header,
.sp-on footer{ position:relative; z-index:1 }

/* Cards get a transform origin and a transition only for the RETURN to rest.
   The lean itself is driven per-frame from the pointer, so transitioning it
   would fight the spring; transitioning only the idle state gives the settle
   without the lag. */
.sp-on .sp-card{
  transform-style:preserve-3d;
  transition:transform 420ms cubic-bezier(0.16,0.84,0.30,1),
             box-shadow 240ms ease-out,
             border-color 240ms ease-out;
  will-change:transform;
}

.sp-on .sp-card.sp-hot{
  transition:box-shadow 160ms ease-out, border-color 160ms ease-out;
  box-shadow:0 18px 42px -18px rgba(224,178,113,0.55),
             0 0 0 1px rgba(224,178,113,0.28) inset;
  border-color:rgba(224,178,113,0.42);
}

/* Proximity accent on the hovered card's own link — the gold only appears where
   the pointer is, so the grid stays calm everywhere else. */
.sp-on .sp-card.sp-hot a{
  color:#e0b271;
  text-shadow:0 0 12px rgba(224,178,113,0.35);
}

/* Screen-reader-only note. Defined HERE rather than assumed: `.sr-only` was
   found used-but-undefined on this very page once before, which left 18
   elements visible in production. A prefixed class with its own definition
   cannot inherit that bug. */
.sp-sr-only{
  position:absolute;
  width:1px;height:1px;
  padding:0;margin:-1px;
  overflow:hidden;
  clip:rect(0 0 0 0);
  clip-path:inset(50%);
  white-space:nowrap;
  border:0;
}

/* ---- CSS-only fallback (no WebGL) ---------------------------------------
   Three gradient layers on a perspective ancestor. translateZ separates them
   in real depth, and each drifts at a different rate from the same
   spring-damped --sp-flow the shader would have consumed — so the parallax is
   driven by the same physics, not a second ad-hoc easing. No images, no
   requests, one paint. */
.sp-fallback{
  position:fixed;
  inset:0;
  z-index:0;
  pointer-events:none;
  overflow:hidden;
  perspective:800px;
  perspective-origin:50% 40%;
  --sp-flow:0;
  opacity:0;
  animation:spFieldIn 1400ms cubic-bezier(0.16,0.84,0.30,1) 120ms forwards;
}

.sp-fb-layer{
  position:absolute;
  inset:-20%;
  background-repeat:no-repeat;
  will-change:transform;
}

/* Far layer: broad warm wash, moves least. */
.sp-fb-1{
  transform:translateZ(-600px) scale(1.75)
            translateY(calc(var(--sp-flow) * -18px));
  background:radial-gradient(120% 80% at 50% 10%, rgba(224,178,113,0.13), transparent 70%);
}

/* Mid layer: the fibre suggestion, repeating gradient standing in for the
   shader's striations. */
.sp-fb-2{
  transform:translateZ(-300px) scale(1.375)
            translateY(calc(var(--sp-flow) * -34px));
  background:repeating-linear-gradient(
    102deg,
    rgba(224,178,113,0.055) 0px,
    rgba(224,178,113,0.055) 2px,
    transparent 2px,
    transparent 11px);
}

/* Near layer: tight highlight, moves most — the depth cue. */
.sp-fb-3{
  transform:translateZ(-120px) scale(1.15)
            translateY(calc(var(--sp-flow) * -56px));
  background:radial-gradient(60% 40% at 30% 70%, rgba(224,178,113,0.10), transparent 65%);
}

.sp-fallback-on main,
.sp-fallback-on header,
.sp-fallback-on footer{ position:relative; z-index:1 }

/* Belt and braces: if a cached older script ever runs for a reduced-motion
   user, the cascade still refuses the motion. */
@media (prefers-reduced-motion: reduce){
  .sp-field{ display:none }
  .sp-fallback{ display:none }
  .sp-on .sp-card{ transition:none; transform:none !important; will-change:auto }
  .sp-on .sp-card.sp-hot{ box-shadow:0 0 0 1px rgba(224,178,113,0.28) inset }
}

/* Coarse pointers never hover, so the tilt layer is pure cost on touch. The
   field stays (it is scroll-driven and reads beautifully on a phone); the
   per-card 3D does not. */
@media (hover: none){
  .sp-on .sp-card{ transition:none; transform:none !important; will-change:auto }
}
