@charset "UTF-8";

/* ==========================================================================
   hyperproplus_product.css v2
   피그마: PUBLISH-K > products > 하이퍼 프로 플러스 제품페이지_PC (248:3930)
           > motion (248:3931) > 20개 씬 프레임(각 1920x1008)

   ※ 피그마의 씬 프레임은 "정지 컷"이 아니라 이동 경로를 설명하기 위한
     키포즈 스냅샷이다. 따라서 퍼블에서는 컷 단위 상태 전환이 아니라
     하나의 연속 타임라인(@keyframes + animation-delay)으로 재생한다.
     스크롤 트리거 없음 — 로드 후 자동으로 끝까지 진행.

   ────────────────────────────────────────────────────────────────────────
   마스터 타임라인 (초). hpp_product_motion.js 의 TL 상수와 반드시 동기화.

     0.00 → 0.80   링 등장 (정면 원, 기준 대비 1.3배 크기)
     0.80 → 1.90   링 **시야각 변경** — 크기는 그대로, 기울여 본 타원이 된다
     1.70 → 3.30   링 축소(1.3 → 0.7571) + cap 테두리로 이동 (시야각과 0.2s 겹쳐 인계)
     3.30 → 4.30   디바이스 페이드인(어두운 상태)   ← 스크롤 단계 분리로 이동
     3.90 → 5.10   디바이스 밝기 0.32 → 1           ← 스크롤 단계 분리로 이동
     3.30 → 4.20   링 소거
     3.80 → 5.30   뚜껑 열림 (한 번에)
     4.40 → 5.30   뚜껑 그림자
     ── scene1 종료 5.30 / delay 0.50 ──
     5.80 → 6.80   그린 배경 전환
     5.90 → 6.40   카피 마스크 인
     5.90 → 7.60   카피(stick) 하강 → **scene2-3 위치까지만** (구멍에 들어가지 않음)
     7.60 → 8.10   ── stick 정지 delay 0.50 ──
     8.10 → 8.50   카피 마스크 아웃 (줌보다 먼저 끝나 겹치지 않음)
     9.00 → 10.20  카메라 줌 (디바이스 scale 1 → 1.3)  ← 게이지보다 먼저
    10.20 → 10.80  게이지 등장
    10.40 → 10.90  숫자 등장
    10.90 → 12.90  게이지 0 → 100% (표시 10.00초 / 실제 2.00초, linear) + 스톱워치 카운트
    20.90 → 21.40  ── 카운트 10.00 도달 후 delay 0.50 ──
    21.40 → 22.30  줌 그룹 페이드아웃
    21.60 → 22.50  그린 배경 아웃
     ── scene3 ──
    22.30 → 23.30  KV 배경 먼저 등장
    23.10 →        나머지 오브젝트 reveal (0.15s 스태거)
   ────────────────────────────────────────────────────────────────────────

   좌표/크기는 모두 피그마 프레임 기준 raw px (스테이지가 scale 되므로 px 유지).
   ========================================================================== */

/* AEM reset */
body .bat-wrapper { max-width: unset; }
.aem-Grid-Container--xxl { max-width: unset; margin: 0; }

/* --------------------------------------------------------------------------
   섹션 스크롤 스냅 (PC/MO 공통, 2026-08)
   · 문서 스크롤러(html)에 걸어야 동작한다 — 전역 태그 스타일을 피하는 프로젝트
     원칙(§1)의 예외로, 스냅 특성상 다른 선택지가 없다. snap-align 이 붙은
     요소(이 페이지의 .product__section)에서만 스냅이 일어나므로 호스트 페이지의
     다른 콘텐츠에는 실질 영향이 없다.
   · mandatory 가 아니라 **proximity** — 섹션 경계 근처에서만 부드럽게 끌어당기고,
     긴 섹션(#foot)이나 빠른 스크롤은 자유롭게 통과시킨다("자연스럽게").
   · ⚠ CMS 배포 시 글로벌 네비가 main 위에 붙는데, html 에 스냅을 바로 걸면
     브라우저가 **로드 직후 초기 스냅**으로 첫 섹션을 뷰포트 상단에 정렬하며
     네비 높이만큼 자동 스크롤되는 문제가 있었다(실서버 실측). 그래서 스냅은
     사용자의 첫 스크롤 의도(휠/터치/키) 이후에만 활성화한다 — 인라인 JS 가
     html 에 .hpp-snap-on 을 붙인다. */
html.hpp-snap-on { scroll-snap-type: y proximity; }
.product__section { scroll-snap-align: start; }

/* --------------------------------------------------------------------------
   글로벌 네비 슬라이드 (2026-08) — #products 에 있는 동안 CMS 의
   .bat-header-wrapper 를 위로 슬라이드해 숨긴다 (인라인 JS 가 #products 50%
   가시 여부로 html.hpp-nav-up 을 토글). transform 기반이라 레이아웃이 변하지
   않으므로 scroll-padding-top 측정값/스냅 기준과 충돌하지 않는다.
   standalone(네비 없음)에서는 매칭 요소가 없어 no-op. */
/* 스테이징 실측(2026-08-13): 실제 네비 = .bat-header (fixed, h80, z1001).
   .bat-wrapper 는 본문 전체 컨테이너라 절대 대상이 아니다.
   ① 네비 자체는 transform 으로 슬라이드. 사이트 자체 transition 선언(특이도
      우위)에 밀려 전환이 0s 가 되는 것이 실측돼 !important 로 고정한다.
   ② 네비가 차지하는 **in-flow 공간**은 별개의 <header>(height:80, 페이지에
      1개뿐, 실측)가 만든다 — transform 만 걸면 이 스페이서가 흰 띠로 남는다.
      margin-top 을 음수로 접어 공간째 사라지게 한다(스테이징 주입 테스트로
      본문이 최상단까지 올라오는 것 확인). 높이는 JS 가 측정해 --hpp-nav-h 로
      주입(모바일 등 네비 높이 변동 대응, 기본 80px). standalone 은 no-op. */
body .bat-header { transition: transform 0.45s ease !important; }
html.hpp-nav-up .bat-header { transform: translateY(-100%); }
/* in-flow 공간 접기 — 대상은 <header> 가 아니라 **본문 컨테이너(.bat-wrapper)**.
   스테이징 실측 결과 상단 공간이 네비(80) 외 추가 요소로 환경/브레이크포인트마다
   달랐고(이번 실측 100px), header 만 접으면 잔여분이 흰 띠로 남는다(모바일 증상).
   .bat-wrapper 를 JS 실측값(--hpp-nav-h = .product__wrap 문서 오프셋)만큼 음수
   마진으로 올리면 스페이서 정체와 무관하게 항상 최상단까지 차오른다.
   ※ transform 이 아니라 margin 인 이유: transform 은 내부 fixed(플로팅 CTA,
     팝업)의 기준을 깨뜨린다. margin 은 안전(스테이징 검증 완료). */
.bat-wrapper { transition: margin-top 0.45s ease; }
/* 초기 적용 구간(hpp-nav-init)에는 트랜지션을 끈다 — 로드 직후 공간 접기가
   0.45s 동안 애니메이션되면 그만큼 흰 띠가 줄어드는 과정이 보인다. */
html.hpp-nav-init .bat-wrapper,
html.hpp-nav-init .bat-header { transition: none !important; }
/* 기본값 80px — head 인라인 스크립트가 첫 페인트 전에 이 규칙을 적용하므로,
   JS 실측 전에도 흰 띠가 그려지지 않아야 한다(실서버 GNB 높이 80 실측, PC/MO 동일).
   실측이 끝나면 JS 가 --hpp-nav-h 를 정확한 값으로 덮어쓴다.
   ※ .bat-wrapper 는 CMS 전용 래퍼라 standalone(로컬 파일)에는 존재하지 않는다
     → 이 규칙이 매칭되지 않아 로컬 레이아웃에는 아무 영향이 없다.
   ※ 트리거가 .hpp-nav-up(네비 숨김)이 아니라 **.hpp-nav-space** 인 이유 —
     방향 기반 숨김(2026-08)에서는 네비가 스크롤 중간에 수시로 토글되는데,
     그때마다 공간까지 접으면 본문이 덜컥거린다. JS 가 "네비 숨김 + 최상단
     근처"일 때만 이 클래스를 붙인다. */
html.hpp-nav-space .bat-wrapper { margin-top: calc(-1 * var(--hpp-nav-h, 80px)); }

.product__wrap {
  --product-unit: min(0.0520833vw, 1px);
  --product-unit-num: calc(var(--product-unit) / 1px);
  position: relative;
  width: 100%;
  font-family: var(--font-en, "Mont"), var(--font-kr, "Onemobile"), sans-serif;
}
.product__wrap, .product__wrap * { box-sizing: border-box; }
.product__wrap img { max-width: 100%; display: block; }
/* 스테이지 내부는 1920 고정 px 좌표계이므로 부모 폭 클램프를 해제한다.
   (.product__wrap img 가 0,1,1 이라 요소 클래스의 max-width:none 을 이김) */
.products__stage img { max-width: none; }

/* ==========================================================================
   #products — 오토플레이 모션 섹션
   ========================================================================== */
#products.product__section {
  --products-stage-scale: calc(100vw / 1920 / 1px);
  position: relative;
  width: 100%;
  aspect-ratio: 1920 / 1008;
  overflow: hidden;
  background: #000000;
}

.products__stage {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 1920px;
  height: 1008px;
  transform: translate(-50%, -50%) scale(var(--products-stage-scale));
  transform-origin: 50% 50%;
}

/* 씬2 그린 그라데이션 (피그마 렌더 샘플: #44AD6B → #7BDAA7) */
.products__bg-green {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, #44ad6b 0%, #7bdaa7 100%);
  opacity: 0;
  z-index: 0;
}

/* --------------------------------------------------------------------------
   주황 광원 링 — **2중 구조**
   scene1-1 → 1-2 는 "원이 커지는" 것이 아니라 **원을 바라보는 시야각이
   바뀌는** 연출이다. 정면(원) → 비스듬히(타원). 크기는 그대로 둔다.
   정사영에서 각도 θ 로 기울여 본 원은 폭 그대로, 높이만 cos θ 로 줄어든
   타원이 되므로 `scaleY(cosθ)` 로 정확히 표현된다.
   (perspective+rotateX 는 세로 중심 이동/사다리꼴 왜곡이 생겨 뚜껑 테두리에
    정확히 안착시키기 어렵다.)

   ① .products__ring-wrap : 위치 + opacity + **시야각(scaleY)**
   ② .products__ring(img) : **축소(scale) + 뚜껑으로 이동(translate)**
   두 모션을 서로 다른 요소에 나눠 두면 시간축에서 0.2s 겹칠 수 있어
   "기울기 끝 → 축소 시작" 접점에서 속도가 0 이 되는 정지감이 사라진다.
   (한 요소의 연속 키프레임으로는 접점 속도 0 을 피하기 어렵다.)

   1-1 원형: 렌더 실측 중심 (960, 504.5), 스트로크 중심 지름 364.55px
     ring.png(890px)는 글로우 블리드를 포함하며 스트로크 중심 지름이
     이미지 폭의 0.5787 → 표시 630px 에서 630 x 0.5787 = 364.55px.
   시야각 목표 scaleY = 126 / 276 = 0.4565  (뚜껑 테두리의 타원 비율과 동일)
   최종 축소 목표 = **뚜껑의 바깥 테두리**
     device_cap.png 실측 실루엣 x 28..303 / y 150..275 (276 x 126)
     cap-win(793,445) + 닫힘 translateY(-137) → 스테이지 x 821..1096 / y 458..583
     → 중심 (958.5, 520.5), 크기 276 x 126
     scaleX = 276 / 364.55 = 0.7571
     최종 scaleY = 0.4565(wrap) x 0.7571(img) = 0.3456 ✔ (실측값과 일치)
   ※ 부모 scaleY(0.4565) 가 자식의 translateY 도 함께 줄이므로
     자식 translateY 는 16 / 0.4565 = 35.05px 로 선보정한다. translateX 는 그대로.
   ※ 이전 구현은 피그마 노드 bbox(269.3x125.76)를 그대로 scale 로 환산해
     실제 밝은 스트로크가 뚜껑 "안쪽"에 들어가 있었다.
   -------------------------------------------------------------------------- */
.products__ring-wrap {
  position: absolute;
  left: 645px;     /* 960 - 315 */
  top: 189.5px;    /* 504.5 - 315 */
  width: 630px;
  height: 630px;
  opacity: 0;
  transform: scaleY(1);
  transform-origin: 50% 50%;
  z-index: 5;
}
.products__ring {
  position: absolute;
  left: 0;
  top: 0;
  width: 630px;
  height: 630px;
  max-width: none;
  /* 등장 크기는 기준(뚜껑 테두리=1.0 환산)보다 30% 크게 시작한다. */
  transform: translate(0, 0) scale(1.3);
  transform-origin: 50% 50%;
}

/* 카메라 줌 그룹 (Group 2147203488) */
.products__zoom {
  position: absolute;
  inset: 0;
  transform-origin: 50% 50%;
  z-index: 3;
}

/* --------------------------------------------------------------------------
   디바이스 : 피그마 379 x 1949 @ (771,440)
   줌 목표 492.7 x 2533.7 @ (714.15, -432.35)
     scale = 492.7 / 379 = 1.3
     origin.x = 960.5 → (960.5-771)/379  = 50%
     origin.y = 3347.83 → (3347.83-440)/1949 = 149.196%
   -------------------------------------------------------------------------- */
.products__device {
  position: absolute;
  left: 771px;
  top: 440px;
  width: 379px;
  height: 1949px;
  opacity: 0;
  transform: scale(1);
  transform-origin: 50% 149.196%;
  z-index: 3;
}
.products__device-body {
  position: absolute;
  left: 0;
  top: 0;
  width: 379px;
  height: auto;
  max-width: none;
  filter: brightness(0.32);
}
/* 뚜껑 그림자 : 피그마 272.098x60.068 @ (822.9043, 663.0576)
   export 이미지는 blur bleed 포함 299x87 → 좌상단 (809.45, 649.56) */
.products__cap-shadow {
  position: absolute;
  left: 38.45px;   /* 809.45 - 771 */
  top: 209.56px;   /* 649.56 - 440 */
  width: 299px;
  height: 87px;
  max-width: none;
  opacity: 0;
}
/* 뚜껑 마스크 창 : 피그마 프레임 '뚜껑' 327x276 @ (793,445) */
.products__cap-win {
  position: absolute;
  left: 22px;      /* 793 - 771 */
  top: 5px;        /* 445 - 440 */
  width: 327px;
  height: 276px;
  overflow: hidden;
}
/* 뚜껑 디스크. translateY(0) = 완전 개방 / -137 = 닫힘 */
.products__cap {
  position: absolute;
  left: 0;
  top: 0;
  width: 327px;
  height: 276px;
  max-width: none;
  transform: translateY(-137px);
}

/* --------------------------------------------------------------------------
   "얼마나 기다렸어?" 곡선 세로 카피 (stick)
   Mask group 130.4349 x 266.5029 @ x 894.8944, y -152 → … → 구멍 속으로
   마스크 하단(피그마 Vector 1 157x269 @ (881,311)) = 스테이지 y 580
   translateY 740 이면 카피 상단이 y 588 → 마스크 밖으로 완전히 사라진다.
   -------------------------------------------------------------------------- */
.products__copy-mask {
  position: absolute;
  left: 881px;
  top: -400px;
  width: 157px;
  height: 980px;      /* 하단 = -400 + 980 = 580 */
  overflow: hidden;
  z-index: 4;
  opacity: 0;
}
/* 2026-08: stick.png(131x267) → stick_pc.png(119x473) / stick_mo.png(111x432).
   좌우는 마스크 창(157) 안에서 잉크 중심이 스테이지 x960 에 오도록 가운데 정렬.
   하강 종점은 기존과 동일하게 **하단 y580(마스크 끝) 정렬** 로 잡았다:
     PC fall = (580 - 473) - (-152) = 259 → 실제로는 기존 종점과 같은 578 기준 257
     MO fall = (578 - 432) + 152 = 298
   시안에서 종점이 다르면 --hpp-copy-fall 만 조정하면 된다. */
.products__copy {
  position: absolute;
  left: 19px;         /* (157 - 119) / 2 */
  top: 248px;         /* -152 - (-400) */
  width: 119px;
  height: 473px;
  max-width: none;
  transform: translateY(0);
  --hpp-copy-fall: 257px;
}
/* PC/MO 교체 — `.product__wrap img` 리셋(0,0,1,1)보다 특이도 확보 (CLAUDE.md §10) */
.product__wrap img.products__copy--mo { display: none; }

