@charset "utf-8";
/* ─────────────────────────────────────────────────────────
   common.css — 리셋 + 디자인 토큰 + 공통 컴포넌트
   ⚠️ 색상/여백은 반드시 아래 CSS 변수를 사용한다(하드코딩 금지).
   ───────────────────────────────────────────────────────── */

:root {
    /* ═══ 1. Color Palette — 디자인 시스템 원본 토큰. 값 변경 금지 ═══════════
       출처: images/color.png (Color Palette)
       컴포넌트에서 이 원본 토큰을 직접 쓰지 말고, 아래 3~4번 레이어를 통해 쓴다. */

    /* Main (브랜드) — 숫자가 클수록 진하다 */
    --c-main-300:  #6A3BE0;
    --c-main-200:  #966FF6;
    --c-main-100:  #F4F0FF;

    /* Sub */
    --c-sub-black: #231F20;
    --c-sub-gold:  #E0A51C;

    /* Gray */
    --c-gray-900:  #1F2021;
    --c-gray-800:  #3C3E40;
    --c-gray-700:  #5F6264;
    --c-gray-600:  #787A7D;
    --c-gray-500:  #A1A3A5;
    --c-gray-400:  #BBBEC0;
    --c-gray-300:  #DFE1E4;
    --c-gray-200:  #EDEFF1;
    --c-gray-100:  #F8F8F9;
    --c-gray-50:   #FCFCFC;

    /* Red / Green / Blue — text(글자) · main(면) · bg(배경) 3단 */
    --c-red-text:    #CF100B;
    --c-red-main:    #FF413C;
    --c-red-bg:      #FFF2F2;
    --c-green-text:  #04791A;
    --c-green-main:  #16BF3B;
    --c-green-bg:    #E7FBEB;
    --c-blue-text:   #094AC2;
    --c-blue-main:   #357BFC;
    --c-blue-bg:     #EBF2FF;

    /* ═══ 2. Semantic Color — 디자인 시스템 정의 ═══════════════════════ */

    /* Background */
    --c-bg-primary:        #FFFFFF;              /* 기본배경 */
    --c-bg-secondary:      var(--c-gray-50);     /* 분리된 배경 */
    --c-bg-disabled:       var(--c-gray-200);    /* 비활성화 배경 */

    /* Divider */
    --c-divider:           var(--c-gray-200);    /* 구분선 */

    /* Border */
    --c-border-primary:    var(--c-gray-300);    /* 기본 테두리 */
    --c-border-secondary:  var(--c-gray-600);    /* 강조 테두리 */
    --c-border-disabled:   var(--c-gray-300);    /* 비활성화 테두리 */

    /* Icon */
    --c-icon-primary:      var(--c-gray-800);    /* 기본아이콘 */
    --c-icon-disabled:     var(--c-gray-400);    /* 비활성화 아이콘 */

    /* Text */
    --c-text-primary:      var(--c-gray-900);    /* 기본텍스트 */
    --c-text-secondary:    var(--c-gray-800);    /* 서브텍스트 */
    --c-text-tertiary:     var(--c-gray-600);    /* 중요X 부수적 */
    --c-text-disabled:     var(--c-gray-500);    /* 비활성화 텍스트 */

    /* ═══ 3. 파생 토큰 — 팔레트에 없어 UI 구현상 추가한 값 ══════════════
       ⚠️ 디자인 확정 시 이 블록의 값만 교체하면 된다. 여기 외에는 색 하드코딩 금지. */
    --c-main-400:   #5A32BE;                 /* Main/300 보다 진한 단계 (팔레트 미정의) */
    --c-focus-ring: #E6DCFD;                 /* 버튼 Focused 링 3px (button_styles.png 실측) */
    --c-gold-text:  #8F6400;                 /* gold 뱃지 글자 (gold text 단계 미정의) */
    --c-gold-bg:    #FDF6E7;                 /* gold 뱃지 배경 (gold bg 단계 미정의) */
    --c-toast-bg:   rgba(35, 31, 32, .92);   /* Sub_black 92% */
    --c-on-color:   #FFFFFF;                 /* 컬러 면 위 글자 */
    --c-dim:        rgba(255, 255, 255, .16);/* 컬러 면 위 반투명 버튼 */
    --c-dim-strong: rgba(255, 255, 255, .26);
    --c-scrim:      rgba(255, 255, 255, .35);/* 사진 위 글씨 가독성용 흰 막 (768 이하 히어로) */
    --c-step-line:  #CAB7FA;                 /* 메인 STEP 타임라인 선 — Main/200 을 흰 배경에 50% 로 얹은 값 */
    --c-hover-bar:  rgba(106, 59, 224, .6);  /* 상품 이미지 위 호버 액션바 (Main/300 60%) */
    --c-backdrop:   rgba(35, 31, 32, .6);    /* 팝업 뒤 딤 (Sub_black 60%) */
    /* 메인 유전자 검사 배너 바탕 — page_img/메인.png 실측 #2E233E (어두운 보라).
       ⚠️ 시안은 여기에 DNA 이중나선 일러스트가 깔린다. **에셋이 없어** 색만 맞춰 둔 상태다. */
    --c-dna-banner: #2E233E;
    --shadow-primary: 0 4px 16px rgba(106, 59, 224, .16);  /* 선택된 카드의 보라 그림자 */
    --shadow-card:    0 4px 20px rgba(31, 32, 33, .10);    /* 테두리 없이 떠 보이는 카드 (키트 HOW TO · 사업소개 등) */
    /* 메인 STEP 카드 — 디자인 지정값(X0 Y4 Blur12 Spread0 · #6A3BE0 25%) 2026-08-13
       ⚠️ 중립 회색이 아니라 **브랜드 보라**가 섞인 그림자다. --shadow-card 는 다른 카드도 함께 쓰므로 따로 둔다. */
    --shadow-step:    0 4px 12px rgba(106, 59, 224, .25);
    /* 카카오 채널 상담 버튼 — 디자인 지정값(X2 Y4 Blur12 Spread0 · #000 15%) */
    --shadow-float:   2px 4px 12px rgba(0, 0, 0, .15);

    /* ═══ 4. 컴포넌트 별칭 — 화면 CSS 는 이 이름을 쓴다 ═════════════════ */
    --c-primary:      var(--c-main-300);
    --c-primary-dark: var(--c-main-400);
    --c-primary-soft: var(--c-main-100);

    --c-text:         var(--c-text-primary);
    --c-text-sub:     var(--c-text-tertiary);
    --c-text-mute:    var(--c-text-disabled);

    /* 페이지 배경은 Background/Primary(#FFF) 대신 Gray/100 을 쓴다 —
       카드/헤더가 흰색(--c-surface)이라 대비가 필요하기 때문. */
    --c-bg:           var(--c-gray-100);
    --c-surface:      var(--c-bg-primary);
    --c-line:         var(--c-border-primary);

    /* Shape */
    --r-sm: 8px;
    --r-md: 12px;
    --r-lg: 16px;
    --shadow: 0 2px 12px rgba(31, 32, 33, .06);

    /* ═══ 5. Layout Grid — images/layout_guide.png ═════════════════════
       PC     1920 뷰포트 · 컨테이너 1320 · 12컬럼 88 · 거터 24 · 좌우여백 300
              (300 은 고정값이 아니라 (1920-1320)/2 의 결과 — 컨테이너를 가운데 정렬하면 자동으로 나온다)
       Mobile  390 뷰포트 · 컨테이너 350 · 6컬럼 50 · 거터 10 · 좌우여백 20
       ⚠️ 컨테이너 폭은 border-box 라 padding 을 포함한다 → --container-outer 를 max-width 로 쓸 것. */
    --container-max:   1320px;
    --grid-cols:       12;
    --grid-col:        88px;
    --grid-gutter:     24px;
    --page-margin:     24px;   /* 컨테이너보다 좁은 화면에서의 좌우 최소 여백 */
    /* 본문 마지막 요소 → 푸터 간격. 전 페이지 공통이며 여기서만 조절한다.
       ⚠️ .footer 에 margin-top 을, 화면 래퍼에 padding-bottom 을 따로 주지 말 것. */
    --page-bottom:     102px;
    --container-outer: calc(var(--container-max) + var(--page-margin) * 2);

    --header-h: 74px;   /* navigation_guide.png — PC 74 / 모바일 48 */

    /* ═══ 6. Typography — guide_images/font_guide.png ══════════════════
       서체 Pretendard. 아래 8단계 외의 크기는 쓰지 않는다.
       (이모지/아이콘 플레이스홀더의 font-size 는 그래픽 크기이므로 예외) */
    --fs-hero:   56px;
    --fs-h1:     46px;
    --fs-h40:    40px;
    --fs-h2:     36px;
    --fs-h3:     32px;
    --fs-h30:    30px;
    --fs-sh0:    28px;
    --fs-sh26:   26px;
    --fs-sh1:    24px;
    --fs-sh15:   20px;
    --fs-sh2:    18px;
    --fs-body1:  16px;   /* 기본 본문 */
    --fs-body2:  14px;
    --fs-sub0:   13px;
    --fs-sub1:   12px;

    /* 굵기는 이 4단계만 사용 (가이드 명시) */
    --fw-regular:  400;
    --fw-medium:   500;
    --fw-semibold: 600;
    --fw-bold:     700;
}

