/*
 * Orbit marketing site — the signature motion layer.
 *
 * One idea, used everywhere: EVERYTHING ORBITS, ORBIT CAPTURES. A call, a
 * WhatsApp, a GPS pin, a form and an invoice circle the Orbit mark; every few
 * seconds one is pulled in and absorbed. That is the product in one picture.
 *
 * Rules this file follows:
 *  - Pure CSS keyframes. Nothing here runs JavaScript, so nothing here can
 *    block or delay the hero paint.
 *  - Animation starts AFTER first paint (animation-delay), so the H1 stays the
 *    largest contentful paint and the animation never costs us LCP.
 *  - prefers-reduced-motion gets the same composition, frozen. Not hidden:
 *    the still frame is designed to look deliberate on its own.
 *  - Under 820px the satellites thin out and slow down; a phone should not be
 *    running five simultaneous orbit loops for decoration.
 */

/* ------------------------------------------------------------- the system */
.orbit-system {
  position: relative;
  width: 100%;
  max-width: 300px;
  aspect-ratio: 1;
  margin: 0 auto;
  pointer-events: none;
}
.orbit-system svg { display: block; width: 100%; height: 100%; overflow: visible; }

/* the rings */
.os-ring {
  fill: none;
  stroke: currentColor;
  opacity: 0.16;
  stroke-width: 1;
}
.os-core-glow { transform-box: fill-box; transform-origin: center; animation: os-breathe 5.5s ease-in-out 0.6s infinite; }
@keyframes os-breathe {
  0%, 100% { opacity: 0.30; transform: scale(1); }
  50%      { opacity: 0.62; transform: scale(1.10); }
}

/* Each satellite rides its own ring. rotate() on a <g> is cheap and, unlike
   offset-path, works everywhere we care about.
   TRANSFORM-BOX MATTERS HERE: an SVG element defaults to transform-box:view-box,
   where transform-origin:0 0 is the TOP-LEFT CORNER of the viewBox, not the SVG
   origin. With a viewBox centred on 0 0 that flung every satellite around the
   corner and bunched them in one clump. 50% 50% of the view box IS the SVG
   origin, which is what the orbit has to turn around. */
.os-sat { transform-box: view-box; transform-origin: 50% 50%; animation: os-spin linear infinite; }
.os-sat.s1 { animation-duration: 15s; animation-delay: 0.6s; }
.os-sat.s2 { animation-duration: 21s; animation-delay: 0.6s; animation-direction: reverse; }
.os-sat.s3 { animation-duration: 27s; animation-delay: 0.6s; }
.os-sat.s4 { animation-duration: 18s; animation-delay: 0.6s; animation-direction: reverse; }
.os-sat.s5 { animation-duration: 24s; animation-delay: 0.6s; }
@keyframes os-spin { to { transform: rotate(360deg); } }

/* Counter-rotate the badge so the glyph inside stays upright while it orbits.
   fill-box here: this one turns about its own centre, not the viewBox's. */
.os-badge { transform-box: fill-box; transform-origin: center; animation: os-spin-back linear infinite; }
.os-sat.s1 .os-badge { animation-duration: 15s; animation-delay: 0.6s; animation-direction: reverse; }
.os-sat.s2 .os-badge { animation-duration: 21s; animation-delay: 0.6s; }
.os-sat.s3 .os-badge { animation-duration: 27s; animation-delay: 0.6s; animation-direction: reverse; }
.os-sat.s4 .os-badge { animation-duration: 18s; animation-delay: 0.6s; }
.os-sat.s5 .os-badge { animation-duration: 24s; animation-delay: 0.6s; animation-direction: reverse; }
@keyframes os-spin-back { to { transform: rotate(-360deg); } }

/* The capture: one artefact at a time gets drawn in and absorbed, staggered so
   the eye always has something to catch but never a queue of them. */