/* --------------------------------------------------------------------------
   좌우 대형 숫자 — 스톱워치(초.1/100초). JS 가 텍스트를 갱신한다.
   Mont SemiBold 470.588px / letter-spacing -14.1176 / line-height 1.4
   색: #fff 50% (피그마 렌더 픽셀 역산 — 배경 (95,195,137) 위 (175,225,196))

   피그마 텍스트 노드의 width 에는 마지막 글자 뒤 letter-spacing 이 포함되어
   있으므로 "잉크 중심"은 박스 중심보다 7.06px 왼쪽이다.
     10 x177 w443 → 잉크중심 391.4 / 00 x1235 w576 → 잉크중심 1515.9
   text-align:center + 트레일링 스페이싱이면 잉크중심 = left + 400 - 7.06
     좌 left -2   → 390.9   우 left 1123 → 1515.9  ✔
   -------------------------------------------------------------------------- */
.products__num {
  position: absolute;
  top: 228.588px;
  width: 800px;
  height: 659px;
  font-family: "Mont", sans-serif;
  font-weight: 600;
  font-size: 470.588px;
  line-height: 1.4;
  letter-spacing: -14.1176px;
  color: rgba(255, 255, 255, 0.5);
  text-align: center;
  white-space: nowrap;
  opacity: 0;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  z-index: 2;
}
.products__num--l { left: -2px; }    /* 잉크중심 390.9 */
.products__num--r { left: 1123px; }  /* 잉크중심 1515.9 */

/* --------------------------------------------------------------------------
   게이지 (이미지 없음)
   트랙 39x329 @ (941,305) / 채움 23x313 @ (949,313) bottom-anchor(y=626)
   불꽃 35.0684x61.9356 @ (943, 660.0645) → flame.png
   -------------------------------------------------------------------------- */
.products__gauge {
  position: absolute;
  inset: 0;
  opacity: 0;
  z-index: 4;
  pointer-events: none;
}
.products__gauge-track {
  position: absolute;
  left: 941px;
  top: 305px;
  width: 39px;
  height: 329px;
  border: 2px solid #d85700;
  border-radius: 19.5px;
}
/* 채움은 **clip-path 가 아니라 height** 로 차오르게 한다.
   ※ `clip-path: inset(... round R)` 은 엔진에 따라 보간에 실패하고
     discrete(불연속) 로 처리된다. 그러면 애니메이션 50% 지점에서 0% → 100% 로
     한 번에 튀어, "5초쯤에 꽉 찬 게이지가 갑자기 나타나는" 증상이 된다.
     height 는 어디서나 보간되고, 요소 자신의 border-radius 덕분에
     차오르는 윗면도 자동으로 둥글게 마감된다(높이가 낮을 땐 캡슐 형태).
   ※ 하단 고정이어야 하므로 top 이 아니라 bottom 기준으로 배치.
     채움 하단 y = 626 → bottom = 1008 - 626 = 382
   ※ 배경 그라데이션은 높이를 따라 늘어나지 않도록 313px 로 고정하고
     하단 정렬한다(색 매핑이 게이지 전체 기준으로 유지됨). */
.products__gauge-fill {
  position: absolute;
  left: 949px;
  bottom: 382px;
  width: 23px;
  height: 0;
  border-radius: 11.5px;
  background: linear-gradient(180deg, #fa2a00 0%, #f87c0d 100%) left bottom / 23px 313px no-repeat;
}
.products__flame {
  position: absolute;
  left: 943px;
  top: 660.064px;
  width: 35.068px;
  height: 61.936px;
  max-width: none;
}

/* --------------------------------------------------------------------------
   scene3 (248:4112) 최종 KV — 배경 먼저, 나머지는 reveal
   -------------------------------------------------------------------------- */
.products__kv {
  position: absolute;
  inset: 0;
  visibility: hidden;
  z-index: 8;
}
/* kv_bg.jpg 는 피그마 원본(2022x1008 @ x=-30)을 프레임 기준으로 이미 크롭한
   1920x1008 이므로 (0,0) 에 원본 크기로 얹는다. */
.products__kv-bg {
  position: absolute;
  left: 0;
  top: 0;
  width: 1920px;
  height: 1008px;
  max-width: none;
  object-fit: cover;
  opacity: 0;
}
.products__kv-logo {
  position: absolute;
  left: 367.25px;
  top: 56.383px;
  width: 222.261px;
  max-width: none;
}
.products__kv-wise {
  position: absolute;
  left: 1598px;
  top: 103px;
  width: 264.173px;
  max-width: none;
}
.products__kv-lockup {
  position: absolute;
  left: 367.25px;
  top: 313px;
  width: 428.385px;
  max-width: none;
}
.products__kv-title {
  position: absolute;
  left: 362px;
  top: 390.258px;
  width: 533.93px;
  max-width: none;
}
.products__kv-sub {
  position: absolute;
  left: 362px;
  top: 521.193px;
  width: 568px;
  margin: 0;
  font-family: "Onemobile", "Mont", sans-serif;
  font-weight: 700;
  font-size: 52px;
  line-height: 1.4;
  letter-spacing: -0.02em;
  color: #ffffff;
  white-space: nowrap;
}
.products__kv-btns {
  position: absolute;
  left: 362px;
  top: 637.693px;
  display: flex;
  align-items: center;
  gap: 20px;
}
.products__kv-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 57px;
  border-radius: 28.5px;
  font-family: "Onemobile", "Mont", sans-serif;
  font-weight: 700;
  font-size: 21px;
  line-height: 1.3;
  letter-spacing: -0.02em;
  text-decoration: none;
  white-space: nowrap;
}
.products__kv-btn--buy {
  width: 199px;
  background: #ffffff;
  color: #fe5000;
}
/* 영상 보기 — 이미지 버튼(원본 205x57). 높이가 옆 버튼(57)과 같아 그대로 쓴다.
   .products__kv-btn 의 height/border-radius 는 이미지가 채우므로 padding 없이 둔다.
   <a> → <button>(팝업 트리거)으로 바뀌어 UA 버튼 기본 스타일을 리셋한다. */
.products__kv-btn--movie {
  width: 205px;
  border-radius: 0;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.products__kv-btn--movie img {
  width: 205px;
  height: 57px;
  max-width: none;
}
.products__kv-legal {
  position: absolute;
  left: 60px;
  top: 950px;
  margin: 0;
  font-family: "NotoSans", "Mont", sans-serif;
  font-weight: 400;
  font-size: 14px;
  line-height: 1.4;
  letter-spacing: -0.02em;
  color: rgba(255, 255, 255, 0.7);
  white-space: nowrap;
}
/* reveal 대상 공통 초기값 (2026-08: legal 은 제외 — 아래 참고) */
.products__kv-logo,
.products__kv-wise,
.products__kv-lockup,
.products__kv-title,
.products__kv-sub,
.products__kv-btns {
  opacity: 0;
  transform: translateY(30px);
}
/* 성인 고지 — 페이지 로드 시점부터 항상 노출 (2026-08 요청).
   부모 .products__kv 는 KV 등장 전까지 visibility:hidden 이지만, 자식에
   visible 을 명시하면 자식만 보인다(visibility 는 상속 후 재정의 가능). */
.products__kv-legal {
  visibility: visible;
  opacity: 1;
  transform: none;
  z-index: 9;
}

/* --------------------------------------------------------------------------
   영상 팝업 (.product__popup) — KV "영상 보기" 버튼으로 오픈. 뷰포트 고정.
   dim 60% / 영상 중앙 / 우측 상단 btn_close.png(원본 30x30).
   영상 크기는 메타데이터 로드 전에도 박스가 잡히도록 aspect-ratio 를 명시한다
   (PC 6_popup.mp4 1920x1080 = 16/9, MO 6_popup_m.mp4 1080x1920 = 9/16).
   show/hide: [hidden] ↔ .is-open — opacity 0.25s 는 JS 의 HIDE_MS(250)와 동기.
   -------------------------------------------------------------------------- */
.product__popup {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.25s ease;
}
.product__popup[hidden] { display: none; }
.product__popup.is-open { opacity: 1; }
.product__popup-dim {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.6); /* dim 60% */
  cursor: pointer;
}
.product__popup-body {
  position: relative;
  z-index: 1;
}
.product__popup-video {
  display: block;
  width: min(1200px, 86vw);
  aspect-ratio: 16 / 9;
  max-height: 80vh;
  background: #000;
}
.product__popup-close {
  position: absolute;
  right: 0;
  top: -44px; /* 영상 우측 상단 바깥 (30px 버튼 + 14px 간격) */
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.product__popup-close img { display: block; width: 100%; }
@media (max-width: 750px) {
  /* MO 는 세로 영상(9/16) — 높이 우선으로 맞추고 폭 86vw 를 넘지 않게 */
  .product__popup-video {
    width: auto;
    height: min(80vh, calc(86vw * 16 / 9));
    aspect-ratio: 9 / 16;
    max-height: none;
  }
}

/* --------------------------------------------------------------------------
   플로팅 구매하기 CTA (.product__float-cta) — 2026-08 도입
   · scene KV 등장 타이밍(18.85s = KV btns reveal 과 동일)에 hppReveal 로 등장,
     이후 스크롤과 무관하게 position:fixed 로 하단 고정.
   · #products 의 형제라 `#products.is-playing ~` 형제 셀렉터로 타이밍을 건다.
   · reveal 애니메이션(fill both)이 <a> 의 opacity 를 점유하므로 #foot 진입시
     숨김(.is-float-hidden)은 내부 .product__float-cta-box 의 opacity 로 처리.
   · 크기: PC main_btn.png 285x65 를 1920 기준 vw 로(섹션 내 표시와 동일 비율),
     MO main_btn_m.png 300x89 를 750 기준 unit 으로.
   · z-index 900 — 섹션(스테이지)들 위, 영상 팝업(9999) 아래.
   -------------------------------------------------------------------------- */
.product__float-cta {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(80 * 100vw / 1920); /* 2026-08: 40 → 80 으로 상향 */
  margin: 0 auto;
  width: calc(285 * 100vw / 1920);
  z-index: 900;
  opacity: 0;
  transform: translateY(30px);
  pointer-events: none;
}
/* 등장 — 2026-08 변경: KV 시점이 아니라 #quickstart 50% 통과 시 인라인 JS 가
   .is-float-on 을 붙인다(한 번 뜨면 유지). 애니메이션 대신 transition 이라
   foot 숨김(-box opacity)과의 fill 충돌도 없다. */
.product__float-cta {
  transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
.product__float-cta.is-float-on {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.product__float-cta-box {
  display: block;
  transition: opacity 0.3s ease;
}
.product__float-cta.is-float-hidden { pointer-events: none; }
.product__float-cta.is-float-hidden .product__float-cta-box { opacity: 0; }
.product__float-cta-img { width: 100%; }
/* PC/MO 교체 — `.product__wrap img` 리셋(0,0,1,1)보다 특이도를 높여야 한다 (CLAUDE.md §10) */
.product__wrap img.product__float-cta-img--mo { display: none; }
@media (max-width: 750px) {
  .product__float-cta {
    bottom: calc(130 * var(--product-unit-mo, 0.1333333vw)); /* easyview 원본 실측(하단 여백 187/1.44) */
    width: calc(300 * var(--product-unit-mo, 0.1333333vw));
  }
  .product__wrap img.product__float-cta-img--pc { display: none; }
  .product__wrap img.product__float-cta-img--mo { display: block; }
}
@media (prefers-reduced-motion: reduce) {
  .product__float-cta { transition: none; } /* is-float-on 토글은 즉시 반영 */
}

/* MO 전용 KV 스테이지는 데스크톱에서 숨긴다 (규칙은 파일 하단 MO 블록에 있다) */
.products__kv_m { display: none; }
/* #quickstart MO 전용 스테이지도 마찬가지 */
.quickstart_m { display: none; }
/* #dualmode 타이틀 래퍼 — PC 에서는 크기 0 의 투명 상자.
   자식(.dualmode__title)이 position:absolute 라 래퍼가 static 이면
   포함블록이 그대로 .product__video-stage 로 유지된다 → PC 좌표 무영향. */
.dualmode_l-block { position: static; }
/* MO 전용 각주 */
.dualmode_m__note,
.easycare_m__note { display: none; }
/* #easycare 카피 래퍼 — .dualmode_l-block 과 같은 이유로 PC 에서는 static */
.easycare_block-r { position: static; }

/* CTA 이미지 PC/MO 교체 (#dualmode / #easyview / #easycare / #colors)
   ※ 리셋 `.product__wrap img`(0,1,1)이 단독 클래스(0,1,0)보다 강하므로
     표시 토글은 반드시 `.product__wrap .클래스`(0,2,0) 형태로 써야 한다.
     mainbanner #preorder 에서 확정된 규칙과 같다. */
.product__wrap .dualmode__btn--mo,
.product__wrap .easyview__btn--mo,
.product__wrap .easycare__btn--mo,
.product__wrap .colors__btn--mo,
.product__wrap .colormotion__btn--mo { display: none; }
/* 모드 설명 이미지도 PC/MO 분리 (dualmode_standard_m.png / dualmode_boost_m.png) */
.product__wrap .dualmode__standard--mo,
.product__wrap .dualmode__boost--mo { display: none; }
/* #easycare 아이콘도 PC/MO 분리 (easycare_icon_m.png) */
.product__wrap .easycare__icon--mo { display: none; }
/* #foot CTA / 박스 6종도 PC/MO 분리 (foot_box1~6_m.png) */
.product__wrap .foot__btn--mo,
.product__wrap .foot__box--mo { display: none; }

/* MO 전용 줄바꿈 — <br> 을 display 로 껐다 켠다.
   PC 에서는 앞의 공백 하나만 남아 기존 한 줄이 그대로 유지된다. */
.easycare__sub-br--mo { display: none; }

/* ==========================================================================
   @keyframes
   ========================================================================== */

/* ---- 링 ① 시야각 변경 (0.80 → 1.90s, wrap 요소) ----
   확장이 아니다. 정면으로 보이던 원을 비스듬히 바라보게 되는 변화이므로
   가로폭은 그대로 두고 세로만 cos θ 로 줄인다. 목표 0.4565 = 126/276
   (뚜껑 테두리 타원의 종횡비와 동일 → 이후 축소만으로 정확히 안착). */
@keyframes hppRingTilt {
  from { transform: scaleY(1); }
  to   { transform: scaleY(0.4565); }
}
/* ---- 링 ② 축소 + 뚜껑 테두리로 이동 (1.70 → 3.30s, img 요소) ----
   시야각 변경이 끝나기 0.2s 전에 시작해 인계 지점의 속도 정지감을 없앤다.
   translateY 는 부모 scaleY(0.4565) 로 다시 축소되므로 16/0.4565 = 35.05 로 선보정. */
@keyframes hppRingShrink {
  from { transform: translate(0, 0) scale(1.3); }
  to   { transform: translate(-1.5px, 35.05px) scale(0.7571); }
}
/* 링 밝기: 등장(0~0.8s) → 유지 → 소거(3.3~4.2s). 총 4.20s */
@keyframes hppRingFade {
  0%     { opacity: 0; }
  19.05% { opacity: 1; }
  78.57% { opacity: 1; }
  100%   { opacity: 0; }
}

@keyframes hppFadeIn      { from { opacity: 0; } to { opacity: 1; } }
@keyframes hppFadeOut     { from { opacity: 1; } to { opacity: 0; } }
@keyframes hppDeviceLight { from { filter: brightness(0.32); } to { filter: brightness(1); } }
@keyframes hppCapOpen     { from { transform: translateY(-137px); } to { transform: translateY(0); } }
/* stick 은 디바이스 **안으로 들어가지 않는다**. scene2-3 위치(피그마 카피 y 311)
   까지만 내려와 멈춘다. 시작 y = -152 → 311 이므로 이동량 463px.
   (카피 하단 = 311 + 266.5 = 577.5 로 마스크 하단 580 바로 위에서 정지) */
/* 하강량은 요소의 --hpp-copy-fall 로 결정 (stick_pc/stick_mo 길이가 달라
   PC/MO 가 다른 값을 쓴다 — .products__copy 참고) */
@keyframes hppCopyFall    { from { transform: translateY(0); } to { transform: translateY(var(--hpp-copy-fall, 463px)); } }
@keyframes hppBob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-12px); }
}
@keyframes hppDeviceZoom  { from { transform: scale(1); } to { transform: scale(1.3); } }
@keyframes hppGaugeFill   { from { height: 0; } to { height: 313px; } }
@keyframes hppZoomOut {
  from { opacity: 1; transform: scale(1); }
  to   { opacity: 0; transform: scale(1.06); }
}
@keyframes hppShow        { from { visibility: hidden; } to { visibility: visible; } }
@keyframes hppReveal {
  from { opacity: 0; transform: translateY(30px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ==========================================================================
   타임라인 배치 — #products.is-playing 이 붙는 순간 전체가 함께 시작
   ========================================================================== */

/* ---- scene 1 ----
   링은 두 요소로 나눠 배치한다. 시야각 변경(0.80~1.90)과 축소·이동(1.70~3.30)이
   0.2s 겹치므로 두 동작 사이에 속도 0 구간이 생기지 않는다. */
#products.is-playing .products__ring-wrap {
  animation:
    hppRingFade 4.2s linear 0s both,
    hppRingTilt 1.1s cubic-bezier(0.45, 0, 0.35, 1) 0.8s both;
}
#products.is-playing .products__ring {
  animation: hppRingShrink 1.6s cubic-bezier(0.35, 0, 0.2, 1) 1.7s both;
}
/* 2026-08: 스크롤 단계를 "링 이동(→3.30)" / "디바이스 등장~뚜껑 열림(3.30→5.30)"
   으로 나누기 위해 디바이스 등장·밝기를 링 이동이 끝나는 3.30s 이후로 미뤘다.
   (원래 2.60 / 3.20 → 3.30 / 3.90. 종료는 각각 4.30 / 5.10 으로 5.30 안에 들어온다) */
#products.is-playing .products__device {
  animation:
    hppFadeIn 1s ease-out 3.3s both,
    hppDeviceZoom 1.2s cubic-bezier(0.65, 0, 0.35, 1) 9s both;
}
#products.is-playing .products__device-body {
  animation: hppDeviceLight 1.2s ease-in-out 3.9s both;
}
#products.is-playing .products__cap {
  animation: hppCapOpen 1.5s cubic-bezier(0.33, 1, 0.68, 1) 3.8s both;
}
#products.is-playing .products__cap-shadow {
  animation: hppFadeIn 0.9s ease-out 4.4s both;
}

