/* ============================================================
   CELAI 상세페이지 생성기 - 모바일 우선 스타일 (리디자인)
   중립 쿨그레이 배경 + 화이트 카드 + 절제된 브랜드 그라디언트
   ============================================================ */

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

:root {
    /* --- 배경/서피스 (쿨톤) --- */
    --bg-primary: #f7f8fc;
    --bg-secondary: #ffffff;
    --surface-soft: #f1f4fa;

    /* --- 텍스트 --- */
    --text-primary: #111827;
    --text-secondary: #6b7280;
    --text-muted: #9ca3af;

    /* --- 보더 --- */
    --border-color: #e5e7eb;
    --border-strong: #d1d5db;

    /* --- 브랜드 accent (유지) --- */
    --accent-primary: #667eea;
    --accent-secondary: #764ba2;
    --accent-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    --accent-soft: rgba(102, 126, 234, 0.10);

    /* --- 상태 컬러 --- */
    --success: #10b981;
    --warn: #f59e0b;
    --danger: #ef4444;
    /* 저채도 tonal 배경(rgba(239,68,68,.10)) 위에 얹는 파괴적 액션 텍스트 색.
       --danger(#ef4444) 는 해당 합성 배경에서 3.29:1 로 AA 미달이므로,
       라이트 모드 전용으로 한 단계 진한 레드를 사용한다(.history-chip--failed #c02626 계열). */
    --danger-strong: #b91c1c;
    --info: #3b82f6;

    /* 배지/칩처럼 --surface-soft(#f1f4fa) 배경 위에 놓이는 소형 보조 텍스트용.
       --text-secondary(#6b7280) 는 해당 배경에서 4.39:1 로 AA 미달이라 한 단계 진하게. */
    --text-badge: #5b616b;

    /* --- 오버레이/레거시 그림자 참조 토큰 (하위 컴포넌트에서 사용) --- */
    --overlay-bg: rgba(17, 24, 39, 0.55);
    --shadow: rgba(17, 24, 39, 0.08);
    --shadow-hover: rgba(17, 24, 39, 0.16);

    /* --- 그림자 (프리미엄: 부드럽고 넓게) --- */
    --shadow-soft: 0 4px 12px rgba(17, 24, 39, 0.06);
    --shadow-card: 0 10px 30px rgba(17, 24, 39, 0.08);
    --shadow-lg: 0 18px 50px rgba(17, 24, 39, 0.14);

    /* --- 배경 무드 blob --- */
    --blob-1: rgba(118, 75, 162, 0.12);
    --blob-2: rgba(102, 126, 234, 0.12);

    /* --- 간격 스케일 (4~40px) --- */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 20px;
    --space-6: 24px;
    --space-7: 28px;
    --space-8: 32px;
    --space-9: 36px;
    --space-10: 40px;

    /* --- radius --- */
    --radius-sm: 10px;
    --radius-md: 14px;
    --radius-lg: 18px;
    --radius-xl: 24px;
    --radius-full: 999px;

    /* --- 레이아웃 --- */
    --app-max: 560px;
    --topbar-h: 64px;
    --panel-w: 420px;

    /* --- 반투명 상단바 배경 --- */
    --topbar-bg: rgba(255, 255, 255, 0.72);

    /* --- 포커스 링 --- */
    --focus-ring: 0 0 0 3px rgba(102, 126, 234, 0.45);

    /* --- 타이포 스케일 --- */
    --fs-xs: 0.75rem;
    --fs-sm: 0.85rem;
    --fs-base: 0.95rem;
    --fs-md: 1.02rem;
    --fs-lg: 1.2rem;
    --fs-xl: 1.5rem;

    /* --- 폰트 토큰 (Pretendard 우선) --- */
    --font-sans: 'Pretendard', 'Pretendard Variable', 'Noto Sans KR',
        -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

    /* --- 모션 --- */
    --transition-fast: 140ms ease;
    --transition-base: 220ms ease;

    /* --- 타이포 토큰 (px 기반 · UI 일관성 기준 스케일) ---
       위 --fs-* (rem) 스케일은 history/results 등 기존 6곳에서 계속 사용 중이므로 유지.
       신규/정리 대상 컴포넌트는 아래 --font-size-* 를 사용한다. */
    --font-size-display: 28px;
    --font-size-title: 22px;
    --font-size-step-title: 20px;
    --font-size-section-title: 18px;
    --font-size-body: 15px;
    --font-size-small: 14px;
    --font-size-helper: 13px;
    --font-size-caption: 12px;
    --line-height-title: 1.3;
    --line-height-body: 1.6;
    --line-height-compact: 1.4;
}

[data-theme="dark"] {
    --bg-primary: #0b0d12;
    --bg-secondary: #14171e;
    --surface-soft: #1c2029;

    --text-primary: #f3f4f6;
    --text-secondary: #a1a1aa;
    --text-muted: #71717a;

    --border-color: rgba(255, 255, 255, 0.10);
    --border-strong: rgba(255, 255, 255, 0.18);

    --accent-soft: rgba(102, 126, 234, 0.18);

    --success: #34d399;
    --warn: #fbbf24;
    --danger: #f87171;
    /* 다크는 기존 밝은 레드가 이미 AA 통과(5.30:1) → 동일 값 유지 */
    --danger-strong: #f87171;
    --info: #60a5fa;

    /* 다크 배지 텍스트는 .optional-badge 다크 규칙이 직접 지정(8.17:1) — 토큰은 폴백용 */
    --text-badge: rgba(255, 255, 255, 0.72);

    --overlay-bg: rgba(0, 0, 0, 0.7);
    --shadow: rgba(0, 0, 0, 0.5);
    --shadow-hover: rgba(0, 0, 0, 0.6);

    --shadow-soft: 0 4px 14px rgba(0, 0, 0, 0.45);
    --shadow-card: 0 10px 30px rgba(0, 0, 0, 0.5);
    --shadow-lg: 0 18px 50px rgba(0, 0, 0, 0.6);

    --blob-1: rgba(118, 75, 162, 0.10);
    --blob-2: rgba(102, 126, 234, 0.08);

    --topbar-bg: rgba(18, 20, 26, 0.72);
    --focus-ring: 0 0 0 3px rgba(126, 150, 255, 0.55);
}

html {
    -webkit-text-size-adjust: 100%;
    /* 페이지 간 스크롤바 유무로 인한 중앙 네비 시프트 방지 */
    scrollbar-gutter: stable;
}

body {
    font-family: var(--font-sans);
    background-color: var(--bg-primary);
    /* 은은한 radial blob 2개 (보라/블루) — 고정 배경, 클릭/스크롤 방해 없음 */
    background-image:
        radial-gradient(620px circle at 8% -8%, var(--blob-1), transparent 60%),
        radial-gradient(720px circle at 100% 2%, var(--blob-2), transparent 55%);
    background-repeat: no-repeat;
    background-attachment: fixed;
    color: var(--text-primary);
    line-height: 1.6;
    /* 2단 선언: 미지원 브라우저는 100vh 를, 지원 브라우저는 뒤의 100dvh 를
       쓴다(순서 필수). iOS Safari 에서 100vh 는 주소창이 접힌 상태 기준이라
       주소창이 보일 때 화면 밖으로 넘쳐 불필요한 스크롤이 생긴다. */
    min-height: 100vh;
    min-height: 100dvh;
    transition: background-color 0.3s, color 0.3s;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

img {
    max-width: 100%;
    display: block;
}

/* ===== 상단바 ===== */
.topbar {
    position: sticky;
    top: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    height: var(--topbar-h);
    padding: 0 var(--space-4);
    background-color: var(--topbar-bg);
    -webkit-backdrop-filter: saturate(180%) blur(16px);
    backdrop-filter: saturate(180%) blur(16px);
    border-bottom: 1px solid var(--border-color);
    box-shadow: var(--shadow-soft);
}
/* backdrop-filter 미지원 브라우저 폴백: 불투명 배경 */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .topbar { background-color: var(--bg-secondary); }
}

.topbar__logo {
    display: flex;
    align-items: center;
    text-decoration: none;
    color: var(--text-primary);
    gap: var(--space-2);
    min-width: 0;
}

.topbar__logo img {
    height: 26px;
    width: auto;
}

.topbar__logo-text {
    font-weight: 700;
    font-size: 1.18rem;
    letter-spacing: -0.02em;
    background: var(--accent-gradient);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

.topbar__logo-black { display: block; }
.topbar__logo-white { display: none; }
[data-theme="dark"] .topbar__logo-black { display: none; }
[data-theme="dark"] .topbar__logo-white { display: block; }

/* 유저칩·설정·테마토글을 pill 그룹으로 정돈 */
.topbar__right {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px;
    border-radius: var(--radius-full);
    background: var(--surface-soft);
    border: 1px solid var(--border-color);
}

/* 유저 메뉴: 아바타 버튼 + 드롭다운 팝오버 */
.user-menu {
    position: relative;
    display: flex;
    align-items: center;
}

/* 아바타 버튼 (로그인 전 숨김 → auth.js가 flex 노출) */
.user-chip {
    display: none;
    align-items: center;
    justify-content: center;
    position: relative;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--accent-soft);
    color: var(--accent-primary);
    font-weight: 700;
    flex-shrink: 0;
    border: 1px solid transparent;
    cursor: pointer;
    padding: 0;
    font-family: inherit;
    transition: transform var(--transition-fast), background-color var(--transition-base),
        box-shadow var(--transition-fast), border-color var(--transition-fast);
}
/* 시각 원형 + 터치 히트영역 44px 확보(theme-toggle 패턴) */
.user-chip::before {
    content: '';
    position: absolute;
    inset: -4px;
    border-radius: 50%;
}
.user-chip:active { transform: scale(0.92); }

.user-chip__avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    font-size: 0.9rem;
}

/* 드롭다운 팝오버 */
.user-dropdown {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
    min-width: 180px;
    max-width: calc(100vw - 24px);
    padding: 8px;
    z-index: 200;
}
.user-dropdown[hidden] { display: none; }

.user-dropdown__head {
    padding: 6px 10px 10px;
    border-bottom: 1px solid var(--border-color);
    margin-bottom: 6px;
}

.user-chip__name {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--text-primary);
}

.user-dropdown__item {
    display: flex;
    align-items: center;
    width: 100%;
    min-height: 44px;
    padding: 0 10px;
    background: none;
    border: none;
    border-radius: 10px;
    text-align: left;
    color: var(--text-primary);
    cursor: pointer;
    font-family: inherit;
    font-size: 0.9rem;
}
@media (hover: hover) {
    .user-dropdown__item:hover { background: var(--surface-soft); }
}

.user-dropdown__item-icon {
    margin-right: 10px;
    width: 20px;
    text-align: center;
    flex-shrink: 0;
}

.theme-toggle {
    position: relative;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    border: 1px solid transparent;
    background-color: transparent;
    color: var(--text-primary);
    font-size: 1.05rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: transform var(--transition-fast), background-color var(--transition-base),
        box-shadow var(--transition-fast), border-color var(--transition-fast);
}
/* 시각 원형 + 터치 히트영역 44px 확보 */
.theme-toggle::before {
    content: '';
    position: absolute;
    inset: -3px;
    border-radius: 50%;
}
.theme-toggle:active { transform: scale(0.92); }

/* ===== 헤더 네비게이션 (홈/이력 segmented pill) ===== */
.topnav {
    display: flex;
    align-items: center;
    gap: 2px;
    padding: 4px;
    border-radius: var(--radius-full);
    background: var(--surface-soft);
    border: 1px solid var(--border-color);
    min-width: 0;
}
.topnav__item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0 12px;
    min-height: 38px;
    border-radius: var(--radius-full);
    text-decoration: none;
    color: var(--text-secondary);
    font-size: 0.84rem;
    font-weight: 700;
    white-space: nowrap;
    position: relative;
    transition: background-color var(--transition-base), color var(--transition-base);
}
/* 터치 히트영역 44px 확보(시각 높이는 38px 유지) */
.topnav__item::before {
    content: '';
    position: absolute;
    inset: -3px 0;
    min-height: 44px;
}
.topnav__icon {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    color: currentColor;
}
.topnav__item.is-active {
    background: var(--accent-soft);
    color: var(--accent-primary);
}
@media (hover: hover) {
    .topnav__item:not(.is-active):hover {
        background: var(--bg-secondary);
        color: var(--text-primary);
    }
}

/* ===== 헤더 네비 중앙 정렬(데스크톱) =====
   topnav을 가진 헤더(index/history)만 3열 grid로 전환해 네비를 뷰포트 기준
   진짜 중앙에 고정한다. 좌/우 트랙을 minmax(0,1fr)로 강제 균등 → 우측그룹 폭이
   변해도(로그인 유저칩 등) 중앙 위치 불변.
   경계는 561이 아닌 769: 561~768 구간은 우측그룹 하드플로어(설정+테마+로그아웃 등
   ≈178px)가 side 트랙(≈177px)을 침범할 여지가 있어, 해당 구간은 기존 flex
   좌측앵커(축소·ellipsis로 안전)를 유지하고 769px 이상에서만 grid를 적용한다.
   login.html은 .topnav이 없어 :has 비매칭 → base flex+margin-left:auto 유지. */
