
/* =============================================
 *  PLAYABLE AD STYLES — Image Gacha (Free Node)
 *  - stage 안에서 모든 노드는 % 좌표로 자유 배치
 *  - 폰트 사이즈는 stage 짧은 변(vmin in stage)의 % 기준
 *  - 좌표/크기는 nodes[].rect 의 {x,y,w,h} (모두 %)
 * ============================================= */

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #000;
  font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  -webkit-user-select: none;
}

#stage {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #000;
}

#contentBox {
  position: absolute;
  background: #1a1a23;
  overflow: hidden;
  transform-origin: center center;
  /* stage 단위(--su) = 짧은 변 1% — 노드 폰트사이즈/스트로크에 사용 */
  --su: 1px;
}

/* 씬 레이어 — 기본은 즉시 전환. scene.transition 설정 시 클래스로 in/out anim */
.sceneLayer {
  position: absolute;
  inset: 0;
}

/* ── 씬 트랜지션 (in / out) ─────────────────── */
.sceneLayer.scn-fade-in            { animation: scn-fade-in            var(--scn-dur, 0.5s) ease forwards; }
.sceneLayer.scn-fade-out           { animation: scn-fade-out           var(--scn-dur, 0.5s) ease forwards; }
.sceneLayer.scn-slide-left-in      { animation: scn-slide-left-in      var(--scn-dur, 0.5s) cubic-bezier(0.2, 0.9, 0.3, 1) forwards; }
.sceneLayer.scn-slide-left-out     { animation: scn-slide-left-out     var(--scn-dur, 0.5s) cubic-bezier(0.2, 0.9, 0.3, 1) forwards; }
.sceneLayer.scn-slide-right-in     { animation: scn-slide-right-in     var(--scn-dur, 0.5s) cubic-bezier(0.2, 0.9, 0.3, 1) forwards; }
.sceneLayer.scn-slide-right-out    { animation: scn-slide-right-out    var(--scn-dur, 0.5s) cubic-bezier(0.2, 0.9, 0.3, 1) forwards; }
.sceneLayer.scn-slide-top-in       { animation: scn-slide-top-in       var(--scn-dur, 0.5s) cubic-bezier(0.2, 0.9, 0.3, 1) forwards; }
.sceneLayer.scn-slide-top-out      { animation: scn-slide-top-out      var(--scn-dur, 0.5s) cubic-bezier(0.2, 0.9, 0.3, 1) forwards; }
.sceneLayer.scn-slide-bottom-in    { animation: scn-slide-bottom-in    var(--scn-dur, 0.5s) cubic-bezier(0.2, 0.9, 0.3, 1) forwards; }
.sceneLayer.scn-slide-bottom-out   { animation: scn-slide-bottom-out   var(--scn-dur, 0.5s) cubic-bezier(0.2, 0.9, 0.3, 1) forwards; }
.sceneLayer.scn-zoom-in-in         { animation: scn-zoom-in-in         var(--scn-dur, 0.5s) cubic-bezier(0.2, 0.9, 0.3, 1) forwards; }
.sceneLayer.scn-zoom-in-out        { animation: scn-zoom-in-out        var(--scn-dur, 0.5s) ease-in forwards; }
.sceneLayer.scn-zoom-out-in        { animation: scn-zoom-out-in        var(--scn-dur, 0.5s) ease-out forwards; }
.sceneLayer.scn-zoom-out-out       { animation: scn-zoom-out-out       var(--scn-dur, 0.5s) cubic-bezier(0.2, 0.9, 0.3, 1) forwards; }
.sceneLayer.scn-flash-in           { animation: scn-flash-in           var(--scn-dur, 0.3s) ease forwards; }
.sceneLayer.scn-flash-out          { animation: scn-flash-out          var(--scn-dur, 0.3s) ease forwards; }

