.v3-skin-intro-wrap.intro-letter-wrap {
    background: var(--intro-letter-invi-bg-color, #f1f1f1);
}
.v3-skin-intro-content {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--intro-text-color, currentColor);
}
.v3-skin-intro-content-inner {
    position: relative;
    width: 325px;
    height: 452px;
    max-height: 1000px;
    transform: translate(var(--intro-drag-x, 0), var(--intro-drag-y, 0));
    transition: height 1s cubic-bezier(0.33, 1, 0.68, 1);
}
.v3-skin-intro-content-inner.is-moving {
    height: 100%;
}
.v3-skin-intro-holder[data-use-drag="T"] .v3-skin-intro-content-inner {
    cursor: grab;
    touch-action: none;
}

.intro-letter-content-clip {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 1;
    width: 100%;
    height: 100%;
    overflow: hidden;
    transition: transform 1s cubic-bezier(0.33, 1, 0.68, 1);
}
.v3-skin-intro-content-inner.is-moving .intro-letter-content-clip {
    /* 후반 확대 시 부모(298px) 밖으로 나가도록.
     * overflow 를 is-moving 순간 즉시 visible 로 바꾸면 애니메이션 시작 전
     * 편지지 초기 상태(top:116 height:260, 바닥이 clip 경계 초과) 가 그대로 노출돼
     * 봉투 하단으로 튀어나오는 시각적 결함이 생김. 애니메이션 50% (편지지가
     * top:0 height:100% 로 정확히 clip 을 채우는 시점) 이후에 overflow 를 풀어
     * 그 이후 뷰포트 확장 구간만 밖으로 나가도록 스위치. */
    animation: intro-letter-invi-clip-overflow 1.6s cubic-bezier(0.33, 1, 0.68, 1) forwards;
    transform: translateY(0);
}
@keyframes intro-letter-invi-clip-overflow {
    0%   { overflow: hidden; }
    49.9%{ overflow: hidden; }
    50%  { overflow: visible; }
    100% { overflow: visible; }
}
.intro-letter-content {
    position: absolute;
    top: 0;
    left: 50%;
    /* -50% of width(282) = -141px. 정적 상태를 애니메이션 0% keyframe(-141px) 과 동일한
     * 절대 px 로 표현해 % → px 단위 변환 왕복이 없도록 함. */
    transform: translateX(-141px);
    width: 282px;
    height: 378px;
    background: var(--skin-bg);
    border-radius: 20px 20px 0 0;
    overflow: hidden;
    box-shadow: 0px -2px 6px rgba(0, 0, 0, 0.04);
}
/* 0→50%: 세로로 길어짐(기존 is-moving) → 50→100%: 모바일 청첩장 화면 크기로 확대 */
.v3-skin-intro-content-inner.is-moving .intro-letter-content {
    z-index: 3;
    animation: intro-letter-invi-content 1.6s cubic-bezier(0.33, 1, 0.68, 1) forwards;
}
/* transform 값을 전 keyframe 모두 절대 단위(px | vw) 로 통일.
 * 원래는 0%/50% 에서 translateX(-50%) (element width 기반) → 100% 에서 translateX(-50vw) (viewport 기반) 였는데,
 * 서로 다른 단위 사이 보간을 브라우저(특히 iOS Safari) 가 매 프레임 % 재계산과 뒤섞으며
 * subpixel 어긋남이 발생. -141px 은 -50% of 282 와 수학적으로 동일하지만 브라우저가
 * width 값에 의존하지 않고 상수 px 로 취급하므로 재계산 밀림이 없음. */