/* ---- scene 2 (scene1 종료 5.30s + delay 0.50s) ----
   ※ 페이드인/아웃을 한 요소에 겹칠 때 뒤쪽 애니메이션에 backwards fill 을 주면
     (both) 지연 구간 내내 그 from 값(opacity:1)이 앞쪽을 덮어써서 처음부터
     보이게 된다. 아웃 애니메이션은 반드시 forwards 만 사용할 것. */
#products.is-playing .products__bg-green {
  animation:
    hppFadeIn 1s ease-in-out 5.8s both,
    hppFadeOut 0.9s ease-in-out 13.6s forwards;
}
/* stick 아웃은 카메라 줌(9.00~)과 겹치지 않도록 앞당기고 짧게 끝낸다.
   8.10 → 8.50 에 소거 완료 → 줌 시작까지 0.50s 여유. */
#products.is-playing .products__copy-mask {
  animation:
    hppFadeIn 0.5s ease-out 5.9s both,
    hppFadeOut 0.4s ease-in 8.1s forwards;
}
/* 하강 속도 1.5배 (2.6s → 1.7s). 5.90 → 7.60 하강 후 8.10 까지 정지(0.5s delay) */
#products.is-playing .products__copy {
  animation: hppCopyFall 1.7s cubic-bezier(0.33, 0, 0.2, 1) 5.9s both;
}
/* 게이지는 카메라 줌(9.0~10.2s)이 끝난 뒤에 등장한다 — 디바이스가 먼저. */
#products.is-playing .products__gauge {
  animation: hppFadeIn 0.6s ease-out 10.2s both;
}
#products.is-playing .products__num {
  animation: hppFadeIn 0.5s ease-out 10.4s both;
}
/* 카운터 5배속 — 화면에는 00:00 → 10:00 이 표시되지만 **실제 소요는 2.00초**다
   (2026-08: 5.00 → 2.50 → 2.00 으로 단축). 게이지도 같은 2초 동안 0→100%.
   10.90 시작 → 12.90 종료. JS 의 GAUGE_DUR_MS(2000) 와 반드시 일치시킬 것. */
#products.is-playing .products__gauge-fill {
  animation: hppGaugeFill 2s linear 10.9s both;
}
/* 카운트가 끝난 뒤 이어지는 모션은 이전과 동일하다 — 게이지 종료(15.90s)에서
   0.50s 정지 후 줌아웃, 그린 배경 아웃. 원래 21.40 / 21.60 이었던 값에서
   게이지가 5초 짧아진 만큼(-5s) 앞당긴 것이다. 종료 시각 17.50s. */
#products.is-playing .products__zoom {
  animation: hppZoomOut 0.9s ease-in 13.4s both;
}

/* ---- scene 3 : 배경 먼저 → 오브젝트 reveal ----
   KV 를 별도 #kv 섹션으로 뺐다가 원위치(#products 스테이지 끝)로 되돌렸다.
   원래 22.30~24.00s 였던 구간을, 게이지가 5초 짧아진 만큼(-5s) 앞당긴 값이다.
   그린 배경 아웃이 끝나는 17.50s 직전(17.30s)부터 KV 배경이 올라온다. */
#products.is-playing .products__kv {
  animation: hppShow 0.01s linear 14.3s both;
}
#products.is-playing .products__kv-bg {
  animation: hppFadeIn 1s ease-out 14.3s both;
}
#products.is-playing .products__kv-logo   { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 15.1s both; }
#products.is-playing .products__kv-wise   { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 15.25s both; }
#products.is-playing .products__kv-lockup { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 15.4s both; }
#products.is-playing .products__kv-title  { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 15.55s both; }
#products.is-playing .products__kv-sub    { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 15.7s both; }
#products.is-playing .products__kv-btns   { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 15.85s both; }
/* legal 은 reveal 대상에서 제외 — 처음부터 노출 (위 .products__kv-legal 참고) */

/* ==========================================================================
   최종 상태 (모션 종료 후 / 모션 미지원 폴백)
   ========================================================================== */
#products.is-ended .products__ring-wrap,
#products.is-ended .products__zoom,
#products.is-ended .products__bg-green,
#products.is-ended .products__copy-mask { opacity: 0; }
#products.is-ended .products__kv { visibility: visible; }
#products.is-ended .products__kv-bg,
#products.is-ended .products__kv-logo,
#products.is-ended .products__kv-wise,
#products.is-ended .products__kv-lockup,
#products.is-ended .products__kv-title,
#products.is-ended .products__kv-sub,
#products.is-ended .products__kv-btns,
#products.is-ended .products__kv-legal { opacity: 1; transform: translateY(0); }

/* 모션 최소화 환경: 애니메이션 없이 최종 KV 만 노출 */
@media (prefers-reduced-motion: reduce) {
  #products.is-playing * { animation: none !important; }
  #products.is-playing .products__ring-wrap,
  #products.is-playing .products__zoom,
  #products.is-playing .products__bg-green,
  #products.is-playing .products__copy-mask { opacity: 0; }
  #products.is-playing .products__kv { visibility: visible; }
  #products.is-playing .products__kv-bg,
  #products.is-playing .products__kv-logo,
  #products.is-playing .products__kv-wise,
  #products.is-playing .products__kv-lockup,
  #products.is-playing .products__kv-title,
  #products.is-playing .products__kv-sub,
  #products.is-playing .products__kv-btns,
  #products.is-playing .products__kv-legal { opacity: 1; transform: translateY(0); }
}

/* ==========================================================================
   영상 섹션 5종 (#quickstart / #easyview / #4colors / #colormotion / #easycare)
   - 각 섹션은 16:9(1920x1080) 고정 비율. 영상 파일의 실제 해상도가 다르면
     object-fit:cover 로 채운다(파일 수급 후 비율 재확인 필요).
   - 재생은 스크롤 진입 시 1회만, 종료되면 마지막 프레임에서 정지한다.
     제어는 assets/js/hpp_product_video.js 가 담당하고, 종료되면 섹션에
     .is-played 가 붙는다 → 그 뒤에 나타날 오브젝트는 이 클래스를 훅으로 쓴다.
   - 영상 5종 모두 1920x1080 / H.264 / 25fps 실측 확인 → 섹션 비율과 정확히 일치.
   - 재생 종료 후 나타나는 오브젝트는 .product__video-stage(1920x1080 고정 px 좌표계)
     안에 놓는다. #products 의 .products__stage 와 같은 방식으로 스케일된다.
   ========================================================================== */
.product__video-section {
  --product-video-scale: calc(100vw / 1920 / 1px);
  position: relative;
  width: 100%;
  aspect-ratio: 1920 / 1080;
  overflow: hidden;
  background: #000000;
}
.product__video {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  display: block;
}
/* 재생 종료 후 나타날 오브젝트용 스테이지 — 영상과 동일한 1920x1080 좌표계 */
.product__video-stage {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 1920px;
  height: 1080px;
  transform: translate(-50%, -50%) scale(var(--product-video-scale));
  transform-origin: 50% 50%;
  z-index: 1;
}
.product__video-stage img { max-width: none; }

/* --------------------------------------------------------------------------
   #quickstart — 영상 종료 후 reveal 되는 오브젝트
   좌표(1920x1080 기준):
     icon  (quickstart_icon.png 154x72)  X:948  Y:340  (340~412)
     title (72px / 130% / -2%)           X:948  Y:427  (2줄 187.2 → 427~614.2)
     sub   (bold 30px / 130% / -2%)      X:948  Y:630  (1줄 39 → 630~669)
     note  (regular 14px / 140% / -2%)   X:60   Y:1030 (~1049.6)
     btn   (main_btn.png 285x65)         X:center(817.5) Y:900  (900~965)
   ※ title 의 font-weight 는 스펙에 없어 헤드라인 관례대로 bold(700) 로 두었다.
   ※ 폰트 규칙 3: 한글은 Onemobile, 로마자/숫자는 Mont 를 앞에 둔다.
     "QuickStart™" 와 숫자("10", "2")는 .quickstart__en / .quickstart__mark 로 분리.
   ※ 모바일 좌표는 아직 미정 — 현재는 PC 좌표계가 그대로 비례 축소된다.
   -------------------------------------------------------------------------- */
.quickstart__icon {
  position: absolute;
  left: 948px;
  top: 340px;
  width: 154px;
}
.quickstart__title {
  position: absolute;
  left: 948px;
  top: 427px;
  margin: 0;
  font-family: "Onemobile", "Mont", sans-serif;
  font-weight: 700;
  font-size: 72px;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: #ffffff;
  text-align: left;
  white-space: nowrap;
}
.quickstart__sub {
  position: absolute;
  left: 948px;
  top: 630px;
  margin: 0;
  font-family: "Onemobile", "Mont", sans-serif;
  font-weight: 700;
  font-size: 30px;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: #ffffff;
  text-align: left;
  white-space: nowrap;
}
/* 로마자/숫자는 Mont 를 앞에 둔다 */
.quickstart__en { font-family: "Mont", "Onemobile", sans-serif; }
/* QuickStart(TM) — 스펙상 semibold */
.quickstart__mark {
  font-family: "Mont", "Onemobile", sans-serif;
  font-weight: 600;
}
.quickstart__note {
  position: absolute;
  left: 60px;
  top: 1030px;
  margin: 0;
  font-family: "NotoSans", "Mont", sans-serif;
  font-weight: 400;
  font-size: 14px;
  line-height: 1.4;
  letter-spacing: -0.02em;
  color: #ffffff;
  white-space: nowrap;
}
/* main_btn.png 285x65 — 가로 중앙. 나중에 플로팅 버튼으로 전용될 수 있어
   좌표를 left:50% + translateX(-50%) 로 잡지 않고 실좌표(817.5)로 둔다
   (reveal 이 transform 을 쓰기 때문에 translate 를 섞으면 서로 덮어쓴다). */
.quickstart__btn-link {
  position: absolute;
  left: 817.5px;   /* (1920 - 285) / 2 */
  top: 900px;
  display: block;
  width: 285px;
}
.quickstart__btn { width: 285px; }

/* reveal — 영상이 끝나 .is-played 가 붙는 순간 0.15s 스태거로 등장 */
.quickstart__icon,
.quickstart__title,
.quickstart__sub,
.quickstart__note,
.quickstart__btn-link {
  opacity: 0;
  transform: translateY(30px);
}
#quickstart.is-played .quickstart__icon      { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.1s both; }
#quickstart.is-played .quickstart__title     { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.25s both; }
#quickstart.is-played .quickstart__sub       { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.4s both; }
#quickstart.is-played .quickstart__btn-link  { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.55s both; }
#quickstart.is-played .quickstart__note      { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.7s both; }

@media (prefers-reduced-motion: reduce) {
  #quickstart.is-played .quickstart__icon,
  #quickstart.is-played .quickstart__title,
  #quickstart.is-played .quickstart__sub,
  #quickstart.is-played .quickstart__note,
  #quickstart.is-played .quickstart__btn-link {
    animation: none !important;
    opacity: 1;
    transform: translateY(0);
  }
}

/* --------------------------------------------------------------------------
   #dualmode — 정적 배경 + 디바이스 클릭으로 가열 모드 전환
   이 섹션만 <video> 가 없다. dualmode_bg.webp(1921x1008)를 배경으로 깔고
   디바이스는 별도 이미지로 얹는다. 배경이 세로 그라데이션 한 장이라
   background-size: 100% 100% 로 늘려도 육안 차이가 없고, 대신 가로가 잘리지 않아
   배경에 구워진 법적고지의 X 위치가 그대로 유지된다(cover 는 좌우 34px 씩 잘린다).

   좌표(1920x1080 기준):
     device (dualmode_device.png 167x723)          X:center(876.5) Y:96   (96~819)
     mask_standard / mask_boost (55x126)           X:center(932.5) Y:238 / Y:247
       → 실측: 디바이스 디스플레이 절대 y 약 237~375 안에 정확히 들어간다.
     title--l "취향에 맞춰"  bold 70px / 130% / -2%  X:354   Y:425
     title--r "선택도 쉽게"  bold 70px / 130% / -2%  X:1233  Y:425
     icon  (dualmode_icon.png 50x49)               X:center(935)   Y:500
     hint  "버튼을 클릭해 보세요." 20px / 130% / -2% X:center       Y:548
     btn   (main_btn.png 285x65)                   X:center(817.5) Y:950
     ※ 법적고지는 배경 이미지에 이미 포함되어 있어 오버레이로 두지 않는다.

   클릭 동작 (hpp_product_video.js 가 .is-step1 / .is-step2 부착):
     1차 → title--l 소거 + standard 콜아웃 + 디스플레이 mask_standard
     2차 → title--r 소거 + standard/mask_standard 소거 + boost 콜아웃 + mask_boost
           + 안내 아이콘/문구 소거
     3차 이상은 스펙에 없어 무시한다.

   ※ 상태 전환을 일반 선언(opacity)이 아니라 **애니메이션 교체**로 처리한다.
     reveal(hppReveal ... both)이 fill 상태로 남아 있으면 일반 opacity 선언보다
     우선하기 때문에, 숨길 때도 hppFadeOut 애니메이션으로 덮어써야 한다.
     transform 은 hppFadeOut 이 건드리지 않으므로 각 규칙에서 명시해 준다.
   ※ 디바이스와 마스크는 translateY 없이 페이드만 쓴다 — 마스크가 디스플레이에
     정확히 얹혀야 하므로 세로 이동이 섞이면 어긋난다.
   -------------------------------------------------------------------------- */
.product__video-section--static {
  background: #000000 url("/content/dam/glo-kr/mcs/images/event/hyperproplus/product/dualmode_bg.webp") no-repeat center / 100% 100%;
}

.dualmode__device {
  position: absolute;
  left: 876.5px;   /* (1920 - 167) / 2 */
  top: 96px;
  width: 167px;
}
.dualmode__mask {
  position: absolute;
  left: 932.5px;   /* (1920 - 55) / 2 */
  width: 55px;
  z-index: 1;
}
.dualmode__mask--standard { top: 238px; }
.dualmode__mask--boost    { top: 247px; }

.dualmode__title {
  position: absolute;
  top: 425px;
  margin: 0;
  font-family: "Onemobile", "Mont", sans-serif;
  font-weight: 700;
  font-size: 70px;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: #ffffff;
  white-space: nowrap;
}
.dualmode__title--l { left: 354px; }
.dualmode__title--r { left: 1233px; }

/* 디바이스 클릭 영역 — 실측 실루엣 x 892.5~1025.5 의 디스플레이~물리버튼 구간 */
.dualmode__hit {
  position: absolute;
  left: 892px;
  top: 220px;
  width: 134px;
  height: 320px;
  display: block;
  cursor: pointer;
  pointer-events: none;   /* reveal 전에는 클릭 불가 */
  z-index: 2;
}
#dualmode.is-played .dualmode__hit { pointer-events: auto; }

.dualmode__standard {
  position: absolute;
  left: 382px;
  top: 241px;
  width: 302px;
}
.dualmode__boost {
  position: absolute;
  left: 1260px;
  top: 241px;
  width: 255px;
}

