/* ============================================================================
   MOTION CONTRACT  —  assets/engine.global.js 와 반드시 함께 배포한다
   ----------------------------------------------------------------------------
   ★ 이 파일이 없으면 엔진의 [data-motion-done] 계약이 아무 일도 하지 않는다.
     엔진은 "속성만 세팅"할 뿐, "정지=시안" 을 강제하는 것은 이 CSS다.
     엔진만 있고 이 파일이 없으면 다음이 전부 깨진다:

       · 진입 모션의 초기 숨김(opacity 0)이 CSS 로 안 걸려 → 전부 처음부터 보임
         (또는 GSAP from 상태가 도달 불가 트리거에 걸려 → 영구 opacity:0 로 갇힘)
       · 완료 요소의 인라인 transform 잔여물이 안 지워짐
       · prefers-reduced-motion 무시
       · 유동 레이아웃에서 모션 훅이 grid/flex 축소를 막아 가로 오버플로

   ----------------------------------------------------------------------------
   전제 (엔진과의 계약)
     · <html> 에 엔진이 js-motion 클래스를 붙인다. JS 가 죽으면 안 붙는다.
     · 진입 요소는 [data-motion], 마스크 리빌은 [data-motion-mask],
       라인 리빌은 .line-mask > .line, 완료 표식은 [data-motion-done].
     · 초기 상태 커스텀 프로퍼티: --m-o0/--m-x0/--m-y0/--m-s0/--m-r0/--m-clip0
     · 시안 알파는 opacity 가 아니라 color/background-color 의 알파에 둔다
       (RC-2b — GSAP 이 인라인 opacity:1 을 남겨도 시안 알파가 살아남게).
     · 섹션 래퍼 관용 클래스는 .fl-sec (유동 섹션). 화면고정 UI 는 그 밖.

   ★ !important 는 prefers-reduced-motion 블록에서만 쓴다(인라인 GSAP 을 이기려).
     그 외에는 한 줄도 쓰지 않는다.

   @layer 순서: 00-layer.css 에서 ..., motion, dlock; 로 선언되어 있어야 한다.
   ========================================================================== */

/* ==========================================================================
   [MOTION LAYER]  진입/리빌 상태 계약 + 인터랙션 + 접근성
   ========================================================================== */
