/* ============================================================
 * vweb-anim.css — V-Web 공통 애니메이션 라이브러리
 *
 * 출처: 과거 퍼블 프로젝트 4종의
 *       css/animation.css 에서 "단위 중립(transform/opacity/filter)"
 *       keyframe 만 추출 → v- 프리픽스로 표준화.
 *
 * 단위 정책:
 *   여기 있는 모든 keyframe 은 transform/opacity/filter 만 사용한다.
 *   → px/vw/%/top/left 같은 좌표·길이 단위에 의존하지 않으므로
 *     캔버스/단위 체계(rem·--px)와 무관하게 그대로 재사용 가능.
 *
 * 사용:
 *   <div class="v-float">…</div>
 *   <ul class="v-marquee-x">…</ul>      (seamless 반복은 내용 2배 복제 + v-*-half)
 *
 * hook:
 *   vweb-* 프리픽스 → 모든 Edit/Write hook 자동 면제.
 *
 * ⛔ 라이브러리에서 제외한 효과 (좌표/px/random 의존 → 섹션 로컬로 작성):
 *   - smoke      : translate(calc(random()*100vw), 100vh) + px  (random() 실험적)
 *   - fall/fall2 : top: -0% → 100%                              (좌표 의존)
 *   - ball       : bottom: 0px → 20px                           (px 좌표)
 *   - slick-circle : left: 0 → 99%                              (좌표 의존)
 *   - ddm/ddm2*/ddm_m* : matrix(... , -30px) / translate(20px)  (px 이동)
 *   - hand/hand2 : translate(%,%)                               (미세 % 손동작)
 *   - uitLineMove: stroke-dashoffset                            (SVG 경로 길이 의존)
 *   필요하면 해당 섹션 style.css 에 직접 정의할 것.
 * ============================================================ */

/* ===== Marquee (무한 흐름) ===== */
/* seamless 무한루프: 내용을 2배 복제하고 -half 사용 (translateX -50%) */
@keyframes v-marquee-x      { from { transform: translateX(0); }    to { transform: translateX(-100%); } }
@keyframes v-marquee-x-rev  { from { transform: translateX(0); }    to { transform: translateX(100%); } }
@keyframes v-marquee-y      { from { transform: translateY(0); }    to { transform: translateY(-100%); } }
@keyframes v-marquee-y-rev  { from { transform: translateY(0); }    to { transform: translateY(100%); } }
@keyframes v-marquee-half     { from { transform: translateX(0); }    to { transform: translateX(-50%); } }
@keyframes v-marquee-half-rev { from { transform: translateX(-50%); } to { transform: translateX(0); } }

.v-marquee-x      { animation: v-marquee-x 20s infinite linear; }
.v-marquee-x-rev  { animation: v-marquee-x-rev 20s infinite linear; }
.v-marquee-y      { animation: v-marquee-y 20s infinite linear; }
.v-marquee-y-rev  { animation: v-marquee-y-rev 20s infinite linear; }
.v-marquee-half     { animation: v-marquee-half 20s infinite linear; }
.v-marquee-half-rev { animation: v-marquee-half-rev 20s infinite linear; }

/* ===== Rotate (연속 회전) ===== */
@keyframes v-rotate   { to { transform: rotate(360deg); } }
@keyframes v-rotate-y { from { transform: rotateY(0); } to { transform: rotateY(360deg); } }

.v-rotate   { animation: v-rotate 10s infinite linear; }
.v-rotate-y { animation: v-rotate-y 10s infinite linear; }

/* ===== Wobble (미세 흔들림) ===== */
@keyframes v-wobble {
  0%   { transform: rotate(-1deg); }
  40%  { transform: rotate(1deg); }
  60%  { transform: rotate(2deg); }
  80%  { transform: rotate(-1deg); }
  100% { transform: rotate(1deg); }
}
.v-wobble { animation: v-wobble 4s infinite ease-in-out; }

/* ===== Float (상하 부유) ===== */
@keyframes v-float { 0% { transform: translateY(-5%); } 100% { transform: translateY(5%); } }

.v-float       { animation: v-float 2s ease-in-out infinite alternate; }
.v-float-delay { animation: v-float 2s 1s ease-in-out infinite alternate; }

