/* ══════════════════════════════════════════════════════════════════════════
   스크롤 연출 — 무대와 완성 상태
   ──────────────────────────────────────────────────────────────────────────
   움직임은 anime.js 가 만든다(assets/js/scroll-demo.js). 이 파일은 무대를 세우고
   "연출이 끝난 뒤의 모습"만 정의한다.

   ⚠️ 이 파일의 기본값은 곧 완성 상태다. 스크립트가 로드되지 않으면 사용자가 보는 것은
      빈 화면이 아니라 폰이 결과를 들고 선 마지막 장면이다. 초기 상태로 되돌리는 일은
      전적으로 JS 가 한다.

   ⚠️ 붙잡는 구간(.flow-track 의 높이)은 `html.anim` 이 붙었을 때만 생긴다. 스크립트가
      없거나 모션 최소화 설정이면 트랙은 내용 높이 그대로라, 아무 일도 일어나지 않는
      빈 스크롤이 생기지 않는다.

   ⚠️ 카메라 렌즈와 사진과 폰은 전부 무대 정중앙에 겹쳐 있다. 그래서 연출이 scale 과
      opacity 만으로 성립하고 좌표를 옮길 일이 없다. 이 겹침을 깨면 안 된다.

   ⚠️ style.css 의 .flow-node / .flow-line / .flow-dot 은 기능 카드 안의 별개
      컴포넌트다. 이름만 비슷하고 아래 규칙들과는 아무 관계가 없다.
   ══════════════════════════════════════════════════════════════════════════ */


.flow-sequence { padding-bottom: 0; overflow: clip; }

.flow-track { position: relative; }

.flow-stage {
  position: relative;
  display: grid;
  /* ⚠️ 열과 행을 minmax(0, 1fr) 로 고정해야 한다. auto 로 두면 화면보다 큰 자식
     (.flow-glow 120vw, .flow-flash 92vw)이 격자를 자기 크기로 부풀리고, 그 격자가
     무대 밖으로 넘치면서 가운데에 있어야 할 것들이 통째로 한쪽으로 밀린다
     (실측: 120vw 짜리 빛 한 장이 사진을 오른쪽으로 144px 밀었다). */
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  place-items: center;
  min-height: min(88vh, 720px);
  overflow: clip;
}

/* 붙잡는 무대. 연출이 살아 있을 때만 만든다. */
.anim .flow-track { height: 460vh; }
.anim .flow-stage {
  position: sticky; top: 0;
  height: 100vh;
  min-height: 0;
}

/* 무대 위 모든 층은 중앙에 겹친다.
   ⚠️ 겹침을 transform: translate(-50%,-50%) 로 만들면 안 된다. anime.js 가 scale 이나 y 를
      건드리는 순간 그 translate 가 통째로 덮여 요소가 화면 구석으로 튄다(실측).
      그래서 정렬은 grid 가 하고 transform 은 연출에게 통째로 넘긴다. */
.flow-glow,
.flow-frame,
.flow-camera,
.flow-phone,
.flow-flash {
  grid-area: 1 / 1;
}

/* --- 배경 빛 --- */
/* 세이프라이트 한 줄기. 장면이 바뀌는 동안 무대가 완전히 검게 죽지 않게 받쳐 준다. */
.flow-glow {
  width: 120vw; height: 120vh;
  background: radial-gradient(closest-side, rgba(232, 162, 69, .16), transparent 72%);
  opacity: .5;
  pointer-events: none;
}

