/* ══════════════════════════════════════════════════════════
   Animations — iBots v3.0  (전면 오버홀)
   WebAnimator 소유. 전역 모션 토큰 + @keyframes + 유틸리티.
   ──────────────────────────────────────────────────────────
   철학: "애니메이션은 정보를 전달하는 도구다. 장식이 아니다."
   규칙: transform/opacity만 애니메이트. 600ms 초과 금지.
   ══════════════════════════════════════════════════════════ */


/* ═══════════════════════════════════════════
   §1  Motion Design Tokens
   ═══════════════════════════════════════════ */
:root {
    /* ═══════════════════════════════════════════════════════
       tokens.css 중복 완전 제거 (2026-03-15)
       tokens.css §Easing / §Transition / §Motion 에서 정의된 토큰:
         --easing-* 10종 + --easing-slide/sheet (§Easing)
         --ease-* 별칭 10종 (§Easing 별칭)
         --duration-* 6종 + --anim-fast/base/smooth (§Transition)
         --motion-hover/state/enter/exit (§Motion 단축)
       animations.css 전용 토큰만 아래에 유지.
       ═══════════════════════════════════════════════════════ */

    /* ── Composite Motion (animations.css 전용 — tokens.css에 없음) ── */
    --motion-spring:  var(--duration-spring) var(--easing-spring-gentle);    /* 바운스 진입 (400ms spring 토큰) */
    --motion-shift:   var(--duration-base) var(--easing-in-out);     /* 위치 이동 */
    --motion-flip:    var(--duration-flip) var(--easing-in-out);     /* FLIP 레이아웃 전환 (500ms) */
    --motion-dramatic: var(--duration-dramatic) var(--easing-out);   /* 히어로 극적 진입 (800ms) */

    /* ── Semantic Motion (animations.css 전용 — tokens.css에 없음) ── */
    --motion-focus:   var(--duration-base) var(--easing-out);        /* 포커스 전환 */
    --motion-layout:  var(--duration-flip) var(--easing-out);        /* 레이아웃 전환 (FLIP 토큰) */
    --motion-color:   var(--duration-base) var(--easing-out);        /* 색상 전환 */

    /* ── Stagger ── */
    --stagger-1: 30ms;
    --stagger-2: 60ms;
    --stagger-3: 90ms;
    --stagger-4: 120ms;
    --stagger-5: 150ms;
    --stagger-6: 180ms;
    --stagger-7: 210ms;
    --stagger-8: 240ms;
    --stagger-9: 270ms;
    --stagger-10: 300ms;
    --stagger-11: 330ms;
    --stagger-12: 360ms;

    /* ── Duration 별칭 (tokens.css에 없는 것만 유지) ── */
    --anim-slow:    var(--duration-slow);     /* 450ms — components.css에서 사용 중 */
    --anim-slower:  var(--duration-slower);   /* 600ms — 페이지 진입/스태거 전체 */
}


/* ═══════════════════════════════════════════
   §2  Core @keyframes — 기본 등장/퇴장
   ═══════════════════════════════════════════ */

/* 페이드 */
@keyframes animFadeIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}
@keyframes animFadeOut {
    from { opacity: 1; }
    to   { opacity: 0; }
}