.dualmode__icon {
  position: absolute;
  left: 935px;   /* (1920 - 50) / 2 */
  top: 500px;
  width: 50px;
  pointer-events: none;   /* 아래 .dualmode__hit 클릭을 가리지 않도록 */
}
.dualmode__hint {
  position: absolute;
  left: 0;
  top: 548px;
  width: 100%;
  margin: 0;
  font-family: "Onemobile", "Mont", sans-serif;
  font-weight: 400;
  font-size: 20px;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: #ffffff;
  text-align: center;
  pointer-events: none;
}
.dualmode__btn-link {
  position: absolute;
  left: 817.5px;   /* (1920 - 285) / 2 */
  top: 950px;
  display: block;
  width: 285px;
  z-index: 3;
}
.dualmode__btn { width: 285px; }

/* reveal 초기값 */
.dualmode__title,
.dualmode__icon,
.dualmode__hint,
.dualmode__btn-link,
.dualmode__standard,
.dualmode__boost { opacity: 0; transform: translateY(30px); }
.dualmode__device,
.dualmode__mask { opacity: 0; }   /* 세로 이동 없이 페이드만 */

/* 스크롤 진입 시 등장 (standard / boost / mask 는 클릭 전까지 숨김 유지) */
#dualmode.is-played .dualmode__device   { animation: hppFadeIn 0.8s ease-out 0s both; }
#dualmode.is-played .dualmode__title--l { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.25s both; }
#dualmode.is-played .dualmode__title--r { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.4s both; }
/* 아이콘/힌트 — reveal 후 위아래로 살짝 반복 이동해 클릭 유도 (2026-08).
   reveal(0.7s + delay)이 끝난 시점부터 hppBob 이 transform 을 이어받는다
   (뒤에 선언된 애니메이션이 같은 속성을 우선하므로 delay 이후 자연 인계). */
#dualmode.is-played .dualmode__icon {
  animation:
    hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.55s both,
    hppBob 1.6s ease-in-out 1.4s infinite;
}
#dualmode.is-played .dualmode__hint {
  animation:
    hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.65s both,
    hppBob 1.6s ease-in-out 1.5s infinite;
}
#dualmode.is-played .dualmode__btn-link { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.8s both; }

/* ---- 클릭 전환 (2026-08 재설계: STANDARD ↔ BOOST 무한 토글) ----
   JS(hpp_product_video.js)가 클릭마다 .is-mode-standard ↔ .is-mode-boost 를
   교대로 붙인다. is-step1/is-step2 는 처음 두 클릭에서 **타이틀 소거 전용**.
   아이콘/힌트("버튼을 클릭해 보세요")는 계속 유지 — 소거 규칙 삭제.
   ※ 반복 토글에는 애니메이션(fill) 방식이 안 맞다 — 클래스를 뗀 순간 fill 이
     사라져 요소가 페이드 없이 즉시 소멸(깜빡임)한다. 그래서 **transition** 으로
     전환. 기본 상태(opacity 0)로 돌아갈 때도 transition 이 페이드를 만든다. */
#dualmode.is-step1 .dualmode__title--l { animation: hppFadeOut 0.4s ease forwards; transform: translateY(0); }
#dualmode.is-step2 .dualmode__title--r { animation: hppFadeOut 0.4s ease forwards; transform: translateY(0); }

.dualmode__standard,
.dualmode__boost {
  transition: opacity 0.45s ease, transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
#dualmode.is-mode-standard .dualmode__standard,
#dualmode.is-mode-boost .dualmode__boost { opacity: 1; transform: translateY(0); }

/* 디스플레이 마스크 — **즉시 교체**(2026-08 요청). 페이드/딜레이를 모두 없앤다.
   두 마스크의 opacity 변경이 같은 스타일 재계산·같은 페인트에서 일어나므로,
   "둘 다 안 보이는" 중간 프레임이 생기지 않는다 → 구워진 화면이 비칠 틈이 없다.
   (이전에는 크로스페이드 중 반투명 구간에 비침이 생겨 0.45s 지연 소거를 썼다) */
.dualmode__mask { transition: none; }
#dualmode.is-mode-standard .dualmode__mask--standard,
#dualmode.is-mode-boost .dualmode__mask--boost { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  #dualmode.is-played .dualmode__device,
  #dualmode.is-played .dualmode__title--l,
  #dualmode.is-played .dualmode__title--r,
  #dualmode.is-played .dualmode__icon,
  #dualmode.is-played .dualmode__hint,
  #dualmode.is-played .dualmode__btn-link {
    animation: none !important; opacity: 1; transform: translateY(0);
  }
  #dualmode.is-step1 .dualmode__title--l,
  #dualmode.is-step2 .dualmode__title--r { animation: none !important; opacity: 0; }
  /* 모드 토글은 transition 만 끄면 상태 클래스가 즉시 반영된다 (아이콘/힌트 유지) */
  .dualmode__standard,
  .dualmode__boost,
  .dualmode__mask { transition: none !important; }
}

/* --------------------------------------------------------------------------
   #easyview — 영상 → 정지 이미지 이어받기(seamless handoff)
   재생이 끝나면 easyview_bg.webp + easyview_device.png 로 구성한 정지 화면을
   영상 위에 크로스페이드한다.

   "바뀐 느낌이 안 나게" 하기 위한 4가지:
     1) 영상을 숨기지 않는다. <video> 는 loop 가 없으면 마지막 프레임을 계속
        들고 있으므로, 정지 화면을 그 **위에** 겹쳐 페이드인만 시킨다.
        (display:none / opacity:0 로 영상을 내리면 그 순간 빈 화면이 보인다)
     2) 정지 화면을 DOM 에 처음부터 넣어 이미지가 미리 로드/디코딩되게 한다.
        opacity:0 이어도 배경 이미지와 <img> 는 정상적으로 받아진다.
     3) 크로스페이드는 0.3s linear — ease 계열은 중간에 두 레이어가 함께
        반투명해지는 구간이 길어져 미세한 어긋남이 겹쳐 보인다. linear 가 짧고 균일하다.
     4) 좌표계를 영상과 동일한 1920x1080 스테이지로 맞춘다.

   ※ 자산이 아직 없어 정합은 검증하지 못했다. 2_easyview.mp4 마지막 프레임 실측값:
        디바이스 잉크 상단  y = 252
        잉크 폭 216 / 가로 중심 x = 947.5  (스테이지 중앙 960 보다 12.5px 왼쪽)
        디바이스는 프레임 하단(1080)까지 잘려 나간다
     지정하신 Y:200 을 그대로 쓰려면 easyview_device.png 의 이미지 상단에서
     디바이스 잉크까지 여백이 52px 이어야 하고, X:center 로 놓으면 잉크 중심이
     12.5px 오른쪽으로 밀린다. 자산 받으면 실제 차이를 픽셀로 재서 보정하겠다.
   -------------------------------------------------------------------------- */
.easyview__still {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  /* cover = 1008 설계를 1080 섹션에 **균등** 확대(x1.07143)하고 좌우 34px 씩 잘라낸다.
     100% 100% 로 늘리면 세로만 7% 늘어나 제품 사진이 찌그러진다. */
  background: url("/content/dam/glo-kr/mcs/images/event/hyperproplus/product/easyview_bg.webp") no-repeat center / cover;
  opacity: 0;
  /* 픽셀 정합이 불가능한 전환이라 페이드를 길게 가져가 '바뀌었다'가 아니라
     '천천히 정착했다'로 읽히게 한다. */
  transition: opacity 0.9s ease-out;
  pointer-events: none;
}
#easyview.is-played .easyview__still { opacity: 1; }

/* 영상 종료 시 <video> 박스 자체를 아래로 내려 정지 이미지 디바이스와의
   위치 괴리를 줄인다 (2026-08 요청).
   이동량은 마지막 프레임 실측(ffmpeg) — 디스플레이(검정 pill) 중심 기준:
     PC 2_easyview.mp4   : 영상 y560.5 vs 정지화면 y645.0 (1920x1080) → +84.5
     MO 2_easyview_m.mp4 : 영상 y607.5 vs 정지화면 y1065.0 (1080x1920) → +457.5
       (MO 값은 파일 하단 MO 블록에서 --easyview-video-shift 로 덮어쓴다)
   페이드(0.9s)와 같은 시간/이징으로 묶어 크로스페이드 중에 미끄러져 정착한다.
   내려간 만큼 상단에 섹션 배경(#000)이 드러나지만, 같은 0.9s 동안 still 이
   전면을 덮으므로 순간적으로만 스친다. */
/* 하강 시 상단이 "잘려 보이는" 문제 보완 (2026-08):
   1) 섹션 배경을 #000 대신 정지화면 배경으로 미리 깔아 둔다 — 재생 중에는
      영상이 섹션을 꽉 채워 안 보이고, 하강으로 드러나는 상단 띠가 최종
      배경과 같은 그림이라 "배경이 이어진다"로 읽힌다.
   2) 영상 상단을 마스크로 페더링한다. mask-image 는 보간이 안 되지만
      mask-position 은 애니메이션이 되므로, 그라데이션을 요소보다 feather 만큼
      크게 만들어 평소엔 위로 밀어 두었다가(전부 불투명) is-played 에 0 으로
      내려 상단 feather 구간만 부드럽게 사라지게 한다. */
#easyview.product__video-section {
  background: #000 url("/content/dam/glo-kr/mcs/images/event/hyperproplus/product/easyview_bg.webp") no-repeat center / cover;
}
#easyview .product__video {
  --easyview-feather: calc(120 / 1920 * 100vw);
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 var(--easyview-feather));
  mask-image: linear-gradient(180deg, transparent 0, #000 var(--easyview-feather));
  -webkit-mask-size: 100% calc(100% + var(--easyview-feather));
  mask-size: 100% calc(100% + var(--easyview-feather));
  -webkit-mask-position: 0 calc(-1 * var(--easyview-feather));
  mask-position: 0 calc(-1 * var(--easyview-feather));
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  transition:
    transform 0.9s ease-out,
    mask-position 0.9s ease-out,
    -webkit-mask-position 0.9s ease-out;
}
#easyview.is-played .product__video {
  transform: translateY(var(--easyview-video-shift, calc(84.5 / 1920 * 100vw)));
  -webkit-mask-position: 0 0;
  mask-position: 0 0;
}

/* 정지 화면의 좌표계는 배경 자산과 같은 **1920x1008** 이다
   (easyview_device.png 가 Y:200 + 높이 808 = 1008 로 하단에 정확히 닿는다).
   배경의 cover 와 동일한 배율(1080/1008)을 곱해 배경과 디바이스가 함께 움직이게 한다. */
.easyview__still-stage {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 1920px;
  height: 1008px;
  transform: translate(-50%, -50%) scale(calc(var(--product-video-scale) * 1.0714286));
  transform-origin: 50% 50%;
}
.easyview__still-stage img { max-width: none; }

/* X:center / Y:200 (1008 설계 기준). width 미지정 = 자산 원본 334x808 그대로 */
.easyview__device {
  position: absolute;
  left: 50%;
  top: 200px;
  transform: translateX(-50%);
  z-index: 10;
}
/* PC/MO 자산 교체 — `.product__wrap img` 리셋(0,0,1,1)보다 특이도 확보 (CLAUDE.md §10) */
.product__wrap img.easyview__device--mo { display: none; }

@media (prefers-reduced-motion: reduce) {
  .easyview__still { transition: none; }
  #easyview .product__video { transition: none; } /* 하강/마스크도 즉시 적용 */
}

/* --------------------------------------------------------------------------
   #easyview — 정지 화면 위 오브젝트 (reveal) + 세로 롤링 목록
   좌표(스테이지 1920x1080 기준):
     title "한 눈에 확인하는 스크린" bold 62px / 130% / -2%  X:center Y:110
     roll  세로 롤링 목록                                    X:343   Y:610
     sub   bold 38px / 130% / -2% / left                     X:1194  Y:529
     btn   (main_btn.png 285x65)                             X:center(817.5) Y:900

   롤링 목록은 참고 영상(BAT_GLO_Boreas_9x16_01.mp4)과 동일한 구조다 —
   3줄이 보이는 창 안에서 목록이 한 줄씩 위로 올라가고, 가운데 줄만 밝다.
     · 창 높이 = 줄높이 x (1 + 2 x peek). peek=0.5 이라 위/아래 줄은 절반만 보이고
       나머지는 창 밖으로 잘린다(위 줄은 윗부분, 아래 줄은 아랫부분이 잘림).
     · 트랙 이동량 = (peek - 현재인덱스) x 줄높이 → 현재 항목이 항상 가운데 칸
     · 위/아래 줄은 opacity 0.3
   ※ 목록 font-size 52px. --ev-roll-fs 한 값만 바꾸면 줄높이/창높이/이동량이 따라온다.
   ※ Y:610 은 이 프로젝트의 다른 좌표와 동일하게 **가운데(현재) 줄의 라인박스 top**
     으로 해석했다.
   -------------------------------------------------------------------------- */
.easyview__title {
  position: absolute;
  left: 0;
  top: 110px;
  width: 100%;
  margin: 0;
  font-family: "Onemobile", "Mont", sans-serif;
  font-weight: 700;
  font-size: 62px;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: #ffffff;
  text-align: center;
}
.easyview__sub {
  position: absolute;
  left: 1194px;
  /* 2026-08: 롤링 목록(현재 줄 중심 643.8 = 창 중심)과 세로 middle 정렬.
     3줄 높이 148.2 → top = 643.8 - 74.1 = 570 (기존 529) */
  top: 570px;
  margin: 0;
  font-family: "Onemobile", "Mont", sans-serif;
  font-weight: 700;
  font-size: 38px;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: #ffffff;
  text-align: left;
  white-space: nowrap;
}
.easyview__mark {          /* EasyView(TM) — 로마자라 Mont, semibold */
  font-family: "Mont", "Onemobile", sans-serif;
  font-weight: 600;
}
.easyview__btn-link {
  position: absolute;
  left: 817.5px;   /* (1920 - 285) / 2 */
  top: 900px;
  display: block;
  width: 285px;
}
.easyview__btn { width: 285px; }

/* ---- 세로 롤링 목록 ---- */
.easyview__roll {
  --ev-roll-fs: 52px;
  --ev-roll-lh: calc(var(--ev-roll-fs) * 1.3);
  /* 항목 사이 여백. lh 를 통째로 더해 pitch 를 두 배로 벌렸다가,
     너무 벌어져 절반(lh/2)으로 되돌렸다. gap 0 = 예전처럼 줄이 붙는 상태. */
  --ev-roll-gap: calc(var(--ev-roll-lh) / 2);
  --ev-roll-pitch: calc(var(--ev-roll-lh) + var(--ev-roll-gap));
  /* 위/아래 줄을 몇 배만큼 보여줄지. 0.5 = 절반만 보인다. */
  --ev-roll-peek: 0.5;
  position: absolute;
  left: 343px;
  /* 가운데 줄의 라인박스 top 이 Y:610 이 되도록 창을 peek 만큼 위에서 시작.
     간격이 pitch 로 커졌으므로 기준도 pitch 다. */
  /* 여백을 글자 위아래로 절반씩 나눠 넣었으므로 gap/2 만큼 더 올린다 */
  top: calc(610px - var(--ev-roll-pitch) * var(--ev-roll-peek) - var(--ev-roll-gap) / 2);
  /* 가운데 정렬로 바꾸면서 폭을 760 -> 457 로 줄였다.
     760 이면 중심이 723 이라 가장 긴 항목(354)이 900 까지 가서 디바이스 잉크
     시작점(816)을 파고들었다(실측 확인). 457 = 800 - 343 → 중심 571.5,
     가장 긴 항목 394.5~748.5 로 디바이스 앞에서 끝난다.
     ※ 모바일은 left/right:0 + margin:auto 로 스테이지 가운데 정렬이라 폭 무관. */
  width: 457px;
  height: calc(var(--ev-roll-pitch) * (1 + 2 * var(--ev-roll-peek)));
  overflow: hidden;
  /* 위/아래 잘린 면을 직선이 아니라 서서히 사라지게.
     overflow:hidden 이 물리적으로 자르고, 마스크가 그 직전 구간을 흐린다.
     ※ 20/80 인 이유 — 위/아래 줄의 글자는 창 끝에서 각각 33.8px(=lh/2)만
       보인다. 페이드 구간을 30% (81px) 로 잡으면 그 33.8px 이 전부 알파
       0~0.42 구간에 들어가고, 항목 자체 opacity 0.3 까지 곱해져
       사실상 안 보였다. 20% (54px) 로 넓혀 최대 0.63 까지 올렸다. */
  -webkit-mask-image: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0) 0%,
    rgba(0, 0, 0, 1) 20%,
    rgba(0, 0, 0, 1) 80%,
    rgba(0, 0, 0, 0) 100%
  );
  mask-image: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0) 0%,
    rgba(0, 0, 0, 1) 20%,
    rgba(0, 0, 0, 1) 80%,
    rgba(0, 0, 0, 0) 100%
  );
}
.easyview__roll-track {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  /* 현재 인덱스는 JS 가 --ev-roll-i 로 넣는다.
     무한 롤링을 위해 앞에 1개, 뒤에 N개를 복제해 두므로 시작 인덱스는 1 이다. */
  transform: translateY(calc((var(--ev-roll-peek) - var(--ev-roll-i, 1)) * var(--ev-roll-pitch)));
  transition: transform 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}