/* 모바일 그리드로 전환 (반응형 쇼핑몰)
   ⚠️ --container-max 는 건드리지 않는다. 모바일의 "컨테이너 350" 은 390 뷰포트에서
      좌우 20 여백을 뺀 결과일 뿐이고, 실제 구현은 화면폭에 따라 유동적이어야 한다. */
@media (max-width: 768px) {
    :root {
        --grid-cols:   6;
        --grid-col:    50px;
        --grid-gutter: 10px;
        --page-margin: 20px;
        --header-h:    48px;
        /* 본문 → 푸터 간격. PC 102 는 폰에서 빈 화면처럼 보인다(2026-08-12).
           ⚠️ PC 값(:root)은 그대로 둔다 — 여기서만 덮어쓴다. */
        --page-bottom: 56px;

        /* 모바일 타입 스케일 — SubHeading2(18) 이하는 데스크탑과 동일하다.
           ⚠️ 2026-08-12 — 가이드 8단계 뒤에 **추가된 토큰들(h40·h3·h30·sh0·sh26·sh15)에
              모바일 값이 없어** 폰에서도 데스크탑 크기 그대로 나왔다.
              그래서 영양제 목록의 '전체 영양제'(h40=40px)가 화면을 다 먹고 상품이 밀렸다.
           ⚠️ 큰 제목일수록 많이 줄이고, **본문성 크기(sh15)는 살짝만** 줄인다 —
              `.best-name`(상품명)·`.rec-name` 이 이 토큰을 쓰기 때문에 많이 줄이면 읽기 어려워진다.
           ⚠️ PC 값(:root)은 건드리지 않는다. 여기서만 덮어쓴다. */
        --fs-hero: 36px;   /* 56 */
        --fs-h1:   28px;   /* 46 */
        --fs-h40:  26px;   /* 40 — 페이지 대제목 (전체 영양제 등) */
        --fs-h2:   24px;   /* 36 */
        --fs-h3:   24px;   /* 32 — 섹션 제목 (메인 BEST·EVENT, 사업소개, 설문 문항) */
        --fs-h30:  23px;   /* 30 — 카드 제목 (키트 HOW TO) */
        --fs-sh0:  22px;   /* 28 — 카드·페이지 제목 (메인 STEP, 고객센터) */
        --fs-sh26: 21px;   /* 26 — 사업소개 소제목 */
        --fs-sh1:  22px;   /* 24 */
        --fs-sh15: 17px;   /* 20 — 상품명·추천 영양제명 (가독성 우선, 조금만) */
    }
}