@keyframes intro-letter-invi-content {
    0% {
        width: 282px;
        height: 378px;
        border-radius: 20px 20px 0 0;
        transform: translateX(-141px);
    }
    50% {
        width: 282px;
        height: 100%;
        border-radius: 20px 20px 0 0;
        transform: translateX(-141px);
    }
    100% {
        /* width:100vw + translateX(-50vw) — 편지지가 뷰포트 좌측 0 에서 우측 100vw 까지 정확히 채움.
         * 50% keyframe 의 translateX(-141px) → 100% translateX(-50vw) 는 둘 다 절대 단위라
         * 브라우저가 두 값을 px 로 해석 후 선형 보간. width 보간과 정확히 대칭이 되어 letter
         * center 가 뷰포트 center 를 유지. */
        width: 100vw;
        height: 100%;
        max-height: 1000px;
        border-radius: 0;
        box-shadow: none;
        transform: translateX(-50vw);
    }
}
/* 편지지 내부 DOM clone (intro_letter_invi.js 가 실 스킨 main+첫 섹션을 복제해 넣음).
   - 폭은 실제 카드 프레임 폭(--intro-clone-frame-w) 기준.
       모바일: viewport 폭
       PC 미리보기: body.v3-skin 폭(400px, preview.css) — 뷰포트가 아닌 카드 프레임 기준이라
                    PC 데스크톱에서도 모바일 레이아웃이 그대로 편지지 안에 담김.
   - --intro-clone-scale (= 282 / frame-w) 로 축소해 letter 초기 폭(282) 에 맞춰 노출.
   - transform-origin: top center — scale 이 상단 중앙 기준으로 축소되어 좌우 대칭 유지.
   - Phase B (letter 확대) 와 동기로 scale 이 1 까지 복원되어 마지막엔 프레임 폭 그대로. */
.intro-letter-content-clone {
    position: absolute;
    top: 0;
    left: 50%;
    width: var(--intro-clone-frame-w, 100vw);
    transform: translateX(calc(var(--intro-clone-frame-w, 100vw) * -0.5)) scale(var(--intro-clone-scale, 1));
    transform-origin: top center;
    pointer-events: none;
}
.v3-skin-intro-content-inner.is-moving .intro-letter-content-clone {
    animation: intro-letter-invi-clone-scale 1.6s cubic-bezier(0.33, 1, 0.68, 1) forwards;
}
/* 0~50%: letter 폭 고정(282) → scale 유지. 50~100%: letter 폭 확대 → scale 1 까지 선형 복원.
 * clone 시각 폭 = frame-w * scale — Phase B 모든 시점에서 letter 폭과 정확히 일치. */
@keyframes intro-letter-invi-clone-scale {
    0%, 50% {
        transform: translateX(calc(var(--intro-clone-frame-w, 100vw) * -0.5)) scale(var(--intro-clone-scale, 1));
    }
    100% {
        transform: translateX(calc(var(--intro-clone-frame-w, 100vw) * -0.5)) scale(1);
    }
}