/* 슬라이드 + 페이드 (각 방향) */
@keyframes animSlideUp {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes animSlideDown {
    from { opacity: 0; transform: translateY(-10px); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes animSlideLeft {
    from { opacity: 0; transform: translateX(12px); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes animSlideRight {
    from { opacity: 0; transform: translateX(-12px); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}

/* 스케일 등장/퇴장 */
@keyframes animScaleIn {
    from { opacity: 0; transform: scale(0.94); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes animScaleOut {
    from { opacity: 1; transform: none; }
    to   { opacity: 0; transform: scale(0.94); }
}


/* ═══════════════════════════════════════════
   §3  Rich @keyframes — 인터랙션/모션
   ═══════════════════════════════════════════ */

/* 스프링 등장 (모달/드로어) — gentle spring 오버슈트 3단계 안착 */
@keyframes animSpringIn {
    0%   { opacity: 0; transform: scale(0.90) translateY(10px); }
    45%  { opacity: 1; transform: scale(1.025) translateY(-2px); }
    70%  { transform: scale(0.995) translateY(0.5px); }
    100% { transform: none; }
}

/* 바운스 등장 — bouncy spring 강한 오버슈트 + 더블 바운스 */
@keyframes animBounceIn {
    0%   { opacity: 0; transform: scale(0.3); }
    40%  { opacity: 1; transform: scale(1.08); }
    60%  { transform: scale(0.94); }
    78%  { transform: scale(1.03); }
    100% { transform: none; }
}

/* 팝 등장 (성공 표시, 뱃지) — spring 오버슈트 + 글로우 임팩트 */
@keyframes animPopIn {
    0%   { opacity: 0; transform: scale(0); }
    55%  { opacity: 1; transform: scale(1.12); }
    72%  { transform: scale(0.96); }
    88%  { transform: scale(1.03); }
    100% { transform: none; }
}

/* 스프링 스케일 등장 (0→1 scale + opacity, elastic 오버슈트 + 리바운드) */
@keyframes animSpringScaleIn {
    0%   { opacity: 0; transform: scale(0); }
    45%  { opacity: 1; transform: scale(1.10); }
    65%  { transform: scale(0.95); }
    82%  { transform: scale(1.03); }
    100% { transform: none; }
}

/* 드롭다운 열기/닫기 — scaleY + 페이드 */
@keyframes animDropdownOpen {
    from { opacity: 0; transform: scaleY(0.96) translateY(-4px); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes animDropdownClose {
    from { opacity: 1; transform: none; }
    to   { opacity: 0; transform: scaleY(0.96) translateY(-4px); }
}

/* 토스트 등장 (우측에서 스프링) */
@keyframes animToastIn {
    0%   { opacity: 0; transform: translateX(32px) scale(0.96); }
    60%  { transform: translateX(-3px) scale(1.01); }
    100% { opacity: 1; transform: none; }
}

/* 부드러운 흔들림 (주목 유도) */
@keyframes animShake {
    0%, 100% { transform: translateX(0); }
    15%, 55% { transform: translateX(-3px); }
    35%, 75% { transform: translateX(3px); }
}

/* 부드러운 부유 */
@keyframes animFloat {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-3px); }
}

/* 유기적 호흡 — 비대칭 리듬, 생물처럼 살아있는 느낌 */
@keyframes animOrganicBreathe {
    0%   { transform: scale(1);      opacity: 1; }
    25%  { transform: scale(1.012);  opacity: 0.94; }
    45%  { transform: scale(1.006);  opacity: 0.97; }
    65%  { transform: scale(0.996);  opacity: 1; }
    80%  { transform: scale(1.003);  opacity: 0.98; }
    100% { transform: scale(1);      opacity: 1; }
}

/* ═══════════════════════════════════════════
   §4  상태 애니메이션 (루프)
   ═══════════════════════════════════════════ */

/* 스피너 — @keyframes spin은 reset.css에 정의됨 */

/* 펄스 (호흡) */
@keyframes animPulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.5; }
}

/* 점멸 */
@keyframes animBlink {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.15; }
}

/* accent 글로우 펄스 — 워킹 상태 */
@keyframes animGlowPulse {
    0%, 100% { box-shadow: var(--shadow-glow-pulse-base); }
    50%      { box-shadow: var(--shadow-glow-pulse-peak); }
}

/* 호흡 글로우 (box-shadow) */
@keyframes animBreathe {
    0%, 100% { box-shadow: 0 0 0 0 var(--surface-active); }
    50%      { box-shadow: var(--shadow-breathe-glow); }
}

/* 그라데이션 흐름 (활성 상태 보더) */
@keyframes animGradientFlow {
    0%   { background-position: 0% 50%; }
    50%  { background-position: 100% 50%; }
    100% { background-position: 0% 50%; }
}

/* 느린 회전 */
@keyframes animRotateSlow {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

/* 포커스 링 확산 */
@keyframes animFocusRing {
    0%   { box-shadow: 0 0 0 0 var(--clr-info-border-strong); }
    70%  { box-shadow: 0 0 0 4px var(--accent-transparent); }
    100% { box-shadow: 0 0 0 0 var(--accent-transparent); }
}

/* 상태 플래시 (배경 전환 시) */
@keyframes animStateFlash {
    0%   { opacity: 0.3; }
    100% { opacity: 1; }
}

/* 리플 (클릭 효과) */
@keyframes animRipple {
    0%   { transform: scale(0); opacity: 0.5; }
    100% { transform: scale(2.5); opacity: 0; }
}


/* ═══════════════════════════════════════════
   §5  탭/패널/채팅 전환
   ═══════════════════════════════════════════ */

/* 탭 패널 진입 */
@keyframes animTabEnter {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}

/* 탭 인디케이터 — §19c L1263에서 scaleX+opacity 버전으로 재정의 */

/* 채팅 메시지 좌측 진입 */
@keyframes animMsgEnterLeft {
    from { opacity: 0; transform: translateX(-6px) scale(0.98); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}

/* 채팅 메시지 우측 진입 */
@keyframes animMsgEnterRight {
    from { opacity: 0; transform: translateX(6px) scale(0.98); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}


/* ═══════════════════════════════════════════
   §6  Skeleton Loading — 시머/플레이스홀더
   ═══════════════════════════════════════════ */

/* 핵심 시머 키프레임 — 좌→우 빛 스윕 */
@keyframes animSkeletonShimmer {
    0%   { background-position: -400px 0; }
    100% { background-position: 400px 0; }
}

/* 기본 스켈레톤 블록 — 시머 애니메이션 기반 클래스
   영역별 레이아웃(.skeleton-agent-card 등)은 components.css에 정의 */
.skeleton {
    position: relative;
    overflow: hidden;
    /* 프리미엄 시머 — 105° 비대칭 + 넓은 그래디언트 하이라이트 */
    background: linear-gradient(
        105deg,
        var(--surface) 0%, var(--surface) 35%,
        var(--surface-hover) 45%, var(--surface-w5, var(--surface-hover)) 50%,
        var(--surface-hover) 55%, var(--surface) 65%, var(--surface) 100%
    );
    background-size: 300% 100%;
    animation: animPremiumShimmer 2s var(--easing-smooth, ease) infinite;
    border-radius: var(--radius, 8px);
}

/* 시머 오버레이 (기존 요소 위에 겹쳐서 로딩 표시) */
.shimmer-overlay {
    position: relative;
    overflow: hidden;
}
.shimmer-overlay::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(
        90deg,
        transparent 0%,
        var(--surface-w4) 40%,
        var(--surface-w8) 50%,
        var(--surface-w4) 60%,
        transparent 100%
    );
    background-size: 400px 100%;
    animation: animSkeletonShimmer 1.5s linear infinite;
    pointer-events: none;
    border-radius: inherit;
}


/* ═══════════════════════════════════════════
   §6b  Skeleton → Content 전환
   ─────────────────────────────────────────
   skeleton-exit: skeleton 요소가 사라질 때 페이드+미세 스케일 축소.
   content-enter: 실제 콘텐츠가 등장할 때 페이드+미세 슬라이드업.
   JS에서 skeleton에 .skeleton-exit 추가 → animationend 후 교체
   → 새 콘텐츠에 .content-enter 추가.
   ═══════════════════════════════════════════ */

/* skeleton 퇴장 — 빠른 페이드+스케일 */
.skeleton-exit {
    animation: animSkeletonExit var(--duration-fast) var(--easing-in) forwards;
    pointer-events: none;
}
@keyframes animSkeletonExit {
    from { opacity: 1; transform: scale(1); }
    to   { opacity: 0; transform: scale(0.98); }
}

/* 콘텐츠 등장 — 부드러운 페이드+슬라이드업 */
.content-enter {
    animation: animContentEnter var(--duration-base) var(--easing-out) both;
}
@keyframes animContentEnter {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}

/* 탭/패널 콘텐츠 전환 — 미세 슬라이드업+페이드 (탭 전환 시 사용) */
@keyframes animTabReveal {
    from { opacity: 0; transform: translateY(8px) scale(0.99); filter: var(--glass-blur-xs); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}

/* 콘텐츠 순차 등장 — 컨테이너에 부여하면 자식이 stagger 등장 */
.content-enter-stagger > * {
    opacity: 0;
    animation: animContentEnter var(--duration-base) var(--easing-out) forwards;
}
.content-enter-stagger > *:nth-child(1) { animation-delay: var(--stagger-1); }
.content-enter-stagger > *:nth-child(2) { animation-delay: var(--stagger-2); }
.content-enter-stagger > *:nth-child(3) { animation-delay: var(--stagger-3); }
.content-enter-stagger > *:nth-child(4) { animation-delay: var(--stagger-4); }
.content-enter-stagger > *:nth-child(5) { animation-delay: var(--stagger-5); }
.content-enter-stagger > *:nth-child(6) { animation-delay: var(--stagger-6); }
.content-enter-stagger > *:nth-child(7) { animation-delay: var(--stagger-7); }
.content-enter-stagger > *:nth-child(8) { animation-delay: var(--stagger-8); }
/* 9~12번째 자식 확장 — .stagger-children 동일 12개 커버리지 (토큰 참조) */
.content-enter-stagger > *:nth-child(9)  { animation-delay: var(--stagger-9); }
.content-enter-stagger > *:nth-child(10) { animation-delay: var(--stagger-10); }
.content-enter-stagger > *:nth-child(11) { animation-delay: var(--stagger-11); }
.content-enter-stagger > *:nth-child(12) { animation-delay: var(--stagger-12); }


/* ═══════════════════════════════════════════
   §6c  Skeleton → Content 심리스 전환 헬퍼
   ─────────────────────────────────────────
   §6b의 클래스 기반 전환을 보강하는 컨테이너 레벨 헬퍼.
   JS에서 replaceSkeletonWithContent() 호출 시 자동 적용.
   ═══════════════════════════════════════════ */

/* 크로스페이드 — skeleton/content 동시 겹침 전환 */
.skeleton-crossfade {
    position: relative;
    overflow: hidden;
}
.skeleton-crossfade > .skeleton,
.skeleton-crossfade > .skeleton-container {
    transition: opacity 180ms var(--easing-in);
}
.skeleton-crossfade > .skeleton.fading,
.skeleton-crossfade > .skeleton-container.fading {
    opacity: 0;
}

/* 콘텐츠 등장 변형 — 위로 슬라이드 */
.content-enter-up {
    animation: animContentEnterUp var(--duration-base) var(--easing-out) both;
}
@keyframes animContentEnterUp {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}

/* 콘텐츠 등장 변형 — 스케일 */
.content-enter-scale {
    animation: animContentEnterScale var(--duration-base) var(--easing-out) both;
}
@keyframes animContentEnterScale {
    from { opacity: 0; transform: scale(0.96); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}

/* 그리드 카드 순차 등장 — CSS variable 기반 (JS에서 --stagger-i 주입) */
.content-grid-stagger > * {
    opacity: 0;
    animation: animContentEnter var(--duration-moderate) var(--easing-out) forwards;
    animation-delay: calc(var(--stagger-i, 0) * 40ms);
}

/* ═══════════════════════════════════════════
   §7  Utility Classes — 진입 애니메이션
   ═══════════════════════════════════════════ */

.anim-fade-in     { animation: animFadeIn var(--duration-base) var(--easing-out) both; }
.anim-fade-out    { animation: animFadeOut var(--duration-fast) var(--easing-in) both; }
.anim-slide-up    { animation: animSlideUp var(--duration-base) var(--easing-out) both; }
.anim-slide-down  { animation: animSlideDown var(--duration-base) var(--easing-out) both; }
.anim-slide-left  { animation: animSlideLeft var(--duration-moderate) var(--easing-out) both; }
.anim-slide-right { animation: animSlideRight var(--duration-moderate) var(--easing-out) both; }
.anim-scale-in    { animation: animScaleIn var(--duration-base) var(--easing-out) both; }
.anim-scale-out   { animation: animScaleOut var(--duration-fast) var(--easing-in) both; }
.anim-bounce-in   { animation: animBounceIn var(--duration-slow) var(--easing-smooth) both; }
.anim-spring-in   { animation: animSpringIn var(--duration-spring) var(--easing-spring-gentle) both; }
.anim-pop-in      { animation: animPopIn var(--duration-spring) var(--easing-spring-gentle) both; }
.anim-spring-scale-in { animation: animSpringScaleIn var(--duration-spring) var(--easing-spring-gentle) both; }
.anim-toast-in    { animation: animToastIn var(--duration-spring) var(--easing-spring-elastic) both; }

/* 상태 루프 유틸리티 */
.anim-spin     { animation: spin 1s linear infinite; }
.anim-pulse    { animation: animPulse 2s var(--easing-in-out) infinite; }
.anim-float    { animation: animFloat 3s var(--easing-in-out) infinite; }
.anim-breathe  { animation: animBreathe 3s var(--easing-in-out) infinite; }
.anim-glow     { animation: animGlowPulse 2.5s var(--easing-in-out) infinite; }
.anim-blink    { animation: animBlink 1.5s var(--easing-smooth) infinite; }
.anim-shake    { animation: animShake var(--duration-flip) var(--easing-smooth); }

/* 시머 유틸리티 (카드 hover 등) */
.anim-shimmer {
    background: linear-gradient(90deg,
        transparent 0%,
        var(--surface-w4) 40%,
        var(--surface-w8) 50%,
        var(--surface-w4) 60%,
        transparent 100%
    );
    background-size: 400px 100%;
    animation: animSkeletonShimmer 1.8s linear infinite;
}

/* 스태거 딜레이 (개별 자식에 직접 부여) */
.stagger-1  { animation-delay: var(--stagger-1); }
.stagger-2  { animation-delay: var(--stagger-2); }
.stagger-3  { animation-delay: var(--stagger-3); }
.stagger-4  { animation-delay: var(--stagger-4); }
.stagger-5  { animation-delay: var(--stagger-5); }
.stagger-6  { animation-delay: var(--stagger-6); }
.stagger-7  { animation-delay: var(--stagger-7); }
.stagger-8  { animation-delay: var(--stagger-8); }
.stagger-9  { animation-delay: var(--stagger-9); }
.stagger-10 { animation-delay: var(--stagger-10); }
.stagger-11 { animation-delay: var(--stagger-11); }
.stagger-12 { animation-delay: var(--stagger-12); }

/* 범용 순차 등장 — 부모에 부여하면 직계 자식이 fade+slide stagger 등장.
   .content-enter-stagger 의 범용 별칭.
   --stagger-gap: 커스텀 간격 (기본 30ms). 부모에 설정 가능.
   nth-child 1~12: 하드코딩 delay / 13+: JS --stagger-i 주입으로 대응 */
.stagger-children > * {
    opacity: 0;
    animation: animContentEnter var(--duration-base) var(--easing-out) forwards;
}
.stagger-children > *:nth-child(1)  { animation-delay: var(--stagger-1); }
.stagger-children > *:nth-child(2)  { animation-delay: var(--stagger-2); }
.stagger-children > *:nth-child(3)  { animation-delay: var(--stagger-3); }
.stagger-children > *:nth-child(4)  { animation-delay: var(--stagger-4); }
.stagger-children > *:nth-child(5)  { animation-delay: var(--stagger-5); }
.stagger-children > *:nth-child(6)  { animation-delay: var(--stagger-6); }
.stagger-children > *:nth-child(7)  { animation-delay: var(--stagger-7); }
.stagger-children > *:nth-child(8)  { animation-delay: var(--stagger-8); }
.stagger-children > *:nth-child(9)  { animation-delay: var(--stagger-9); }
.stagger-children > *:nth-child(10) { animation-delay: var(--stagger-10); }
.stagger-children > *:nth-child(11) { animation-delay: var(--stagger-11); }
.stagger-children > *:nth-child(12) { animation-delay: var(--stagger-12); }

/* calc 기반 stagger — JS에서 --stagger-i를 0,1,2,...로 주입 시
   12개 넘는 리스트도 대응. --stagger-gap으로 간격 커스텀 가능 */
.stagger-children-calc > * {
    opacity: 0;
    animation: animContentEnter var(--duration-base) var(--easing-out) forwards;
    animation-delay: calc(var(--stagger-i, 0) * var(--stagger-gap, 30ms));
}


/* ═══════════════════════════════════════════
   §8  인터랙션 유틸리티 — hover/active/focus
   ═══════════════════════════════════════════ */

/* 카드 호버 리프트 — 스프링 기반 유기적 움직임 (A2: GPU 안정화 + 타이밍 최적화) */
.hover-lift {
    transition: transform 250ms var(--easing-spring-gentle),
                box-shadow var(--duration-fast) var(--easing-out);
    will-change: transform;
    backface-visibility: hidden;
}
.hover-lift:hover {
    transform: translateY(var(--hover-lift)) scale(1.005);
    box-shadow: var(--shadow-lift);
}
.hover-lift:active {
    transform: translateY(0) scale(0.98);
    transition-duration: var(--duration-instant);
    box-shadow: none;
}

/* 소형 요소 호버 리프트 — 리스트 아이템, 미니 카드, 칩 등 */
.hover-lift-sm {
    transition: transform var(--duration-base) var(--easing-spring-gentle),
                box-shadow var(--duration-fast) var(--easing-out);
    will-change: transform;
    backface-visibility: hidden;
}
.hover-lift-sm:hover {
    transform: translateY(var(--hover-lift-sm)) scale(1.003);
    box-shadow: var(--shadow-float);
}
.hover-lift-sm:active {
    transform: translateY(0) scale(var(--active-scale));
    transition-duration: var(--duration-instant);
    box-shadow: none;
}

/* 카드 호버 글로우 — 유기적 확산 */
.hover-glow {
    transition: box-shadow 300ms var(--easing-out),
                transform 250ms var(--easing-spring-gentle);
}
.hover-glow:hover {
    box-shadow: var(--shadow-hover-glow-card);
    transform: scale(1.003);
}

/* 버튼 탄성 클릭 — 강화된 스프링 (bouncy: 가벼운 오버슈트) */
.press-spring {
    transition: transform 200ms var(--easing-spring-bouncy);
}
.press-spring:hover {
    transform: scale(1.02);
}
.press-spring:active {
    transform: scale(0.94);
    transition-duration: 60ms;
}

/* 포커스 링 */
.focus-ring:focus-visible {
    outline: none;
    box-shadow: var(--shadow-outline-double);
    animation: animFocusRing 1.5s var(--easing-out);
}

/* 호버 시 시머 오버레이 */
.hover-shimmer {
    position: relative;
    overflow: hidden;
}
.hover-shimmer::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(
        105deg,
        transparent 40%,
        var(--surface-w3) 45%,
        var(--surface-w5) 50%,
        var(--surface-w3) 55%,
        transparent 60%
    );
    transform: translateX(-100%);
    transition: transform var(--duration-moderate) var(--easing-out);
    pointer-events: none;
    border-radius: inherit;
}
.hover-shimmer:hover::after {
    transform: translateX(100%);
}


/* ═══════════════════════════════════════════
   §8b  Extended Hover-Lift — 주요 인터랙티브 요소 일괄 적용
   ─────────────────────────────────────────
   hover-lift 적용률 확대: 기존 유틸리티 클래스(§8)에 더해
   주요 카드·리스트·패널 요소에 직접 트랜지션을 선언.
   OV 검증: 기존 :hover에 transform 미사용 확인 완료.
   ═══════════════════════════════════════════ */

/* agent-card hover/active transform: components.css 단일 권위 선언으로 통합 (T1) */

/* ── Tier 1 (Strong) — 카드급: translateY + shadow ── */
.create-team-agent-card:not(.no-lift),
.mcp-tool-item:not(.no-lift),
.modal-icon-option:not(.no-lift),
.mc-dpick-item:not(.no-lift),
.job-timeline-item[style*="cursor:pointer"]:not(.no-lift),
.sd-output-item:not(.no-lift) {
    transition: transform 250ms var(--easing-spring-gentle),
                box-shadow var(--duration-fast) var(--easing-out);
    will-change: transform;
    backface-visibility: hidden;
}
.create-team-agent-card:not(.no-lift):hover,
.mcp-tool-item:not(.no-lift):hover,
.modal-icon-option:not(.no-lift):hover,
.mc-dpick-item:not(.no-lift):hover,
.job-timeline-item[style*="cursor:pointer"]:not(.no-lift):hover,
.sd-output-item:not(.no-lift):hover {
    transform: translateY(var(--hover-lift-sm)) scale(1.003);
}
.create-team-agent-card:not(.no-lift):active,
.mcp-tool-item:not(.no-lift):active,
.modal-icon-option:not(.no-lift):active,
.mc-dpick-item:not(.no-lift):active,
.job-timeline-item[style*="cursor:pointer"]:not(.no-lift):active,
.sd-output-item:not(.no-lift):active {
    transform: translateY(0) scale(var(--active-scale));
    transition-duration: var(--duration-instant);
}

/* ── Tier 2 (Subtle) — 리스트 아이템: 미세 lift ── */
.sd-message:not(.no-lift),
.sd-agent-progress:not(.no-lift),
.sd-round-header:not(.no-lift),
.ref-browse-item:not(.no-lift),
.mc-wf-head:not(.no-lift),
.mcp-tool-btn:not(.no-lift),
.modal-tab:not(.no-lift),
.create-team-replan-btn:not(.no-lift) {
    transition: transform var(--duration-base) var(--easing-spring-gentle);
    will-change: transform;
}
.sd-message:not(.no-lift):hover,
.sd-agent-progress:not(.no-lift):hover,
.sd-round-header:not(.no-lift):hover,
.ref-browse-item:not(.no-lift):hover,
.mc-wf-head:not(.no-lift):hover,
.mcp-tool-btn:not(.no-lift):hover,
.modal-tab:not(.no-lift):hover,
.create-team-replan-btn:not(.no-lift):hover {
    transform: translateY(-0.5px);
}
.sd-message:not(.no-lift):active,
.sd-agent-progress:not(.no-lift):active,
.sd-round-header:not(.no-lift):active,
.ref-browse-item:not(.no-lift):active,
.mc-wf-head:not(.no-lift):active,
.mcp-tool-btn:not(.no-lift):active,
.modal-tab:not(.no-lift):active,
.create-team-replan-btn:not(.no-lift):active {
    transform: scale(0.98);
    transition-duration: var(--duration-instant);
}

/* ── Tier 3 (Minimal) — 아이콘 버튼: scale only ── */
.btn-icon:not(.no-lift):active,
.mc-dpick-close:not(.no-lift):active,
.job-drawer-close:not(.no-lift):active,
.create-modal-header button:not(.no-lift):active,
.modal-btn-back:not(.no-lift):active {
    transform: scale(var(--active-scale-btn));
    transition-duration: var(--duration-instant);
}

/* ═══════════════════════════════════════════
   §9  상태 전환 — 에이전트/카드 상태 변화
   ═══════════════════════════════════════════ */

/* 범용 상태 전환 */
.state-transition {
    transition: background-color var(--duration-moderate) var(--easing-in-out),
                box-shadow var(--duration-moderate) var(--easing-in-out);
}

/* 워킹 상태 글로우 (accent 펄스) */
.state-working-glow {
    animation: animGlowPulse 2.5s var(--easing-in-out) infinite;
}

/* 그라데이션 보더 활성 */
.active-gradient-border {
    background-size: 200% 200%;
    animation: animGradientFlow 3s var(--easing-smooth) infinite;
}

/* ── A1: 에이전트 카드/이름/도트 — 상태 전환 보간 ──
   JS가 s-idle → s-working → s-complete 등 클래스를 토글할 때
   color/box-shadow를 부드럽게 보간. --motion-state(300ms ease-in-out) 활용.
   agents.css, components.css에 transition 미선언 → 여기서 단일 권위 선언. */

/* 에이전트 카드 — transition 선언 (단일 권위)
   hover/active transform → components.css 단일 권위로 통합 (T1 충돌 해소) */
.agent-card {
    transition: transform var(--duration-base) var(--easing-spring-gentle),
                box-shadow var(--motion-state),
                background var(--duration-base) var(--easing-out),
                border-color var(--duration-moderate) var(--easing-in-out);
    will-change: transform;
    backface-visibility: hidden;
}
/* hover/active transform → components.css로 통합 완료 (T1) */

/* 에이전트 이름 — 상태별 색상 보간 (working=accent, retrying=amber 등) */
.agent-name {
    transition: color var(--motion-state);
}

/* ── wp/sj/prompt/draft 카드 — hover-lift 단일 권위 (T2~T6 통일) ──
   각 원본 CSS(outputs.css, command.css, pages.css)에서 transform/transition 이관.
   background/box-shadow는 원본에서 관리. agent-card 패턴 동일. */
.wp-card:not(.no-lift),
.sj-card:not(.no-lift),
.prompt-card:not(.no-lift),
.draft-card:not(.no-lift) {
    transition: transform var(--duration-base) var(--easing-spring-gentle),
                box-shadow var(--motion-state),
                background var(--duration-base) var(--easing-out);
    will-change: transform;
    backface-visibility: hidden;
}
.wp-card:not(.no-lift):hover,
.sj-card:not(.no-lift):hover,
.prompt-card:not(.no-lift):hover,
.draft-card:not(.no-lift):hover {
    transform: translateY(var(--hover-lift)) scale(var(--hover-scale));
}
.wp-card:not(.no-lift):active,
.sj-card:not(.no-lift):active,
.prompt-card:not(.no-lift):active,
.draft-card:not(.no-lift):active {
    transform: translateY(0) scale(var(--active-scale));
    transition-duration: var(--duration-instant);
}

/* 상태 도트 — 색상은 smooth 보간, 글로우(box-shadow)는 spring 바운스
   색상에 spring easing 사용 시 cubic-bezier 값이 1.0을 초과(1.56)하여
   중간 색상 플래시가 발생할 수 있으므로 easing-in-out 사용 */
.agent-status-dot {
    transition: background var(--duration-moderate) var(--easing-in-out),
                box-shadow var(--duration-moderate) var(--easing-spring-gentle),
                opacity var(--duration-base) var(--easing-out);
}

/* 상태 뱃지 — 색상은 smooth 보간 (overshoot 방지), transform은 spring 유지 */
.agent-status-badge {
    transition: background-color var(--duration-moderate) var(--easing-in-out),
                color var(--duration-moderate) var(--easing-in-out),
                transform var(--duration-fast) var(--easing-spring-bouncy);
}

/* wp-card-status — 워크프로젝트 상태 보간 (outputs.css) */
.wp-card-status {
    transition: background-color var(--motion-state),
                color var(--motion-state);
}


/* ═══════════════════════════════════════════
   §10  디비전 섹션 접기/펼치기
   ═══════════════════════════════════════════ */

/* 쉐브론 회전: ∨(열림, 0deg) ↔ >(접힘, -90deg) — SVG polyline 기준 */
.division-chevron {
    transform: rotate(0deg);
    will-change: transform;
    transition: transform var(--duration-base) var(--easing-out);
}
.division-section.collapsed .division-chevron {
    transform: rotate(-90deg);
}

/* 접힌 상태 인디케이터 숨김 */
.division-section:not(.collapsed) .division-collapsed-indicator,
.division-section:not(.collapsed) .division-collapsed-error {
    display: none;
}


/* ═══════════════════════════════════════════
   §11  전역 인터랙티브 요소 기본 트랜지션
   ═══════════════════════════════════════════ */

/* 모든 인터랙티브 요소 */
a, button, [role="button"], [role="tab"],
summary, label[for], .clickable {
    transition: color var(--duration-base) var(--easing-out),
                background-color var(--duration-base) var(--easing-out),
                opacity var(--duration-base) var(--easing-out);
}

/* 리스트 아이템 */
[role="listitem"],
[role="option"],
.list-item,
.dropdown-item {
    transition: background-color var(--duration-base) var(--easing-out),
                color var(--duration-base) var(--easing-out);
}


/* ═══════════════════════════════════════════
   §12  입력 필드 포커스
   ═══════════════════════════════════════════ */

input:focus, textarea:focus, select:focus,
.modal-input:focus, .modal-textarea:focus, .modal-select:focus {
    transition: border-color var(--duration-base) var(--easing-out),
                box-shadow var(--duration-moderate) var(--easing-out);
}


/* ═══════════════════════════════════════════
   §13  토글 스위치 — 전 토글 spring easing 통일
   ═══════════════════════════════════════════ */

/* ── 슬라이더 본체 (label/span 기반 토글) ── */
.toggle-slider {
    transition: background var(--duration-base) var(--easing-spring-bouncy),
                border-color var(--duration-base) var(--easing-spring-bouncy),
                box-shadow var(--duration-base) var(--easing-out);
}
.toggle-slider::before {
    transition: transform var(--duration-moderate) var(--easing-spring-bouncy),
                background var(--duration-base) var(--easing-spring-bouncy),
                box-shadow var(--duration-base) var(--easing-out);
}

/* ── 범용 토글 스프링 — thumb(::after) 슬라이드에 spring 오버슈트 ── */
.toggle::after,
.pwa-toggle::after,
.figma-bar-toggle::after {
    transition: transform var(--duration-moderate) var(--easing-spring-bouncy),
                background var(--duration-base) var(--easing-spring-bouncy),
                box-shadow var(--duration-base) var(--easing-out);
    will-change: transform;
}

/* ── 후속 cascade 주의 ──
   figma-bar-toggle (figma.css L26), oc-toggle-row (openclaw.css L28),
   toggle-item-chevron (prompts.css L25) 는 animations.css(L17) 뒤에
   로드되어 여기서 transition을 선언해도 cascade에 의해 무효됨.
   → @REQUEST:frontend 에 spring easing 전환 위임. */


/* ═══════════════════════════════════════════
   §14  프로그레스 바
   ═══════════════════════════════════════════ */

.acct-usage-bar-fill,
.progress-fill,
[role="progressbar"] > * {
    transition: width var(--duration-slow) var(--easing-out);
}


/* ═══════════════════════════════════════════
   §15  뱃지/태그 상태 전환
   ═══════════════════════════════════════════ */

.badge, .tag, .status-badge, .count {
    transition: background-color var(--duration-moderate) var(--easing-in-out),
                color var(--duration-moderate) var(--easing-in-out),
                transform var(--duration-fast) var(--easing-spring-bouncy);
}


/* ═══════════════════════════════════════════
   §16  카드/패널 스크롤 Reveal
   ═══════════════════════════════════════════ */

/* JS IntersectionObserver가 .revealed 추가 */
.reveal-on-scroll {
    opacity: 0;
    transform: translateY(10px);
    transition: opacity var(--duration-moderate) var(--easing-out),
                transform var(--duration-moderate) var(--easing-out);
}
.reveal-on-scroll.revealed {
    opacity: 1;
    transform: none;
}


/* ═══════════════════════════════════════════
   §17  아코디언/접기
   ═══════════════════════════════════════════ */

.collapsible-content {
    overflow: hidden;
    max-height: 0;
    opacity: 0;
    transition: max-height var(--duration-moderate) var(--easing-out),
                opacity var(--duration-base) var(--easing-out),
                padding var(--duration-base) var(--easing-out);
}
.collapsible-content.expanded {
    opacity: 1;
    /* max-height는 JS에서 동적 설정 */
}


/* ═══════════════════════════════════════════
   §18  툴팁
   ═══════════════════════════════════════════ */

/* [data-tooltip]::after 제거 — agents.css, modals.css에서 개별 tooltip이
   자체 opacity/transform/transition을 완전 정의하므로 generic 규칙 불필요.
   scale(0.97) + transform:none이 translateX(-50%) 중앙 정렬과 충돌 (89cf775 참고) */
.tooltip {
    opacity: 0;
    transform: translateY(4px) scale(0.97);
    transition: opacity var(--duration-fast) var(--easing-out),
                transform var(--duration-fast) var(--easing-spring-gentle);
    pointer-events: none;
}
.tooltip.visible {
    opacity: 1;
    transform: none;
}


/* ═══════════════════════════════════════════
   §19  유기적 생동감 — 애플급 마이크로 인터랙션
   ═══════════════════════════════════════════ */

/* ── 탭 패널 진입 — 스프링 fade+slide+블러 ── */
.tab-panel-enter,
.panel-enter {
    animation: animPanelEnter var(--duration-spring) var(--easing-spring-gentle) both;
}

/* ── D1: 탭 전환 시 패널 — 블러→리빌 프리미엄 진입 ── */
.anim-panel-enter {
    animation: animBlurRevealPremium var(--blur-reveal-duration) var(--easing-out) both;
    will-change: filter, opacity, transform;
}

@keyframes animPanelEnter {
    0%   { opacity: 0; transform: translateY(12px) scale(0.98); filter: var(--glass-blur-xs); }
    50%  { opacity: 1; filter: var(--glass-blur-xs); }
    100% { transform: none; filter: blur(0); }
}

/* ── 서브뷰 콘텐츠 전환 — 스프링 진입 ── */
.subview-enter {
    animation: animSubviewEnter 320ms var(--easing-spring-gentle) both;
}
@keyframes animSubviewEnter {
    from { opacity: 0; transform: translateY(6px) scale(0.99); filter: var(--glass-blur-xs); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}


/* ── 버튼/인터랙티브 — 유기적 프레스 ── */
.modal-action:active,
.btn:active,
.action-btn:active {
    transform: scale(0.95);
    transition: transform 60ms var(--easing-spring-bouncy);
}

/* ── 뱃지/카운트 — 팝 등장 ── */
.cmd-sub-badge,
.filter-count {
    transition: transform var(--duration-fast) var(--easing-spring-bouncy),
                opacity var(--duration-fast) var(--easing-out);
}

/* ── 토스트/알림 — 스프링 진입 강화 ── */
@keyframes animToastSpring {
    0%   { opacity: 0; transform: translateY(20px) scale(0.90); }
    40%  { opacity: 1; transform: translateY(-4px) scale(1.03); }
    60%  { transform: translateY(1.5px) scale(0.99); }
    80%  { transform: translateY(-0.5px) scale(1.005); }
    100% { transform: none; }
}
/* 토스트 스프링 진입 유틸리티 클래스 */
.toast-spring-enter {
    animation: animToastSpring var(--duration-spring) var(--easing-spring) both;
    will-change: transform, opacity;
}

/* ── 모달 — gentle spring 등장 (물리 기반 3단계 안착 + 블러 리빌) ── */
@keyframes animModalSpring {
    0%   { opacity: 0; filter: var(--glass-blur-xs); transform: scale(0.85) translateY(16px); }
    40%  { opacity: 0.9; filter: var(--glass-blur-xs); transform: scale(1.03) translateY(-3px); }
    65%  { opacity: 1; transform: scale(0.993) translateY(1px); }
    82%  { transform: scale(1.005) translateY(-0.3px); }
    100% { transform: none; }
}

/* ── 드롭다운/메뉴 — bouncy spring 오픈 ── */
@keyframes animMenuOpen {
    0%   { opacity: 0; transform: scaleY(0.88) translateY(-8px); }
    50%  { opacity: 1; transform: scaleY(1.03) translateY(0); }
    75%  { transform: scaleY(0.995); }
    100% { transform: none; }
}

/* ── 워킹 에이전트 — 부드러운 호흡 (opacity 기반) ── */
@keyframes animAliveGlow {
    0%, 100% { opacity: 1; }
    30%      { opacity: 0.85; }
    60%      { opacity: 0.95; }
}
.agent-card.s-working {
    animation: animAliveGlow 3s var(--easing-in-out) infinite, animPremiumPulse 3s var(--easing-breathe) infinite;
}

/* ── 프로그레스 바 — 유기적 채움 ── */
@keyframes animProgressPulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.85; }
}


/* ═══════════════════════════════════════════
   §19b  패널/드로어 스프링 열기·닫기
   ─────────────────────────────────────────
   GPU 가속 속성(transform, opacity)만 사용.
   60fps 보장. will-change는 열리는 순간만 적용.
   ═══════════════════════════════════════════ */

/* ── 패널 슬라이드 업 (하단→상단) ── */
.panel-slide-up {
    animation: animPanelSlideUp var(--duration-moderate) var(--easing-out) both;
    will-change: transform, opacity;
}
@keyframes animPanelSlideUp {
    0%   { opacity: 0; transform: translateY(16px); }
    60%  { opacity: 1; }
    100% { transform: none; }
}

/* ── 패널 슬라이드 다운 (닫기) ── */
.panel-slide-down {
    animation: animPanelSlideDown var(--duration-fast) var(--easing-in) forwards;
    pointer-events: none;
}
@keyframes animPanelSlideDown {
    from { opacity: 1; transform: none; }
    to   { opacity: 0; transform: translateY(12px); }
}

/* ── 드로어 우측 슬라이드 인 ── */
.drawer-slide-in {
    animation: animDrawerSlideIn var(--duration-moderate) var(--easing-spring-gentle) both;
    will-change: transform, opacity;
}
@keyframes animDrawerSlideIn {
    0%   { opacity: 0; transform: translateX(24px); }
    50%  { opacity: 1; }
    100% { transform: none; }
}

/* ── 드로어 슬라이드 아웃 ── */
.drawer-slide-out {
    animation: animDrawerSlideOut var(--duration-fast) var(--easing-in) forwards;
    pointer-events: none;
}
@keyframes animDrawerSlideOut {
    from { opacity: 1; transform: none; }
    to   { opacity: 0; transform: translateX(24px); }
}

/* ── 모달 스프링 등장 (§19 animModalSpring 활용) ── */
.modal-spring-enter {
    animation: animModalSpring var(--duration-moderate) var(--easing-spring-gentle) both;
    will-change: transform, opacity;
}

/* ── 모달 퇴장 — 빠른 축소 ── */
.modal-spring-exit {
    animation: animModalExit var(--duration-fast) var(--easing-in) forwards;
    pointer-events: none;
}
@keyframes animModalExit {
    from { opacity: 1; transform: none; }
    to   { opacity: 0; transform: scale(0.94) translateY(8px); }
}

/* ── 드롭다운/메뉴 스프링 열기 (§19 animMenuOpen 활용) ── */
.menu-spring-open {
    animation: animMenuOpen var(--duration-base) var(--easing-spring-gentle) both;
    transform-origin: top center;
    will-change: transform, opacity;
}

/* ── 드롭다운 닫기 ── */
.menu-spring-close {
    animation: animMenuClose var(--duration-fast) var(--easing-in) forwards;
    transform-origin: top center;
    pointer-events: none;
}
@keyframes animMenuClose {
    from { opacity: 1; transform: none; }
    to   { opacity: 0; transform: scaleY(0.92) translateY(-6px); }
}


/* ═══════════════════════════════════════════
   §19c  범용 마이크로 인터랙션 강화
   ─────────────────────────────────────────
   전역 인터랙티브 요소에 일관된 :active 피드백 부여.
   transform/opacity만 사용하여 60fps 보장.
   ═══════════════════════════════════════════ */

/* ── Ghost 버튼 — 미세 lift ── */
.btn-ghost:not(.no-lift):hover {
    transform: translateY(-0.5px);
}

/* ── 토글 스위치 클릭 — 미세 스케일 바운스 ── */
.toggle:not(.no-lift):active,
.pwa-toggle:not(.no-lift):active {
    transform: scale(0.96);
    transition-duration: var(--duration-instant);
}

/* ── 태그/뱃지 클릭 — 부드러운 눌림 ── */
.tag:not(.no-lift):active,
.status-badge:not(.no-lift):active {
    transform: scale(0.94);
    transition-duration: var(--duration-instant);
}

/* ── 탭 인디케이터 — 스프링 슬라이드 ── */
.tab-indicator,
.cmd-sub-indicator {
    transition: transform var(--duration-base) var(--easing-spring-gentle),
                width var(--duration-base) var(--easing-spring-gentle);
    will-change: transform, width;
}

/* ── 아코디언 쉐브론 — 스프링 회전 ── */
.accordion-chevron,
.collapsible-chevron {
    transition: transform var(--duration-base) var(--easing-spring-gentle);
    will-change: transform;
}

/* ── 카운트 뱃지 업데이트 — 팝+안착 ── */
@keyframes animCountBadgeUpdate {
    0%   { transform: scale(1); }
    40%  { transform: scale(1.15); }
    70%  { transform: scale(0.95); }
    100% { transform: scale(1); }
}
.count-updated {
    animation: animCountBadgeUpdate 250ms var(--easing-spring-bouncy) both;
}

/* ── 프리미엄 뱃지 업데이트 — 스프링 팝 + 글로우 플래시 + 컬러 모프 ── */
@keyframes animBadgeUpdate {
    0%   { transform: scale(1);    filter: brightness(1); }
    25%  { transform: scale(1.25); filter: brightness(1.4); }
    50%  { transform: scale(0.92); filter: brightness(1.15); }
    70%  { transform: scale(1.06); filter: brightness(1); }
    100% { transform: scale(1);    filter: brightness(1); }
}
.badge-update {
    animation: animBadgeUpdate 350ms var(--easing-spring-bouncy) both;
    will-change: transform, filter;
}

/* ── 유기적 호흡 유틸리티 — 살아있는 느낌의 루프 ── */
.anim-organic-breathe {
    animation: animOrganicBreathe 4s var(--easing-breathe) infinite;
    will-change: transform, opacity;
}

/* ── 스크롤 인디케이터 — 부드러운 페이드 ── */
.scroll-fade-top,
.scroll-fade-bottom {
    transition: opacity var(--duration-base) var(--easing-out);
}


/* ═══════════════════════════════════════════
   §19  Premium Polish — 1000억 프로덕트급 마이크로 인터랙션
   ─────────────────────────────────────────
   Linear/Vercel/Notion 급 시각적 polish.
   드롭다운 트랜지션, 값 변경 팝, 탭 인디케이터,
   리스트 아이템 인터랙션, 스무스 확장/축소.
   ═══════════════════════════════════════════ */

/* ── 드롭다운 열기/닫기 — 기존 keyframes 활용 유틸리티 ── */
.dropdown-animated {
    animation: animDropdownOpen var(--duration-base) var(--easing-out) both;
    transform-origin: top center;
}
.dropdown-animated.closing {
    animation: animDropdownClose var(--duration-fast) var(--easing-in) both;
}

/* ── 값 변경 팝 — 카운트/배지 숫자 변경 시 미세 팝 ── */
@keyframes animValuePop {
    0%   { transform: scale(1); }
    40%  { transform: scale(1.15); }
    100% { transform: scale(1); }
}
.value-pop {
    animation: animValuePop var(--duration-base) var(--easing-spring-bouncy);
}

/* ── 탭 인디케이터 슬라이드 — 활성 탭 하단 바 ── */
@keyframes animTabIndicator {
    from { transform: scaleX(0); opacity: 0; }
    to   { transform: scaleX(1); opacity: 1; }
}
.tab-indicator-animated::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: var(--s-3);
    right: var(--s-3);
    height: 2px;
    background: var(--accent);
    border-radius: var(--radius-s);
    transform-origin: center;
    animation: animTabIndicator var(--duration-base) var(--easing-out) both;
}

/* ── 리스트 아이템 인터랙티브 — Tier 2 호버 + 액티브 ── */
.list-interactive {
    transition: background var(--duration-base) var(--easing-out),
                transform var(--duration-base) var(--easing-spring-gentle);
    cursor: pointer;
}
.list-interactive:hover {
    background: var(--surface-hover);
}
.list-interactive:active {
    transform: scale(0.99);
    transition-duration: var(--duration-instant);
}

/* ── 스무스 확장/축소 — max-height 기반 ── */
.expand-animated {
    overflow: hidden;
    transition: max-height var(--duration-moderate) var(--easing-out),
                opacity var(--duration-moderate) var(--easing-out);
    max-height: 2000px;
    opacity: 1;
}
.expand-animated.collapsed {
    max-height: 0;
    opacity: 0;
}

/* ── 하이라이트 플래시 — 중요 업데이트/변경 알림 ── */
@keyframes animHighlightFlash {
    0%   { background-color: var(--surface-active); }
    100% { background-color: transparent; }
}
.highlight-flash {
    animation: animHighlightFlash 1.5s var(--easing-out) both;
}

/* ── CTA 버튼 글로우 펄스 — 주요 액션 강조 ── */
@keyframes animCtaGlow {
    0%, 100% { box-shadow: 0 0 0 0 var(--surface-active); }
    50%      { box-shadow: 0 0 0 6px transparent; }
}
.cta-glow-pulse {
    animation: animCtaGlow 2.5s var(--easing-in-out) infinite;
}

/* ── 스무스 페이지 전환 — 탭/패널 콘텐츠 전환 ── */
@keyframes animPageEnter {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes animPageExit {
    from { opacity: 1; transform: none; }
    to   { opacity: 0; transform: translateY(-4px); }
}
.page-enter {
    animation: animPageEnter var(--duration-base) var(--easing-out) both;
}
.page-exit {
    animation: animPageExit var(--duration-fast) var(--easing-in) both;
}

/* ── 스무스 높이 전환 — 콘텐츠 높이 변경 시 자연스러운 리사이즈 ── */
.smooth-resize {
    transition: height var(--duration-moderate) var(--easing-out);
    overflow: hidden;
}

/* ── 인풋 포커스 글로우 확산 — 프리미엄 포커스 피드백 ── */
@keyframes animFocusGlowExpand {
    0%   { box-shadow: 0 0 0 0 var(--surface-active); }
    50%  { box-shadow: var(--shadow-step-active), 0 0 16px var(--surface-active); }
    100% { box-shadow: var(--shadow-focus-glow-expand); }
}

/* ── 토글 체크 축하 이펙트 — 스프링 오버슈트 + GPU 가속 (box-shadow→filter) ── */
@keyframes animToggleCelebrate {
    0%   { transform: scale(1);    filter: brightness(1) drop-shadow(0 0 0 transparent); }
    30%  { transform: scale(1.14); filter: brightness(1.25) drop-shadow(0 0 8px var(--accent-glow)); }
    55%  { transform: scale(0.96); filter: brightness(1.08); }
    75%  { transform: scale(1.03); filter: brightness(1); }
    100% { transform: scale(1);    filter: brightness(1) drop-shadow(0 0 0 transparent); }
}
.toggle-celebrate {
    animation: animToggleCelebrate 350ms var(--easing-spring-bouncy) both;
    will-change: transform, filter;
}


/* ═══════════════════════════════════════════
   §19d  프리미엄 콘텐츠 전환 유틸리티
   ─────────────────────────────────────────
   Skeleton→Content, 폼 그룹 Focus, 콘텐츠 리빌
   Linear/Vercel 급 디테일.
   ═══════════════════════════════════════════ */

/* ── Skeleton→Content 스무스 교체 ── */
.content-reveal {
    animation: animContentReveal 400ms var(--easing-out) both;
}
@keyframes animContentReveal {
    0%   { opacity: 0; transform: translateY(4px); filter: var(--glass-blur-xs); }
    60%  { opacity: 1; filter: blur(0); }
    100% { transform: none; }
}

/* ── 폼 그룹 Focus-Within 글로우 — 자식 input 포커스 시 부모 강조 ── */
.form-group-glow {
    transition: box-shadow var(--duration-moderate) var(--easing-out);
    border-radius: var(--radius-s);
}
.form-group-glow:focus-within {
    box-shadow: var(--shadow-ring-dim-xs), 0 0 16px var(--clr-teal-bg-xs);
}

/* ── 스무스 상태 변경 — 뱃지/상태 color+bg 변경 시 부드러운 전환 ── */
.state-transition {
    transition: background-color var(--duration-moderate) var(--easing-out),
                color var(--duration-moderate) var(--easing-out),
                box-shadow var(--duration-moderate) var(--easing-out);
}

/* ── 인터랙티브 링크 밑줄 애니메이션 — 프리미엄 호버 ── */
.link-animated {
    position: relative;
    text-decoration: none;
}
.link-animated::after {
    content: '';
    position: absolute;
    bottom: -1px;
    left: 0;
    width: 100%;
    height: 1px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: right;
    transition: transform var(--duration-base) var(--easing-out);
}
.link-animated:hover::after {
    transform: scaleX(1);
    transform-origin: left;
}


/* ═══════════════════════════════════════════
   §19e  서브뷰 페이드 — subviewFadeIn 정본
   ─────────────────────────────────────────
   dashboard.html 인라인에서 이관. command.js switchCmdSubView()에서 참조.
   스프링 오버슈트로 자연스러운 서브뷰 전환.
   ═══════════════════════════════════════════ */
@keyframes subviewFadeIn {
    0%   { opacity: 0; transform: translateY(6px) scale(0.998); }
    60%  { opacity: 1; transform: translateY(-1px); }
    100% { transform: none; }
}

/* ── 탭 패널 콘텐츠 리빌 — 탭 전환 시 내부 콘텐츠 스태거 등장 ──
   JS에서 탭 전환 후 panel에 .tab-content-reveal 추가 시 직계 자식 순차 등장 */
.tab-content-reveal > * {
    opacity: 0;
    animation: animTabReveal var(--duration-enter) var(--easing-spring-gentle) both;
}
.tab-content-reveal > *:nth-child(1) { animation-delay: 40ms; }
.tab-content-reveal > *:nth-child(2) { animation-delay: 70ms; }
.tab-content-reveal > *:nth-child(3) { animation-delay: 100ms; }
.tab-content-reveal > *:nth-child(4) { animation-delay: 130ms; }
.tab-content-reveal > *:nth-child(5) { animation-delay: 160ms; }
.tab-content-reveal > *:nth-child(6) { animation-delay: 190ms; }


/* ═══════════════════════════════════════════
   §19f  Heroic Entrance — 초기 페이지 로드 순차 등장
   ─────────────────────────────────────────
   페이지 로드 시 topbar→메인 콘텐츠→사이드바 순서로 등장.
   GPU 가속(transform/opacity만). 600ms 이내 완료.
   JS에서 body에 .hero-loaded 추가 시 트리거.
   ═══════════════════════════════════════════ */

/* 히로익 진입 키프레임 — dramatic 극적 등장 (블러+스케일+트랜슬레이트 5단계) */
@keyframes animHeroEnter {
    0%   { opacity: 0; transform: translateY(16px) scale(0.96); filter: var(--glass-blur-xs); }
    30%  { opacity: 0.6; transform: translateY(4px) scale(0.99); filter: var(--glass-blur-xs); }
    60%  { opacity: 1; transform: translateY(-2px) scale(1.008); filter: blur(0); }
    80%  { transform: translateY(0.5px) scale(0.999); }
    100% { transform: none; filter: none; }
}

/* 히로익 대상 — 로드 후 순차 등장 */
.hero-target {
    /* ⚠️ opacity:0 의도적 제거 — .dash-entrance와 동일 (no-JS 안전장치).
       animation fill:both의 backwards가 트리거 시 숨김 처리 */
    will-change: transform, opacity, filter;
}

/* body.hero-loaded 트리거 시 순차 등장 — dramatic 토큰(800ms) 적용 */
.hero-loaded .hero-target {
    animation: animHeroEnter var(--duration-dramatic) var(--easing-out) both;
}

/* 순서별 딜레이 — 극적 캐스케이드 (topbar→콘텐츠→서브 요소, 80ms 간격) */
.hero-loaded .hero-target.hero-1 { animation-delay: 0ms; }
.hero-loaded .hero-target.hero-2 { animation-delay: 80ms; }
.hero-loaded .hero-target.hero-3 { animation-delay: 160ms; }
.hero-loaded .hero-target.hero-4 { animation-delay: 240ms; }
.hero-loaded .hero-target.hero-5 { animation-delay: 320ms; }
.hero-loaded .hero-target.hero-6 { animation-delay: 400ms; }

/* calc 기반 — JS에서 --hero-order를 0,1,2,...로 주입 시 12+ 요소도 대응 */
.hero-loaded .hero-target[style*="--hero-order"] {
    animation-delay: calc(var(--hero-order) * 80ms);
}


/* ═══════════════════════════════════════════
   §19g  D&D 요소별 물리감 트랜지션
   ─────────────────────────────────────────
   실제 D&D 모션은 §28-4 통합 시스템(drag-ghost-lift/
   drag-source-dim/drag-return)이 담당.
   여기서는 요소별 base transition만 정의.
   ═══════════════════════════════════════════ */

/* ── sq-item 전용 — 대기열 순서 변경 D&D 물리감 강화 ── */
.sq-item {
    transition: transform var(--duration-base) var(--easing-spring-gentle),
                opacity var(--duration-fast) var(--easing-out),
                box-shadow var(--duration-base) var(--easing-out);
}
.sq-item.sq-dragging {
    /* opacity/transform → drag-source-dim 클래스가 제어 (dndApplyGhostLift) */
    box-shadow: var(--shadow-drag);
}

/* ── prompt-block 전용 — 프롬프트 블록 D&D 물리감 ── */
.prompt-block-wrapper {
    transition: transform var(--duration-base) var(--easing-spring-gentle),
                opacity var(--duration-fast) var(--easing-out),
                box-shadow var(--duration-base) var(--easing-out);
}
.prompt-block-wrapper.dragging {
    /* opacity/transform → drag-source-dim 클래스가 제어 (dndApplyGhostLift) */
    box-shadow: var(--shadow-drag);
}

/* 프롬프트 블록 드롭존 — 드래그 오버 시 하이라이트 */
.block-dropzone.drag-over {
    background: var(--surface-active);
    outline: 2px dashed var(--accent);
    outline-offset: -2px;
    border-radius: var(--radius-s);
    transition: background var(--duration-fast) var(--easing-out),
                outline-color var(--duration-fast) var(--easing-out);
}

/* ── 큐 D&D — cj-queue-section-item 전용 ── */
.cj-queue-section-item {
    transition: transform var(--duration-base) var(--easing-spring-gentle),
                opacity var(--duration-fast) var(--easing-out),
                box-shadow var(--duration-base) var(--easing-out);
}

/* ── 드래그 오버 인디케이터 — 미세 확장 ── */
.sq-drag-over-top,
.sq-drag-over-bottom {
    transition: transform var(--duration-fast) var(--easing-spring-gentle);
}
.sq-drag-over-top {
    transform: translateY(-2px);
}
.sq-drag-over-bottom {
    transform: translateY(2px);
}


/* ═══════════════════════════════════════════
   §20  접근성 — prefers-reduced-motion
   ═══════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }

    /* 시머 오버레이 완전 비활성화 */
    .hover-shimmer::after,
    .shimmer-overlay::after {
        display: none;
    }

    /* 스켈레톤은 정적 배경만 유지 (시머 없이) */
    .skeleton {
        animation: none;
        background: var(--surface);
    }

    /* skeleton→content 전환도 즉시 표시 */
    .skeleton-exit,
    .skeleton-exit-smooth {
        animation: none !important;
        opacity: 0;
    }
    .content-enter,
    .content-enter-spring,
    .content-enter-up,
    .content-enter-scale,
    .content-reveal,
    .content-enter-stagger > *,
    .content-grid-stagger > *,
    .content-grid-spring > *,
    .content-list-stagger > *,
    .stagger-children > *,
    .stagger-children-calc > * {
        animation: none !important;
        opacity: 1;
        transform: none;
    }

    /* PromptFort 생물형 — reduced motion 시 즉시 표시 */
    .pp-anim-pulse-orb {
        animation: none;
        opacity: 0.8;
    }
    .pp-anim-breathe-glow {
        animation: none;
    }
    .pp-stagger-item {
        animation: none;
        opacity: 1;
        transform: none;
    }
    .pp-stagger-section {
        animation: none;
        opacity: 1;
        transform: none;
    }
    .pp-stagger-cat,
    .pp-stagger-direction,
    .pp-stagger-history,
    .pp-stagger-stat,
    .pp-stagger-improve {
        animation: none;
        opacity: 1;
        transform: none;
    }
    .pp-anim-wave-bar {
        transition: none !important;
    }
    .ripple-host > .ripple {
        animation: none !important;
        opacity: 0;
    }
    .pp-view {
        transition: none !important;
    }
    .pp-view.exit-left,
    .pp-view.exit-right,
    .pp-view.crossfade-exit {
        transition: none !important;
    }
    .pp-nav-icon::after {
        transition: none !important;
    }

    /* §19e 서브뷰/탭 콘텐츠 — reduced motion */
    .tab-content-reveal > * {
        animation: none !important;
        opacity: 1;
        transform: none;
    }

    /* §19f Heroic Entrance — reduced motion */
    .hero-target {
        opacity: 1;
    }
    .hero-loaded .hero-target {
        animation: none !important;
        opacity: 1;
        transform: none;
    }

    /* §19g D&D 요소별 트랜지션 — reduced motion */
    .sq-item.sq-dragging,
    .prompt-block-wrapper.dragging {
        transform: none;
        transition: none !important;
    }

    /* §19 Premium Polish — reduced motion */
    .dropdown-animated,
    .dropdown-animated.closing { animation: none !important; opacity: 1; transform: none; }
    .value-pop { animation: none !important; transform: none; }
    .highlight-flash { animation: none !important; }
    .cta-glow-pulse { animation: none !important; }
    .page-enter, .page-exit { animation: none !important; opacity: 1; transform: none; }
    .expand-animated { transition: none !important; }
    .smooth-resize { transition: none !important; }
    .list-interactive { transition: none !important; }

    /* §27 Premium Polish II — reduced motion */
    .backdrop-blur-enter { transition: none !important; }
    .backdrop-blur-enter.active { backdrop-filter: var(--glass-blur-sm); -webkit-backdrop-filter: var(--glass-blur-sm); opacity: 1; }
    .text-reveal-up > * { animation: none !important; opacity: 1; transform: none; }
    .blur-reveal { animation: none !important; opacity: 1; filter: none; transform: none; }
    .morph-transition { transition: none !important; }
    .card-tilt { transition: none !important; transform: none; }
    .elastic-in { animation: none !important; opacity: 1; transform: none; }
    .state-morph-success,
    .state-morph-error { animation: none !important; }
    .premium-shimmer { animation: none !important; background: var(--surface); }
    .insert-item { animation: none !important; opacity: 1; transform: none; max-height: 2000px; }
    .remove-item { animation: none !important; }
    .check-draw path { animation: none !important; stroke-dashoffset: 0; }
    .notch-enter { animation: none !important; opacity: 1; transform: none; }
    .swipe-hint { animation: none !important; }
}


/* ═══════════════════════════════════════════
   §21  PromptFort 생물형(Organic) 애니메이션
   ─────────────────────────────────────────
   UX 설계서 섹션 4 구현.
   4종: 맥동(Pulse) / 호흡(Breathe) / 물결(Wave) / 탄성(Spring)
   + 6종 Stagger 등장 패턴.
   ═══════════════════════════════════════════ */

/* ── §21-1  맥동(Pulse) 스피너 ──
   로딩 Phase에서 원형 요소가 유기적으로 커졌다 줄어듦.
   1.5s 주기, scale + opacity 복합. */

@keyframes ppPulseOrb {
    0%   { transform: scale(0.85); opacity: 0.4; }
    50%  { transform: scale(1.1);  opacity: 1; }
    100% { transform: scale(0.85); opacity: 0.4; }
}

.pp-anim-pulse-orb {
    animation: ppPulseOrb 1.5s var(--easing-breathe) infinite;
    will-change: transform, opacity;
}


/* ── §21-2  호흡(Breathe) 글로우 ──
   점수 게이지 배경에 accent 색상 발광이 부드럽게 맥동.
   3s 주기, box-shadow opacity 기반. */

@keyframes ppBreatheGlow {
    0%, 100% { box-shadow: 0 0 0 0 var(--accent-transparent); }
    50%      { box-shadow: var(--shadow-breathe-glow-lg); }
}

.pp-anim-breathe-glow {
    animation: ppBreatheGlow 3s var(--easing-breathe) infinite;
    will-change: box-shadow;
}


/* ── §21-3  물결(Wave) 등장 ──
   카테고리 바 채워짐에 spring 오버슈트 이징 적용.
   약간 넘쳤다 안착하는 물결 느낌. */

.pp-anim-wave-bar {
    transition: width var(--duration-slower) var(--easing-spring-gentle);
    will-change: width;
}


/* ── §21-4  탄성(Spring) 카운트업 ──
   JS requestAnimationFrame 기반 — easeOutElastic 커브.
   CSS로는 숫자 카운트업 불가. JS 유틸리티 함수를 제공.
   아래 data attribute로 목표값 전달, JS에서 읽음.

   사용법 (JS):
     ppSpringCountUp(element, targetValue, {
       duration: 800,
       startValue: 0
     });

   CSS는 숫자 표시 요소의 기본 트랜지션만 제공: */

.pp-anim-spring-count {
    display: inline-block;
    will-change: transform;
    transition: transform 200ms var(--easing-spring-gentle);
}

/* 카운트업 완료 시 미세 바운스 (JS에서 .counted 클래스 추가) */
@keyframes ppCountBounce {
    0%   { transform: scale(1); }
    40%  { transform: scale(1.08); }
    70%  { transform: scale(0.97); }
    100% { transform: scale(1); }
}
.pp-anim-spring-count.counted {
    animation: ppCountBounce 300ms var(--easing-spring-bouncy) both;
}


/* ═══════════════════════════════════════════
   §22  PromptFort Stagger 등장 패턴
   ─────────────────────────────────────────
   --pp-stagger-i CSS 변수를 JS에서 주입.
   각 컨텍스트별 딜레이 간격을 CSS 변수로 제어.
   ═══════════════════════════════════════════ */

/* ── 기본 stagger 키프레임 ── */
@keyframes ppStaggerIn {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ── §22-1  진단 결과 섹션 stagger (150ms 간격) ──
   원본 → 게이지 → 넛지 → 카테고리 → 방향 순서.
   JS에서 --pp-stagger-i를 0,1,2,3,4로 설정. */

.pp-stagger-section {
    opacity: 0;
    transform: translateY(12px);
    animation: ppStaggerIn 400ms var(--easing-out) forwards;
    animation-delay: calc(var(--pp-stagger-i, 0) * 150ms);
}

/* ── §22-2  카테고리 바 리스트 stagger (80ms 간격) ──
   5개 차원 바가 순차 등장. */

.pp-stagger-cat {
    opacity: 0;
    transform: translateY(8px);
    animation: ppStaggerIn 350ms var(--easing-out) forwards;
    animation-delay: calc(var(--pp-stagger-i, 0) * 80ms);
}

/* ── §22-3  방향 카드 stagger (100ms 간격) ── */

.pp-stagger-direction {
    opacity: 0;
    transform: translateY(10px);
    animation: ppStaggerIn 350ms var(--easing-out) forwards;
    animation-delay: calc(var(--pp-stagger-i, 0) * 100ms);
}

/* ── §22-4  히스토리 카드 stagger (60ms 간격) ── */

.pp-stagger-history {
    opacity: 0;
    transform: translateY(8px);
    animation: ppStaggerIn 300ms var(--easing-out) forwards;
    animation-delay: calc(var(--pp-stagger-i, 0) * 60ms);
}

/* ── §22-5  통계 카드 stagger (120ms 간격) ── */

.pp-stagger-stat {
    opacity: 0;
    transform: translateY(10px);
    animation: ppStaggerIn 350ms var(--easing-out) forwards;
    animation-delay: calc(var(--pp-stagger-i, 0) * 120ms);
}

/* ── §22-6  개선 결과 섹션 stagger (150ms 간격) ──
   점수변화 → 비교 → 변경사항 → 카테고리 → 액션 순서. */

.pp-stagger-improve {
    opacity: 0;
    transform: translateY(12px);
    animation: ppStaggerIn 400ms var(--easing-out) forwards;
    animation-delay: calc(var(--pp-stagger-i, 0) * 150ms);
}

/* ── §22-7  범용 stagger (커스텀 간격) ──
   --pp-stagger-gap으로 간격 지정 가능. */

.pp-stagger-item {
    opacity: 0;
    transform: translateY(10px);
    animation: ppStaggerIn 350ms var(--easing-out) forwards;
    animation-delay: calc(var(--pp-stagger-i, 0) * var(--pp-stagger-gap, 80ms));
}


/* ═══════════════════════════════════════════
   §23  PromptFort 마이크로 인터랙션
   ═══════════════════════════════════════════ */

/* ── 진단 버튼 클릭 — scale(0.96) 탄성 ── */
.pp-btn-press:active {
    transform: scale(0.96);
    transition: transform 100ms var(--easing-spring-bouncy);
}

/* ── 히스토리 카드 호버 — 미세 lift ── */
.pp-card-hover {
    transition: background-color 150ms var(--easing-out),
                transform 150ms var(--easing-spring-gentle);
}
.pp-card-hover:hover {
    transform: translateY(-1px);
}
.pp-card-hover:active {
    transform: scale(0.98);
    transition-duration: var(--duration-instant);
}

/* ── 방향 카드 선택 — 배경 전환 + 체크 fade-in ── */
.pp-direction-select-anim {
    transition: background-color 150ms var(--easing-out);
}
.pp-direction-select-anim .pp-check-icon {
    opacity: 0;
    transform: scale(0.8);
    transition: opacity 150ms var(--easing-out),
                transform 150ms var(--easing-spring-gentle);
}
.pp-direction-select-anim.selected .pp-check-icon {
    opacity: 1;
    transform: scale(1);
}

/* ── 에러 재시도 아이콘 회전 ── */
@keyframes ppRetryRotate {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}
.pp-anim-retry-spin {
    animation: ppRetryRotate 300ms var(--easing-out) both;
}

/* ═══════════════════════════════════════════
   §RIPPLE  통합 리플 시스템
   ─────────────────────────────────────────
   기존 pp-ripple(§4.6) + ripple-container(§28-6) + ripple-accent(§29) 통합.
   컨테이너: .ripple-host (position:relative + overflow:hidden)
   리플 요소: .ripple (JS가 pointerdown 시 span.ripple 생성)
   색상: --ripple-color(기본) / --ripple-accent(.ripple-host--accent 시)
   키프레임: animRipple 재사용 (scale(0)→scale(2.5), opacity 0.5→0)
   ═══════════════════════════════════════════ */

.ripple-host {
    position: relative;
    overflow: hidden;
}

.ripple-host > .ripple {
    position: absolute;
    border-radius: 50%;
    background: var(--ripple-color);
    transform: scale(0);
    animation: animRipple var(--ripple-duration) var(--easing-out) forwards;
    pointer-events: none;
    will-change: transform, opacity;
}

/* accent 변형 — CTA/강조 버튼 */
.ripple-host--accent > .ripple {
    background: var(--ripple-accent);
}


/* ═══════════════════════════════════════════
   §24  PromptFort SPA 뷰 전환 애니메이션
   ─────────────────────────────────────────
   UX 보충 설계서 §2.2 / §4.8 구현.
   Cross-Fade + 미세 Slide (translateX ±8%, 250ms).
   메인↔히스토리/통계 = 좌우 슬라이드.
   히스토리↔통계 = 크로스페이드(200ms).
   ═══════════════════════════════════════════ */

/* ── 뷰 컨테이너 기본 상태 (숨김) ── */
.pp-view {
    position: absolute;
    inset: 0;
    opacity: 0;
    transform: translateX(8%);
    transition: opacity 250ms var(--easing-out),
                transform 250ms var(--easing-out);
    pointer-events: none;
    will-change: transform, opacity;
}

/* ── 활성 뷰 ── */
.pp-view.active {
    opacity: 1;
    transform: translateX(0);
    pointer-events: auto;
    position: relative;
}

/* ── 퇴장 방향 ── */
.pp-view.exit-left {
    opacity: 0;
    transform: translateX(-8%);
}
.pp-view.exit-right {
    opacity: 0;
    transform: translateX(8%);
}

/* ── 크로스페이드 전용 (히스토리↔통계) ── */
.pp-view.crossfade-exit {
    opacity: 0;
    transform: none;
    transition-duration: 200ms;
}
.pp-view.crossfade-enter {
    transform: none;
    transition-duration: 200ms;
}

/* ── 네비게이션 아이콘 상태 ── */
.pp-nav-icon {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--s-8-5);
    height: var(--s-8-5);
    color: var(--text-sub);
    transition: color 200ms var(--easing-out);
    cursor: pointer;
    background: none;
    border: none;
    padding: 0;
}
.pp-nav-icon:hover {
    color: var(--text-sub);
}
.pp-nav-icon.active {
    color: var(--accent);
}

/* ── 활성 뷰 인디케이터 (아이콘 하단 accent 점) ── */
.pp-nav-icon.active::after {
    content: '';
    position: absolute;
    bottom: var(--s-1);
    left: 50%;
    transform: translateX(-50%) scale(1);
    width: var(--s-1);
    height: var(--s-1);
    border-radius: 50%;
    background: var(--accent);
    opacity: 1;
    transition: opacity 200ms var(--easing-out),
                transform 200ms var(--easing-spring-gentle);
}
.pp-nav-icon::after {
    content: '';
    position: absolute;
    bottom: var(--s-1);
    left: 50%;
    transform: translateX(-50%) scale(0);
    width: var(--s-1);
    height: var(--s-1);
    border-radius: 50%;
    background: var(--accent);
    opacity: 0;
    transition: opacity 200ms var(--easing-out),
                transform 200ms var(--easing-spring-gentle);
}


/* ═══════════════════════════════════════════
   §25  Skeleton → Content 강화 전환
   ─────────────────────────────────────────
   hideSkeleton() 호출 시 skeleton은 fade+scale-out,
   새 콘텐츠는 fade+slide-up stagger 등장.
   크로스페이드 래퍼 없이도 동작하는 단순 패턴.
   ═══════════════════════════════════════════ */

/* skeleton 퇴장 강화 — 페이드+미세 스케일+블러 (180ms: 120ms에서 상향 — 급격한 사라짐 방지) */
.skeleton-exit-smooth {
    animation: animSkeletonExitSmooth 180ms var(--easing-in) forwards;
    pointer-events: none;
}
@keyframes animSkeletonExitSmooth {
    from { opacity: 1; transform: scale(1); filter: blur(0); }
    to   { opacity: 0; transform: scale(0.97); filter: var(--glass-blur-xs); }
}

/* 콘텐츠 등장 강화 — 스프링 기반 slide-up + fade */
.content-enter-spring {
    animation: animContentEnterSpring var(--duration-moderate) var(--easing-spring-gentle) both;
}
@keyframes animContentEnterSpring {
    0%   { opacity: 0; transform: translateY(8px) scale(0.98); }
    60%  { opacity: 1; transform: translateY(-1px) scale(1.002); }
    100% { transform: none; }
}

/* 그리드 카드 순차 등장 — 스프링 기반 강화 stagger
   부모에 .content-grid-spring 추가, JS에서 자식에 --stagger-i 주입 */
.content-grid-spring > * {
    opacity: 0;
    animation: animContentEnterSpring var(--duration-moderate) var(--easing-spring-gentle) forwards;
    animation-delay: calc(var(--stagger-i, 0) * 35ms);
}

/* 리스트 아이템 순차 등장 — 가벼운 slide-right stagger */
.content-list-stagger > * {
    opacity: 0;
    animation: animContentListEnter var(--duration-base) var(--easing-out) forwards;
    animation-delay: calc(var(--stagger-i, 0) * 25ms);
}
@keyframes animContentListEnter {
    from { opacity: 0; transform: translateX(-6px); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}


/* ═══════════════════════════════════════════
   §26  Extended Hover-Lift Wave A — 적용률 확대
   ─────────────────────────────────────────
   §8b에 이어 추가 대상.
   OV 검증 완료: 아래 선택자들의 기존 :hover 규칙은
   background/color/border/opacity만 변경하고 transform 미사용.
   ═══════════════════════════════════════════ */

/* ── Tier 1 (Strong) — 카드급 요소 ── */
.add-agent-card:not(.no-lift),
.mc-wf-v2:not(.no-lift),
.ref-item-card:not(.no-lift),
.ref-analysis-history-item:not(.no-lift),
.division-section:not(.no-lift),
.rq-card:not(.no-lift),
.welcome-card:not(.no-lift) {
    transition: transform 250ms var(--easing-spring-gentle),
                box-shadow 250ms var(--easing-out),
                background 200ms var(--easing-out),
                border-color 200ms var(--easing-out),
                color 200ms var(--easing-out);
    will-change: transform;
    backface-visibility: hidden;
}
.add-agent-card:not(.no-lift):hover,
.mc-wf-v2:not(.no-lift):hover,
.ref-item-card:not(.no-lift):hover,
.ref-analysis-history-item:not(.no-lift):hover,
.division-section:not(.no-lift):hover,
.rq-card:not(.no-lift):hover,
.welcome-card:not(.no-lift):hover {
    transform: translateY(var(--hover-lift-sm)) scale(1.003);
    box-shadow: var(--shadow-float);
}
.add-agent-card:not(.no-lift):active,
.mc-wf-v2:not(.no-lift):active,
.ref-item-card:not(.no-lift):active,
.ref-analysis-history-item:not(.no-lift):active,
.division-section:not(.no-lift):active,
.rq-card:not(.no-lift):active,
.welcome-card:not(.no-lift):active {
    transform: translateY(0) scale(var(--active-scale));
    transition-duration: var(--duration-instant);
    box-shadow: none;
}

/* ── Tier 2 (Subtle) — 리스트/행 아이템 ── */
.ref-list-item:not(.no-lift),
.mc-wf-step:not(.no-lift),
.mc-par-item:not(.no-lift),
.mc-sess-tab:not(.no-lift),
.idle-agents-toggle:not(.no-lift),
.division-header.clickable:not(.no-lift),
.mc-regen-chip:not(.no-lift),
.auth-setup-card-header:not(.no-lift) {
    transition: transform var(--duration-base) var(--easing-spring-gentle),
                background 200ms var(--easing-out);
    will-change: transform;
}
.ref-list-item:not(.no-lift):hover,
.mc-wf-step:not(.no-lift):hover,
.mc-par-item:not(.no-lift):hover,
.mc-sess-tab:not(.no-lift):hover,
.idle-agents-toggle:not(.no-lift):hover,
.division-header.clickable:not(.no-lift):hover,
.mc-regen-chip:not(.no-lift):hover,
.auth-setup-card-header:not(.no-lift):hover {
    transform: translateY(-0.5px);
}
.ref-list-item:not(.no-lift):active,
.mc-wf-step:not(.no-lift):active,
.mc-par-item:not(.no-lift):active,
.mc-sess-tab:not(.no-lift):active,
.idle-agents-toggle:not(.no-lift):active,
.division-header.clickable:not(.no-lift):active,
.mc-regen-chip:not(.no-lift):active,
.auth-setup-card-header:not(.no-lift):active {
    transform: scale(0.98);
    transition-duration: var(--duration-instant);
}

/* ── Tier 3 (Micro) — 폼 버튼, 피드백 메시지 ── */
.auth-setup-save-btn {
    transition: background var(--duration-fast) var(--easing-out);
}
.auth-setup-save-btn:active {
    transition-duration: var(--duration-instant);
}
.auth-setup-feedback {
    transition: opacity var(--duration-fast) var(--easing-out);
}


/* ═══════════════════════════════════════════
   §26b  Extended Hover-Lift Wave B — 적용률 확대 2차
   ─────────────────────────────────────────
   §26에 이어 추가 대상: agent-detail, command, pages,
   outputs, factory, openclaw, plans, ideas, vrt 요소.
   OV 검증 완료: 모든 선택자의 기존 :hover 규칙은
   background/color/border/opacity만 변경하고 transform 미사용.
   ═══════════════════════════════════════════ */

/* ── Tier 1 (Strong) — 카드급 요소: hover-lift-sm + shadow ── */
.node-item:not(.no-lift),
.ad-toggle-item:not(.no-lift),
.ad-thinking-step:not(.no-lift),
.ad-version-item:not(.no-lift),
.ad-skill-item-full:not(.no-lift),
.ad-ctx-card-v2:not(.no-lift),
.ad-file-item:not(.no-lift),
.meta-preset-badge:not(.no-lift),
.meta-preset-detail:not(.no-lift),
.comm-bubble:not(.no-lift),
.chat-example-btn:not(.no-lift),
.welcome-step:not(.no-lift),
.summary-stat:not(.no-lift),
.ov-file-item:not(.no-lift),
.factory-template-card:not(.no-lift),
.factory-history-card:not(.no-lift),
.oc-agent-card:not(.no-lift),
.oc-channel-card:not(.no-lift) {
    transition: transform 250ms var(--easing-spring-gentle),
                box-shadow 250ms var(--easing-out),
                background 200ms var(--easing-out),
                border-color 200ms var(--easing-out),
                color 200ms var(--easing-out);
    will-change: transform;
    backface-visibility: hidden;
}
.node-item:not(.no-lift):hover,
.ad-toggle-item:not(.no-lift):hover,
.ad-thinking-step:not(.no-lift):hover,
.ad-version-item:not(.no-lift):hover,
.ad-skill-item-full:not(.no-lift):hover,
.ad-ctx-card-v2:not(.no-lift):hover,
.ad-file-item:not(.no-lift):hover,
.meta-preset-badge:not(.no-lift):hover,
.meta-preset-detail:not(.no-lift):hover,
.comm-bubble:not(.no-lift):hover,
.chat-example-btn:not(.no-lift):hover,
.welcome-step:not(.no-lift):hover,
.summary-stat:not(.no-lift):hover,
.ov-file-item:not(.no-lift):hover,
.factory-template-card:not(.no-lift):hover,
.factory-history-card:not(.no-lift):hover,
.oc-agent-card:not(.no-lift):hover,
.oc-channel-card:not(.no-lift):hover {
    transform: translateY(var(--hover-lift-sm)) scale(1.003);
    box-shadow: var(--shadow-float);
}
.node-item:not(.no-lift):active,
.ad-toggle-item:not(.no-lift):active,
.ad-thinking-step:not(.no-lift):active,
.ad-version-item:not(.no-lift):active,
.ad-skill-item-full:not(.no-lift):active,
.ad-ctx-card-v2:not(.no-lift):active,
.ad-file-item:not(.no-lift):active,
.meta-preset-badge:not(.no-lift):active,
.meta-preset-detail:not(.no-lift):active,
.comm-bubble:not(.no-lift):active,
.chat-example-btn:not(.no-lift):active,
.welcome-step:not(.no-lift):active,
.summary-stat:not(.no-lift):active,
.ov-file-item:not(.no-lift):active,
/* wp-card → 상단 T2~T6 통일 섹션으로 이관 */
.factory-template-card:not(.no-lift):active,
.factory-history-card:not(.no-lift):active,
.oc-agent-card:not(.no-lift):active,
.oc-channel-card:not(.no-lift):active {
    transform: translateY(0) scale(var(--active-scale));
    transition-duration: var(--duration-instant);
    box-shadow: none;
}

/* ── Tier 2 (Subtle) — 탭/리스트/칩: 미세 lift ── */
.ad-tab:not(.no-lift),
.ad-filter-btn:not(.no-lift),
.ad-prompt-toc-item:not(.no-lift),
.ad-prompt-section-head:not(.no-lift),
.ad-tab-more-item:not(.no-lift),
.ad-breadcrumb-item:not(.no-lift),
.ad-collab-chip:not(.no-lift),
.content-chip:not(.no-lift),
.overview-graph-toggle:not(.no-lift),
.draft-tab:not(.no-lift),
.draft-panel-toggle:not(.no-lift),
.wp-view-btn:not(.no-lift),
.job-link-toggle:not(.no-lift),
.factory-tab:not(.no-lift),
.factory-domain-chip:not(.no-lift),
.factory-scale-btn:not(.no-lift),
.factory-squad-header:not(.no-lift),
.oc-subtab-btn:not(.no-lift),
.pp-chip:not(.no-lift),
.plan-mode-toggle:not(.no-lift),
.plan-card-btn:not(.no-lift),
.plan-fmt-btn:not(.no-lift),
.ideas-card-action:not(.no-lift),
.ideas-cat-btn:not(.no-lift) {
    transition: transform var(--duration-base) var(--easing-spring-gentle),
                background 200ms var(--easing-out),
                color 150ms var(--easing-out);
    will-change: transform;
}
.ad-tab:not(.no-lift):hover,
.ad-filter-btn:not(.no-lift):hover,
.ad-prompt-toc-item:not(.no-lift):hover,
.ad-prompt-section-head:not(.no-lift):hover,
.ad-tab-more-item:not(.no-lift):hover,
.ad-breadcrumb-item:not(.no-lift):hover,
.ad-collab-chip:not(.no-lift):hover,
.content-chip:not(.no-lift):hover,
.overview-graph-toggle:not(.no-lift):hover,
.draft-tab:not(.no-lift):hover,
.draft-panel-toggle:not(.no-lift):hover,
.wp-view-btn:not(.no-lift):hover,
.job-link-toggle:not(.no-lift):hover,
.factory-tab:not(.no-lift):hover,
.factory-domain-chip:not(.no-lift):hover,
.factory-scale-btn:not(.no-lift):hover,
.factory-squad-header:not(.no-lift):hover,
.oc-subtab-btn:not(.no-lift):hover,
.pp-chip:not(.no-lift):hover,
.plan-mode-toggle:not(.no-lift):hover,
.plan-card-btn:not(.no-lift):hover,
.plan-fmt-btn:not(.no-lift):hover,
.ideas-card-action:not(.no-lift):hover,
.ideas-cat-btn:not(.no-lift):hover {
    transform: translateY(-0.5px);
}
.ad-tab:not(.no-lift):active,
.ad-filter-btn:not(.no-lift):active,
.ad-prompt-toc-item:not(.no-lift):active,
.ad-prompt-section-head:not(.no-lift):active,
.ad-tab-more-item:not(.no-lift):active,
.ad-breadcrumb-item:not(.no-lift):active,
.ad-collab-chip:not(.no-lift):active,
.content-chip:not(.no-lift):active,
.overview-graph-toggle:not(.no-lift):active,
.draft-tab:not(.no-lift):active,
.draft-panel-toggle:not(.no-lift):active,
.wp-view-btn:not(.no-lift):active,
.job-link-toggle:not(.no-lift):active,
.factory-tab:not(.no-lift):active,
.factory-domain-chip:not(.no-lift):active,
.factory-scale-btn:not(.no-lift):active,
.factory-squad-header:not(.no-lift):active,
.oc-subtab-btn:not(.no-lift):active,
.pp-chip:not(.no-lift):active,
.plan-mode-toggle:not(.no-lift):active,
.plan-card-btn:not(.no-lift):active,
.plan-fmt-btn:not(.no-lift):active,
.ideas-card-action:not(.no-lift):active,
.ideas-cat-btn:not(.no-lift):active {
    transform: scale(0.98);
    transition-duration: var(--duration-instant);
}

/* ── Tier 3 (Micro) — 액션 버튼: active scale only ── */
.status-restart-btn:not(.no-lift):active,
.deploy-btn:not(.no-lift):active,
.ideas-btn-primary:not(.no-lift):active,
.ideas-btn-secondary:not(.no-lift):active,
.factory-btn-primary:not(.no-lift):active,
.factory-btn-secondary:not(.no-lift):active,
.factory-btn-ghost:not(.no-lift):active,
.factory-btn-danger:not(.no-lift):active,
.ad-btn-primary:not(.no-lift):active,
.ad-btn-secondary:not(.no-lift):active,
.ad-btn-danger:not(.no-lift):active,
.sd-footer-btn:not(.no-lift):active,
.mc-wf-start-btn:not(.no-lift):active,
.mc-par-proceed-btn:not(.no-lift):active,
.mc-step-start-btn:not(.no-lift):active,
.mc-wf-quick-btn:not(.no-lift):active,
.plan-editor-save:not(.no-lift):active,
.plan-editor-implement:not(.no-lift):active {
    transform: scale(var(--active-scale-btn));
    transition-duration: var(--duration-instant);
}

/* ── Spring 업그레이드: agent-detail 기존 non-spring hover → spring ── */
.ad-output-item:not(.no-lift),
.ad-job-item:not(.no-lift),
.ad-stat-card:not(.no-lift) {
    transition: transform 250ms var(--easing-spring-gentle),
                background 200ms var(--easing-out),
                box-shadow 250ms var(--easing-out);
    will-change: transform;
    backface-visibility: hidden;
}


/* ═══════════════════════════════════════════
   §10c  Spring Hover Transition — Wave 3
   ─────────────────────────────────────────
   기존 CSS에서 var(--motion-hover)/var(--motion-hover) 기반
   비-spring 트랜지션으로 hover transform하는 요소에
   spring easing 적용. :not(.no-lift) specificity 부스트.
   OV 검증: 각 요소의 원본 transition 확인 완료.
   ═══════════════════════════════════════════ */

/* ── Tier 1 — 카드/리스트 아이템: transform spring + 나머지 easing-out ── */
/* prompt-card → 상단 T2~T6 통일 섹션으로 이관 */
.output-file:not(.no-lift),
.solo-gen-card:not(.no-lift),
.git-branch-item:not(.no-lift),
.job-tl-item:not(.no-lift),
.draft-option:not(.no-lift),
.pp-direction-card:not(.no-lift) {
    transition: transform 250ms var(--easing-spring-gentle),
                background 200ms var(--easing-out),
                box-shadow 250ms var(--easing-out),
                border-color 200ms var(--easing-out);
    will-change: transform;
}
.output-file:not(.no-lift):hover,
.solo-gen-card:not(.no-lift):hover,
.git-branch-item:not(.no-lift):hover,
.job-tl-item:not(.no-lift):hover,
.draft-option:not(.no-lift):hover,
.pp-direction-card:not(.no-lift):hover {
    transform: translateY(var(--hover-lift-sm)) scale(1.003);
    box-shadow: var(--shadow-float);
}
.output-file:not(.no-lift):active,
.solo-gen-card:not(.no-lift):active,
.git-branch-item:not(.no-lift):active,
.job-tl-item:not(.no-lift):active,
.draft-option:not(.no-lift):active,
.pp-direction-card:not(.no-lift):active {
    transform: translateY(0) scale(var(--active-scale));
    transition-duration: var(--duration-instant);
}

/* ── Tier 2 — 버튼/칩: transform spring + 색상 기본 ease ── */
.topbar-job-chip:not(.no-lift),
.gpt-example-btn:not(.no-lift),
.owui-example-btn:not(.no-lift),
.research-btn:not(.no-lift),
.draft-select-btn:not(.no-lift),
.config-chip:not(.no-lift),
.chip:not(.no-lift) {
    transition: transform var(--duration-base) var(--easing-spring-gentle),
                background 150ms var(--easing-out),
                color 150ms var(--easing-out),
                box-shadow var(--duration-base) var(--easing-out);
    will-change: transform;
}
.topbar-job-chip:not(.no-lift):active,
.gpt-example-btn:not(.no-lift):active,
.owui-example-btn:not(.no-lift):active,
.research-btn:not(.no-lift):active,
.draft-select-btn:not(.no-lift):active,
.config-chip:not(.no-lift):active,
.chip:not(.no-lift):active {
    transform: scale(var(--active-scale-btn));
    transition-duration: var(--duration-instant);
}


/* ══════════════════════════════════════════════════════════
   §23  패널 전환 유틸리티 — 탭/뷰 전환 시 사용
   ══════════════════════════════════════════════════════════ */

/* 패널 fade-slide 진입 (왼→오) */
.panel-fade-in {
    animation: animPanelFadeIn var(--duration-moderate) var(--easing-out) both;
}
@keyframes animPanelFadeIn {
    from { opacity: 0; transform: translateX(8px); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}

/* 패널 fade-slide 퇴장 (→왼) */
.panel-fade-out {
    animation: animPanelFadeOut var(--duration-fast) var(--easing-in) both;
}
@keyframes animPanelFadeOut {
    from { opacity: 1; transform: none; }
    to   { opacity: 0; transform: translateX(-8px); }
}

/* 부드러운 높이 전환 — max-height 기반 */
.height-transition {
    overflow: hidden;
    transition: max-height var(--duration-moderate) var(--easing-out),
                opacity var(--duration-base) var(--easing-out);
}
.height-transition.collapsed { max-height: 0; opacity: 0; }
.height-transition.expanded { opacity: 1; }


/* ══════════════════════════════════════════════════════════
   §24  Interactive Glow — 카드/요소 호버 시 accent glow
   ══════════════════════════════════════════════════════════ */

/* 카드 호버 시 미묘한 accent glow halo */
.glow-on-hover {
    position: relative;
}
.glow-on-hover::before {
    content: '';
    position: absolute;
    inset: -1px;
    border-radius: inherit;
    background: radial-gradient(ellipse at center, var(--surface-active) 0%, transparent 70%);
    opacity: 0;
    transition: opacity var(--motion-hover);
    pointer-events: none;
    z-index: 0;
}
.glow-on-hover:hover::before {
    opacity: 1;
}

/* 포커스 시 accent ring glow */
.focus-glow:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    box-shadow: var(--shadow-focus-ring), 0 0 16px var(--clr-teal-bg-lg);
}

/* 프레스 피드백 — 누름 + 릴리즈 스프링 */
.press-feedback {
    transition: transform var(--duration-base) var(--ease-spring);
    will-change: transform;
}
.press-feedback:active {
    transform: scale(var(--active-scale));
    transition-duration: var(--duration-instant);
}


/* ═══════════════════════════════════════════
   §27  Premium Polish II — 1000억 프로덕트급 강화
   ─────────────────────────────────────────
   Linear/Vercel/Notion이 사용하는 프리미엄 패턴.
   GPU 가속 속성만 사용. 접근성 §20에서 일괄 대응.
   ═══════════════════════════════════════════ */

/* ── §27-1  Backdrop Blur 트랜지션 — 모달/오버레이 진입 시 배경 블러 ── */
.backdrop-blur-enter {
    backdrop-filter: blur(0);
    -webkit-backdrop-filter: blur(0);
    transition: backdrop-filter var(--duration-moderate) var(--easing-out),
                -webkit-backdrop-filter var(--duration-moderate) var(--easing-out),
                opacity var(--duration-moderate) var(--easing-out);
    opacity: 0;
}
.backdrop-blur-enter.active {
    backdrop-filter: var(--glass-blur-sm);
    -webkit-backdrop-filter: var(--glass-blur-sm);
    opacity: 1;
}

/* ── §27-2  텍스트 마스크 리빌 — 제목/통계 숫자의 프리미엄 등장 ── */
@keyframes animTextRevealUp {
    from { opacity: 0; transform: translateY(100%); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}
.text-reveal-up {
    overflow: hidden;
    display: inline-block;
}
.text-reveal-up > * {
    display: inline-block;
    animation: animTextRevealUp var(--duration-moderate) var(--easing-out) both;
}

/* ── §27-3  블러 리빌 — 콘텐츠가 포커스로 선명해지는 효과 + Y축 이동 ── */
@keyframes animBlurReveal {
    0%   { opacity: 0; filter: blur(var(--blur-reveal-from)); transform: translateY(var(--blur-reveal-y)) scale(0.98); }
    40%  { opacity: 1; filter: var(--glass-blur-xs); transform: translateY(2px) scale(0.995); }
    100% { filter: blur(0); transform: none; }
}
.blur-reveal {
    animation: animBlurReveal var(--blur-reveal-duration) var(--easing-out) both;
    will-change: filter, opacity, transform;
}

/* ── §27-4  모프 트랜지션 — 상태 변경 시 부드러운 형태 변환 ── */
.morph-transition {
    transition: border-radius var(--duration-moderate) var(--easing-spring-gentle),
                transform var(--duration-moderate) var(--easing-spring-gentle),
                opacity var(--duration-base) var(--easing-out);
    will-change: transform, border-radius;
}

/* ── §27-5  카드 3D 틸트 — 마우스 위치 기반 미세 회전 (JS에서 --tilt-x, --tilt-y 주입) ── */
.card-tilt {
    transform: perspective(600px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg));
    transition: transform var(--duration-base) var(--easing-out);
    will-change: transform;
}
.card-tilt:hover {
    transition-duration: 60ms;
}

/* ── §27-6  글로우 트레일 — 마우스 추종 빛 효과 (JS에서 --glow-x, --glow-y 주입) ── */
.glow-trail {
    position: relative;
    overflow: hidden;
}
.glow-trail::before {
    content: '';
    position: absolute;
    width: var(--card-min-sm);
    height: var(--card-min-sm);
    border-radius: 50%;
    background: radial-gradient(circle, var(--surface-active) 0%, transparent 70%);
    transform: translate(
        calc(var(--glow-x, 50%) - 100px),
        calc(var(--glow-y, 50%) - 100px)
    );
    opacity: 0;
    transition: opacity var(--duration-base) var(--easing-out);
    pointer-events: none;
    z-index: 0;
}
.glow-trail:hover::before {
    opacity: 1;
}

/* ── §27-7  스무스 카운터 — CSS @property 기반 애니메이션 가능 숫자 ── */
@property --counter-value {
    syntax: '<integer>';
    initial-value: 0;
    inherits: false;
}
.counter-animate {
    transition: --counter-value var(--duration-slow) var(--easing-out);
    counter-reset: value var(--counter-value);
}
.counter-animate::after {
    content: counter(value);
}

/* ── §27-8  엘라스틱 등장 — 바운스 오버슈트가 있는 프리미엄 등장 ── */
@keyframes animElasticIn {
    0%   { opacity: 0; transform: scale(0.7); }
    45%  { transform: scale(1.06); }
    65%  { transform: scale(0.97); }
    82%  { transform: scale(1.02); }
    100% { opacity: 1; transform: none; }
}
.elastic-in {
    animation: animElasticIn 500ms var(--easing-smooth) both;
}

/* ── §27-9  스테이트 모프 — 성공/에러/워킹 상태 변환 시 부드러운 색상+글로우 ── */
@keyframes animStateMorphSuccess {
    0%   { box-shadow: 0 0 0 0 var(--accent-transparent); }
    50%  { box-shadow: var(--shadow-state-morph-success); }
    100% { box-shadow: 0 0 0 0 var(--accent-transparent); }
}
@keyframes animStateMorphError {
    0%   { box-shadow: 0 0 0 0 var(--clr-error-transparent); }
    50%  { box-shadow: var(--shadow-state-morph-error); }
    100% { box-shadow: 0 0 0 0 var(--clr-error-transparent); }
}
.state-morph-success {
    animation: animStateMorphSuccess var(--duration-slower) var(--easing-out) both;
}
.state-morph-error {
    animation: animStateMorphError var(--duration-slower) var(--easing-out) both;
}

/* ── §27-10  인피니트 시머 — 프리미엄 로딩 그래디언트 (기존 skeleton보다 정교) ── */
@keyframes animPremiumShimmer {
    0%   { background-position: -200% 0; }
    100% { background-position: 200% 0; }
}
.premium-shimmer {
    background: linear-gradient(
        105deg,
        var(--surface) 0%,
        var(--surface) 35%,
        var(--surface-w5) 42%,
        var(--surface-w8) 48%,
        var(--surface-w5) 54%,
        var(--surface) 65%,
        var(--surface) 100%
    );
    background-size: 300% 100%;
    animation: animPremiumShimmer 2s linear infinite;
}

/* ── §27-11  슬라이드 업 페이드 — 리스트 아이템 삽입 시 부드러운 등장 ── */
@keyframes animInsertItem {
    0%   { opacity: 0; transform: translateY(12px) scale(0.97); max-height: 0; }
    50%  { max-height: var(--card-min-sm); }
    100% { opacity: 1; transform: none; max-height: var(--card-min-sm); }
}
.insert-item {
    animation: animInsertItem var(--duration-moderate) var(--easing-out) both;
    overflow: hidden;
}

/* ── §27-12  삭제 아이템 퇴장 — 리스트에서 아이템 제거 시 ── */
@keyframes animRemoveItem {
    0%   { opacity: 1; transform: none; max-height: var(--card-min-sm); }
    40%  { opacity: 0; transform: translateX(16px) scale(0.97); }
    100% { opacity: 0; max-height: 0; transform: translateX(16px) scale(0.97); }
}
.remove-item {
    animation: animRemoveItem var(--duration-moderate) var(--easing-in) forwards;
    overflow: hidden;
    pointer-events: none;
}

/* ── §27-13  성공 체크마크 — 스프링 오버슈트 draw + 스케일 펀치 ── */
@keyframes animCheckDraw {
    0%   { stroke-dashoffset: 24; opacity: 0; }
    20%  { opacity: 1; }
    70%  { stroke-dashoffset: -2; }
    100% { stroke-dashoffset: 0; }
}
@keyframes animCheckPunch {
    0%   { transform: scale(0.8); opacity: 0; }
    50%  { transform: scale(1.15); opacity: 1; }
    75%  { transform: scale(0.95); }
    100% { transform: scale(1); }
}
.check-draw {
    animation: animCheckPunch 400ms var(--easing-spring-bouncy) both;
    will-change: transform;
}
.check-draw path {
    stroke-dasharray: 24;
    stroke-dashoffset: 24;
    animation: animCheckDraw 350ms var(--easing-out) 80ms forwards;
}

/* ── §27-14  Notch 진입 — 상단 알림 바가 아래로 내려오는 슬라이드 ── */
@keyframes animNotchEnter {
    0%   { opacity: 0; transform: translateY(-100%) scaleX(0.8); }
    60%  { opacity: 1; transform: translateY(2px) scaleX(1.01); }
    100% { transform: none; }
}
.notch-enter {
    animation: animNotchEnter 350ms var(--easing-spring-elastic) both;
    transform-origin: top center;
}

/* ── §27-15  스와이프 힌트 — 좌우 스와이프 가능 표시 ── */
@keyframes animSwipeHint {
    0%, 100% { transform: translateX(0); }
    25%      { transform: translateX(-4px); }
    75%      { transform: translateX(4px); }
}
.swipe-hint {
    animation: animSwipeHint 1.5s var(--easing-in-out) 2;
    will-change: transform;
}

/* ── §27-16  칩 도트 pulse-glow — topbar job chip 상태 도트 ── */
@keyframes cj-pulse-glow {
    0%, 100% { opacity: 1; transform: scale(1); box-shadow: 0 0 0 0 currentColor; }
    50%      { opacity: .7; transform: scale(1.35); box-shadow: 0 0 6px 2px currentColor; }
}

/* ── §27-17  상태 아이콘 스핀 — 배치 진행 pill 아이콘 ── */
@keyframes statusIconSpin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}


/* ═══════════════════════════════════════════
   §28  프리미엄 마이크로 인터랙션 v2
   ─────────────────────────────────────────
   1000억 프로덕트급 UI polish.
   Linear/Vercel/Notion 수준 디테일.
   ═══════════════════════════════════════════ */

/* ── §28-1  카드 호버 글래스 라이트 — 마우스 위치 기반 빛 반사
   JS에서 mousemove 시 --mx, --my CSS 변수를 설정하면
   radial-gradient가 마우스 위치를 따라 이동. 프리미엄 인터랙션. ── */
.card-light-follow {
    position: relative;
    overflow: hidden;
}
.card-light-follow::before {
    content: '';
    position: absolute;
    inset: 0;
    background: radial-gradient(
        300px circle at var(--mx, 50%) var(--my, 50%),
        var(--surface-active) 0%,
        transparent 70%
    );
    opacity: 0;
    transition: opacity var(--duration-base) var(--easing-out);
    pointer-events: none;
    border-radius: inherit;
    z-index: 1;
}
.card-light-follow:hover::before {
    opacity: 1;
}

/* ── §28-2  뱃지 상태 전환 모프 — 색상+크기 동시 보간 ── */
@keyframes animBadgeMorph {
    0%   { transform: scale(0.85); opacity: 0.5; filter: var(--glass-blur-xs); }
    50%  { transform: scale(1.08); filter: blur(0); }
    100% { transform: scale(1); opacity: 1; }
}
.badge-morph {
    animation: animBadgeMorph var(--duration-base) var(--easing-spring-bouncy) both;
}

/* ── §28-3  스크롤 기반 등장 — Intersection Observer 연동
   JS에서 IntersectionObserver가 .scroll-reveal에 .revealed 추가. ── */
.scroll-reveal {
    opacity: 0;
    transform: translateY(var(--scroll-reveal-distance));
    transition: opacity var(--duration-moderate) var(--easing-out),
                transform var(--duration-spring) var(--easing-spring-gentle);
    transition-delay: calc(var(--stagger-i, 0) * var(--scroll-stagger-gap, 50ms));
    will-change: opacity, transform;
}
.scroll-reveal.revealed {
    opacity: 1;
    transform: none;
}

/* ── §28-4  드래그 — D&D 통합 모션 시스템 ── */

/* 드래그 고스트 리프트 — dragstart 시 원본에 적용하여 브라우저 고스트에 반영
   HTML5 dragImage는 캡처 시점 스타일만 반영 → dragstart에서 즉시 적용,
   requestAnimationFrame에서 제거 후 .drag-source-dim 전환 */
.drag-ghost-lift {
    transform: scale(1.04) rotate(0.8deg);
    box-shadow: var(--shadow-lg), var(--shadow-glow-dim-md);
    opacity: 0.95;
    will-change: transform;
    backface-visibility: hidden;
}

/* 드래그 소스 — 원본 위치에 남는 자리표시자 (고스트 캡처 후 전환)
   transform에 spring easing 적용하여 물리적 무게감 부여 (§35-5 통합) */
.drag-source-dim {
    opacity: 0.35;
    transform: scale(0.97);
    transition: opacity var(--duration-fast) var(--easing-out),
                transform var(--duration-base) var(--easing-spring-gentle);
    will-change: opacity, transform;
}

/* 드래그 복귀 — dragend 시 spring bounce 복귀 (§35-6 통합)
   transition 대신 animation으로 다단 바운스 물리감 구현 */
@keyframes dragReturnBounce {
    0%   { opacity: 0.35; transform: scale(0.97); }
    50%  { opacity: 1;    transform: scale(1.02); }
    75%  { transform: scale(0.99); }
    100% { opacity: 1;    transform: none; }
}
.drag-return {
    animation: dragReturnBounce 280ms var(--easing-spring-gentle) both;
    will-change: opacity, transform;
    backface-visibility: hidden;
}

/* 터치 드래그 클론 — 모바일 long-press 시 플로팅 클론 보강 */
.drag-floating {
    box-shadow: var(--shadow-lg), var(--shadow-glow-dim-md);
    transform: scale(1.04) rotate(0.8deg);
    opacity: 0.92;
    z-index: var(--z-modal);
    will-change: transform;
    backface-visibility: hidden;
    transition: box-shadow var(--duration-fast) var(--easing-out),
                transform var(--duration-fast) var(--easing-spring-gentle);
}

/* ── §28-5  프리미엄 모달 퇴장 — 반대 방향 spring ── */
@keyframes animModalExit {
    0%   { opacity: 1; transform: none; }
    100% { opacity: 0; transform: scale(0.95) translateY(8px); }
}
.modal-exit {
    animation: animModalExit var(--duration-fast) var(--easing-in) both;
    pointer-events: none;
}

/* ── §28-6  하위 호환 별칭 — .ripple-container → .ripple-host 참조 ──
   기존 HTML/JS에서 ripple-container 클래스를 사용하는 요소 지원.
   신규 코드는 .ripple-host 사용 권장. */
.ripple-container {
    position: relative;
    overflow: hidden;
}
.ripple-container > .ripple {
    position: absolute;
    border-radius: 50%;
    background: var(--ripple-color);
    transform: scale(0);
    animation: animRipple var(--ripple-duration) var(--easing-out) forwards;
    pointer-events: none;
    will-change: transform, opacity;
}
.ripple-container.ripple-accent > .ripple {
    background: var(--ripple-accent);
}

/* ── §28-7  커서 근접 글로우 — 커서 접근 시 미세 글로우 ── */
@keyframes animNearGlow {
    0%   { box-shadow: none; }
    100% { box-shadow: var(--shadow-near-glow); }
}

/* ── §28-8  빈상태 부유 — 아이콘이 부드럽게 떠다님 ── */
@keyframes animEmptyFloat {
    0%, 100% { transform: translateY(0) rotate(0deg); }
    25%      { transform: translateY(-4px) rotate(-1deg); }
    75%      { transform: translateY(-2px) rotate(1deg); }
}
.empty-float {
    animation: animEmptyFloat 4s var(--easing-breathe) infinite;
    will-change: transform;
}

/* ── §28-9  토스트 퇴장 — 우측으로 스프링 퇴장 ── */
@keyframes animToastOut {
    0%   { opacity: 1; transform: none; }
    100% { opacity: 0; transform: translateX(32px) scale(0.96); }
}
.toast-exit {
    animation: animToastOut 250ms var(--easing-in) both;
    pointer-events: none;
}

/* ── §28-10  스무스 카운터 — 숫자 변경 시 슬롯머신 효과 ── */
/* height와 line-height가 반드시 동일해야 슬롯 1자리만 표시됨 (1.3 불가 — 잘림 발생) */
.counter-slot {
    --counter-lh: 1.2; /* 슬롯 높이=line-height 결합 토큰 (--leading-tight 1.3과 차이 → 전용 값 유지) */
    display: inline-flex;
    overflow: hidden;
    height: calc(var(--counter-lh) * 1em);
    vertical-align: bottom;
}
.counter-slot .counter-digit {
    display: inline-block;
    transition: transform var(--duration-base) var(--easing-spring-gentle);
    line-height: var(--counter-lh);
}

/* ── §28-11  프리미엄 로딩 도트 — 3개 도트 순차 펄스 ── */
@keyframes animLoadDots {
    0%, 80%, 100% { opacity: 0.3; transform: scale(0.6); }
    40%           { opacity: 1;   transform: scale(1); }
}
.loading-dots {
    display: inline-flex;
    gap: var(--s-1);
    align-items: center;
}
.loading-dots > span {
    width: var(--s-1);
    height: var(--s-1);
    border-radius: 50%;
    background: var(--accent);
    animation: animLoadDots 1.4s var(--easing-in-out) infinite;
}
.loading-dots > span:nth-child(2) { animation-delay: 160ms; }
.loading-dots > span:nth-child(3) { animation-delay: 320ms; }


/* ═══════════════════════════════════════════
   §30  Skeleton→Content 오케스트레이션 전환
   ─────────────────────────────────────────
   §6b/§25 개별 클래스를 조합하여 사용하는 컨테이너 레벨
   오케스트레이션. skeleton 퇴장과 content 등장의 타이밍을
   정밀 좌표화하여 깜빡임(flash) 없는 심리스 전환 보장.
   GPU 가속 속성(transform, opacity, filter)만 사용. 60fps.
   ═══════════════════════════════════════════ */

/* ── §30-1  컨테이너 크로스페이드 v2 — 겹침 전환 ──
   skeleton과 content가 동일 위치에서 크로스페이드.
   JS: 컨테이너에 .skel-orchestrate 부여,
       skeleton에 .skel-orch-exit 추가 → 120ms 후 content 주입 + .skel-orch-enter 추가.
   타이밍: skeleton 퇴장(120ms) + content 등장(250ms) = 총 ~280ms 체감. */

.skel-orchestrate {
    position: relative;
}

/* skeleton 퇴장 — 빠른 fade+미세 scale+blur (120ms) */
.skel-orch-exit {
    animation: animSkelOrchExit 120ms var(--easing-in) forwards;
    pointer-events: none;
    will-change: opacity, transform, filter;
}
@keyframes animSkelOrchExit {
    0%   { opacity: 1; transform: scale(1); filter: blur(0); }
    100% { opacity: 0; transform: scale(0.985); filter: var(--glass-blur-xs); }
}

/* content 등장 — blur-to-sharp + fade + 미세 slide-up (250ms) */
.skel-orch-enter {
    animation: animSkelOrchEnter 250ms var(--easing-out) both;
    will-change: opacity, transform, filter;
}
@keyframes animSkelOrchEnter {
    0%   { opacity: 0; transform: translateY(6px); filter: var(--glass-blur-xs); }
    40%  { opacity: 0.8; filter: var(--glass-blur-xs); }
    100% { opacity: 1; transform: none; filter: blur(0); }
}

/* ── §30-2  그리드 카드 오케스트레이션 — stagger + blur-reveal ──
   카드 그리드(에이전트, 출력물 등)가 skeleton에서 전환 시
   각 카드가 순차적으로 blur-to-sharp + slide-up.
   JS: 부모에 .skel-grid-reveal, 자식에 --stagger-i 주입. */

.skel-grid-reveal > * {
    opacity: 0;
    animation: animSkelGridCard var(--duration-moderate) var(--easing-spring-gentle) forwards;
    animation-delay: calc(var(--stagger-i, 0) * 40ms);
    will-change: opacity, transform, filter;
}
@keyframes animSkelGridCard {
    0%   { opacity: 0; transform: translateY(10px) scale(0.97); filter: var(--glass-blur-xs); }
    50%  { opacity: 0.9; filter: blur(0); }
    70%  { transform: translateY(-1px) scale(1.003); }
    100% { opacity: 1; transform: none; filter: blur(0); }
}

/* ── §30-3  리스트 오케스트레이션 — 행 순차 slide-in ──
   리스트 아이템이 skeleton에서 전환 시 좌측에서 순차 슬라이드.
   JS: 부모에 .skel-list-reveal, 자식에 --stagger-i 주입. */

.skel-list-reveal > * {
    opacity: 0;
    animation: animSkelListItem var(--duration-moderate) var(--easing-spring-bouncy, var(--easing-bounce)) forwards;
    animation-delay: calc(var(--stagger-i, 0) * 35ms);
    will-change: opacity, transform;
}
@keyframes animSkelListItem {
    0%   { opacity: 0; transform: translateY(12px) scale(0.96); }
    50%  { opacity: 1; transform: translateY(-2px) scale(1.01); }
    75%  { transform: translateY(1px) scale(0.995); }
    100% { transform: none; }
}

/* ── §30-4  패널 전환 오케스트레이션 — 전체 패널 리빌 ──
   탭/패널 전환 시 skeleton→content가 아닌 패널 전체의 전환.
   blur reveal + spring overshoot로 프리미엄 느낌. */

.skel-panel-reveal {
    animation: animSkelPanelReveal 350ms var(--easing-spring-gentle) both;
    will-change: opacity, transform, filter;
}
@keyframes animSkelPanelReveal {
    0%   { opacity: 0; transform: translateY(8px) scale(0.995); filter: var(--glass-blur-xs); }
    40%  { opacity: 0.9; filter: var(--glass-blur-xs); }
    70%  { transform: translateY(-1px) scale(1.002); filter: blur(0); }
    100% { opacity: 1; transform: none; }
}


/* ═══════════════════════════════════════════
   §31  카드/버튼 마이크로 인터랙션 Polish
   ─────────────────────────────────────────
   1000억 프로덕트급 인터랙션 디테일 보강.
   :active shadow depression, 호버 엣지 라이트,
   CTA 버튼 프리미엄 프레스 피드백.
   ═══════════════════════════════════════════ */

/* ── §31-1  버튼 프레스 디프레션 — :active 시 shadow 눌림 ──
   scale만으로는 부족한 깊이감을 shadow inset으로 보강.
   프리미엄 SaaS에서 공통 사용하는 패턴. */

.btn-press-depth:active {
    transform: scale(0.97);
    box-shadow: var(--shadow-inset);
    transition: transform 60ms var(--easing-spring-bouncy),
                box-shadow 60ms var(--easing-out);
}

/* ── §31-2  카드 호버 엣지 라이트 — 상단 미세 하이라이트 ──
   카드 호버 시 상단에 1px 빛 효과로 입체감 부여.
   ::after pseudo-element로 구현, GPU 가속. */

.card-edge-light {
    position: relative;
    overflow: hidden;
}
.card-edge-light::after {
    content: '';
    position: absolute;
    top: 0;
    left: 10%;
    right: 10%;
    height: 1px;
    background: linear-gradient(
        90deg,
        transparent 0%,
        var(--surface-w6) 30%,
        var(--surface-w10) 50%,
        var(--surface-w6) 70%,
        transparent 100%
    );
    opacity: 0;
    transition: opacity var(--duration-base) var(--easing-out);
    pointer-events: none;
    z-index: 1;
}
.card-edge-light:hover::after {
    opacity: 1;
}

/* ── §31-3  CTA 호버 글로우 확산 — 주요 액션 버튼 호버 시 accent glow ──
   accent 배경 버튼 호버 시 미묘한 글로우 확산으로 클릭 유도. */

.cta-hover-glow {
    transition: box-shadow var(--duration-base) var(--easing-out),
                transform var(--duration-base) var(--easing-spring-gentle);
}
.cta-hover-glow:hover {
    box-shadow: var(--shadow-ring-dim-xs),
                0 4px 12px var(--surface-active),
                0 0 24px var(--clr-teal-bg-xs);
    transform: translateY(-1px);
}
.cta-hover-glow:active {
    box-shadow: var(--shadow-ring-dim-xs);
    transform: translateY(0) scale(0.97);
    transition-duration: 60ms;
}

/* ── §31-4  상태 전환 팝 + 글로우 — 에이전트/카드 상태 변경 시 ──
   상태 클래스 전환 시 미세 scale pop + 상태색 글로우 확산.
   JS에서 상태 변경 시 .state-pop 클래스 잠시 추가 → animationend 후 제거. */

@keyframes animStatePop {
    0%   { transform: scale(1); }
    30%  { transform: scale(1.04); }
    60%  { transform: scale(0.98); }
    100% { transform: scale(1); }
}
.state-pop {
    animation: animStatePop 300ms var(--easing-spring-bouncy) both;
}

/* ── §31-5  호버 리프트 + 글래스 라이트 통합 — 프리미엄 카드 호버 ──
   hover-lift + card-edge-light + 미세 shadow 변화를 통합.
   기존 hover-lift 클래스와 함께 사용 가능. */

.hover-lift-premium {
    transition: transform 250ms var(--easing-spring-gentle),
                box-shadow 250ms var(--easing-out);
    will-change: transform;
    backface-visibility: hidden;
    position: relative;
    overflow: hidden;
}
.hover-lift-premium::after {
    content: '';
    position: absolute;
    top: 0;
    left: 10%;
    right: 10%;
    height: 1px;
    background: linear-gradient(90deg,
        transparent 0%,
        var(--surface-w8) 50%,
        transparent 100%
    );
    opacity: 0;
    transition: opacity var(--duration-base) var(--easing-out);
    pointer-events: none;
    z-index: 1;
}
.hover-lift-premium:hover {
    transform: translateY(var(--hover-lift)) scale(1.005);
    box-shadow: var(--shadow-card-hover);
}
.hover-lift-premium:hover::after {
    opacity: 1;
}
.hover-lift-premium:active {
    transform: translateY(0) scale(0.98);
    transition-duration: var(--duration-instant);
    box-shadow: none;
}
.hover-lift-premium:active::after {
    opacity: 0;
}


/* ═══════════════════════════════════════════
   §29  접근성 — prefers-reduced-motion 보강
   ═══════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
    .scroll-reveal { opacity: 1; transform: none; transition: none; }
    .card-light-follow::before { display: none; }
    .empty-float { animation: none; }
    .loading-dots > span { animation: none; opacity: 0.6; transform: none; }
    .badge-morph { animation: none; opacity: 1; transform: none; }
    .modal-exit, .toast-exit { animation: none; opacity: 0; }

    /* 패널 전환 + 마이크로 인터랙션 보강 */
    .panel-fade-in { animation: none !important; opacity: 1; transform: none; }
    .panel-fade-out { animation: none !important; opacity: 0; }
    .pp-anim-retry-spin { animation: none !important; }
    .pp-anim-spring-count.counted { animation: none !important; transform: none; }
    .ripple-host > .ripple,
    .ripple-container > .ripple { animation: none !important; opacity: 0; }
    .drag-floating { transition: none !important; }
    .drag-ghost-lift { transform: none; box-shadow: none; }
    .drag-source-dim { transition: none !important; }
    .glow-trail::before { display: none; }
    .height-transition { transition: none !important; }
    .press-feedback { transition: none !important; }
    .counter-slot .counter-digit { transition: none !important; }

    /* §29-프리미엄 인터랙션 키프레임 reduced-motion */
    .blur-reveal { animation: none !important; opacity: 1; filter: none; transform: none; }
    .check-draw { animation: none !important; transform: none; }
    .check-draw path { animation: none !important; stroke-dashoffset: 0; opacity: 1; }
    .count-updated { animation: none !important; transform: none; }
    .badge-update { animation: none !important; transform: none; filter: none; }
    .toggle-celebrate { animation: none !important; transform: none; filter: none; }

    /* §30 Skeleton→Content 오케스트레이션 */
    .skel-orch-exit { animation: none !important; opacity: 0; }
    .skel-orch-enter { animation: none !important; opacity: 1; transform: none; filter: none; }
    .skel-grid-reveal > * { animation: none !important; opacity: 1; transform: none; filter: none; }
    .skel-list-reveal > * { animation: none !important; opacity: 1; transform: none; }
    .skel-panel-reveal { animation: none !important; opacity: 1; transform: none; filter: none; }

    /* §31 마이크로 인터랙션 polish */
    .state-pop { animation: none !important; transform: none; }
    .card-edge-light::after { display: none; }
    .hover-lift-premium::after { display: none; }
    .cta-hover-glow { transition: none; }
    .btn-press-depth:active { transform: none; transition: none; }
    .state-working-glow { animation: none !important; }
    .active-gradient-border { animation: none !important; }

    /* §32 신규 마이크로 모션 (2026-03-15) */
    .empty-state-icon { animation: none !important; transform: none; }
    .skeleton-loaded { animation: none !important; opacity: 1; filter: none; transform: none; }
    .skeleton-container.skeleton-hidden { filter: none; transform: none; }
    .toggle-switch input:checked + .toggle-slider::after { animation: none !important; display: none; }
    .tpl-tab-content.active,
    .tab-panel.active { animation: none !important; opacity: 1; }

    /* §36 커스텀 체크박스 reduced-motion */
    .custom-check input:checked + .check-mark { animation: none !important; }
    .check-mark::after { transition: none !important; }
}


/* ═══════════════════════════════════════════
   §33  터치 기기 hover-lift 리셋
   ─────────────────────────────────────────
   터치 기기에서 sticky hover 방지.
   유틸리티 클래스 + Wave B/C 인라인 hover-lift 대상.
   mobile.css가 .btn / .agent-card 커버,
   여기서 animations.css 정의 요소 커버.
   ═══════════════════════════════════════════ */
@media (hover: none) {
    /* 유틸리티 클래스 */
    .hover-lift:hover,
    .hover-lift-sm:hover,
    .hover-lift-premium:hover {
        transform: none;
        box-shadow: inherit;
    }

    /* §26b Tier 1 — 카드급 */
    .node-item:hover,
    .ad-toggle-item:hover,
    .ad-thinking-step:hover,
    .ad-version-item:hover,
    .ad-skill-item-full:hover,
    .ad-ctx-card-v2:hover,
    .ad-file-item:hover,
    .meta-preset-badge:hover,
    .meta-preset-detail:hover,
    .comm-bubble:hover,
    .chat-example-btn:hover,
    .welcome-step:hover,
    .summary-stat:hover,
    .ov-file-item:hover,
    .factory-template-card:hover,
    .factory-history-card:hover,
    .oc-agent-card:hover,
    .oc-channel-card:hover,
    /* Wave B/C hover-lift 카드 + T2~T6 통일 대상 */
    .wp-card:hover,
    .sj-card:hover,
    .prompt-card:hover,
    .draft-card:hover,
    .sp-item:hover {
        transform: none;
        box-shadow: inherit;
    }

    /* §26b Tier 2 — 탭/칩/리스트 */
    .ad-tab:hover,
    .ad-filter-btn:hover,
    .ad-prompt-toc-item:hover,
    .ad-prompt-section-head:hover,
    .ad-tab-more-item:hover,
    .ad-breadcrumb-item:hover,
    .ad-collab-chip:hover,
    .content-chip:hover,
    .overview-graph-toggle:hover,
    .draft-tab:hover,
    .draft-panel-toggle:hover,
    .wp-view-btn:hover,
    .job-link-toggle:hover,
    .factory-tab:hover,
    .factory-domain-chip:hover,
    .factory-scale-btn:hover,
    .factory-squad-header:hover,
    .oc-subtab-btn:hover,
    .pp-chip:hover,
    .plan-mode-toggle:hover,
    .plan-card-btn:hover,
    .plan-fmt-btn:hover,
    .ideas-card-action:hover,
    .ideas-cat-btn:hover,
    /* cdf1438 hover-lift-sm 요소 */
    .summary-retry-all-btn:hover,
    .agent-filter-btn:hover,
    .agent-search-btn:hover,
    .agent-search-close:hover,
    .tpl-segment-btn:hover,
    .config-settings-btn:hover,
    .modal-tab:hover,
    .drawer-close:hover,
    .sd-tab:hover,
    .server-restart-dismiss-btn:hover {
        transform: none;
    }

    /* §10c Tier 1 — Spring Hover Wave 3 카드 (prompt-card → §33 T2~T6 그룹으로 이관) */
    .output-file:hover,
    .solo-gen-card:hover,
    .git-branch-item:hover,
    .job-tl-item:hover,
    .draft-option:hover,
    .pp-direction-card:hover {
        transform: none;
        box-shadow: inherit;
    }

    /* §10c Tier 2 — Spring Hover Wave 3 칩/버튼 */
    .topbar-job-chip:hover,
    .gpt-example-btn:hover,
    .owui-example-btn:hover,
    .research-btn:hover,
    .draft-select-btn:hover,
    .config-chip:hover,
    .chip:hover {
        transform: none;
    }

    /* Spring 업그레이드 요소 */
    .ad-output-item:hover,
    .ad-job-item:hover,
    .ad-stat-card:hover {
        transform: none;
        box-shadow: inherit;
    }

    /* §33 — Touch sticky hover 방지 (Round 3) */

    /* §33a Tier 1 — 카드급 (transform + box-shadow 리셋) */
    .btn-icon:hover,
    .modal-btn-cancel:hover,
    .modal-btn-submit:hover,
    .modal-btn-back:hover,
    .toast-action-btn:hover,
    .mcp-server-item:hover,
    .th-card:hover,
    .ctx-file-item:hover,
    .auth-setup-card:hover,
    .registry-card:hover,
    .deploy-btn:hover,
    .pw-search-trigger:hover,
    .pw-block:hover,
    .welcome-card:hover {
        transform: none;
        box-shadow: inherit;
    }

    /* §33b Tier 2 — 탭/칩/버튼 (transform only) */
    .tag:hover,
    .list-row:hover,
    .toggle-item:hover,
    .pw-toolbar-btn:hover,
    .pw-team-pill:hover,
    .pw-shelf-item:hover,
    .mc-sess-tab:hover,
    .mc-par-item:hover,
    .output-group-header:hover,
    .settings-row:hover,
    .settings-app-row:hover,
    .sidebar-tab:hover,
    .gpt-retry-btn:hover,
    .draft-panel-close:hover,
    .pvm-agent-btn:hover,
    .pvm-btn:hover,
    .pvm-snapshot-btn:hover,
    .prompt-attach-btn:hover,
    .prompt-expand-btn:hover,
    .cwd-selector-btn:hover,
    .solo-gen-send:hover,
    .pp-card-hover:hover,
    .sd-output-item:hover,
    .create-team-replan-btn:hover,
    .ov-premium-cat-chip:hover,
    .wp-detail-tab:hover,
    .zip-viewer-share-btn:hover,
    .division-header.clickable:hover {
        transform: none;
    }

    /* §33c Tier 3 — translateX/scale 요소 */
    .pw-sys-item:hover,
    .pvm-ver-item:hover,
    .cwd-dropdown-item:hover,
    .cwd-dropdown-add:hover,
    .agent-more-item:hover,
    .wp-detail-back:hover,
    .wp-detail-close:hover,
    .zip-carousel-dot:hover,
    .job-search-clear:hover,
    .press-spring:hover {
        transform: none;
    }

    /* §33d 유틸리티 — box-shadow only */
    .hover-glow:hover,
    .cta-hover-glow:hover,
    .toast-action-primary:hover {
        box-shadow: inherit;
    }
}


/* ═══════════════════════════════════════════
   §33e  접근성 — prefers-reduced-motion (hover-lift 대응)
   ─────────────────────────────────────────
   §33 터치 기기 hover-lift 리셋의 reduced-motion 등가.
   모션 감소 선호 사용자에게 hover 시 transform 비활성화.
   ═══════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
    /* 유틸리티 클래스 */
    .hover-lift:hover,
    .hover-lift-sm:hover,
    .hover-lift-premium:hover {
        transform: none;
    }

    /* Tier 1 — 카드급 (§26b + §33a) */
    .node-item:hover,
    .ad-toggle-item:hover,
    .ad-thinking-step:hover,
    .ad-version-item:hover,
    .ad-skill-item-full:hover,
    .ad-ctx-card-v2:hover,
    .ad-file-item:hover,
    .meta-preset-badge:hover,
    .meta-preset-detail:hover,
    .comm-bubble:hover,
    .chat-example-btn:hover,
    .welcome-step:hover,
    .summary-stat:hover,
    .ov-file-item:hover,
    .factory-template-card:hover,
    .factory-history-card:hover,
    .oc-agent-card:hover,
    .oc-channel-card:hover,
    .btn-icon:hover,
    .modal-btn-cancel:hover,
    .modal-btn-submit:hover,
    .modal-btn-back:hover,
    .toast-action-btn:hover,
    .mcp-server-item:hover,
    .th-card:hover,
    .ctx-file-item:hover,
    .auth-setup-card:hover,
    .registry-card:hover,
    .deploy-btn:hover,
    .pw-search-trigger:hover,
    .pw-block:hover,
    .wp-card:hover,
    .sj-card:hover,
    .draft-card:hover,
    .sp-item:hover,
    .welcome-card:hover {
        transform: none;
        box-shadow: inherit;
    }

    /* box-shadow only 유틸리티 (§33d 등가) */
    .hover-glow:hover,
    .cta-hover-glow:hover,
    .toast-action-primary:hover {
        box-shadow: inherit;
        transform: none;
    }

    /* Tier 2 — 탭/칩/리스트 (§26b + cdf1438 + §33b) */
    .ad-tab:hover,
    .ad-filter-btn:hover,
    .ad-prompt-toc-item:hover,
    .ad-prompt-section-head:hover,
    .ad-tab-more-item:hover,
    .ad-breadcrumb-item:hover,
    .ad-collab-chip:hover,
    .content-chip:hover,
    .overview-graph-toggle:hover,
    .draft-tab:hover,
    .draft-panel-toggle:hover,
    .wp-view-btn:hover,
    .job-link-toggle:hover,
    .factory-tab:hover,
    .factory-domain-chip:hover,
    .factory-scale-btn:hover,
    .factory-squad-header:hover,
    .oc-subtab-btn:hover,
    .pp-chip:hover,
    .plan-mode-toggle:hover,
    .plan-card-btn:hover,
    .plan-fmt-btn:hover,
    .ideas-card-action:hover,
    .ideas-cat-btn:hover,
    .summary-retry-all-btn:hover,
    .agent-filter-btn:hover,
    .agent-search-btn:hover,
    .agent-search-close:hover,
    .tpl-segment-btn:hover,
    .config-settings-btn:hover,
    .modal-tab:hover,
    .drawer-close:hover,
    .sd-tab:hover,
    .server-restart-dismiss-btn:hover,
    .tag:hover,
    .list-row:hover,
    .toggle-item:hover,
    .pw-toolbar-btn:hover,
    .pw-team-pill:hover,
    .pw-shelf-item:hover,
    .mc-sess-tab:hover,
    .mc-par-item:hover,
    .output-group-header:hover,
    .settings-row:hover,
    .settings-app-row:hover,
    .sidebar-tab:hover,
    .gpt-retry-btn:hover,
    .draft-panel-close:hover,
    .pvm-agent-btn:hover,
    .pvm-btn:hover,
    .pvm-snapshot-btn:hover,
    .prompt-attach-btn:hover,
    .prompt-expand-btn:hover,
    .cwd-selector-btn:hover,
    .solo-gen-send:hover,
    .pp-card-hover:hover,
    .sd-output-item:hover,
    .create-team-replan-btn:hover,
    .ov-premium-cat-chip:hover,
    .wp-detail-tab:hover,
    .zip-viewer-share-btn:hover,
    .division-header.clickable:hover {
        transform: none;
    }

    /* §10c — Spring Hover Wave 3 카드 */
    .output-file:hover,
    .solo-gen-card:hover,
    .prompt-card:hover,
    .git-branch-item:hover,
    .job-tl-item:hover,
    .draft-option:hover,
    .pp-direction-card:hover {
        transform: none;
    }

    /* §10c — Spring Hover Wave 3 칩/버튼 */
    .topbar-job-chip:hover,
    .gpt-example-btn:hover,
    .owui-example-btn:hover,
    .research-btn:hover,
    .draft-select-btn:hover,
    .config-chip:hover,
    .chip:hover {
        transform: none;
    }

    /* Spring 업그레이드 요소 */
    .ad-output-item:hover,
    .ad-job-item:hover,
    .ad-stat-card:hover {
        transform: none;
    }

    /* §33c — translateX/scale 요소 */
    .pw-sys-item:hover,
    .pvm-ver-item:hover,
    .cwd-dropdown-item:hover,
    .cwd-dropdown-add:hover,
    .agent-more-item:hover,
    .wp-detail-back:hover,
    .wp-detail-close:hover,
    .zip-carousel-dot:hover,
    .job-search-clear:hover,
    .press-spring:hover {
        transform: none;
    }
}


/* ═══════════════════════════════════════════
   §34  대시보드 Entrance — 초기 페이지 로드 순차 등장
   ─────────────────────────────────────────
   최초 로드 시 주요 섹션(topbar, 사이드바, 메인 콘텐츠)이
   순차적으로 등장하여 프리미엄 SaaS 첫인상 제공.
   JS에서 body에 .dashboard-ready 클래스 추가로 트리거.
   ═══════════════════════════════════════════ */

/* ── §34-1  dashboardEntrance 키프레임 — fade+slide+blur 3중 ── */
@keyframes dashboardEntrance {
    0%   { opacity: 0; transform: translateY(12px); filter: var(--glass-blur-xs); }
    60%  { opacity: 1; filter: blur(0); }
    100% { opacity: 1; transform: none; filter: none; }
}

/* ── §34-2  유틸리티 클래스 — 섹션에 부여 ── */
.dash-entrance {
    /* ⚠️ opacity:0 의도적 제거 — JS가 .dashboard-ready를 추가하기 전에도
       요소가 보여야 함 (no-JS 안전장치). animation fill:both의 backwards가
       트리거 시 delay 동안 키프레임 0%(opacity:0)을 적용하므로 정상 작동 */
    /* will-change 제거 — 400ms 1회성 애니메이션에 영구 compositing layer 불필요 */
    backface-visibility: hidden;
}

/* body.dashboard-ready 추가 시 트리거 */
.dashboard-ready .dash-entrance {
    animation: dashboardEntrance 400ms var(--easing-out) backwards; /* both→backwards: 완료 후 compositing 해제 */
}

/* 순차 딜레이 — 섹션 순서 (topbar→sidebar→main→cmd 등) */
.dash-entrance-1 { animation-delay: 0ms; }
.dash-entrance-2 { animation-delay: 60ms; }
.dash-entrance-3 { animation-delay: 120ms; }
.dash-entrance-4 { animation-delay: 180ms; }
.dash-entrance-5 { animation-delay: 240ms; }
.dash-entrance-6 { animation-delay: 300ms; }

/* ── §34-3  탭 전환 시 패널 fadeIn 보강 — 탭 콘텐츠 전환에 사용 ── */
.dash-tab-enter {
    animation: dashboardEntrance 300ms var(--easing-out) backwards;
}

/* ── §34-4  페이지 로드 순차 등장 — 내부 콘텐츠 stagger ──
   body.dashboard-ready 트리거 후, 레이아웃 섹션(§34-2)이 등장 완료되면
   내부 콘텐츠가 순차 fade+slide-up으로 등장.
   사용법: 부모에 .page-entrance-stagger 부여.
   §34-2 dash-entrance 완료 후(~300ms) 시작하도록 base delay 포함. */
@keyframes pageEntranceSlideUp {
    0%   { opacity: 0; transform: translateY(10px); }
    100% { opacity: 1; transform: none; }
}

.page-entrance-stagger > * {
    /* ⚠️ opacity:0 의도적 제거 — .dash-entrance와 동일 이유 (no-JS 안전장치).
       animation fill:both의 backwards가 delay 동안 숨김 처리 */
    /* will-change 제거 — 400ms 1회성 애니메이션에 영구 compositing layer 불필요 */
    backface-visibility: hidden;
}

.dashboard-ready .page-entrance-stagger > * {
    animation: pageEntranceSlideUp var(--duration-base) var(--easing-out) both;
}

/* nth-child 기반 자동 딜레이 — JS 없이도 작동 (최대 8개 섹션) */
.dashboard-ready .page-entrance-stagger > *:nth-child(1) { animation-delay: 300ms; }
.dashboard-ready .page-entrance-stagger > *:nth-child(2) { animation-delay: 350ms; }
.dashboard-ready .page-entrance-stagger > *:nth-child(3) { animation-delay: 400ms; }
.dashboard-ready .page-entrance-stagger > *:nth-child(4) { animation-delay: 450ms; }
.dashboard-ready .page-entrance-stagger > *:nth-child(5) { animation-delay: 500ms; }
.dashboard-ready .page-entrance-stagger > *:nth-child(6) { animation-delay: 550ms; }
.dashboard-ready .page-entrance-stagger > *:nth-child(7) { animation-delay: 600ms; }
.dashboard-ready .page-entrance-stagger > *:nth-child(8) { animation-delay: 650ms; }


/* ═══════════════════════════════════════════
   §35  D&D 물리감 강화 — ghost/clone/dragging 프리미엄 모션
   ─────────────────────────────────────────
   §28-4 기존 drag-ghost-lift/drag-source-dim/drag-return에 추가하여
   touch-drag-clone과 cj-dragging에 물리적 감촉 부여.
   ═══════════════════════════════════════════ */

/* ── §35-1  cj-dragging 물리감 — 원본 dim + 미세 축소 + spring 전환 ── */
.cj-dragging {
    opacity: 0.35;
    transform: scale(0.97);
    transition: opacity var(--duration-fast) var(--easing-out),
                transform var(--duration-fast) var(--easing-out);
    will-change: opacity, transform;
}

/* ── §35-2  cj-drag-over 드롭존 — agents.css border에 트랜지션 추가 ── */
.cj-drag-over-top,
.cj-drag-over-bottom {
    transition: border-color var(--duration-fast) var(--easing-out);
}

/* ── §35-3  touch-drag-clone 물리감 — 리프트+회전+그림자 ── */
.touch-drag-clone {
    transform: scale(1.04) rotate(0.8deg);
    box-shadow: var(--shadow-lg), var(--shadow-glow-dim-md);
    opacity: 0.92;
    transition: transform var(--duration-fast) var(--easing-spring-gentle),
                box-shadow var(--duration-fast) var(--easing-out);
    will-change: transform;
    backface-visibility: hidden;
}

/* ── §35-4  드래그 드롭 완료 spring 안착 — 물리적 바운스 강화 ── */
@keyframes dragDropSettle {
    0%   { transform: scale(1.04); }
    40%  { transform: scale(0.97); }
    70%  { transform: scale(1.01); }
    100% { transform: none; }
}
.drag-drop-settle {
    animation: dragDropSettle 300ms var(--easing-spring-gentle) both;
    will-change: transform;
    backface-visibility: hidden;
}

/* §35-5, §35-6 → §28-4로 통합 완료 (중복 제거) */

/* ── §35-7  ghost-lift 미세 pulse — 픽업 순간 scale 강조 ──
   dragstart 시 ghost 캡처 후, source에 미세 pulse로 "집어 올렸다" 느낌 보강.
   JS: drag-ghost-lift 제거 전 → drag-pickup-pulse 추가 → rAF 후 drag-source-dim 전환. */
@keyframes dragPickupPulse {
    0%   { transform: scale(1.04) rotate(0.8deg); }
    60%  { transform: scale(0.96); }
    100% { transform: scale(0.97); }
}
.drag-pickup-pulse {
    animation: dragPickupPulse 180ms var(--easing-spring-gentle) both;
    will-change: transform;
}


/* ═══════════════════════════════════════════
   §37  1000억급 프리미엄 인터랙션 (v1)
   ─────────────────────────────────────────
   Tier별 easing 통일 + 선언적 모션 클래스.
   GPU 가속 속성만 사용(transform/opacity/filter).
   ═══════════════════════════════════════════ */

/* ── §37-1  블러 진입 — 블러→선명 전환 (프리미엄 텍스트/카드 등장) ── */
@keyframes animBlurEnter {
    from { opacity: 0; filter: var(--glass-blur-xs); transform: translateY(8px) scale(0.98); }
    to   { opacity: 1; filter: blur(0);   transform: none; }
}
.blur-enter {
    opacity: 0;
    filter: var(--glass-blur-xs);
    transform: translateY(8px) scale(0.98);
    transition: opacity var(--duration-enter) var(--easing-out),
                filter var(--blur-reveal-duration) var(--easing-out),
                transform var(--duration-enter) var(--easing-organic);
}
.blur-enter.active {
    opacity: 1;
    filter: blur(0);
    transform: none;
}

/* ── §37-2  프리미엄 카드 호버 글로우 — 은은한 주변광 + 리프트 ── */
.premium-hover-glow {
    transition: box-shadow var(--duration-moderate) var(--easing-out),
                transform var(--duration-base) var(--easing-spring-gentle);
}
.premium-hover-glow:hover {
    box-shadow: var(--glow-premium), var(--shadow-lg);
    transform: translateY(var(--hover-lift)) scale(1.005);
}
.premium-hover-glow:active {
    box-shadow: var(--shadow);
    transform: scale(var(--active-scale));
    transition-duration: var(--duration-instant);
}

/* ── §37-3  리스트 순차 등장 — blur+slide 조합 ── */
@keyframes animListBlurEnter {
    from { opacity: 0; filter: var(--glass-blur-xs); transform: translateY(12px); }
    to   { opacity: 1; filter: blur(0);   transform: none; }
}
.motion-list-enter > * {
    animation: animListBlurEnter var(--duration-enter) var(--easing-organic) both;
}
.motion-list-enter > *:nth-child(1)  { animation-delay: 0ms; }
.motion-list-enter > *:nth-child(2)  { animation-delay: 40ms; }
.motion-list-enter > *:nth-child(3)  { animation-delay: 80ms; }
.motion-list-enter > *:nth-child(4)  { animation-delay: 120ms; }
.motion-list-enter > *:nth-child(5)  { animation-delay: 160ms; }
.motion-list-enter > *:nth-child(6)  { animation-delay: 200ms; }
.motion-list-enter > *:nth-child(7)  { animation-delay: 240ms; }
.motion-list-enter > *:nth-child(8)  { animation-delay: 280ms; }
.motion-list-enter > *:nth-child(n+9) { animation-delay: 320ms; }

/* ── §37-4  프레스 잉크 — 버튼 클릭 시 포커스 포인트 확산 ── */
@keyframes animPressInk {
    from { transform: scale(0); opacity: 0.4; }
    to   { transform: scale(2.5); opacity: 0; }
}
.btn-press-ink {
    position: relative;
    overflow: hidden;
}
.press-ink {
    position: absolute;
    border-radius: 50%;
    background: var(--ripple-color);
    pointer-events: none;
    animation: animPressInk var(--ripple-duration) var(--easing-out) forwards;
}

/* ── §37-5  히어로 텍스트 리빌 — 글자별 블러→선명 (JS에서 span 래핑) ── */
@keyframes animHeroCharReveal {
    from { opacity: 0; filter: blur(var(--blur-reveal-char)); transform: translateY(6px); }
    to   { opacity: 1; filter: blur(0); transform: none; }
}
.hero-text-reveal span {
    display: inline-block;
    animation: animHeroCharReveal var(--blur-reveal-duration) var(--easing-organic) both;
}

/* ── §37-6  스크롤 리빌 강화 — blur 포함 버전 ── */
.scroll-reveal-blur {
    opacity: 0;
    filter: var(--glass-blur-xs);
    transform: translateY(var(--scroll-reveal-distance, 20px));
    transition: opacity var(--duration-enter) var(--easing-out),
                filter var(--blur-reveal-duration) var(--easing-out),
                transform var(--duration-enter) var(--easing-organic);
}
.scroll-reveal-blur.revealed {
    opacity: 1;
    filter: blur(0);
    transform: none;
}

/* ── §37-7  얼라이브 글로우 — 에이전트 working 상태 프리미엄 맥동 ── */
@keyframes animPremiumPulse {
    0%, 100% { box-shadow: 0 0 8px var(--clr-teal-bg-md); }
    50%      { box-shadow: 0 0 20px var(--accent-glow), 0 0 40px var(--clr-teal-bg-sm); }
}
.premium-alive-glow {
    animation: animPremiumPulse 3s var(--easing-breathe) infinite;
}


/* ── §37-8  스프링 물리 키프레임 (멀티바운스 오버슈트) ── */
@keyframes animSpringPop {
    0%   { transform: scale(0.85); opacity: 0; }
    40%  { transform: scale(1.08); opacity: 1; }
    60%  { transform: scale(0.96); }
    75%  { transform: scale(1.03); }
    90%  { transform: scale(0.99); }
    100% { transform: scale(1); }
}
@keyframes animSpringSlideUp {
    0%   { transform: translateY(24px) scale(0.97); opacity: 0; }
    45%  { transform: translateY(-6px) scale(1.01); opacity: 1; }
    70%  { transform: translateY(2px) scale(0.995); }
    100% { transform: translateY(0) scale(1); }
}
@keyframes animSpringPress {
    0%   { transform: scale(1); }
    30%  { transform: scale(0.92); }
    60%  { transform: scale(1.04); }
    80%  { transform: scale(0.98); }
    100% { transform: scale(1); }
}
.spring-pop {
    animation: animSpringPop var(--duration-flip) var(--easing-spring-gentle) both;
}
.spring-slide-up {
    animation: animSpringSlideUp 0.55s var(--easing-spring-gentle) both;
}
.spring-press {
    animation: animSpringPress var(--duration-spring) var(--easing-spring-gentle) both;
}


/* ── §37-9  마그네틱 버튼 (JS가 --mag-x/--mag-y 설정) ── */
.btn-magnetic {
    --mag-x: 0px;
    --mag-y: 0px;
    transform: translate(var(--mag-x), var(--mag-y));
    transition: transform var(--magnetic-return, 400ms) var(--easing-spring-gentle);
    will-change: transform;
}
.btn-magnetic-glow {
    position: relative;
}
.btn-magnetic-glow::after {
    content: '';
    position: absolute;
    inset: -2px;
    border-radius: inherit;
    background: radial-gradient(
        circle at calc(50% + var(--mag-x, 0px)) calc(50% + var(--mag-y, 0px)),
        var(--accent-glow) 0%,
        transparent 70%
    );
    opacity: 0;
    transition: opacity var(--duration-enter) var(--easing-out);
    pointer-events: none;
    z-index: -1;
}
.btn-magnetic-glow:hover::after {
    opacity: 1;
}


/* ── §37-10  [통합 완료] accent/neutral 리플은 §RIPPLE 통합 시스템으로 이관.
   .ripple-host + .ripple-host--accent 사용.
   accent-ripple/neutral-ripple 클래스는 하위 호환용 별칭으로 유지. ── */
.accent-ripple {
    position: absolute;
    border-radius: 50%;
    background: var(--ripple-accent, var(--accent-glow));
    transform: scale(0);
    animation: animRipple var(--ripple-duration) var(--easing-out) forwards;
    pointer-events: none;
    will-change: transform, opacity;
}
.neutral-ripple {
    position: absolute;
    border-radius: 50%;
    background: var(--ripple-color, var(--surface-w20));
    transform: scale(0);
    animation: animRipple var(--ripple-duration) var(--easing-out) forwards;
    pointer-events: none;
    will-change: transform, opacity;
}


/* ── §37-11  글자별 블러 리빌 ──
   @keyframes animCharBlurReveal 은 §37-3 에서 정의 (중복 방지).
   --blur-reveal-stagger 토큰으로 글자 간 딜레이 제어. */
.char-blur-reveal {
    display: inline-block;
    animation: animCharBlurReveal var(--blur-reveal-duration, 600ms) var(--easing-out) both;
    animation-delay: calc(var(--char-i, 0) * var(--blur-reveal-stagger, 30ms));
}
.word-blur-reveal {
    display: inline-block;
    animation: animCharBlurReveal var(--blur-reveal-duration, 600ms) var(--easing-out) both;
    animation-delay: calc(var(--char-i, 0) * calc(var(--blur-reveal-stagger, 30ms) * 2));
}


/* ── §37-12  FLIP 레이아웃 트랜지션 (JS가 --flip-dx/dy/sx/sy 설정) ── */
.flip-animate {
    --flip-dx: 0px;
    --flip-dy: 0px;
    --flip-sx: 1;
    --flip-sy: 1;
    transform: translate(var(--flip-dx), var(--flip-dy)) scale(var(--flip-sx), var(--flip-sy));
    transition: transform 350ms var(--easing-spring-gentle);
    will-change: transform;
}
.flip-animate-fade {
    --flip-dx: 0px;
    --flip-dy: 0px;
    --flip-sx: 1;
    --flip-sy: 1;
    transform: translate(var(--flip-dx), var(--flip-dy)) scale(var(--flip-sx), var(--flip-sy));
    transition: transform 350ms var(--easing-spring-gentle), opacity var(--duration-base) var(--easing-out);
    will-change: transform, opacity;
}


/* ── §37-13  스크롤 스태거 스프링 (IntersectionObserver → .is-visible) ── */
@keyframes animScrollStaggerSpringIn {
    0%   { opacity: 0; transform: translateY(var(--scroll-reveal-distance, 20px)) scale(0.97); }
    50%  { opacity: 1; transform: translateY(-4px) scale(1.01); }
    100% { opacity: 1; transform: translateY(0) scale(1); }
}
.scroll-stagger-spring {
    opacity: 0;
    transform: translateY(var(--scroll-reveal-distance, 20px)) scale(0.97);
}
.scroll-stagger-spring.is-visible {
    animation: animScrollStaggerSpringIn 0.55s var(--easing-spring-gentle) both;
    animation-delay: calc(var(--stagger-i, 0) * var(--scroll-stagger-gap, 50ms));
}


/* ── §37-14  성공 축하 + 카운터 증가 이펙트 ── */
@keyframes animSuccessCelebrate {
    0%   { transform: scale(1); }
    15%  { transform: scale(1.15); }
    30%  { transform: scale(0.95); }
    45%  { transform: scale(1.05); }
    60%  { transform: scale(0.98); }
    100% { transform: scale(1); }
}
@keyframes animCountIncrease {
    0%   { transform: translateY(0); opacity: 1; }
    50%  { transform: translateY(-8px); opacity: 0.6; }
    100% { transform: translateY(0); opacity: 1; }
}
.success-celebrate {
    animation: animSuccessCelebrate var(--duration-slower) var(--easing-spring-bouncy) both;
}
.count-increase {
    animation: animCountIncrease 0.35s var(--easing-out) both;
}


/* ── §37-15  인풋 포커스 프리미엄 글로우 ── */
.input-focus-premium {
    transition: box-shadow var(--duration-enter) var(--easing-out);
}
.input-focus-premium:focus {
    box-shadow: var(--glow-premium);
    outline: none;
}


/* ── §37-Z2  Reduced Motion — §37-8~15 ── */
@media (prefers-reduced-motion: reduce) {
    .spring-pop,
    .spring-slide-up,
    .spring-press {
        animation: none !important;
        transform: none;
        opacity: 1;
    }
    .btn-magnetic {
        transform: none !important;
        transition: none !important;
    }
    .btn-magnetic-glow::after {
        display: none;
    }
    .accent-ripple,
    .neutral-ripple {
        animation: none !important;
        display: none;
    }
    .char-blur-reveal,
    .word-blur-reveal {
        animation: none !important;
        filter: none;
        opacity: 1;
        transform: none;
    }
    .flip-animate,
    .flip-animate-fade {
        transition: none !important;
        transform: none;
    }
    .scroll-stagger-spring,
    .scroll-stagger-spring.is-visible {
        animation: none !important;
        opacity: 1;
        transform: none;
    }
    .success-celebrate,
    .count-increase {
        animation: none !important;
        transform: none;
        opacity: 1;
    }
    .input-focus-premium {
        transition: none !important;
    }
    /* §37-6 스크롤 리빌 블러 */
    .scroll-reveal-blur {
        opacity: 1;
        filter: none;
        transform: none;
        transition: none !important;
    }
    /* §37-7 얼라이브 글로우 */
    .premium-alive-glow {
        animation: none !important;
    }
}


/* ── §37-T  터치 디바이스 호버 리셋 — §37 전체 ── */
@media (hover: none) {
    .btn-magnetic {
        transform: none !important;
    }
    .btn-magnetic-glow::after {
        display: none;
    }
    .premium-hover-glow:hover {
        box-shadow: none;
        transform: none;
    }
}


/* ═══════════════════════════════════════════
   §36  D5 — D&D 원본 요소 시각 피드백 (Wave D)
   ─────────────────────────────────────────
   queueDragStart → .dragging, queueDragOver → .drag-over
   HTML5 D&D 한계 내 원본 요소 스타일링.
   ═══════════════════════════════════════════ */

/* ── §36-1  .dragging — 원본 dim + 미세 축소 ── */
.dragging {
    opacity: 0.5;
    transform: scale(0.98);
    transition: opacity var(--duration-fast) var(--easing-out),
                transform var(--duration-fast) var(--easing-out);
    will-change: opacity, transform;
    backface-visibility: hidden;
}

/* ── §36-2  .drag-over — 드롭존 배경 하이라이트 ── */
.drag-over {
    background-color: var(--surface-active) !important;
    transition: background-color var(--duration-fast) var(--easing-out);
}


/* ── §29 보강 — §34-§36 reduced-motion 대응 ── */
@media (prefers-reduced-motion: reduce) {
    /* §34 대시보드 Entrance */
    .dashboard-ready .dash-entrance {
        animation: none !important;
        opacity: 1;
        transform: none;
        filter: none;
    }
    .dash-tab-enter {
        animation: none !important;
        opacity: 1;
        transform: none;
        filter: none;
    }

    /* §34-4 페이지 로드 stagger */
    .dashboard-ready .page-entrance-stagger > * {
        animation: none !important;
        opacity: 1;
        transform: none;
    }

    /* §35 D&D 물리감 */
    .drag-drop-settle {
        animation: none !important;
        transform: none;
    }
    .drag-return {
        animation: none !important;
        opacity: 1;
        transform: none;
    }
    .drag-pickup-pulse {
        animation: none !important;
        transform: none;
    }
    .cj-dragging {
        transition: none !important;
    }
    .cj-drag-over-top,
    .cj-drag-over-bottom {
        transition: none !important;
    }
    .touch-drag-clone {
        transition: none !important;
    }

    /* §36 D5 D&D 원본 피드백 — reduced motion */
    .dragging {
        transform: none;
        transition: none !important;
    }
    .drag-over {
        transition: none !important;
    }

    /* D1 .anim-panel-enter — reduced motion (blur 리셋 포함) */
    .anim-panel-enter {
        animation: none !important;
        opacity: 1;
        transform: none;
        filter: none;
    }

    /* §37 프리미엄 인터랙션 — reduced motion */
    .blur-enter { filter: none !important; opacity: 1 !important; transform: none !important; }
    .blur-enter.active { filter: none !important; }
    .premium-hover-glow:hover { box-shadow: none !important; }
    .motion-list-enter > * { animation: none !important; opacity: 1; transform: none; }
    .btn-press-ink .press-ink { display: none !important; }
    .hero-text-reveal span { opacity: 1 !important; filter: none !important; transform: none !important; }
}


/* ═══════════════════════════════════════════
   §37  Premium Interaction Motions
   ─────────────────────────────────────────
   1000억급 인터랙션 모션 업그레이드.
   tokens.css Premium Interaction Tokens 기반.
   카테고리: Ripple Wave, Magnetic Return,
   Blur Reveal Premium, Scroll Stagger, Premium Glow.
   GPU 가속 속성(transform, opacity, filter)만 사용. 60fps.
   ═══════════════════════════════════════════ */

/* ── §37-1  리플 웨이브 — 프리미엄 클릭 피드백 ──
   기존 animRipple(§4)의 강화 버전.
   물결형 확산 + accent 색상 지원.
   --ripple-color / --ripple-accent / --ripple-duration 토큰 활용. */

@keyframes animRippleWave {
    0%   { transform: scale(0); opacity: 0.6; }
    40%  { opacity: 0.3; }
    100% { transform: scale(3); opacity: 0; }
}

/* 기본 리플 (neutral) */
.ripple-wave {
    position: absolute;
    border-radius: 50%;
    background: var(--ripple-color);
    transform: scale(0);
    animation: animRippleWave var(--ripple-duration) var(--easing-out) forwards;
    pointer-events: none;
    will-change: transform, opacity;
}

/* accent 리플 (CTA 버튼 전용) */
.ripple-wave-accent {
    position: absolute;
    border-radius: 50%;
    background: var(--ripple-accent);
    transform: scale(0);
    animation: animRippleWave var(--ripple-duration) var(--easing-out) forwards;
    pointer-events: none;
    will-change: transform, opacity;
}

/* 리플 컨테이너 — JS에서 클릭 시 .ripple-wave 요소 동적 생성 */
.ripple-wave-container {
    position: relative;
    overflow: hidden;
}


/* ── §37-2  마그네틱 리턴 — 버튼 복귀 스프링 ──
   JS에서 마우스 위치 기반 transform 적용 후,
   mouseleave 시 이 트랜지션으로 원위치 복귀.
   --magnetic-return 토큰 (400ms) 활용. */

.magnetic-target {
    transition: transform var(--magnetic-return) var(--easing-spring-gentle);
    will-change: transform;
}
/* 마그네틱 활성 상태 — JS에서 mousemove 시 직접 transform 설정 */
.magnetic-target.magnetic-active {
    transition: none;
}


/* ── §37-3  블러 리빌 프리미엄 — 토큰 기반 강화 ──
   기존 animBlurReveal(§27-3)의 프리미엄 확장.
   --blur-reveal-from / --blur-reveal-duration 토큰 활용.
   더 깊은 블러 시작점 + 더 정교한 단계별 선명화. */

@keyframes animBlurRevealPremium {
    0%   { opacity: 0; filter: blur(var(--blur-reveal-from)); transform: scale(0.97) translateY(var(--blur-reveal-y, 8px)); }
    30%  { opacity: 0.7; filter: var(--glass-blur-xs); }
    60%  { opacity: 0.9; filter: var(--glass-blur-xs); transform: scale(1) translateY(0); }
    100% { opacity: 1; filter: blur(0); transform: none; }
}

.blur-reveal-premium {
    animation: animBlurRevealPremium var(--blur-reveal-duration) var(--easing-out) both;
    will-change: filter, opacity, transform;
}

/* 글자별 블러 리빌 — 각 span에 stagger 적용, --blur-reveal-char 활용 */
@keyframes animCharBlurReveal {
    0%   { opacity: 0; filter: blur(var(--blur-reveal-char, 8px)); transform: translateY(var(--blur-reveal-y, 8px)); }
    50%  { opacity: 0.8; filter: var(--glass-blur-xs); }
    100% { opacity: 1; filter: blur(0); transform: none; }
}

.char-blur-reveal > span {
    display: inline-block;
    animation: animCharBlurReveal var(--blur-reveal-duration, 600ms) var(--easing-out) both;
    animation-delay: calc(var(--stagger-i, 0) * var(--blur-reveal-stagger, 30ms));
    will-change: filter, opacity, transform;
}


/* ── §37-4  스크롤 리빌 — IntersectionObserver 연동 ──
   뷰포트 진입 시 fade + slide-up + blur 등장.
   --scroll-reveal-distance / --scroll-stagger-gap 토큰 활용.
   JS initScrollReveal() → .scroll-reveal + .revealed 클래스 사용. */

@keyframes animScrollRevealUp {
    0%   { opacity: 0; transform: translateY(var(--scroll-reveal-distance)); filter: blur(4px); }
    40%  { filter: var(--glass-blur-xs); }
    100% { opacity: 1; transform: none; filter: blur(0); }
}


/* ── §37-5  프리미엄 글로우 펄스 — 중요 요소 호버/활성 글로우 ──
   --glow-premium / --glow-premium-strong 토큰 활용.
   은은한 teal 발광 효과로 프리미엄 느낌 강화. */

@keyframes animPremiumGlowPulse {
    0%, 100% { box-shadow: var(--glow-premium); }
    50%      { box-shadow: var(--glow-premium-strong); }
}

/* 호버 시 프리미엄 글로우 */
.premium-glow-hover {
    transition: box-shadow 300ms var(--easing-out);
}
.premium-glow-hover:hover {
    box-shadow: var(--glow-premium);
}

/* 활성 상태 글로우 펄스 (워킹/CTA 등) */
.premium-glow-pulse {
    animation: animPremiumGlowPulse 3s var(--easing-in-out) infinite;
}

/* 정적 프리미엄 글로우 (포커스/선택 상태) */
.premium-glow-static {
    box-shadow: var(--glow-premium);
    transition: box-shadow 300ms var(--easing-out);
}


/* ── §37-6  프리미엄 버튼 프레스 — 리플 + 스케일 + 글로우 통합 ──
   CTA/주요 버튼의 완전한 프레스 피드백 시퀀스.
   hover: 글로우 + 미세 lift
   active: 눌림 + 리플 확산
   ripple-wave-container와 함께 사용. */

.btn-premium-press {
    position: relative;
    overflow: hidden;
    transition: transform 200ms var(--easing-spring-gentle),
                box-shadow 250ms var(--easing-out);
    will-change: transform;
    backface-visibility: hidden;
}
.btn-premium-press:hover {
    transform: translateY(-1px) scale(1.01);
    box-shadow: var(--glow-premium);
}
.btn-premium-press:active {
    transform: translateY(0) scale(0.96);
    box-shadow: var(--shadow-inset);
    transition-duration: 60ms;
}


/* ═══════════════════════════════════════════
   §37r  접근성 — §37 Premium Interaction reduced-motion
   ═══════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
    /* §37-1 리플 웨이브 */
    .ripple-wave,
    .ripple-wave-accent {
        animation: none !important;
        opacity: 0;
    }

    /* §37-2 마그네틱 */
    .magnetic-target {
        transition: none !important;
    }

    /* §37-3 블러 리빌 프리미엄 */
    .blur-reveal-premium {
        animation: none !important;
        opacity: 1;
        filter: none;
        transform: none;
    }
    .char-blur-reveal > span {
        animation: none !important;
        opacity: 1;
        filter: none;
        transform: none;
    }

    /* §37-5 프리미엄 글로우 */
    .premium-glow-pulse {
        animation: none !important;
    }

    /* §37-6 프리미엄 버튼 프레스 */
    .btn-premium-press {
        transition: none;
    }
    .btn-premium-press:hover {
        transform: none;
        box-shadow: none;
    }
}


/* ═══════════════════════════════════════════
   §38  Premium Spring / FLIP / Dramatic — 프리미엄 모션 확장
   ─────────────────────────────────────────
   tokens.css의 --duration-spring(400ms), --duration-flip(500ms),
   --duration-dramatic(800ms) 토큰 활용.
   GPU 가속 속성만 사용(transform/opacity/filter). reduced-motion 대응 §38-R.
   ═══════════════════════════════════════════ */

/* ── §38-1  Spring Bounce — 탄성 바운스 강화 ──
   체크 표시, 성공 알림, 뱃지 업데이트 등 임팩트 피드백용.
   기존 animSpringIn 대비 오버슈트 + 리바운드 2회로 물리감 극대화. */
@keyframes animSpringBounce {
    0%   { transform: scale(0); opacity: 0; }
    35%  { transform: scale(1.12); opacity: 1; }
    55%  { transform: scale(0.94); }
    72%  { transform: scale(1.04); }
    88%  { transform: scale(0.99); }
    100% { transform: none; }
}
.anim-spring-bounce {
    animation: animSpringBounce var(--duration-spring) var(--easing-spring-bouncy) both;
    will-change: transform;
    backface-visibility: hidden;
}

/* ── §38-1b  Spring Bounce Subtle — 은은한 스프링 (호버/포커스 피드백) ── */
@keyframes animSpringBounceSubtle {
    0%   { transform: scale(0.96); opacity: 0.7; }
    40%  { transform: scale(1.03); opacity: 1; }
    65%  { transform: scale(0.99); }
    100% { transform: none; }
}
.anim-spring-bounce-subtle {
    animation: animSpringBounceSubtle var(--duration-spring) var(--easing-spring-bouncy) both;
    will-change: transform;
}

/* ── §38-2  FLIP Layout Transition — 카드/리스트 재정렬 ──
   JS에서 FLIP 패턴(First/Last/Invert/Play) 계산 후
   --flip-x, --flip-y, --flip-scale CSS 변수를 주입하여 트리거. */
@keyframes animFlipLayout {
    0%   { opacity: 0.7; transform: translate(var(--flip-x, 0), var(--flip-y, 0)) scale(var(--flip-scale, 1)); }
    60%  { opacity: 1; transform: translate(0, 0) scale(1.01); }
    100% { transform: none; }
}
.anim-flip-layout {
    animation: animFlipLayout var(--duration-flip) var(--easing-in-out) both;
    will-change: transform;
    backface-visibility: hidden;
}

/* ── §38-2b  FLIP Card — 개별 카드 뷰 모드 전환 (그리드 ↔ 리스트) ── */
@keyframes animFlipCard {
    0%   { opacity: 0.5; transform: translate(var(--flip-x, 0), var(--flip-y, 0)) scale(0.95); }
    50%  { opacity: 0.9; transform: translate(calc(var(--flip-x, 0) * 0.2), calc(var(--flip-y, 0) * 0.2)) scale(1.02); }
    80%  { transform: translate(0, 0) scale(0.995); }
    100% { opacity: 1; transform: none; }
}
.anim-flip-card {
    animation: animFlipCard var(--duration-flip) var(--easing-in-out) both;
    will-change: transform;
    backface-visibility: hidden;
}

/* ── §38-3  Dramatic Enter — 극적 섹션/모달 진입 ──
   대형 모달, 온보딩, 빈 상태 일러스트 등 "와" 효과.
   blur→sharp + scale + translate 복합 모션 (duration-dramatic 800ms). */
@keyframes animDramaticEnter {
    0%   { opacity: 0; transform: translateY(24px) scale(0.92); filter: var(--glass-blur-xs); }
    25%  { opacity: 0.4; transform: translateY(10px) scale(0.96); filter: var(--glass-blur-xs); }
    55%  { opacity: 0.9; transform: translateY(-3px) scale(1.01); filter: blur(0.5px); }
    75%  { opacity: 1; transform: translateY(1px) scale(0.998); filter: blur(0); }
    100% { transform: none; filter: none; }
}
.anim-dramatic-enter {
    animation: animDramaticEnter var(--duration-dramatic) var(--easing-out) both;
    will-change: transform, opacity, filter;
    backface-visibility: hidden;
}

/* ── §38-3b  Dramatic Scale — 극적 스케일 진입 (확대 효과) ── */
@keyframes animDramaticScale {
    0%   { opacity: 0; transform: scale(0.85); filter: var(--glass-blur-xs); }
    30%  { opacity: 0.5; transform: scale(0.95); filter: var(--glass-blur-xs); }
    60%  { opacity: 1; transform: scale(1.015); filter: blur(0); }
    80%  { transform: scale(0.997); }
    100% { transform: none; filter: none; }
}
.anim-dramatic-scale {
    animation: animDramaticScale var(--duration-dramatic) var(--easing-out) both;
    will-change: transform, opacity, filter;
    backface-visibility: hidden;
}

/* ── §38-4  Check Draw — 체크마크 SVG 드로잉 (stroke + spring) ── */
@keyframes animCheckDraw {
    0%   { stroke-dashoffset: 24; opacity: 0; }
    40%  { stroke-dashoffset: 6; opacity: 1; }
    60%  { stroke-dashoffset: -1; }
    80%  { stroke-dashoffset: 1; }
    100% { stroke-dashoffset: 0; }
}
.anim-check-draw path,
.anim-check-draw polyline {
    stroke-dasharray: 24;
    stroke-dashoffset: 24;
    animation: animCheckDraw var(--duration-spring) var(--easing-spring-bouncy) both;
}

/* ── §38-5  Badge Bounce — 뱃지/카운터 업데이트 바운스 ── */
@keyframes animBadgeBounce {
    0%   { transform: scale(1); }
    25%  { transform: scale(1.2); }
    50%  { transform: scale(0.9); }
    75%  { transform: scale(1.06); }
    100% { transform: none; }
}
.anim-badge-bounce {
    animation: animBadgeBounce var(--duration-spring) var(--easing-spring-bouncy) both;
    will-change: transform;
}

/* ── §38-R  Reduced motion — §38 전체 ── */
@media (prefers-reduced-motion: reduce) {
    .anim-spring-bounce { animation: none !important; transform: none; opacity: 1; }
    .anim-spring-bounce-subtle { animation: none !important; transform: none; opacity: 1; }
    .anim-flip-layout { animation: none !important; transform: none; opacity: 1; }
    .anim-flip-card { animation: none !important; transform: none; opacity: 1; }
    .anim-dramatic-enter { animation: none !important; transform: none; opacity: 1; filter: none; }
    .anim-dramatic-scale { animation: none !important; transform: none; opacity: 1; filter: none; }
    .anim-check-draw path, .anim-check-draw polyline { animation: none !important; stroke-dashoffset: 0; }
    .anim-badge-bounce { animation: none !important; transform: none; }
}


/* ═══════════════════════════════════════════════════════════════
   §39  방향별 스크롤 리빌 + 뱃지 스프링 + reduced-motion 보강
   ─────────────────────────────────────────────────────────────
   WebAnimator 추가. §37-4 animScrollRevealUp의 좌/우 방향 확장 +
   §37 v1 reduced-motion 누락분 보강.
   GPU 가속(transform/opacity/filter)만 사용. 600ms 이내.
   ═══════════════════════════════════════════════════════════════ */

/* ── §39-1  스크롤 리빌 좌측 — 왼쪽에서 진입 ── */
@keyframes animScrollRevealLeft {
    0%   { opacity: 0; transform: translateX(calc(var(--scroll-reveal-distance) * -1)); filter: blur(4px); }
    40%  { filter: var(--glass-blur-xs); }
    100% { opacity: 1; transform: none; filter: blur(0); }
}
.scroll-reveal-left {
    opacity: 0;
    will-change: transform, opacity, filter;
}
.scroll-reveal-left.scroll-reveal-visible {
    animation: animScrollRevealLeft var(--scroll-reveal-duration) var(--easing-out) both;
}

/* ── §39-2  스크롤 리빌 우측 — 오른쪽에서 진입 ── */
@keyframes animScrollRevealRight {
    0%   { opacity: 0; transform: translateX(var(--scroll-reveal-distance)); filter: blur(4px); }
    40%  { filter: var(--glass-blur-xs); }
    100% { opacity: 1; transform: none; filter: blur(0); }
}
.scroll-reveal-right {
    opacity: 0;
    will-change: transform, opacity, filter;
}
.scroll-reveal-right.scroll-reveal-visible {
    animation: animScrollRevealRight var(--scroll-reveal-duration) var(--easing-out) both;
}

/* 좌/우 스크롤 스태거 — 컨테이너 자식 순차 등장 */
.scroll-stagger-container > .scroll-reveal-left.scroll-reveal-visible,
.scroll-stagger-container > .scroll-reveal-right.scroll-reveal-visible {
    animation-delay: calc(var(--stagger-i, 0) * var(--scroll-stagger-gap));
}

/* ── §39-3  뱃지 스프링 업데이트 — 강한 5-bounce 오버슈트 ──
   §38-5 animBadgeBounce 대비: 5단계 바운스로 더 극적인 물리감.
   JS에서 카운트/상태 변경 시 .badge-spring-update 추가 → animationend로 제거. */
@keyframes animBadgeSpringUpdate {
    0%   { transform: scale(1); }
    20%  { transform: scale(1.35); }
    40%  { transform: scale(0.82); }
    60%  { transform: scale(1.12); }
    80%  { transform: scale(0.95); }
    100% { transform: scale(1); }
}
.badge-spring-update {
    animation: animBadgeSpringUpdate 450ms var(--easing-spring-bouncy) both;
    will-change: transform;
}


/* ═══════════════════════════════════════════
   §39r  접근성 — §39 + §37 v1 보강 reduced-motion
   ═══════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
    /* §39-1, §39-2 방향별 스크롤 리빌 */
    .scroll-reveal-left,
    .scroll-reveal-right {
        opacity: 1;
        transform: none;
        filter: none;
    }
    .scroll-reveal-left.scroll-reveal-visible,
    .scroll-reveal-right.scroll-reveal-visible {
        animation: none !important;
    }

    /* §39-3 뱃지 스프링 */
    .badge-spring-update {
        animation: none !important;
        transform: none;
    }

    /* §37 v1 reduced-motion 누락분 보강 */
    .scroll-reveal-blur {
        opacity: 1;
        filter: none;
        transform: none;
        transition: none !important;
    }
    .premium-alive-glow {
        animation: none !important;
    }
}


/* ═══════════════════════════════════════════
   §40  FLIP DOM + 히어로 + 마그네틱 스냅백 + 스크롤 스태거 블러
   ─────────────────────────────────────────
   WebAnimator 구현. §38 anim-* 유틸리티와 별개로
   JS FLIP 패턴 직접 연동(--flip-dx/dy CSS 변수),
   히어로 극적 진입, 마그네틱 키프레임 스냅백,
   스크롤 스태거 블러 컨테이너 등장.
   토큰: --duration-flip(500ms), --duration-dramatic(800ms),
         --duration-spring(400ms), --scroll-stagger-gap(50ms),
         --blur-reveal-from(12px), --scroll-reveal-distance(20px).
   GPU 가속만(transform/opacity/filter). 동시 blur 3개 이하.
   ═══════════════════════════════════════════ */

/* ── §40-1  FLIP Move — JS에서 --flip-dx/--flip-dy 주입 후 play ── */
@keyframes animFlipMove {
    from { transform: translate(var(--flip-dx, 0), var(--flip-dy, 0)); opacity: 0.7; }
    to   { transform: none; opacity: 1; }
}
.flip-move {
    animation: animFlipMove var(--duration-flip) var(--easing-in-out) both;
    /* will-change 제거 — 400ms 1회성 애니메이션에 영구 compositing layer 불필요 */
    backface-visibility: hidden;
}

/* FLIP Enter — 새 아이템 scale+fade 진입 */
@keyframes animFlipEnter {
    0%   { opacity: 0; transform: scale(0.85); }
    60%  { opacity: 1; transform: scale(1.03); }
    100% { transform: none; }
}
.flip-enter {
    animation: animFlipEnter var(--duration-flip) var(--easing-spring-gentle) both;
    will-change: transform, opacity;
}

/* FLIP Exit — 제거 아이템 축소+fade */
@keyframes animFlipExit {
    0%   { opacity: 1; transform: none; }
    100% { opacity: 0; transform: scale(0.85); }
}
.flip-exit {
    animation: animFlipExit var(--duration-base) var(--easing-in) both;
    pointer-events: none;
}

/* ── §40-2  히어로 극적 진입 — 페이지 레벨 1회성 ──
   blur+scale+Y 3중. --duration-dramatic(800ms) — 600ms MAX 예외. */
@keyframes animHeroEntrance {
    0%   { opacity: 0; filter: blur(var(--blur-reveal-from, 12px)); transform: translateY(16px) scale(0.96); }
    25%  { opacity: 0.4; filter: var(--glass-blur-xs); }
    60%  { opacity: 0.9; filter: var(--glass-blur-xs); transform: translateY(-2px) scale(1.003); }
    100% { opacity: 1; filter: blur(0); transform: none; }
}
.hero-entrance {
    animation: animHeroEntrance var(--duration-dramatic) var(--easing-out) both;
    will-change: filter, opacity, transform;
}

/* ── §40-3  마그네틱 스냅백 — 오버슈트 다단 바운스 복귀 ──
   JS mouseleave 시 --mag-x/--mag-y(마지막 오프셋) 주입.
   transition 기반 magnetic-target(§37-2)과 달리 키프레임 오버슈트. */
@keyframes animMagneticSnapback {
    0%   { transform: translate(var(--mag-x, 0), var(--mag-y, 0)); }
    45%  { transform: translate(
               calc(var(--mag-x, 0) * -0.12),
               calc(var(--mag-y, 0) * -0.12)
           ); }
    70%  { transform: translate(
               calc(var(--mag-x, 0) * 0.04),
               calc(var(--mag-y, 0) * 0.04)
           ); }
    100% { transform: none; }
}
.magnetic-snapback {
    animation: animMagneticSnapback var(--duration-spring) var(--easing-spring-gentle) both;
    will-change: transform;
}

/* ── §40-4  스크롤 스태거 블러 — IO 컨테이너 순차 등장 ──
   부모에 .scroll-stagger-blur, JS에서 IO 감지 시 .scroll-stagger-active 추가.
   자식에 --stagger-i 주입. blur+slide+scale 3중 등장. */
@keyframes animScrollStaggerBlur {
    0%   { opacity: 0; filter: blur(6px); transform: translateY(var(--scroll-reveal-distance, 20px)) scale(0.97); }
    40%  { opacity: 0.7; filter: var(--glass-blur-xs); }
    100% { opacity: 1; filter: blur(0); transform: none; }
}
.scroll-stagger-blur > * {
    opacity: 0;
}
.scroll-stagger-blur.scroll-stagger-active > * {
    animation: animScrollStaggerBlur var(--duration-moderate) var(--easing-out) forwards;
    animation-delay: calc(var(--stagger-i, 0) * var(--scroll-stagger-gap, 50ms));
    will-change: filter, opacity, transform;
}


/* ── §40-R  Reduced motion ── */
@media (prefers-reduced-motion: reduce) {
    .flip-move,
    .flip-enter,
    .flip-exit {
        animation: none !important;
        opacity: 1;
        transform: none;
    }
    .hero-entrance {
        animation: none !important;
        opacity: 1;
        filter: none;
        transform: none;
    }
    .magnetic-snapback {
        animation: none !important;
        transform: none;
    }
    .scroll-stagger-blur > * {
        opacity: 1;
    }
    .scroll-stagger-blur.scroll-stagger-active > * {
        animation: none !important;
        opacity: 1;
        filter: none;
        transform: none;
    }
}


/* ═══════════════════════════════════════════
   §41  프리미엄 인터랙션 v2 — 텍스트 블러 리빌 + 카운터 슬라이드
   ─────────────────────────────────────────
   1000억급 "와" 효과 추가 키프레임.
   animBlurRevealText — 탭/패널 전환 시 텍스트 blur→선명 + 상승
   animCountUpSlide   — 카운터 숫자 오버슈트 슬라이드 업
   GPU 가속(transform/opacity/filter)만 사용. 600ms 이내.
   ═══════════════════════════════════════════ */

/* ── §41-1  블러 리빌 텍스트 — blur --blur-reveal-from→0 + translateY --blur-reveal-y→0 + opacity 0→1 ──
   탭 전환, 패널 진입 시 제목/헤더에 프리미엄 진입감.
   기존 animBlurReveal(§27-3)과 달리 scale 없이 translateY로 상승 효과.
   tokens.css의 --blur-reveal-y(8px), --blur-reveal-from(12px) 토큰 참조.
   will-change: filter, transform, opacity 필수. */

@keyframes animBlurRevealText {
    0%   { opacity: 0; filter: blur(var(--blur-reveal-from, 12px)); transform: translateY(var(--blur-reveal-y, 8px)); }
    40%  { opacity: 0.7; filter: blur(calc(var(--blur-reveal-from, 12px) / 3)); transform: translateY(calc(var(--blur-reveal-y, 8px) * 0.25)); }
    70%  { opacity: 0.95; filter: var(--glass-blur-xs); transform: translateY(0); }
    100% { opacity: 1; filter: blur(0); transform: none; }
}

.blur-reveal-text {
    animation: animBlurRevealText 500ms var(--easing-out) both;
    will-change: filter, transform, opacity;
    backface-visibility: hidden;
}


/* ── §41-2  카운트 업 슬라이드 — 숫자 카운터 오버슈트 진입 ──
   뱃지 카운터, 통계 숫자 변경 시 아래→위 슬라이드 + 스프링 안착.
   오버슈트(-8%) + 리바운드로 물리감 극대화.
   GPU 가속: transform + opacity만 사용. */

@keyframes animCountUpSlide {
    0%   { opacity: 0; transform: translateY(100%); }
    50%  { opacity: 1; transform: translateY(-8%); }
    75%  { transform: translateY(3%); }
    100% { transform: none; }
}

.count-up-slide {
    display: inline-block;
    animation: animCountUpSlide 350ms var(--easing-spring-bouncy) both;
    will-change: transform;
    backface-visibility: hidden;
}


/* ── §41-3  파티클 버스트 — 확대 폭발 + 페이드아웃 ──
   리플 잔향, 삭제 피드백, 알림 dismiss 후 확산 이펙트.
   scale(0)→scale(4) + opacity 1→0. GPU 가속: transform + opacity. */

@keyframes animParticleBurst {
    0%   { opacity: 1; transform: scale(0); }
    40%  { opacity: 0.6; transform: scale(2); }
    100% { opacity: 0; transform: scale(4); }
}

.particle-burst {
    animation: animParticleBurst var(--duration-moderate) var(--easing-out) both;
    will-change: transform, opacity;
    pointer-events: none;
}


/* ── §41-4  러버밴드 — 탄성 스케일 바운스 ──
   성공 체크, 뱃지 변경, 강조 탭 시 탄력 피드백.
   scale 1→1.3→0.9→1 3단계 오버슈트. GPU 가속: transform. */

@keyframes animRubberBand {
    0%   { transform: scale(1); }
    35%  { transform: scale(1.3); }
    65%  { transform: scale(0.9); }
    100% { transform: scale(1); }
}

.rubber-band {
    animation: animRubberBand var(--duration-moderate) var(--easing-elastic) both;
    will-change: transform;
    backface-visibility: hidden;
}


/* ── §41-5  글로우 버스트 — accent 발광 단발 파동 ──
   활성 상태 강조, 알림 어텐션, CTA 강조 시 사용.
   box-shadow 0→glow→0 단발(one-shot). 기존 animGlowPulse(§초반, 2.5s infinite)와 별개.
   ⚠️ paint 비용 있으므로 동시 3개 이하 권장. */

@keyframes animGlowBurst {
    0%, 100% { box-shadow: 0 0 0 var(--accent-transparent), 0 0 0 var(--accent-transparent); }
    50%      { box-shadow: 0 0 20px var(--clr-teal-bg-lg), 0 0 40px var(--clr-teal-bg-xs); }
}

.glow-burst {
    animation: animGlowBurst var(--duration-moderate) var(--easing-smooth) both;
}


/* ── §41-6  스트로크 드로우 — SVG 패스 그리기 ──
   체크마크 드로우, 진행 표시, 장식 라인 등장.
   stroke-dashoffset 100→0. SVG에 stroke-dasharray: 100 필수.
   GPU 가속: stroke-dashoffset (합성 레이어 비트리거). */

@keyframes animStrokeDraw {
    from { stroke-dashoffset: 100; }
    to   { stroke-dashoffset: 0; }
}

.stroke-draw {
    stroke-dasharray: 100;
    animation: animStrokeDraw var(--duration-spring) var(--easing-out) both;
}


/* ── §41-R  Reduced motion — §41 전체 ── */
@media (prefers-reduced-motion: reduce) {
    .blur-reveal-text {
        animation: none !important;
        opacity: 1;
        filter: none;
        transform: none;
    }
    .count-up-slide {
        animation: none !important;
        opacity: 1;
        transform: none;
    }
    .particle-burst {
        animation: none !important;
        opacity: 0;
        transform: none;
    }
    .rubber-band {
        animation: none !important;
        transform: none;
    }
    .glow-burst {
        animation: none !important;
        box-shadow: none;
    }
    .stroke-draw {
        animation: none !important;
        stroke-dashoffset: 0;
    }
}


/* ═══════════════════════════════════════════
   §42  JS 연동 누락 셀렉터 보강
   ─────────────────────────────────────────
   core.js initRipple / IntersectionObserver가
   참조하지만 CSS 정의가 누락된 셀렉터 보강.
   GPU 가속(transform/opacity)만 사용.
   ═══════════════════════════════════════════ */

/* ── §42-1  .ripple-accent 독립 사용 — initRipple() 연동 ──
   .ripple-container 없이 .ripple-accent만 가진 요소에서
   JS가 .ripple 자식 span을 동적 생성.
   기존 .ripple-container > .ripple(§28-6)과 동일한 스타일링을
   standalone .ripple-accent에도 적용. */
.ripple-accent:not(.ripple-container) {
    position: relative;
    overflow: hidden;
}
.ripple-accent:not(.ripple-container) > .ripple {
    position: absolute;
    border-radius: 50%;
    background: var(--ripple-accent, var(--accent-glow));
    transform: scale(0);
    animation: animRipple var(--ripple-duration, 500ms) var(--easing-out) forwards;
    pointer-events: none;
    will-change: transform, opacity;
}

/* ── §42-2  .scroll-stagger-group 초기 숨김 — IO 트리거 전 flash 방지 ──
   core.js IntersectionObserver가 자식에 .scroll-reveal + .revealed 추가.
   IO 트리거 전까지 자식을 숨겨 FOUC 방지.
   .scroll-reveal(§28-3), .scroll-reveal.revealed가 실제 전환 처리. */
/* [HOTFIX] scroll-stagger-group opacity:0 비활성화 — 산출물 카드 숨김 문제 근본 수정 */
/* .scroll-stagger-group > *:not(.revealed) {
    opacity: 0;
    transform: translateY(var(--scroll-reveal-distance, 20px));
} */


/* ── §42-R  Reduced motion — §42 전체 ── */
@media (prefers-reduced-motion: reduce) {
    .ripple-accent:not(.ripple-container) > .ripple {
        animation: none !important;
        opacity: 0;
    }
    .scroll-stagger-group > * {
        opacity: 1 !important;
        transform: none !important;
    }
}

/* ── §42-T  터치 디바이스 — §42 리플 시간 단축 ── */
@media (hover: none) {
    .ripple-accent:not(.ripple-container) > .ripple {
        animation-duration: 300ms;
    }
}


/* ═══════════════════════════════════════════
   §43  3D 온톨로지 그래프 — 컨테이너 모션
   ─────────────────────────────────────────
   ForceGraph3D 래퍼의 진입/전환/로딩 애니메이션.
   실제 3D 오브젝트 모션(토러스, 오비탈)은 prompts.js
   rAF 루프에서 THREE.js 직접 제어.
   ═══════════════════════════════════════════ */

/* 그래프 컨테이너 진입 — 탭 전환 시 페이드+스케일 */
@keyframes anim3dGraphEnter {
    from { opacity: 0; transform: scale(0.97); }
    to   { opacity: 1; transform: none; }
}

.node-graph.graph-enter {
    animation: anim3dGraphEnter var(--duration-base, 200ms) var(--easing-out) both;
}

/* 그래프 캔버스 GPU 가속 힌트 */
.node-graph canvas {
    will-change: contents;
    backface-visibility: hidden;
}

/* 3D 호버 툴팁 — 노드 위에 표시되는 정보 패널 */
@keyframes anim3dTooltipIn {
    from { opacity: 0; transform: translateY(4px) scale(0.96); }
    to   { opacity: 1; transform: none; }
}
@keyframes anim3dTooltipOut {
    from { opacity: 1; transform: none; }
    to   { opacity: 0; transform: translateY(4px) scale(0.96); }
}

/* .graph-tooltip 구조 + 애니메이션 → §43-5로 통합 (OV1 중복 방지) */
.graph-tooltip.hiding {
    animation: anim3dTooltipOut var(--duration-fast, 120ms) var(--easing-in) both;
}

/* 그래프 로딩 오버레이 — 3D 씬 빌드 중 표시 */
@keyframes anim3dGraphLoading {
    0%   { opacity: 0.3; }
    50%  { opacity: 0.6; }
    100% { opacity: 0.3; }
}

.node-graph-loading {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--bg) 70%, transparent);
    animation: anim3dGraphLoading 1.5s var(--easing-smooth) infinite;
    z-index: 10;
    pointer-events: none;
    border-radius: inherit;
}