* { box-sizing: border-box; }
html, body, h1, h2, h3, p, ul, ol, li, dl, dt, dd, figure, form { margin: 0; padding: 0; }
ul, ol { list-style: none; }

html { -webkit-text-size-adjust: 100%; }

/* 더블탭 줌 차단 — 스크롤·핀치 같은 정상 제스처는 그대로 둔다.
   ⚠️ 수량 스테퍼(+/-)·페이징처럼 같은 자리를 연달아 누르는 UI 가 더블탭으로 인식돼
      화면이 확대되던 문제 때문이다. touch-action 은 상속되지 않지만 **조상의 제한이
      자손에도 함께 적용**되므로 html 한 줄이면 전 화면에 걸린다.
      더 좁은 규칙(예: shop.css 슬라이더의 pan-y)은 그대로 우선한다.
   ⚠️ 핀치 줌 차단은 user_header.php 의 viewport 메타(user-scalable=no)가 맡는다 — 둘이 한 쌍이다. */
html { touch-action: manipulation; }

/* 서체 = Pretendard (font_guide.png).
   웹폰트는 각 레이아웃의 <head> 에서 CDN 으로 로드한다. 로드 실패 시 아래 폴백으로 떨어진다.
   ⚠️ 운영 전에는 폰트 파일을 assets/font/ 로 내려받아 self-host 하는 편이 안전하다. */
body {
    font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont,
                 "Apple SD Gothic Neo", "Malgun Gothic", "맑은 고딕", sans-serif;
    color: var(--c-text);
    background: var(--c-bg);
    font-size: var(--fs-body1);
    font-weight: var(--fw-regular);
    line-height: 1.55;
    word-break: keep-all;
}

/* 본문 배경을 흰색으로 쓰는 화면 — render_shop(..., ['body' => 'is-plain'])
   ⚠️ 배경만 담당한다. 아래 여백은 --page-bottom 이 전 페이지 공통으로 처리한다. */
body.is-plain { background: var(--c-bg-primary); }

a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }
button { font: inherit; color: inherit; cursor: pointer; border: 0; background: none; }
input, select, textarea { font: inherit; color: inherit; }
em, i { font-style: normal; }
del { color: var(--c-text-mute); }

/* ── 버튼 ─────────────────────────────────────────────────────────────
   출처: images/button_styles.png (실측 반영)

   Size   XLarge .btn-xl  h52 · pad 24 · font 16 · radius 8 · icon 24
          Large  .btn-lg  h48 · pad 20 · font 16 · radius 8 · icon 20
          Medium .btn     h36 · pad 16 · font 14 · radius 6 · icon 16   ← 기본
          Small  .btn-sm  h32 · pad 14 · font 14 · radius 6 · icon 16
   Type   Fill .btn-primary · Outline .btn-outline · Ghost .btn-ghost
   State  Default / Hover / Focused(3px 링) / Disabled
   Icon   .btn-ico 를 텍스트 앞(Left)/뒤(Right)에 두면 되고, 아이콘 전용은 .btn-icon
   ⚠️ .btn-ghost 는 "테두리 없는 텍스트 버튼"이다. 테두리 있는 보조 버튼은 .btn-outline. */
.btn {
    /* Medium 기본값 — 아래 사이즈 클래스가 덮어쓴다 */
    --btn-h: 36px; --btn-px: 16px; --btn-fs: var(--fs-body2); --btn-r: 6px; --btn-gap: 8px; --btn-ico: 16px;

    display: inline-flex; align-items: center; justify-content: center;
    gap: var(--btn-gap);
    height: var(--btn-h); padding: 0 var(--btn-px);
    border-radius: var(--btn-r);
    font-size: var(--btn-fs); font-weight: var(--fw-medium); line-height: 1;
    border: 1px solid transparent;
    white-space: nowrap;
    transition: background-color .15s, border-color .15s, color .15s, box-shadow .15s;
}
.btn-xl { --btn-h: 52px; --btn-px: 24px; --btn-fs: var(--fs-body1); --btn-r: 8px; --btn-gap: 12px; --btn-ico: 24px; }
.btn-lg { --btn-h: 48px; --btn-px: 20px; --btn-fs: var(--fs-body1); --btn-r: 8px; --btn-gap: 12px; --btn-ico: 20px; }
.btn-sm { --btn-h: 32px; --btn-px: 14px; --btn-fs: var(--fs-body2); --btn-r: 6px; --btn-gap:  8px; --btn-ico: 16px; }
.btn-block { display: flex; width: 100%; }

/* 아이콘 */
.btn-ico {
    flex: 0 0 auto; width: var(--btn-ico); height: var(--btn-ico);
    display: inline-flex; align-items: center; justify-content: center;
    font-size: var(--btn-ico); line-height: 1;
}
.btn-ico > svg, .btn-ico > img { width: 100%; height: 100%; display: block; }
/* 아이콘 전용 — 정사각 */
.btn-icon { width: var(--btn-h); padding: 0; }

/* Fill */
.btn-primary { background: var(--c-main-300); border-color: var(--c-main-300); color: var(--c-on-color); }
.btn-primary:hover { background: var(--c-main-200); border-color: var(--c-main-200); }

