/* ============================================================
   TOKENS — the whole loop is tuned from here
   ------------------------------------------------------------
   --dot-cycle     full loop period (one complete wave)
   --dot-stagger   offset between neighbouring dots
   --dot-float     idle drift distance (SVG user units)
   --dot-width     rendered width of the artwork
   ============================================================ */
:root {
  --dot-cycle: 5000ms;
  --dot-stagger: 50ms;
  --dot-float: 2.5px;
  --dot-width: clamp(140px, 22vmin, 202px);

  --brand-blue: #4f6bff;
  --brand-red: #ff4b32;

  /* ---- Shared CTA motion tokens (both buttons read these) ---- */
  --cta-fill-duration: 500ms;
  --cta-fill-ease: cubic-bezier(0.65, 0, 0.35, 1);
  --cta-gleam-duration: 900ms;
  --cta-lift: -2px;
  --cta-arrow-shift: 4px;
}

/* ============================================================
   STAGE
   ============================================================ */
.dot-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  padding: 32px;
}

.dot-swoosh {
  display: block;
  width: var(--dot-width);
  height: auto;
  overflow: visible; /* the drift must not be clipped */
}

/* ============================================================
   BASE STATE — final composed shape.
   Shown while: paused, off-screen, or prefers-reduced-motion.
   ============================================================ */
.dot-swoosh ellipse {
  transform-box: fill-box; /* scale/rotate around each dot's own centre */
  transform-origin: 50% 50%;
  opacity: 1;
  scale: 1;
  translate: 0 0;
}

/* ============================================================
   THE LOOP — one keyframe timeline, 24 phase offsets.
   translate / scale / opacity are independent channels, so a
   single animation drives both the pop and the float with no
   transform conflicts and no wrapper <g> elements.
   ============================================================ */
.dot-swoosh.is-playing ellipse {
  animation: dot-cycle var(--dot-cycle) linear infinite backwards;
  animation-delay: calc(var(--i, 0) * var(--dot-stagger));

  will-change: transform, opacity;
  backface-visibility: hidden; /* kills sub-pixel shimmer on some GPUs */
}

@keyframes dot-cycle {
  /* --- enter (staggered pop with overshoot) --------------- */
  0% {
    opacity: 0;
    scale: 0.3;
    translate: 0 0;
    animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
  }
  6% {
    opacity: 1;
    scale: 1.12;
    animation-timing-function: cubic-bezier(0.34, 1.4, 0.64, 1);
  }
  12% {
    scale: 1;
    animation-timing-function: ease-in-out;
  }

  /* --- idle float ----------------------------------------- */
  30% {
    translate: 0 calc(var(--dot-float) * -1);
  }
  44% {
    translate: 0 0;
  }
  58% {
    translate: 0 calc(var(--dot-float) * -1);
  }

  /* --- exit fade ------------------------------------------ */
  66% {
    opacity: 1;
    scale: 1;
    translate: 0 calc(var(--dot-float) * -1);
    animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45);
  }
  74% {
    opacity: 0;
    scale: 0.88;
    translate: 0 calc(var(--dot-float) * -2);
  }

  /* --- invisible tail (the beat before the next wave) ------ */
  100% {
    opacity: 0;
    scale: 0.3;
    translate: 0 0;
  }
}

/* ============================================================
   PHASE OFFSETS (--i)
   Diagonal sweep, bottom-left ➜ top-right, ranked by (x − y).
   :nth-of-type (not :nth-child) so the <title> element
   doesn't shift the count.
   ============================================================ */