@keyframes scn-fade-in            { from { opacity: 0; } to { opacity: 1; } }
@keyframes scn-fade-out           { from { opacity: 1; } to { opacity: 0; } }
@keyframes scn-slide-left-in      { from { transform: translateX(100%);  } to { transform: translateX(0); } }
@keyframes scn-slide-left-out     { from { transform: translateX(0);     } to { transform: translateX(-100%); } }
@keyframes scn-slide-right-in     { from { transform: translateX(-100%); } to { transform: translateX(0); } }
@keyframes scn-slide-right-out    { from { transform: translateX(0);     } to { transform: translateX(100%); } }
@keyframes scn-slide-top-in       { from { transform: translateY(100%);  } to { transform: translateY(0); } }
@keyframes scn-slide-top-out      { from { transform: translateY(0);     } to { transform: translateY(-100%); } }
@keyframes scn-slide-bottom-in    { from { transform: translateY(-100%); } to { transform: translateY(0); } }
@keyframes scn-slide-bottom-out   { from { transform: translateY(0);     } to { transform: translateY(100%); } }
@keyframes scn-zoom-in-in         { from { transform: scale(0.6); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes scn-zoom-in-out        { from { transform: scale(1);   opacity: 1; } to { transform: scale(1.4); opacity: 0; } }
@keyframes scn-zoom-out-in        { from { transform: scale(1.4); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes scn-zoom-out-out       { from { transform: scale(1);   opacity: 1; } to { transform: scale(0.6); opacity: 0; } }
@keyframes scn-flash-in           { 0% { opacity: 0; filter: brightness(3); } 40% { opacity: 1; filter: brightness(3); } 100% { opacity: 1; filter: brightness(1); } }
/* 이전 씬을 붙잡지 않고 밝기 피크(35~50%) 동안 빠르게 사라지게 → 배경채우기(투명 레이어) 상태에서도 잔상 없음 */
@keyframes scn-flash-out          { 0% { opacity: 1; filter: brightness(1); } 35% { opacity: 1; filter: brightness(3); } 50% { opacity: 0; filter: brightness(3); } 100% { opacity: 0; filter: brightness(2); } }

/* 배경 (씬마다 하나) */
.scene-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* 씬 위 자유 탭 영역 (onTap이 있을 때) */
.scene-taparea {
  position: absolute;
  inset: 0;
  background: transparent;
  border: 0;
  cursor: pointer;
}

/* 노드 공통 */
.node {
  position: absolute;
  /* rect.x/y/w/h 는 인라인 style 로 % 지정 */
}

/* 이미지 노드 */
.node.kind-image {
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
}

/* 텍스트 노드 */
.node.kind-text {
  display: flex;
  align-items: center;            /* 기본 = middle */
  white-space: pre-wrap;
  pointer-events: none;
  line-height: 1.15;
  overflow: visible;
  /* stroke가 글자 안쪽을 잠식하지 않도록 — stroke를 먼저 그리고 fill을 위에 덮음 */
  paint-order: stroke fill;
}
.node.kind-text.align-left   { justify-content: flex-start; text-align: left; }
.node.kind-text.align-center { justify-content: center;     text-align: center; }
.node.kind-text.align-right  { justify-content: flex-end;   text-align: right; }
.node.kind-text.valign-top    { align-items: flex-start; }
.node.kind-text.valign-middle { align-items: center; }
.node.kind-text.valign-bottom { align-items: flex-end; }
.node.kind-text > span {
  display: inline-block;
  width: 100%;
}

/* 버튼 노드 (이미지+라벨 또는 단독) */
.node.kind-button {
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  border: 0;
  background-color: transparent;
  cursor: pointer;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #1a0d00;
  font-weight: 900;
}
.node.kind-button.has-bg-color { background-color: var(--bg, #ff8a1f); }

/* 도형 노드 */
.node.kind-shape {
  background-color: var(--shape-fill, #ff8a3d);
  box-sizing: border-box;
}
.node.kind-shape.shape-circle  { border-radius: 50%; }
.node.kind-shape.shape-ellipse { border-radius: 50%; }
.node.kind-shape.shape-triangle      { clip-path: polygon(50% 0, 0 100%, 100% 100%); }
.node.kind-shape.shape-right-triangle{ clip-path: polygon(0 0, 100% 100%, 0 100%); }
.node.kind-shape.shape-pentagon      { clip-path: polygon(50% 0, 100% 38%, 82% 100%, 18% 100%, 0 38%); }
.node.kind-shape.shape-hexagon       { clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%); }
.node.kind-shape.shape-star          { clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%); }
/* shape-rect / shape-parallelogram / shape-trapezoid 는 inline clip-path / borderRadius 적용 */

/* 노드 애니메이션 — 룬타임에서 anim 속성으로 클래스 부여 */
.node.anim-pop  { animation: na-pop 0.45s cubic-bezier(0.2, 1.6, 0.4, 1) forwards; }
@keyframes na-pop {
  0%   { transform: scale(0.5); opacity: 0; }
  60%  { transform: scale(1.08); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
.node.anim-pop-delayed { opacity: 0; animation: na-pop 0.55s cubic-bezier(0.2,1.6,0.4,1) forwards; animation-delay: 0.9s; }

.node.anim-bob { animation: na-bob 1.6s ease-in-out infinite; }
@keyframes na-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(calc(var(--su) * -1.5 * var(--anim-amp-loop, 1))); }
}

.node.anim-shake { animation: na-shake 0.18s ease-in-out infinite; }
@keyframes na-shake {
  0%, 100% { transform: translate(0, 0); }
  25%      { transform: translate(calc(var(--su) * -0.5 * var(--anim-amp-loop, 1)), calc(var(--su) * 0.4 * var(--anim-amp-loop, 1))); }
  75%      { transform: translate(calc(var(--su) * 0.5 * var(--anim-amp-loop, 1)),  calc(var(--su) * -0.4 * var(--anim-amp-loop, 1))); }
}

.node.anim-spin { animation: na-spin 1.5s linear infinite; }
@keyframes na-spin {
  0%, 100% { transform: scaleX(1); }
  50%      { transform: scaleX(-1); }
}

.node.anim-fadein { animation: na-fadein 0.5s ease forwards; opacity: 0; }
.node.anim-fadein-delayed { opacity: 0; animation: na-fadein 0.5s ease forwards; animation-delay: 1.2s; }
@keyframes na-fadein { to { opacity: 1; } }

.node.anim-fxburst {
  opacity: 0; transform: scale(0.5) rotate(0);
  animation: na-fxburst 1.4s ease-out forwards;
  animation-delay: 0.7s;
}
@keyframes na-fxburst {
  0%   { opacity: 0; transform: scale(0.5) rotate(0); }
  30%  { opacity: 1; }
  100% { opacity: 1; transform: scale(1.3) rotate(360deg); }
}

.node.anim-cta { animation: na-cta 1.2s ease-in-out infinite; }
@keyframes na-cta {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.06); }
}

/* ── 추가 모션 (등장/퇴장/반복) ─────────────────── */

/* 등장 — slide-in 4방향 */
.node.anim-slide-in-left   { animation: na-slide-in-left   0.5s cubic-bezier(0.2, 0.9, 0.3, 1) forwards; opacity: 0; }
.node.anim-slide-in-right  { animation: na-slide-in-right  0.5s cubic-bezier(0.2, 0.9, 0.3, 1) forwards; opacity: 0; }
.node.anim-slide-in-top    { animation: na-slide-in-top    0.5s cubic-bezier(0.2, 0.9, 0.3, 1) forwards; opacity: 0; }
.node.anim-slide-in-bottom { animation: na-slide-in-bottom 0.5s cubic-bezier(0.2, 0.9, 0.3, 1) forwards; opacity: 0; }
@keyframes na-slide-in-left   { from { transform: translateX(-130%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes na-slide-in-right  { from { transform: translateX(130%);  opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes na-slide-in-top    { from { transform: translateY(-130%); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
@keyframes na-slide-in-bottom { from { transform: translateY(130%);  opacity: 0; } to { transform: translateY(0); opacity: 1; } }

/* 등장 — zoom-in / zoom-out (둘 다 최종 scale=1, 시작점만 다름) */
.node.anim-zoom-in  { animation: na-zoom-in  0.45s cubic-bezier(0.2, 1.6, 0.4, 1) forwards; opacity: 0; }
.node.anim-zoom-out { animation: na-zoom-out 0.45s ease-out forwards; opacity: 0; }
@keyframes na-zoom-in  { from { transform: scale(0);   opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes na-zoom-out { from { transform: scale(2.2); opacity: 0; } to { transform: scale(1); opacity: 1; } }

/* 등장 — bounce-in (위에서 통통 튕기며) */
.node.anim-bounce-in { animation: na-bounce-in 0.75s cubic-bezier(0.34, 1.56, 0.64, 1) forwards; opacity: 0; }
@keyframes na-bounce-in {
  0%   { transform: translateY(calc(-60% * var(--anim-amp-intro, 1))) scale(0.6); opacity: 0; }
  50%  { transform: translateY(calc(8% * var(--anim-amp-intro, 1)))   scale(1.06); opacity: 1; }
  75%  { transform: translateY(calc(-4% * var(--anim-amp-intro, 1)))  scale(0.98); }
  100% { transform: translateY(0)    scale(1);    opacity: 1; }
}

/* 퇴장 — fade-out */
.node.anim-fade-out { animation: na-fade-out 0.5s ease forwards; }
@keyframes na-fade-out { from { opacity: 1; } to { opacity: 0; } }

/* 퇴장 — slide-out 좌/우 */
.node.anim-slide-out-left  { animation: na-slide-out-left  0.5s ease-in forwards; }
.node.anim-slide-out-right { animation: na-slide-out-right 0.5s ease-in forwards; }
@keyframes na-slide-out-left  { from { transform: translateX(0); opacity: 1; } to { transform: translateX(-130%); opacity: 0; } }
@keyframes na-slide-out-right { from { transform: translateX(0); opacity: 1; } to { transform: translateX(130%);  opacity: 0; } }

/* 등장 — flash-in (깜빡이며 나타남) — 1 cycle = 1번 깜빡임. 횟수는 animation-iteration-count로 제어 */
.node.anim-flash-in { opacity: 0; animation: na-flash-in 0.18s ease-in-out forwards; animation-iteration-count: 5; }
@keyframes na-flash-in {
  0%, 49%   { opacity: 0; }
  50%, 100% { opacity: 1; }
}

/* 퇴장 — flash-out (깜빡이며 사라짐) — 1 cycle = 1번 깜빡임 */
.node.anim-flash-out { animation: na-flash-out 0.18s ease-in-out forwards; animation-iteration-count: 5; }
@keyframes na-flash-out {
  0%, 49%   { opacity: 1; }
  50%, 100% { opacity: 0; }
}

/* 등장 — shake-in (강한 흔들림으로 들어와 안정) */
.node.anim-shake-in { opacity: 0; animation: na-shake-in 0.9s cubic-bezier(0.2, 0.7, 0.3, 1) forwards; }
@keyframes na-shake-in {
  0%   { opacity: 0; transform: translate(0, calc(-10% * var(--anim-amp-intro, 1))) rotate(0); }
  10%  { opacity: 1; transform: translate(calc(-12% * var(--anim-amp-intro, 1)), calc(4% * var(--anim-amp-intro, 1)))  rotate(calc(-6deg * var(--anim-amp-intro, 1))); }
  20%  { transform: translate(calc(10% * var(--anim-amp-intro, 1)), calc(-3% * var(--anim-amp-intro, 1)))  rotate(calc(5deg * var(--anim-amp-intro, 1))); }
  30%  { transform: translate(calc(-9% * var(--anim-amp-intro, 1)), calc(2% * var(--anim-amp-intro, 1)))   rotate(calc(-4deg * var(--anim-amp-intro, 1))); }
  40%  { transform: translate(calc(7% * var(--anim-amp-intro, 1)), calc(-2% * var(--anim-amp-intro, 1)))   rotate(calc(3deg * var(--anim-amp-intro, 1))); }
  55%  { transform: translate(calc(-5% * var(--anim-amp-intro, 1)), calc(1% * var(--anim-amp-intro, 1)))   rotate(calc(-2deg * var(--anim-amp-intro, 1))); }
  70%  { transform: translate(calc(3% * var(--anim-amp-intro, 1)), 0)     rotate(calc(1deg * var(--anim-amp-intro, 1))); }
  85%  { transform: translate(calc(-1.5% * var(--anim-amp-intro, 1)), 0)  rotate(calc(-0.5deg * var(--anim-amp-intro, 1))); }
  100% { transform: translate(0, 0)      rotate(0); opacity: 1; }
}

/* 등장 — slam-in (위에서 쾅 떨어지듯) */
.node.anim-slam-in { opacity: 0; animation: na-slam-in 0.7s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
@keyframes na-slam-in {
  0%   { transform: translateY(calc(-150% * var(--anim-amp-intro, 1))) scale(calc(1 + 0.5 * var(--anim-amp-intro, 1))); opacity: 0; }
  55%  { transform: translateY(0) scale(calc(1 + 0.25 * var(--anim-amp-intro, 1))); opacity: 1; }
  65%  { transform: translateY(0) scale(0.92); }
  78%  { transform: translateY(0) scale(1.06); }
  90%  { transform: translateY(0) scale(0.98); }
  100% { transform: translateY(0) scale(1); opacity: 1; }
}

/* 등장 — stamp-in (도장 찍듯 큰 크기에서 빠르게 작아지며) */
.node.anim-stamp-in { opacity: 0; animation: na-stamp-in 0.55s cubic-bezier(0.34, 1.6, 0.4, 1) forwards; }
@keyframes na-stamp-in {
  0%   { transform: scale(calc(2.5 + 0.5 * var(--anim-amp-intro, 1))); opacity: 0; }
  55%  { transform: scale(0.85); opacity: 1; }
  72%  { transform: scale(1.08); }
  100% { transform: scale(1); opacity: 1; }
}

/* 등장 — rubber-in (고무줄처럼 늘어났다가 안착) */
.node.anim-rubber-in { opacity: 0; animation: na-rubber-in 0.8s ease-out forwards; }
@keyframes na-rubber-in {
  0%   { transform: scale3d(0.3, 0.3, 1); opacity: 0; }
  20%  { transform: scale3d(calc(1 + 0.15 * var(--anim-amp-intro, 1)), calc(1 - 0.15 * var(--anim-amp-intro, 1)), 1); opacity: 1; }
  40%  { transform: scale3d(calc(1 - 0.1 * var(--anim-amp-intro, 1)), calc(1 + 0.15 * var(--anim-amp-intro, 1)), 1); }
  60%  { transform: scale3d(1.05, 0.95, 1); }
  80%  { transform: scale3d(0.97, 1.03, 1); }
  100% { transform: scale3d(1, 1, 1); opacity: 1; }
}

/* 등장 — flip-3d-in (3D Y축 뒤집기) */
.node.anim-flip-3d-in { opacity: 0; animation: na-flip-3d-in 0.7s ease-out forwards; }
@keyframes na-flip-3d-in {
  0%   { transform: perspective(600px) rotateY(90deg) scale(0.8); opacity: 0; }
  40%  { transform: perspective(600px) rotateY(-25deg) scale(1.05); opacity: 1; }
  60%  { transform: perspective(600px) rotateY(12deg) scale(0.97); }
  80%  { transform: perspective(600px) rotateY(-5deg) scale(1.02); }
  100% { transform: perspective(600px) rotateY(0deg) scale(1); opacity: 1; }
}

/* 등장 — starburst-in (회전+스케일 폭발) */
.node.anim-starburst-in { opacity: 0; animation: na-starburst-in 0.7s cubic-bezier(0.34, 1.56, 0.64, 1) forwards; }
@keyframes na-starburst-in {
  0%   { transform: scale(0) rotate(calc(-180deg * var(--anim-amp-intro, 1))); opacity: 0; }
  60%  { transform: scale(calc(1.1 + 0.1 * var(--anim-amp-intro, 1))) rotate(calc(20deg * var(--anim-amp-intro, 1))); opacity: 1; }
  80%  { transform: scale(0.95) rotate(calc(-5deg * var(--anim-amp-intro, 1))); }
  100% { transform: scale(1) rotate(0); opacity: 1; }
}

/* 등장 — swirl-in (소용돌이로 들어옴) */
.node.anim-swirl-in { opacity: 0; animation: na-swirl-in 0.8s cubic-bezier(0.34, 1.4, 0.64, 1) forwards; }
@keyframes na-swirl-in {
  0%   { transform: scale(0) rotate(calc(540deg * var(--anim-amp-intro, 1))); opacity: 0; }
  60%  { transform: scale(1.08) rotate(calc(30deg * var(--anim-amp-intro, 1))); opacity: 1; }
  100% { transform: scale(1) rotate(0); opacity: 1; }
}

/* 등장 — shine-in (빛이 일시적으로 강해지며 등장) */
.node.anim-shine-in { opacity: 0; animation: na-shine-in 0.7s cubic-bezier(0.2, 0.8, 0.3, 1) forwards; }
@keyframes na-shine-in {
  0%   { opacity: 0; filter: brightness(0.2); }
  35%  { opacity: 1; filter: brightness(2.5); }
  65%  { filter: brightness(1.5); }
  100% { opacity: 1; filter: brightness(1); }
}

/* 등장 — light-sweep-in (좌→우 빛이 쓸고 지나가며 노출 — swipe 효과) */
.node.anim-light-sweep-in {
  opacity: 0;
  -webkit-mask-image: linear-gradient(110deg, transparent 0%, black 40%, black 60%, transparent 100%);
          mask-image: linear-gradient(110deg, transparent 0%, black 40%, black 60%, transparent 100%);
  -webkit-mask-size: 250% 100%;
          mask-size: 250% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  animation: na-light-sweep-in 0.9s cubic-bezier(0.2, 0.9, 0.3, 1) forwards;
}
@keyframes na-light-sweep-in {
  0%   { opacity: 0; -webkit-mask-position: -150% 0; mask-position: -150% 0; filter: brightness(2); }
  30%  { opacity: 1; filter: brightness(1.7); }
  99%  { opacity: 1; -webkit-mask-position: 150% 0;  mask-position: 150% 0;  filter: brightness(1); }
  100% { opacity: 1; -webkit-mask-image: none; mask-image: none; filter: brightness(1); }
}

/* 등장 — glow-pulse-in (광원이 펄스하며 등장) */
.node.anim-glow-pulse-in { opacity: 0; animation: na-glow-pulse-in 0.9s ease-out forwards; }
@keyframes na-glow-pulse-in {
  0%   { opacity: 0; filter: drop-shadow(0 0 0 #fff) brightness(0.5); }
  40%  { opacity: 1; filter: drop-shadow(0 0 calc(var(--su) * 6) #fff) brightness(2); }
  70%  { filter: drop-shadow(0 0 calc(var(--su) * 3) #fff) brightness(1.3); }
  100% { opacity: 1; filter: drop-shadow(0 0 0 transparent) brightness(1); }
}

/* 등장 — shimmer-in (반짝이며 등장) */
.node.anim-shimmer-in { opacity: 0; animation: na-shimmer-in 0.8s ease-out forwards; }
@keyframes na-shimmer-in {
  0%   { opacity: 0;   filter: brightness(0.3); }
  20%  { opacity: 1;   filter: brightness(3); }
  30%  { filter: brightness(0.5); }
  40%  { filter: brightness(2.5); }
  55%  { filter: brightness(0.8); }
  70%  { filter: brightness(1.8); }
  100% { opacity: 1;   filter: brightness(1); }
}

/* 퇴장 — shine-out (빛이 강해졌다가 사라짐) */
.node.anim-shine-out { animation: na-shine-out 0.7s cubic-bezier(0.4, 0, 0.6, 1) forwards; }
@keyframes na-shine-out {
  0%   { opacity: 1; filter: brightness(1); }
  35%  { opacity: 1; filter: brightness(2.5); }
  100% { opacity: 0; filter: brightness(0.2); }
}

/* 퇴장 — light-sweep-out (우→좌 빛이 쓸고 지나가며 사라짐 — swipe 효과) */
.node.anim-light-sweep-out {
  -webkit-mask-image: linear-gradient(110deg, transparent 0%, black 40%, black 60%, transparent 100%);
          mask-image: linear-gradient(110deg, transparent 0%, black 40%, black 60%, transparent 100%);
  -webkit-mask-size: 250% 100%;
          mask-size: 250% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  animation: na-light-sweep-out 0.9s ease-in forwards;
}
@keyframes na-light-sweep-out {
  0%   { opacity: 1; -webkit-mask-position: 150% 0;  mask-position: 150% 0;  filter: brightness(1); }
  50%  { filter: brightness(1.8); }
  100% { opacity: 0; -webkit-mask-position: -150% 0; mask-position: -150% 0; filter: brightness(0.5); }
}

/* 퇴장 — dissolve-out (빛으로 산화되며 사라짐) */
.node.anim-dissolve-out { animation: na-dissolve-out 0.8s ease-out forwards; }
@keyframes na-dissolve-out {
  0%   { opacity: 1;    filter: brightness(1) blur(0); }
  40%  { opacity: 0.85; filter: brightness(2.5) blur(calc(var(--su) * 0.5)); }
  100% { opacity: 0;    filter: brightness(4)   blur(calc(var(--su) * 2)); }
}

/* 퇴장 — shimmer-out (반짝이며 사라짐) */
.node.anim-shimmer-out { animation: na-shimmer-out 0.8s ease-out forwards; }
@keyframes na-shimmer-out {
  0%   { opacity: 1;   filter: brightness(1); }
  15%  { opacity: 0.5; filter: brightness(2); }
  30%  { opacity: 1;   filter: brightness(0.7); }
  45%  { opacity: 0.4; filter: brightness(2.5); }
  60%  { opacity: 0.8; filter: brightness(0.5); }
  100% { opacity: 0;   filter: brightness(1); }
}

/* 등장 — glow-burst-in (광원 폭발과 함께 등장. 외곽선 stroke와 함께 못 씀) */
.node.anim-glow-burst-in { opacity: 0; animation: na-glow-burst-in 0.8s cubic-bezier(0.2, 0.9, 0.3, 1) forwards; }
@keyframes na-glow-burst-in {
  0%   { transform: scale(0.4); opacity: 0; filter: brightness(3) blur(calc(var(--su) * 3)); }
  30%  { transform: scale(calc(1.15 + 0.15 * var(--anim-amp-intro, 1))); opacity: 1; filter: brightness(2.5) blur(0); }
  60%  { transform: scale(0.96); opacity: 1; filter: brightness(1.6) blur(0); }
  85%  { transform: scale(1.03); filter: brightness(1.2); }
  100% { transform: scale(1); opacity: 1; filter: brightness(1); }
}

/* 퇴장 — shake-out (점점 커지는 흔들림으로 부서지듯 사라짐) */
.node.anim-shake-out { animation: na-shake-out 0.8s cubic-bezier(0.5, 0, 0.8, 0.3) forwards; }
@keyframes na-shake-out {
  0%   { transform: translate(0, 0)         rotate(0); opacity: 1; }
  15%  { transform: translate(calc(-2% * var(--anim-amp-intro, 1)), 0)       rotate(calc(-1deg * var(--anim-amp-intro, 1))); }
  30%  { transform: translate(calc(4% * var(--anim-amp-intro, 1)), calc(-1% * var(--anim-amp-intro, 1)))      rotate(calc(2deg * var(--anim-amp-intro, 1))); }
  45%  { transform: translate(calc(-6% * var(--anim-amp-intro, 1)), calc(2% * var(--anim-amp-intro, 1)))      rotate(calc(-3deg * var(--anim-amp-intro, 1))); }
  60%  { transform: translate(calc(9% * var(--anim-amp-intro, 1)), calc(-3% * var(--anim-amp-intro, 1)))      rotate(calc(4deg * var(--anim-amp-intro, 1))); opacity: 0.85; }
  75%  { transform: translate(calc(-13% * var(--anim-amp-intro, 1)), calc(5% * var(--anim-amp-intro, 1)))     rotate(calc(-5deg * var(--anim-amp-intro, 1))); opacity: 0.55; }
  100% { transform: translate(calc(18% * var(--anim-amp-intro, 1)), calc(-8% * var(--anim-amp-intro, 1)))     rotate(calc(7deg * var(--anim-amp-intro, 1))); opacity: 0; }
}

/* 반복 — pulse (CTA보다 강한 스케일) */
.node.anim-pulse { animation: na-pulse 1.2s ease-in-out infinite; }
@keyframes na-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(calc(1 + 0.12 * var(--anim-amp-loop, 1))); }
}

/* 반복 — flash (깜빡임) */
.node.anim-flash { animation: na-flash 1.2s ease-in-out infinite; }
@keyframes na-flash {
  0%, 50%, 100% { opacity: 1; }
  25%, 75%      { opacity: 0.3; }
}

/* 반복 — swing (좌우로 살짝 회전) */
.node.anim-swing { animation: na-swing 1.6s ease-in-out infinite; transform-origin: top center; }
@keyframes na-swing {
  0%, 100% { transform: rotate(0); }
  25%      { transform: rotate(calc(8deg * var(--anim-amp-loop, 1))); }
  75%      { transform: rotate(calc(-8deg * var(--anim-amp-loop, 1))); }
}

/* 반복 — rotate (연속 회전, 360°) */
.node.anim-rotate { animation: na-rotate 2.5s linear infinite; }
@keyframes na-rotate { to { transform: rotate(360deg); } }

/* 반복 — tada (스케일 + 흔들기, 강조) */
.node.anim-tada { animation: na-tada 2.4s ease-in-out infinite; }
@keyframes na-tada {
  0%, 100%            { transform: scale(1) rotate(0); }
  10%, 20%            { transform: scale(0.95) rotate(calc(-3deg * var(--anim-amp-loop, 1))); }
  30%, 50%, 70%, 90%  { transform: scale(calc(1 + 0.1 * var(--anim-amp-loop, 1)))  rotate(calc(3deg * var(--anim-amp-loop, 1))); }
  40%, 60%, 80%       { transform: scale(calc(1 + 0.1 * var(--anim-amp-loop, 1)))  rotate(calc(-3deg * var(--anim-amp-loop, 1))); }
}

/* ── 반복 빛 효과 ─────────────────── */

/* 반복 — glow-loop (광채 펄스) */
.node.anim-glow-loop { animation: na-glow-loop 2s ease-in-out infinite; }
@keyframes na-glow-loop {
  0%, 100% { filter: drop-shadow(0 0 0 transparent) brightness(1); }
  50%      { filter: drop-shadow(0 0 calc(var(--su) * 2 * var(--anim-amp-loop, 1)) #fff) brightness(calc(1 + 0.3 * var(--anim-amp-loop, 1))); }
}

/* 반복 — shimmer-loop (반짝임 깜빡임) */
.node.anim-shimmer-loop { animation: na-shimmer-loop 2s ease-in-out infinite; }
@keyframes na-shimmer-loop {
  0%, 100% { filter: brightness(1); }
  25%      { filter: brightness(calc(1 + 0.6 * var(--anim-amp-loop, 1))); }
  50%      { filter: brightness(calc(1 - 0.1 * var(--anim-amp-loop, 1))); }
  75%      { filter: brightness(calc(1 + 0.4 * var(--anim-amp-loop, 1))); }
}

/* 반복 — shine-loop (강한 빛 peak 반복) */
.node.anim-shine-loop { animation: na-shine-loop 2.5s ease-in-out infinite; }
@keyframes na-shine-loop {
  0%, 100% { filter: brightness(1); }
  40%      { filter: brightness(calc(1 + 1 * var(--anim-amp-loop, 1))); }
}

/* 반복 — sweep-loop (빛 띠가 element 위를 반복 sweep — ::after overlay) */
/* .node 가 이미 position: absolute 라 ::after 가 부모 기준으로 그려짐 — position 추가 불필요 */
.node.anim-sweep-loop::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(110deg,
    transparent 30%,
    rgba(255, 255, 255, calc(0.55 * var(--anim-amp-loop, 1))) 50%,
    transparent 70%);
  background-size: 250% 100%;
  background-position: -150% 0;
  animation: na-sweep-loop 3s ease-in-out infinite;
  mix-blend-mode: screen;
  border-radius: inherit;
}
@keyframes na-sweep-loop {
  0%        { background-position: -150% 0; }
  60%, 100% { background-position: 150% 0; }
}

/* 손가락 탭 인디케이터 */
.indicator-finger {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--su) * 8);
  height: calc(var(--su) * 8);
  margin-left: calc(var(--su) * -4);
  margin-top: calc(var(--su) * -4);
  pointer-events: none;
  z-index: 10;
  animation: finger-tap 1.4s ease-in-out infinite;
}
.indicator-finger::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 35%, #fff 38%, rgba(255,255,255,0) 70%);
  border-radius: 50%;
  opacity: 0.85;
}
@keyframes finger-tap {
  0%, 100% { transform: scale(0.95); opacity: 0.7; }
  50%      { transform: scale(1.1); opacity: 1.0; }
}

/* 전역 로고 (모든 씬 위) */
#globalLogo {
  position: absolute;
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  pointer-events: none;
  z-index: 30;
  display: none;
}
#globalLogo.visible { display: block; }

/* 코너 CTA 버튼 (상시) */
#cornerCta {
  position: absolute;
  top: 16px;
  right: 16px;
  padding: 10px 18px;
  background: linear-gradient(180deg, #ff6b3d, #e6432a);
  color: #fff;
  font-weight: 800;
  font-size: 14px;
  border: 0;
  border-radius: 999px;
  box-shadow: 0 6px 16px rgba(0,0,0,0.35);
  z-index: 30;
  cursor: pointer;
  display: none;
}
#cornerCta.visible { display: inline-flex; align-items: center; }

/* 풀스크린 CTA (마지막) */
#finalCta {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(0,0,0,0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 40;
}
#finalCta.visible { display: flex; }
#finalCta button {
  padding: 20px 42px;
  background: linear-gradient(180deg, #ffd24a, #ff8a1f);
  color: #1a0d00;
  font-weight: 900;
  font-size: 22px;
  border: 0;
  border-radius: 999px;
  box-shadow: 0 10px 28px rgba(0,0,0,0.45);
  cursor: pointer;
  animation: na-cta 1.2s ease-in-out infinite;
}

/* ============================================================
 *  씬 동적 연출(FX) — PlayableFX (fx.js) 와 함께 동작
 *  파티클은 .fx-canvas(캔버스), 배경모션은 .fx-css(+자식) 로 렌더.
 *  --fx-int(강도, 기본1), --fx-color(색상) 변수로 조절.
 * ============================================================ */
.fx-layer { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
.fx-canvas { position: absolute; inset: 0; pointer-events: none; }
.fx-css { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }

/* 회전 광선 */
.fx-rays::before {
  content: ''; position: absolute; left: 50%; top: 50%; width: 220%; height: 220%;
  transform: translate(-50%, -50%);
  background: repeating-conic-gradient(from 0deg, transparent 0deg,
    var(--fx-color, rgba(255,255,255,0.16)) 3deg, transparent 11deg);
  opacity: calc(0.55 * var(--fx-int, 1));
  animation: fx-spin 20s linear infinite;
}
@keyframes fx-spin { to { transform: translate(-50%, -50%) rotate(360deg); } }

/* 방사 펄스 */
.fx-pulse::before {
  content: ''; position: absolute; inset: -25%;
  background: radial-gradient(circle at 50% 52%, var(--fx-color, rgba(255,220,150,0.6)) 0%, transparent 55%);
  animation: fx-pulse 3.2s ease-in-out infinite;
}
@keyframes fx-pulse {
  0%, 100% { transform: scale(0.85); opacity: calc(0.25 * var(--fx-int, 1)); }
  50%      { transform: scale(1.12); opacity: calc(0.7 * var(--fx-int, 1)); }
}

/* 그라데이션 흐름 */
.fx-gradient::before {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(60deg, transparent, var(--fx-color, rgba(120,170,255,0.4)),
    transparent, rgba(255,140,200,0.32), transparent);
  background-size: 320% 320%;
  opacity: calc(0.8 * var(--fx-int, 1));
  animation: fx-grad 9s ease-in-out infinite;
}
@keyframes fx-grad { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }

/* 보케 (떠다니는 원) — 자식 span 은 fx.js 가 배치 */
.fx-bokeh span {
  position: absolute; border-radius: 50%;
  background: radial-gradient(circle, var(--fx-color, rgba(255,255,255,0.7)) 0%, transparent 70%);
  filter: blur(3px);
  opacity: calc(0.5 * var(--fx-int, 1));
  transform: translate(-50%, -50%);
  animation-name: fx-bokeh-float; animation-timing-function: ease-in-out; animation-iteration-count: infinite;
}
@keyframes fx-bokeh-float {
  0%   { transform: translate(-50%, -50%) translateY(7%); }
  50%  { transform: translate(-50%, -50%) translateY(-7%); }
  100% { transform: translate(-50%, -50%) translateY(7%); }
}

/* 빛 쓸기 */
.fx-sweep::before {
  content: ''; position: absolute; top: -50%; left: -60%; width: 38%; height: 200%;
  background: linear-gradient(90deg, transparent, var(--fx-color, rgba(255,255,255,0.5)), transparent);
  transform: rotate(18deg);
  opacity: calc(0.85 * var(--fx-int, 1));
  animation: fx-sweep 4.5s ease-in-out infinite;
}
@keyframes fx-sweep { 0% { left: -60%; } 55%, 100% { left: 135%; } }

/* 비네팅 호흡 (가장자리 어둡게) */
.fx-vignette::before {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(ellipse at center, transparent 42%, var(--fx-color, rgba(0,0,0,0.78)) 125%);
  animation: fx-vig 4s ease-in-out infinite;
}
@keyframes fx-vig {
  0%, 100% { opacity: calc(0.5 * var(--fx-int, 1)); }
  50%      { opacity: calc(0.9 * var(--fx-int, 1)); }
}

