/**
 * 랜딩 모션.
 *
 * ## 원칙 하나가 나머지를 정한다
 *
 * **스크립트가 죽어도 페이지는 전부 보여야 한다.** 이 페이지는 증거를 늘어놓는
 * 곳이라, 자바스크립트 한 줄이 실패했다고 근거가 안 보이면 그 순간 페이지의
 * 존재 이유가 사라진다. 그래서 숨김 상태를 CSS 에 직접 쓰지 않는다 —
 * `motion.js` 가 <html> 에 `.js-motion` 을 붙인 뒤에만 숨김이 걸린다.
 * 스크립트가 안 뜨면 클래스가 안 붙고, 페이지는 그냥 정적으로 다 보인다.
 *
 * ## 축소 모드
 *
 * `prefers-reduced-motion: reduce` 에서는 **움직임을 전부 끈다.** 페이드조차
 * 남기지 않는다 — 전정기관이 예민한 사람에게는 오퍼시티 변화도 자극이다.
 * 대신 최종 상태를 그대로 보여 준다. 정보는 하나도 잃지 않는다.
 */

/* 모션 토큰. design.md 의 값을 마케팅 표면 기준으로 늘려 잡는다 —
   앱은 200ms 가 상한이지만 랜딩은 한 번 보고 지나가는 화면이라 더 길어도 된다. */
:root {
  --m-ease: cubic-bezier(0.16, 1, 0.3, 1);
  --m-ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --m-rise: 620ms;
  --m-stagger: 70ms;
}

/* ── 등장 ────────────────────────────────────────────────
   .js-motion 이 붙었을 때만 숨는다. 위 머리말의 이유다. */
.js-motion [data-reveal] {
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition:
    opacity var(--m-rise) var(--m-ease),
    transform var(--m-rise) var(--m-ease);
  transition-delay: var(--m-delay, 0ms);
  will-change: opacity, transform;
}
.js-motion [data-reveal].is-in {
  opacity: 1;
  transform: none;
}
/* 다 올라온 뒤에는 합성 힌트를 뗀다. 안 떼면 섹션 수만큼 레이어가 남는다. */
.js-motion [data-reveal].is-done { will-change: auto; }

/* 제목은 한 줄씩 올라온다. 줄은 motion.js 가 감싼다. */
.js-motion .line { display: block; overflow: hidden; }
.js-motion .line > i {
  display: block;
  font-style: normal;
  transform: translate3d(0, 100%, 0);
  transition: transform 760ms var(--m-ease);
  transition-delay: var(--m-delay, 0ms);
}
.js-motion .is-in .line > i,
.js-motion .line.is-in > i { transform: none; }

/* ── 히어로 ──────────────────────────────────────────── */
.js-motion .hero__kicker,
.js-motion .hero__lede,
.js-motion .hero__actions,
.js-motion .hero__note { opacity: 0; transform: translate3d(0, 16px, 0); }
.js-motion .hero.is-in .hero__kicker,
.js-motion .hero.is-in .hero__lede,
.js-motion .hero.is-in .hero__actions,
.js-motion .hero.is-in .hero__note {
  opacity: 1;
  transform: none;
  transition: opacity 700ms var(--m-ease), transform 700ms var(--m-ease);
}
.js-motion .hero.is-in .hero__kicker  { transition-delay: 80ms; }
.js-motion .hero.is-in .hero__lede    { transition-delay: 460ms; }
.js-motion .hero.is-in .hero__actions { transition-delay: 560ms; }
.js-motion .hero.is-in .hero__note    { transition-delay: 640ms; }

/* 제품 스크린샷은 살짝 늦게, 조금 크게 들어온다. */
.js-motion .hero .shot { opacity: 0; transform: translate3d(0, 34px, 0) scale(0.985); }
.js-motion .hero.is-in .shot {
  opacity: 1;
  transform: none;
  transition: opacity 900ms var(--m-ease) 320ms, transform 900ms var(--m-ease) 320ms;
}