/* ===== Scale + Opacity (확산/펄스) ===== */
@keyframes v-scale-opa  { 0% { transform: scale(0.5); opacity: 0; } 50% { opacity: 1; } 100% { transform: scale(1); opacity: 0; } }
@keyframes v-scale-opa-2 { 0% { transform: scale(1); opacity: 0; } 20% { opacity: 0.4; } 100% { transform: scale(1.2); opacity: 0; } }
@keyframes v-scale-opa-3 { 100% { transform: scale(1.3); opacity: 0; } }

.v-scale-opa   { animation: v-scale-opa 2s infinite; }
.v-scale-opa-2 { animation: v-scale-opa-2 2s infinite; }
.v-scale-opa-3 { animation: v-scale-opa-3 2s infinite; }

/* ===== Zoom (스케일 펄스) ===== */
@keyframes v-zoom        { 0% { transform: scale(1); } 50% { transform: scale(1.02); } 100% { transform: scale(1); } }
@keyframes v-zoom-strong { 0% { transform: scale(1); } 50% { transform: scale(1.1); }  100% { transform: scale(1); } }

.v-zoom        { animation: v-zoom 4s infinite ease-in-out; }
.v-zoom-strong { animation: v-zoom-strong 4s infinite ease-in-out; }

/* ===== Blink (점멸) ===== */
@keyframes v-blink   { 0% { opacity: 0; } 30% { opacity: 0; } 31% { opacity: 1; } 99% { opacity: 1; } 100% { opacity: 0; } }
@keyframes v-blink-2 { 0% { opacity: 0; } 49% { opacity: 0; } 50% { opacity: 1; } 99% { opacity: 1; } 100% { opacity: 0; } }
@keyframes v-blink-3 { 0% { opacity: 1; } 24% { opacity: 1; } 25% { opacity: 0; } 99% { opacity: 0; } 100% { opacity: 1; } }

.v-blink   { animation: v-blink 1s infinite ease-in-out; }
.v-blink-2 { animation: v-blink-2 1s infinite ease-in-out; }
.v-blink-3 { animation: v-blink-3 1s infinite ease-in-out; }

/* ===== Fade loop (페이드 인-아웃 반복) ===== */
@keyframes v-fade-loop { 0% { opacity: 0; } 50% { opacity: 1; } 100% { opacity: 0; } }
.v-fade-loop { animation: v-fade-loop 3s infinite ease-in-out; }

/* ===== Light (네온/조명 플리커) ===== */
@keyframes v-light {
  0%, 31%, 34%, 39%, 42%, 47% { opacity: 0; }
  5%, 30%, 35%, 38%, 43%, 46% { opacity: 0.4; }
  50%, 51%, 54%, 55%, 60%, 67%, 68%, 100% { opacity: 1; }
  70% { opacity: 0.2; }
}
.v-light { animation: v-light 5s infinite; }

/* ===== Bright (밝기 호흡) ===== */
@keyframes v-bright { 0% { filter: brightness(0.5); } 50% { filter: brightness(1.2); } 100% { filter: brightness(0.5); } }
.v-bright { animation: v-bright 3s infinite ease-in-out; }

/* ===== Shine (사선 빛줄기 sweep) — 대상이 overflow 클립을 소유해야 띠가 밖으로 안 샌다 ===== */
@keyframes v-shine {
  0%   { transform: translateX(-160%) rotate(22deg); }
  100% { transform: translateX(320%) rotate(22deg); }
}
.v-shine { position: relative; }
.v-shine::after {
  content: "";
  position: absolute;
  top: -50%;
  left: 0;
  width: 30%;
  height: 200%;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.55) 50%, rgba(255, 255, 255, 0) 100%);
  animation: v-shine 2s infinite linear;
  pointer-events: none;
  opacity: var(--shine-opacity, 1); /* 띠를 껐다 켜려면 클래스 대신 이 변수를 움직인다 — 클래스 토글은 sweep 을 도중에 끊는다 */
}
.v-shine--slow::after { animation-duration: 3s; }
.v-shine--fast::after { animation-duration: 1s; }