/* Outline */
.btn-outline { background: var(--c-bg-primary); border-color: var(--c-main-300); color: var(--c-main-300); }
.btn-outline:hover { background: var(--c-main-100); }

/* Outline(neutral) — ⚠️ button_styles.png 에는 없다.
   page_img/로그인.png 의 '회원가입' 버튼(흰 배경 + Sub_black 1px + 검은 글자)용. */
.btn-outline-dark { background: var(--c-bg-primary); border-color: var(--c-sub-black); color: var(--c-gray-800); }
.btn-outline-dark:hover { background: var(--c-gray-100); }
.btn-outline-dark:disabled, .btn-outline-dark[aria-disabled="true"] {
    background: var(--c-bg-disabled); border-color: var(--c-border-disabled); color: var(--c-text-disabled);
}

/* Soft(neutral fill) — ⚠️ button_styles.png 에는 없다.
   page_img/맞춤영양제(2).png 의 '이전 단계' 버튼(Gray/100 배경 + 어두운 글자)용. */
.btn-soft { background: var(--c-gray-100); border-color: var(--c-gray-100); color: var(--c-text-secondary); }
.btn-soft:hover { background: var(--c-gray-200); border-color: var(--c-gray-200); }
.btn-soft:disabled, .btn-soft[aria-disabled="true"] {
    background: var(--c-bg-disabled); border-color: var(--c-border-disabled); color: var(--c-text-disabled);
}

/* Ghost */
.btn-ghost { background: transparent; border-color: transparent; color: var(--c-main-300); }
.btn-ghost:hover { background: var(--c-main-100); }

/* Focused — 버튼 바깥으로 3px 링 (간격 없이 맞붙음) */
.btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--c-focus-ring); }
.btn-outline:focus-visible, .btn-ghost:focus-visible { background: var(--c-main-100); }

/* Disabled — 투명도가 아니라 지정색으로 표현한다 */
.btn:disabled, .btn[aria-disabled="true"] { cursor: not-allowed; box-shadow: none; }
.btn-primary:disabled, .btn-primary[aria-disabled="true"] {
    background: var(--c-gray-400); border-color: var(--c-gray-400); color: var(--c-on-color);
}
.btn-outline:disabled, .btn-outline[aria-disabled="true"] {
    background: var(--c-bg-disabled); border-color: var(--c-border-disabled); color: var(--c-text-disabled);
}
.btn-ghost:disabled, .btn-ghost[aria-disabled="true"] {
    background: var(--c-gray-100); border-color: transparent; color: var(--c-text-disabled);
}

input:disabled, select:disabled, textarea:disabled {
    background: var(--c-bg-disabled); border-color: var(--c-border-disabled);
    color: var(--c-text-disabled); cursor: not-allowed;
}

/* ── 레이아웃 그리드 유틸 ─────────────────────────────────────────────
   PC 12컬럼 / 모바일 6컬럼. 컬럼폭은 1fr 로 유동 처리하고 거터만 토큰을 따른다.
   사용: <div class="grid"><div class="col-3 mcol-6">…</div></div>
   - .col-N  : PC(769px~) 에서 차지할 컬럼 수 (1~12)
   - .mcol-N : 모바일(~768px) 에서 차지할 컬럼 수 (1~6). 미지정 시 6(전체폭). */
.container { width: 100%; max-width: var(--container-outer); margin: 0 auto; padding: 0 var(--page-margin); }

/* 화면에서는 숨기고 **스크린리더에는 읽히는** 텍스트.
   ⚠️ `display: none` · `visibility: hidden` 은 보조기기에서도 사라져 쓸 수 없다.
   ⚠️ 2026-08-10 — 클래스가 정의돼 있지 않아 상품 상세의 별점 분포 "N건",
      찜 리스트의 체크박스 라벨이 그대로 화면에 보이고 있었다. */
.sr-only {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; white-space: nowrap; border: 0;
    clip: rect(0 0 0 0); clip-path: inset(50%);
}
.grid { display: grid; grid-template-columns: repeat(var(--grid-cols), 1fr); gap: var(--grid-gutter); }
.grid > * { grid-column: span var(--grid-cols); }   /* 기본 = 전체폭 */

@media (min-width: 769px) {
    .col-1 { grid-column: span 1; }   .col-2  { grid-column: span 2; }
    .col-3 { grid-column: span 3; }   .col-4  { grid-column: span 4; }
    .col-5 { grid-column: span 5; }   .col-6  { grid-column: span 6; }
    .col-7 { grid-column: span 7; }   .col-8  { grid-column: span 8; }
    .col-9 { grid-column: span 9; }   .col-10 { grid-column: span 10; }
    .col-11 { grid-column: span 11; } .col-12 { grid-column: span 12; }
}
@media (max-width: 768px) {
    .mcol-1 { grid-column: span 1; }  .mcol-2 { grid-column: span 2; }
    .mcol-3 { grid-column: span 3; }  .mcol-4 { grid-column: span 4; }
    .mcol-5 { grid-column: span 5; }  .mcol-6 { grid-column: span 6; }
}

/* ── 뱃지 ────────────────────────────────────────────── */
.badge {
    display: inline-block; padding: 2px 9px;
    border-radius: 999px;
    font-size: var(--fs-sub1); font-weight: var(--fw-semibold); line-height: 1.6;
    border: 1px solid currentColor;
}
/* 팔레트가 지원하는 색만 사용한다 — blue / green / red / gray / gold / purple */
.badge-blue   { color: var(--c-blue-text);      background: var(--c-blue-bg); }
.badge-green  { color: var(--c-green-text);     background: var(--c-green-bg); }
.badge-red    { color: var(--c-red-text);       background: var(--c-red-bg); }
.badge-gray   { color: var(--c-text-tertiary);  background: var(--c-gray-200); }
.badge-gold   { color: var(--c-gold-text);      background: var(--c-gold-bg); }
.badge-purple { color: var(--c-main-300);       background: var(--c-main-100); }