.os-capture { transform-box: fill-box; transform-origin: center; animation: os-capture 12s ease-in-out infinite; }
.os-sat.s1 .os-capture { animation-delay: 1.5s; }
.os-sat.s2 .os-capture { animation-delay: 3.9s; }
.os-sat.s3 .os-capture { animation-delay: 6.3s; }
.os-sat.s4 .os-capture { animation-delay: 8.7s; }
.os-sat.s5 .os-capture { animation-delay: 11.1s; }
/* --r is the satellite's orbit radius in SVG user units, set per element. On an
   SVG element a px length in a CSS transform maps 1:1 to a user unit, so
   translateX(calc(var(--r) * -1)) lands the artefact exactly on the core. */
@keyframes os-capture {
  0%, 62%   { transform: translateX(0) scale(1); opacity: 1; }
  74%       { transform: translateX(calc(var(--r, 90px) * -0.5)) scale(0.86); opacity: 1; }
  82%       { transform: translateX(calc(var(--r, 90px) * -1)) scale(0.3); opacity: 0; }
  83%       { transform: translateX(0) scale(0.3); opacity: 0; }
  92%, 100% { transform: translateX(0) scale(1); opacity: 1; }
}

/* the pulse the core gives off as it swallows one */
.os-pulse { transform-box: fill-box; transform-origin: center; opacity: 0; animation: os-pulse 2.4s ease-out infinite; }
@keyframes os-pulse {
  0%   { opacity: 0.55; transform: scale(0.55); }
  70%  { opacity: 0;    transform: scale(1.65); }
  100% { opacity: 0;    transform: scale(1.65); }
}

/* --------------------------------------------------- section divider trail */
.orbit-trail {
  position: relative;
  height: 1px;
  margin: 0;
  border: 0;
  background: linear-gradient(90deg, transparent, var(--border), transparent);
  overflow: visible;
}
.orbit-trail::after {
  content: "";
  position: absolute;
  top: -2px;
  left: 0;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #7c5cff;
  box-shadow: 0 0 12px 3px rgba(124, 92, 255, 0.6);
  animation: os-streak 9s cubic-bezier(0.6, 0, 0.4, 1) 1s infinite;
}
@keyframes os-streak {
  0%        { left: 6%;  opacity: 0; }
  12%       { opacity: 1; }
  78%       { opacity: 1; }
  90%, 100% { left: 94%; opacity: 0; }
}

/* ------------------------------------------------------- micro-interaction */
.btn-primary { position: relative; }
.btn-primary::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: 0 0 0 0 rgba(124, 92, 255, 0.5);
  transition: box-shadow 0.4s ease;
  pointer-events: none;
}
.btn-primary:hover::after { box-shadow: 0 0 0 6px rgba(124, 92, 255, 0); }

/* ------------------------------------------------- pause when out of sight */
/* The satellites are decoration. Left alone they keep turning long after the
   hero has scrolled away, which costs battery on a laptop or phone for a
   picture nobody can see. orbit-demos.js toggles .os-idle from an
   IntersectionObserver; animation-play-state is free to flip. */
.orbit-system.os-idle .os-sat,
.orbit-system.os-idle .os-badge,
.orbit-system.os-idle .os-capture,
.orbit-system.os-idle .os-pulse,
.orbit-system.os-idle .os-core-glow,
.orbit-trail.os-idle::after {
  animation-play-state: paused;
}

/* ------------------------------------------------------------- small print */
@media (max-width: 820px) {
  .orbit-system { max-width: 210px; }
  /* Fewer moving parts on a phone: two rings carry the idea just as well. */
  .os-sat.s4, .os-sat.s5 { display: none; }
  .os-sat { animation-duration: 34s !important; }
  .os-sat .os-badge { animation-duration: 34s !important; }
}

@media (prefers-reduced-motion: reduce) {
  .os-sat,
  .os-sat .os-badge,
  .os-capture,
  .os-pulse,
  .os-core-glow,
  .orbit-trail::after {
    animation: none !important;
  }
  /* The frozen frame is the point of the composition, not a fallback: the
     satellites sit at their start angles, spread evenly around the core. */
  .os-pulse { opacity: 0; }
  .os-core-glow { opacity: 0.45; }
}