@media (min-width: 769px) {
    .topbar:has(.topnav) {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
        align-items: center;
    }
    .topbar:has(.topnav) .topbar__logo { justify-self: start; }
    .topbar:has(.topnav) .topnav { justify-self: center; }
    .topbar:has(.topnav) .topbar__right {
        justify-self: end;
        /* flex용 margin-left:auto 무효화 + 좁을 때 유저칩 ellipsis 흡수 */
        margin-left: 0;
        min-width: 0;
    }
}

/* ===== 레이아웃 ===== */
/* 하단 padding 은 0 이다(상/좌우만 유지).
   과거엔 여기서 64px 을 잡아 모바일 sticky 바(.cta-wrap / #wizardNav)를
   피했지만, .site-footer 가 .app 의 마지막 자식이라 그 여백은 "푸터 아래"에
   붙을 뿐 sticky 바가 도달하는 위치가 아니다 → 무의미한 빈 공간만 생긴다.
   sticky 바 회피 여백은 실제로 겹치는 컨테이너인 .controls-panel 의
   padding-bottom 80px(<1024 블록) 하나로 일원화한다.
   ≥1024 의 `.app { padding: ... 0 }` 산술과도 값이 일치해 브레이크포인트별
   차이가 사라진다. 문서 페이지는 .app.legal(0,2,0)이 별도 하단 여백을
   유지하므로 영향받지 않는다. */
.app {
    max-width: var(--app-max);
    margin: 0 auto;
    padding: var(--space-5) var(--space-4) 0;
}

/* ===== 워크스페이스 (모바일: 1열 자연 스택) ===== */
.workspace {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0;
}
.controls-panel { min-width: 0; }
.results-area { min-width: 0; }

.section {
    position: relative;
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    padding: 20px;
    margin-bottom: 18px;
    box-shadow: var(--shadow-soft);
    transition: box-shadow var(--transition-base), transform var(--transition-base);
}

.section__title {
    font-size: var(--font-size-step-title);
    font-weight: 800;
    line-height: var(--line-height-title);
    letter-spacing: -0.02em;
    margin-bottom: 6px;
    display: flex;
    align-items: center;
    gap: 10px;
    /* step title 확대(≈16.8→20px) + optional-badge 동반 노출 시 좁은 화면(≤360px)
       가로 넘침 방지. 넘치지 않으면 한 줄 유지되어 기존 렌더 무변경. */
    flex-wrap: wrap;
}

.section__step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 9px;
    background: var(--accent-gradient);
    color: #fff;
    font-size: var(--font-size-caption);
    font-weight: 700;
    flex-shrink: 0;
    box-shadow: 0 3px 8px rgba(102, 126, 234, 0.35);
}

/* ===== 스크린리더 전용 텍스트 =====
   시각적으로는 숨기되 접근성 트리에는 남긴다(display:none / visibility:hidden 과 다름).
   flex 컨테이너(.section__title 등) 안에서도 position:absolute 라 out-of-flow →
   gap 계산에 영향을 주지 않는다. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* ===== 선택(optional) 배지 =====
   "(선택)" 괄호 표기를 대체하는 공용 배지. 문구 자체("기준 인물 이미지" 등)는 불변.
   color 는 --text-badge(#5b616b) 사용: 배지 배경 --surface-soft(#f1f4fa) 기준
   대비 5.66:1 로 WCAG AA(4.5:1) 충족.
   (--text-secondary #6b7280 은 같은 배경에서 4.39:1 로 미달, --text-muted #9ca3af 는 더 낮음.)
   배지는 aria-hidden 처리하고 옆의 .sr-only 가 "(선택 항목)" 을 낭독한다 → 마크업 참고. */
.optional-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 22px;
    padding: 0 8px;
    margin-left: var(--space-2);
    border-radius: var(--radius-full);
    font-size: var(--font-size-caption);
    line-height: 1;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text-badge);
    background: var(--surface-soft);
    border: 1px solid var(--border-strong);
    vertical-align: middle;
    white-space: nowrap;
    flex-shrink: 0;
}
/* .section__title / .upload-details__summary 는 flex + gap 컨테이너라
   margin-left 가 gap 과 중복 적용된다 → 해당 문맥에서만 0 으로 리셋. */
.section__title .optional-badge,
.upload-details__summary .optional-badge {
    margin-left: 0;
}
[data-theme="dark"] .optional-badge {
    color: rgba(255, 255, 255, 0.72);
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.16);
}

/* 필수 항목 변형(어드민 폼 등에서 사용).
   합성 배경 rgb(241,226,232)(=rgba(239,68,68,.10) on --surface-soft) 기준
   --danger(#ef4444) 는 3.01:1 로 미달 → --danger-strong(#b91c1c, 5.17:1) 사용. */
.optional-badge--required {
    color: var(--danger-strong);
    background: rgba(239, 68, 68, 0.10);
    border-color: rgba(239, 68, 68, 0.28);
}
/* color 를 다시 지정해야 한다. 바로 아래 [data-theme="dark"] .optional-badge--required 는
   위 [data-theme="dark"] .optional-badge(:572) 와 특이도가 같고(0,2,0) 소스 순서가 뒤라
   이긴다 — 그런데 color 를 빼면 "이긴 규칙"에 color 선언이 없어 :572 의 밝은 색이 그대로
   내려와 다크에서 흰색이 남는다. 바로 위 라이트용 .optional-badge--required 는 (0,1,0)
   이라 :572 에 밀려 구제해 주지 못한다.
   → 다크에서도 --danger-strong 이 적용되도록 명시.
   다크 합성 배경 rgb(59,43,51)(=rgba(248,113,113,.14) on --surface-soft #1c2029)
   에서 #f87171 = 4.81:1 (AA 통과). */
[data-theme="dark"] .optional-badge--required {
    color: var(--danger-strong);
    background: rgba(248, 113, 113, 0.14);
    border-color: rgba(248, 113, 113, 0.32);
}

/* 필수 표시 '*' — index.html 의 .field-label 안에서 쓰이는 인라인 마크.
   대응쌍인 .optional-badge--required 와 같은 --danger-strong 톤을 쓰되,
   배지가 아니라 글자 하나이므로 배경/테두리 없이 색·굵기로만 구분한다.
   (aria-hidden 이고 옆의 .sr-only 가 "(필수 항목)" 을 낭독한다 → 마크업 참고)
   대비: 라이트 #b91c1c on --bg-secondary(#ffffff) = 6.6:1,
        다크  #f87171 on --bg-secondary(#14171e) = 6.7:1 로 AA 충족.
   색은 토큰만 사용 → 테마 전환 자동 대응(하드코딩 색 없음). */
.required-mark {
    margin-left: var(--space-1);
    color: var(--danger-strong);
    font-weight: 700;
}

/* 라벨 옆 부가 설명("최대 2장" 등) — 배지가 아닌 평문 보조 텍스트 */
.field-label__note {
    margin-left: var(--space-1);
    font-weight: 400;
    font-size: var(--font-size-caption);
    color: var(--text-secondary);
}

.section__desc {
    /* 색은 --text-secondary 유지(대비 확보). 크기만 helper 토큰으로 통일. */
    font-size: var(--font-size-helper);
    color: var(--text-secondary);
    margin-bottom: 16px;
}

/* ===== 탭 ===== */
.tabs {
    display: flex;
    gap: 6px;
    margin-bottom: 16px;
    background-color: var(--surface-soft);
    padding: 4px;
    border-radius: var(--radius-full);
    border: 1px solid var(--border-color);
}

.tab {
    flex: 1;
    padding: 10px 8px;
    border: none;
    border-radius: var(--radius-full);
    background: transparent;
    color: var(--text-secondary);
    font-size: var(--font-size-small);
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: background var(--transition-base), color var(--transition-base),
        box-shadow var(--transition-base);
    min-height: 44px;
}
.tab.is-active {
    background: var(--accent-gradient);
    color: #fff;
    box-shadow: 0 4px 12px rgba(102, 126, 234, 0.36);
}

.tab-panel { display: none; }
.tab-panel.is-active { display: block; }

/* ===== 폼 요소 ===== */
label.field-label {
    display: block;
    font-size: var(--font-size-body);
    font-weight: 600;
    margin-bottom: 7px;
    color: var(--text-primary);
}

.input,
.textarea,
.select {
    width: 100%;
    padding: 12px 14px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    background-color: var(--surface-soft);
    color: var(--text-primary);
    /* iOS Safari는 16px 미만 입력 요소 포커스 시 자동 확대(줌)됨 → 1rem(16px) 유지 */
    font-size: 1rem;
    font-family: inherit;
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast),
        background-color var(--transition-fast);
}
.input::placeholder,
.textarea::placeholder { color: var(--text-muted); }
.input:focus,
.textarea:focus,
.select:focus {
    outline: none;
    border-color: var(--accent-primary);
    background-color: var(--bg-secondary);
    box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.15);
}
.textarea { resize: vertical; min-height: 88px; }

/* 필수 입력 미충족 상태(app.js 가 aria-invalid="true" 를 붙임).
   대비: --danger-strong 은 라이트/다크 모두 AA 통과 값으로 이미 검증된 토큰. */
.input[aria-invalid="true"],
.textarea[aria-invalid="true"] {
    border-color: var(--danger-strong);
}
.input[aria-invalid="true"]:focus,
.textarea[aria-invalid="true"]:focus {
    border-color: var(--danger-strong);
    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.18);
}

/* 인라인 필드 오류 메시지(role="alert"). 기본 숨김 → .is-visible 로만 노출.
   display:none 이므로 숨김 상태에서 레이아웃/스크린리더 모두에 영향 없음. */
.field-error {
    display: none;
    margin: 6px 0 0;
    font-size: var(--font-size-helper);
    font-weight: 600;
    color: var(--danger-strong);
}
.field-error.is-visible { display: block; }

.field { margin-bottom: 16px; }
.field:last-child { margin-bottom: 0; }

/* 입력칸 바로 아래에 붙는 보조 액션 버튼(예: 가격 정보 지우기).
   버튼 스타일은 기존 .btn--secondary.btn--small 을 그대로 재사용하고 간격만 준다.
   .btn 이 display:inline-flex 라 hidden 속성이 무력화되므로 [hidden] 을 명시적으로 되살린다. */
.field-action { margin-top: 6px; }
.field-action[hidden] { display: none; }

.field-row {
    display: flex;
    gap: 12px;
}
.field-row .field { flex: 1; }

.url-row {
    display: flex;
    gap: 8px;
}
.url-row .input { flex: 1; }

/* ===== 버튼 ===== */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 0 18px;
    border: none;
    border-radius: var(--radius-md);
    font-size: var(--font-size-body);
    font-weight: 700;
    font-family: inherit;
    cursor: pointer;
    min-height: 48px;
    transition: transform var(--transition-fast), box-shadow var(--transition-base),
        opacity var(--transition-base), filter var(--transition-fast);
}
.btn:active { transform: scale(0.98); }
.btn:disabled { opacity: 0.55; cursor: not-allowed; }

.btn--primary {
    background: var(--accent-gradient);
    color: #fff;
    box-shadow: 0 4px 14px rgba(102, 126, 234, 0.28);
}
.btn--secondary {
    background-color: var(--surface-soft);
    color: var(--text-primary);
    border: 1px solid var(--border-color);
}
/* 보조/밀집 액션용 소형 버튼. --primary/--secondary 뒤에 선언해야
   조합 사용(.btn--secondary.btn--small) 시 크기 규격이 이긴다. */
.btn--small {
    min-height: 36px;
    padding: 0 var(--space-3);
    font-size: var(--font-size-caption);
    gap: 4px;
    border-radius: var(--radius-sm);
}
/* 파괴적 액션(삭제 등) — 저채도 tonal 스타일.
   .btn--small(12px) 과 조합되므로 large-text 예외가 불가 → 본문 기준 4.5:1 필요.
   라이트 합성 배경 rgb(253,236,236) 에서 --danger(#ef4444)=3.29:1 미달 →
   --danger-strong(#b91c1c)=5.66:1(hover 배경 rgb(252,225,225) 에서도 5.24:1).
   어드민 표에서는 .admin-table tbody tr:hover(--accent-soft) 가 버튼 아래 배경을
   바꾸므로 그 조합까지 계산해야 한다. 라이트는 행hover 5.14:1 / 행+버튼hover
   4.74:1 로 통과. 다크는 --danger-strong(#f87171) 이 정지 5.30:1 이지만
   행hover 위에서 4.19:1(행+버튼hover 4.42:1) 로 AA 미달 → 다크 전용 텍스트 색을
   #fca5a5 로 올린다(정지 7.73 / 행hover 6.11 / 버튼hover 8.05 / 행+버튼hover 6.44).
   :hover 는 터치기기 색 고착 방지를 위해 @media (hover:hover) 블록에 있음. */