/* 그래프 줌 트랜지션 — JS 카메라 줌 중 컨테이너 비네트 */
.node-graph.zooming::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 5;
    background: radial-gradient(
        ellipse at center,
        transparent 50%,
        color-mix(in srgb, var(--bg) 25%, transparent) 100%
    );
    opacity: 0;
    animation: animFadeIn var(--duration-base, 200ms) var(--easing-out) forwards;
}

/* ── §43-R  Reduced motion — 3D 그래프 ── */
@media (prefers-reduced-motion: reduce) {
    .node-graph.graph-enter {
        animation: none;
        opacity: 1;
    }
    .graph-tooltip {
        animation: none;
        opacity: 1;
    }
    .node-graph-loading {
        animation: none;
        opacity: 0.5;
    }
    .node-graph.zooming::after {
        animation: none;
        opacity: 0;
    }
}


/* ═══════════════════════════════════════════
   §43-2  3D 그래프 — 컨테이너 퇴장 모션
   ─────────────────────────────────────────
   탭 전환 시 그래프 컨테이너 페이드+스케일 퇴장.
   JS에서 .graph-exit 추가 → animationend 후 제거.
   ═══════════════════════════════════════════ */

@keyframes anim3dGraphExit {
    from { opacity: 1; transform: none; }
    to   { opacity: 0; transform: scale(0.97); }
}