/* 되감을 때 한 프레임 동안 트랜지션을 끈다(JS 가 붙였다 뗀다) */
.easyview__roll-track.is-snapping { transition: none; }
.easyview__roll-item {
  display: block;
  /* 박스는 pitch, 글자는 lh. 여백을 **위아래 절반씩** 나눠 넣어야
     글자가 칸 한가운데 오고, 위/아래 줄도 글자가 절반씩 보인다.
     (아래로만 몰면 현재 줄이 창 위쪽으로 치우치고 윗줄이 통째로 잘린다)
     .product__wrap * 가 border-box 라 height 에 padding 이 포함된다
     → 콘텐츠 높이 = pitch - gap = lh */
  height: var(--ev-roll-pitch);
  padding: calc(var(--ev-roll-gap) / 2) 0;
  line-height: var(--ev-roll-lh);
  font-family: "Onemobile", "Mont", sans-serif;
  font-weight: 700;
  font-size: var(--ev-roll-fs);
  letter-spacing: -0.02em;
  color: #ffffff;
  text-align: center;
  white-space: nowrap;
  opacity: 0.3;
  transition: opacity 0.45s ease;
}
.easyview__roll-item.is-current { opacity: 1; }

/* ---- 디바이스 디스플레이 안의 화면 (롤링과 동기) ----
   easyview_device.png 디스플레이 실측: 설계 left 878 / top 420 / 165x350.
   자산이 오면 실제 크기에 맞춰 다시 확인할 것. */
.easyview__screens {
  position: absolute;
  left: 878px;
  top: 420px;
  width: 165px;
  height: 350px;
}
.easyview__screen,
.easyview__screen-bg {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  max-width: none;
  opacity: 0;
}
.easyview__screen {
  z-index: 12;
  transition: opacity 0.35s ease;
}
.easyview__screen.is-current { opacity: 1; }

/* 화면 배경판 — 디바이스(10)와 화면(12) 사이.
   나타날 때는 0.25s 로 화면(0.35s)보다 먼저 자리를 잡고,
   사라질 때는 0.15s 늦게 시작해 마지막 화면이 다 빠진 뒤에 사라진다.
   (전환 속성은 "도착 상태"의 규칙이 쓰이므로 in/out 을 따로 줄 수 있다) */
.easyview__screen-bg {
  z-index: 11;
  transition: opacity 0.35s ease 0.15s;
}
.easyview__screen-bg.is-on {
  opacity: 1;
  transition: opacity 0.25s ease 0s;
}

/* reveal 초기값 / 등장 */
.easyview__title,
.easyview__roll,
.easyview__sub,
.easyview__btn-link { opacity: 0; transform: translateY(30px); }

#easyview.is-played .easyview__title    { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.9s both; }
#easyview.is-played .easyview__roll     { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 1.05s both; }
#easyview.is-played .easyview__sub      { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 1.2s both; }
#easyview.is-played .easyview__btn-link { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 1.35s both; }

@media (prefers-reduced-motion: reduce) {
  #easyview.is-played .easyview__title,
  #easyview.is-played .easyview__roll,
  #easyview.is-played .easyview__sub,
  #easyview.is-played .easyview__btn-link {
    animation: none !important; opacity: 1; transform: translateY(0);
  }
  .easyview__roll-track, .easyview__roll-item, .easyview__screen, .easyview__screen-bg { transition: none; }
}

/* --------------------------------------------------------------------------
   #easycare — 영상 종료 후 reveal (quickstart 와 동일한 구성)
   좌표(1920x1080):
     icon  (easycare_icon.png 72x72)   X:1150 Y:340  (340~412)
     title (bold 72px / 130% / -2%)    X:1150 Y:427  (2줄 187.2 → 427~614.2)
     sub   (bold 30px / 130% / -2%)    X:1150 Y:630  (1줄 39 → 630~669)
     btn   (main_btn.png 285x65)       X:center(817.5) Y:851
   -------------------------------------------------------------------------- */
.easycare__icon {
  position: absolute;
  left: 1150px;
  top: 340px;
  width: 72px;
}
.easycare__title {
  position: absolute;
  left: 1150px;
  top: 427px;
  margin: 0;
  font-family: "Onemobile", "Mont", sans-serif;
  font-weight: 700;
  font-size: 72px;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: #ffffff;
  text-align: left;
  white-space: nowrap;
}
.easycare__sub {
  position: absolute;
  left: 1150px;
  top: 630px;
  margin: 0;
  font-family: "Onemobile", "Mont", sans-serif;
  font-weight: 700;
  font-size: 30px;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: #ffffff;
  text-align: left;
  white-space: nowrap;
}
.easycare__btn-link {
  position: absolute;
  left: 817.5px;   /* (1920 - 285) / 2 */
  top: 930px;
  display: block;
  width: 285px;
}
.easycare__btn { width: 285px; }

.easycare__icon,
.easycare__title,
.easycare__sub,
.easycare__btn-link { opacity: 0; transform: translateY(30px); }
#easycare.is-played .easycare__icon      { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.1s both; }
#easycare.is-played .easycare__title     { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.25s both; }
#easycare.is-played .easycare__sub       { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.4s both; }
#easycare.is-played .easycare__btn-link  { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.55s both; }

/* --------------------------------------------------------------------------
   #colors — 컬러명은 영상 재생 시간에 동기, 카피/버튼은 종료 후 reveal
   좌표(1920x1080):
     name  (bold 72px / 130% / -2%)  Y:457 고정, X 는 항목마다 다름
             0.0s MOSS GREEN    X:1193
             1.5s BLUE          X:1339
             2.5s GRAPHITE      X:1250
             4.0s STELLA SILVER X:1180
           → X 는 각 요소의 인라인 style 로 넣어 CSS 를 한 벌만 쓴다.
     copy  (58px / 130% / -2% / center)  X:356  Y:392
     btn   (main_btn.png 285x65)         X:center(817.5) Y:851
   ※ copy 의 font-weight 는 스펙에 없어 다른 헤드라인과 동일하게 bold(700).
   -------------------------------------------------------------------------- */
.colors__name {
  position: absolute;
  top: 457px;
  margin: 0;
  font-family: "Mont", "Onemobile", sans-serif;   /* 전부 로마자 */
  font-weight: 700;
  font-size: 72px;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: #ffffff;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.35s ease;
}
.colors__name.is-current { opacity: 1; }

.colors__copy {
  position: absolute;
  left: 356px;
  top: 392px;
  margin: 0;
  font-family: "Onemobile", "Mont", sans-serif;
  font-weight: 700;
  font-size: 58px;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: #ffffff;
  text-align: center;
  white-space: nowrap;
}
.colors__en { font-family: "Mont", "Onemobile", sans-serif; }
.colors__btn-link {
  position: absolute;
  left: 817.5px;   /* (1920 - 285) / 2 */
  top: 930px;
  display: block;
  width: 285px;
}
.colors__btn { width: 285px; }

/* copy 는 reveal 없이 처음부터 고정 노출. 버튼만 재생 종료 후 등장. */
.colors__btn-link { opacity: 0; transform: translateY(30px); }
#colors.is-played .colors__btn-link { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.25s both; }

@media (prefers-reduced-motion: reduce) {
  #easycare.is-played .easycare__icon,
  #easycare.is-played .easycare__title,
  #easycare.is-played .easycare__sub,
  #easycare.is-played .easycare__btn-link,
  #colors.is-played .colors__btn-link {
    animation: none !important; opacity: 1; transform: translateY(0);
  }
  .colors__name { transition: none; }
}

/* --------------------------------------------------------------------------
   #colormotion — 재생 중 / 재생 후 카피 교체
     --play "퍼포먼스만큼 / 스타일도 / 완성된 디바이스"  X:240 Y:363  bold 72px center
     --end  "당신의 컬러를 / 선택하세요!"                X:272 Y:410  bold 72px center
   재생 중에는 --play 가 보이고(기본 노출), 영상이 끝나 .is-played 가 붙으면
   --play 는 페이드아웃, --end 가 reveal 로 올라온다.
   -------------------------------------------------------------------------- */
.colormotion__copy {
  position: absolute;
  margin: 0;
  font-family: "Onemobile", "Mont", sans-serif;
  font-weight: 700;
  font-size: 72px;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: #ffffff;
  text-align: center;
  white-space: nowrap;
}
.colormotion__copy--play { left: 240px; top: 363px; transition: opacity 0.5s ease; }
.colormotion__copy--end  { left: 272px; top: 410px; opacity: 0; transform: translateY(30px); }

/* CTA / 각주 — 다른 섹션과 같은 규격(main_btn.png 285x65 @ X:center Y:930,
   각주 NotoSans 14px @ X:60 Y:1030) */
.colormotion__btn-link {
  position: absolute;
  left: 817.5px;   /* (1920 - 285) / 2 */
  top: 930px;
  display: block;
  width: 285px;
}
.colormotion__btn { width: 285px; }
.colormotion__note {
  position: absolute;
  left: 60px;
  top: 1030px;
  margin: 0;
  font-family: "NotoSans", "Mont", sans-serif;
  font-weight: 400;
  font-size: 14px;
  line-height: 1.4;
  letter-spacing: -0.02em;
  color: #ffffff;
  white-space: nowrap;
}
.colormotion__btn-link,
.colormotion__note { opacity: 0; transform: translateY(30px); }
#colormotion.is-played .colormotion__btn-link { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.5s both; }
#colormotion.is-played .colormotion__note     { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.65s both; }

#colormotion.is-played .colormotion__copy--play { opacity: 0; }
#colormotion.is-played .colormotion__copy--end  { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.35s both; }

@media (prefers-reduced-motion: reduce) {
  .colormotion__copy--play { transition: none; }
  #colormotion.is-played .colormotion__copy--end,
  #colormotion.is-played .colormotion__btn-link,
  #colormotion.is-played .colormotion__note { animation: none !important; opacity: 1; transform: translateY(0); }
}

/* ==========================================================================
   #foot — 특징 박스 6개 + CTA + 각주
   좌표계: 1920 기준 vw 단위(--foot-unit = 100/1920 vw). 다른 섹션은 1920 고정 px
   스테이지를 transform: scale 로 줄이지만, 여기는 높이를 **콘텐츠에 맞게 자동**으로
   두어야 해서 스테이지를 쓰지 않는다(scale 된 박스는 부모 높이를 만들지 못한다).

   박스 그리드 — 원본 708x501, 가로/세로 gap 22, 2열 x 3행:
     그리드 폭  708*2 + 22      = 1438  → 좌우 여백 (1920-1438)/2 = 241
     그리드 높이 501*3 + 22*2   = 1547  → 346 ~ 1893
     열 X = 241 / 971 (=241+708+22)
     행 Y = 346 / 869 / 1392
   ※ 처음 주신 좌표(열 241/732, 행 346/524/1049)는 708x501 원본과 겹쳐서
     gap 22 + 중앙 정렬 규칙으로 다시 계산한 값이다.
   ※ 그리드 하단이 1550 -> 1893 으로 343 내려갔으므로, 그 아래 요소도 같은 폭만큼
     내려 원래 간격을 유지했다: main_btn 1600->1943 / movie_btn 1697->2040 /
     각주 2100->2443.
   ========================================================================== */
#foot.product__section {
  --foot-unit: 0.0520833vw;
  position: relative;
  width: 100%;
  overflow: hidden;
  background: #000000;
}
#foot img { max-width: none; }

.foot__title {
  position: absolute;
  left: 50%;
  top: calc(150 * var(--foot-unit));
  transform: translateX(-50%);
  width: calc(552 * var(--foot-unit));
}

.foot__box {
  position: absolute;
  width: calc(708 * var(--foot-unit));
}
.foot__box--1 { left: calc(241 * var(--foot-unit)); top: calc(346 * var(--foot-unit)); }
.foot__box--2 { left: calc(971 * var(--foot-unit)); top: calc(346 * var(--foot-unit)); }
.foot__box--3 { left: calc(241 * var(--foot-unit)); top: calc(869 * var(--foot-unit)); }
.foot__box--4 { left: calc(971 * var(--foot-unit)); top: calc(869 * var(--foot-unit)); }
.foot__box--5 { left: calc(241 * var(--foot-unit)); top: calc(1392 * var(--foot-unit)); }
.foot__box--6 { left: calc(971 * var(--foot-unit)); top: calc(1392 * var(--foot-unit)); }

.foot__btn-link {
  position: absolute;
  left: 50%;
  top: calc(1943 * var(--foot-unit));
  transform: translateX(-50%);
  display: block;
  width: calc(285 * var(--foot-unit));
}
.foot__btn { width: 100%; }
.foot__movie-link {
  position: absolute;
  left: 50%;
  top: calc(2040 * var(--foot-unit));
  transform: translateX(-50%);
  display: block;
  width: calc(217 * var(--foot-unit));
  /* <a> → <button>(영상 팝업 트리거) 전환에 따른 UA 기본 스타일 리셋 */
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.foot__movie { width: 100%; }

/* 유일한 일반 흐름 요소 — 이 블록의 높이가 섹션 높이를 만든다.
   margin-top 으로 Y 를, margin-left 로 X:37 을 준다. */
.foot__note {
  margin: calc(2143 * var(--foot-unit)) calc(37 * var(--foot-unit)) calc(80 * var(--foot-unit));
  font-family: "NotoSans", "Mont", sans-serif;
  font-weight: 400;
  font-size: calc(16 * var(--foot-unit));
  line-height: 1.25;
  letter-spacing: -0.03em;
  color: #ffffff;
}
/* --------------------------------------------------------------------------
   #foot 스크롤 리빌 (PC / MO 공용)
   이 섹션만 <video> 가 없어 .is-played 훅이 없다 → hpp_product_video.js 의
   initFootReveal() 이 IntersectionObserver 로 요소마다 .is-in 을 붙인다.
   숨김을 `#foot.is-reveal-ready` 아래에만 두는 이유 — JS 가 안 돌면 아무것도
   숨지 않아야 하기 때문이다(스크립트 실패 시 백지 방지).
   ※ .foot__title / .foot__btn-link / .foot__movie-link 는 PC 에서
     translateX(-50%) 로 가로 중앙을 잡고 있어 세로 이동을 덧붙여야 한다.
     (MO 블록에서 이 셋의 translateX 를 걷어내고 다시 정의한다)
   -------------------------------------------------------------------------- */
#foot { --foot-reveal-dy: 30px; }
#foot.is-reveal-ready .foot__box,
#foot.is-reveal-ready .foot__note {
  opacity: 0;
  transform: translateY(var(--foot-reveal-dy));
}
#foot.is-reveal-ready .foot__title,
#foot.is-reveal-ready .foot__btn-link,
#foot.is-reveal-ready .foot__movie-link {
  opacity: 0;
  transform: translateX(-50%) translateY(var(--foot-reveal-dy));
}
#foot.is-reveal-ready .foot__box,
#foot.is-reveal-ready .foot__note,
#foot.is-reveal-ready .foot__title,
#foot.is-reveal-ready .foot__btn-link,
#foot.is-reveal-ready .foot__movie-link {
  transition:
    opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}
#foot.is-reveal-ready .foot__box.is-in,
#foot.is-reveal-ready .foot__note.is-in {
  opacity: 1;
  transform: translateY(0);
}
#foot.is-reveal-ready .foot__title.is-in,
#foot.is-reveal-ready .foot__btn-link.is-in,
#foot.is-reveal-ready .foot__movie-link.is-in {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}