.btn--danger {
    background-color: rgba(239, 68, 68, 0.10);
    color: var(--danger-strong);
    border: 1px solid rgba(239, 68, 68, 0.28);
    box-shadow: none;
}
[data-theme="dark"] .btn--danger {
    color: #fca5a5;
    background-color: rgba(248, 113, 113, 0.14);
    border-color: rgba(248, 113, 113, 0.32);
}
/* 폼 하단 버튼 행 — 균등 분할 */
.form-actions {
    display: flex;
    gap: var(--space-2);
}
.form-actions .btn { flex: 1; }
.btn--block { width: 100%; }
.btn--cta {
    width: 100%;
    /* 56px 고정 높이 유지(주 CTA 강조) — --small 규격 미적용 대상 */
    font-size: var(--font-size-section-title);
    padding: 16px;
    min-height: 56px;
    box-shadow: 0 8px 22px rgba(102, 126, 234, 0.34);
}

/* ===== 생성 CTA 래퍼 (모바일 하단 sticky) ===== */
.cta-wrap {
    margin-top: 6px;
}

/* ===== 상품 미리보기 카드 ===== */
.preview-card {
    display: none;
    margin-top: 16px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    overflow: hidden;
    background-color: var(--surface-soft);
}
.preview-card.is-visible { display: block; }

.preview-card__body {
    display: flex;
    gap: 12px;
    padding: 12px;
}
.preview-card__thumb {
    width: 84px;
    height: 84px;
    border-radius: 10px;
    object-fit: cover;
    background-color: var(--border-color);
    flex-shrink: 0;
}
.preview-card__thumb--placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.6rem;
}
.preview-card__info { min-width: 0; flex: 1; }
.preview-card__title {
    font-weight: 700;
    font-size: var(--font-size-small);
    margin-bottom: 4px;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.preview-card__meta {
    font-size: var(--font-size-caption);
    color: var(--text-secondary);
}
.preview-card__price {
    font-weight: 700;
    color: var(--accent-primary);
    margin-top: 4px;
}
.preview-card__badge {
    display: inline-block;
    margin: 12px 12px 10px;
    padding: 4px 12px;
    border-radius: var(--radius-full);
    font-size: var(--font-size-caption);
    font-weight: 700;
    background: rgba(16, 185, 129, 0.14);
    color: var(--success);
}

/* ===== 이미지 업로드 프리뷰 ===== */
.upload-drop {
    display: block;
    border: 2px dashed var(--border-strong);
    border-radius: var(--radius-md);
    padding: 22px;
    text-align: center;
    cursor: pointer;
    color: var(--text-secondary);
    font-size: var(--font-size-small);
    background-color: var(--surface-soft);
    transition: border-color var(--transition-fast), background-color var(--transition-fast);
}
.upload-drop:hover {
    border-color: var(--accent-primary);
    background-color: var(--accent-soft);
}
.upload-drop input[type="file"] { display: none; }

/* 상품 변경 잠금(변환·업로드·URL 추출·이미지 주소·이미지 삭제 진행 중) 시각 표시.
   🔴 상태 클래스로 한정한다 — .upload-drop 라벨은 이 페이지에 여러 개 있고(상품 이미지·
      참고 이미지·인물 이미지), 잠기는 것은 상품 변경 뮤텍스가 거는 상품 이미지 라벨
      하나뿐이다(app.js applyProductLockUI 가 #imagesInput 의 조상 라벨에만 붙인다).
   🔴 opacity 는 .btn:disabled(0.55) 와 같은 값으로 통일한다(비활성 표현의 일관성).
   🔴 pointer-events: none 을 쓰지 않는다 — 안의 input 이 disabled 라 라벨 클릭은
      이미 무시되고, 넣으면 안내 문구의 텍스트 선택까지 막힌다.
   🔴 .upload-drop:hover 가 @media (hover: hover) 바깥에 있으므로 hover 상태도
      함께 덮어야 한다(안 덮으면 잠긴 상태에서 손대면 활성처럼 보인다). */
.upload-drop.is-locked {
    opacity: 0.55;
    cursor: not-allowed;
    border-color: var(--border-color);
    background-color: var(--surface-soft);
}
.upload-drop.is-locked:hover {
    border-color: var(--border-color);
    background-color: var(--surface-soft);
}
.upload-drop__icon { font-size: 1.8rem; margin-bottom: 6px; }

.thumb-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
    gap: 8px;
    margin-top: 12px;
}
.thumb-grid:empty { margin-top: 0; }
.thumb-grid__item {
    position: relative;
    aspect-ratio: 1 / 1;
    border-radius: 10px;
    overflow: hidden;
    border: 1px solid var(--border-color);
}
.thumb-grid__item img { width: 100%; height: 100%; object-fit: cover; }

/* 썸네일 개별 삭제 버튼 — 우상단. 버튼 자체는 44x44 터치 히트영역(투명),
   보이는 원형 배지는 ::before 로 작게 유지(model-preview__remove 패턴 재사용). */
.thumb-del {
    position: absolute;
    top: 0;
    right: 0;
    width: 44px;
    height: 44px;
    border: none;
    background: transparent;
    cursor: pointer;
    padding: 0;
    z-index: 2;
    -webkit-tap-highlight-color: transparent;
    transition: transform var(--transition-fast);
}
.thumb-del::before {
    content: '×';
    position: absolute;
    top: 4px;
    right: 4px;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--danger);
    color: #fff;
    font-size: 0.95rem;
    font-weight: 700;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 1px 6px var(--shadow-hover);
}
.thumb-del:active { transform: scale(0.9); }
.thumb-del:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* 상품 변경 잠금 중의 × 버튼(상품 이미지 그리드 한정. applyProductLockUI 가 disabled 를 건다).
   🔴 disabled 만으로는 화면이 그대로라 "눌렀는데 아무 일도 안 난다"로 읽힌다 →
      .btn:disabled / .upload-drop.is-locked 와 같은 0.55 로 통일한다.
   🔴 :active 확대 반응도 함께 끈다(눌리는 것처럼 보이면 잠금 표시가 무효가 된다). */
.thumb-del:disabled { opacity: 0.55; cursor: not-allowed; }
.thumb-del:disabled:active { transform: none; }

/* 업로드 진행 중 임시 썸네일: 원본을 흐리게 + 중앙 스피너 오버레이 */
.thumb-grid__item--loading img { opacity: 0.45; }
.thumb-grid__item--loading::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 22px;
    height: 22px;
    margin: -11px 0 0 -11px;
    border: 3px solid var(--border-color);
    border-top-color: var(--accent-primary);
    border-radius: 50%;
    animation: spin 0.9s linear infinite;
    z-index: 3;
}

/* ===== 이미지 카드 (파일 업로드 / 이미지 주소 세그먼트) =====
   업로드 탭의 주 액션. .tabs pill 패턴 재사용 + 파일/URL pane 전환. */
.media-card {
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    background-color: var(--bg-secondary);
    padding: var(--space-3);
    margin-bottom: var(--space-4);
}

/* 세그먼트 컨트롤 — .tabs pill 패턴 재사용(중립 트랙 + accent 활성) */
.media-segment {
    display: flex;
    gap: 6px;
    margin-bottom: var(--space-3);
    background-color: var(--surface-soft);
    padding: 4px;
    border-radius: var(--radius-full);
    border: 1px solid var(--border-color);
}
.media-seg-btn {
    flex: 1;
    padding: 10px 8px;
    border: none;
    border-radius: var(--radius-full);
    background: transparent;
    color: var(--text-secondary);
    font-size: var(--font-size-small);
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    min-height: 44px;
    transition: background var(--transition-base), color var(--transition-base),
        box-shadow var(--transition-base);
}
.media-seg-btn.is-active {
    background: var(--accent-gradient);
    color: #fff;
    box-shadow: 0 4px 12px rgba(102, 126, 234, 0.36);
}
@media (hover: hover) {
    .media-seg-btn:not(.is-active):hover { color: var(--text-primary); }
}
.media-seg-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* pane: 한 번에 하나만 노출. hidden 속성 우선(레이아웃 점프 최소화). */
.media-pane {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.media-pane[hidden] { display: none; }

/* ===== 접이식 선택 정보 (details/summary) ===== */
.upload-details {
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    background-color: var(--surface-soft);
    margin-bottom: var(--space-4);
}
.upload-details__summary {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 44px;
    padding: 0 var(--space-4);
    font-size: var(--font-size-body);
    font-weight: 600;
    color: var(--text-primary);
    cursor: pointer;
    list-style: none;
    border-radius: var(--radius-md);
    -webkit-tap-highlight-color: transparent;
}
/* 기본 마커 제거 후 커스텀 화살표 */
.upload-details__summary::-webkit-details-marker { display: none; }
.upload-details__summary::before {
    content: '';
    width: 8px;
    height: 8px;
    border-right: 2px solid var(--text-secondary);
    border-bottom: 2px solid var(--text-secondary);
    transform: rotate(-45deg);
    transition: transform var(--transition-fast);
    flex-shrink: 0;
    margin-right: 2px;
}
.upload-details[open] .upload-details__summary::before {
    transform: rotate(45deg);
}
.upload-details__summary:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}
.upload-details__body {
    padding: 0 var(--space-4) var(--space-4);
}

/* ===== 인물 이미지 ===== */
.model-preview {
    display: none;
    margin-top: 12px;
    position: relative;
    width: 96px;
}
.model-preview.is-visible { display: block; }
.model-preview img {
    width: 96px;
    height: 128px;
    object-fit: cover;
    border-radius: 12px;
    border: 1px solid var(--border-color);
}
.model-preview__remove {
    /* 터치 타깃 44x44 확보. 보이는 원은 ::before로 작게 유지 */
    position: absolute;
    top: -16px;
    right: -16px;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    border: none;
    background: transparent;
    color: #fff;
    font-size: 1rem;
    cursor: pointer;
    line-height: 1;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}
.model-preview__remove::before {
    content: '';
    position: absolute;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--danger);
    box-shadow: 0 1px 6px var(--shadow-hover);
    z-index: -1;
}

/* ===== 스타일 캐러셀 (도트 넘김 · 단일 카드 뷰) =====
   가로 스크롤/드래그 대신 --style-idx 로 트랙(.style-grid)을 translateX 시켜
   한 번에 카드 하나만 노출. 뷰포트가 넘침을 감추고 도트로만 인덱스를 이동한다. */
.style-carousel {
    position: relative;
    max-width: 340px;
    margin-inline: auto;
}
/* 트랙 넘침을 감추는 뷰포트 — 카드 하나 폭만 보이게 clip.
   안쪽 여백을 둬서 카드 box-shadow / is-selected 글로우 링(3px) / hover 리프트(-3px)가
   clip 경계 안(보이는 영역)에서 렌더되도록 한다. overflow:hidden 은 트랙 클립용으로 유지.
   grid(트랙)는 이 content-box(패딩 제외) 폭을 기준으로 flex 100% 채우므로
   translateX(-idx*100%) 한 장 이동 정합은 그대로 유지된다. */
.style-viewport {
    overflow: hidden;
    padding: 14px 12px;
    /* 가로 제스처는 JS(Pointer Events)가 선점하고, 세로 스크롤은 브라우저에 양보. */
    touch-action: pan-y;
    /* 데스크톱: 잡아끌 수 있음을 커서로 암시. */
    cursor: grab;
}
/* transform 트랙: 카드들이 100% 폭으로 가로로 늘어서고, 현재 인덱스만큼 좌로 이동.
   드래그 중엔 --style-drag(px) 임시 오프셋을 더해 손가락/커서를 실시간 추적한다. */
.style-grid {
    display: flex;
    gap: 0;
    transform: translateX(calc(var(--style-idx, 0) * -100% + var(--style-drag, 0px)));
    transition: transform .32s ease;
    will-change: transform;
}
/* 드래그/스와이프 진행 중: transition 해제(라이브 추적) + 텍스트 선택/커서 처리. */
.style-grid.is-dragging {
    transition: none;
    -webkit-user-select: none;
    user-select: none;
}
.style-grid.is-dragging,
.style-grid.is-dragging .style-card { cursor: grabbing; }
/* 예시 이미지가 브라우저 기본 드래그(고스트)되지 않도록. */
.style-card__thumb-img {
    -webkit-user-drag: none;
    user-drag: none;
}
.style-card {
    /* 캐러셀 아이템: 한 화면에 카드 하나(폭 100%). 트랙 translateX 로 넘김. */
    flex: 0 0 100%;
    width: 100%;
    max-width: none;
    display: flex;
    flex-direction: column;
    border: 2px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: 0;
    background-color: var(--bg-secondary);
    cursor: pointer;
    overflow: hidden;
    text-align: left;
    box-shadow: var(--shadow-soft);
    transition: border-color var(--transition-fast), transform var(--transition-fast),
        box-shadow var(--transition-base);
    font-family: inherit;
    color: var(--text-primary);
}
.style-card:active { transform: scale(0.97); }
.style-card.is-selected {
    border-color: var(--accent-primary);
    box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.18), var(--shadow-card);
}