/* **스크린샷에는 패럴랙스를 걸지 않는다.**
 * 전폭 판으로 키운 뒤에는 같은 18px 이 훨씬 크게 읽히고, 확대 크롭에서는
 * 글자가 흔들려 읽기를 방해한다. 이 그림의 목적은 분위기가 아니라 읽히는
 * 것이다 — 읽으라고 키워 놓고 흔들면 앞뒤가 안 맞는다. */

/* ── 숫자 ────────────────────────────────────────────── */
/* 자릿수가 바뀌어도 폭이 흔들리지 않게. 카운트업의 기본 예의다. */
.num, .figure__n, .figure-lead__n { font-variant-numeric: tabular-nums; }

/* 수령자 축소: 오른쪽 이름이 한 칸씩 들어온다. 왼쪽 59칸은 정지 상태다 —
   그쪽은 '고를 수 없음'을 뜻하므로 움직이면 오히려 활발해 보인다. */
.js-motion .narrow__list li {
  opacity: 0;
  transform: translate3d(0, 6px, 0);
  transition: opacity 380ms var(--m-ease), transform 380ms var(--m-ease);
  transition-delay: var(--m-delay, 0ms);
}
.js-motion .narrow.is-in .narrow__list li { opacity: 1; transform: none; }

/* ── 부하 시험 막대 ───────────────────────────────────
   실제 측정값(p50/p95/p99)으로 그린다. 없는 데이터를 그리지 않는다. */
.lat { margin-top: var(--space-lg); display: grid; gap: 0.55rem; }
.lat__row { display: grid; grid-template-columns: 3.4rem 1fr auto; align-items: center; gap: 0.75rem; }
.lat__k { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-ink-3); }
.lat__track { height: 6px; border-radius: 999px; background: var(--color-rule); overflow: hidden; }
.lat__bar {
  display: block; height: 100%; width: 0; border-radius: 999px;
  background: var(--color-accent);
  transition: width 1100ms var(--m-ease-in-out);
  transition-delay: var(--m-delay, 0ms);
}
.lat__v { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-ink-2); font-variant-numeric: tabular-nums; }
.lat__note { margin-top: 0.5rem; font-size: var(--text-xs); color: var(--color-ink-3); }

/* ── 섹션 사이 얇은 진행선 ───────────────────────────── */
.progress {
  position: fixed; inset-block-start: 0; inset-inline: 0; height: 2px; z-index: 60;
  background: var(--color-accent); transform-origin: 0 50%; transform: scaleX(0);
  pointer-events: none;
}
@supports (animation-timeline: scroll()) {
  .progress {
    animation: progress-grow linear both;
    animation-timeline: scroll(root block);
  }
  @keyframes progress-grow { to { transform: scaleX(1); } }
}

/* ── 카드 호버 ───────────────────────────────────────── */
.js-motion .makers li {
  transition: color 200ms var(--m-ease), border-color 200ms var(--m-ease),
              transform 200ms var(--m-ease);
}
.js-motion .makers li:hover { transform: translateY(-2px); }

/* ── 축소 모드: 전부 끈다 ─────────────────────────────
   페이드도 남기지 않는다. 최종 상태만 보여 준다. */
