/* Hero motion. Nothing here changes the layout the Figma specifies — every
   animation starts offset and lands on the design's own position. */

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

  /* ---------- entrance ---------- */

  .nav,
  .hero-title > span,
  .hero-sub,
  .hero-actions,
  .showcase,
  .logos {
    animation: rise 900ms cubic-bezier(0.16, 1, 0.3, 1) backwards;
  }

  .nav                        { animation-delay: 80ms;  }
  .hero-title > span:first-child { animation-delay: 160ms; }
  .hero-title > span:last-child  { animation-delay: 260ms; }
  .hero-sub                   { animation-delay: 360ms; }
  .hero-actions               { animation-delay: 460ms; }
  .logos                      { animation-delay: 760ms; }

  @keyframes rise {
    from { opacity: 0; transform: translateY(24px); }
    to   { opacity: 1; transform: translateY(0); }
  }

  /* The product shot is centred with translateX(-50%), so its entrance has to
     carry that transform through or it jumps sideways. */
  .showcase {
    animation-name: rise-centred;
    animation-delay: 560ms;
    animation-duration: 1100ms;
  }

  @keyframes rise-centred {
    from { opacity: 0; transform: translateX(-50%) translateY(48px) scale(0.975); }
    to   { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
  }

  .hero-copy { animation: none; }

  /* The logo wall reads as one object, so the marks stagger inside it rather
     than each fading in from nothing. */
  .logo { animation: logo-in 700ms ease-out backwards; }
  .logo-1 { animation-delay: 820ms; }
  .logo-2 { animation-delay: 880ms; }
  .logo-3 { animation-delay: 940ms; }
  .logo-4 { animation-delay: 1000ms; }
  .logo-5 { animation-delay: 1060ms; }
  .logo-6 { animation-delay: 1120ms; }

  @keyframes logo-in {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
  }

  /* ---------- continuous ---------- */

  /* Slow drift on the background artwork. Scaled up first so the drift never
     exposes an edge. */
  .hero-art-clip img {
    animation: drift 28s ease-in-out infinite alternate;
    will-change: transform;
  }

  /* Only as much zoom as the drift's own travel needs. It used to run to 1.12,
     which ate the corner of the mark inside the clip. */
  @keyframes drift {
    from { transform: scale(1.01) translate(0, 0); }
    to   { transform: scale(1.04) translate(-1.5%, 1%); }
  }

  /* The brand is chrome, so light travels across the mark rather than the
     mark itself moving. Long pause, one quick pass. */
  /* A wider, brighter band than a hairline glint: on chrome the reflection
     has to be readable at 46px, not just technically present. */
  .brand-sheen {
    background: linear-gradient(104deg,
      transparent 32%,
      rgba(255, 255, 255, 0.35) 42%,
      rgba(255, 255, 255, 0.95) 50%,
      rgba(255, 255, 255, 0.35) 58%,
      transparent 68%);
    background-size: 320% 100%;
    background-position: 130% 0;
    animation: logo-sheen 9s linear 1.5s infinite;
  }

  /* The pass takes 3.6s of the 9s cycle; the rest is a neutral hold, and the
     band is off the mark at both ends so the wrap is invisible. */
  @keyframes logo-sheen {
    0%, 50%     { background-position: 130% 0; }
    90%, 100%   { background-position: -30% 0; }
  }

  /* ---------- the record writing itself ---------- */
  /* Hidden only while motion is welcome: with reduced motion the whole record
     is simply there, which is the frame that tells the story anyway. */

  .trail li {
    opacity: 0;
    transform: translateY(3px);
    transition: opacity 320ms ease, transform 320ms ease;
  }

  .trail li.is-in { opacity: 1; transform: none; }

  .verdict { opacity: 0; transition: opacity 360ms ease; }

  .verdict.is-in { opacity: 1; }

  .verdict p span { opacity: 0; transition: opacity 220ms ease; }

  .verdict p span.is-in { opacity: 1; }

  /* ---------- pointer parallax ---------- */
  /* Scoped to .is-settled, which the script adds once the entrance has
     finished — otherwise the two would fight over `transform`.
     --px / --py are the cursor offset from centre, -1 to 1. */

  .is-settled .hero-art  { transform: translate3d(calc(var(--px, 0) * 18px), calc(var(--py, 0) * 12px), 0); }
  .is-settled .showcase  { transform: translateX(-50%) translate3d(calc(var(--px, 0) * -7px), calc(var(--py, 0) * -5px), 0); }
  .is-settled .hero-copy { transform: translateX(-50%) translate3d(calc(var(--px, 0) * -3px), calc(var(--py, 0) * -2px), 0); }

  .is-settled .hero-art,
  .is-settled .showcase,
  .is-settled .hero-copy { transition: transform 600ms cubic-bezier(0.22, 1, 0.36, 1); }
}

/* Sections rise as they come into view, the way cursor.com reveals its page.
   Plain CSS and one observer; no animation library. */
@media (prefers-reduced-motion: no-preference) {
  [data-reveal] {
    opacity: 0;
    transform: translateY(22px);
    transition: opacity 700ms cubic-bezier(0.16, 1, 0.3, 1), transform 700ms cubic-bezier(0.16, 1, 0.3, 1);
  }

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

/* The halftone radiates: rings of dots travel outward from the mark, like a
   signal leaving it. Two rings, half a cycle apart, so the pulse is
   continuous without either ring ever being obvious on its own. */
@media (prefers-reduced-motion: no-preference) {
  .halo-a, .halo-b {
    display: block;
    opacity: 0;
    animation: halo-out 4s cubic-bezier(0.22, 1, 0.3, 1) infinite;
    will-change: transform, opacity;
  }

  .halo-b { animation-delay: 2s; }

  @keyframes halo-out {
    0%   { transform: scale(0.72); opacity: 0; }
    18%  { opacity: 0.75; }
    100% { transform: scale(1.9); opacity: 0; }
  }

  /* The resting field breathes very slightly against the travelling rings,
     so the centre does not sit perfectly static under moving dots. */
  .halo-rest { animation: halo-rest 4s ease-in-out infinite; }

  @keyframes halo-rest {
    0%, 100% { opacity: 0.5; }
    50%      { opacity: 0.68; }
  }
}

/* The manager's answer writes itself, the way it does in the product. The
   buttons wait until the sentence is finished. */
@media (prefers-reduced-motion: no-preference) {
  [data-stream] span { opacity: 0; transition: opacity 200ms ease; }

  [data-stream] span.is-in { opacity: 1; }

  .chat-acts { opacity: 0; transform: translateY(6px); transition: opacity 400ms ease, transform 400ms ease; }

  .chat-acts.is-in { opacity: 1; transform: none; }

  /* Changing step swaps both panes at once, so the screen reads as one
     screen responding rather than two boxes updating separately. */
  .how-main, .chat-body { animation: pane-in 420ms cubic-bezier(.22, 1, .3, 1) both; }

  @keyframes pane-in {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
  }
}