/* 캐러셀 위치 인디케이터(도트): 현재 노출 카드 표시 + 클릭 이동. app.js가 카드 수만큼 주입. */
.style-dots {
    display: flex;
    justify-content: center;
    /* 버튼 44px + gap 4px = 중심 간격 48px > 44 → 히트영역 겹침 0 */
    gap: 4px;
    width: 100%;
    padding: 10px 0 2px;
}
/* 버튼 자체가 44px 실히트영역. 시각 점은 ::before 로 중앙에 렌더링. */
.style-dot {
    -webkit-appearance: none;
    appearance: none;
    width: 44px;
    height: 44px;
    background: transparent;
    border: none;
    padding: 0;
    /* 시각 점(::before)의 기준점 */
    position: relative;
    cursor: pointer;
}
/* 시각 점(8px) — 44px 버튼 중앙 배치. 상태 전환은 여기(::before)에서. */
.style-dot::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 8px;
    height: 8px;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    background: var(--border-strong);
    opacity: 0.55;
    transition: transform var(--transition-fast), opacity var(--transition-fast),
        background-color var(--transition-fast);
}
.style-dot:hover::before { opacity: 0.85; }
.style-dot.is-active::before {
    background: var(--accent-primary);
    opacity: 1;
    transform: translate(-50%, -50%) scale(1.35);
}
.style-dot:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-full); }

/* ① 프리뷰 영역: 실제 예시 이미지(2:3 세로)가 채움. 틴트/색상 배경 제거.
   이미지 로드 전/폴백엔 중립 배경(--surface-soft)만 보임. */
.style-card__thumb {
    position: relative;
    aspect-ratio: 2 / 3;
    /* 폭 100% 카드에서 2:3 비율이 과도한 세로높이를 만들지 않도록 상한(초과분은 img object-fit:cover로 크롭). */
    max-height: 46vh;
    background: var(--surface-soft);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
/* 예시 이미지 전체가 잘리지 않고 온전히 보이도록 contain(레터박스는 thumb 중립배경). */
.style-card__thumb-img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
    position: relative;
    z-index: 1;
}

/* "🔍 크게 보기" — hover/포커스 시 노출(터치=no-hover 환경은 상시 노출). */
.style-card__zoom {
    position: absolute;
    right: 8px;
    bottom: 8px;
    z-index: 3;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 34px;
    padding: 0 12px;
    border-radius: var(--radius-full);
    background: rgba(255, 255, 255, 0.92);
    color: #111827;
    font-size: var(--font-size-caption);
    font-weight: 700;
    box-shadow: var(--shadow-soft);
    cursor: pointer;
    transition: opacity var(--transition-base), transform var(--transition-fast);
}
/* 터치 히트영역 44px 확보 */
.style-card__zoom::before {
    content: '';
    position: absolute;
    inset: -5px;
    border-radius: var(--radius-full);
}
.style-card__zoom:active { transform: scale(0.94); }
@media (hover: hover) {
    .style-card__zoom { opacity: 0; }
    .style-card:hover .style-card__zoom,
    .style-card__thumb:focus-within .style-card__zoom { opacity: 1; }
}
.style-card__zoom:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* 선택 표식: 색상 외 비색상 표식 — 체크 배지 + "선택됨" 텍스트(색약 대비) */
.style-card.is-selected .style-card__thumb::after {
    content: '✓';
    position: absolute;
    top: 6px;
    right: 6px;
    z-index: 4;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--accent-primary);
    color: #fff;
    font-size: 0.9rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 6px var(--shadow-hover);
}

/* ②~④ 본문 */
.style-card__body {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px 12px 12px;
}
.style-card__namerow {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}
.style-card__name {
    font-size: var(--font-size-small);
    font-weight: 600;
    color: var(--text-primary);
}
.style-card.is-selected .style-card__name::after {
    content: ' · 선택됨';
    color: var(--accent-primary);
    font-weight: 700;
}
.style-card__badge {
    display: inline-block;
    max-width: 100%;
    padding: 2px 8px;
    border-radius: var(--radius-full);
    font-size: var(--font-size-caption);
    font-weight: 700;
    line-height: 1.5;
    /* 중립 accent-soft 배지(고정 색상 표현 제거) */
    background: var(--accent-soft);
    color: var(--accent-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.style-card__desc {
    font-size: var(--font-size-caption);
    line-height: 1.45;
    color: var(--text-secondary);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* ===== 진행 표시 + 스켈레톤 ===== */
.progress {
    display: none;
    text-align: center;
    padding: 28px 18px;
    /* sticky 상단바 가림 방지 */
    scroll-margin-top: calc(var(--topbar-h) + var(--space-3));
}
.progress.is-visible { display: block; }
.spinner {
    width: 46px;
    height: 46px;
    border: 4px solid var(--border-color);
    border-top-color: var(--accent-primary);
    border-radius: 50%;
    margin: 0 auto 14px;
    animation: spin 0.9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.progress__text { font-weight: 700; letter-spacing: -0.01em; }
.progress__sub { font-size: var(--font-size-helper); color: var(--text-secondary); margin-top: 4px; }

/* 이미지 업로드 진행바 (업로드 단계에서만 노출, hidden 속성으로 제어).
   위저드 진행바(.wizard-progress__*)의 트랙/필 패턴을 그대로 따르되 클래스는 분리한다 —
   위저드 규칙은 @media(max-width:1023px) 안에만 있어 데스크톱에선 보이지 않기 때문이다. */
.upload-progress { margin: 10px auto 0; max-width: 320px; }
.upload-progress[hidden] { display: none; }
.upload-progress__track {
    position: relative;
    height: 8px;
    border-radius: var(--radius-full);
    background: var(--surface-soft);
    border: 1px solid var(--border-color);
    overflow: hidden;
}
.upload-progress__fill {
    display: block;
    height: 100%;
    width: 0%;
    border-radius: var(--radius-full);
    background: var(--accent-gradient);
    transition: width var(--transition-base);
}

/* 결과 자리 스켈레톤 (shimmer) */
.progress__skeleton {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
    margin-top: 24px;
}
.skeleton-card {
    aspect-ratio: 1024 / 1536;
    border-radius: var(--radius-md);
    background: linear-gradient(100deg,
        var(--surface-soft) 30%,
        rgba(255, 255, 255, 0.55) 50%,
        var(--surface-soft) 70%);
    background-size: 200% 100%;
    animation: shimmer 1.4s linear infinite;
}
[data-theme="dark"] .skeleton-card {
    background: linear-gradient(100deg,
        var(--surface-soft) 30%,
        rgba(255, 255, 255, 0.08) 50%,
        var(--surface-soft) 70%);
    background-size: 200% 100%;
}
@keyframes shimmer {
    to { background-position: -200% 0; }
}

/* ===== 결과 갤러리 ===== */
.results {
    display: none;
    /* sticky 상단바 가림 방지 */
    scroll-margin-top: calc(var(--topbar-h) + var(--space-3));
}
.results.is-visible { display: block; }

.result-gallery {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
}
/* 2컷 상세페이지: 세로 1열로 이어 붙여 연속 표시(상/하 컷이 이어지는 느낌) */
.result-gallery--continuous {
    gap: 0;
}
.result-gallery--continuous .result-card {
    border-radius: 0;
}
.result-gallery--continuous .result-card:not(:last-child) {
    /* 이음매 이중 테두리 방지 */
    border-bottom: 0;
}
.result-gallery--continuous .result-card:first-child {
    border-top-left-radius: var(--radius-md);
    border-top-right-radius: var(--radius-md);
}
.result-gallery--continuous .result-card:last-child {
    border-bottom-left-radius: var(--radius-md);
    border-bottom-right-radius: var(--radius-md);
}
.result-gallery--continuous .result-card__img {
    /* 세로 컷이 잘리지 않도록 원본 비율 유지(이음매 보존) */
    aspect-ratio: auto;
    object-fit: contain;
}
.result-card {
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    overflow: hidden;
    background-color: var(--bg-secondary);
    box-shadow: var(--shadow-soft);
    transition: transform var(--transition-base), box-shadow var(--transition-base);
}
.result-card__img {
    width: 100%;
    height: auto;
    /* 상세페이지 세로 비율(1024×1536 = 2:3) 유지 */
    aspect-ratio: 1024 / 1536;
    object-fit: cover;
    display: block;
    background-color: var(--border-color);
}
.result-card__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 14px;
    gap: 10px;
}
.result-card__label { font-size: var(--font-size-small); font-weight: 700; }
.result-card__dl {
    padding: 8px 14px;
    /* 다운로드는 주요 터치 액션 → min-height 44px 유지(.btn--small 36px 규격 미적용 대상) */
    min-height: 44px;
    font-size: var(--font-size-small);
    border-radius: var(--radius-sm);
}
/* 다운로드 버튼 강조 + 카드 상승: hover 환경에서만 */
@media (hover: hover) {
    .result-card:hover {
        transform: translateY(-3px);
        box-shadow: var(--shadow-card);
    }
    .result-card__dl:hover {
        border-color: var(--accent-primary);
        color: var(--accent-primary);
    }
}

/* ===== 알림 배너 ===== */
.notice {
    display: none;
    position: relative;
    padding: 12px 14px 12px 40px;
    border-radius: var(--radius-md);
    font-size: var(--font-size-helper);
    margin-bottom: 14px;
    line-height: 1.5;
    font-weight: 500;
}
.notice.is-visible { display: block; }
.notice::before {
    content: '';
    position: absolute;
    left: 14px;
    top: 50%;
    transform: translateY(-50%);
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.9;
}
.notice--info {
    background: var(--accent-soft);
    color: var(--accent-primary);
}
.notice--warn {
    background: rgba(239, 68, 68, 0.12);
    color: var(--danger);
}
.notice--success {
    background: rgba(16, 185, 129, 0.14);
    color: var(--success);
}

/* 제목형 안내(2줄 구성) — 자동 추출 실패처럼 "무슨 상황인지"를 먼저 인지시켜야 하는 경우.
   .notice 의 원형 아이콘은 1줄 기준(top:50%)이라 여러 줄에서는 첫 줄에 맞춘다. */
.notice--block::before {
    top: 15px;
    transform: none;
}
.notice__title {
    display: block;
    font-size: var(--font-size-body);
    font-weight: 700;
    margin-bottom: 4px;
}
.notice__body { display: block; font-weight: 500; }

/* ===== 토스트 ===== */
.toast {
    position: fixed;
    left: 50%;
    bottom: calc(24px + env(safe-area-inset-bottom, 0px));
    transform: translateX(-50%) translateY(20px);
    background-color: #111827;
    color: #fff;
    padding: 12px 20px;
    border-radius: var(--radius-full);
    font-size: 0.85rem;
    font-weight: 600;
    box-shadow: var(--shadow-lg);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--transition-base), transform var(--transition-base);
    z-index: 2000;
    max-width: 90vw;
    text-align: center;
}
.toast.is-visible {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}

/* ===== 앱 게이팅 ===== */
.app-hidden { display: none !important; }

/* ===== 로그인 페이지 ===== */
.login-wrap {
    position: relative;
    min-height: calc(100vh - var(--topbar-h));
    min-height: calc(100dvh - var(--topbar-h));
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    overflow: hidden;
}
/* 은은한 blur blob 배경 */
.login-wrap::before,
.login-wrap::after {
    content: '';
    position: absolute;
    border-radius: 50%;
    filter: blur(70px);
    pointer-events: none;
    z-index: 0;
}
.login-wrap::before {
    width: 320px;
    height: 320px;
    top: -60px;
    left: -40px;
    background: rgba(118, 75, 162, 0.28);
}
.login-wrap::after {
    width: 360px;
    height: 360px;
    bottom: -80px;
    right: -60px;
    background: rgba(102, 126, 234, 0.26);
}
[data-theme="dark"] .login-wrap::before { background: rgba(118, 75, 162, 0.22); }
[data-theme="dark"] .login-wrap::after { background: rgba(102, 126, 234, 0.20); }

.login-card {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: 400px;
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-xl);
    padding: var(--space-10) var(--space-8);
    text-align: center;
    box-shadow: var(--shadow-lg);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
}
@supports (backdrop-filter: blur(10px)) or (-webkit-backdrop-filter: blur(10px)) {
    .login-card { background-color: rgba(255, 255, 255, 0.82); }
    [data-theme="dark"] .login-card { background-color: rgba(20, 23, 30, 0.72); }
}
.login-card__logo { height: 40px; margin: 0 auto 20px; width: auto; }
.login-card__logo-black { display: block; margin: 0 auto 20px; }
.login-card__logo-white { display: none; margin: 0 auto 20px; }
[data-theme="dark"] .login-card__logo-black { display: none; }
[data-theme="dark"] .login-card__logo-white { display: block; }
.login-card__title {
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin-bottom: 10px;
}
.login-card__sub {
    font-size: 0.9rem;
    color: var(--text-secondary);
    margin-bottom: 28px;
    line-height: 1.65;
}
.google-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    padding: 14px;
    min-height: 52px;
    border-radius: var(--radius-md);
    text-decoration: none;
    font-weight: 700;
    font-size: 0.98rem;
    background: var(--accent-gradient);
    color: #fff;
    box-shadow: 0 8px 22px rgba(102, 126, 234, 0.34);
    transition: transform var(--transition-fast), box-shadow var(--transition-base);
}
.google-btn:active { transform: scale(0.98); }
.google-btn__g {
    background: #fff;
    color: #4285f4;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 900;
    font-size: 0.95rem;
}
.login-card__foot {
    margin-top: 22px;
    font-size: 0.76rem;
    color: var(--text-muted);
}