@media (prefers-reduced-motion: reduce) {
  .js-motion [data-reveal],
  .js-motion [data-reveal].is-in,
  .js-motion .hero__kicker, .js-motion .hero__lede,
  .js-motion .hero__actions, .js-motion .hero__note,
  .js-motion .hero .shot, .js-motion .narrow__list li {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .js-motion .line > i { transform: none !important; transition: none !important; }
  .lat__bar { transition: none !important; }
  .progress, .js-motion .hero .shot img { animation: none !important; }
  .progress { transform: scaleX(0) !important; }
}

/* ── 블루프린트 격자 ──────────────────────────────────
 * Bklit 에서 가져온 구조다. 배경 이미지가 아니라 **테두리를 가진 빈 칸의
 * 그리드**다. 이유는 선명도가 아니라(측정해 보면 정수로 안 나뉘는 폭에서는
 * 어차피 반픽셀이 생긴다) 칸이 실제 요소라서 토큰으로 쓸 수 있고, 칸마다
 * 따로 손댈 수 있고, 자바스크립트도 외부 요청도 0이라는 점이다 —
 * 수령자를 늘리지 않는다는 이 페이지의 논지와 어긋나지 않는다.
 *
 * 칸이 정사각형이어야 모눈종이로 읽힌다. 그래서 aspect-ratio 를 칸 수에
 * 맞춰 함께 바꾼다. 안 그러면 직사각형이 되고 그냥 표처럼 보인다.
 */
.bp { position: relative; }
.bp__lines {
  position: absolute; inset: 0; z-index: 0; display: grid; pointer-events: none;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-rows: repeat(2, minmax(0, 1fr));
}
.bp__lines > i {
  /* 헤어라인. 굵어지면 화면이 표처럼 보인다(tokens.css:34). 그래서 규칙선을
     그대로 쓰지 않고 더 옅게 섞는다 — 18칸이 한꺼번에 서면 같은 굵기라도
     훨씬 무겁게 보인다. */
  border-right: 1px solid var(--bp-hair);
  border-bottom: 1px solid var(--bp-hair);
}
.bp__lines > i:nth-child(-n + 3) { border-top: 1px solid var(--bp-hair); }
.bp__lines > i:nth-child(3n + 1) { border-left: 1px solid var(--bp-hair); }

@media (min-width: 64rem) {
  .bp__lines {
    grid-template-columns: repeat(6, minmax(0, 1fr));
    grid-template-rows: repeat(3, minmax(0, 1fr));
  }
  .bp__lines > i:nth-child(-n + 3) { border-top: 0; }
  .bp__lines > i:nth-child(3n + 1) { border-left: 0; }
  .bp__lines > i:nth-child(-n + 6) { border-top: 1px solid var(--bp-hair); }
  .bp__lines > i:nth-child(6n + 1) { border-left: 1px solid var(--bp-hair); }
}

/* 모서리 등록 표식. 밖으로 32px, 안으로 8px — 여백에 앉아 본문과 겹치지 않는다.
   **작은 화면에서는 감춘다.** 여백이 32px 도 안 남아서 표식이 화면 밖으로
   잘려 나가고, 잘린 조각은 표식이 아니라 그냥 얼룩으로 보인다. */
.bp__tick { display: none; position: absolute; background: var(--bp-tick); pointer-events: none; }
@media (min-width: 64rem) { .bp__tick { display: block; } }
.bp__tick--v { width: 1px; height: 40px; }
.bp__tick--h { height: 1px; width: 40px; }
.bp__tick--tl-v { top: -32px; left: 0 }      .bp__tick--tl-h { top: 0; left: -32px }
.bp__tick--tr-v { top: -32px; right: 0 }     .bp__tick--tr-h { top: 0; right: -32px }
.bp__tick--bl-v { bottom: -32px; left: 0 }   .bp__tick--bl-h { bottom: 0; left: -32px }
.bp__tick--br-v { bottom: -32px; right: 0 }  .bp__tick--br-h { bottom: 0; right: -32px }

/* **격자에는 모션을 걸지 않는다.**
 * 처음에 스크롤 연동 페이드(animation-timeline: view())를 걸었더니 히어로에서
 * 통째로 안 보였다 — 히어로는 로드 시점에 이미 화면에 있어서 "entry" 구간을
 * 지나 있고, 그 상태의 키프레임 값이 opacity 0 이었다. 화면에 이미 있는 것에
 * 등장 애니메이션을 걸면 영영 안 나타난다.
 *
 * 그리고 이건 장식이 아니라 **구조**다. 구조가 스크롤 위치에 따라 있었다
 * 없었다 하면 안 된다. 모션은 내용에만 건다. */