@layer motion {

  /* Lenis: html/body 가 height:100% 이면 limit=0 이 되어 스크롤이 죽는다 */
  html.lenis,
  html.lenis body { height: auto; }

  /* 1. ★ FOUC 방지 — js-motion·엔진 init 을 기다리지 않고 즉시 숨김 ----------------
     [data-motion] = 스크롤/진입 연출 대상. 완료([data-motion-done]) 또는
     LCP 예외([data-motion-visible])만 첫 프레임부터 보인다.
     (예전: html.js-motion 일 때만 숨겨 CSS·스크립트 순서에 따라 잠깐 보였다) */
  [data-motion]:not([data-motion-done]):not([data-motion-visible]) {
    opacity: var(--m-o0, 0);
    translate: var(--m-x0, 0) var(--m-y0, 0);
    scale: var(--m-s0, 1);
    rotate: var(--m-r0, 0deg);
  }

  [data-motion][data-motion-visible]:not([data-motion-done]) {
    opacity: var(--mo, 1);
  }

  /* 서브 히어로 — 타이틀·서브카피 FOUC 방지 (fade-up 은 GSAP 인라인이 애니 중 덮음) */
  html.js-motion :is(.sol-hero, .ct-hero, .ab-hero, .c-hero, .t-hero)
  :is([class$="__title"], [class$="__body"], [class$="__copy"], [class$="__lead"]):not([data-motion-done]) {
    opacity: 0;
  }
  html.js-motion :is(.sol-hero, .ct-hero, .ab-hero, .c-hero, .t-hero)
  [class$="__title"][data-motion][data-motion-visible]:not([data-motion-done]) {
    opacity: 0;
  }
  html:not(.js-motion) :is(.sol-hero, .ct-hero, .ab-hero, .c-hero, .t-hero)
  :is([class$="__title"], [class$="__body"], [class$="__copy"], [class$="__lead"]) {
    opacity: 1;
  }

  /* word-cascade — SplitText 전 원문이 --m-o0:1 로 잠깐 노출되는 FOUC 방지 */
  [data-motion="word-cascade"]:not([data-motion-done]):not(:has(.word)) {
    opacity: 0;
  }
  html.js-motion [data-motion="word-cascade"]:not([data-motion-done]):has(.word) {
    opacity: var(--m-o0, 1);
  }

  /* JS 미실행(=html 에 js-motion 없음) — NoScript·엔진 실패 시 정적 노출 */
  html:not(.js-motion) [data-motion],
  html:not(.js-motion) [data-motion-mask],
  html:not(.js-motion) [data-motion]:not([data-motion-done]) [data-motion-target],
  html:not(.js-motion) [data-motion]:not([data-motion-done]) .word,
  html:not(.js-motion) [data-motion="list-cascade-line"] > li {
    opacity: var(--mo, 1);
    translate: none;
    scale: none;
    rotate: none;
    clip-path: none;
  }

  html:not(.js-motion) .line-mask > .line {
    translate: none;
  }

  /* 호스트가 [data-motion-target] 자식만 연출할 때 — 엔진 init·GSAP from 적용 전 깜빡임 방지.
     (--m-o0:1 호스트는 투명하지만 자식이 그대로 보이던 결함) */
  [data-motion]:not([data-motion-done]) [data-motion-target]:not([data-motion-done]) {
    opacity: var(--mt-o0, 0);
    translate: var(--mt-x0, 0) var(--mt-y0, 0);
    scale: var(--mt-s0, var(--m-s0, 1));
    rotate: var(--mt-r0, 0deg);
  }

  /* tick-pulse-row — scale 0 에서 튀어 오르는 연출. opacity 는 1 유지. */
  [data-motion="tick-pulse-row"]:not([data-motion-done]) [data-motion-target]:not([data-motion-done]) {
    --mt-o0: 1;
    --mt-s0: 0;
  }

  /* SplitText word — 호스트(--m-o0:1)만 보일 때 조각이 먼저 노출되던 깜빡임 방지 */
  [data-motion]:not([data-motion-done]) .word {
    opacity: 0;
  }

  /* list-cascade-line — li 는 본인 done 전까지 숨김 (호스트만 done → 띡 노출 방지) */
  [data-motion="list-cascade-line"] > li:not([data-motion-done]) {
    opacity: 0;
  }

  /* ★ LCP 후보 — 위 [data-motion-visible] 규칙 참고 */

  /* 마스크 리빌용 클리핑 */
  [data-motion-mask]:not([data-motion-done]) {
    clip-path: var(--m-clip0, inset(0 0 100% 0));
  }

  html:not(.js-motion) [data-motion-mask] {
    clip-path: none;
  }

  /* ★ 완료 요소 — 인라인 잔여물을 정적 상태로 되돌린다.
     이것이 "도달 불가 트리거로 갇힘" 의 최종 복구선이다.
     엔진이 IntersectionObserver 로 화면 밖 요소에도 data-motion-done 을 찍으면
     여기서 opacity:1 로 복원된다(footer 카피 갇힘의 근본 해결). */
  [data-motion-done] {
    opacity: var(--mo, 1);
    translate: none;
    scale: none;
    rotate: none;
    clip-path: none;
  }

  [data-motion-target][data-motion-done] {
    opacity: var(--mo, 1);
    translate: none;
    scale: none;
    rotate: none;
  }

  /* 2. 라인 마스크 리빌 (부모 overflow:clip + 자식 translateY) --------------- */
  .line-mask { overflow: clip; display: block; }

  /* letter-spacing-settle 의 임시 클립 — 완료(=data-motion-done) 즉시 자동 해제된다.
     인라인 스타일로 걸었더니 완료 콜백이 건너뛰어질 때 영구히 남아 글자가 잘렸다. */
  html.js-motion [data-ls-settle]:not([data-motion-done]) { overflow: clip; white-space: nowrap; }
  .line-mask > .line:not([data-motion-done]) { translate: 0 110%; }

  /* 3. CSS 전용 스크롤 리빌 (@supports 게이팅 · 미지원 시 정적 노출) --------- */
  @supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
      .reveal-css {
        animation: mc-reveal linear both;
        animation-timeline: view();
        animation-range: entry 10% cover 32%;
      }
      @keyframes mc-reveal {
        from { opacity: 0; translate: 0 24px; }
        to   { opacity: 1; translate: 0 0; }
      }
    }
  }

  /* 4. 인터랙션 (호버/프레스) — 항상 속성 명시, transition:all 금지 ---------- */
  .i-lift {
    transition-property: translate;
    transition-duration: var(--dur-fast, .2s);
    transition-timing-function: var(--ease-out-quart, cubic-bezier(.22,1,.36,1));
    transform-origin: bottom center;
  }
  @media (hover: hover) and (pointer: fine) {
    .i-lift:hover { translate: 0 -4px; }
  }
  .i-press {
    transition-property: scale;
    transition-duration: var(--dur-instant, .12s);
    transition-timing-function: var(--ease-out-quart, cubic-bezier(.22,1,.36,1));
  }
  .i-press:active { scale: .97; }

  /* 5. ★ prefers-reduced-motion — 옵션이 아니라 기본 (WCAG 2.3.3) ------------
     "느리게" 가 아니라 "즉시 최종 상태". 인라인 GSAP 을 이겨야 하므로
     이 블록에서만 !important 를 쓴다. */
  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
      animation-duration: .01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: .01ms !important;
      scroll-behavior: auto !important;
    }
    html.js-motion [data-motion],
    html.js-motion [data-motion-mask],
    html.js-motion .line-mask > .line {
      opacity: var(--mo, 1) !important;
      translate: none !important;
      scale: none !important;
      rotate: none !important;
      clip-path: none !important;
    }
    [data-parallax], [data-marquee], [data-autoplay] {
      animation: none !important;
      translate: none !important;
    }
  }
  @media (prefers-reduced-motion: no-preference) {
    html:focus-within { scroll-behavior: smooth; }
  }

  /* 6. 성능 훅 — will-change 는 엔진이 애니메이션 직전에만 부여한다 ---------- */
  .will-animate { will-change: transform, opacity; }
}