/* --- 사진 --- */
.flow-frame {
  width: 100vw; height: 100vh;
  overflow: clip;
}
.flow-shot {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
/* 현상되듯 위에서 아래로 덮이는 층. 완성 상태(--dev: 0)는 다 덮인 뒤다.
   JS 는 --dev 숫자 하나만 옮기고, 잘라낼 양과 현상선 위치를 여기서 함께 끌어낸다.
   두 값을 각각 애니메이트하면 한 프레임씩 어긋나 선이 경계에서 떨어진다. */
.flow-develop {
  position: absolute; inset: 0;
  clip-path: inset(0 0 calc(var(--dev, 0) * 1%) 0);
}
/* 현상선. 현상이 끝나면 사라지므로 기본은 보이지 않는다.
   top 을 쓰는 것은 잘린 경계에 붙어야 하기 때문이다. 절대 배치된 요소 하나이고 같은
   프레임에 clip-path 도 함께 바뀌므로, 이 한 줄이 만드는 리플로는 무시할 만하다. */
.flow-edge {
  position: absolute; left: 0; right: 0;
  top: calc((100 - var(--dev, 0)) * 1%);
  height: 3px;
  background: linear-gradient(90deg, transparent, rgba(255, 244, 220, .95) 30%, rgba(255, 244, 220, .95) 70%, transparent);
  box-shadow: 0 0 26px 6px rgba(255, 214, 150, .45);
  opacity: 0;
  pointer-events: none;
}

/* --- 렌즈 --- */
/* 완성 상태에서는 이미 제 역할을 마쳤으므로 보이지 않는다. */
.flow-camera {
  width: min(38vw, 440px);
  opacity: 0;
}
.flow-cam { display: block; width: 100%; height: auto; overflow: visible; }

/* 경통. 바깥으로 갈수록 어두워져 금속처럼 읽힌다. */
.flow-lens-barrel {
  fill: #0B0D11;
  stroke: #2E353F;
  stroke-width: 1.4;
}
.flow-lens-ring {
  fill: #05070A;
  stroke: rgba(232, 162, 69, .22);
  stroke-width: 1;
}
/* 날개. 겹친 채로 중앙을 덮고 있다가 회전하면서 구멍이 열린다. */
.flow-iris path {
  fill: #171B21;
  stroke: rgba(232, 162, 69, .55);
  stroke-width: 1.1;
  stroke-linejoin: round;
  /* 회전 중심은 각 날개의 bounding box 가 아니라 렌즈 한가운데여야 한다.
     fill-box 로 두면 날개가 제자리에서 뱅글뱅글 돌아 조리개로 읽히지 않는다. */
  transform-box: view-box;
  transform-origin: 100px 100px;
}
/* 구멍 가장자리에 얹는 빛. 날개 위에 그려야 테두리가 끊기지 않는다. */
.flow-lens-rim {
  fill: none;
  stroke: rgba(232, 162, 69, .5);
  stroke-width: 1.6;
}

/* 셔터 섬광. 이미 터진 뒤가 완성 상태다. */
.flow-flash {
  width: 92vw; height: 92vh;
  background: radial-gradient(closest-side, rgba(255, 252, 245, .92), rgba(255, 226, 170, .35) 38%, transparent 66%);
  opacity: 0;
  pointer-events: none;
}

/* --- 폰 --- */
.flow-phone {
  /* 높이 상한은 아래 네 단계 띠에 물리지 않는 선에서 정한다. 더 키우면 폰 하단의
     파일 칩이 그 띠에 가려진다(실측). */
  width: calc(min(62vh, 500px) * 0.462);   /* 9 : 19.5 */
  height: min(62vh, 500px);
  padding: 9px;
  border-radius: 38px;
  background: linear-gradient(155deg, #2A3037, #0B0D10 42%, #1B2027);
  box-shadow:
    0 40px 90px rgba(0, 0, 0, .7),
    0 0 0 1px rgba(255, 255, 255, .07) inset;
}
.flow-phone-screen {
  position: relative;
  width: 100%; height: 100%;
  overflow: hidden;
  border-radius: 30px;
  background: var(--bg, #050607);
}
/* 가로 사진을 세로 화면에 담으면 좌우가 크게 잘린다. 인물이 화면 왼쪽에 서 있으므로
   크롭 기준을 왼쪽으로 당겨야 폰 안에서도 구도가 읽힌다. */
.flow-phone-screen .flow-shot { object-position: 34% 50%; }
/* 유리 반사 한 줄. 폰이 물체로 보이게 하는 것은 이 한 겹이다. */
.flow-phone-glare {
  position: absolute; inset: 0;
  background: linear-gradient(118deg, rgba(255, 255, 255, .16) 6%, transparent 34%, transparent 68%, rgba(255, 255, 255, .06) 96%);
  pointer-events: none;
}
.flow-files {
  position: absolute; left: 12px; right: 12px; bottom: 14px;
  display: flex; flex-direction: column; gap: 6px;
}
/* .chip-file 은 기능 카드용이라 폰 화면에 넣기에는 여백이 크고, 배경이 거의 투명이라
   사진 위에 놓으면 글자가 묻힌다. 크기를 좁히고 배경을 불투명하게 덮는다. */
.flow-files .chip-file {
  padding: 5px 9px; font-size: 10px;
  background: rgba(10, 11, 13, .86);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
.flow-files .chip-file.amber { background: rgba(52, 33, 10, .88); }

/* --- 필름 이름 --- */
/* 가운데 정렬을 transform 으로 하지 않는다(anime.js 가 y 를 건드리면 덮인다).
   left/right 0 + margin auto 로 자리를 잡고 transform 은 연출에게 넘긴다. */
.flow-stock {
  position: absolute;
  left: 0; right: 0; margin-inline: auto;
  top: clamp(74px, 11vh, 118px);
  width: fit-content;
  padding: 6px 14px;
  border: 1px solid var(--amber-35, rgba(232, 162, 69, .35));
  border-radius: 999px;
  background: rgba(10, 11, 13, .7);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11.5px; letter-spacing: .1em; white-space: nowrap;
  color: var(--amber, #E8A245);
}

/* --- 네 단계 --- */
/* 사진 위에 얹히므로 배경을 깔아 글자가 묻히지 않게 한다.
   기본 상태는 네 단계가 모두 또렷하게 읽히는 것이다. */
.flow-steps {
  position: absolute; left: 0; right: 0; bottom: 0;
  z-index: 2;
  list-style: none; margin: 0;
  padding: 56px clamp(20px, 4vw, 56px) clamp(20px, 4vh, 44px);
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: clamp(14px, 2.4vw, 34px);
  background: linear-gradient(transparent, rgba(5, 6, 7, .72) 30%, rgba(5, 6, 7, .95) 62%, rgba(5, 6, 7, .98));
}
.flow-step { position: relative; padding-top: 14px; }
.flow-step::before {
  content: ""; position: absolute; left: 0; top: 0;
  width: 100%; height: 2px;
  background: var(--amber, #E8A245);
  transform-origin: left center;
}
.flow-step i {
  display: block; margin-bottom: 6px;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px; font-style: normal; letter-spacing: .14em;
  color: var(--amber, #E8A245);
}
.flow-step b {
  display: block;
  font-size: 17px; font-weight: 600; letter-spacing: -.02em;
  color: var(--ink, #F6F7F8);
}
.flow-step span {
  display: block; margin-top: 5px;
  font-size: 14px; line-height: 1.65;
  color: var(--ink-dim, #B6BCC6);
}

/* 좁은 화면. 네 단계를 2×2 로 접고 무대 크기를 줄인다. */
@media (max-width: 767px) {
  .anim .flow-track { height: 360vh; }
  .flow-phone {
    width: calc(min(46vh, 350px) * 0.462);
    height: min(46vh, 350px);
    border-radius: 30px; padding: 7px;
  }
  .flow-phone-screen { border-radius: 24px; }
  .flow-camera { width: 78vw; }
  .flow-stock { top: clamp(64px, 9vh, 92px); font-size: 10.5px; }
  .flow-steps {
    grid-template-columns: repeat(2, 1fr);
    gap: 12px 16px;
    padding: 40px 20px 22px;
  }
  .flow-step b { font-size: 15px; }
  .flow-step span { font-size: 12.5px; line-height: 1.5; }
}

@media (max-width: 420px) {
  .flow-step span { display: none; }   /* 제목만 남겨야 네 칸이 화면에 들어온다 */
}


/* ══════════════ 색감 전송 강도 ══════════════
   강도 단계마다 다른 이미지를 부르는 구조라 값 자체는 JS 가 옮긴다.
   여기서는 갈아타는 순간만 부드럽게 덮는다. 레이아웃 속성은 건드리지 않는다. */

#ctResult { transition: opacity .28s var(--ease-out, ease-out); }
#ctResult.is-swapping { opacity: .55; }

@media (prefers-reduced-motion: reduce) {
  #ctResult { transition: none !important; }
  #ctResult.is-swapping { opacity: 1 !important; }
}


/* ══════════════ 히어로 헤드라인 단어 등장 ══════════════
   is-split 은 분절에 성공했을 때만 붙는다. 스크립트가 실패하면 이 규칙도 걸리지 않으므로
   제목이 투명한 채 남는 일이 없다. inline-block 이어야 transform 이 먹는다. */

.hero-title.is-split .hw {
  display: inline-block;
  opacity: 0;                 /* anime.js 가 1 로 올린다 */
  will-change: transform, opacity;
}
/* 애니메이션이 끝나면 will-change 를 유지할 이유가 없지만, 히어로는 한 번 등장하고
   끝이라 레이어가 오래 남지 않는다. 대신 줄바꿈만 원래대로 지켜 준다. */
.hero-title.is-split .accent { display: inline; }

@media (prefers-reduced-motion: reduce) {
  .hero-title.is-split .hw { opacity: 1 !important; transform: none !important; }
}