/* ==========================================================================
   #foot — 모바일 (max-width: 750px)
   ──────────────────────────────────────────────────────────────────────────
   이 섹션만 스케일 스테이지가 아니라 **1920 기준 vw 단위(--foot-unit)** 를
   그대로 쓴다(높이가 콘텐츠에 따라 자동이어야 해서 scale 박스를 못 쓴다).
   따라서 MO 값도 1920 기준으로 적는다 — 750 기준 값을 섞지 말 것.
     · 타이틀 폭 1000 → 화면의 52.1%
     · 박스   폭 1400 → 화면의 72.9%

   PC 는 2열 x 3행 절대배치, MO 는 **1열 6행**이다. 배치 방식이 반대라
   각 이미지를 `.foot__box-row` 로 감싸고 MO 에서만 흐름 배치로 바꾼다.
   래퍼는 PC 에서 높이 0 인 빈 블록이라(자식이 absolute) 레이아웃에 영향이 없다.

   MO 는 타이틀만 절대배치로 남기고 박스/버튼/각주를 전부 흐름에 태운다
   — 박스 높이가 6장 누적되므로 절대좌표로는 아래 요소를 따라가게 할 수 없다.
   ========================================================================== */
@media (max-width: 750px) {

  .foot__title {
    top: calc(400 * var(--foot-unit));
    width: calc(1000 * var(--foot-unit));
  }

  /* 1열 6행. 첫 행은 타이틀(400 + 1000x0.1757 = 575.7) 아래로 내려보낸다.
     #foot 이 overflow:hidden 이라 첫 자식의 margin-top 이 밖으로 새지 않는다. */
  .foot__box-row {
    width: calc(1400 * var(--foot-unit));
    margin: 0 auto calc(60 * var(--foot-unit));
  }
  .foot__box-row:first-of-type { margin-top: calc(740 * var(--foot-unit)); }
  .product__wrap .foot__box--pc { display: none; }
  .product__wrap .foot__box--mo { display: block; }
  .foot__box {
    position: static;
    left: auto;
    top: auto;
    width: 100%;
  }

  /* 버튼 2종도 흐름으로 — 박스 6장 아래에 자동으로 따라온다.
     폭 지정 없이 원본 크기를 쓰므로 링크는 width:max-content 로 이미지를 감싸고
     margin:auto 로 중앙 정렬한다.
     ※ 이 섹션은 스케일 스테이지가 아니라서 원본 px 가 **CSS px 그대로**다
       (다른 섹션처럼 뷰포트에 따라 줄지 않는다). main_btn_m.png / foot_movie_btn.png
       의 실제 크기가 모바일 표시 크기가 된다. */
  .product__wrap .foot__btn--pc { display: none; }
  .product__wrap .foot__btn--mo { display: block; }
  .foot__btn-link {
    position: static;
    left: auto;
    top: auto;
    transform: none;
    width: max-content;
    margin: calc(200 * var(--foot-unit)) auto 0;
  }
  .foot__btn { width: auto; }
  /* 구매하기(main_btn_m.png 원본 300x89)를 아래 영상보기 버튼과 같은 폭으로
     비율 축소 (2026-08): foot_movie_btn.png 원본 폭 217 → 217x64.4 */
  .product__wrap .foot__btn--mo { width: 217px; }
  .foot__movie-link {
    position: static;
    left: auto;
    top: auto;
    transform: none;
    width: max-content;
    margin: calc(60 * var(--foot-unit)) auto 0;
  }
  .foot__movie { width: auto; }

  /* 리빌 — MO 에서는 버튼/영상버튼이 흐름 배치라 translateX(-50%) 가 없다.
     이동량도 다른 섹션(750 기준 30)과 화면상 같은 거리로 맞춘다(30 x 1920/750). */
  #foot { --foot-reveal-dy: calc(76.8 * var(--foot-unit)); }
  #foot.is-reveal-ready .foot__btn-link,
  #foot.is-reveal-ready .foot__movie-link {
    transform: translateY(var(--foot-reveal-dy));
  }
  #foot.is-reveal-ready .foot__btn-link.is-in,
  #foot.is-reveal-ready .foot__movie-link.is-in {
    transform: translateY(0);
  }

  /* 각주 — 다른 MO 각주(750 기준 14px / 500)와 **화면상 같은 크기**로 맞춘다.
     14 x 1920/750 = 35.84 */
  .foot__note {
    margin: calc(120 * var(--foot-unit)) calc(60 * var(--foot-unit)) calc(120 * var(--foot-unit));
    font-weight: 500;
    font-size: calc(35.84 * var(--foot-unit));
    line-height: 1.4;
  }

}

/* ==========================================================================
   #quickstart — 모바일 (max-width: 750px) / 750 x 1200
   ──────────────────────────────────────────────────────────────────────────
   PC 는 건드리지 않는다. PC 스테이지(.product__video-stage)는 MO 에서 통째로
   끄고, 전용 DOM `.quickstart_m` 을 쓴다. 줄바꿈이 PC 와 다르기 때문이다
   (타이틀 2줄 → 4줄 / 서브 1줄 → 2줄). <br> 는 미디어쿼리로 못 끄므로
   `_m` 서브트리 분리가 유일한 방법이다.

   ── 단위: 스케일 스테이지로 통일 ──────────────────────────────────────────
   `.quickstart_m` 은 처음에 width/height 100% 의 평범한 박스라서 내부 좌표를
   전부 `calc(N * var(--quickstart-unit-mo))` (vw 기반) 으로 써야 했다.
   지금은 #dualmode / .product__video-stage 와 **같은 방식**으로 바꿨다 —
   750x1200 고정 px 박스를 `scale(100vw/750)` 로 축소한다.
   → 내부는 raw px 가 곧 750 기준 디자인 단위다. calc() 필요 없음.
   → 원본 크기를 그대로 쓰는 이미지(예: CTA)도 자동으로 뷰포트에 맞춰 줄어든다.

   ※ 규칙: **스테이지 바깥 DOM**(.products__kv_m) → vw 기반 unit,
           **스케일 스테이지 안**(.quickstart_m / .product__video-stage) → raw px.

   ── 좌표 ──────────────────────────────────────────────────────────────────
   `.quickstart_l-block`(280 / 440) 안에 아이콘·타이틀·서브를 넣고 흐름 +
   margin-top 으로 쌓는다. 블록만 옮기면 셋이 같이 움직인다.
   좌측 정렬선 420 → 카피 가용 폭 330. 실측 sub 가장 긴 줄 305.6 로 여유 24.4.

   ※ 섹션 비율 750:1200(0.625). MO 영상 1_quickstart_m.mp4 는 2160x3840(0.5625)
     이라 cover 로 상하 각 5.5% 가 잘린다.
   ========================================================================== */
@media (max-width: 750px) {

  /* 750 기준 공통 단위 — 스케일 스테이지 **바깥**에 있는 DOM 전용
     (.products__kv_m 등). 스테이지 안에서는 쓰면 안 된다(두 번 축소됨). */
  .product__wrap { --product-unit-mo: 0.1333333vw; }

  #quickstart.product__video-section {
    aspect-ratio: 750 / 1200;
  }

  /* PC 스테이지는 통째로 끈다 */
  #quickstart .product__video-stage { display: none; }

  /* MO 스테이지 — 750x1200 고정 px 좌표계 */
  .quickstart_m {
    display: block;
    position: absolute;
    left: 50%;
    top: 50%;
    width: 750px;
    height: 1200px;
    transform: translate(-50%, -50%) scale(calc(100vw / 750 / 1px));
    transform-origin: 50% 50%;
    z-index: 1;
  }
  .quickstart_m img { max-width: none; display: block; }

  /* 아이콘/타이틀/서브 묶음 */
  .quickstart_l-block {
    position: absolute;
    top: 280px;
    left: 420px;
  }
  /* 폭 지정 없음 — quickstart_icon_m.png 원본 크기를 그대로 쓴다.
     스테이지가 scale 되므로 원본 px = 750 기준 디자인 단위다.
     (CTA / dualmode 모드 이미지와 같은 방식) */
  .quickstart_m__icon {
    position: relative;
    left: 0;
    top: auto;
    margin: 0;
  }
  .quickstart_m__title {
    position: relative;
    left: 0;
    top: auto;
    margin: 30px 0 0;
    font-family: "Onemobile", "Mont", sans-serif;
    font-weight: 700;
    font-size: 56px;
    line-height: 1.3;
    letter-spacing: -0.02em;
    color: #ffffff;
    text-align: left;
    white-space: nowrap;
  }
  .quickstart_m__sub {
    position: relative;
    left: 0;
    top: auto;
    margin: 40px 0 0;
    font-family: "Onemobile", "Mont", sans-serif;
    font-weight: 700;
    font-size: 26px;
    line-height: 1.3;
    letter-spacing: -0.02em;
    color: #ffffff;
    text-align: left;
    white-space: nowrap;
  }
  .quickstart_m__en { font-family: "Mont", "Onemobile", sans-serif; }
  .quickstart_m__mark {
    font-family: "Mont", "Onemobile", sans-serif;
    font-weight: 600;
  }

  /* CTA — 폭 지정 없이 main_btn_m.png 원본 크기 그대로.
     스테이지가 scale 되므로 원본 px = 750 기준 디자인 단위가 된다.
     가로 중앙은 left/right:0 + margin:auto + width:max-content 로 잡는다
     (translateX 를 쓰면 reveal 의 transform 과 서로 덮어쓴다).
     세로는 하단에서 120. */
  .quickstart_m__btn-link {
    position: absolute;
    left: 0;
    right: 0;
    top: auto;
    bottom: 120px;
    display: block;
    width: max-content;
    margin: 0 auto;
  }
  .quickstart_m__btn { width: auto; }

  .quickstart_m__note {
    position: absolute;
    left: 48px;
    top: 1148px;
    margin: 0;
    font-family: "NotoSans", "Mont", sans-serif;
    font-weight: 500;
    font-size: 14px;
    line-height: 1.4;
    letter-spacing: -0.02em;
    color: rgba(255, 255, 255, 0.7);
    white-space: nowrap;
  }

  /* reveal — PC .quickstart__* 와 1:1 미러 (영상 종료 .is-played 훅) */
  .quickstart_m__icon,
  .quickstart_m__title,
  .quickstart_m__sub,
  .quickstart_m__note,
  .quickstart_m__btn-link {
    opacity: 0;
    transform: translateY(30px);
  }
  #quickstart.is-played .quickstart_m__icon     { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.1s both; }
  #quickstart.is-played .quickstart_m__title    { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.25s both; }
  #quickstart.is-played .quickstart_m__sub      { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.4s both; }
  #quickstart.is-played .quickstart_m__btn-link { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.55s both; }
  #quickstart.is-played .quickstart_m__note     { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.7s both; }
}

@media (max-width: 750px) and (prefers-reduced-motion: reduce) {
  /* #easycare 화면 이동은 최종 상태만 즉시 적용 */
  #easycare .product__video { transition: none; }
  /* 모션 최소화 환경에서도 1차 클릭에 두 줄 다 사라져야 한다 */
  #dualmode.is-step1 .dualmode__title--r { animation: none !important; opacity: 0; }
  #quickstart.is-played .quickstart_m__icon,
  #quickstart.is-played .quickstart_m__title,
  #quickstart.is-played .quickstart_m__sub,
  #quickstart.is-played .quickstart_m__note,
  #quickstart.is-played .quickstart_m__btn-link {
    animation: none !important;
    opacity: 1;
    transform: translateY(0);
  }
}

/* ==========================================================================
   #products — 모바일 (max-width: 750px) / 750 x 1200
   ──────────────────────────────────────────────────────────────────────────
   ※ PC 는 건드리지 않는다. 이 블록 안에서만 재배치한다.

   [1] 섹션 비율을 750:1200 (0.625) 으로 바꾼다.

   [2] 모션 씬(1~2)은 PC 스테이지(1920x1008)를 그대로 재사용한다.
       링/디바이스/뚜껑/게이지/카피는 전부 x 960 을 중심으로 폭 630 안에 들어
       있으므로, 스테이지를 "세로가 꽉 차도록" 키우면 그 중앙 컬럼이 정확히
       모바일 프레임을 채운다.
         스테이지 렌더 높이 = 1008 * s = 섹션 높이 = 100vw * 1200/750
         → s = 100vw / 630
       이때 렌더 폭은 1920 * s = 3.048 * 100vw 라 좌우가 잘리고,
       **보이는 PC 좌표 범위는 x 645 ~ 1275 / y 0 ~ 1008** 이 된다.
       → 키프레임(translate px)과 요소 좌표를 하나도 고치지 않아도 된다.

   [3] 유일한 예외가 좌우 대형 숫자(스톱워치)다. PC 에서 x -2 / 1123 에 폭 800
       이라 세로 프레임에서는 완전히 화면 밖이다. 가시 범위(645~1275) 안으로
       옮기고 크기를 줄인다. 이 위치에서는 줌된 디바이스와 겹치므로
       z-index 를 디바이스(3)/게이지(4) 위인 5 로 올린다
       (게이지는 x 941~980 이라 숫자 박스와 가로로 겹치지 않는다).

   [4] scene3 최종 KV 는 세로 배치가 필요해 **별도 DOM(.products__kv_m)** 을
       쓴다. PC 의 .products__kv 는 숨긴다. 배치 기준은 preorder.html #main 의
       모바일 스테이지(.main_stage_m) — 좌측 정렬선 X:48, 로고 좌상단 /
       배지 우상단, 락업 → 타이틀 → 서브 → CTA 순. 단위는 750 기준.
       reveal 타이밍은 PC 와 동일한 값으로 미러링한다(17.3s ~ 19.0s).

   ※ 미확인: MO 전용 KV 배경 자산이 없다. kv_bg.jpg(1920x1008 가로)를
     cover 로 채우고 있어 디바이스 4개 스택이 크게 잘린다. kv_bg_m 필요.
   ========================================================================== */