/* ── 알림(플래시) ────────────────────────────────────── */
.alert {
    padding: 12px 16px; border-radius: var(--r-sm);
    font-size: var(--fs-body2); margin-bottom: 16px;
}
.alert-success { background: var(--c-green-bg); color: var(--c-green-text); }
.alert-danger  { background: var(--c-red-bg);   color: var(--c-red-text); }
.alert-info    { background: var(--c-blue-bg);  color: var(--c-blue-text); }

/* ── 토스트 ──────────────────────────────────────────── */
.toast {
    position: fixed; left: 50%; bottom: 88px; transform: translate(-50%, 12px);
    max-width: min(90vw, 420px);
    padding: 12px 20px; border-radius: 999px;
    background: var(--c-toast-bg); color: var(--c-on-color);
    font-size: var(--fs-body2); text-align: center;
    opacity: 0; pointer-events: none; transition: opacity .2s, transform .2s;
    z-index: 200;
}
.toast.is-show { opacity: 1; transform: translate(-50%, 0); }

/* ── 인트로(스플래시) ─────────────────────────────────────────────────
   2026-08-11 신규 · 마크업 `views/partials/intro.php` · ⚠️ 기획서·시안에 없는 화면(요청 반영)
   **모바일(768 이하)에서 세션 첫 진입 1회**만 뜬다. 구성은 로고 + 인디케이터뿐.
   z-index 300 — 토스트(200)·모달(170) 위. 잠깐이지만 그 위를 덮어야 한다.

   ⚠️ 사라지는 것은 **CSS 애니메이션**이 한다(1.15s 대기 → 0.45s 페이드아웃, forwards).
      JS 가 막혀도 화면이 갇히지 않게 하려는 것이다 — JS 는 '봤다' 표시와 노드 제거만 맡는다.
   ⚠️ `pointer-events` 대신 **`visibility: hidden`** 으로 끝낸다. 숨겨진 요소는 클릭 판정에서도 빠진다. */
.intro { display: none; }        /* PC 는 아예 그려지지 않는다 */

@media (max-width: 768px) {
    .intro {
        position: fixed; inset: 0; z-index: 300;
        display: flex; flex-direction: column; align-items: center; justify-content: center;
        gap: 26px;
        background: var(--c-surface);
        animation: introOut .45s ease 1.15s forwards;
    }
    .intro-logo { height: 34px; width: auto; max-width: 60%; }
    .intro-dots { display: flex; gap: 8px; }
    .intro-dots i {
        width: 8px; height: 8px; border-radius: 50%;
        background: var(--c-main-300); opacity: .25;
        animation: introDot 1s ease-in-out infinite;
    }
    .intro-dots i:nth-child(2) { animation-delay: .15s; }
    .intro-dots i:nth-child(3) { animation-delay: .3s; }
}
@keyframes introOut { to { opacity: 0; visibility: hidden; } }
@keyframes introDot {
    0%, 100% { opacity: .25; transform: scale(.85); }
    40%      { opacity: 1;   transform: scale(1); }
}
/* 움직임을 줄여 달라는 설정이면 점만 멈추고 더 빨리 걷는다 */
@media (prefers-reduced-motion: reduce) {
    .intro { animation-delay: .5s; animation-duration: .01s; }
    .intro-dots i { animation: none; opacity: .45; }
}

/* ── 모달 (공통 팝업) ─────────────────────────────────────────────────
   출처: 상품상세 '설문을 먼저 진행해 주세요' 팝업. **알림·확인 팝업은 전부 이 컴포넌트를 쓴다.**
   마크업은 `views/partials/modal.php`, 여닫기는 shop.js 의 [data-modal-open]/[data-modal-close].
   실측: 박스 420 · r12 · 패딩 32/20/26 · 제목 SH2 · 설명 Body2 · 버튼 Large 전폭 · 닫기 24(우상단 16)
   z-index 170 — 드로어(160) 위, 토스트(200) 아래.
   ⚠️ hidden 이 아니라 visibility/opacity 로 여닫는다(전환 애니메이션). 열기 전엔 접근성 트리에서도 빠진다. */
.modal {
    position: fixed; inset: 0; z-index: 170;
    display: flex; align-items: center; justify-content: center;
    padding: var(--page-margin);
    background: var(--c-backdrop);
    visibility: hidden; opacity: 0;
    transition: opacity .18s, visibility .18s;
}
.modal.is-open { visibility: visible; opacity: 1; }
.modal-box.is-wide { width: 648px; }        /* 배송지 목록 등 목록형 모달 */
.modal-box.is-left { text-align: left; }
.modal-box {
    position: relative; width: 420px; max-width: 100%;
    padding: 32px 20px 26px; border-radius: var(--r-md);
    background: var(--c-surface); text-align: center;
    transform: translateY(8px); transition: transform .18s;
    /* 화면이 낮으면 박스가 잘리고 **스크롤도 되지 않았다**(배송지 등록 폼에서 저장 버튼에 닿지 못함).
       박스를 화면 안으로 묶고 **본문만** 흘린다 — 제목·닫기·버튼은 항상 보인다. */
    display: flex; flex-direction: column;
    max-height: 100%;
}
/* ⚠️ `min-height: 0` 이 없으면 플렉스 아이템이 내용 높이 밑으로 줄지 않아 overflow 가 먹지 않는다. */
.modal-body {
    margin-top: 22px;
    flex: 1 1 auto; min-height: 0;
    overflow-y: auto; -webkit-overflow-scrolling: touch;
}
/* 제목·버튼은 줄어들지 않는다 — 줄어들 몫은 전부 본문이 가져간다 */
.modal-title, .modal-actions { flex: 0 0 auto; }
/* 본문 파셜이 없는 안내형 모달은 설명이 대신 흘러야 한다 */
.modal-desc { overflow-y: auto; min-height: 0; }
.modal.is-open .modal-box { transform: none; }
.modal-close {
    position: absolute; top: 16px; right: 16px; width: 24px; height: 24px; padding: 0;
    font-size: var(--fs-body2); color: var(--c-icon-primary);
}
.modal-close:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--c-focus-ring); border-radius: var(--r-sm); }
.modal-title { font-size: var(--fs-sh15); font-weight: var(--fw-bold); color: var(--c-text-primary); }
.modal-desc { margin-top: 22px; font-size: var(--fs-body2); color: var(--c-text-tertiary); line-height: 1.6; }
.modal-actions { display: grid; gap: 8px; margin-top: 34px; }
.modal-actions .btn { width: 100%; }