/* ==========================================================================
   [DLOCK LAYER]  마지막 레이어 — 모션이 디자인/유동배치를 이기지 못하게
   --------------------------------------------------------------------------
   motion 레이어는 components 레이어를 이긴다. 그 힘이 유동 레이아웃을 깨지
   못하도록 마지막에 두 가지 전제를 복원한다. 배치 값을 새로 정하지 않는다.
   ========================================================================== */
@layer dlock {

  /* 그리드/플렉스 아이템은 콘텐츠보다 작아질 수 있어야 한다.
     모션 훅이 붙은 노드의 min-*-size:auto 때문에 트랙이 밀려 가로 오버플로가
     나는 것을 막는다(유동형에서 가장 비싼 사고). */
  .fl-sec :is([data-motion], [data-motion-hover], [data-motion-touch]) {
    min-inline-size: 0;
  }

  /* .line-mask(overflow:clip) 는 폭을 부모에게서 받아야 한다.
     안 그러면 콘텐츠 폭으로 커져 래퍼 상한을 넘는다. */
  .fl-sec .line-mask { max-inline-size: 100%; }

  /* --------------------------------------------------------------------------
     [선택 · 폰트별] locl 글리프 전사
     Noto Sans CJK KR 처럼 <html lang="ko"> 에서 KOR locl lookup 이 문장부호를
     한국어 전용 글리프로 치환하는 폰트를 쓰면, Figma 렌더와 글자 모양이 달라진다
     (특히 가운뎃점 · / 공백 advance). 그런 폰트일 때만 아래 주석을 해제한다.
     Pretendard / Poppins / Inter 는 해당 lookup 이 없어 불필요하다.
     .fl-sec, .fl-sec * { font-feature-settings: "locl" 0; }
     -------------------------------------------------------------------------- */
}

/* 레이어 밖 — 문서 스크롤은 항상 브라우저 기본.
   Lenis·모션 레이어가 html overflow 를 가리면 전 페이지 휠이 죽는다. */
html, body {
	height: auto;
}
html {
	overflow-x: clip;
	overflow-y: auto;
}
body {
	overflow: visible;
}