@media (max-width: 750px) {

  #products.product__section {
    /* 750 기준 1unit = 100/750 vw */
    --product-unit-mo: 0.1333333vw;
    /* 세로가 꽉 차도록: 1008 * s = 100vw * 1.6  →  s = 100vw / 630 */
    --products-stage-scale: calc(100vw / 630 / 1px);
    aspect-ratio: 750 / 1200;
  }

  /* ---- [3] 스톱워치 숫자 — **하단 전폭** 배치 (2026-08 시안 변경) ----
     가시 범위 x 645~1275 (스테이지 중앙 630px 폭만 보임 — 스케일 100vw/630).
     시안(750x1200): 숫자 4자리가 하단(세로중심 ≈ 81%)에 거의 전폭으로 깔린다.
       세로중심 0.81 x 1008 ≈ 817 → 박스 top = 817 - (200 x 1.4)/2 = 675
       좌 "00"(초) 650~935 우측정렬 / 우 "00"(1/100초) 985~1270 좌측정렬
       → 그룹 사이 50px 간격, 양끝 여백 5px.
     letter-spacing 은 PC 와 같은 -3% (= -6/200) 비율을 유지. */
  .products__num {
    top: 675px;
    width: 285px;
    height: 280px;
    font-size: 200px;
    letter-spacing: -6px;
    z-index: 5;
  }
  .products__num--l { left: 650px; text-align: right; }
  .products__num--r { left: 985px; text-align: left; }

  /* stick MO 자산 교체 — stick_mo.png 111x432. 종점 하단 578 정렬 (base 주석 참고) */
  .product__wrap img.products__copy--pc { display: none; }
  .product__wrap img.products__copy--mo { display: block; }
  .products__copy {
    left: 23px;        /* (157 - 111) / 2 */
    width: 111px;
    height: 432px;
    --hpp-copy-fall: 298px;
  }

  /* ---- [3b] 숫자 뒤 배경 블러 밴드 (시안: 하단부 블러 위에 숫자) ----
     .products__zoom 의 ::after 로 만들어 backdrop-filter 로 아래에 그려진
     그린 배경 + 디바이스 본체를 흐린다.
     z-index 3 = 디바이스(3)와 동급이지만 트리상 뒤라 디바이스 위,
     게이지(4)/숫자(5)보다는 아래 → 게이지·불꽃·숫자는 선명하게 유지된다.
     top 660 은 디스플레이/게이지 하단(불꽃 660~722, z4라 어차피 밴드 위)
     아래에서 시작한다는 뜻이고, 상단 90px 마스크 페이드로 경계선을 없앤다.
     등장은 숫자와 동일 타이밍(10.4s), 소거는 줌 그룹 페이드아웃(16.4s)에 편승. */
  .products__zoom::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 660px;
    bottom: 0;
    backdrop-filter: blur(18px);
    -webkit-backdrop-filter: blur(18px);
    -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 90px);
    mask-image: linear-gradient(180deg, transparent 0, #000 90px);
    opacity: 0;
    z-index: 3;
    pointer-events: none;
  }
  #products.is-playing .products__zoom::after {
    animation: hppFadeIn 0.5s ease-out 10.4s both;
  }

  /* ---- [4] KV : PC 숨김 / MO 스테이지 노출 ---- */
  .products__kv { display: none; }

  .products__kv_m {
    display: block;
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    visibility: hidden;
    overflow: hidden;
    z-index: 8;
  }
  .products__kv_m img { max-width: none; display: block; }

  /* 2026-08: MO 전용 자산 kv_bg_m.jpg 로 교체 — 가로 자산 시절의
     object-position 71% 보정을 제거하고 중앙 cover.
     (파일 수급 후 비율이 스테이지 750:1200 과 다르면 실측해서 조정) */
  .products__kv_m-bg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
    opacity: 0;
  }

  /* 로고 128 x 90 @ (51.8, 32.76) — preorder .main_stage_m__logo 와 동일 */
  .products__kv_m-logo {
    position: absolute;
    left: calc(51.8 * var(--product-unit-mo));
    top: calc(32.76 * var(--product-unit-mo));
    width: calc(128 * var(--product-unit-mo));
  }
  /* "현명한 선택" 배지 172 @ (542.35, 38) — 우측 여백 35.65 */
  .products__kv_m-wise {
    position: absolute;
    left: calc(542.35 * var(--product-unit-mo));
    top: calc(38 * var(--product-unit-mo));
    width: calc(172 * var(--product-unit-mo));
  }
  /* 락업 285.5 @ (48, 162.77) */
  .products__kv_m-lockup {
    position: absolute;
    left: calc(48 * var(--product-unit-mo));
    top: calc(162.77 * var(--product-unit-mo));
    width: calc(285.5 * var(--product-unit-mo));
  }
  /* 타이틀 491.4 @ (48, 218.41) */
  .products__kv_m-title {
    position: absolute;
    left: calc(48 * var(--product-unit-mo));
    top: calc(218.41 * var(--product-unit-mo));
    width: calc(491.4 * var(--product-unit-mo));
  }
  /* 서브카피 — preorder 서브타이틀 자리(Y:330.5) / 52.46px.
     PC(.products__kv-sub 52px, 1920 기준)와 같은 문구, 한 줄. */
  .products__kv_m-sub {
    position: absolute;
    left: calc(48 * var(--product-unit-mo));
    top: calc(330.5 * var(--product-unit-mo));
    margin: 0;
    font-family: "Onemobile", "Mont", sans-serif;
    font-weight: 700;
    font-size: calc(52.46 * var(--product-unit-mo));
    line-height: 1.25;
    letter-spacing: -0.02em;
    color: #ffffff;
    white-space: nowrap;
  }
  /* CTA — preorder 는 Y:549.5 지만 이 섹션은 기간 라인이 없어 그만큼(66) 올린다.
     크기 규격(h60 / pad 40 / radius 1000 / 28px)은 페이지 공통 모바일 CTA 와 동일.
     색은 KV 규격 유지(흰 배경 + 오렌지 텍스트). */
  /* 2026-08: 두 버튼을 +40 내리고, 구매하기 크기를 영상보기(216x60)와 동일 박스로 통일 */
  .products__kv_m-btns {
    position: absolute;
    left: calc(48 * var(--product-unit-mo));
    top: calc(470 * var(--product-unit-mo)); /* 430 + 40 */
    display: flex;
    align-items: center;
    gap: calc(20 * var(--product-unit-mo));
  }
  .products__kv_m-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: calc(216 * var(--product-unit-mo));  /* 영상보기 버튼과 동일 폭 */
    height: calc(60 * var(--product-unit-mo));
    padding: 0;
    border-radius: calc(1000 * var(--product-unit-mo));
    font-family: "Onemobile", "Mont", sans-serif;
    font-weight: 700;
    font-size: calc(28 * var(--product-unit-mo));
    line-height: 1.3;
    letter-spacing: -0.02em;
    text-decoration: none;
    white-space: nowrap;
  }
  .products__kv_m-btn--buy {
    background: #ffffff;
    color: #fe5000;
  }
  /* 영상 보기(MO) — 구매하기 **아래**. main_movie_btn_m.png 실측 126x35 를
     옆 PC 규격(영상보기 높이 = 구매 버튼 높이)과 같은 원칙으로 h60 에 맞춰
     w216(= 126/35 x 60) 으로 표시한다. 시안 확정되면 이 폭만 조정. */
  .products__kv_m-movie {
    position: absolute;
    left: calc(48 * var(--product-unit-mo));
    top: calc(554 * var(--product-unit-mo)); /* btns top 470 + h 60 + 간격 24 */
    width: calc(216 * var(--product-unit-mo));
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
  }
  .products__kv_m-movie img { width: 100%; display: block; }
  /* 성인 고지 — preorder MO(1300 기준 Y:1222 = 94.0%)를 1200 기준으로 환산 */
  .products__kv_m-legal {
    position: absolute;
    left: calc(48 * var(--product-unit-mo));
    top: calc(1148 * var(--product-unit-mo));
    margin: 0;
    font-family: "NotoSans", "Mont", sans-serif;
    font-weight: 500;
    font-size: calc(14 * var(--product-unit-mo));
    line-height: 1.4;
    letter-spacing: -0.02em;
    color: rgba(255, 255, 255, 0.7);
    white-space: nowrap;
  }
  /* reveal 초기값 */
  .products__kv_m-logo,
  .products__kv_m-wise,
  .products__kv_m-lockup,
  .products__kv_m-title,
  .products__kv_m-sub,
  .products__kv_m-btns,
  .products__kv_m-movie {
    opacity: 0;
    transform: translateY(30px);
  }
  /* 성인 고지 — PC 와 동일하게 처음부터 노출 (2026-08) */
  .products__kv_m-legal {
    visibility: visible;
    opacity: 1;
    transform: none;
    z-index: 9;
  }

  /* ---- reveal 타이밍 : PC .products__kv-* 와 1:1 미러 ---- */
  #products.is-playing .products__kv_m    { animation: hppShow 0.01s linear 14.3s both; }
  #products.is-playing .products__kv_m-bg { animation: hppFadeIn 1s ease-out 14.3s both; }
  #products.is-playing .products__kv_m-logo   { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 15.1s both; }
  #products.is-playing .products__kv_m-wise   { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 15.25s both; }
  #products.is-playing .products__kv_m-lockup { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 15.4s both; }
  #products.is-playing .products__kv_m-title  { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 15.55s both; }
  #products.is-playing .products__kv_m-sub    { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 15.7s both; }
  #products.is-playing .products__kv_m-btns   { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 15.85s both; }
  #products.is-playing .products__kv_m-movie  { animation: hppReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 16s both; }
  /* legal 은 reveal 대상에서 제외 — 처음부터 노출 */

  /* 최종 상태 / 모션 미지원 폴백 */
  #products.is-ended .products__kv_m { visibility: visible; }
  #products.is-ended .products__kv_m-bg,
  #products.is-ended .products__kv_m-logo,
  #products.is-ended .products__kv_m-wise,
  #products.is-ended .products__kv_m-lockup,
  #products.is-ended .products__kv_m-title,
  #products.is-ended .products__kv_m-sub,
  #products.is-ended .products__kv_m-btns,
  #products.is-ended .products__kv_m-movie,
  #products.is-ended .products__kv_m-legal { opacity: 1; transform: translateY(0); }
}

@media (max-width: 750px) and (prefers-reduced-motion: reduce) {
  #products.is-playing .products__kv_m { visibility: visible; }
  #products.is-playing .products__kv_m-bg,
  #products.is-playing .products__kv_m-logo,
  #products.is-playing .products__kv_m-wise,
  #products.is-playing .products__kv_m-lockup,
  #products.is-playing .products__kv_m-title,
  #products.is-playing .products__kv_m-sub,
  #products.is-playing .products__kv_m-btns,
  #products.is-playing .products__kv_m-movie,
  #products.is-playing .products__kv_m-legal { opacity: 1; transform: translateY(0); }
}

/* ==========================================================================
   모바일 (max-width: 750px)
   ──────────────────────────────────────────────────────────────────────────
   MO 영상은 1080x1920 세로다(PC 1920x1080 의 90도 반대). 그래서 PC 와 같은
   방식으로, 영상과 동일한 1080x1920 좌표계 스테이지를 만들고 뷰포트 폭에
   맞춰 scale 한다. PC 가 100vw/1920 이면 MO 는 100vw/1080 이다.

   ※ 이 블록의 오브젝트 좌표는 **1차안**이다. MO 시안이 없어서, 세로 화면의
     통상 배치(카피는 위쪽 1/3, CTA 는 하단)로 잡았다. K 확인 후 조정 예정.

   ※ MO 자산이 없어 PC 것을 쓰는 곳 — 추후 교체 필요
     - #dualmode 배경 dualmode_bg.webp (1921x1008, 하단 법적고지가 구워져 있음)
     - #easyview 정지화면 배경 easyview_bg.webp (1920x1008)
     둘 다 가로 자산이라 세로 섹션에서 cover 로 크게 잘린다.
   ========================================================================== */
