/* ===================================================================
   motion.css — continuous ambient motion for every diagram.

   site.css already animates a diagram once, as it arrives. That is an
   entrance, and an entrance is over. Everything below keeps running, so a
   figure the visitor is looking at is never a still picture.

   Rules held throughout:
     - Every loop returns exactly to the drawn state, so the resting frame
       is always the correct one. Nothing here changes what a diagram says.
     - Motion is small and slow. The page should feel alive, not restless.
     - Nothing loops faster than 2.4s and nothing moves more than 3px.
     - The whole file is inside prefers-reduced-motion: no-preference, so
       reduced motion gets the still, correct diagram and nothing else.
   =================================================================== */

@media (prefers-reduced-motion: no-preference) {

    /* --- 1. Figure float: removed ---------------------------------------
     Nineteen figures each drifting 3px on their own cycle read as wobble
     rather than as life, and it fought the flex centring that now lets a
     diagram grow into its card. The motion that earns its place is the
     kind that means something: the wave through a point field, the gap
     travelling a curve, the scan across a schedule. Drift means nothing,
     so it is gone. */

/* --- 2. Shimmer across dense point fields ---------------------------
     A slow wave of brightness travels through a dot matrix or block grid,
     so a field of 1,015 dots reads as a living population rather than a
     texture. Opacity only: position and colour never change. */
  @keyframes cell-wave {
    /* Smooth, not snappy. The travel fills the cycle instead of happening in
       80ms and holding, and the range is small so a field of a thousand marks
       breathes rather than flickers. */
    0%   { opacity: 1;   transform: translateY(0) scale(1); }
    50%  { opacity: .62; transform: translateY(-2px) scale(.88); }
    100% { opacity: 1;   transform: translateY(0) scale(1); }
  }
  .card__art .pop,
  .proj__art .pop {
    transform-box: fill-box;
    transform-origin: center;
    animation: cell-wave 3.4s ease-in-out infinite;
  }
  .card__art .pop:nth-of-type(6n+1) { animation-delay: -0.0s; }
  .card__art .pop:nth-of-type(6n+2) { animation-delay: -0.7s; }
  .card__art .pop:nth-of-type(6n+3) { animation-delay: -1.4s; }
  .card__art .pop:nth-of-type(6n+4) { animation-delay: -2.1s; }
  .card__art .pop:nth-of-type(6n+5) { animation-delay: -2.8s; }
  .card__art .pop:nth-of-type(6n+6) { animation-delay: -3.5s; }
  .proj__art .pop:nth-of-type(4n+2) { animation-delay: -1.05s; }
  .proj__art .pop:nth-of-type(4n+3) { animation-delay: -2.10s; }
  .proj__art .pop:nth-of-type(4n+4) { animation-delay: -3.15s; }

  /* --- 3. The travelling gap: removed --------------------------------
     A 0.85/0.15 dash moving along a stroke is a highlight on a curve and a
     missing segment on a straight data line. Every chart here draws its
     series as a polyline, so two of the mujoco series were rendering as
     broken lines. A measured number drawn on a broken line is a number
     nobody believes. The strokes are solid, and motion is carried by the
     things that can afford it: the point fields and the schedule scan. */

  /* --- 4. Endpoint pulse ----------------------------------------------
     The marker a diagram wants you to end on breathes gently. Radius is
     animated rather than scale so it cannot drift off its own coordinate. */
  @keyframes end-pulse {
    0%   { opacity: 1; }
    50%  { opacity: .58; }
    100% { opacity: 1; }
  }
  .pulse { animation: end-pulse 2.8s ease-in-out infinite; }

  /* --- 5. Hairline drift on axes --------------------------------------
     Axis rules and guide lines breathe very slightly, which stops a chart
     from looking printed. */
  @keyframes rule-breathe {
    0%, 100% { opacity: .9; }
    50%      { opacity: .62; }
  }
  .card__art line[stroke*="hair"],
  .proj__art line[stroke*="hair"] {
    animation: rule-breathe 5.2s ease-in-out infinite;
  }

  /* --- 6. Pause on hover ----------------------------------------------
     A visitor reading a specific figure can stop it moving by pointing at
     it. Nothing is lost: every loop rests at the drawn state. */
  .card:hover .card__art svg,
  .card:hover .card__art svg *,
  .proj:hover .proj__art svg,
  .proj:hover .proj__art svg * {
    animation-play-state: paused;
  }

  /* --- 7. The opening line arrives ------------------------------------
     "Hi, I'm Teerth." is the first thing anyone reads, and it was simply
     present. It now rises into place with the subhead a beat behind it,
     once, on load. Both animate from a visible end state, so if the
     animation never runs the words are already where they belong. */
  @keyframes line-rise {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: translateY(0); }
  }
  .hero__h1   { animation: line-rise 460ms cubic-bezier(.2,.7,.3,1) both; }
  .hero__sub  { animation: line-rise 460ms cubic-bezier(.2,.7,.3,1) 130ms both; }
  .hero__note { animation: line-rise 460ms cubic-bezier(.2,.7,.3,1) 240ms both; }

  /* --- 8. The wall of marks breathes ----------------------------------
     A pulse travels across the eleven proof cells, one after another, so
     the wall reads as something live rather than a sheet of stickers. The
     glow is a soft blue-tinted shadow rather than a dark one, because the
     page has no dark surfaces and a grey drop shadow would dirty the
     ground. Each cell also lifts under the pointer.
     The mark itself desaturates slightly at rest and comes to full colour
     as the pulse passes, which is what makes the wall look like it is
     being read rather than displayed. */
  @keyframes cell-glow {
    0%, 100% { box-shadow: var(--e1); }
    50%      { box-shadow: 0 1px 0 #fff inset,
                           0 2px 6px rgba(36,86,220,.16),
                           0 10px 26px rgba(36,86,220,.14); }
  }
  @keyframes mark-wake {
    0%, 100% { filter: saturate(.80) opacity(.88); }
    50%      { filter: saturate(1) opacity(1); }
  }
  .proofcell { animation: cell-glow 5.6s ease-in-out infinite; }
  .proofcell__org,
  .proofcell img { animation: mark-wake 5.6s ease-in-out infinite; }

  .proofcell:nth-of-type(1)  { animation-delay: 0ms; }
  .proofcell:nth-of-type(2)  { animation-delay: 100ms; }
  .proofcell:nth-of-type(3)  { animation-delay: 200ms; }
  .proofcell:nth-of-type(4)  { animation-delay: 300ms; }
  .proofcell:nth-of-type(5)  { animation-delay: 400ms; }
  .proofcell:nth-of-type(6)  { animation-delay: 500ms; }
  .proofcell:nth-of-type(7)  { animation-delay: 600ms; }
  .proofcell:nth-of-type(8)  { animation-delay: 700ms; }
  .proofcell:nth-of-type(9)  { animation-delay: 800ms; }
  .proofcell:nth-of-type(10) { animation-delay: 900ms; }
  .proofcell:nth-of-type(11) { animation-delay: 1000ms; }
  .proofcell:nth-of-type(1)  .proofcell__org { animation-delay: 0ms; }
  .proofcell:nth-of-type(2)  .proofcell__org { animation-delay: 100ms; }
  .proofcell:nth-of-type(3)  .proofcell__org { animation-delay: 200ms; }
  .proofcell:nth-of-type(4)  .proofcell__org { animation-delay: 300ms; }
  .proofcell:nth-of-type(5)  .proofcell__org { animation-delay: 400ms; }
  .proofcell:nth-of-type(6)  .proofcell__org { animation-delay: 500ms; }
  .proofcell:nth-of-type(7)  .proofcell__org { animation-delay: 600ms; }
  .proofcell:nth-of-type(8)  .proofcell__org { animation-delay: 700ms; }
  .proofcell:nth-of-type(9)  .proofcell__org { animation-delay: 800ms; }
  .proofcell:nth-of-type(10) .proofcell__org { animation-delay: 900ms; }
  .proofcell:nth-of-type(11) .proofcell__org { animation-delay: 1000ms; }

  .proofcell:hover,
  .proofcell:focus-visible { animation-play-state: paused; }

}

/* Loop durations are held at 900ms or slower on purpose. A repeating
   animation at 30ms is 33 cycles per second, which is inside the 3 to 60Hz
   band associated with photosensitive seizures, and this page animates over a
   thousand elements at once. Responses to a pointer or a key are a different
   thing and are set to 30ms, because those fire once and should feel instant.
   Do not lower the loop floor. */