.node-graph.graph-exit {
    animation: anim3dGraphExit var(--duration-base, 200ms) var(--easing-in) both;
}


/* ═══════════════════════════════════════════
   §43-3  3D 그래프 — 노드 포커스 상태
   ─────────────────────────────────────────
   노드 클릭(선택) 시 컨테이너 레벨 시각 피드백.
   ::before로 내부 accent 글로우 + 비네트 강화.
   GPU 가속: opacity만 전환.
   ═══════════════════════════════════════════ */

.node-graph.node-focused::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    z-index: 4;
    background: radial-gradient(
        ellipse at center,
        transparent 40%,
        var(--clr-accent-bg-xs) 80%,
        var(--accent-dim) 100%
    );
    opacity: 0;
    animation: animFadeIn var(--duration-base, 200ms) var(--easing-out) forwards;
    will-change: opacity;
}

/* 포커스 해제 시 퇴장 */
.node-graph.node-unfocusing::before {
    animation: animFadeOut var(--duration-base, 200ms) var(--easing-in) forwards;
}


/* ═══════════════════════════════════════════
   §43-4  3D 그래프 — 앰비언트 호흡
   ─────────────────────────────────────────
   idle 상태에서 컨테이너 미세 호흡 글로우.
   accent 글로우가 은은하게 펄싱하여 "살아있는" 느낌.
   ═══════════════════════════════════════════ */