/* ===== 설정 오버레이/모달 (OpenAI API 키) ===== */
.settings-overlay {
    position: fixed;
    inset: 0;
    background: var(--overlay-bg);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
    display: none;
    align-items: flex-end;
    justify-content: center;
    z-index: 2100;
    padding: 0;
}
.settings-overlay.is-visible { display: flex; }
.settings-modal {
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    width: 100%;
    max-width: 520px;
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    padding: 22px 18px calc(24px + env(safe-area-inset-bottom, 0px));
    box-shadow: var(--shadow-lg);
    max-height: 88vh;
    overflow-y: auto;
    /* 스크롤바: 표준 속성만 사용(::-webkit-scrollbar 금지) */
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
}
.settings-modal__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 16px;
}
.settings-modal__title {
    font-size: 1.1rem;
    font-weight: 700;
    letter-spacing: -0.02em;
}
.settings-modal__close {
    position: relative;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 1px solid var(--border-color);
    background-color: var(--surface-soft);
    color: var(--text-primary);
    font-size: 1.3rem;
    line-height: 1;
    cursor: pointer;
    flex-shrink: 0;
    transition: transform var(--transition-fast), background-color var(--transition-fast);
}
.settings-modal__close::before {
    content: '';
    position: absolute;
    inset: -2px;
    border-radius: 50%;
}
.settings-modal__close:active { transform: scale(0.92); }
.settings-modal__body { margin-top: 4px; }

@media (min-width: 560px) {
    .settings-overlay { align-items: center; }
    .settings-modal { border-radius: var(--radius-xl); }
}

/* ===== 스타일 프리뷰 모달 (설정 모달 오버레이 패턴/토큰 재사용) ===== */
.style-preview-overlay {
    position: fixed;
    inset: 0;
    background: var(--overlay-bg);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
    display: none;
    align-items: flex-end;
    justify-content: center;
    z-index: 2100;
}
.style-preview-overlay.is-visible { display: flex; }
.style-preview-modal {
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    width: 100%;
    max-width: 520px;
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    padding: 22px 18px calc(24px + env(safe-area-inset-bottom, 0px));
    box-shadow: var(--shadow-lg);
    max-height: 88vh;
    overflow-y: auto;
    /* 스크롤바: 표준 속성만 사용(::-webkit-scrollbar 금지) */
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
}
.style-preview-modal__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: 14px;
}
.style-preview-modal__title {
    font-size: 1.1rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    min-width: 0;
}
/* 예시 이미지 슬롯 컨테이너(최대 2장). 좁은 화면은 세로, 넓은 화면은 가로 2열. */
.style-preview-modal__figures {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
@media (min-width: 560px) {
    .style-preview-modal__figures {
        flex-direction: row;
    }
    .style-preview-modal__figures .style-preview-modal__figure {
        flex: 1 1 0;
        min-width: 0;
    }
}
.style-preview-modal__figure {
    border-radius: var(--radius-md);
    overflow: hidden;
    border: 1px solid var(--border-color);
    background: var(--surface-soft);
}
.style-preview-modal__figure img {
    width: 100%;
    height: auto;
    display: block;
}
.style-preview-modal__badge {
    display: inline-block;
    margin-top: 14px;
    padding: 4px 12px;
    border-radius: var(--radius-full);
    font-size: 0.76rem;
    font-weight: 700;
    background: var(--accent-soft);
    color: var(--accent-primary);
}
.style-preview-modal__desc {
    margin-top: 12px;
    font-size: 0.88rem;
    line-height: 1.6;
    color: var(--text-secondary);
}
@media (min-width: 560px) {
    .style-preview-overlay { align-items: center; }
    .style-preview-modal { border-radius: var(--radius-xl); }
}

/* ===== 좁은 화면 상단바 한 줄 유지 (<=559px) =====
   375/390/414px 등 흔한 폭에서 로고+네비+우측그룹 합산 폭이 넘치지 않도록
   패딩·gap 축소 + 로고텍스트 숨김(display:none).
   텍스트는 유지(라벨 낭독 보존). <=360 블록이 이후에 와 최종 축소값을 덮음.
   🔴 경계가 560 이 아니라 559 인 이유: 위 모달 블록들이 min-width:560px 이라
      560 을 그대로 두면 정확히 560px 에서 두 블록이 동시에 매치된다(대상 선택자가
      서로 소라 실렌더 모순은 없었지만 경계 의미가 모순이었다). 이 파일의 기존
      관행인 max/min 1px 쌍(max-width:1023px ↔ min-width:1024px)에 맞춰 559/560 으로
      정렬한다 → 560px 부터는 "넓은 쪽" 규격으로 일관된다. */
@media (max-width: 559px) {
    .topbar { gap: var(--space-2); padding: 0 var(--space-3); }
    .topbar__logo-text {
        font-size: 1.06rem;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        min-width: 0;
    }
    .topbar__logo-text { display: none; }
    .topnav { gap: 1px; padding: 3px; }
    .topnav__item { padding: 0 10px; gap: 5px; font-size: 0.82rem; }
    .topbar__right { gap: 4px; }
}

/* ===== 아주 작은 화면 대응 (<=360px) ===== */
@media (max-width: 360px) {
    /* 하단 값은 0 — sticky 바 여백은 .controls-panel 80px 로 일원화(위 .app 주석 참고).
       상/좌우 12px 축소만 이 브레이크포인트의 목적이다. */
    .app { padding: 12px 12px 0; }
    .section { padding: 16px; }
    .field-row { flex-direction: column; gap: 0; }
    .url-row { flex-direction: column; }
    /* 캐러셀은 한 화면에 카드 하나 — 좁은 화면에서도 폭 100% 유지 */
    .style-card { width: 100%; }
    /* 상단바 넘침 방지: 로고 텍스트 축소, 네비 패딩 축소 */
    .topbar { gap: var(--space-2); padding: 0 var(--space-3); }
    .topbar__logo-text { font-size: 1.02rem; }
    .topnav { gap: 0; padding: 3px; }
    .topnav__item { padding: 0 9px; gap: 4px; font-size: 0.8rem; }
}

/* ============================================================
   결과 빈 상태 안내
   ============================================================ */
.results-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: var(--space-2);
    padding: var(--space-9) var(--space-5);
    margin-bottom: 18px;
    background-color: var(--bg-secondary);
    border: 1.5px dashed var(--border-strong);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-soft);
    color: var(--text-secondary);
}
.results-empty__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 72px;
    height: 72px;
    border-radius: 50%;
    background: var(--accent-soft);
    font-size: 2.2rem;
    line-height: 1;
    margin-bottom: var(--space-2);
}
.results-empty__title {
    font-weight: 700;
    font-size: var(--fs-md);
    letter-spacing: -0.01em;
    color: var(--text-primary);
}
.results-empty__desc {
    font-size: var(--fs-sm);
    line-height: 1.6;
}

/* 진행/결과가 표시되면(:has 지원 브라우저) 빈 상태 숨김. */
.results-area:has(#progress.is-visible) .results-empty,
.results-area:has(#results.is-visible) .results-empty {
    display: none;
}

/* ============================================================
   포커스 링 (키보드 접근성)
   ============================================================ */
.btn:focus-visible,
.tab:focus-visible,
.theme-toggle:focus-visible,
.user-chip:focus-visible,
.user-dropdown__item:focus-visible,
.topnav__item:focus-visible,
.style-card:focus-visible,
.google-btn:focus-visible,
.settings-modal__close:focus-visible,
.model-preview__remove:focus-visible,
.result-card__dl:focus-visible,
.input:focus-visible,
.textarea:focus-visible,
.select:focus-visible,
.upload-drop:focus-within,
input[type="range"]:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}
.style-card:focus-visible { border-color: var(--accent-primary); }

/* ============================================================
   hover 지원 환경에서만 상승 인터랙션 (터치 오조작 방지)
   ============================================================ */
@media (hover: hover) {
    .section:hover { box-shadow: var(--shadow-card); }
    .btn--primary:hover:not(:disabled) {
        transform: translateY(-2px);
        box-shadow: 0 10px 26px rgba(102, 126, 234, 0.36);
    }
    .btn--secondary:hover:not(:disabled) {
        transform: translateY(-2px);
        border-color: var(--accent-primary);
        box-shadow: var(--shadow-soft);
    }
    .btn--cta:hover:not(:disabled) {
        transform: translateY(-2px);
        box-shadow: 0 14px 34px rgba(102, 126, 234, 0.42);
    }
    /* 삭제 버튼 hover. 터치기기에서 confirm 취소 후 빨간 잔상이 남지 않도록
       다른 .btn--* hover 와 동일하게 이 블록 안 + :not(:disabled) 규격을 맞춘다. */
    .btn--danger:hover:not(:disabled) { background-color: rgba(239, 68, 68, 0.16); }
    .style-card:hover {
        transform: translateY(-3px);
        border-color: var(--accent-primary);
        box-shadow: var(--shadow-card);
    }
    .tab:not(.is-active):hover { color: var(--text-primary); }
    .theme-toggle:hover {
        background-color: var(--bg-secondary);
        box-shadow: var(--shadow-soft);
    }
    .google-btn:hover {
        transform: translateY(-2px);
        box-shadow: 0 12px 30px rgba(102, 126, 234, 0.42);
    }
    .settings-modal__close:hover { background-color: var(--border-color); }
}

/* ============================================================
   반응형 브레이크포인트
   ============================================================ */

/* ≥769: 태블릿 — 여백/타이포 소폭 상향 (여전히 1열)
   🔴 경계가 768 이 아니라 769 다. 예전엔 768 이었는데, 그러면 정확히 768px 에서
      .app 만 태블릿 규격이 되고 상단바(.topbar:has(.topnav), min-width:769px)는
      모바일 배치로 남아 한 뷰포트 안에서 규격이 갈렸다.
      769 쪽으로 통일한 이유: 769 는 실측 근거가 붙은 경계다(위 .topbar:has(.topnav)
      주석 — 561~768 구간은 우측그룹 하드플로어 ≈178px 가 side 트랙 ≈177px 를 침범할
      여지가 있어 grid 를 걸지 않는다). admin.css 의 .topbar:has(.tabs) 도 769 를 쓴다.
      반대로 이 블록의 768 은 여백만 올리는 관용 브레이크포인트라 근거가 없다.
      → 근거 있는 쪽(769)을 남기고 근거 없는 쪽을 맞춘다. */
@media (min-width: 769px) {
    .app {
        max-width: 640px;
        /* 하단 값은 0 — sticky 바 여백은 .controls-panel 80px 로 일원화.
           이 블록은 min-width:769 라 ≥1024 에도 상속되지만, ≥1024 블록의
           `.app { padding: var(--space-7) var(--space-7) 0 }` 이 동일 특이도
           (0,1,0) + 소스 뒤라 그대로 이긴다(기존과 동일). 이제 하단 값이
           양쪽 다 0 이라 충돌 자체가 없다. */
        padding: var(--space-6) var(--space-6) 0;
    }
    .section { padding: var(--space-6); }
    /* .section__title 크기는 --font-size-step-title 토큰이 전 구간을 담당 → 뷰포트별 개별 override 제거 */
    /* 태블릿 이상에서도 한 화면에 카드 하나 — 폭 100% 유지 */
    .style-card { width: 100%; }
    /* 업로드 폼 컨테이너: 넓은 화면에서 과도한 가로폭 방지 */
    #panelUpload { max-width: 720px; }
}

/* ============================================================
   사이트 푸터 (사업자 정보 / 법적 고지) — index.html / history.html /
   terms.html / privacy.html 4곳 공용
   🔴 푸터 마크업은 4개 파일에 각각 복제되어 있다(공용 템플릿이 없다).
      법정 표기(상호·대표자·사업자등록번호·통신판매업신고·주소·연락처·
      개인정보보호책임자)를 고칠 때는 반드시 4파일을 동시에 수정해야 한다.
      한 곳만 고치면 표기가 갈라지고, 갈라진 사실이 화면에서 드러나지 않는다.
   기본(≤1023): 고정 높이 없이 자연 높이. 상단 여백은 margin 이 아니라
   padding-top 으로 잡는다(마진은 높이 예산 밖이라 데스크톱에서 스크롤을 되살림).
   데스크톱(≥1024) 전용 고정 높이 규칙은 아래 min-width:1024px 블록에 있으므로
   이 기본 블록은 반드시 그 앞에 와야 한다(동일 특이도 → 소스 순서로 결정).
   ============================================================ */