/* ── 입력 (Input / Select / Textarea) ─────────────────────────────────
   출처: guide_images/input_guide.png (실측)
     컨트롤  높이 48 · radius 8 · padding 0 16 · 글자 16 · placeholder Gray/600
     ⚠️ 글자 16px 은 가이드 실측값이자, iOS Safari 가 16px 미만 입력창 포커스 시
        페이지를 확대해버리는 문제를 피하는 값이다. 더 줄이지 말 것.
     Default  흰 배경 + 1px Gray/300
     Hover    배경 Gray/100 (테두리 그대로)
     Focused  1px Main/200 + 3px 링(--c-focus-ring)
     Disabled 배경 Gray/200 + 1px Gray/300 + 글자 Gray/500
     Success  1px Green/main    Error  1px Red/main
     라벨 13 / Gray700, 헬퍼 12 (Gray600 · Green/text · Red/text)
   ⚠️ 컨트롤에는 .input / .select / .textarea 클래스를 반드시 붙인다. */
.field, .form-row { margin-bottom: 18px; }
.field-label, .form-row > label {
    display: block; margin-bottom: 8px;
    font-size: var(--fs-body1); font-weight: var(--fw-medium); color: var(--c-gray-900);
}
.field-label em, .form-row > label em { color: var(--c-red-main); }
.field-help {
    margin-top: 8px; font-size: var(--fs-sub1); color: var(--c-text-tertiary);
}
.field-help.is-success { color: var(--c-green-text); }
.field-help.is-error   { color: var(--c-red-text); }

.input, .select, .textarea {
    width: 100%; height: 48px; padding: 0 16px;
    border: 1px solid var(--c-border-primary); border-radius: 8px;
    background-color: var(--c-bg-primary);
    color: var(--c-text-primary); font-size: var(--fs-body1);
    transition: background-color .15s, border-color .15s, box-shadow .15s;
}
.input::placeholder, .textarea::placeholder { color: var(--c-text-tertiary); }

.input:hover:not(:disabled):not(:focus),
.select:hover:not(:disabled):not(:focus),
.textarea:hover:not(:disabled):not(:focus) { background-color: var(--c-gray-100); }

.input:focus, .select:focus, .textarea:focus {
    outline: none;
    background-color: var(--c-bg-primary);
    border-color: var(--c-main-200);
    box-shadow: 0 0 0 3px var(--c-focus-ring);
}
.input:disabled, .select:disabled, .textarea:disabled {
    background-color: var(--c-bg-disabled);
    border-color: var(--c-border-disabled);
    color: var(--c-text-disabled); cursor: not-allowed;
}
/* 검증 결과 — :focus 보다 뒤에 두어 포커스 중에도 색이 유지되게 한다 */
.input.is-success, .select.is-success, .textarea.is-success { border-color: var(--c-green-main); }
.input.is-error,   .select.is-error,   .textarea.is-error   { border-color: var(--c-red-main); }

/* 브라우저 자동완성 — 크롬이 제 마음대로 하늘색(#E8F0FE) 배경을 칠한다 (2026-08-11)
 *
 * `background-color` 로는 못 막는다(사용자 에이전트 스타일이 이긴다).
 * 크롬은 그 배경을 **전환(transition)으로** 칠하므로, 전환 시간을 아주 길게 잡으면 **끝내 칠해지지 않는다.**
 * 글자색만 `-webkit-text-fill-color` 로 되돌린다.
 *
 * ⚠️ 흔히 쓰는 "안쪽 그림자로 덮기" 는 **여기서 쓰면 안 된다.**
 *    `.input-btn` 안의 입력칸은 배경이 투명하고 **바깥 래퍼가 배경을 갖는다**(위 .input-btn 규칙).
 *    흰색으로 덮으면 hover(회색)·비활성(회색) 상태가 입력칸만 흰색으로 남아 어긋난다.
 *    전환 지연 방식은 배경을 건드리지 않아 기존 상태 색이 그대로 살아 있다.
 * ⚠️ 웹킷 접두사와 표준 `:autofill` 을 **따로** 쓴다 — 한 선택자로 묶으면
 *    모르는 쪽을 만난 브라우저가 규칙 전체를 버린다. */
.input:-webkit-autofill,
.select:-webkit-autofill,
.textarea:-webkit-autofill {
    transition: background-color 100000s ease-in-out 0s;
    -webkit-text-fill-color: var(--c-text-primary);
    caret-color: var(--c-text-primary);
}
.input:autofill,
.select:autofill,
.textarea:autofill {
    transition: background-color 100000s ease-in-out 0s;
    -webkit-text-fill-color: var(--c-text-primary);
    caret-color: var(--c-text-primary);
}
/* 잠긴 칸(인증완료·비활성)은 글자도 흐리게 — 잠긴 티가 나야 한다 */
.input:disabled:-webkit-autofill,
.input.is-verified:-webkit-autofill { -webkit-text-fill-color: var(--c-text-secondary); }
.input:disabled:autofill,
.input.is-verified:autofill { -webkit-text-fill-color: var(--c-text-secondary); }