@keyframes anim3dAmbientBreath {
    0%, 100% { opacity: 0; }
    50%      { opacity: 1; }
}

.node-graph.graph-ambient::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 2;
    border-radius: inherit;
    background: radial-gradient(
        ellipse at 50% 50%,
        var(--clr-teal-bg-2xs) 0%,
        transparent 70%
    );
    animation: anim3dAmbientBreath 5s var(--easing-in-out) infinite;
    will-change: opacity;
}


/* ═══════════════════════════════════════════
   §43-5  3D 그래프 — 프리미엄 툴팁 스타일
   ─────────────────────────────────────────
   호버 시 표시되는 노드 정보 패널.
   글래스모피즘 + accent 글로우 보더.
   ═══════════════════════════════════════════ */

.graph-tooltip {
    position: absolute;
    z-index: 20;
    padding: var(--s-2) var(--s-3);
    background: var(--glass-dark-dense);
    backdrop-filter: var(--glass-blur-md);
    -webkit-backdrop-filter: var(--glass-blur-md);
    border-radius: var(--radius-s);
    color: var(--text, #ededef);
    font-size: var(--text-sm);
    font-family: var(--font);
    line-height: 1.4;
    pointer-events: none;
    max-width: var(--card-min-sm);
    box-shadow: var(--shadow-3d-tooltip);
    animation: anim3dTooltipIn var(--duration-fast, 120ms) var(--easing-out) both;
    will-change: transform, opacity;
}

.graph-tooltip-title {
    font-weight: 600;
    color: var(--accent, #2dd4bf);
    margin-bottom: var(--s-1);
}

.graph-tooltip-status {
    font-size: var(--text-sm);
    color: var(--text-secondary, #9399a8);
    display: flex;
    align-items: center;
    gap: var(--s-1-5);
}

.graph-tooltip-dot {
    display: inline-block;
    width: var(--s-1-5);
    height: var(--s-1-5);
    border-radius: 50%;
    flex-shrink: 0;
}

.graph-tooltip-info {
    margin-top: var(--s-1);
    padding-top: var(--s-1);
    border-top: 1px solid var(--border-subtle);
    font-size: var(--text-xs);
    color: var(--text-muted, #505058);
    line-height: 1.6;
}


/* ═══════════════════════════════════════════
   §43-6  3D 그래프 — 팀 전환 크로스페이드
   ─────────────────────────────────────────
   currentTeam 변경 시 그래프 전체 크로스페이드.
   exit → destroy → rebuild → enter 시퀀스용.
   ═══════════════════════════════════════════ */

@keyframes anim3dTeamSwitch {
    0%   { opacity: 0; transform: scale(0.95) rotateY(3deg); }
    100% { opacity: 1; transform: none; }
}

.node-graph.team-switching {
    animation: anim3dTeamSwitch var(--duration-moderate) var(--easing-out) both;
    will-change: transform, opacity;
}


/* ═══════════════════════════════════════════
   §43-7  3D 그래프 — 줌 인/아웃 오버레이 강화
   ─────────────────────────────────────────
   노드 줌인 시 비네트 + 포커스 라인.
   줌아웃(원위치 복귀) 시 비네트 해제 트랜지션.
   ═══════════════════════════════════════════ */

.node-graph.zoom-in::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 5;
    background: radial-gradient(
        ellipse at center,
        transparent 35%,
        color-mix(in srgb, var(--bg) 35%, transparent) 100%
    );
    opacity: 0;
    animation: animFadeIn var(--duration-moderate) var(--easing-out) forwards;
    will-change: opacity;
}

.node-graph.zoom-out::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 5;
    background: radial-gradient(
        ellipse at center,
        transparent 35%,
        color-mix(in srgb, var(--bg) 35%, transparent) 100%
    );
    opacity: 1;
    animation: animFadeOut var(--duration-moderate) var(--easing-in) forwards;
    will-change: opacity;
}


/* ═══════════════════════════════════════════
   §43-8  3D 그래프 — 로딩 스켈레톤 시머
   ─────────────────────────────────────────
   3D 씬 빌드 대기 중 스켈레톤 시머 효과.
   ═══════════════════════════════════════════ */

@keyframes anim3dSkeleton {
    0%   { background-position: -200% 0; }
    100% { background-position: 200% 0; }
}

.node-graph-skeleton {
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    z-index: 8;
    background: linear-gradient(
        90deg,
        transparent 0%,
        var(--clr-accent-bg-xs) 40%,
        var(--clr-accent-bg-sm) 50%,
        var(--clr-accent-bg-xs) 60%,
        transparent 100%
    );
    background-size: 200% 100%;
    animation: anim3dSkeleton 2s var(--easing-smooth) infinite;
    will-change: background-position;
}


/* ── §43-2R  Reduced motion — §43-2~§43-8 전체 ── */
@media (prefers-reduced-motion: reduce) {
    .node-graph.graph-exit {
        animation: none;
        opacity: 0;
    }
    .node-graph.node-focused::before,
    .node-graph.node-unfocusing::before {
        animation: none;
        opacity: 0;
    }
    .node-graph.graph-ambient::after {
        animation: none;
        opacity: 0;
    }
    .node-graph.team-switching {
        animation: none;
        opacity: 1;
    }
    .node-graph.zoom-in::after,
    .node-graph.zoom-out::after {
        animation: none;
        opacity: 0;
    }
    .node-graph-skeleton {
        animation: none;
        opacity: 0;
    }
    .zoom-back-btn {
        animation: none !important;
    }
}

/* ═══════════════════════════════════════════
   §43-9  3D 그래프 — 줌백 버튼 진입 모션
   ─────────────────────────────────────────
   노드 줌인 시 표시되는 '전체 보기' 버튼.
   scale + fade 진입. 기본 스타일은 agents.css.
   ═══════════════════════════════════════════ */
@keyframes anim3dZoomBackIn {
    from { opacity: 0; transform: scale(0.85) translateY(-4px); }
    to   { opacity: 1; transform: none; }
}

.zoom-back-btn[style*="display: flex"] {
    animation: anim3dZoomBackIn var(--duration-base) var(--easing-out) both;
    /* will-change 제거 — 400ms 1회성 애니메이션에 영구 compositing layer 불필요 */
    backface-visibility: hidden;
}


/* ═══════════════════════════════════════════
   §43-10  3D 그래프 — 카메라 줌 트레일
   ─────────────────────────────────────────
   노드 클릭 → 카메라 줌인 시 방사형 스피드 라인.
   JS에서 .zoom-trail 추가 → 2초 후 자동 제거.
   ═══════════════════════════════════════════ */
@keyframes anim3dZoomTrail {
    0%   { opacity: 0; transform: scale(0.9); }
    20%  { opacity: 1; transform: scale(1); }
    100% { opacity: 0; transform: scale(1.05); }
}

.node-graph.zoom-trail::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 6;
    border-radius: inherit;
    background: radial-gradient(
        ellipse at center,
        transparent 25%,
        var(--clr-accent-bg-xs) 50%,
        var(--clr-accent-bg-sm) 70%,
        transparent 100%
    );
    animation: anim3dZoomTrail 1.2s var(--easing-out) both;
    will-change: transform, opacity;
}


/* ═══════════════════════════════════════════
   §43-11  3D 그래프 — 스태거 진입 시머
   ─────────────────────────────────────────
   노드 스태거 출현 중 컨테이너 상단 시머 스윕.
   JS에서 .entrance-shimmer 추가 → 완료 후 제거.
   ═══════════════════════════════════════════ */
@keyframes anim3dEntranceShimmer {
    0%   { background-position: -100% 0; opacity: 0.6; }
    60%  { opacity: 0.4; }
    100% { background-position: 200% 0; opacity: 0; }
}

.node-graph.entrance-shimmer::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 7;
    border-radius: inherit;
    background: linear-gradient(
        110deg,
        transparent 30%,
        var(--clr-accent-bg-xs) 45%,
        var(--clr-purple-bg-2xs) 55%,
        transparent 70%
    );
    background-size: 200% 100%;
    animation: anim3dEntranceShimmer 2s var(--easing-out) both;
    will-change: background-position, opacity;
}


