@charset "utf-8";
/* ============================================================================
   MOTION-LITE — 의존성 0 진입 모션 계약 CSS (scripts/motion-lite.js 와 한 쌍)
   ----------------------------------------------------------------------------
   왜 생겼나 (2026-09-02)
     도도·오리콤 두 프로젝트가 연달아 GSAP 엔진(motion-engine.js) 대신 **의존성 없는 15KB 엔진**을
     각자 새로 썼고, 같은 함정(p116 0면적 사전상태 · p117 넘침 · p118 재진입 · p071 레이아웃 소실)에
     각자 빠졌다. 그 두 엔진에서 실측으로 확정된 규칙을 여기 한 벌로 모은다.

   원칙
     1. **모션 채널과 레이아웃 채널을 섞지 않는다.** 레이아웃 기하는 `transform`(또는 left/top/margin)에,
        모션은 `translate`·`scale`·`rotate`·`opacity`·`clip-path` 에만 싣는다. 완료 규칙은 모션 채널만 비운다.
     2. JS 가 없으면 **전부 보인다.** 사전 상태는 `html.js-motion` 아래에만 있다.
     3. 사전 오프셋은 가로 넘침을 만들지 않는다 — X 는 clamp 된 px 이고 좁은 폭에서는 0 이다.
     4. 기본은 play-once. 재진입은 `html[data-motion-replay="floor"]` 로만 켜고, 그때도 하한이 있다.
   ========================================================================== */
:root{
  --mo-shift: clamp(24px, 3.3vw, 64px);   /* 세로 진입 진폭 */
  --mo-x:     clamp(0px, 2vw, 40px);      /* 가로 진폭 — 작게. 좁은 폭에서 0 (p117) */
  --mo-scale: .94;
  --mo-dur:   .95s;
  --mo-stag:  90ms;
  --mo-ease:  cubic-bezier(.22,.61,.36,1);
}
@media (max-width:1023.98px){ :root{ --mo-shift:26px; --mo-x:0px; --mo-scale:.97; --mo-dur:.7s; --mo-stag:70ms } }

/* ── 진입 사전 상태 — 엔진이 살아 있을 때만 ────────────────────────────── */
html.js-motion [data-mo]{
  opacity:0;
  transition:opacity var(--mo-dur) var(--mo-ease),
             translate var(--mo-dur) var(--mo-ease),
             scale     var(--mo-dur) var(--mo-ease),
             rotate    var(--mo-dur) var(--mo-ease),
             clip-path var(--mo-dur) var(--mo-ease);
  transition-delay:calc(var(--i, 0) * var(--mo-stag));
}
html.js-motion [data-mo="up"]       { translate:0 var(--mo-shift) }
html.js-motion [data-mo="down"]     { translate:0 calc(var(--mo-shift) * -1) }
html.js-motion [data-mo="left"]     { translate:calc(var(--mo-x) * -1) 0 }
html.js-motion [data-mo="right"]    { translate:var(--mo-x) 0 }
html.js-motion [data-mo="pop"]      { translate:0 calc(var(--mo-shift) * .5); scale:var(--mo-scale) }
html.js-motion [data-mo="fade"]     { }
/* 0 면적 사전 상태 — 엔진이 **부모를 대신 관측**한다(p116). 자기 자신을 관측하면 영원히 안 보인다. */
html.js-motion [data-mo="clip-up"]   { clip-path:inset(0 0 100% 0); translate:0 calc(var(--mo-shift) * .35) }
html.js-motion [data-mo="clip-left"] { clip-path:inset(0 100% 0 0) }
html.js-motion [data-mo="clip-down"] { clip-path:inset(100% 0 0 0); translate:0 calc(var(--mo-shift) * -.35) }

/* in-state — 항등값. SF10 은 이 리셋이 있어야 위 사전 상태를 "레이아웃이 아니다" 로 판정한다 */
html.js-motion [data-mo].is-in{ opacity:1; translate:0 0; scale:1; rotate:0deg; clip-path:inset(0 0 0 0) }

/* 재진입 하한(floor) — html[data-motion-replay="floor"] 에서만. 한 번 본 요소는 완전히 사라지지 않는다(p118) */
html.js-motion[data-motion-replay="floor"] [data-mo].is-floor{ opacity:.55; transition-delay:0ms }
html.js-motion[data-motion-replay="floor"] [data-mo="up"].is-floor   { translate:0 calc(var(--mo-shift) * .45) }
html.js-motion[data-motion-replay="floor"] [data-mo="down"].is-floor { translate:0 calc(var(--mo-shift) * -.45) }
html.js-motion[data-motion-replay="floor"] [data-mo="pop"].is-floor  { translate:0 calc(var(--mo-shift) * .2); scale:.985 }
html.js-motion[data-motion-replay="floor"] [data-mo^="clip"].is-floor{ clip-path:inset(0 0 0 0) }