.site-footer {
    border-top: 1px solid var(--border-color);
    padding-top: 18px;
    font-size: 12px;
    line-height: 1.6;
    color: var(--text-secondary);
}
.site-footer__inner {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
/* 사업자 정보 그룹 / 법적 링크·저작권 그룹.
   기본(≤1023)에서는 두 그룹 모두 세로 스택 + 좌측정렬로, 교체 전 3행 흐름과
   동일하게 보인다(2단 배치는 ≥1024 블록에서만 켠다). */
.site-footer__biz,
.site-footer__meta {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.site-footer__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0 6px;
}
/* 구분점 '·': --border-strong 는 배경 대비 약 1.3~1.5:1 이라 사실상 렌더되지 않는다.
   --text-muted(라이트 #9ca3af / 다크 #71717a)로 본문보다 흐리되 확실히 보이게 한다. */
.site-footer__sep { color: var(--text-muted); }
.site-footer__link {
    color: inherit;
    text-decoration: none;
}
.site-footer__link:hover {
    color: var(--text-primary);
    text-decoration: underline;
}
.site-footer__link:focus-visible {
    outline: none;
    border-radius: var(--radius-sm);
    box-shadow: var(--focus-ring);
}

/* ≥1024: 2단 워크스페이스 */
@media (min-width: 1024px) {
    .app {
        /* --app-gap-b = workspace 하단 여백(데스크톱 전용).
           workspace(패널/결과영역) 아래에 이만큼 빈 공간을 남기고, 그 자리를
           .site-footer 의 margin-top 이 그대로 채운다 → 푸터는 첫 화면(100vh)
           바로 아래에서 시작하고 border-top 조차 노출되지 않는다.
           상단 여백(.app padding-top = --space-7)과 같은 값이라 위아래가 대칭.
           .app 자체의 padding-bottom 은 반드시 0 이어야 아래 산술이 성립한다:
             문서높이 = 64(topbar) + 28(pad-t) + (100vh−64−28−28)(workspace)
                      + 28(footer margin-top) + F(푸터 자연높이) = 100vh + F
           → 스크롤량이 정확히 푸터 높이 F. F 가 소거되지 않고 그대로 남으므로
             푸터 높이가 바뀌어도(2줄/3줄) 산술은 그대로 성립한다. */
        --app-gap-b: var(--space-7);
        max-width: 1320px;
        padding: var(--space-7) var(--space-7) 0;
    }
    /* 데스크톱: 단일 카드 뷰 컨테이너 폭을 소폭 축소 */
    .style-carousel { max-width: 300px; }
    .workspace {
        grid-template-columns: var(--panel-w) minmax(0, 1fr);
        gap: var(--space-7);
        align-items: start;
    }
    .controls-panel {
        position: sticky;
        top: calc(var(--topbar-h) + var(--space-7));
        align-self: start;
        /* 2단 선언(100vh → 100dvh). --topbar-h/--space-7/--app-gap-b 항은 불변.
           iPad 가로처럼 폭 ≥1024 이면서 툴바가 접히는 환경에서 100vh 가
           실제 가시 높이보다 커져 패널이 화면 밖으로 밀리는 것을 막는다. */
        max-height: calc(100vh - var(--topbar-h) - var(--space-7) - var(--app-gap-b));
        max-height: calc(100dvh - var(--topbar-h) - var(--space-7) - var(--app-gap-b));
        overflow-y: auto;
        /* 스크롤바 여백 확보 + 포커스 링 클리핑 방지 */
        padding-right: var(--space-1);
        margin-right: calc(var(--space-1) * -1);
        /* 스크롤바: 표준 속성만 사용(::-webkit-scrollbar 금지).
           Chrome/Edge 121+ 는 scrollbar-width ≠ auto 인 요소의 webkit 의사요소를
           무시하므로 두 방식을 섞으면 브라우저별로 디자인이 갈린다. */
        scrollbar-width: thin;
        scrollbar-color: var(--border-strong) transparent;
    }
    /* 2단 선언(100vh → 100dvh). 나머지 항은 불변이라 문서높이 산술
       64 + 28 + (100dvh−120) + 28 + F = 100dvh + F 가 그대로 성립한다. */
    .results-area { min-height: calc(100vh - var(--topbar-h) - var(--space-7) - var(--app-gap-b)); }
    .results-area { min-height: calc(100dvh - var(--topbar-h) - var(--space-7) - var(--app-gap-b)); }
    /* 연속 결과 갤러리(2컷 상세페이지)는 데스크톱에서도 항상 1열 세로 유지 */
    .result-gallery:not(.result-gallery--continuous) {
        grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    }
    .progress__skeleton {
        grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    }
    .results-empty { padding: var(--space-10) var(--space-6); }
    .results-empty__icon { width: 84px; height: 84px; font-size: 2.8rem; }

    /* 선택된 상품 미리보기: 스크롤되는 컨트롤 패널 안에서 하단 sticky 보조영역으로 유지.
       (≤1023에서는 기본 하단 흐름 그대로) */
    .preview-card.is-visible {
        position: sticky;
        bottom: var(--space-2);
        z-index: 1;
    }

    /* 사이트 푸터: 첫 화면(100vh) 바로 아래에서 시작한다.
       margin-top: var(--app-gap-b) 가 workspace 하단 여백을 그대로 채우므로
       푸터의 border-top 선조차 초기 화면에 노출되지 않고, 스크롤을 내려야 보인다.
       (여백을 .app 의 padding-bottom 으로 잡으면 푸터가 그만큼 위로 올라와
        상단 28px + 경계선이 첫 화면에 노출되어 요구사항 위반이다.)
       min-height 를 두지 않는 이유: 문서높이 = 100vh + F 산술에서 푸터 높이 F 는
       소거되지 않고 그대로 남는다 → 높이를 고정할 필요가 없고, 2줄/3줄 어느
       구성이든 스크롤량 = 푸터 높이가 자동으로 성립한다.
       또 Chrome '최소 글꼴 크기' 강제 등으로 내용이 커져도 자연히 자라므로
       사업자정보·통신판매업신고번호(표기 의무 대상)가 잘릴 위험이 없다. */
    .site-footer {
        box-sizing: border-box;
        margin: var(--app-gap-b) 0 0;
        border-top: 1px solid var(--border-color);
        padding: 24px 0 20px;
        /* 세로 중앙정렬은 푸터 자신이 flex 컨테이너가 되어 처리한다.
           자식에 height: 100% 를 주는 방식은 부모가 min-height 인 경우
           퍼센트 높이의 기준(definite height)이 없어 auto 로 떨어질 수 있다. */
        display: flex;
        align-items: center;
    }
    .site-footer__inner {
        /* 콘텐츠 폭을 그대로 채운다(블록이던 때와 동일한 가로 레이아웃).
           min-width: 0 은 flex 아이템 기본값 min-width: auto 로 인해
           내용 최소폭이 가용폭을 넘길 때 가로 오버플로가 생기는 것을 막는다. */
        flex: 1;
        min-width: 0;
        display: flex;
        /* 데스크톱 2단: 왼쪽 사업자정보 / 오른쪽 법적 링크·저작권.
           두 그룹이 같은 줄을 나눠 쓰되 구역은 분리된다. */
        flex-direction: row;
        justify-content: space-between;
        align-items: center;
        gap: var(--space-6);
    }
    /* 오른쪽 그룹은 오른쪽 끝에 맞춘다(윗줄: 이용약관·개인정보처리방침 / 아랫줄: 저작권). */
    .site-footer__meta {
        align-items: flex-end;
        text-align: right;
    }
    .site-footer__meta .site-footer__row { justify-content: flex-end; }
    /* 데스크톱에서도 .site-footer__row 는 기본값(flex-wrap: wrap)을 그대로 쓴다.
       nowrap 이면 Chrome '최소 글꼴 크기' 강제처럼 폰트가 커지는 조건에서 행 실폭이
       가용폭(≈953px)을 넘어 가로 오버플로 → 가로 스크롤바가 생기고, 가로 스크롤바가
       가시 높이를 먹는 동안 100vh 는 줄지 않아 세로 스크롤까지 되살아난다.
       자연 줄바꿈을 허용하면 그 경로가 막힌다. */

    /* history.html 전용: 푸터를 뷰포트 바닥에 붙인다.
       index.html 은 .results-area 의 min-height 가 문서를 100vh 로 밀어주지만
       history.html 에는 그런 최소높이 컨테이너가 없어 푸터가 화면 중간에 떴다.
       🔴 .app 전역에 display:flex 를 주면 안 된다 — index.html 의 .workspace(그리드)가
          flex 아이템이 되어 폭 계산이 달라진다. 반드시 .app--history 스코프 유지.
       margin-top: auto 는 남는 공간을 흡수할 뿐 높이를 만들지 않으므로,
       이력이 많아 콘텐츠가 길면 min-height 를 넘겨 자연히 늘어나고 푸터는 맨 아래에 남는다. */
    .app--history {
        display: flex;
        flex-direction: column;
        /* 2단 선언(100vh → 100dvh). --topbar-h 항은 불변. */
        min-height: calc(100vh - var(--topbar-h));
        min-height: calc(100dvh - var(--topbar-h));
    }
    .app--history .site-footer { margin-top: auto; }
}

/* ≥1440: 넓은 데스크톱 */
@media (min-width: 1440px) {
    .app {
        max-width: 1480px;
    }
    .workspace { gap: var(--space-8); }
}

/* ============================================================
   모바일 하단 sticky 생성 CTA (<1024)
   ============================================================ */
@media (max-width: 1023px) {
    .cta-wrap {
        position: sticky;
        bottom: 0;
        z-index: 50;
        margin-top: 10px;
        padding: 12px 0 calc(12px + env(safe-area-inset-bottom, 0px));
        /* 컨텐츠가 자연스럽게 아래로 스크롤되어 들어가도록 페이드 */
        background: linear-gradient(to top,
            var(--bg-primary) 62%,
            rgba(247, 248, 252, 0) 100%);
    }
    [data-theme="dark"] .cta-wrap {
        background: linear-gradient(to top,
            var(--bg-primary) 62%,
            rgba(11, 13, 18, 0) 100%);
    }
    /* sticky 바에 컨텐츠가 가리지 않도록 하단 여유.
       🔴 .app 에 주면 안 된다 — .site-footer 가 .app 의 마지막 자식이라
       그 여백이 "푸터 아래"(sticky 바가 도달할 수 없는 위치)에 붙어
       모바일 푸터 밑 빈 공간만 만든다. sticky 바(.cta-wrap / #wizardNav)는
       둘 다 .controls-panel 직속이므로 겹칠 수 있는 컨테이너는 거기다.
       값 80px = .cta-wrap 실측(12 + .btn--cta min-height 56 + 12).
       (#wizardNav 는 12+48+12=72px 라 80px 안에 포함된다.)
       ≥1024 에서는 이 블록이 적용되지 않으므로 .app 의 padding 3번째 값
       0 이 그대로 유지되어 데스크톱 높이 산술은 불변이다. */
    .controls-panel { padding-bottom: calc(80px + env(safe-area-inset-bottom, 0px)); }
}

/* ============================================================
   상세페이지 사이즈 시각 선택 (index.html 로컬 <style> 에서 이관)
   3옵션을 실제 비율(2:3 / 1:1 / 3:2)로 크기 비교되는 박스 프리뷰로 렌더.
   선택값은 hidden #imageSize select 로 계약 보존.
   ============================================================ */
.size-options { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 4px; }
.size-option {
    flex: 1 1 0; min-width: 92px;
    display: flex; flex-direction: column; align-items: center; gap: 10px;
    padding: 14px 10px;
    background: transparent;
    border: 1.5px solid var(--border-color);
    border-radius: 12px;
    cursor: pointer; color: var(--text-primary); font: inherit;
    transition: border-color .15s ease, background .15s ease;
}
.size-option:hover { border-color: var(--accent-primary); }
.size-option.is-selected {
    border-color: var(--accent-primary);
    background: var(--accent-soft);
}
.size-option__frame {
    height: 96px; display: flex; align-items: flex-end; justify-content: center;
}
/* 공통 스케일(1024→60px, 1536→90px)로 실제 비율 비교. */
.size-option__box {
    background: var(--border-color);
    border: 1px solid var(--text-secondary);
    border-radius: 4px;
}
.size-option.is-selected .size-option__box {
    background: var(--accent-primary);
    border-color: var(--accent-primary);
}
.size-option__label {
    font-size: var(--font-size-caption); line-height: 1.35; text-align: center;
    color: var(--text-secondary);
}
.size-option.is-selected .size-option__label {
    color: var(--text-primary); font-weight: 600;
}
.size-option:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; }