/* ═══════════════════════════════════════════
   §43-12  3D 그래프 — 툴팁 상태 펄스
   ─────────────────────────────────────────
   working 상태 노드 호버 시 툴팁 내 상태 도트 펄싱.
   ═══════════════════════════════════════════ */
@keyframes anim3dStatusPulse {
    0%, 100% { transform: scale(1); opacity: 0.8; }
    50%      { transform: scale(1.4); opacity: 1; }
}

.graph-tooltip-dot.working {
    animation: anim3dStatusPulse 1.5s var(--easing-in-out) infinite;
    will-change: transform, opacity;
}

.graph-tooltip-dot.error {
    animation: anim3dStatusPulse var(--duration-dramatic) var(--easing-in-out) infinite;
}


/* ═══════════════════════════════════════════
   §43-13  3D 그래프 — 프리미엄 아이들 스파클
   ─────────────────────────────────────────
   idle 상태에서 미세 반짝임 오버레이.
   §43-4 앰비언트 호흡과 레이어 분리 (z-index 1).
   JS에서 .graph-idle-sparkle 추가.
   ═══════════════════════════════════════════ */
@keyframes anim3dIdleSparkle {
    0%   { background-position: 0% 0%; opacity: 0; }
    25%  { opacity: 0.03; }
    50%  { background-position: 100% 100%; opacity: 0; }
    75%  { opacity: 0.02; }
    100% { background-position: 0% 0%; opacity: 0; }
}

