/* ==================================================================
   BrainScores — appear animations

   Values are taken from the design's own components, not invented.
   The `js` class is set inline in <head>, so without scripting every
   block simply stays visible from the start.
   ================================================================== */

:root {
  /* stand-ins for the design's springs, named by bounce amount */
  --spring-0: cubic-bezier(.33, 1, .68, 1);
  --spring-1: cubic-bezier(.28, 1.12, .6, 1);
  --spring-2: cubic-bezier(.34, 1.25, .64, 1);
  /* stiffness 500, damping 60, mass 1 — overdamped, no overshoot */
  --spring-over: cubic-bezier(.22, .53, .15, 1);
}

/* ---------- appear animations ----------
   Values taken from the design's own components, not invented:

     cards    (.framer-kcuxx6)  fade only, spring bounce .2, 0.4s,
                                threshold 0, plays once
     captions (section labels)  fade only, spring bounce .2, 0.6s,
                                threshold .5, replays on re-entry
     nav      load              fade, 0.8s
     wordmark load              from x -150, 0.6s, delay .4
     subtitle load              from y 10,   0.6s, delay .4
     headline / lead paragraph  per line: opacity + y 10, 0.6s,
                                0.075s apart, threshold .5

   The springs are matched with beziers: bounce .2 overshoots slightly,
   bounce 0 does not. The js flag is set inline in <head>, so without
   scripting every block is simply visible from the start. */

.js [data-appear] {
  transition-property: opacity, transform;
  transition-duration: .6s;
  transition-timing-function: var(--spring-2);
}
.js [data-appear]:not(.is-in) { opacity: 0; }

.js [data-appear="card"]      { transition-duration: .4s; }
.js [data-appear="load-fade"] { transition-duration: .8s; }

.js [data-appear="load-left"] { transition-delay: .4s; transition-timing-function: var(--spring-1); }
.js [data-appear="load-left"]:not(.is-in) { transform: translateX(-150px); }

.js [data-appear="load-up"]   { transition-delay: .4s; }
.js [data-appear="load-up"]:not(.is-in)   { transform: translateY(10px); }

.js [data-appear].is-in { opacity: 1; transform: none; }

/* per-line text reveal */
.js [data-lines] .ln {
  display: inline-block;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .6s var(--spring-0), transform .6s var(--spring-0);
}
.js [data-lines].is-in .ln { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .js [data-appear],
  .js [data-lines] .ln { opacity: 1; transform: none; transition: none; }
}

/* ---------- tilt on arrival ----------
   The design gives these blocks a transform effect, not an appear one:
   they start tilted back and settle flat when they reach the viewport.

     start   perspective 1200, scale 1.1, rotateX 20
     end     perspective 1200, scale 1,   rotateX 0
     spring  stiffness 500, damping 60, mass 1

   That spring is overdamped, so it never overshoots. It settles to
   99.5% in 0.553s, and the bezier below tracks it to within 1.8%.

   On phones the design turns the effect off for the wide blocks and
   softens it to 12 degrees for the two carousels. */

.js [data-tilt] {
  transition: transform .55s var(--spring-over);
}
.js [data-tilt]:not(.is-in) {
  transform: perspective(1200px) scale(1.1) rotateX(20deg);
}
.js [data-tilt].is-in {
  transform: perspective(1200px);
}

@media (max-width: 809.98px) {
  .js [data-tilt="20-off"] { transition: none; }
  .js [data-tilt="20-off"]:not(.is-in) { transform: perspective(1200px); }
  .js [data-tilt="20-12"]:not(.is-in) {
    transform: perspective(1200px) scale(1.1) rotateX(12deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .js [data-tilt] { transform: perspective(1200px); transition: none; }
}