.textarea { height: 120px; padding: 14px 16px; line-height: 1.5; resize: vertical; }

/* Select — 네이티브 화살표를 끄고 토큰 색으로 직접 그린다(에셋 불필요) */
.select { appearance: none; -webkit-appearance: none; padding-right: 44px; cursor: pointer; }
.select-wrap { position: relative; display: block; }
.select-wrap::after {
    content: ''; position: absolute; right: 18px; top: 50%;
    width: 8px; height: 8px; margin-top: -6px;
    border-right: 1.5px solid var(--c-icon-primary);
    border-bottom: 1.5px solid var(--c-icon-primary);
    transform: rotate(45deg); pointer-events: none;
}
.select-wrap:has(.select:disabled)::after { border-color: var(--c-icon-disabled); }

/* Input + Btn — 가이드는 버튼이 입력창 '안쪽' 우측에 들어간다.
   래퍼가 테두리를 갖고 input 은 투명하게 얹어, 버튼 라벨 길이와 무관하게 동작한다. */
.input-btn {
    display: flex; align-items: center; gap: 8px;
    height: 48px; padding: 0 8px 0 16px;
    border: 1px solid var(--c-border-primary); border-radius: 8px;
    background-color: var(--c-bg-primary);
    transition: background-color .15s, border-color .15s, box-shadow .15s;
}
.input-btn .input {
    flex: 1; min-width: 0;
    height: 100%; padding: 0; border: 0; border-radius: 0;
    background: transparent;
}
/* ⚠️ `:not()` 두 개를 붙여 특이도를 올린 이유 (2026-08-12)
   위쪽 `.input:hover:not(:disabled):not(:focus)` 가 (0,4,0) 이라
   `.input-btn .input:hover`(0,3,0) 로는 **이기지 못한다**.
   그대로 두면 인증번호·중복확인처럼 버튼이 붙은 입력칸에 마우스만 올려도
   래퍼는 흰색인데 **안쪽만 회색**으로 칠해져 좌우가 어긋나 보인다.
   배경은 래퍼(`.input-btn`)가 그리고 입력칸은 항상 투명해야 한다. */
.input-btn .input:hover:not(:disabled):not(:focus),
.input-btn .input:focus { background: transparent; box-shadow: none; }
.input-btn:hover:not(:focus-within) { background-color: var(--c-gray-100); }
.input-btn:focus-within { border-color: var(--c-main-200); box-shadow: 0 0 0 3px var(--c-focus-ring); }
.input-btn:has(.input:disabled) {
    background-color: var(--c-bg-disabled); border-color: var(--c-border-disabled);
}
/* 비밀번호 표시/숨김 토글 — 입력창 안쪽 우측(여백 16) */
.input-pw { position: relative; }
.input-pw .input { padding-right: 52px; }
.pw-toggle {
    position: absolute; top: 50%; right: 16px; transform: translateY(-50%);
    width: 24px; height: 24px; padding: 0;
    display: flex; align-items: center; justify-content: center;
    color: var(--c-icon-primary);
}
.pw-toggle svg { width: 20px; height: 20px; }
.pw-toggle[aria-pressed="true"] .pw-slash { display: none; }   /* 표시중에는 사선 제거 */

.field-btn {
    flex: 0 0 auto;
    height: 32px; min-width: 74px; padding: 0 12px;   /* 시안 실측 74×32 */
    border: 0; border-radius: 8px;
    background-color: var(--c-sub-black); color: var(--c-on-color);
    font-size: var(--fs-body2); font-weight: var(--fw-semibold); line-height: 1;
    cursor: pointer; transition: background-color .15s, box-shadow .15s;
}
.field-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--c-focus-ring); }
.field-btn:disabled { background-color: var(--c-gray-400); cursor: not-allowed; }

/* ── 체크박스 · 라디오 · 토글 ─────────────────────────────────────────
   출처: guide_images/component_guide.png (실측)
     Checkbox 24×24 · radius 4 · 체크아이콘 12×9(원본 26×19)
     Radio    24×24 · checked = 7px 테두리 → 안쪽 흰 원 10px
     Toggle   트랙 44×24 · 노브 20×20 · 상하좌우 인셋 2
   네이티브 input 에 appearance:none 을 씌워 폼 시맨틱·키보드 조작을 유지한다. */
.chk, .rdo {
    appearance: none; -webkit-appearance: none;
    flex: 0 0 auto; width: 24px; height: 24px; margin: 0;
    background-color: var(--c-bg-primary);
    border: 1px solid var(--c-border-primary);
    cursor: pointer;
    transition: background-color .15s, border-color .15s, box-shadow .15s;
}
.chk { border-radius: 4px; }
.rdo { border-radius: 50%; }
/* ⚠️ 소형(18) — component_guide 는 24 인데 page_img/로그인.png 시안은 18 이다.
   시스템 기본은 24 로 두고, 시안이 18 인 화면에서만 이 변형을 쓴다. 디자인 확인 필요. */
.chk-sm { width: 18px; height: 18px; border-radius: 3px; background-size: 10px auto; }

.chk:checked {
    background-color: var(--c-main-300);
    border-color: var(--c-main-300);
    background-image: url("../img/common/chk_icon.png");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 12px auto;        /* 26×19 → 12×9 */
}
.rdo:checked { border: 7px solid var(--c-main-300); }