.node-graph.graph-idle-sparkle::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 1;
    border-radius: inherit;
    background-image:
        radial-gradient(1px 1px at 20% 30%, var(--clr-accent-bg-4xl) 0%, transparent 100%),
        radial-gradient(1px 1px at 60% 70%, var(--clr-purple-bg-2xl) 0%, transparent 100%),
        radial-gradient(1px 1px at 80% 20%, var(--surface-w20) 0%, transparent 100%),
        radial-gradient(1px 1px at 40% 80%, var(--clr-accent-bg-3xl) 0%, transparent 100%);
    background-size: 300% 300%;
    animation: anim3dIdleSparkle 8s var(--easing-in-out) infinite;
    will-change: background-position, opacity;
}


/* ═══════════════════════════════════════════
   §43-14  3D 그래프 — 연결 하이라이트 글로우
   ─────────────────────────────────────────
   노드 호버 시 컨테이너 하단에 accent 글로우 반영.
   JS에서 .link-highlight 추가/제거.
   ═══════════════════════════════════════════ */
@keyframes anim3dLinkGlow {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.node-graph.link-highlight::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 10%;
    right: 10%;
    height: 40%;
    pointer-events: none;
    z-index: 3;
    border-radius: inherit;
    background: radial-gradient(
        ellipse at 50% 100%,
        var(--clr-accent-bg-xs) 0%,
        transparent 70%
    );
    animation: anim3dLinkGlow var(--duration-fast, 120ms) var(--easing-out) both;
    will-change: opacity;
}