/* ===== 스타일 지정 방식 2모드 세그먼트 — .media-segment/.media-seg-btn 패턴 재사용 ===== */
/* 세그먼트 자체 스타일은 .media-segment 를 그대로 쓰고, 여백만 이 섹션에 맞춘다. */
.style-mode-seg { margin-top: 4px; }
/* 비활성(관리자 미설정) 모드 버튼: 눌리지 않음을 시각적으로 명확히. */
.media-seg-btn:disabled,
.media-seg-btn[aria-disabled="true"] {
    opacity: 0.45;
    cursor: not-allowed;
}
@media (hover: hover) {
    .media-seg-btn:disabled:hover { color: var(--text-secondary); }
}
/* 패널: 한 번에 하나만 노출(hidden 속성 기준). */
.style-mode-pane { margin-top: var(--space-3); }
.style-mode-pane[hidden] { display: none; }

/* ===== 원하는 스타일 이미지 첨부 — thumb-grid/model-preview 패턴 재사용 ===== */
.ref-attach { margin-top: 16px; }
.ref-attach__hint {
    font-size: var(--font-size-helper); color: var(--text-secondary); margin: 6px 0 0;
}

/* ============================================================
   영역B · 모바일 스텝 위저드 (<=1023 전용, additive)
   - 전 규칙이 @media (max-width:1023px) 안에만 존재 → 데스크톱(>=1024) 완전 무변경.
   - 위저드 크롬(#wizardProgress/#wizardNav)은 기본 hidden. .controls-panel.is-wizard 활성 시에만 노출.
   - controls-panel 직속 .section 5개 중 .is-current 만 표시. 마지막 스텝에서 .cta-wrap 동반 노출.
   ============================================================ */
@media (max-width: 1023px) {
    /* --- 스텝 게이팅: 위저드 활성 시 현재 스텝만 표시 --- */
    .controls-panel.is-wizard > .section:not(.is-current) { display: none; }

    /* --- 생성 CTA: 위저드 활성 시 기본 숨김, 마지막 스텝(5)에서만 노출 --- */
    .controls-panel.is-wizard .cta-wrap { display: none; }
    .controls-panel.is-wizard.is-laststep .cta-wrap {
        display: block;
        /* 위저드에선 sticky 대신 흐름 배치 → 하단 #wizardNav sticky와 겹치지 않게 */
        position: static;
        z-index: auto;
        padding: 0;
        margin-top: 12px;
        background: none;
    }

    /* --- 진행 표시 (진행바 + n/5 인디케이터) --- */
    .controls-panel.is-wizard #wizardProgress {
        display: flex;
        align-items: center;
        gap: 12px;
        margin-bottom: 16px;
    }
    .wizard-progress__track {
        position: relative;
        flex: 1;
        height: 8px;
        border-radius: var(--radius-full);
        background: var(--surface-soft);
        border: 1px solid var(--border-color);
        overflow: hidden;
    }
    .wizard-progress__fill {
        display: block;
        height: 100%;
        /* 5스텝 중 1스텝 = 20%. activate() 직후 render() 가 즉시 덮어쓰므로 시각 결함은
           없지만, 값이 스텝 수와 어긋나 있으면 다음 사람이 스텝 수를 오독한다. */
        width: 20%;
        border-radius: var(--radius-full);
        background: var(--accent-gradient);
        transition: width var(--transition-base);
    }
    .wizard-progress__count {
        flex-shrink: 0;
        font-size: var(--font-size-small);
        font-weight: 700;
        color: var(--text-secondary);
        font-variant-numeric: tabular-nums;
    }

    /* --- 하단 이전/다음 네비 (sticky bottom + safe-area) --- */
    .controls-panel.is-wizard #wizardNav {
        display: flex;
        gap: 12px;
        position: sticky;
        bottom: 0;
        /* cta(50)보다 위, 상단바(100)보다 아래 */
        z-index: 60;
        margin-top: 12px;
        padding: 12px 0 calc(12px + env(safe-area-inset-bottom, 0px));
        background: linear-gradient(to top,
            var(--bg-primary) 62%,
            rgba(247, 248, 252, 0) 100%);
    }
    [data-theme="dark"] .controls-panel.is-wizard #wizardNav {
        background: linear-gradient(to top,
            var(--bg-primary) 62%,
            rgba(11, 13, 18, 0) 100%);
    }
    /* 버튼 균등 분할 + 최소 터치 타깃(.btn min-height:48px 상속) */
    .wizard-nav__btn { flex: 1; min-height: 48px; }
    /* 마지막 스텝: '다음' 숨김 → 기존 #generateBtn 사용, '이전'만 남김 */
    .controls-panel.is-wizard.is-laststep #wizardNext { display: none; }
}

/* ============================================================
   모션 감소 선호 (접근성)
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
    /* 배경 무드 고정 (이미 정적이나 명시) */
    body { background-attachment: scroll; }
    .skeleton-card { background-position: 0 0; }
}

/* ============================================================
   영역2 · 생성 이력 페이지 (history.html) — 기존 .section/.result-card 재사용에
   더해 이력 전용 배치만 추가(additive). 기존 계약/스타일 회귀 없음.
   ============================================================ */
.history-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: 18px;
}
.history-toolbar__title {
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: -0.02em;
}
.history-list {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0;
}
.history-job__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: 14px;
    flex-wrap: wrap;
}
.history-job__title {
    font-size: 1.02rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    min-width: 0;
    word-break: break-word;
}
.history-job__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 6px;
    font-size: 0.82rem;
    color: var(--text-secondary);
}
.history-chip {
    display: inline-flex;
    align-items: center;
    padding: 3px 10px;
    border-radius: var(--radius-full);
    background: var(--surface-soft);
    border: 1px solid var(--border-color);
    font-size: 0.76rem;
    font-weight: 600;
    color: var(--text-secondary);
    white-space: nowrap;
}
.history-chip--completed { color: #1a7f37; border-color: rgba(26, 127, 55, 0.4); }
.history-chip--partial { color: #b26a00; border-color: rgba(178, 106, 0, 0.4); }
.history-chip--failed { color: #c02626; border-color: rgba(192, 38, 38, 0.4); }
.history-chip--processing,
.history-chip--pending { color: var(--accent-primary); border-color: rgba(102, 126, 234, 0.4); }

.history-thumbs {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 12px;
}
.history-thumbs .result-card__img {
    /* 이력 썸네일은 더 촘촘하게(높이 과다 방지). 비율만 살짝 조정. */
    aspect-ratio: 1024 / 1536;
}
.history-cut__label {
    font-size: var(--fs-sm);
    font-weight: 700;
    padding: 8px 10px;
}
/* 이력 썸네일 foot — 'CUT n' 라벨 + '⬇ 저장' 버튼 한 줄 유지.
   .result-card__foot / .result-card__dl / .history-cut__label 은 생성 결과 화면
   (index.html)과 공유하는 전역 클래스라 손대지 않고, 이력 전용 컨테이너
   .history-thumbs(history.js 에서만 부착) 하위로만 스코프한다.
   그리드 minmax 하한 150px = 최악 컬럼폭 기준 계산:
     가용 = 150 - 20(foot 좌우 패딩) - 8(gap) = 122px
     필요 = 라벨 39.2(패딩 0) + 버튼 46.9+16(패딩 8+8) = 102.1 … +gap 8 = 110.1px
   → 모든 뷰포트에서 여유 ≈11.9px. 44px 터치 타깃(min-height)은 그대로 둔다. */
.history-thumbs .result-card__foot {
    padding: 12px 10px;
    gap: 8px;
    /* 안전망: 만약 넘치더라도 글자가 2줄로 접히거나 잘리지 않고 줄만 나뉜다 */
    flex-wrap: wrap;
}
.history-thumbs .history-cut__label {
    padding-left: 0;
    padding-right: 0;
    white-space: nowrap;
}
.history-thumbs .result-card__dl {
    padding-left: 8px;
    padding-right: 8px;
    white-space: nowrap;
}
.history-empty {
    text-align: center;
    padding: var(--space-10) var(--space-6);
    color: var(--text-secondary);
}
.history-empty__icon { font-size: 2.6rem; margin-bottom: 12px; }
.history-empty__title { font-size: 1.05rem; font-weight: 700; color: var(--text-primary); margin-bottom: 8px; }
.history-empty__desc { font-size: var(--fs-sm); line-height: 1.6; }
.history-empty .btn { margin-top: 16px; }

/* 이력 카드 우측 액션(상태 chip + 삭제 버튼) */
.history-job__actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}
/* 이력 삭제 버튼 — 44x44 터치 히트영역(투명), 보이는 배지는 ::before(thumb-del 패턴 재사용) */
.history-del {
    position: relative;
    width: 44px;
    height: 44px;
    border: none;
    background: transparent;
    cursor: pointer;
    padding: 0;
    -webkit-tap-highlight-color: transparent;
    transition: transform var(--transition-fast);
}
.history-del::before {
    content: '×';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--surface-soft);
    border: 1px solid var(--border-color);
    color: var(--danger);
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
}
.history-del:active { transform: scale(0.9); }
.history-del:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.history-del:disabled { opacity: 0.5; cursor: not-allowed; }

/* ============================================================
   타이포 토큰 · 소형 화면 축소 (<=640px)
   토큰 값만 재정의 → 이를 참조하는 모든 컴포넌트가 일괄 축소된다.
   (개별 선택자 override 를 두지 않는 이유: 일관성 단일 소스 유지)
   ============================================================ */
@media (max-width: 640px) {
    :root {
        --font-size-display: 24px;
        --font-size-step-title: 18px;
        --font-size-section-title: 17px;
    }
}

/* ============================================================
   이력 · 크게 보기(라이트박스) + 원본 상품 이미지
   - 오버레이/패널 셸은 .style-preview-overlay / .style-preview-modal 재사용
     (여기서는 그 안쪽 요소만 정의한다).
   - 신규 커스텀 프로퍼티 토큰 없음 / !important 없음.
   - .result-card* 전역 규칙은 건드리지 않고 .history-thumbs 하위로만 스코프한다
     (생성 결과 화면 index.html 과 공유하는 클래스이므로).
   ============================================================ */
.lb-figure {
    border-radius: var(--radius-md);
    overflow: hidden;
    border: 1px solid var(--border-color);
    background: var(--surface-soft);
}
/* 원본 비율 유지: 폭에 맞추되 세로가 길면 max-height 안에서 contain 으로 letterbox. */
.lb-img {
    display: block;
    width: 100%;
    height: auto;
    max-height: 68vh;
    object-fit: contain;
    margin: 0 auto;
}
.lb-error {
    margin: 0;
    padding: 32px 16px;
    text-align: center;
    font-size: var(--font-size-helper);
    color: var(--text-secondary);
}
/* style.css 에는 전역 [hidden] 규칙이 없어 UA 기본값에 의존한다. 명시해 보강. */
.lb-error[hidden] { display: none; }
.lb-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-top: 12px;
}
.lb-nav__btn { white-space: nowrap; }
.lb-nav__count {
    font-size: var(--fs-sm);
    color: var(--text-secondary);
}

/* 이력 컷 썸네일 — 클릭하면 크게 보기(포인터/포커스 링만 추가). */
.history-thumbs .result-card__img {
    cursor: zoom-in;
}
.history-thumbs .result-card__img:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

/* 이 상품의 원본 이미지 — 결과 컷 그리드와 시각적으로 구분되는 별도 블록. */
.history-source {
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px dashed var(--border-color);
}
.history-source__label {
    font-size: var(--fs-sm);
    font-weight: 700;
    color: var(--text-secondary);
    margin-bottom: 10px;
}
.history-source__empty { margin-bottom: 0; }
.history-source__grid {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}
.history-source__img {
    display: block;
    width: 72px;
    height: 72px;
    object-fit: cover;
    border-radius: var(--radius-md);
    border: 1px solid var(--border-color);
    background: var(--surface-soft);
    cursor: zoom-in;
}
.history-source__img:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

/* ============================================================
   법적 고지 문서 (.legal) — 이용약관 / 개인정보처리방침
   ------------------------------------------------------------
   이 파일 최상단의 `* { margin:0; padding:0 }` 전역 리셋 때문에
   h1~h6 / p / ul / ol / li / table 의 기본 여백·마커가 전부 0 으로
   붕괴한다. 앱 UI 는 그 리셋을 전제로 짜여 있으므로 전역으로 되돌리면
   안 되고, 긴 산문이 들어가는 문서 페이지에서만 복구해야 한다.
   → 모든 규칙을 `.legal` 네임스페이스 안으로만 스코프한다.
     (`p { }` 같은 전역 요소 선택자는 이 블록에 단 하나도 없다.)

   레이아웃 주의:
   - `.legal` 은 `main.app.legal` 로 `.app` 과 함께 쓰인다. `.app` 은
     본문 폭 560px(≥1024 에서 1320px)이라 산문에는 과하게 넓다 →
     `.app.legal`(특이도 0,2,0)로만 좁힌다. `.app` 단독 규칙(0,1,0)은
     건드리지 않으므로 index/history 렌더는 완전히 불변이다.
   - ≥1024 의 `.app { padding: ... 0 }`(데스크톱 스크롤 0 산술)도
     그대로 두고, `.app.legal` 의 padding-bottom 만 특이도로 덮는다.
     문서 페이지는 워크스페이스(.controls-panel/.results-area)가 없어
     해당 산술의 영향권 밖이다.
   - 색은 전부 기존 토큰만 사용 → 다크모드 자동 대응(하드코딩 색 없음).
   ============================================================ */