.dot-swoosh ellipse:nth-of-type(1) {
  --i: 0;
}
.dot-swoosh ellipse:nth-of-type(2) {
  --i: 2;
}
.dot-swoosh ellipse:nth-of-type(3) {
  --i: 1;
}
.dot-swoosh ellipse:nth-of-type(4) {
  --i: 4;
}
.dot-swoosh ellipse:nth-of-type(5) {
  --i: 3;
}
.dot-swoosh ellipse:nth-of-type(6) {
  --i: 6;
}
.dot-swoosh ellipse:nth-of-type(7) {
  --i: 5;
}
.dot-swoosh ellipse:nth-of-type(8) {
  --i: 8;
}
.dot-swoosh ellipse:nth-of-type(9) {
  --i: 7;
}
.dot-swoosh ellipse:nth-of-type(10) {
  --i: 10;
}
.dot-swoosh ellipse:nth-of-type(11) {
  --i: 9;
}
.dot-swoosh ellipse:nth-of-type(12) {
  --i: 11;
}
.dot-swoosh ellipse:nth-of-type(13) {
  --i: 13;
}
.dot-swoosh ellipse:nth-of-type(14) {
  --i: 12;
}
.dot-swoosh ellipse:nth-of-type(15) {
  --i: 14;
}
.dot-swoosh ellipse:nth-of-type(16) {
  --i: 15;
}
.dot-swoosh ellipse:nth-of-type(17) {
  --i: 16;
}
.dot-swoosh ellipse:nth-of-type(18) {
  --i: 18;
}
.dot-swoosh ellipse:nth-of-type(19) {
  --i: 17;
}
.dot-swoosh ellipse:nth-of-type(20) {
  --i: 19;
}
.dot-swoosh ellipse:nth-of-type(21) {
  --i: 20;
}
.dot-swoosh ellipse:nth-of-type(22) {
  --i: 21;
}
.dot-swoosh ellipse:nth-of-type(23) {
  --i: 22;
}
.dot-swoosh ellipse:nth-of-type(24) {
  --i: 23;
}

/* ============================================================
   REPLAY CONTROL
   ============================================================ */
.replay-btn {
  font: 600 13px/1 inherit;
  letter-spacing: 0.03em;
  color: var(--brand-blue);
  background: #fff;
  border: 1.5px solid var(--brand-blue);
  border-radius: 999px;
  padding: 10px 20px;
  cursor: pointer;
  transition:
    background-color 0.18s ease,
    color 0.18s ease,
    transform 0.18s ease;
  -webkit-tap-highlight-color: transparent;
}

.replay-btn:hover {
  background: var(--brand-blue);
  color: #fff;
}
.replay-btn:active {
  transform: scale(0.96);
}

.replay-btn:focus-visible {
  outline: 2px solid var(--brand-red);
  outline-offset: 3px;
}

/* ============================================================
   ACCESSIBILITY — honour the OS "reduce motion" setting
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .dot-swoosh ellipse {
    animation: none !important;
    opacity: 1;
    scale: 1;
    translate: 0 0;
    will-change: auto;
  }
}


/* ============================================================
   CTA — SHARED BASE
   Every visual/motion behaviour that both buttons share lives
   here. The variant classes below only set the "paint".
   ============================================================ */
.cta {
  /* --- layout --------------------------------------------- */
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  isolation: isolate;
  overflow: hidden;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  text-decoration: none;
  white-space: nowrap;

  /* --- typography & box ----------------------------------- */
  border-radius: 0;
  border: 1px solid currentColor;
  padding: 16px 32px;
  background: transparent;
  font-family: var(--font-main);
  font-weight: 600;
  font-size: clamp(14px, 2vw, 18px);
  line-height: 1;
  letter-spacing: 0.01em;

  /* --- motion ---------------------------------------------
     `translate` (not `transform`) so AOS's `transform` on the
     secondary button never conflicts with our hover lift.
     -------------------------------------------------------- */
  transition:
    color       var(--cta-fill-duration) var(--cta-fill-ease),
    border-color var(--cta-fill-duration) var(--cta-fill-ease),
    translate   220ms cubic-bezier(0.34, 1.4, 0.64, 1);
}

/* --- label sits above the fill ----------------------------- */
.cta > .cta-label {
  position: relative;
  z-index: 2;
  display: inline-block;
}

/* --- trailing arrow ---------------------------------------- */
.cta .cta-arrow {
  position: relative;
  z-index: 2;
  width: 1em;
  height: 1em;
  flex: 0 0 auto;
  transition: transform 320ms cubic-bezier(0.34, 1.4, 0.64, 1);
}

/* ============================================================
   FILL LAYER — ::before
   Two variants share this element but drive it on different axes
   via --fill-axis. Default = horizontal sweep (primary).
   ============================================================ */