/* ═══════════════════════════════════════════
   §43-15  3D 그래프 — 카메라 줌백 리셋 펄스
   ─────────────────────────────────────────
   줌아웃 복귀 시 원점 도달 순간 미세 리셋 펄스.
   JS에서 .zoom-reset-pulse 추가 → animationend 후 제거.
   ═══════════════════════════════════════════ */
@keyframes anim3dResetPulse {
    0%   { opacity: 0; transform: scale(1.02); }
    30%  { opacity: 0.06; }
    100% { opacity: 0; transform: scale(1); }
}

.node-graph.zoom-reset-pulse::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 6;
    border-radius: inherit;
    background: radial-gradient(
        circle at center,
        var(--clr-accent-bg-md) 0%,
        transparent 60%
    );
    animation: anim3dResetPulse var(--duration-slower) var(--easing-out) both;
    will-change: transform, opacity;
}


/* ── §43-10~15R  Reduced motion — 프리미엄 3D 확장 ── */
@media (prefers-reduced-motion: reduce) {
    .node-graph.zoom-trail::before,
    .node-graph.entrance-shimmer::after,
    .node-graph.graph-idle-sparkle::before,
    .node-graph.link-highlight::after,
    .node-graph.zoom-reset-pulse::before {
        animation: none;
        opacity: 0;
    }
    .graph-tooltip-dot.working,
    .graph-tooltip-dot.error {
        animation: none;
    }
}

/* ═══════════════════════════════════════════
   §40  프리미엄 상태 변경 펄스 — 에이전트 카드/뱃지 상태 전환 시 시각 피드백
   ═══════════════════════════════════════════ */

/* §40-1 카드 상태 변경 — 외곽 링 펄스 (JS에서 .status-change-pulse 토글) */
.status-change-pulse {
    animation: animStatusChangePulse 600ms var(--easing-out) forwards;
}
@keyframes animStatusChangePulse {
    0%   { box-shadow: 0 0 0 0 var(--accent-glow); }
    40%  { box-shadow: 0 0 0 6px var(--accent-glow); }
    100% { box-shadow: 0 0 0 0 transparent; }
}

/* §40-2 상태 도트 펄스 — 상태 전환 순간 강조 링 */
.status-dot-pulse {
    animation: animStatusDotPulse 500ms var(--easing-out) forwards;
}
@keyframes animStatusDotPulse {
    0%   { box-shadow: 0 0 0 0 currentColor; }
    50%  { box-shadow: 0 0 0 4px transparent; }
    100% { box-shadow: none; }
}

@media (prefers-reduced-motion: reduce) {
    .status-change-pulse,
    .status-dot-pulse {
        animation: none;
    }
}


/* ═══════════════════════════════════════════
   §44  프리미엄 뷰 트랜지션 — 탭/페이지 전환 크로스페이드 + 슬라이드
   ─────────────────────────────────────────
   기존 §5 animTabEnter(단순 fadeY 6px)를 보강.
   크로스페이드 + 방향성 슬라이드 + 블러→선명 조합.
   GPU 가속 속성만 (transform/opacity/filter). 600ms 이내.
   ═══════════════════════════════════════════ */

/* ── §44-3  탭 프리미엄 진입 — 블러리빌 + 미세 스케일 + 스태거 자식 ── */
@keyframes animTabPremiumEnter {
    0%   { opacity: 0; transform: translateY(8px) scale(0.985); filter: var(--glass-blur-xs); }
    50%  { opacity: 0.8; filter: var(--glass-blur-xs); }
    80%  { transform: translateY(-1px) scale(1.002); }
    100% { opacity: 1; transform: none; filter: blur(0); }
}
.tab-premium-enter {
    animation: animTabPremiumEnter var(--duration-swift) var(--easing-organic) both;
    will-change: transform, opacity, filter;
}
/* 탭 내 자식 스태거 (직계 자식 최대 5개, 20ms 간격) */
.tab-premium-enter > *:nth-child(1) { animation-delay: 20ms; }
.tab-premium-enter > *:nth-child(2) { animation-delay: 40ms; }
.tab-premium-enter > *:nth-child(3) { animation-delay: 60ms; }
.tab-premium-enter > *:nth-child(4) { animation-delay: 80ms; }
.tab-premium-enter > *:nth-child(5) { animation-delay: 100ms; }

/* ── §44-4  탭 프리미엄 퇴장 — 빠른 블러 축소 ── */
@keyframes animTabPremiumExit {
    0%   { opacity: 1; transform: none; filter: blur(0); }
    100% { opacity: 0; transform: translateY(-6px) scale(0.98); filter: var(--glass-blur-xs); }
}
.tab-premium-exit {
    animation: animTabPremiumExit var(--duration-instant) var(--easing-in) forwards;
    pointer-events: none;
}


/* ═══════════════════════════════════════════
   §45  프리미엄 카드 캐스케이드 — 블러 리빌 스태거 등장
   ─────────────────────────────────────────
   카드/리스트 아이템이 blur→선명 + scale→1 + 아래→위 순차 등장.
   JS에서 컨테이너에 .card-cascade 추가 시 트리거.
   ═══════════════════════════════════════════ */

/* ── §45-1  카드 캐스케이드 키프레임 — 블러+스케일+트랜슬레이트 3단계 ── */
@keyframes animCardCascade {
    0%   { opacity: 0; transform: translateY(12px) scale(0.96); filter: var(--glass-blur-xs); }
    40%  { opacity: 0.7; filter: var(--glass-blur-xs); }
    75%  { transform: translateY(-2px) scale(1.005); filter: blur(0); }
    100% { opacity: 1; transform: none; filter: blur(0); }
}

/* 컨테이너 자식에 자동 적용 (최대 12개) */
.card-cascade > * {
    animation: animCardCascade var(--duration-moderate) var(--easing-organic) both;
    will-change: transform, opacity, filter;
}
.card-cascade > *:nth-child(1)  { animation-delay: 0ms; }
.card-cascade > *:nth-child(2)  { animation-delay: 40ms; }
.card-cascade > *:nth-child(3)  { animation-delay: 80ms; }
.card-cascade > *:nth-child(4)  { animation-delay: 120ms; }
.card-cascade > *:nth-child(5)  { animation-delay: 160ms; }
.card-cascade > *:nth-child(6)  { animation-delay: 200ms; }
.card-cascade > *:nth-child(7)  { animation-delay: 240ms; }
.card-cascade > *:nth-child(8)  { animation-delay: 280ms; }
.card-cascade > *:nth-child(9)  { animation-delay: 320ms; }
.card-cascade > *:nth-child(10) { animation-delay: 360ms; }
.card-cascade > *:nth-child(11) { animation-delay: 400ms; }
.card-cascade > *:nth-child(12) { animation-delay: 440ms; }

/* ═══════════════════════════════════════════
   §46  드로어/모달 프리미엄 스프링 — 다단계 바운스 + 백드롭 블러
   ─────────────────────────────────────────
   §19b 기본 스프링을 초월하는 다단계 오버슈트 진입.
   GPU 가속만. 600ms 이내. prefers-reduced-motion 존중.
   ═══════════════════════════════════════════ */

/* ── §46-1  드로어 프리미엄 진입 — 3단계 스프링 바운스 ── */
@keyframes animDrawerPremiumIn {
    0%   { opacity: 0; transform: translateX(32px) scale(0.98); filter: var(--glass-blur-xs); }
    35%  { opacity: 1; transform: translateX(-4px) scale(1.01); filter: blur(0); }
    60%  { transform: translateX(2px) scale(0.998); }
    80%  { transform: translateX(-1px); }
    100% { transform: none; }
}
.drawer-premium-in {
    animation: animDrawerPremiumIn var(--duration-spring) var(--easing-out) both;
    will-change: transform, opacity, filter;
}

/* ── §46-2  드로어 프리미엄 퇴장 — 가속 + 블러 ── */
@keyframes animDrawerPremiumOut {
    0%   { opacity: 1; transform: none; filter: blur(0); }
    40%  { opacity: 0.6; }
    100% { opacity: 0; transform: translateX(32px) scale(0.97); filter: var(--glass-blur-xs); }
}
.drawer-premium-out {
    animation: animDrawerPremiumOut var(--duration-base) var(--easing-in) forwards;
    pointer-events: none;
}

/* ── §46-3  모달 프리미엄 진입 — 스케일 + 블러 3단계 바운스 ── */
@keyframes animModalPremiumIn {
    0%   { opacity: 0; transform: scale(0.88) translateY(12px); filter: var(--glass-blur-xs); }
    30%  { opacity: 0.9; filter: var(--glass-blur-xs); }
    55%  { transform: scale(1.02) translateY(-2px); filter: blur(0); }
    75%  { transform: scale(0.995) translateY(1px); }
    100% { opacity: 1; transform: none; }
}
.modal-premium-in {
    animation: animModalPremiumIn var(--duration-spring) var(--easing-out) both;
    will-change: transform, opacity, filter;
}

/* ── §46-4  모달 프리미엄 퇴장 — 축소 + 블러아웃 ── */
@keyframes animModalPremiumOut {
    0%   { opacity: 1; transform: none; filter: blur(0); }
    100% { opacity: 0; transform: scale(0.92) translateY(8px); filter: var(--glass-blur-xs); }
}
.modal-premium-out {
    animation: animModalPremiumOut var(--duration-fast) var(--easing-in) forwards;
    pointer-events: none;
}

/* ── §46-5  백드롭 블러 진입 — 오버레이 배경 블러 전환 ── */
@keyframes animBackdropBlurIn {
    0%   { opacity: 0; backdrop-filter: blur(0); }
    100% { opacity: 1; backdrop-filter: var(--glass-blur-sm); }
}
.backdrop-premium-in {
    animation: animBackdropBlurIn var(--duration-moderate) var(--easing-out) both;
}

/* ── §46-6  백드롭 블러 퇴장 ── */
@keyframes animBackdropBlurOut {
    0%   { opacity: 1; backdrop-filter: var(--glass-blur-sm); }
    100% { opacity: 0; backdrop-filter: blur(0); }
}
.backdrop-premium-out {
    animation: animBackdropBlurOut var(--duration-fast) var(--easing-in) forwards;
}

/* ═══════════════════════════════════════════
   §47  프리미엄 모션 유틸리티
   ─────────────────────────────────────────
   §44~§46 보조 유틸리티 (Sheen, 숫자 리빌, 마이크로 인터랙션).
   ═══════════════════════════════════════════ */

/* ── §47-4  Sheen 효과 — 카드/패널 호버 시 왼→오 광택 ── */
@keyframes animSheenSwipe {
    0%   { transform: translateX(-100%) skewX(-15deg); }
    100% { transform: translateX(200%) skewX(-15deg); }
}
.premium-sheen {
    position: relative;
}
/* sheen 효과를 자식 .sheen-layer 요소로 구현 — tooltip ::after와 충돌 없음 */
.premium-sheen .sheen-layer {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
    pointer-events: none;
    z-index: 2;
    border-radius: inherit;
}
.premium-sheen .sheen-layer::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 50%;
    height: 100%;
    background: linear-gradient(
        90deg,
        transparent,
        var(--surface-w4),
        transparent
    );
    transform: translateX(-100%) skewX(-15deg);
    pointer-events: none;
    border-radius: inherit;
}
.premium-sheen:hover .sheen-layer::after {
    animation: animSheenSwipe 500ms var(--easing-out) forwards;
}

/* ── §47-5  숫자 카운트업 프리미엄 — 오버슈트 + 블러 ── */
@keyframes animNumberReveal {
    0%   { opacity: 0; transform: translateY(100%) scale(0.9); filter: var(--glass-blur-xs); }
    60%  { opacity: 1; transform: translateY(-5%); filter: blur(0); }
    80%  { transform: translateY(2%); }
    100% { transform: none; }
}
.anim-number-reveal {
    animation: animNumberReveal var(--duration-moderate) var(--easing-spring-bouncy) both;
    will-change: transform, opacity, filter;
}

/* ── §48  마이크로 인터랙션 — 버튼 프레스 피드백 ── */
/* 공통 :active 프레스 (스케일 + 밝기 감소) — 기존에 없는 버튼 대상 */
.mc-tab:active,
.mc-action-btn:active,
.chip-toggle-capsule:active,
.tone-capsule:active,
.shortcut-type-btn:active,
.feedback-btn:active,
.bs-tab-btn:active,
.draft-tab:active {
    transform: scale(0.96);
    transition-duration: 50ms;
}

/* 탭 활성 인디케이터 슬라이드 — .mc-tab.active 전환 시 팝 */
.mc-tab.active {
    animation: animTabPop 250ms var(--easing-spring-bouncy);
}
@keyframes animTabPop {
    0%   { transform: scale(0.94); }
    50%  { transform: scale(1.03); }
    100% { transform: scale(1); }
}


/* ═══════════════════════════════════════════
   §44-R ~ §47-R  Reduced motion — 프리미엄 모션 시스템
   ═══════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
    /* §44 탭 프리미엄 트랜지션 */
    .tab-premium-enter,
    .tab-premium-exit {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
        filter: none !important;
    }
    .tab-premium-enter > * {
        animation-delay: 0ms !important;
        animation: none !important;
        opacity: 1 !important;
    }

    /* §45 카드 캐스케이드 */
    .card-cascade > * {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
        filter: none !important;
    }

    /* §46 드로어/모달 프리미엄 */
    .drawer-premium-in,
    .drawer-premium-out,
    .modal-premium-in,
    .modal-premium-out,
    .backdrop-premium-in,
    .backdrop-premium-out {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
        filter: none !important;
    }

    /* §47 유틸리티 */
    .anim-number-reveal {
        animation: none !important;
        opacity: 1 !important;
    }
    .premium-sheen .sheen-layer::after {
        animation: none !important;
    }
    /* §48 마이크로 인터랙션 */
    .mc-tab.active {
        animation: none !important;
    }
}


/* ═══════════════════════════════════════════
   §49  .animate-* 별칭 — .anim-* 공식 유틸리티의 BEM 스타일 별칭
   ═══════════════════════════════════════════
   규칙: 실제 구현은 .anim-* 클래스에 존재.
         .animate-*는 편의 별칭으로만 사용.
   추가일: 2026-03-27
   ═══════════════════════════════════════════ */

/* 등장/퇴장 */
.animate-fade-in     { animation: animFadeIn var(--duration-base) var(--easing-out) both; }
.animate-fade-out    { animation: animFadeOut var(--duration-fast) var(--easing-in) both; }
.animate-slide-up    { animation: animSlideUp var(--duration-base) var(--easing-out) both; }
.animate-slide-down  { animation: animSlideDown var(--duration-base) var(--easing-out) both; }
.animate-slide-left  { animation: animSlideLeft var(--duration-moderate) var(--easing-out) both; }
.animate-slide-right { animation: animSlideRight var(--duration-moderate) var(--easing-out) both; }
.animate-scale-in    { animation: animScaleIn var(--duration-base) var(--easing-out) both; }
.animate-scale-out   { animation: animScaleOut var(--duration-fast) var(--easing-in) both; }

/* 스프링/바운스 */
.animate-bounce-in   { animation: animBounceIn var(--duration-slow) var(--easing-smooth) both; }
.animate-spring-in   { animation: animSpringIn var(--duration-spring) var(--easing-spring-gentle) both; }
.animate-pop-in      { animation: animPopIn var(--duration-spring) var(--easing-spring-gentle) both; }
.animate-toast-in    { animation: animToastIn var(--duration-spring) var(--easing-spring-elastic) both; }

/* 상태 루프 */
.animate-spin     { animation: spin 1s linear infinite; }
.animate-pulse    { animation: animPulse 2s var(--easing-in-out) infinite; }
.animate-float    { animation: animFloat 3s var(--easing-in-out) infinite; }
.animate-breathe  { animation: animBreathe 3s var(--easing-in-out) infinite; }
.animate-glow     { animation: animGlowPulse 2.5s var(--easing-in-out) infinite; }
.animate-blink    { animation: animBlink 1.5s var(--easing-smooth) infinite; }
.animate-shake    { animation: animShake var(--duration-flip) var(--easing-smooth); }
.animate-shimmer  { animation: animSkeletonShimmer 1.5s linear infinite; }

/* 프리미엄 등장 */
.animate-dramatic-enter { animation: animDramaticEnter var(--duration-dramatic) var(--easing-out) both; }
.animate-hero-enter     { animation: animHeroEntrance var(--duration-dramatic) var(--easing-out) both; }
.animate-panel-enter    { animation: animPanelEnter var(--duration-moderate) var(--easing-out) both; }

/* reduced-motion 대응 */
@media (prefers-reduced-motion: reduce) {
    .animate-fade-in, .animate-fade-out,
    .animate-slide-up, .animate-slide-down,
    .animate-slide-left, .animate-slide-right,
    .animate-scale-in, .animate-scale-out,
    .animate-bounce-in, .animate-spring-in,
    .animate-pop-in, .animate-toast-in,
    .animate-spin, .animate-pulse,
    .animate-float, .animate-breathe,
    .animate-glow, .animate-blink,
    .animate-shake, .animate-shimmer,
    .animate-dramatic-enter, .animate-hero-enter,
    .animate-panel-enter {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
    }
}