.chk:focus-visible, .rdo:focus-visible {
    outline: none; box-shadow: 0 0 0 3px var(--c-focus-ring);
}

/* Disabled — 가이드: 배경 Gray/200 + 테두리 Gray/300 */
.chk:disabled, .rdo:disabled {
    background-color: var(--c-bg-disabled);
    border-color: var(--c-border-disabled);
    cursor: not-allowed;
}
/* ⚠️ 가이드 원본은 disabled+checked 를 '빈 상자 / 빈 원'으로 그려 선택 상태가 사라진다.
   같은 가이드의 토글은 disabled 에서도 노브 위치(on/off)를 유지하므로 원본 누락으로 보고
   체크·점을 Gray/400 으로 살려둔다. 디자인 확정 시 이 두 줄만 고치면 된다. */
.chk:disabled:checked { background-color: var(--c-gray-400); border-color: var(--c-gray-400); }
.rdo:disabled:checked { border: 7px solid var(--c-gray-400); background-color: var(--c-bg-primary); }

/* 토글 — input 은 숨기고 .toggle-track 을 그린다 */
.toggle { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; }
.toggle-input { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; }
.toggle-track {
    position: relative; flex: 0 0 auto;
    width: 44px; height: 24px; border-radius: 999px;
    background-color: var(--c-bg-disabled);          /* off */
    transition: background-color .15s, box-shadow .15s;
}
.toggle-track::after {                                /* 노브 */
    content: ''; position: absolute; top: 2px; left: 2px;
    width: 20px; height: 20px; border-radius: 50%;
    background-color: var(--c-bg-primary);
    transition: transform .15s;
}
.toggle-input:checked + .toggle-track { background-color: var(--c-main-300); }
.toggle-input:checked + .toggle-track::after { transform: translateX(20px); }
.toggle-input:focus-visible + .toggle-track { box-shadow: 0 0 0 3px var(--c-focus-ring); }
/* disabled — 트랙만 회색으로 죽이고 노브 위치(on/off)는 유지한다 (가이드 그대로) */
.toggle-input:disabled + .toggle-track { background-color: var(--c-bg-disabled); cursor: not-allowed; }
.toggle:has(.toggle-input:disabled) { cursor: not-allowed; color: var(--c-text-disabled); }

.agree {
    display: flex; align-items: flex-start; gap: 8px;
    margin: 10px 0; font-size: var(--fs-body2); color: var(--c-text-sub); cursor: pointer;
}
.agree .chk, .agree .rdo { margin-top: 1px; }

/* 수량 스테퍼 */
.qty {
    display: inline-flex; align-items: center;
    border: 1px solid var(--c-line); border-radius: var(--r-sm);
    background: var(--c-surface); overflow: hidden;
}
.qty-btn { width: 40px; height: 42px; font-size: var(--fs-sh2); color: var(--c-icon-primary); }
.qty-btn:hover { background: var(--c-bg-secondary); }
.qty input {
    width: 52px; height: 42px; text-align: center;
    border: 0; border-left: 1px solid var(--c-line); border-right: 1px solid var(--c-line);
    background: transparent; -moz-appearance: textfield;
}
.qty input::-webkit-outer-spin-button,
.qty input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.qty-sm .qty-btn { width: 32px; height: 34px; font-size: var(--fs-body1); }
.qty-sm input { width: 42px; height: 34px; font-size: var(--fs-body2); }

/* ── 빈 상태 ───────────────────────────────────────────
   ⚠️ 2026-08-12 — **이모지 아이콘(.empty-ico) 을 전 화면에서 걷어냈다.**
      플랫폼마다 그림이 달라 톤이 제각각이었고(맥·윈도우·안드로이드), 브랜드와도 어울리지 않았다.
      빈 화면은 **문구 하나로만** 알린다. 아이콘이 다시 필요해지면 이모지가 아니라
      단색 SVG 로 만들어 붙인다(색은 --c-icon-disabled). */
.empty { padding: 72px 20px; text-align: center; }
.empty-text { color: var(--c-text-sub); margin-bottom: 18px; }
/* 빈 화면에서 "그럼 어디서 하나" 를 알려 주는 보조 한 줄 (예: 상품 문의는 상품 상세에서 작성) */
.empty-sub { margin: -8px 0 18px; font-size: var(--fs-body2); color: var(--c-text-tertiary); }

/* ── 에러 페이지 ─────────────────────────────────────── */
.error-page {
    min-height: 100vh; display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: 10px; padding: 24px; text-align: center;
}
.error-code { font-size: var(--fs-hero); font-weight: var(--fw-bold); color: var(--c-primary); }
.error-title { font-size: var(--fs-sh1); }
.error-desc { color: var(--c-text-sub); margin-bottom: 12px; }

/* 할인율 표기 */
.rate { color: var(--c-red-text); font-weight: var(--fw-bold); margin-right: 6px; }

/* 휴대폰 인증 완료 — 입력칸을 잠근다 (2026-08-11 · 2026-08-12 배경 제거)
   ⚠️ **배경색을 칠하지 않는다.**
      이 입력칸은 버튼과 한 테두리 안에 든 구조(`.input-btn`)다. 배경을 입력칸에만 칠하면
      래퍼의 좌측 패딩(16px)은 흰색으로 남아 **안쪽만 회색인 두 톤**으로 어긋나 보인다.
      (초록 배경 → 회색 배경 순으로 걷어냈고, 이번에 회색까지 뺐다)
      잠긴 상태는 [인증완료] 로 바뀐 비활성 버튼 + readonly 로 충분히 드러난다. */
.input.is-verified {
    color: var(--c-text-secondary);
    cursor: default;
}