/* ===== Shine (텍스트판) — background-clip:text 요소용. 원본 그라디언트는 --shine-base 로 넘겨 그대로 깔고 하이라이트 띠만 흐른다 ===== */
@keyframes v-shine-text {
  0%   { background-position: 160% 0, 0 0; }
  100% { background-position: -60% 0, 0 0; }
}
.v-shine-text {
  /* 하이라이트색은 대상 대비로 고른다 — 어두운 배경의 밝은 글자는 흰색, 밝은 배경의 어두운 글자는 금색(흰색은 글자가 흐려져 보인다) */
  background-image:
    linear-gradient(100deg, transparent 40%, rgb(var(--shine-hl, 255 255 255) / var(--shine-strength, .8)) 50%, transparent 60%),
    var(--shine-base, linear-gradient(90deg, #e7c588, #fefbcb, #e0c38b));
  background-size: 220% 100%, 100% 100%;
  background-repeat: no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: v-shine-text 3s infinite linear;
}
.v-shine-text--slow { animation-duration: 5s; }
.v-shine-text--fast { animation-duration: 2s; }

/* 대상이 직사각형이 아닐 때 — 마스크는 정지한 컨테이너가 소유한다(::after 에 걸면 띠와 함께 회전·이동해 무의미) */
.v-shine--mask {
  -webkit-mask-image: var(--shine-mask);
  mask-image: var(--shine-mask);
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

/* ===== Gloss sweep — 흰 띠를 "덧칠"하지 않고 backdrop-filter 로 밑색을 그대로 밝힌다(짙은/유채색 표면에서 우유 띠 대신 광택으로 읽힘).
 * ::after 를 두 겹 mask 로 자른다: 1층(--gloss-clip, 기본 none=클립 없음)=대상 실루엣, 2층(내장 그라디언트)=흐르는 대각 띠.
 * mask-composite:intersect 로 교집합만 남겨 실루엣 밖·띠 밖은 완전히 투명(=필터 미적용) 처리한다. 단위중립(%, deg, 무단위 배율만). */
.v-gloss { position: relative; }
.v-gloss::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  backdrop-filter: brightness(var(--gloss-strength, 1.25)) saturate(1.1);
  -webkit-backdrop-filter: brightness(var(--gloss-strength, 1.25)) saturate(1.1);
  mask-image: var(--gloss-clip, none), linear-gradient(100deg, transparent 0%, transparent 42%, rgba(255, 255, 255, 1) 50%, transparent 58%, transparent 100%);
  -webkit-mask-image: var(--gloss-clip, none), linear-gradient(100deg, transparent 0%, transparent 42%, rgba(255, 255, 255, 1) 50%, transparent 58%, transparent 100%);
  mask-repeat: no-repeat, no-repeat;
  -webkit-mask-repeat: no-repeat, no-repeat;
  mask-size: 100% 100%, 220% 100%;
  -webkit-mask-size: 100% 100%, 220% 100%;
  mask-position: 0 0, -110% 0;
  -webkit-mask-position: 0 0, -110% 0;
  mask-composite: intersect;
  -webkit-mask-composite: source-in;
  animation: v-gloss-sweep 3s infinite linear;
}
.v-gloss--slow::after { animation-duration: 4s; }
.v-gloss--fast::after { animation-duration: 1.6s; }
@keyframes v-gloss-sweep {
  0%   { mask-position: 0 0, -110% 0; -webkit-mask-position: 0 0, -110% 0; }
  100% { mask-position: 0 0, 210% 0; -webkit-mask-position: 0 0, 210% 0; }
}

/* ============================================================
 * Peel (테이프 필링/스틱 — 2겹 clip 접힘)
 *   대상 .v-peel + 2겹(.peel-main/.peel-flap, 같은 이미지 2장). JS = library.js peel().
 *   --peel 0=붙음~1=떼짐 (GSAP 제어). 단위중립(%, deg, clip-path). 기본 = 오른쪽 끝 peel.
 * ============================================================ */
.v-peel {
  --peel: 0; --tilt: -10deg; --fold: calc((1 - var(--peel)) * 100%);
  position: relative;
  transform: rotate(calc(var(--peel) * var(--tilt))); transform-origin: 6% 50%;
}
.v-peel .peel-main, .v-peel .peel-flap { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
.v-peel .peel-main img, .v-peel .peel-flap img { width: 100%; display: block; }
.v-peel .peel-main { clip-path: inset(0 calc(100% - var(--fold)) 0 0); }
.v-peel .peel-flap { clip-path: inset(0 0 0 var(--fold)); transform: scaleX(-1); left: calc(2 * var(--fold) - 100%); }
.v-peel .peel-flap img { filter: grayscale(1) brightness(1.3) contrast(0.82); }
/* 왼쪽 끝 peel */
.v-peel--left { --tilt: 10deg; --fold: calc(var(--peel) * 100%); transform-origin: 94% 50%; }
.v-peel--left .peel-main { clip-path: inset(0 0 0 var(--fold)); }
.v-peel--left .peel-flap { clip-path: inset(0 calc(100% - var(--fold)) 0 0); }
