/* ===========================================================================
   처리 흐름도의 움직임

   레일을 따라 빛 한 점이 내려가고, 지나는 단계마다 점 둘레에 고리가 퍼지고
   넘기는 것이 한 번 진해진다. 히어로의 봉투 흐름과 같은 이야기를 문서 쪽에서
   한 번 더 한다 — 흐름도가 정지된 그림이 아니라 흐르는 것이 되게.

   차례(--i)는 마크업이 알려 주고, 지연은 여기서 계산한다. 주기와 간격은
   flow.css 의 --flow-cycle · --flow-gap 에 있다.

   '모션 최소화' 설정에서는 base.css 의 규칙이 이 애니메이션들을 멈춘다.

   끝없이 돌지 않는다. 흐름도가 화면에 들어온 뒤 세 바퀴(약 23초)만 돌고
   멈춘다 — 무한 반복보다 덜 거슬리지만 WCAG 2.2.2 의 5초 기준을 채우지는
   않는다. 모션 최소화 사용자는 움직임을 보지 않는다. 시작 신호는 단계 하나가
   .is-visible 을 받는 순간이고, 빛 · 고리 · 넘기는 것이 모두 그 순간에 함께
   출발해야 박자가 맞는다. :has() 를 모르는 브라우저에서는 셋 다 가만히 있다.
   =========================================================================== */

.flow__pulse {
  position: absolute;
  left: 16px;
  top: 18px;
  bottom: 18px;
  width: 4px;
  overflow: hidden;
  pointer-events: none;
  /* 채움 레일(.flow::after)이 뒤에 그려져 빛을 덮는다. 빛을 그 위로 올린다.
     점(.flow__dot)도 z-index 1 이고 문서에서 더 뒤라 여전히 빛 위에 있다. */
  z-index: 1;
}

/* 레일 길이만 한 띠의 가운데에 96px 짜리 빛을 두고, 띠를 transform 으로
   민다. top 을 움직이면 매 프레임 레이아웃을 다시 계산한다. 쉬는 자리는 레일
   위쪽 바깥이라, 애니메이션이 없거나 끝나면 빛이 보이지 않는다. */
.flow__pulse::before {
  content: "";
  position: absolute;
  left: 1px;
  top: 0;
  width: 2px;
  height: 100%;
  border-radius: 2px;
  background: linear-gradient(
    180deg,
    rgba(0, 113, 227, 0) calc(50% - 48px),
    rgba(0, 113, 227, 0.85) 50%,
    rgba(0, 113, 227, 0) calc(50% + 48px)
  );
  transform: translateY(calc(-50% - 48px));
}

.section--dark .flow__pulse::before,
.on-dark .flow__pulse::before {
  background: linear-gradient(
    180deg,
    rgba(41, 151, 255, 0) calc(50% - 48px),
    rgba(41, 151, 255, 0.95) 50%,
    rgba(41, 151, 255, 0) calc(50% + 48px)
  );
}

.flow:has(.flow__step.is-visible) .flow__pulse::before {
  animation: flow-run var(--flow-cycle) linear 3;
}

@keyframes flow-run {
  from {
    transform: translateY(calc(-50% - 48px));
  }
  to {
    transform: translateY(calc(50% + 48px));
  }
}

/* 빛이 지날 때 그 단계의 점 둘레에 고리가 한 번 퍼진다. 점 자체의 배경을
   건드리지 않는다 — AI 단계는 이미 채워져 있어 덧칠하면 뭉개진다.
   z-index 는 아래 채움 레일(.flow::after)보다 점을 위에 두려는 것이다. */
.flow__dot,
.flow__cap {
  position: relative;
  z-index: 1;
}

.flow__dot::after,
.flow__cap::after {
  content: "";
  position: absolute;
  inset: -5px;
  border-radius: 50%;
  border: 1px solid var(--nx-accent);
  opacity: 0;
}

.flow:has(.flow__step.is-visible) .flow__dot::after,
.flow:has(.flow__step.is-visible) .flow__cap::after {
  animation: flow-ring var(--flow-cycle) linear 3;
  animation-delay: calc(var(--i, 0) * var(--flow-gap));
}

.section--dark .flow__dot::after,
.on-dark .flow__dot::after,
.section--dark .flow__cap::after,
.on-dark .flow__cap::after {
  border-color: var(--nx-accent-dark);
}

@keyframes flow-ring {
  0% {
    opacity: 0;
    transform: scale(0.8);
  }
  3% {
    opacity: 0.9;
    transform: scale(1);
  }
  10% {
    opacity: 0;
    transform: scale(1.3);
  }
  100% {
    opacity: 0;
    transform: scale(1.3);
  }
}

/* 넘기는 것도 그때 한 번 진해진다. 쉬는 동안에도 0.85 — 검정 위에서 글자가
   읽힐 만큼은 남긴다. 다 돌고 나면 원래 진하기(1)로 돌아간다. */
/* backwards 는 지연 동안 첫 장면(0.85)을 붙든다. 없으면 1 로 있다가 첫 바퀴가
   시작될 때 한 단 흐려져, 목록을 따라 깜빡임이 번진다. */
.flow:has(.flow__step.is-visible) .flow__out {
  animation: flow-hand var(--flow-cycle) linear 3 backwards;
  animation-delay: calc(var(--i, 0) * var(--flow-gap) + 0.2s);
}

@keyframes flow-hand {
  0%,
  2% {
    opacity: 0.85;
  }
  6% {
    opacity: 1;
  }
  14%,
  100% {
    opacity: 0.85;
  }
}

/* ── 읽어 내려간 만큼 차오르는 레일 ─────────────────────────
   스크롤과 묶인 움직임이라 스스로 돌지 않는다. 스크롤 타임라인을 모르는
   브라우저에서는 옅은 레일(flow.css 의 .flow::before)만 남는다. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .flow::after {
      content: "";
      position: absolute;
      left: 17px;
      top: 18px;
      bottom: 18px;
      width: 2px;
      background: var(--nx-accent);
      /* 빛과 같은 색이라 다 차면 빛이 묻힌다. 한 단 낮춰 그 위의 빛이 보이게 한다. */
      opacity: 0.55;
      transform-origin: top;
      animation: flow-fill linear both;
      animation-timeline: view();
      animation-range: cover 15% cover 75%;
    }

    .section--dark .flow::after,
    .on-dark .flow::after {
      background: var(--nx-accent-dark);
    }
  }
}

@keyframes flow-fill {
  from {
    transform: scaleY(0);
  }
  to {
    transform: scaleY(1);
  }
}

@media (max-width: 680px) {
  .flow__pulse {
    left: 12px;
  }
  .flow::after {
    left: 13px;
  }
}