/* --- 컨테이너: 읽기 좋은 좁은 폭 + 중앙 정렬 --- */
.app.legal {
    max-width: 860px;
    /* ≥1024 에서 .app 이 padding-bottom:0 을 걸지만 문서 페이지는
       하단 여백이 필요하다. 특이도(0,2,0)로만 덮어 다른 페이지 무영향. */
    padding-bottom: var(--space-10);
    color: var(--text-primary);
}

/* --- 헤더 --- */
.legal__header {
    padding-bottom: var(--space-5);
    margin-bottom: var(--space-6);
    border-bottom: 1px solid var(--border-color);
}

.legal__title {
    font-size: var(--font-size-display);
    font-weight: 800;
    line-height: var(--line-height-title);
    letter-spacing: -0.02em;
    margin-bottom: var(--space-2);
    /* 앵커/해시 이동 시 sticky 상단바(--topbar-h)에 가리지 않도록 */
    scroll-margin-top: calc(var(--topbar-h) + var(--space-4));
}

.legal__meta {
    font-size: var(--font-size-helper);
    line-height: var(--line-height-compact);
    color: var(--text-muted);
}

/* --- 목차(카드형) --- */
.legal__toc {
    background: var(--surface-soft);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    padding: var(--space-5) var(--space-5) var(--space-5) var(--space-8);
    margin-bottom: var(--space-8);
}

.legal__toc ol {
    list-style: decimal;
    margin: 0;
    padding: 0;
}

.legal__toc li {
    margin: 0 0 var(--space-2);
    padding-left: var(--space-1);
    color: var(--text-secondary);
    font-size: var(--font-size-small);
    line-height: var(--line-height-body);
}

.legal__toc li:last-child { margin-bottom: 0; }

.legal__toc a {
    color: var(--accent-primary);
    text-decoration: none;
    font-weight: 600;
}

@media (hover: hover) {
    .legal__toc a:hover { text-decoration: underline; }
}

.legal__toc a:focus-visible {
    outline: none;
    border-radius: var(--radius-sm);
    box-shadow: var(--focus-ring);
}

/* --- 조(section) --- */
.legal__section {
    margin-bottom: var(--space-8);
    scroll-margin-top: calc(var(--topbar-h) + var(--space-4));
}

.legal__section:last-of-type { margin-bottom: 0; }

.legal__section-title {
    font-size: var(--font-size-section-title);
    font-weight: 800;
    line-height: var(--line-height-title);
    letter-spacing: -0.01em;
    margin: 0 0 var(--space-3);
    padding-bottom: var(--space-2);
    border-bottom: 1px solid var(--border-color);
    scroll-margin-top: calc(var(--topbar-h) + var(--space-4));
}

.legal h3 {
    font-size: var(--font-size-body);
    font-weight: 700;
    line-height: var(--line-height-title);
    margin: var(--space-5) 0 var(--space-2);
    color: var(--text-primary);
    scroll-margin-top: calc(var(--topbar-h) + var(--space-4));
}

/* --- 문단 --- */
.legal p {
    font-size: var(--font-size-body);
    line-height: 1.75;
    color: var(--text-secondary);
    margin: 0 0 var(--space-3);
}

.legal p:last-child { margin-bottom: 0; }

.legal strong { color: var(--text-primary); font-weight: 700; }

/* --- 목록: 전역 리셋으로 사라진 마커/들여쓰기 복구 --- */
.legal ol,
.legal ul {
    margin: 0 0 var(--space-4);
    padding-left: var(--space-6);
}

.legal ol { list-style: decimal; }
.legal ul { list-style: disc; }

.legal li {
    font-size: var(--font-size-body);
    line-height: 1.75;
    color: var(--text-secondary);
    margin-bottom: var(--space-2);
    padding-left: var(--space-1);
}

.legal li:last-child { margin-bottom: 0; }

/* 중첩 목록: 한 단계 더 들여쓰고 마커를 바꿔 계층을 드러낸다. */
.legal li > ol,
.legal li > ul {
    margin: var(--space-2) 0 0;
    padding-left: var(--space-5);
}

.legal li > ol { list-style: lower-alpha; }
.legal li > ul { list-style: circle; }

/* `제N조` 하위 항 번호 목록 — 번호를 마커 자리에 정렬해 본문과 구분 */
.legal__list {
    list-style: decimal;
    margin: 0 0 var(--space-4);
    padding-left: var(--space-6);
}

.legal__list > li::marker {
    color: var(--text-primary);
    font-weight: 700;
}

/* --- 표(국외이전 4행 4열: 헤더 1행 + 본문 4행, th 4개): 좁은 화면에서 가로 스크롤 --- */
.legal__tablewrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    margin: 0 0 var(--space-4);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    background: var(--bg-secondary);
    /* 스크롤바: 표준 속성만 사용(::-webkit-scrollbar 금지 규약 준수) */
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
}

.legal__table {
    width: 100%;
    /* 4열이 뭉개지지 않을 최소 폭 — 이보다 좁으면 wrap 이 가로 스크롤 */
    min-width: 640px;
    border-collapse: collapse;
    font-size: var(--font-size-helper);
    line-height: var(--line-height-body);
}

.legal__table th,
.legal__table td {
    padding: var(--space-3);
    text-align: left;
    vertical-align: top;
    border-bottom: 1px solid var(--border-color);
    border-right: 1px solid var(--border-color);
    color: var(--text-secondary);
    word-break: keep-all;
}

.legal__table th:last-child,
.legal__table td:last-child { border-right: 0; }

.legal__table thead th {
    background: var(--surface-soft);
    color: var(--text-primary);
    font-weight: 700;
    white-space: nowrap;
}

.legal__table tbody tr:last-child th,
.legal__table tbody tr:last-child td { border-bottom: 0; }

/* --- 문서 하단 상호 링크 --- */
.legal__nav {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-top: var(--space-8);
    padding-top: var(--space-5);
    border-top: 1px solid var(--border-color);
}

.legal__nav a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 0 var(--space-4);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    background: var(--surface-soft);
    color: var(--text-primary);
    font-size: var(--font-size-small);
    font-weight: 600;
    text-decoration: none;
    transition: background-color var(--transition-base), border-color var(--transition-fast);
}

@media (hover: hover) {
    .legal__nav a:hover {
        background: var(--accent-soft);
        border-color: var(--accent-primary);
    }
}

.legal__nav a:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

/* --- 본문 인라인 링크 --- */
.legal__section a,
.legal p a {
    color: var(--accent-primary);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.legal__section a:focus-visible,
.legal p a:focus-visible {
    outline: none;
    border-radius: var(--radius-sm);
    box-shadow: var(--focus-ring);
}

/* --- 모바일: 제목·여백 축소(표는 위 tablewrap 이 가로 스크롤) --- */
@media (max-width: 640px) {
    .app.legal { padding-bottom: var(--space-8); }

    .legal__title { font-size: var(--font-size-title); }

    .legal__toc {
        padding: var(--space-4) var(--space-4) var(--space-4) var(--space-7);
        margin-bottom: var(--space-6);
    }

    .legal__section { margin-bottom: var(--space-6); }

    .legal ol,
    .legal ul,
    .legal__list { padding-left: var(--space-5); }

    /* 좁은 화면에서는 링크 2개를 세로로 쌓아 터치 타깃을 넓게 */
    .legal__nav { flex-direction: column; }
    .legal__nav a { width: 100%; }
}

/* --- 인쇄: 탐색 요소 제거 + 배경 제거 --- */
@media print {
    .legal__toc,
    .legal__nav { display: none; }

    /* 상단바는 .legal 의 형제라 자손 선택자로 닿지 않는다. 전역
       `.topbar { display:none }` 을 쓰면 index/history 인쇄까지 바뀌므로
       `body:has(.legal)` 로 문서 페이지에서만 숨긴다(:has 는 이 파일의
       헤더 그리드 규칙에서 이미 쓰고 있는 패턴). 기존 .topbar 규칙
       자체는 한 줄도 수정하지 않는다.
       🔴 푸터는 숨기지 않는다 — 약관/방침 인쇄물에도 사업자등록번호·
       통신판매업신고번호·대표자·주소·연락처가 남아야 한다(표기 의무).
       대신 아래에서 푸터 텍스트/링크/구분점 색을 강제한다. */
    body:has(.legal) .topbar { display: none; }

    body:has(.legal) {
        background-image: none;
        background-color: transparent;

        /* 다크모드로 인쇄해도(data-theme 은 <html> 에 붙어 인쇄 시에도 유지)
           종이는 위 배경 제거로 흰색이 된다. 그런데 다크 토큰
           --border-color: rgba(255,255,255,.10) 을 그대로 두면
           .legal__header / .legal__section-title / .legal__tablewrap /
           .legal__table td / .site-footer 의 선이 "흰 종이 위 흰 선"이라
           전부 사라진다. body 에서 토큰을 한 번만 재지정해 문서·표·푸터의
           경계선이 함께 복구되게 한다(선택자별 재선언 불필요).
           :has(.legal) 스코프라 index/history 인쇄에는 영향이 없다. */
        --border-color: #000;
    }

    .app.legal {
        max-width: none;
        padding: 0;
    }

    /* 흰 종이 대비 강제.
       다크 토큰 --text-primary(#f3f4f6)를 상속하면 흰 종이 대비 약 1.08:1 로
       사실상 안 보인다. 본문(p/li)만 잡으면 제목·소제목·강조·목록 마커가
       백지로 남으므로 아래 5종을 반드시 함께 포함한다:
       .legal__title / .legal__section-title / .legal h3 / .legal strong /
       .legal__list > li::marker */
    .legal__title,
    .legal__section-title,
    .legal h3,
    .legal strong,
    .legal p,
    .legal li,
    .legal__meta,
    .legal__table th,
    .legal__table td { color: #000; }

    /* ::marker 는 셀렉터 리스트에 섞으면 미지원 브라우저가 규칙 전체를
       버릴 수 있어 분리. 화면 규칙 `.legal__list > li::marker`(0,1,1)와
       동일 특이도 + 뒤 순서라 !important 없이 이긴다. */
    .legal__list > li::marker { color: #000; }

    .legal__tablewrap {
        overflow-x: visible;
        background: transparent;
    }

    .legal__table { min-width: 0; }

    /* 🔴 특이도 역전 해소.
       위 `.legal__table th`(0,1,1)는 화면 규칙 `.legal__table thead th`
       (0,1,2)에 져서 표 머리글이 흰색으로 남는다. !important 를 쓰는 대신
       같은 선택자를 인쇄 스코프에서 그대로 다시 선언해(동일 특이도 +
       소스 뒤) 정상적으로 이기게 한다. 화면 규칙(:2842)은 무수정. */
    .legal__table thead th {
        background: transparent;
        color: #000;
    }

    .legal__section { break-inside: avoid; }

    /* 푸터(표기 의무 항목): 인쇄에 남기되 색을 강제한다.
       .site-footer 는 --text-secondary, .site-footer__sep 는 --text-muted,
       .site-footer__link 는 color:inherit 이라 다크 값이면 그대로 소실된다.
       특이도 (0,2,1) 로 기존 (0,1,0) 규칙들을 덮는다. */
    body:has(.legal) .site-footer,
    body:has(.legal) .site-footer__link,
    body:has(.legal) .site-footer__sep { color: #000; }
}

/* ============================================================
   로그인 카드 하단 고지 링크 (.login-card__foot-link)
   login.html 에는 푸터가 없어 약관 진입점이 여기뿐이다. 기존
   .login-card__foot(--text-muted, 0.76rem) 규칙은 수정하지 않고,
   그 안의 앵커만 판별 가능하도록 최소한으로 스타일링한다.
   대비: 링크 색을 --text-secondary 로 한 단계 올리고 밑줄을 유지해
   색 외 단서(밑줄)로도 링크임이 드러나게 한다.
   ============================================================ */
.login-card__foot-link {
    color: var(--text-secondary);
    text-decoration: underline;
    text-underline-offset: 2px;
    font-weight: 600;
}

@media (hover: hover) {
    .login-card__foot-link:hover { color: var(--text-primary); }
}

.login-card__foot-link:focus-visible {
    outline: none;
    border-radius: var(--radius-sm);
    box-shadow: var(--focus-ring);
}