/* 완료 규칙 — **모션 채널만** 비운다. transform 은 건드리지 않는다(p071 · SF10).
   ★ 2026-09-30 (DAEMO) — in-state `[data-mo].is-in`(명시도 0,3,1)이 이 규칙(0,2,1)을 이겨 완료 뒤에도
   translate:0px · scale:1 · rotate:0deg 가 시안 좌표 노드에 남았다(MO7-b 21건). 같은 명시도의 선택자를 함께 둔다. */
html.js-motion [data-motion-done],html.js-motion [data-mo].is-in[data-motion-done]{ translate:none; scale:none; rotate:none; clip-path:none; transition:none }

/* ── 패럴랙스 (미디어·장식 전용 · p033) — translate 만 얹는다. 회전·좌표는 그대로 ── */
[data-parallax]{ will-change:translate }

/* ── 플로팅 CTA 도킹 (p127) — 숨기지 않는다. 푸터가 들어오면 absolute 로 착지한다 ── */
[data-dock-to]{ position:fixed; z-index:50; transition:translate .5s var(--mo-ease) }
[data-dock-to].is-docked{ position:absolute }
/* 도킹 좌표(우/하 여백)는 프로젝트 CSS 가 시안 값으로 정한다. 여기서는 상태만 정의한다. */

/* ── 접근성: 모션을 줄여 달라고 하면 전부 끈다 ────────────────────────── */
@media (prefers-reduced-motion:reduce){
  html.js-motion [data-mo]{ opacity:1 !important; translate:none !important; scale:none !important; rotate:none !important; clip-path:none !important; transition:none !important }
  [data-parallax]{ translate:none !important }
  [data-dock-to]{ transition:none }
}

/* ==========================================================================
   PHP 보안 안내 랜딩 — Motion Grammar (강도: 강하게)
   primary   : 진입 up / clip-up / right / pop + 순차(stagger) · 1회 재생
   signature : 히어로 — 배경 줌아웃(1.12→1) + 제목 줄 단위 클립 리빌
   secondary : 69.3% 카운트업 + 진행바 채움 · STEP 02 체크 팝+획 그리기 · '필수작업' 말풍선 팝·바운스 · FAQ 아코디언
   interaction: 화살표 대각 이동 · 카드 떠오름 · 메뉴 밑줄 · 현재 섹션 메뉴 표시(scrollspy)
   ambient   : SCROLL 마우스 휠 점 이동(작게)
   금지(C10): 커서 반응 · rotateX · 문서 smooth scroll(앵커는 JS scrollTo)
   ========================================================================== */
@keyframes hero-settle{from{scale:1.12}to{scale:1}}
html.js-motion [data-hero-media]{animation:hero-settle 3.2s var(--mo-ease) backwards}
html.js-motion [data-mo="clip-up"]{--mo-dur:1.05s}

@keyframes wheel-move{0%,15%{translate:0 0;opacity:1}70%{translate:0 4px;opacity:0}71%{translate:0 0;opacity:0}100%{opacity:1}}
html.js-motion .hero__wheel{animation:wheel-move 1.8s var(--mo-ease) infinite}

/* 69.3% — 진행바 채움 (숫자는 main.js 가 카운트업) */
html.js-motion .stat:not(.is-in) [data-fill]{scale:0 1}
[data-fill]{transition:scale 1.6s var(--mo-ease) .35s}

/* STEP 02 체크 — 팝 + 획 그리기 */
.step__tick{stroke-dasharray:60;stroke-dashoffset:0;transition:stroke-dashoffset .6s var(--mo-ease) 1.05s}
html.js-motion .step--must:not(.is-in) [data-check]{scale:.3;opacity:0}
html.js-motion .step--must:not(.is-in) .step__tick{stroke-dashoffset:60}
[data-check]{transition:scale .6s cubic-bezier(.34,1.56,.64,1) .75s,opacity .3s .75s}

/* '필수작업' 말풍선 — 상자와 꼬리가 한 덩어리로 팝 후 세 번 통통.
   카드(.task)의 진입 clip-path 가 카드 밖으로 나온 말풍선을 자르지 않게 끈다. */
@keyframes tip-bob{0%,100%{translate:0 0}50%{translate:0 -6px}}
html.js-motion .task--paid:not(.is-in) [data-tip]{scale:.6;opacity:0}
[data-tip]{transform-origin:20% 100%;transition:scale .55s cubic-bezier(.34,1.56,.64,1) .45s,opacity .3s .45s}
html.js-motion .task--paid[data-motion-done] [data-tip]{animation:tip-bob 1.1s var(--mo-ease) 3}
html.js-motion .task--paid[data-mo].is-in{clip-path:none;overflow:visible}

@media (prefers-reduced-motion:reduce){
  html.js-motion [data-hero-media],html.js-motion .hero__wheel,html.js-motion .task--paid[data-motion-done] [data-tip]{animation:none}
  [data-fill],.step__tick,[data-check],[data-tip]{transition:none}
  html.js-motion .stat:not(.is-in) [data-fill]{scale:none}
  html.js-motion .step--must:not(.is-in) [data-check]{scale:none;opacity:1}
  html.js-motion .step--must:not(.is-in) .step__tick{stroke-dashoffset:0}
  html.js-motion .task--paid:not(.is-in) [data-tip]{scale:none;opacity:1}
}