.intro-letter-bottom {
    position: absolute;
    bottom: -8px;
    left: 0;
    z-index: 4;
    width: 100%;
    color: var(--intro-letter-invi-color, #F4ECD4);
    /* [2026-09-01] 종전에는 여기 transition 으로 0.8s 뒤 봉투가 그대로 내려가 사라졌다.
     * 이제 편지지와 같은 구간에 봉투도 함께 커진 뒤 사라지므로 아래 animation 이 담당한다. */
    /* [2026-09-01] origin 을 bottom center 로 두면 하단이 고정된 채 위로만 자라서
     * "봉투가 한 번 위로 튕겼다가 커진다"로 보인다(진수님 지적) → 제자리에서 커지도록 center. */
    transform-origin: center center;
    will-change: transform;
}
/* [2026-09-01 진수님 지시 — 인트로 모션 자체 변경]
 * 종전: 편지지만 100vw 로 커지고 봉투는 원래 크기 그대로 아래로 내려가 사라졌다.
 * 변경: 봉투도 편지지와 **같은 구간(0.8~1.6s)에 함께 커지고**, 다 커진 뒤(1.6~2.0s) 아래로 사라진다.
 *   - 확대는 transform:scale 로만 처리(width 애니는 매 프레임 리플로우라 버벅임)
 *   - 배율 --intro-bottom-scale (= 프레임폭 / 325) 은 intro_letter_invi.js 가 넣어준다
 *   - 총 2.0s 로 늘어나므로 intro_letter_invi.js 의 fadeDelay 도 1800 → 2200 으로 맞췄다 */
.v3-skin-intro-content-inner.is-moving .intro-letter-bottom {
    animation: intro-letter-invi-bottom 2s cubic-bezier(0.33, 1, 0.68, 1) forwards;
    pointer-events: none;
    transform-origin: center center;
}
@keyframes intro-letter-invi-bottom {
    0%, 40% {
        transform: scale(1) translateY(0);
        opacity: 1;
    }
    80% {
        transform: scale(var(--intro-bottom-scale, 1)) translateY(0);
        opacity: 1;
    }
    100% {
        transform: scale(var(--intro-bottom-scale, 1)) translateY(110%);
        opacity: 0;
    }
}
.intro-letter-invi-case {
    position: relative;
    width: 100%;
}
.intro-letter-invi-body {
    position: relative;
    overflow: visible;
    border-radius: 10px;
}
.intro-letter-invi-body > svg {
    display: block;
    width: 100%;
    height: auto;
}
.intro-letter-invi-cover {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
    pointer-events: none;
}
.intro-letter-invi-cover svg {
    display: block;
    overflow: visible;
    width: 100%;
    height: 100%;
}
.intro-letter-invi-label {
    position: absolute;
    left: 50%;
    top: 52%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    color: color-mix(in srgb, var(--intro-letter-invi-color, #F4ECD4) 72%, #3d4d63);
    transform: translate(-50%, -50%);
    pointer-events: none;
}
.intro-letter-invi-heart {
    display: flex;
    width: 24px;
    height: 24px;
}
.intro-letter-invi-heart svg {
    width: 100%;
    height: 100%;
}
.intro-letter-invi-title {
    font-family: Georgia, 'Times New Roman', serif;
    font-size: 20px;
    font-weight: 700;
    line-height: 1.7;
    letter-spacing: -0.02em;
    white-space: nowrap;
}
/* 봉투 파트만 스코프 — 확장 시 clone 내부(스킨) SVG 에 영향 주지 않도록 */
.intro-letter-top > svg,
.intro-letter-tape > svg,
.intro-letter-left > svg,
.intro-letter-right > svg,
.intro-letter-bottom > svg,
.intro-letter-invi-body > svg {
    display: block;
    width: 100%;
    height: auto;
}
/* left/right는 높이만 고정 → width:100%면 부모(전체) 너비로 늘어나 가운데로 모임 */
.intro-letter-left > svg,
.intro-letter-right > svg {
    width: auto;
    height: 100%;
}

/* ── "인트로 고정" (is_intro_fixed=T → holder.is-fixed) ──
 * [2026-09-01 진수님 지시] 종전에는 animation:none 으로 0% 프레임(봉투에 편지지가 꽂힌 상태)에
 * 멈춰 있어서 "청첩장이 나오는 모션"이 전혀 안 보였다.
 *
 * 원하는 그림 = **봉투와 클론이 사라지고 실제 청첩장이 나오기 직전의 모습**.
 *   - 편지지(.intro-letter-content) 는 원본 애니 그대로 100% 까지 재생(forwards 로 유지)
 *   - 봉투(.intro-letter-bottom) 는 원본이라면 0.8s delay 후 내려가 사라지는데, 여기서는
 *     사라지지 않고 **편지지와 같은 구간(50~100%)에 맞춰 함께 커진다**
 *   - z-index 는 편지지 3 / 봉투 4 라 봉투가 편지지 위에 겹쳐 보인다
 *
 * ⚡ 성능: 봉투 확대를 width/left 로 하면 매 프레임 리플로우가 나서 인트로가 버벅인다(진수님 지적).
 *    그래서 transform:scale 로만 처리한다. 배율(--intro-bottom-scale = 프레임폭 / 325)은
 *    CSS 로 무단위 숫자를 만들 수 없어 intro_letter_invi.js 의 updateCloneScale() 이 넣어준다.
 *
 * wrap 의 is-fade-out/is-hidden 무효화는 skin.css 의 .is-fixed 규칙이 담당한다.
 * ⚠ 화면을 덮는 것은 실제 본문이 아니라 클론이라 그 위에서 스크롤은 동작하지 않는다(의도된 정지 화면).
 */
.v3-skin-intro-holder.is-fixed .intro-letter-wrap .v3-skin-intro-content-inner.is-moving .intro-letter-bottom {
    /* 원본의 transition(0.8s delay 후 translateY(110%)+opacity:0) 을 끄고 확대 애니로 대체 */
    transition: none;
    pointer-events: auto;
    transform-origin: center center;
    will-change: transform;
    animation: intro-letter-invi-bottom-fixed 1.6s cubic-bezier(0.33, 1, 0.68, 1) forwards;
}
/* 0~50%: 봉투 원래 크기 유지(편지지가 봉투에서 올라오는 구간)
 * 50~100%: 편지지 확대와 같은 구간에 맞춰 봉투도 프레임 폭까지 확대 */
@keyframes intro-letter-invi-bottom-fixed {
    0%, 50% {
        transform: scale(1);
        opacity: 1;
    }
    100% {
        transform: scale(var(--intro-bottom-scale, 1));
        opacity: 1;
    }
}