@media (max-width: 750px) {

  /* ---- 영상 섹션 공통 : 1080x1920 좌표계 ---- */
  .product__video-section {
    --product-video-scale: calc(100vw / 1080 / 1px);
    aspect-ratio: 1080 / 1920;
  }
  .product__video-stage {
    width: 1080px;
    height: 1920px;
  }

  /* 공통 CTA — 세로 화면에서는 하단에 가운데 정렬 (버튼 원본 285x65 -> 420 폭)
     ※ #quickstart 는 아래 전용 블록에서 750x1200 스테이지로 따로 잡으므로 제외한다. */
  .dualmode__btn,
  .easyview__btn,
  .easycare__btn,
  .colors__btn,
  .colormotion__btn { width: 420px; }
  .dualmode__btn-link,
  .easyview__btn-link,
  .easycare__btn-link,
  .colors__btn-link,
  .colormotion__btn-link {
    left: 330px;      /* (1080 - 420) / 2 */
    /* 링크 자신도 420 이어야 한다. 기본값 285 인 채로 두면 리셋
       `.product__wrap img { max-width:100% }` 가 이미지를 285 로 잘라
       left:330 과 어긋나 **가로 중앙에서 67.5 왼쪽으로 밀린다**(기존 버그). */
    width: 420px;
    top: auto;
    /* 하단에서 172.8 = quickstart(750 기준 120)와 **같은 물리적 거리**.
       120 * 1080 / 750 = 172.8. 두 스테이지의 기준 폭이 달라서 그대로 120 을
       쓰면 화면상 여백이 달라진다(11.1% vs 16.0%). */
    bottom: 172.8px;
  }
  /* CTA 이미지 PC -> MO 교체 */
  .product__wrap .dualmode__btn--pc,
  .product__wrap .easyview__btn--pc,
  .product__wrap .easycare__btn--pc,
  .product__wrap .colors__btn--pc,
  .product__wrap .colormotion__btn--pc { display: none; }
  .product__wrap .dualmode__btn--mo,
  .product__wrap .easyview__btn--mo,
  .product__wrap .easycare__btn--mo,
  .product__wrap .colors__btn--mo,
  .product__wrap .colormotion__btn--mo { display: block; }

  /* ---- #quickstart 는 전용 750x1200 블록에서 따로 처리한다 (파일 하단) ---- */

  /* ---- #dualmode : 750 x 1200 로 전환 ----
     좌표는 K 지정(350 기준)을 2배 환산했다.
       device   X:62  Y:85  -> 124 / 170
       title--l X:162 Y:102 -> 324 / 204   (--r 은 래퍼 안에서 아래 줄로 붙는다)
     나머지(마스크 / 클릭영역 / 아이콘 / 힌트 / 모드설명 / CTA / 각주)는 지정이
     없어 PC 비율과 750x1200 프레임에 맞춰 계산했다 — 1차안. */
  #dualmode.product__video-section {
    aspect-ratio: 750 / 1200;
  }
  .product__video-section--static {
    background-size: cover;
    background-position: center center;
  }
  /* 스테이지 자체를 750x1200 좌표계로 바꾼다 (다른 영상 섹션은 1080x1920 유지) */
  #dualmode .product__video-stage {
    width: 750px;
    height: 1200px;
    transform: translate(-50%, -50%) scale(calc(100vw / 750 / 1px));
  }

  /* 디바이스 — 폭은 지정이 없어 기존 MO(1080 기준 230 = 폭의 21.3%)와
     **같은 화면 비율**이 되도록 160 으로 환산했다(230 x 750/1080). */
  .dualmode__device { left: 124px; top: 170px; width: 160px; }

  /* 마스크/클릭영역은 디바이스에 종속이라 PC 실측 비율로 다시 잡는다.
       mask  left  +0.3353W / width 0.3293W / standard +0.8503W / boost +0.9042W
       hit   left  +0.0928W / top +0.7425W / 0.8024W x 1.9162W       (W = 디바이스 폭)
     ※ 기존 MO 블록은 .dualmode__hit 를 안 덮어써서 PC 좌표(892/220)가 그대로
       남아 있었다 — 클릭 영역이 디바이스 밖이었다. 여기서 같이 고친다. */
  .dualmode__mask   { left: 177.6px; width: 52.7px; }
  .dualmode__mask--standard { top: 306px; }
  .dualmode__mask--boost    { top: 314.7px; }
  /* 클릭영역 — **아이콘 윗부분**(= 디바이스 물리버튼 구간)까지.
     하단을 아이콘 상단 560 에 맞춘다 → height 560 - 288.8 = 271.2 */
  .dualmode__hit {
    left: 138.8px;
    top: 288.8px;
    width: 128.4px;
    height: 271.2px;
  }

  /* 타이틀 2줄 — 래퍼를 X:324 Y:204 에 놓고 안에서 세로로 쌓는다.
     크기는 quickstart 헤드라인(56)과 같은 스케일로 맞췄다. */
  .dualmode_l-block {
    position: absolute;
    left: 324px;
    top: 364px;
  }
  .dualmode__title {
    position: relative;
    left: auto;
    top: auto;
    margin: 0;
    font-size: 56px;
  }
  .dualmode__title--l,
  .dualmode__title--r { left: auto; }

  /* 아이콘 + 힌트 — PC 와 같이 **디바이스 몸통 위**, 물리버튼 바로 아래.
     디바이스 170~862.7 안에서 물리버튼이 대략 490~547 구간이라
     셰브론(위 방향)을 560 에 두면 버튼을 정확히 가리킨다.
     힌트는 아이콘 바로 아래(아이콘 하단 605.1 → 608). */
  .dualmode__icon { left: 181px; top: 560px; width: 46px; }
  .dualmode__hint {
    left: 0;
    top: 608px;
    width: 408px;      /* 중심 204 = 디바이스 중심 */
    font-weight: 600;
    font-size: 21px;
    text-align: center;
  }

  /* 모드 설명 이미지(클릭 시 노출) — 원본 302x414 / 255x414 로 세로가 길다.
     PC 처럼 디바이스 옆에 두면 세로가 안 맞아서, MO 에서는 **타이틀 아래
     오른쪽 컬럼**에 넣는다(X:324 = 타이틀 정렬선, Y:400 → 하단 814). */
  /* 모드 설명 — MO 전용 이미지로 교체하고 두 장 다 같은 자리(324 / 240)에 놓는다.
     1차/2차 클릭에서 STANDARD → BOOST 로 제자리 교체되는 그림이다.
     ※ width 를 주지 않는다 — CTA 와 같은 이유로 `_m` 자산의 원본 px 가
       그대로 750 기준 디자인 단위가 된다(스테이지가 scale 되므로). */
  .product__wrap .dualmode__standard--pc,
  .product__wrap .dualmode__boost--pc { display: none; }
  .product__wrap .dualmode__standard--mo,
  .product__wrap .dualmode__boost--mo { display: block; width: auto; }
  /* 2026-08: 두 이미지의 **상단 검은 원**을 기준으로 위치를 맞춘다.
     실측(캔버스 기준 원 중심 x):
       dualmode_standard_m.png 302x414 → 150
       dualmode_boost_m.png    255x414 → 126   (차이 24)
     같은 left 로 두면 폭 차이(302/255)만큼 원이 24px 어긋나 이미지가
     옆으로 미끄러지는 것처럼 보였다 → boost 만 +24 이동해 원 중심을 일치시킨다.
     ※ 자산이 교체되면 원 중심을 다시 실측해 이 오프셋을 갱신할 것. */
  .dualmode__standard,
  .dualmode__boost {
    left: 324px;
    right: auto;
    top: 240px;
    margin: 0;
  }
  .dualmode__boost { left: 348px; }   /* 324 + (150 - 126) */

  /* CTA — 폭 지정 없이 main_btn_m.png 원본 크기 그대로.
     스테이지가 scale 되므로 원본 px = 750 기준 디자인 단위가 된다.
     가로 중앙은 left/right:0 + margin:auto + width:max-content
     (translateX 는 reveal 의 transform 과 서로 덮어쓴다). */
  .dualmode__btn-link {
    left: 0;
    right: 0;
    top: auto;
    bottom: 120px;
    width: max-content;
    margin: 0 auto;
  }
  .product__wrap .dualmode__btn--mo { width: auto; }

  /* 1차 클릭에서 두 줄이 **같이** 사라진다(PC 는 --l 만 소거하고 --r 은 2차에서).
     타이틀 자리에 모드 설명(240)이 올라오므로 한 번에 비워야 겹치지 않는다.
     ※ 파일 뒤쪽이라 같은 특이도(1,2,0)의 기본 규칙을 순서로 이긴다.
       JS 는 2차에서 .is-step1 을 떼지 않고 .is-step2 를 더하므로,
       이 규칙이 2차에도 계속 걸리지만 동작(hppFadeOut forwards)이 같아 무해하다. */
  /* (2026-08 무한 토글 전환으로 MO 전용 STANDARD 소거 예외는 제거 —
     mode 클래스 + transition 이 PC/MO 공통으로 교대 처리한다.
     같은 자리 투명 PNG 겹침은 전환 0.45s 동안만 잠깐 겹치고 이전 쪽이 빠진다) */
  #dualmode.is-step1 .dualmode__title--r {
    animation: hppFadeOut 0.4s ease forwards;
    transform: translateY(0);
  }

  /* 각주 — quickstart_m__note 와 같은 스펙.
     ※ 단위가 다르다. quickstart 각주는 스테이지 **바깥**(.quickstart_m)이라
       vw 기반 --product-unit-mo 를 쓰지만, 이 각주는 scale() 된
       .product__video-stage **안**이라 vw 를 쓰면 두 번 축소된다.
       스테이지 내부는 750 좌표계 그대로이므로 raw px 로 적는다
       (48 / 1128 / 20 = quickstart 와 같은 값). */
  .dualmode_m__note {
    display: block;
    position: absolute;
    left: 48px;
    top: 1148px;
    margin: 0;
    font-family: "NotoSans", "Mont", sans-serif;
    font-weight: 500;
    font-size: 14px;
    line-height: 1.4;
    letter-spacing: -0.02em;
    color: rgba(255, 255, 255, 0.7);
    white-space: nowrap;
    z-index: 3;
  }

  /* ---- #easyview ---- */
  /* ── 섹션 축소 + 상단 앵커 (2026-08): 디바이스 하단 = 섹션 끝 ──────────────
     디바이스 하단(스테이지 710.9 + 734x1.331 = 1687.8 → 섹션 1808.4)에 맞춰
     섹션 높이를 1920 → 1808.4 로 줄인다. 가운데 정렬(top 50%) 스테이지는 섹션
     높이가 줄면 내용이 함께 위로 밀리므로, 두 스테이지를 모두 **섹션 상단
     기준**으로 바꾸고 스테이지 내부 y 좌표에 기존 상단 오프셋(420/1.0714=392)을
     더해 화면상 위치를 전부 보존한다 (pill 중심 1238 앵커 불변).
     bg_m(750x1260)은 cover 시 1080x1814.4 로 렌더 → 상하 3px 씩만 잘려,
     구워진 각주(y1204..1215)도 섹션 하단부로 자연스럽게 비례 이동한다. */
  #easyview.product__video-section { aspect-ratio: 1080 / 1808.4; }
  /* 영상(1080x1920)도 상단 앵커로 크롭해 정지화면과 기준을 통일 (하단만 잘림) */
  #easyview .product__video { object-position: 50% 0; }
  #easyview .product__video-stage {
    top: 0;
    transform: translate(-50%, 0) scale(var(--product-video-scale));
    transform-origin: 50% 0;
  }
  /* 배경 — MO 전용 자산 (easyview_bg_m.png 750x1260). */
  .easyview__still {
    background-image: url("/content/dam/glo-kr/mcs/images/event/hyperproplus/product/easyview_bg_m.png");
  }
  .easyview__still-stage {
    top: 0;
    transform: translate(-50%, 0) scale(calc(100vw / 1008 / 1px));
    transform-origin: 50% 0;
  }
  .easyview__title {
    left: 0;
    right: 0;
    top: 110px;
    width: max-content;
    margin: 0 auto;
    font-size: 90px;
    text-align: center;
  }
  /* ── 2026-08 3차: 원본 디자인 스크린샷 픽셀 실측으로 전면 재계산 ─────────
     원본(537px 캡처)을 1080 스테이지로 환산(x2.0112)한 실측값:
       title 글리프 y129..205(h76) → font 90 / box top 110
       roll 현재줄 글리프 y378..432(h54) → font 61 / 줄중심 y405
       sub  글리프 y611..712 → font 44 / box top 600
       디스플레이 pill y1038..1438, w174, 중심 (538, 1238)
     디바이스 배율 k = 174 / 146(png pill 잉크 실측) = 1.19
     ★ 앵커 = 디스플레이 중심 1238 / k = 1.19. 아래 값 전부 여기서 파생. */
  .easyview__roll {
    --ev-roll-fs: 61px; /* 실측: 글리프 h54 → 52 x 54/46 */
    left: 0;
    right: 0;
    top: 286px; /* 줄중심 405 - lh/2(39.7) - pitch x peek(59.5) - gap/2(19.8) */
    margin: 0 auto;
  }
  .easyview__sub {
    left: 0;
    right: 0;
    top: 600px;
    width: max-content;
    margin: 0 auto;
    font-size: 44px;
    text-align: center;
  }
  .easyview__sub-br--pc { display: none; }
  /* 롤링 목록 1번 항목 — MO 는 "전원 " 접두를 숨겨 "ON/OFF 상태"로 표기 */
  .easyview__roll-txt--pc { display: none; }

  /* 디바이스 — MO 전용 자산 easyview_device_m.png (278x734, pill 잉크 122x281,
     pill 중심 (138.5, 334) 실측)로 교체. 스테이지(1920x1008) 좌표 기준.
     앵커(섹션): pill 중심 (538, 1238), pill 폭 174 → 스테이지 환산(÷1.07143):
       중심 y 763.5 / pill 폭 162.4 → k = 162.4 / 122 = 1.331
       width = 278 x 1.331 = 370 / top = 763.5 - 334 x 1.331 = 318.9
     ※ 이전 k=1.19 는 스테이지→섹션 배율(1.0714)을 빠뜨린 값이라 폐기. */
  .product__wrap img.easyview__device--pc { display: none; }
  .product__wrap img.easyview__device--mo { display: block; }
  .easyview__device {
    top: 710.9px;  /* 318.9 + 상단앵커 보정 392 */
    width: 370px;
  }
  /* 디스플레이 화면 박스 — _m 자산 pill 에 PC 의 box/ink 여유율(1.130/1.070) 적용
     w 122x1.130x1.331=183.5 / h 281x1.070x1.331=400.3, pill 중심(960,763.5) 정렬 */
  .easyview__screens {
    left: 868.3px;   /* 960 - 183.5/2 */
    top: 955.4px;    /* 563.4 + 상단앵커 보정 392 */
    width: 183.5px;
    height: 400.3px;
  }
  /* 화면/배경판 자산 배율 — 박스 확대율(183.5/165) */
  .easyview__screen,
  .easyview__screen-bg { transform: translate(-50%, -50%) scale(1.11); }

  /* 영상 하강 — MO 에서는 제거(2026-08). 영상은 제자리에서 크로스페이드만.
     transform 과 마스크 이동을 모두 무효화해 상단 페더도 발동하지 않는다. */
  #easyview.is-played .product__video {
    transform: none;
    -webkit-mask-position: 0 calc(-1 * var(--easyview-feather));
    mask-position: 0 calc(-1 * var(--easyview-feather));
  }
  /* 섹션 배경 MO 자산 교체(하강 제거와 무관하게 유지 — still 페이드 배경 연속용) */
  #easyview.product__video-section {
    background-image: url("/content/dam/glo-kr/mcs/images/event/hyperproplus/product/easyview_bg_m.png");
  }

  /* ---- #easycare ----
     ── 스테이지만 750 기준으로 바꾼다 (섹션 비율은 그대로) ────────────────
     같은 숫자라도 스테이지 기준 폭이 다르면 화면에서 크기가 달라진다.
     quickstart / dualmode 는 750 기준인데 여기만 1080 기준이라, 시안 값을
     그대로 넣으면 **1.44 배 작게** 그려졌다(예: title 64 → 375 뷰포트에서
     22.2px, 750 기준이면 32px). 아이콘도 원본 72 가 6.67% → 9.6% 로 달라진다.

     그래서 **섹션 비율(1080:1920 = 0.5625)은 유지한 채 스테이지 좌표계만**
     750 x 1333.33 (= 750 x 1920/1080) 으로 바꿨다.
       · 폰트/아이콘이 750 기준으로 커진다 → 시안과 일치
       · 영상 크롭 여유가 그대로라 --easycare-shift: 157 (한계치)도 유효
       · 섹션 높이 비율도 그대로라 아래 섹션들과의 관계가 안 바뀐다
     기존 1080 기준 값들은 전부 1.44(=1080/750)로 나눠 환산했다.

     ※ 750:1200 으로 비율까지 바꾸면 좌우 크롭 여유가 21.1% → 14% 로 줄어
       157 이 못 버틴다(최대 105). 그래서 비율은 건드리지 않았다.
     -------------------------------------------------------------------- */
  #easycare .product__video-stage {
    width: 750px;
    height: 1333.33px;   /* 750 x 1920/1080 — 섹션 비율 유지 */
    transform: translate(-50%, -50%) scale(calc(100vw / 750 / 1px));
  }

  /* 영상: 재생 종료 후 왼쪽으로 이동 + 확대.
     ※ transform: translateX 로 옮기면 <video> 박스 자체가 이동해 오른쪽에
       섹션 배경(#000)이 드러난다. **object-position** 은 박스를 그대로 두고
       크롭 창만 움직이므로 빈틈이 생기지 않는다(애니메이션 가능한 속성).
     ※ 크롭 여유 — 5_easycare_m.mp4 3072x3840(0.8) 을 0.5625 박스에 cover 하면
       렌더 폭이 박스의 1.4222 배라 좌우 각 21.1% 가 이미 잘려 있다.
       이동량 157/750 = 20.93vw = 20.93% → 남는 여백 0.7px, **사실상 한계치**.
       최대 158.4. 넘기면 오른쪽에 검은 띠가 생긴다.
     ※ scale 은 레이아웃 박스를 안 건드리므로 크롭 계산에 영향이 없다.
       화면상 이동량만 scale 배율만큼 보인다(375 뷰포트에서 78.5 → 109.9px @1.4).
     ※ `.product__video` 는 스케일 스테이지 **바깥**이라 raw px 가 아니라
       vw 기반 단위를 써야 한다(--product-unit-mo). */
  #easycare .product__video {
    --easycare-shift: calc(157 * var(--product-unit-mo));
    object-position: 50% 50%;
    transform: scale(1);
    transform-origin: 50% 50%;
    /* 2026-08: 0.1s 딜레이 제거 — is-played 즉시 이동 시작 */
    transition:
      object-position 0.9s cubic-bezier(0.22, 1, 0.36, 1),
      transform 0.9s cubic-bezier(0.22, 1, 0.36, 1);
  }
  #easycare.is-played .product__video {
    object-position: calc(50% - var(--easycare-shift)) 50%;
    transform: scale(1.4);
  }

  /* 카피 3종 묶음 — 1080 기준 값을 1.44 로 나눈 750 기준 좌표.
       left 620 → 430.6 / top 820 → 569.4 / width 460 → 319.4
     폭 319.4 는 750 - 430.6 과 정확히 같다(오른쪽 여백 0).
     서브카피는 MO 전용 <br> 로 2줄이 되므로 nowrap 을 풀어둔다. */
  .easycare_block-r {
    position: absolute;
    top: 569.4px;
    left: 430.6px;
    width: 319.4px;
  }
  /* 아이콘 MO 교체 + 폭 지정 없음(easycare_icon_m.png 원본 크기).
     ※ 기본 규칙 `.easycare__icon { width: 72px }` 과 특이도가 같으므로
       그냥 지우면 안 되고 `width: auto` 로 명시해 덮어써야 한다. */
  .product__wrap .easycare__icon--pc { display: none; }
  .product__wrap .easycare__icon--mo { display: block; }
  .easycare__sub-br--mo { display: inline; }
  .easycare__icon {
    position: relative;
    left: 0;
    top: auto;
    margin: 0;
    width: auto;
  }
  .easycare__title {
    position: relative;
    left: 0;
    right: auto;
    top: auto;
    width: auto;
    margin: 40.3px 0 0;   /* 58 / 1.44 */
    font-size: 64px;
    text-align: left;
  }
  .easycare__sub {
    position: relative;
    left: 0;
    right: auto;
    top: auto;
    width: auto;
    margin: 20px 0 0;
    font-size: 26px;
    text-align: left;
    white-space: normal;
  }

  /* CTA — 750 기준으로 다시 잡는다. 폭 지정 없이 원본 크기 / 가로 중앙 / 하단 120
     (dualmode 와 동일 규격). 공통 MO 규칙(1080 기준 left:330)을 덮어쓴다. */
  .easycare__btn-link {
    left: 0;
    right: 0;
    top: auto;
    bottom: 120px;
    width: max-content;
    margin: 0 auto;
  }
  .product__wrap .easycare__btn--mo { width: auto; }

  /* 각주 — quickstart / dualmode 와 같은 값(48 / 20px).
     세로는 스테이지 높이가 1333.33 이므로 같은 94% 지점 = 1253.3.
     ※ 스테이지 안이라 raw px (vw 를 쓰면 두 번 축소된다). */
  .easycare_m__note {
    display: block;
    position: absolute;
    left: 48px;
    top: 1273.3px;
    margin: 0;
    font-family: "NotoSans", "Mont", sans-serif;
    font-weight: 500;
    font-size: 14px;
    line-height: 1.4;
    letter-spacing: -0.02em;
    color: rgba(255, 255, 255, 0.7);
    white-space: nowrap;
    z-index: 3;
  }

  /* ---- #colors ----
     ※ 이 섹션 스테이지는 아직 1080x1920 기준이다(quickstart/dualmode 는 750,
       easycare 는 750x1333.33). 값 섞지 말 것.

     카피는 MO 에서 3줄 → 2줄로 바꾼다. 두 번째 <br> 만 끄는 방식이라
     PC 마크업/렌더는 그대로다(앞의 공백은 PC 에서 줄끝에 붙어 사라진다).
       PC "세련된 마감과 / 트렌디한 / 4가지 컬러"
       MO "세련된 마감과 / 트렌디한 4가지 컬러"

     컬러명은 카피(하단 391.6 = 220 + 2줄 x 66 x 1.3) 아래에 410 / 82px 로 둔다.
     ※ 컬러명은 PC 에서 항목마다 인라인 left 가 박혀 있어 !important 가 필요하다.
     -------------------------------------------------------------------- */
  .colors__copy-br--pc { display: none; }

  .colors__copy {
    left: 0;
    right: 0;
    top: 220px;
    width: max-content;
    margin: 0 auto;
    font-size: 66px;
    text-align: center;
  }
  .colors__name {
    left: 0 !important;
    right: 0;
    top: 410px;
    width: max-content;
    margin: 0 auto;
    font-size: 82px;
    text-align: center;
  }

  /* ---- #colormotion ---- */
  .colormotion__copy {
    left: 0;
    right: 0;
    width: max-content;
    margin: 0 auto;
    font-size: 76px;
    text-align: center;
  }
  .colormotion__copy--play { top: 220px; }
  .colormotion__copy--end  { top: 260px; }
  /* 각주 — 다른 MO 각주(750 기준 48 / 1148 / 14px / 500)와 화면상 같은 값.
     이 섹션 스테이지는 1080x1920 이므로 가로는 x1.44, 세로는 같은 비율 지점.
       left 48 x 1.44 = 69.1 / top 1920 x (1148/1200) = 1836.8 / font 14 x 1.44 = 20.16 */
  .colormotion__note {
    left: 69.1px;
    top: 1836.8px;
    font-weight: 500;
    font-size: 20.16px;
    color: rgba(255, 255, 255, 0.7);
  }
}

/* ==========================================================================
   섹션 내 구매하기 CTA 숨김 (2026-08) — 플로팅 CTA(.product__float-cta)로 대체.
   #foot 의 구매하기(foot__btn-link)만 유지한다 (플로팅은 foot 진입 시 사라짐).
   ※ 반드시 파일 **맨 끝**에 둘 것 — 같은 특이도의 기본/MO 규칙(display 지정)을
     선언 순서로 이겨야 한다. DOM 은 남겨둔다(되돌리기 쉬움).
   ========================================================================== */
.quickstart__btn-link,
.quickstart_m__btn-link,
.dualmode__btn-link,
.easyview__btn-link,
.easycare__btn-link,
.colors__btn-link,
.colormotion__btn-link { display: none; }
