/* ==========================================================================
   EFFECTS — everything that moves. Only inside .fx and only when the visitor
   has not asked for reduced motion. Without it, everything is simply visible.
   ========================================================================== */

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

  /* One orchestrated page-load moment in the hero: headline lines rise,
     then the window settles into place, then the terminal starts typing (JS). */
  .fx .hero h1 .line > span { transform: translateY(110%); animation: line-up 1.1s var(--ease-out) forwards; animation-delay: calc(.1s + var(--i, 0) * .12s); }
  @keyframes line-up { to { transform: none; } }
  .fx .hero [data-rise] { opacity: 0; animation: rise .9s var(--ease-out) forwards; animation-delay: calc(.45s + var(--i, 0) * .12s); }
  @keyframes rise { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
  .fx .hero__win .win { opacity: 0; animation: win-in 1.4s var(--ease-out) .35s forwards; }
  @keyframes win-in { from { opacity: 0; transform: rotateY(-14deg) rotateX(6deg) translateY(40px) scale(.96); } to { opacity: 1; transform: rotateY(-6deg) rotateX(2deg); } }
  @media (max-width: 980px) { @keyframes win-in { from { opacity: 0; transform: translateY(40px) scale(.96); } to { opacity: 1; transform: none; } } }

  /* Scroll reveal, reserved for the big windows and panels — not every paragraph */
  .fx [data-reveal] { opacity: 0; transform: translateY(28px); filter: blur(6px);
    transition: opacity var(--dur-slow) var(--ease-out) calc(var(--i, 0) * 100ms), transform 1.1s var(--ease-out) calc(var(--i, 0) * 100ms), filter var(--dur-slow) var(--ease-out) calc(var(--i, 0) * 100ms); }
  .fx [data-reveal].is-in { opacity: 1; transform: none; filter: none; }

  /* Windows follow the pointer a little (tilt set by JS) */
  .fx .win.is-tilting { transition: transform .15s linear; }
  .fx .win[style*="--ry"] { transform: perspective(1400px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)); }
  .fx .hero__win .win[style*="--ry"] { transform: rotateY(calc(-6deg + var(--ry, 0deg))) rotateX(calc(2deg + var(--rx, 0deg))); }

  /* The Pro plan: a slow light running around the border */
  @property --spin { syntax: '<angle>'; initial-value: 0deg; inherits: false; }
  .fx .plan--pro { animation: spin 7s linear infinite; }
  @keyframes spin { to { --spin: 360deg; } }

  /* Status dots breathe */
  .fx .win__tab i:not(.idle), .fx .tree .on, .fx .row .st:not(.off):not(.retry) { animation: breathe 2.4s ease-in-out infinite; }
  @keyframes breathe { 50% { opacity: .55; } }

  /* Mode switch: the new panel slides in */
  .fx .mode__panel.is-active { animation: panel-in .5s var(--ease-out); }
  @keyframes panel-in { from { opacity: 0; transform: translateY(14px); } }

  /* Transfer bar moves */
  .fx .xfer__bar i { animation: xfer 6s ease-in-out infinite alternate; }
  @keyframes xfer { from { width: 38%; } to { width: 86%; } }

  /* Download button: a sweep of light now and then */
  .fx .btn--primary::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
    background: linear-gradient(105deg, transparent 40%, rgb(255 255 255 / .45) 50%, transparent 60%); background-size: 250% 100%;
    animation: shine 6s ease-in-out infinite; }
  @keyframes shine { 0%, 70% { background-position: 150% 0; } 100% { background-position: -50% 0; } }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; scroll-behavior: auto !important; }
  .cursor { animation: none; }
}