.cta::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--fill-color, transparent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--cta-fill-duration) var(--cta-fill-ease);
  will-change: transform;
}

/* Vertical variant (secondary) */
.cta--fill-y::before {
  transform: scaleY(0);
  transform-origin: bottom center;
}

/* ============================================================
   GLEAM LAYER — ::after  (primary only, keeps secondary calm)
   ============================================================ */
.cta--gleam::after {
  content: "";
  position: absolute;
  top: -50%;
  bottom: -50%;
  left: -60%;
  width: 40%;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(
    100deg,
    transparent 0%,
    rgba(255, 255, 255, 0.55) 50%,
    transparent 100%
  );
  transform: translateX(-160%) skewX(-18deg);
  opacity: 0;
  will-change: transform, opacity;
}

/* ============================================================
   SHARED ACTIVE STATE (hover + keyboard focus)
   ============================================================ */
.cta:hover,
.cta:focus-visible {
  color: var(--fill-contrast, currentColor);
  border-color: var(--fill-color, currentColor);
}

.cta:hover::before,
.cta:focus-visible::before {
  transform: scaleX(1);
}
.cta--fill-y:hover::before,
.cta--fill-y:focus-visible::before {
  transform: scaleY(1);
}

.cta:hover .cta-arrow,
.cta:focus-visible .cta-arrow {
  transform: translateX(var(--cta-arrow-shift));
}

/* Gleam fires once per hover */
.cta--gleam:hover::after,
.cta--gleam:focus-visible::after {
  animation: cta-gleam var(--cta-gleam-duration) var(--cta-fill-ease) 1;
}

@keyframes cta-gleam {
  0%   { transform: translateX(-160%) skewX(-18deg); opacity: 0; }
  15%  { opacity: 1; }
  70%  { opacity: 1; }
  100% { transform: translateX(360%)  skewX(-18deg); opacity: 0; }
}

/* ---- Hover lift (fine pointers only) ---------------------- */
@media (hover: hover) and (pointer: fine) {
  .cta:hover { translate: 0 var(--cta-lift); }
}

/* ---- Press ------------------------------------------------ */
.cta:active {
  translate: 0 0;
  scale: 0.98;
  transition-duration: 90ms;
}

/* ---- Focus ring ------------------------------------------- */
.cta:focus-visible {
  outline: 2px solid var(--clr-insight);
  outline-offset: 4px;
}
.cta:focus:not(:focus-visible) { outline: none; }

/* ---- Disabled --------------------------------------------- */
.cta[aria-disabled="true"] {
  opacity: 0.45;
  pointer-events: none;
  cursor: not-allowed;
}

/* ============================================================
   VARIANT: PRIMARY
   Outlined warm-bone → red fill sweeping left ➜ right.
   ============================================================ */
.cta--primary {
  color: var(--clr-brand-warm-bone);
  --fill-color:    var(--clr-action-primary);
  --fill-contrast: var(--clr-brand-engine-black);
}

/* ============================================================
   VARIANT: SECONDARY
   Outlined black → black fill rising bottom ➜ top.
   Use on light surfaces (--clr-brand-warm-bone background).
   ============================================================ */
.cta--secondary {
  color: var(--clr-brand-engine-black);
  --fill-color:    var(--clr-brand-engine-black);
  --fill-contrast: var(--clr-brand-warm-bone);
}

/* ============================================================
   AOS CO-EXISTENCE
   AOS writes `transform`; our hover lift uses `translate`,
   so they never fight. We only release AOS's will-change hint
   after the entrance settles — prevents a pinned GPU layer.
   ============================================================ */
.cta.aos-animate { will-change: auto; }

/* ============================================================
   ACCESSIBILITY — reduce motion
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .cta,
  .cta::before,
  .cta::after,
  .cta .cta-arrow {
    transition: none !important;
    animation: none !important;
  }
  .cta:hover,
  .cta:focus-visible {
    background: var(--fill-color);
    color: var(--fill-contrast);
    border-color: var(--fill-color);
    translate: 0 0;
    scale: 1;
  }
}
