---
title: GLOBEAU 관리자 UI 스타일 작업 명세 및 CSS 리팩토링 기록서
section_key: chapter_7
section_label: 제7장 - 프론트엔드 스타일 및 UI 가이드
---

# GLOBEAU 관리자 UI 스타일 작업 명세 및 CSS 리팩토링 기록서
(Technical Specification & Work History for Admin UI/UX Refactoring)

--------------------------------------------------------------------------------

## 문서 제어 및 개정 이력 (Document Control & Revision History)

### 기본 제어 정보
| 항목 | 내용 |
| :--- | :--- |
| **문서명** | GLOBEAU 관리자 UI 스타일 작업 명세 및 CSS 리팩토링 기록서 |
| **현재 버전** | v1.2.0 |
| **최종 개정일** | 2026-11-05 |
| **작성/관리자** | 시스템개발팀 프론트엔드 담당 |
| **적용 시스템** | GLOBEAU 본사 관리자 (`/admin`), 뷰티샵 관리자 (`/shop-admin`), 공용 컴포넌트 |
| **문서 목적** | 본사 관리자와 뷰티샵 관리자의 디바이스별 사용성 차이를 수용한 스타일시트 물리 분리 정책, 16px/12px 반응형 그리드 여백 표준 수립, 주소 검색 5대 컴포넌트 공용화, 멀티 이미지 슬롯(Swiper + 롱프레스 정렬) 독립 엔진화 및 정돈된 CSS 전체 소스코드의 영구 보존 |
| **문서 상태** | 개발 및 운영 공식 표준 (Production Standard) |

### 개정 및 변경 이력
| 버전 | 개정일자 | 구분 | 주요 변경 내역 | 작업자 |
| :--- | :--- | :--- | :--- | :--- |
| **v1.0.0** | 2026-11-05 | 신규제정 | • 본사 관리자(`admin_custom.css`)와 뷰티샵 관리자(`shop_admin_custom.css`) 스타일시트 물리 분리 확립<br>• `admin_custom.css` 내 뷰티샵 모카 전용 코드 걷어내고 순수 본사 블루톤 및 공용 컴포넌트(01~17) 계층형 넘버링(`X.1 ~ X.5`) 표준화<br>• 주소 검색(우편번호, 레이어, 닫기, 검색버튼, 주소인풋) 5대 요소를 `admin_custom.css` [16. 관리자 공용 주소 검색 컴포넌트]로 단일화<br>• `shop_admin_custom.css` 모바일 사각 테두리 박스 완전 배제 및 토스/당근 감성의 심리스 밑줄(언더라인) 폼으로 전면 개편<br>• 모바일 여백 정책 단일화: 일반 모바일(391px~767px) 16px 거터, 초소형 모바일(390px 이하) 4/8px 그리드 표준 최소 마진 12px 엄격 고정<br>• PC(768px 이상) 접속 시 아코디언 완전 해제 및 섹션별 저장 버튼 숨김을 통한 720px 전개형 카드 뷰 구현<br>• 레이아웃(`shop_admin.blade.php`) 및 개별 뷰(`edit.blade.php`) 내 수백 줄의 인라인 `<style>` 완전 제거로 템플릿 초경량화 달성 | 개발팀 |
| **v1.1.0** | 2026-11-05 | 기능확장 | • 멀티 이미지 슬롯(Swiper + 롱프레스 FLIP 드래그) 전용 독립 엔진(`image_multi_slot.js`) 신설 및 DAM(`image_library.js`) 간 역할 분리<br>• `admin_custom.css` [17.6] 섹션 개편: 모바일 100% Edge-to-Edge 전폭 확장(`margin: 0 -16px; width: calc(100% + 32px)`), 1:1 정방형 무패딩 중앙 핏, 롱프레스 시 점선 테두리(`.is-dragging`) 적용<br>• Swiper 좌우 화살표 버튼 복원 및 이전/다음 슬라이드가 없을 때 자동 숨김 처리(`.swiper-button-disabled`, `.swiper-button-lock`) | 개발팀 |
| **v1.2.0** | 2026-11-05 | 반응형최적화 | • 브라우저 윈도우 폭 대신 컴포넌트 실제 가로폭을 감지하는 `ResizeObserver` 기반 슬라이드 개수 산출 로직 구현<br>• 롱프레스 시 `position: fixed` 기준점 튕김 및 우측 하단 쏠림 버그 완벽 수정 (`transform-origin: center`, 뷰포트 절대좌표 LERP 추종)<br>• 블레이드 컴포넌트 내 `@pushOnce`를 통한 Swiper 11 CSS/JS 및 엔진 스크립트 자립형(Self-Contained) 주입 구조 확립 | 개발팀 |

--------------------------------------------------------------------------------

## 1. 아키텍처 및 디자인 분리 정책 (Design Architecture Policy)

### 1.1. 본사 관리자 (Head Office Admin)
- 주 사용 환경: 와이드 데스크톱 PC 모니터 (사용 비율 95% 이상)
- 디자인 기조: PC 최적화 고밀도 데이터 그리드 + 모바일 안전 호환 (Safe Compatibility)
- 핵심 색상: 신뢰성 높은 비즈니스 블루톤 (`--primary-color: #3b82f6`, hover `#2563eb`)
- 폼/카드 형태: 정갈하고 뚜렷한 사각 테두리 박스 폼 (`border: 1px solid #cbd5e1`, 6px 곡률)
- 레이아웃 및 뷰: 와이드 대량 데이터 테이블, 가로 스크롤 보장, 일반 전개형 카드

### 1.2. 뷰티샵 관리자 (Beauty Shop Admin)
- 주 사용 환경: 원장님 스마트폰 및 태블릿 현장 터치 접속 (모바일 비율 90% 이상)
- 디자인 기조: 모바일 퍼스트(Mobile-First) 앱(App) 네이티브 감성 극대화
- 핵심 색상: 에스테틱 뷰티 감성의 브론즈 모카톤 (`--primary-color: #b18977`, hover `#9c7564`)
- 폼 형태: 사각 테두리를 제거한 토스/당근 스타일의 심리스 밑줄(언더라인) 폼
- 카드 형태: 모바일 12px 소프트 카드 + 1열 원터치 접이식 아코디언 (스크롤 피로도 방어)
- PC 환경 대응: PC(768px 이상) 접속 시 아코디언 및 섹션별 저장 버튼을 완전 해제하고, 720px 중앙 정렬 카드 뷰로 자동 전환

### 1.3. 스타일 및 스크립트 물리 분리 원칙 (SSOT & Isolation)
- `public/css/admin_custom.css`:
    본사 관리자와 뷰티샵 관리자가 공유하는 단일 진실 공급원(SSOT). 전역 토큰, 공용 라운드(6px), 사이드바, 상단바, 푸터, 데이터 테이블, 모달, 미디어 라이브러리(DAM), 공용 주소 검색 엔진(Daum/카카오 LBS), 멀티 이미지 슬롯 전폭 레이아웃을 전담.
- `public/css/shop_admin_custom.css`:
    뷰티샵 전용 확장 스타일시트. 본사 관리자에 영향을 주지 않도록 레이아웃 뼈대(`.shop-main-body`), 720px/모바일 래퍼(`.shop-mobile-container`), 모카 테마, 원터치 아코디언, 심리스 언더라인 폼, 갤러리 Swiper를 독점 관리.
- `public/js/admin/image_multi_slot.js`:
    모든 등록/수정 블레이드에서 반복 사용되는 멀티 이미지 슬롯 공용 코어 엔진. Swiper 슬라이드 생성, 모달 다중 선택 이미지 동적 푸시, 롱프레스(220ms) FLIP 드래그 정렬, 순번 자동 갱신(`image_sorts[]`), 개별 삭제 처리를 전담.
- `public/js/image_library.js`:
    순수 미디어 보관함(DAM) 모달 및 독립 탐색기 코어 스크립트. 특정 폼 전용 코드(Swiper, 정렬)를 배제하고 업로드, 50개 페이징, 폴더 트리, 라이트박스에 집중.

---

## 2. 반응형 그리드, 여백 및 멀티 슬롯 표준화 정책

스마트폰 디바이스 폭과 컴포넌트 실제 가로폭에 따른 규격을 단일 위치에서 엄격하게 통제합니다.

### 2.1. 뷰티샵 컨테이너 여백 정책
- PC 환경 (768px 이상): 중앙 720px 최대 너비 카드 뷰 및 `padding: 24px 16px 0 16px`
- 모바일 표준 환경 (391px ~ 767.98px): 모바일 그리드 표준 좌우 16px 안전 거터 (`padding: 16px 16px 0 16px !important`)
- 초소형 모바일 환경 (390px 이하, iPhone SE / 폴드 전면 등): 4/8px 그리드 표준 최소 마진인 12px 적용 (`padding: 12px 12px 0 12px !important`)
- 폼 카드 내부 여백: 표준 모바일 16px, 초소형 화면 12px로 통일하여 베젤 마진과 시각적 리듬 일치

### 2.2. 멀티 이미지 슬롯 (Swiper Gallery) 규격 정책
- 모바일 Edge-to-Edge 전폭 확장:
    모바일 세로 화면에서 아코디언 카드 외곽 패딩을 음수 마진(`margin: 0 -16px; width: calc(100% + 32px)`)으로 상쇄하여 화면 좌우 끝까지 100% 전폭 확장.
- 1:1 완벽 정방형 및 무패딩 중앙 정렬:
    슬라이드 내부 불필요한 패딩을 제거(`p-0`)하고, 가로폭에 따라 동적으로 높이가 결정되는 `aspect-ratio: 1 / 1` 박스 적용. 내부는 `max-width: 100%`, `max-height: 100%`, `object-fit: contain`으로 정중앙 배치 및 은은한 소프트 드롭 섀도우 부여.
- 롱프레스 인터랙션:
    0.22초(220ms) 길게 누름 시 햅틱 진동(50ms)과 함께 카드가 부유하며, 롱프레스 중에만 파란색 점선 테두리(`border: 1.5px dashed #3b82f6`) 노출. 덜컹거림(CLS) 방지를 위해 평상시에도 `1.5px solid transparent`를 유지.
- 네비게이션 버튼 노출 및 자동 잠금:
    모바일에서도 화살표 버튼이 보이도록 설정하되, 맨 앞/맨 뒤에 도달하거나 전체 이미지 수가 한 화면 노출 수 이하일 때는 `.swiper-button-disabled`, `.swiper-button-lock`을 통해 자동으로 화면에서 숨김 처리.
- 컴포넌트 컨테이너 가로폭 감지 (ResizeObserver):
    단순 윈도우 창 크기가 아닌 컴포넌트의 실제 가로폭에 맞춰 슬라이드 개수를 동적으로 제어:
    - 480px 미만 (모바일 세로/좁은 컬럼): 2개
    - 480px ~ 699px (모바일 가로/중간 폭): 3개
    - 700px ~ 999px (일반 PC 아코디언 폭): 4개
    - 1000px ~ 1299px (넓은 PC 컨테이너): 5개
    - 1300px 이상 (와이드 화면): 6개

---

## 3. 관리자 공용 스타일시트 (`public/css/admin_custom.css`)

모든 섹션을 누락 없이 1번부터 17번까지 계층형 번호(X.1, X.2...)와 상세 코멘트로 표준화한 전체 소스코드입니다.

    /* =============================================================================
       [GLOBEAU ADMIN - Main Custom CSS]
       파일 경로: public/css/admin_custom.css
       =============================================================================
       - 본사 관리자(Admin) 및 뷰티샵 관리자(Shop Admin) 공용 베이스 스타일시트
       - 본사/뷰티샵 공용 컴포넌트 및 기본 UI 토큰을 단일 진실 공급원(SSOT)으로 정의합니다.
       - 뷰티샵 모바일 퍼스트 전용 스타일은 shop_admin_custom.css에서 확장합니다.
       ============================================================================= */

    /* 어드민 전용 사이드바 컴포넌트 불러오기 */
    @import url('admin/sidebar.css');

    /* =============================================================================
       [01. 전역 디자인 토큰 및 CSS 변수 정의 (:root)]
       ============================================================================= */
    :root {
        /* 1.1. 레이아웃 규격 변수 */
        --sidebar-width: 260px;
        --sidebar-collapsed-width: 60px;
        --topbar-height: 54px;

        /* 1.2. 공용 배경 및 보더 컬러 */
        --bg-color: #f8fafc;
        --border-color: #e2e8f0;
        --border-default: #e2e8f0;

        /* 1.3. 사이드바 다크 테마 변수 */
        --sidebar-bg: #0f172a;
        --sidebar-color: #94a3b8;
        --sidebar-hover-color: #ffffff;
        --sidebar-hover-bg: rgba(255, 255, 255, 0.05);
        --sidebar-active-bg: #1e293b;

        /* 1.4. 본사 관리자 기본 브랜드 테마 (블루톤) */
        --primary-color: #3b82f6;
        --primary-hover: #2563eb;

        /* 1.5. 타이포그래피 및 본문 컬러 */
        --color-dark: #1e293b;
        --color-text-main: #0f172a;
        --color-text-sub: #cbd5e1;

        /* 1.6. 공용 그림자, 모션, 고정 곡률 토큰 */
        --shadow-card: 0 4px 15px rgba(0, 0, 0, 0.02);
        --transition-base: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
        --app-radius: 6px;
        --radius-fixed: 6px;

        /* 1.7. 데이터 테이블 헤더 전용 컬러 */
        --table-header-bg: #e2e8f0;
        --table-header-color: #334155;
        --table-header-border: #cbd5e1;
    }

    /* =============================================================================
       [02. 기본 리셋 및 단일 요소 고정 곡률 (Border Radius)]
       ============================================================================= */
    /* 2.1. 전역 폰트 및 바디 핏 */
    html,
    body {
        background-color: var(--bg-color);
        color: var(--color-text-main);
        font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, system-ui, Roboto, sans-serif;
        width: 100%;
        margin: 0;
    }

    /* 2.2. 독립 단일 UI 요소 표준 6px 곡률 강제 */
    .rounded, .rounded-top, .rounded-bottom, .rounded-start, .rounded-end, 
    .card, .form-control, .form-select, .btn {
        border-radius: var(--app-radius) !important;
    }

    /* 2.3. 정원형 요소 예외 보장 */
    .rounded-circle {
        border-radius: 50% !important;
    }

    /* =============================================================================
       [03. 결합 그룹 UI (Button Group & Input Group) 모서리 정상화]
       ============================================================================= */
    /* 3.1. 가로형 버튼 그룹 (.btn-group) */
    .btn-group {
        border-radius: var(--app-radius) !important;
    }
    .btn-group > .btn,
    .btn-group > .btn-check + .btn,
    .btn-group > .btn-group > .btn {
        border-radius: 0 !important;
        position: relative;
        flex: 1 1 auto;
    }
    .btn-group > .btn:first-child,
    .btn-group > :first-child.btn-check + .btn,
    .btn-group > .btn-group:first-child > .btn {
        border-top-left-radius: var(--app-radius) !important;
        border-bottom-left-radius: var(--app-radius) !important;
        border-top-right-radius: 0 !important;
        border-bottom-right-radius: 0 !important;
    }
    .btn-group > .btn:last-child,
    .btn-group > .btn-check:last-of-type + .btn,
    .btn-group > :last-child + .btn,
    .btn-group > .btn-group:last-child > .btn {
        border-top-right-radius: var(--app-radius) !important;
        border-bottom-right-radius: var(--app-radius) !important;
        border-top-left-radius: 0 !important;
        border-bottom-left-radius: 0 !important;
    }
    .btn-group > .btn:only-child,
    .btn-group > .btn-check:only-of-type + .btn {
        border-radius: var(--app-radius) !important;
    }
    .btn-group > .btn:not(:first-child),
    .btn-group > .btn-check + .btn:not(:first-of-type),
    .btn-group > .btn-group:not(:first-child) {
        margin-left: -1px;
    }
    .btn-group > .btn:hover,
    .btn-group > .btn:focus,
    .btn-group > .btn:active,
    .btn-group > .btn.active {
        z-index: 2;
    }

    /* 3.2. 세로형 버튼 그룹 (.btn-group-vertical) */
    .btn-group-vertical {
        border-radius: var(--app-radius) !important;
    }
    .btn-group-vertical > .btn,
    .btn-group-vertical > .btn-check + .btn,
    .btn-group-vertical > .btn-group > .btn {
        border-radius: 0 !important;
        position: relative;
        width: 100%;
    }
    .btn-group-vertical > .btn:first-child,
    .btn-group-vertical > :first-child.btn-check + .btn,
    .btn-group-vertical > .btn-group:first-child > .btn {
        border-top-left-radius: var(--app-radius) !important;
        border-top-right-radius: var(--app-radius) !important;
        border-bottom-left-radius: 0 !important;
        border-bottom-right-radius: 0 !important;
    }
    .btn-group-vertical > .btn:last-child,
    .btn-group-vertical > .btn-check:last-of-type + .btn,
    .btn-group-vertical > :last-child + .btn,
    .btn-group-vertical > .btn-group:last-child > .btn {
        border-bottom-left-radius: var(--app-radius) !important;
        border-bottom-right-radius: var(--app-radius) !important;
        border-top-left-radius: 0 !important;
        border-top-right-radius: 0 !important;
    }
    .btn-group-vertical > .btn:not(:first-child),
    .btn-group-vertical > .btn-check + .btn:not(:first-of-type),
    .btn-group-vertical > .btn-group:not(:first-child) {
        margin-top: -1px;
        margin-left: 0;
    }
    .btn-group-vertical > .btn:hover,
    .btn-group-vertical > .btn:focus,
    .btn-group-vertical > .btn:active,
    .btn-group-vertical > .btn.active {
        z-index: 2;
    }

    /* 3.3. 인풋 결합 그룹 (.input-group) */
    .input-group {
        border-radius: var(--app-radius) !important;
        overflow: hidden;
        box-shadow: var(--shadow-card);
        display: flex;
        flex-wrap: nowrap;
        align-items: stretch;
        width: 100%;
    }
    .input-group > .form-control,
    .input-group > .form-select,
    .input-group > .btn,
    .input-group > .input-group-text {
        border-radius: 0 !important;
        border-color: var(--border-color);
        transition: var(--transition-base);
        margin-bottom: 0 !important;
    }
    .input-group > :first-child,
    .input-group > :first-child .form-control,
    .input-group > :first-child .form-select {
        border-top-left-radius: var(--app-radius) !important;
        border-bottom-left-radius: var(--app-radius) !important;
    }
    .input-group > :last-child,
    .input-group > :last-child .form-control,
    .input-group > :last-child .form-select,
    .input-group > :last-child.btn {
        border-top-right-radius: var(--app-radius) !important;
        border-bottom-right-radius: var(--app-radius) !important;
    }
    .input-group .form-control:focus,
    .input-group .form-select:focus {
        border-color: var(--primary-color) !important;
        box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15) !important;
        z-index: 3;
    }
    .input-group-text {
        background-color: #f1f5f9 !important;
        color: var(--color-text-sub);
        border-color: var(--border-color);
        font-size: 0.875rem;
        font-weight: 500;
    }

    /* =============================================================================
       [04. 전역 버튼 규격 시스템 (Buttons Sizing)]
       ============================================================================= */
    /* 4.1. 초소형 알약/관리 버튼 (24px 핏) */
    .btn-app-xs {
        padding: 0.2rem 0.5rem !important;
        font-size: 0.75rem !important;
        line-height: 1.3 !important;
        font-weight: 500;
    }

    /* 4.2. 소형 인라인 액션 버튼 (32px 핏) */
    .btn-app-sm {
        padding: 0.3rem 0.65rem !important;
        font-size: 0.8rem !important;
        line-height: 1.4 !important;
        font-weight: 600;
    }

    /* 4.3. 중형 표준 폼 액션 버튼 (38px 핏) */
    .btn-app-md {
        padding: 0.45rem 1rem !important;
        font-size: 0.9rem !important;
        line-height: 1.5 !important;
        font-weight: 600;
    }

    /* =============================================================================
       [05. 메인 레이아웃 및 글로벌 상단바/푸터/플로팅 도구]
       ============================================================================= */
    /* 5.1. 본사 메인 콘텐츠 컨테이너 */
    #main-content {
        margin-left: var(--sidebar-width);
        transition: margin-left 0.3s cubic-bezier(0.4, 0, 0.2, 1);
        will-change: margin-left;
        min-height: 100vh;
        display: flex;
        flex-direction: column;
    }
    #main-content.expanded {
        margin-left: var(--sidebar-collapsed-width);
    }

    /* 5.2. 글로벌 고정 상단바 (Sticky Topbar) */
    #topbar {
        position: sticky;
        top: 0;
        height: var(--topbar-height);
        background-color: rgba(255, 255, 255, 0.9);
        backdrop-filter: blur(8px);
        border-bottom: 1px solid var(--border-color);
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 1.5rem;
        z-index: 1030;
    }

    /* 5.3. 본사 관리자 본문 패딩 */
    .content-body {
        flex: 1;
        padding: 2rem;
    }

    /* 5.4. 관리자 공용 하단 푸터 */
    .admin-footer {
        padding: 1.5rem;
        background-color: #ffffff;
        border-top: 1px solid var(--border-color);
        color: #64748b;
        font-size: 0.875rem;
    }

    /* 5.5. 모바일 사이드바 오픈 백드롭 */
    .ui-backdrop {
        display: none;
        position: fixed;
        top: 0;
        left: 0;
        width: 100vw;
        height: 100vh;
        background-color: rgba(255, 255, 255, 0.65);
        backdrop-filter: blur(1px);
        z-index: 1035;
        opacity: 0;
        transition: opacity 0.3s ease;
    }
    .ui-backdrop.show {
        display: block;
        opacity: 1;
    }
    body.sidebar-open {
        overflow: hidden !important;
    }

    /* 5.6. 페이지 상단 이동 플로팅 버튼 (Scroll to Top) */
    #scrollTopBtn {
        position: fixed;
        bottom: 2rem;
        right: 2rem;
        width: 40px;
        height: 40px;
        background-color: var(--primary-color);
        color: #fff;
        border: none;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
        cursor: pointer;
        opacity: 0;
        visibility: hidden;
        transition: all 0.3s;
        z-index: 1050;
    }
    #scrollTopBtn.show {
        opacity: 1;
        visibility: visible;
    }
    #scrollTopBtn:hover {
        background-color: var(--primary-hover);
    }

    /* =============================================================================
       [06. 프리로드 (FOUC 깜빡임 방지) 스타일]
       ============================================================================= */
    html.preload-collapsed #sidebar {
        width: var(--sidebar-collapsed-width) !important;
    }
    html.preload-collapsed #sidebar .sidebar-text-box,
    html.preload-collapsed #sidebar .menu-text-content,
    html.preload-collapsed #sidebar .sidebar-footer span,
    html.preload-collapsed #sidebar .submenu {
        opacity: 0 !important;
        visibility: hidden !important;
        display: none !important;
    }
    html.preload-collapsed #main-content {
        margin-left: var(--sidebar-collapsed-width) !important;
    }

    /* =============================================================================
       [07. 플랫폼별 환경 분기 제어 (PC vs 모바일 브라우저)]
       ============================================================================= */
    /* 7.1. PC 환경 (데스크톱 최적화) */
    body.platform-pc {
        overflow-x: auto !important;
    }
    body.platform-pc .content-body {
        overflow-x: auto !important;
        -webkit-overflow-scrolling: touch;
    }
    body.platform-pc #mobileSidebarToggle {
        display: none !important;
    }
    body.platform-pc .d-lg-none { display: none !important; }
    body.platform-pc .d-lg-block { display: block !important; }
    body.platform-pc .d-none.d-lg-block { display: block !important; }
    body.platform-pc .d-block.d-lg-none { display: none !important; }
    body.platform-pc .d-md-flex { display: flex !important; }
    body.platform-pc .d-sm-block { display: block !important; }
    body.platform-pc .d-sm-inline { display: inline !important; }
    body.platform-pc .mobile-only-section { display: none !important; }
    body.platform-pc .pc-only-section { display: block !important; }
    body.platform-pc .table-responsive {
        overflow-x: visible !important;
    }
    body.platform-pc .container-fluid {
        width: 100% !important;
        min-width: 1200px !important;
    }

    /* 7.2. 모바일 환경 (스마트폰 최적화) */
    body.platform-mobile {
        overflow-x: hidden !important;
    }
    body.platform-mobile #sidebar {
        transform: translateX(-100%);
        z-index: 1040;
        width: var(--sidebar-width) !important;
        height: 100vh;
        height: 100dvh;
    }
    body.platform-mobile #sidebar.mobile-open {
        transform: translateX(0);
    }
    body.platform-mobile #sidebar.mobile-open .sidebar-text-box,
    body.platform-mobile #sidebar.mobile-open .menu-text-content,
    body.platform-mobile #sidebar.mobile-open .sidebar-footer span {
        opacity: 1 !important;
        visibility: visible !important;
        display: flex !important;
    }
    body.platform-mobile #main-content,
    body.platform-mobile #main-content.expanded {
        margin-left: 0 !important;
        width: 100% !important;
    }
    body.platform-mobile .container-fluid {
        min-width: 0 !important;
        width: 100% !important;
    }
    body.platform-mobile .content-body {
        overflow-x: visible !important;
        padding: 1rem;
    }
    body.platform-mobile #topbar {
        padding: 0 1rem;
    }
    body.platform-mobile .pc-only-section { display: none !important; }
    body.platform-mobile .mobile-only-section { display: block !important; }

    /* =============================================================================
       [08. 툴팁 및 안내 도움말 컴포넌트]
       ============================================================================= */
    /* 8.1. 부트스트랩 툴팁 바디 커스텀 */
    .tooltip {
        font-size: 0.8rem !important;
        font-family: 'Pretendard', sans-serif !important;
        opacity: 1 !important;
    }
    .tooltip .tooltip-inner {
        background-color: #0f172a !important;
        color: #f8fafc !important;
        padding: 0.65rem 0.95rem !important;
        border-radius: 8px !important;
        box-shadow: 0 10px 25px -5px rgba(15, 23, 42, 0.25), 0 8px 10px -6px rgba(15, 23, 42, 0.2) !important;
        font-weight: 400;
        line-height: 1.5;
        max-width: 300px !important;
        text-align: left !important;
        white-space: pre-line !important;
        word-break: break-all;
        letter-spacing: -0.2px;
    }

    /* 8.2. 툴팁 꼬리표(Arrow) 색상 바인딩 */
    .bs-tooltip-top .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^="top"] .tooltip-arrow::before {
        border-top-color: #0f172a !important;
    }
    .bs-tooltip-bottom .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^="bottom"] .tooltip-arrow::before {
        border-bottom-color: #0f172a !important;
    }
    .bs-tooltip-start .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^="left"] .tooltip-arrow::before {
        border-left-color: #0f172a !important;
    }
    .bs-tooltip-end .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^="right"] .tooltip-arrow::before {
        border-right-color: #0f172a !important;
    }

    /* 8.3. 도움말 원형 아이콘 버튼 호버 인터랙션 */
    .help-tooltip-btn {
        color: #94a3b8 !important;
        transition: color 0.2s ease, transform 0.2s ease;
    }
    .help-tooltip-btn:hover {
        color: var(--primary-color) !important;
        transform: scale(1.1);
    }

    /* =============================================================================
       [09. 콘텐츠 헤더 및 본사 관리자 검색 필터 박스]
       ============================================================================= */
    /* 9.1. 페이지 상단 헤더 박스 */
    .content-header-box {
        display: flex !important;
        flex-wrap: wrap !important;
        justify-content: space-between !important;
        align-items: center !important;
        gap: 0.75rem 1rem !important;
        margin-bottom: 1.25rem !important;
        width: 100% !important;
    }
    .content-title-wrap {
        flex: 1 1 auto !important;
        min-width: 0 !important;
        text-align: left !important;
    }
    .content-header-box .content-title {
        font-size: 1.25rem !important;
        font-weight: 700 !important;
        margin: 0 !important;
        white-space: nowrap !important;
        overflow: hidden !important;
        text-overflow: ellipsis !important;
        letter-spacing: -0.5px;
        color: var(--color-text-main);
    }
    @media (min-width: 768px) {
        .content-header-box .content-title {
            font-size: 1.75rem !important;
        }
    }
    .content-btn-wrap {
        flex-shrink: 0 !important;
    }

    /* 9.2. 리스트 상단 검색 필터 섹션 */
    .search-filter-section {
        background-color: #ffffff;
        border-top: 1px solid var(--border-color);
        border-bottom: 1px solid var(--border-color);
        padding: 1rem;
        margin-left: -1rem;
        margin-right: -1rem;
        margin-bottom: 1.5rem;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
    }
    @media (min-width: 768px) {
        .search-filter-section {
            margin-left: 0;
            margin-right: 0;
            border-radius: var(--app-radius);
            border: 1px solid var(--border-color);
            padding: 1.25rem;
        }
    }

    /* =============================================================================
       [10. 데이터 카드 및 리스트 UI (.app-card & #shopListContainer)]
       ============================================================================= */
    @keyframes fadeInUp {
        from { opacity: 0; transform: translateY(12px); }
        to { opacity: 1; transform: translateY(0); }
    }

    /* 10.1. 공용 리스트용 소프트 카드 */
    .app-card {
        background-color: #ffffff;
        border: 1px solid var(--border-color);
        border-radius: 14px;
        padding: 1.25rem;
        margin-bottom: 1rem;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.03);
        overflow: hidden;
        transition: transform 0.2s ease, box-shadow 0.2s ease;
        animation: fadeInUp 0.35s cubic-bezier(0.16, 1, 0.3, 1) forwards;
        position: relative;
    }
    .app-card.pinned {
        border: 2px solid var(--primary-color);
        box-shadow: 0 0.25rem 0.75rem rgba(59, 130, 246, 0.15);
        background-color: #f8faff;
    }
    .app-card-img-wrap {
        width: calc(100% + 2.5rem);
        margin-top: -1.25rem;
        margin-left: -1.25rem;
        margin-right: -1.25rem;
        margin-bottom: 1.25rem;
        aspect-ratio: 1 / 1;
        position: relative;
        background-color: #f1f5f9;
    }
    .app-card-img-wrap img {
        width: 100%;
        height: 100%;
        object-fit: cover;
    }
    .app-card-title {
        font-size: 1.05rem;
        font-weight: 700;
        color: var(--color-text-main);
        letter-spacing: -0.3px;
        line-height: 1.4;
    }
    .app-card-title-wrap {
        margin-bottom: 0.75rem;
    }
    .app-meta-row {
        display: flex;
        justify-content: space-between;
        flex-wrap: wrap;
        gap: 0.25rem 1rem;
        font-size: 0.825rem;
        line-height: 1.5;
        color: #64748b;
        margin-bottom: 0.5rem;
    }
    .app-meta-item {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    .app-card-desc {
        font-size: 0.825rem;
        line-height: 1.5;
        color: #64748b;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
        word-break: break-all;
        margin-bottom: 0.75rem;
    }

    /* 10.2. 매장 리스트 그리드 컨테이너 */
    #shopListContainer {
        display: flex;
        flex-direction: column;
        gap: 1rem;
    }
    #shopListContainer .app-card {
        margin-bottom: 0 !important;
    }
    @media (min-width: 576px) {
        body.platform-mobile #shopListContainer {
            display: grid;
            grid-template-columns: repeat(2, 1fr);
            gap: 1rem;
        }
    }

    /* =============================================================================
       [11. 데이터 테이블 및 카드 헤더 스타일]
       ============================================================================= */
    /* 11.1. 테마 카드 헤더 */
    .card-header-theme-light {
        background-color: rgba(59, 130, 246, 0.1) !important;
        color: var(--color-dark) !important;
        border-bottom: 1px solid rgba(59, 130, 246, 0.15) !important;
        font-weight: 700 !important;
    }

    /* 11.2. 공용 데이터 테이블 thead 규격 */
    .app-table-header th,
    .table thead.app-table-header th {
        background-color: var(--table-header-bg) !important;
        color: var(--table-header-color) !important;
        font-weight: 600 !important;
        border-bottom: 2px solid var(--table-header-border) !important;
        padding-top: 0.9rem !important;
        padding-bottom: 0.9rem !important;
        vertical-align: middle !important;
    }

    /* =============================================================================
       [12. 뱃지 (Badge) 시스템 (Solid & Outline)]
       ============================================================================= */
    /* 12.1. 기본 뱃지 뼈대 */
    .badge {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        padding: 0.35em 0.65em;
        font-size: 0.75rem;
        font-weight: 600;
        line-height: 1;
        border-radius: var(--app-radius) !important;
        letter-spacing: -0.2px;
        white-space: nowrap;
        vertical-align: middle;
    }

    /* 12.2. 솔리드(Solid) 배경 채움형 */
    .badge-solid-danger {
        background-color: #ef4444 !important;
        color: #ffffff !important;
        border: none !important;
    }
    .badge-solid-success {
        background-color: #22c55e !important;
        color: #ffffff !important;
        border: none !important;
    }
    .badge-solid-primary {
        background-color: var(--primary-color) !important;
        color: #ffffff !important;
        border: none !important;
    }

    /* 12.3. 아웃라인(Outline) 테두리형 */
    .badge-outline-danger {
        background-color: #ffffff !important;
        color: #dc2626 !important;
        border: 1px solid #ef4444 !important;
    }
    .badge-outline-success {
        background-color: #ffffff !important;
        color: #15803d !important;
        border: 1px solid #22c55e !important;
    }
    .badge-outline-primary {
        background-color: #ffffff !important;
        color: var(--primary-color) !important;
        border: 1px solid var(--primary-color) !important;
    }

    /* 12.4. 뱃지 크기 옵션 */
    .badge-sm {
        padding: 0.25em 0.5em;
        font-size: 0.7rem;
    }
    .badge-lg {
        padding: 0.45em 0.8em;
        font-size: 0.825rem;
    }

    /* =============================================================================
       [13. 등록/수정 폼 전용 공용 카드 (app-form-card)]
       ============================================================================= */
    .app-form-card {
        background-color: #ffffff;
        border: 1px solid var(--border-color);
        border-radius: var(--app-radius);
        box-shadow: var(--shadow-card);
        margin-bottom: 1.25rem;
        overflow: hidden;
    }
    .app-form-card .app-card-header {
        padding: 0.85rem 1.25rem;
        font-weight: 700;
        font-size: 0.95rem;
        background-color: rgba(59, 130, 246, 0.08);
        color: var(--color-dark);
        border-bottom: 1px solid rgba(59, 130, 246, 0.15);
    }
    .app-form-card .app-card-body {
        padding: 1.25rem;
    }

    /* =============================================================================
       [14. 관리자 프리미엄 페이지네이션 및 가로 스크롤바]
       ============================================================================= */
    /* 14.1. 페이지네이션 버튼 */
    .pagination {
        margin-bottom: 0;
        gap: 0.25rem;
    }
    .pagination .page-item .page-link {
        display: flex;
        align-items: center;
        justify-content: center;
        min-width: 36px;
        height: 36px;
        padding: 0 0.5rem;
        font-size: 0.85rem;
        font-weight: 500;
        color: var(--color-text-main);
        background-color: #ffffff;
        border: 1px solid var(--border-color);
        border-radius: var(--app-radius) !important;
        transition: var(--transition-base);
        box-shadow: 0 1px 2px rgba(0, 0, 0, 0.02);
    }
    .pagination .page-item .page-link:hover {
        color: var(--primary-color);
        background-color: #f1f5f9;
        border-color: #cbd5e1;
        z-index: 2;
    }
    .pagination .page-item.active .page-link {
        color: #ffffff;
        background-color: var(--primary-color);
        border-color: var(--primary-color);
        font-weight: 600;
        box-shadow: 0 4px 10px rgba(59, 130, 246, 0.3);
        z-index: 3;
    }
    .pagination .page-item.disabled .page-link {
        color: #94a3b8;
        background-color: #f8fafc;
        border-color: var(--border-color);
        opacity: 0.7;
    }
    .pagination .page-item .page-link i {
        font-size: 0.75rem;
    }

    /* 14.2. 관리자 탭/필터 전용 가로 스크롤 트랙 */
    .admin-horizontal-scroll {
        overflow-x: auto;
        white-space: nowrap;
        scrollbar-width: thin;
        scrollbar-color: #cbd5e1 #f8f9fa;
        display: flex;
        flex-direction: row;
        flex-wrap: nowrap;
        gap: 0.5rem;
        align-items: center;
        padding-bottom: 4px;
    }
    .admin-horizontal-scroll::-webkit-scrollbar {
        height: 6px;
    }
    .admin-horizontal-scroll::-webkit-scrollbar-track {
        background: #f8f9fa;
        border-radius: 4px;
    }
    .admin-horizontal-scroll::-webkit-scrollbar-thumb {
        background: #cbd5e1;
        border-radius: 4px;
    }
    .admin-horizontal-scroll::-webkit-scrollbar-thumb:hover {
        background: #94a3b8;
    }

    /* =============================================================================
       [15. 검색 필터 전용 인터랙티브 컴포넌트 (Select, Radio, Switch)]
       ============================================================================= */
    /* 15.1. 셀렉트 박스 활성화 상태 (Primary 블루 배경 & 화이트 화살표) */
    .form-select.is-active-filter {
        background-color: var(--primary-color) !important;
        color: #ffffff !important;
        border-color: var(--primary-color) !important;
        font-weight: 600;
        background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e") !important;
    }
    .form-select.is-active-filter:focus {
        box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.25) !important;
    }
    .form-select.is-active-filter option {
        background-color: #ffffff !important;
        color: var(--color-text-main) !important;
        font-weight: normal;
    }

    /* 15.2. 세그먼트 라디오 그룹 트랙 */
    .filter-radio-group {
        background-color: #f1f5f9 !important;
        padding: 0px !important;
        border-radius: 8px !important;
        border: 1px solid var(--border-color) !important;
        gap: 2px !important;
        display: inline-flex !important;
    }
    .filter-radio-group .btn-check + .filter-radio-label {
        background-color: transparent !important;
        border: none !important;
        border-radius: var(--app-radius) !important;
        color: #64748b !important;
        font-weight: 500;
        padding: 0.3rem 0.65rem !important;
        margin: 0 !important;
        transition: all 0.2s ease-in-out;
    }
    .filter-radio-group .btn-check + .filter-radio-label:hover {
        background-color: rgba(0, 0, 0, 0.04) !important;
        color: var(--color-text-main) !important;
    }

    /* 15.3. 라디오 '전체(빈값)' 선택 시: 은은한 화이트 칩 */
    .filter-radio-group .btn-check[value=""]:checked + .filter-radio-label {
        background-color: #ffffff !important;
        color: var(--color-text-main) !important;
        font-weight: 600 !important;
        border-radius: var(--app-radius) !important;
        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08) !important;
    }

    /* 15.4. 라디오 '실제 필터값' 선택 시: Primary 블루 6px 알약 칩 */
    .filter-radio-group .btn-check:not([value=""]):checked + .filter-radio-label {
        background-color: var(--primary-color) !important;
        color: #ffffff !important;
        font-weight: 700 !important;
        border-radius: var(--app-radius) !important;
        box-shadow: 0 2px 5px rgba(59, 130, 246, 0.35) !important;
    }

    /* 15.5. 스위치 토글 활성화 시 */
    .filter-switch-wrap .filter-switch-input:checked {
        background-color: var(--primary-color) !important;
        border-color: var(--primary-color) !important;
        box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2) !important;
    }
    .filter-switch-wrap.is-active-filter .filter-switch-label {
        color: var(--primary-color) !important;
        font-weight: 700 !important;
    }

    /* =============================================================================
       [16. 관리자 공용 주소 검색 컴포넌트 (본사 관리자 & 뷰티샵 관리자 공용)]
       - Daum 우편번호 레이어 임베드 및 Kakao LBS Geocoder 연동 엔진 규격
       - 전담 스크립트: /public/js/address_search.js
       ============================================================================= */
    /* 16.1. 우편번호 입력 필드 래퍼 */
    .zip-input-wrap {
        flex: 0 1 140px !important;
        max-width: 140px !important;
        min-width: 90px !important;
    }

    /* 16.2. 우편번호 검색 트리거 버튼 공용 규격 (36px 인라인 핏) */
    .btn-admin-find-addr {
        height: 36px !important;
        min-height: 36px !important;
        padding: 0 12px !important;
        font-size: 0.86rem !important;
        font-weight: 700;
        border: 1px solid #cbd5e1 !important;
        background-color: #ffffff !important;
        color: #1e293b !important;
        border-radius: var(--radius-fixed, 6px) !important;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        white-space: nowrap !important;
        flex-shrink: 0 !important;
        transition: all 0.15s ease-in-out;
    }
    .btn-admin-find-addr:hover,
    .btn-admin-find-addr:focus {
        background-color: #f1f5f9 !important;
        border-color: #94a3b8 !important;
        color: #0f172a !important;
    }

    /* 16.3. 우편번호 검색창 닫기(X) 토글 버튼 (36×36px 사각 버튼) */
    .btn-admin-close-addr {
        width: 36px !important;
        height: 36px !important;
        min-height: 36px !important;
        padding: 0 !important;
        font-size: 0.95rem !important;
        border: 1px solid #cbd5e1 !important;
        background-color: #f8fafc !important;
        color: #64748b !important;
        border-radius: var(--radius-fixed, 6px) !important;
        display: inline-flex !important;
        align-items: center !important;
        justify-content: center !important;
        flex-shrink: 0 !important;
        transition: all 0.15s ease-in-out;
    }
    .btn-admin-close-addr:hover {
        background-color: #fee2e2 !important;
        border-color: #ef4444 !important;
        color: #dc2626 !important;
    }

    /* 16.4. Daum 우편번호 레이어 임베드 컨테이너 박스 (#wrap 바인딩) */
    .zipcode-embed-box {
        display: none;
        border: 1px solid #ced4da;
        width: 100%;
        height: 380px;
        position: relative;
        border-radius: var(--radius-fixed, 6px);
        background: #ffffff;
        overflow: hidden;
        margin-top: 8px;
        margin-bottom: 8px;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
    }

    /* 16.5. 주소 검색 연동 공용 인풋 필드 상태 제어 */
    .zip-input-field[readonly],
    input[name="address1"][readonly] {
        cursor: default;
    }

    /* =============================================================================
       [17. 모달, 레이어 스택, 미디어 슬롯 및 전용 툴 (DAM & Lightbox)]
       ============================================================================= */
    /* 17.1. 부트스트랩 모달 공용 규격 */
    .modal-backdrop.show {
        background-color: rgba(0, 0, 0, 0.4);
        backdrop-filter: blur(6px);
        -webkit-backdrop-filter: blur(6px);
    }
    .modal-content {
        border-radius: var(--app-radius) !important;
        overflow: hidden;
    }
    .modal-header {
        border-top-left-radius: var(--app-radius) !important;
        border-top-right-radius: var(--app-radius) !important;
    }
    .modal-footer {
        border-bottom-left-radius: var(--app-radius) !important;
        border-bottom-right-radius: var(--app-radius) !important;
    }
    .modal-backdrop {
        z-index: 1080 !important;
    }
    .modal {
        z-index: 1085 !important;
    }

    /* 17.2. 카테고리 피커 드롭다운 스택(Stacking Context) 정상화 */
    .app-form-card:has(.category-picker-wrap),
    .accordion-item:has(.category-picker-wrap),
    .accordion-collapse:has(.category-picker-wrap) {
        overflow: visible !important;
    }
    .category-picker-wrap {
        position: relative;
        z-index: 1080 !important;
    }
    .category-picker-dropdown,
    .category-search-results,
    .category-dropdown-menu {
        position: absolute !important;
        top: 100% !important;
        left: 0 !important;
        width: 100% !important;
        z-index: 1090 !important;
        box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15) !important;
        background-color: #ffffff !important;
    }

    /* 17.3. 단일 이미지 슬롯 (Single Image Slot) 규격 */
    .single-image-slot {
        min-width: 0 !important;
        width: 100% !important;
    }

    .single-image-slot .slot-container {
        display: flex !important;
        align-items: center !important;
        gap: 12px !important;
        width: 100% !important;
        min-width: 0 !important;
    }

    /* 슬롯 미리보기 컨테이너 (보더 완전 제거 및 가로/세로 정중앙 배치) */
    .single-image-slot .slot-preview-box {
        border: none !important;
        background-color: #f1f5f9 !important;
        overflow: hidden !important;
        position: relative !important;
        display: flex !important;
        align-items: center !important;
        justify-content: center !important;
        border-radius: var(--radius-fixed, 6px) !important;
        flex-shrink: 0 !important;
    }

    /* 미리보기 이미지 (중앙 핏 + max 100% + 은은한 그림자) */
    .single-image-slot .slot-preview-img {
        max-width: 100% !important;
        max-height: 100% !important;
        width: auto !important;
        height: auto !important;
        object-fit: contain !important;
        display: block !important;
        margin: auto !important;
        border-radius: 4px !important;
        box-shadow: 0 2px 6px rgba(15, 23, 42, 0.12) !important;
    }

    /* 미등록 텍스트 및 안내 문구 */
    .single-image-slot .slot-empty-text {
        font-size: 0.72rem !important;
        color: #94a3b8 !important;
        white-space: nowrap !important;
    }
    .single-image-slot .slot-ratio-text {
        font-size: 0.72rem !important;
        line-height: 1.35 !important;
        color: #64748b !important;
        margin-top: 4px !important;
        margin-bottom: 0 !important;
        word-break: keep-all !important;
    }

    /* PC 환경 (768px 이상) */
    @media (min-width: 768px) {
        .single-image-slot .slot-preview-box {
            width: calc(var(--slot-w, 60) * 1px) !important;
            max-width: 45% !important;
            aspect-ratio: var(--slot-w, 1) / var(--slot-h, 1) !important;
            height: auto !important;
            min-height: 48px !important;
        }

        .single-image-slot .btn-slot-remove {
            width: 34px !important;
            height: 34px !important;
            min-height: 34px !important;
            padding: 0 !important;
            border-radius: var(--radius-fixed, 6px) !important;
            display: inline-flex !important;
            align-items: center !important;
            justify-content: center !important;
        }
    }

    /* 모바일 환경 (767.98px 이하): 좌측 40%(3:2 비율) / 우측 60% 분할 */
    @media (max-width: 767.98px) {
        .single-image-slot .slot-container {
            gap: 10px !important;
        }

        .single-image-slot .slot-preview-box {
            flex: 0 0 calc(40% - 5px) !important;
            width: calc(40% - 5px) !important;
            max-width: calc(40% - 5px) !important;
            aspect-ratio: 3 / 2 !important;
            height: auto !important;
            min-height: unset !important;
        }

        .single-image-slot .slot-action-box {
            flex: 0 0 calc(60% - 5px) !important;
            width: calc(60% - 5px) !important;
            max-width: calc(60% - 5px) !important;
            min-width: 0 !important;
            display: flex !important;
            flex-direction: column !important;
            justify-content: center !important;
            gap: 5px !important;
        }

        .single-image-slot .slot-btn-group {
            display: flex !important;
            align-items: center !important;
            gap: 6px !important;
            width: 100% !important;
        }

        .single-image-slot .btn-slot-select {
            flex: 1 1 auto !important;
            height: 34px !important;
            min-height: 34px !important;
            font-size: 0.82rem !important;
            font-weight: 600 !important;
            padding: 0 8px !important;
            white-space: nowrap !important;
            border-radius: var(--radius-fixed, 6px) !important;
        }

        .single-image-slot .btn-slot-remove {
            flex: 0 0 34px !important;
            width: 34px !important;
            height: 34px !important;
            min-height: 34px !important;
            padding: 0 !important;
            border-radius: var(--radius-fixed, 6px) !important;
        }
    }

    /* 17.4. 라이트박스 줌 인디케이터 및 가이드 뱃지 */
    .lightbox-zoom-indicator {
        transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.1s ease !important;
        border-radius: var(--app-radius, 6px) !important;
    }
    .lightbox-zoom-indicator:hover {
        background-color: rgba(255, 255, 255, 0.25) !important;
        border-color: rgba(255, 255, 255, 0.5) !important;
        color: #ffffff !important;
        transform: translateY(-1px);
    }
    .lightbox-zoom-indicator:hover * {
        color: inherit;
    }
    .lightbox-zoom-indicator:hover .fa-arrows-rotate {
        color: #ffffff !important;
    }
    .lightbox-hint-badge {
        background-color: rgba(15, 23, 42, 0.5) !important;
        backdrop-filter: blur(4px);
        border: 1px solid rgba(255, 255, 255, 0.12);
        opacity: 0.35;
        cursor: default;
        user-select: none;
        -webkit-user-select: none;
        transition: opacity 0.25s ease, background-color 0.25s ease, border-color 0.25s ease, transform 0.2s ease;
    }
    .lightbox-hint-badge:hover {
        opacity: 1 !important;
        background-color: rgba(15, 23, 42, 0.85) !important;
        border-color: rgba(255, 255, 255, 0.3);
        transform: translate(-50%, -2px) !important;
    }

    /* 17.5. 모바일 미디어 라이브러리(DAM) 2열 그리드 및 썸네일 */
    @media (max-width: 767.98px) {
        #globeauMediaModal .modal-dialog {
            max-width: 100vw !important;
            width: 100vw !important;
            margin: 0 !important;
            height: 100% !important;
        }
        #globeauMediaModal .modal-content {
            height: 100vh !important;
            height: 100dvh !important;
            border-radius: 0 !important;
            border: none !important;
        }
        #mediaFolderOffcanvas {
            max-width: 280px !important;
            box-shadow: 4px 0 20px rgba(0, 0, 0, 0.25) !important;
        }
        #mediaImageContainer {
            width: 100% !important;
            min-width: 100% !important;
            padding: 4px 8px !important;
            margin: 0 !important;
            box-sizing: border-box !important;
        }
        #mediaImageContainer.is-mobile-grid,
        #mediaImageContainer,
        #mediaImageContainer > div,
        #mediaImageContainer .media-library-grid,
        #mediaImageContainer .media-grid,
        #mediaGridList {
            display: grid !important;
            grid-template-columns: repeat(2, calc(50% - 4px)) !important;
            gap: 8px !important;
            width: 100% !important;
            margin: 0 !important;
            padding: 0 !important;
            box-sizing: border-box !important;
        }
        #mediaImageContainer .media-thumb-item,
        #mediaImageContainer .media-item-card,
        #mediaImageContainer [class*="thumb-item"],
        #mediaImageContainer [class*="item-card"] {
            width: 100% !important;
            max-width: 100% !important;
            min-width: 0 !important;
            margin: 0 !important;
            padding: 4px !important;
            background-color: #ffffff !important;
            border: 1px solid #e2e8f0 !important;
            border-radius: var(--radius-fixed, 6px) !important;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04) !important;
            box-sizing: border-box !important;
            display: flex !important;
            flex-direction: column !important;
            position: relative !important;
        }
        .media-thumb-box {
            width: 100% !important;
            aspect-ratio: 1 / 1 !important;
            background-color: #f8fafc !important;
            border-radius: calc(var(--radius-fixed, 6px) - 2px) !important;
            display: flex !important;
            align-items: center !important;
            justify-content: center !important;
            overflow: hidden !important;
            position: relative !important;
            box-sizing: border-box !important;
            cursor: pointer !important;
        }
        .media-thumb-img,
        .media-thumb-box img {
            max-width: 100% !important;
            max-height: 100% !important;
            width: auto !important;
            height: auto !important;
            object-fit: contain !important;
            display: block !important;
            margin: auto !important;
        }
        .media-thumb-title,
        .media-thumb-name {
            font-size: 0.75rem !important;
            line-height: 1.25 !important;
            font-weight: 600 !important;
            text-align: center !important;
            word-break: break-all !important;
            display: -webkit-box !important;
            -webkit-line-clamp: 2 !important;
            -webkit-box-orient: vertical !important;
            overflow: hidden !important;
            text-overflow: ellipsis !important;
            height: 2.5em !important;
            margin-top: 4px !important;
            margin-bottom: 2px !important;
            padding: 0 2px !important;
        }
        .btn-mobile-more-action {
            border: 1px solid rgba(255, 255, 255, 0.3) !important;
            backdrop-filter: blur(2px);
        }
        #mobileImageActionSheet {
            z-index: 10090 !important;
        }
        .offcanvas-backdrop.show {
            z-index: 10080 !important;
        }
    }

    /* =============================================================================
       [17.6. 멀티 이미지 슬롯 (Marketing Swiper Gallery) 반응형 전폭 확장]
       ============================================================================= */
    /* 17.6.1. 상단 액션바 버튼 줄바꿈 방지 */
    .multi-slot-action-header button {
        white-space: nowrap !important;
        flex-shrink: 0 !important;
    }

    /* 17.6.2. Swiper 좌우 네비게이션 화살표 버튼 (비활성화 시 자동 숨김) */
    .marketing-swiper .swiper-button-prev,
    .marketing-swiper .swiper-button-next {
        width: 32px !important;
        height: 32px !important;
        background-color: rgba(255, 255, 255, 0.95) !important;
        border: 1px solid #cbd5e1 !important;
        border-radius: 50% !important;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15) !important;
        color: #0f172a !important;
        top: 45% !important;
        z-index: 10 !important;
        transition: opacity 0.2s ease, visibility 0.2s ease !important;
    }

    /* 이전/다음 이미지가 없거나 전체 이미지가 적을 때 완전 숨김 */
    .marketing-swiper .swiper-button-prev.swiper-button-disabled,
    .marketing-swiper .swiper-button-next.swiper-button-disabled,
    .marketing-swiper .swiper-button-prev.swiper-button-lock,
    .marketing-swiper .swiper-button-next.swiper-button-lock {
        display: none !important;
        opacity: 0 !important;
        visibility: hidden !important;
        pointer-events: none !important;
    }

    .marketing-swiper .swiper-button-prev:after,
    .marketing-swiper .swiper-button-next:after {
        font-size: 0.8rem !important;
        font-weight: 800 !important;
    }
    .marketing-swiper .swiper-button-prev { left: 4px !important; }
    .marketing-swiper .swiper-button-next { right: 4px !important; }

    /* 17.6.3. PC & 모바일 공통: 1:1 완벽 정방형 박스 & 정중앙 정렬 (높이 불일치 해결) */
    .marketing-swiper .swiper-slide.marketing-slide-item {
        height: auto !important;
        box-sizing: border-box !important;
    }

    .marketing-slide-card {
        height: 100% !important;
        background: transparent !important;
        background-color: transparent !important;
        box-shadow: none !important;
        padding: 0 !important;
        margin: 0 !important;
        border: 1.5px solid transparent !important;
        border-radius: var(--radius-fixed, 6px) !important;
        transition: border-color 0.2s ease !important;
        display: flex !important;
        flex-direction: column !important;
        justify-content: space-between !important;
    }

    /* 롱프레스 시 점선 테두리 */
    .marketing-slide-item.is-dragging .marketing-slide-card,
    .marketing-slide-item:active .marketing-slide-card {
        border-color: #3b82f6 !important;
        border-style: dashed !important;
        background-color: rgba(59, 130, 246, 0.05) !important;
    }

    /* 가로폭에 연동되는 1:1 정방형 박스 */
    .marketing-slide-card .preview-wrap {
        width: 100% !important;
        aspect-ratio: 1 / 1 !important;
        height: auto !important;
        background-color: #f8fafc !important;
        border-radius: var(--radius-fixed, 6px) !important;
        padding: 0 !important;
        margin: 0 !important;
        display: flex !important;
        align-items: center !important;
        justify-content: center !important;
        position: relative !important;
        overflow: hidden !important;
    }

    /* 내부 이미지 (중앙 핏 + max 100% + 소프트 섀도우) */
    .marketing-slide-card .preview-wrap img,
    .marketing-slide-card .preview-wrap .marketing-img-thumb {
        max-width: 100% !important;
        max-height: 100% !important;
        width: auto !important;
        height: auto !important;
        object-fit: contain !important;
        display: block !important;
        margin: auto !important;
        border-radius: 4px !important;
        box-shadow: 0 3px 8px rgba(15, 23, 42, 0.1) !important;
    }

    .marketing-slide-card .marketing-filename-clamp {
        font-size: 0.75rem !important;
        padding: 6px 2px 0 2px !important;
        background-color: transparent !important;
        color: #475569 !important;
        text-align: center !important;
    }

    /* 17.6.4. 모바일 환경 전용 (767.98px 이하): 100% Edge-to-Edge 확장 & 2개 분할 */
    @media (max-width: 767.98px) {
        .multi-slot-action-header {
            flex-direction: row !important;
            align-items: center !important;
        }
        .multi-slot-guide-text {
            width: 100% !important;
            margin-top: 4px !important;
            display: block !important;
        }

        /* 아코디언 카드 패딩(16px) 상쇄 전폭 확장 */
        .multi-slot-edge-to-edge {
            margin-left: -16px !important;
            margin-right: -16px !important;
            width: calc(100% + 32px) !important;
        }

        .multi-slot-swiper-outer {
            width: 100% !important;
            padding: 8px 10px !important;
            background-color: #f8fafc !important;
            border-top: 1px solid #e2e8f0 !important;
            border-bottom: 1px solid #e2e8f0 !important;
            overflow: hidden !important;
        }

        /* 모바일 슬라이드 너비 */
        .marketing-slide-item {
            flex: 0 0 calc(50% - 5px) !important;
            width: calc(50% - 5px) !important;
            max-width: calc(50% - 5px) !important;
            min-width: 0 !important;
        }

        /* 모바일 화살표 버튼 크기 및 터치 영역 */
        .marketing-swiper .swiper-button-prev,
        .marketing-swiper .swiper-button-next {
            display: flex !important;
            width: 28px !important;
            height: 28px !important;
            top: 42% !important;
            border: 1px solid #94a3b8 !important;
        }

        .marketing-swiper .swiper-button-prev.swiper-button-disabled,
        .marketing-swiper .swiper-button-next.swiper-button-disabled,
        .marketing-swiper .swiper-button-prev.swiper-button-lock,
        .marketing-swiper .swiper-button-next.swiper-button-lock {
            display: none !important;
        }

        .marketing-swiper .swiper-button-prev:after,
        .marketing-swiper .swiper-button-next:after {
            font-size: 0.7rem !important;
        }
        .marketing-swiper .swiper-button-prev { left: 2px !important; }
        .marketing-swiper .swiper-button-next { right: 2px !important; }

        .marketing-slide-card .marketing-filename-clamp {
            font-size: 0.72rem !important;
        }
    }

    /* 17.6.5. 초소형 모바일 기기 (390px 이하) 마진 보정 */
    @media (max-width: 390px) {
        .multi-slot-edge-to-edge {
            margin-left: -12px !important;
            margin-right: -12px !important;
            width: calc(100% + 24px) !important;
        }
    }

---

## 4. 뷰티샵 관리자 전용 스타일시트 (`public/css/shop_admin_custom.css`)

모바일 퍼스트 최적화, 16px/12px 반응형 거터, 밑줄 폼, PC 아코디언 해제 로직이 적용된 전체 소스코드입니다.

    /* =============================================================================
       [GLOBEAU SHOP ADMIN - Mobile First Custom CSS]
       파일 경로: public/css/shop_admin_custom.css
       =============================================================================
       - 뷰티샵 원장님 모바일/태블릿 터치 친화적 전용 스타일시트
       - 본사 관리자(admin_custom.css)의 기본 컴포넌트 및 주소 검색 규격을 상속받아 확장합니다.
       - PC(768px 이상): 아코디언 완전 해제 & 720px 사각 박스 카드 뷰
       - 모바일(767.98px 이하): 원터치 아코디언 & 16px 거터(390px 이하는 12px) & 심리스 밑줄 폼
       ============================================================================= */

    /* =============================================================================
       [01. 뷰티샵 레이아웃 뼈대 및 Sticky Footer 구조]
       ============================================================================= */
    /* 1.1. 우측 메인 영역: Sticky Footer 구조 적용 (푸터 하단 밀착) */
    #main-content {
        display: flex;
        flex-direction: column;
        min-height: 100vh;
        padding-top: 0 !important;
        margin-top: 0 !important;
    }

    /* 1.2. 뷰티샵 관리자 전용 메인 본문 컨테이너 (.content-body 간섭 및 중복 패딩 완전 배제) */
    .shop-main-body {
        flex-grow: 1;
        padding: 0 !important;
        margin: 0 !important;
    }

    /* 1.3. 뷰티샵 관리자 기본 배경 및 모바일 하단 탭바 안전 영역 */
    body.is-shop-admin {
        background-color: #f8fafc;
        padding-bottom: 60px;
    }

    /* 1.4. PC 모니터 (992px 이상): 하단 탭바가 숨겨지므로 바닥 여백을 0으로 초기화 */
    @media (min-width: 992px) {
        body.is-shop-admin {
            padding-bottom: 0 !important;
        }
    }

    /* 1.5. 푸터 자체의 하단 마진 제거 */
    footer,
    .admin-footer {
        margin-bottom: 0 !important;
    }

    /* =============================================================================
       [02. 뷰티샵 본문 720px 중앙 반응형 프레임 (외곽 거터 단일 제어소)]
       ============================================================================= */
    /* 2.1. PC 환경 (768px 이상): 중앙 720px 카드 형태 및 상하좌우 안전 여백 */
    @media (min-width: 768px) {
        .shop-mobile-container {
            width: 100%;
            max-width: 720px;
            margin-left: auto;
            margin-right: auto;
            padding: 24px 16px 0 16px;
        }
    }

    /* 2.2. 모바일 표준 환경 (391px ~ 767.98px): 모바일 플랫폼 표준 16px 좌우 거터 */
    @media (max-width: 767.98px) {
        .shop-mobile-container {
            width: 100% !important;
            max-width: 100% !important;
            margin-left: 0 !important;
            margin-right: 0 !important;
            padding-left: 16px !important;
            padding-right: 16px !important;
            padding-top: 16px !important;
            padding-bottom: 0 !important;
            box-sizing: border-box !important;
        }
    }

    /* 2.3. 초소형 모바일 환경 (390px 이하): 그리드 표준 최소 여백 12px 엄격 고정 */
    @media (max-width: 390px) {
        .shop-mobile-container {
            padding-left: 12px !important;
            padding-right: 12px !important;
            padding-top: 12px !important;
        }

        /* 카드 내부 패딩도 12px로 균형 조정 */
        .custom-accordion .accordion-body,
        .app-card-body {
            padding-left: 12px !important;
            padding-right: 12px !important;
        }
    }

    /* =============================================================================
       [03. 뷰티샵 전용 브랜드 포인트 및 버튼 시스템]
       ============================================================================= */
    /* 3.1. 모바일 메인 타이틀(H1) 좌측 브랜드 모카 포인트 세로 바 (4×20px) */
    .content-title-indicator {
        width: 4px;
        height: 20px;
        background-color: var(--primary-color, #b18977);
    }

    /* 3.2. 아코디언 헤더 아이콘 테마 컬러 강제 주입 */
    .icon-theme {
        color: var(--primary-color, #b18977) !important;
    }

    /* 3.3. 헤더 필수/선택 뱃지 슬림 폰트 (0.75rem) */
    .badge-required {
        font-size: 0.75rem;
    }

    /* 3.4. 뷰티샵 기본 브랜드 모카 액션 버튼 */
    .btn-admin-primary {
        background-color: var(--primary-color, #b18977) !important;
        border-color: var(--primary-color, #b18977) !important;
        color: #ffffff !important;
        border-radius: var(--radius-fixed, 6px) !important;
        min-height: 38px;
        padding: 4px 16px;
        font-size: 0.90rem;
        font-weight: 700;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        transition: all 0.15s ease-in-out;
    }
    .btn-admin-primary:hover,
    .btn-admin-primary:focus {
        background-color: #9c7564 !important;
        border-color: #9c7564 !important;
        color: #ffffff !important;
    }

    /* 3.5. 상단 모바일 전용 슬림 헤더 저장 버튼 (34px) */
    .btn-admin-mobile-header {
        min-height: 34px !important;
        padding: 4px 14px !important;
        font-size: 0.88rem !important;
    }

    /* 3.6. 아코디언 섹션별 인라인 저장 버튼 (36px) */
    .btn-admin-section-save {
        min-height: 36px !important;
        padding: 4px 16px !important;
        font-size: 0.86rem !important;
    }

    /* 3.7. 하단 PC 전용 최종 메인 저장 버튼 (40px) */
    .btn-admin-main-save {
        min-height: 40px !important;
        padding: 6px 28px !important;
        font-size: 0.95rem !important;
    }

    /* =============================================================================
       [04. 뷰티샵 마케팅 갤러리 Swiper 전용 컴포넌트]
       ============================================================================= */
    /* 4.1. Swiper 슬라이드 아이템 마진 초기화 (간격은 Swiper 옵션 전담) */
    .shop-marketing-swiper .swiper-slide {
        margin-right: 0;
        box-sizing: border-box;
    }

    /* 4.2. 갤러리 슬라이드 카드 박스 */
    .marketing-slide-card {
        border-radius: var(--radius-fixed, 6px) !important;
    }

    /* 4.3. 썸네일 우측 상단 정원형 삭제(X) 버튼 (22×22px) */
    .slide-del-btn {
        width: 22px;
        height: 22px;
        z-index: 5;
    }
    .slide-del-icon {
        font-size: 0.65rem;
    }

    /* 4.4. 1:1 정방형 썸네일 뷰박스 및 커버 이미지 */
    .preview-ratio-wrap {
        aspect-ratio: 1 / 1;
        width: 100%;
    }
    .marketing-img-thumb {
        max-width: 100%;
        max-height: 100%;
        width: auto;
        height: auto;
        object-fit: cover;
        display: block;
    }

    /* 4.5. 파일명 1줄 말줄임 클램프 */
    .marketing-filename-clamp {
        font-size: 0.75rem;
    }

    /* 4.6. 갤러리 상단 설명 텍스트 (0.82rem) */
    .gallery-desc-text {
        font-size: 0.82rem;
    }

    /* 4.7. 네비게이션 좌우 화살표 아이콘 */
    .swiper-nav-arrow-icon {
        font-size: 0.75rem;
    }

    /* 4.8. 사진 추가 모달 트리거 버튼 */
    .btn-admin-add-photo {
        border-radius: var(--radius-fixed, 6px) !important;
        font-size: 0.85rem !important;
        padding: 6px 14px !important;
    }

    /* 4.9. 정산 입금 계좌 일치 안내 박스 텍스트 */
    .account-notice-text {
        font-size: 0.85rem;
        color: #334155;
    }

    /* =============================================================================
       [05. PC 환경 (768px 이상): 아코디언 완전 해제 & 상시 노출 사각 박스 카드 뷰]
       ============================================================================= */
    @media (min-width: 768px) {
        /* 5.1. 각 섹션 카드 외곽선 및 라운드 규격 */
        .custom-accordion .accordion-item,
        .app-form-card {
            border: 1px solid #e2e8f0 !important;
            border-radius: var(--radius-fixed, 6px) !important;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04) !important;
            overflow: hidden;
            background-color: #ffffff;
            margin-bottom: 24px !important;
        }

        /* 5.2. 아코디언 헤더: 클릭 방지 및 화살표 제거 (일반 카드 헤더화) */
        .custom-accordion .accordion-button {
            cursor: default !important;
            pointer-events: none !important;
            background-color: #ffffff !important;
            color: #0f172a !important;
            padding: 16px 20px !important;
            box-shadow: none !important;
        }
        .custom-accordion .accordion-button::after {
            display: none !important;
        }

        /* 5.3. 모든 컨텐츠 영역 상시 노출 (접힘 상태 무력화) */
        .custom-accordion .accordion-collapse,
        .custom-accordion .accordion-collapse.collapse,
        .custom-accordion .accordion-collapse.collapse:not(.show) {
            display: block !important;
            height: auto !important;
            visibility: visible !important;
        }

        /* 5.4. 카드 본문 패딩 */
        .custom-accordion .accordion-body,
        .app-card-body {
            background-color: #ffffff !important;
            border-top: 1px solid #edf2f7 !important;
            padding: 20px !important;
        }

        /* 5.5. PC 화면 섹션별 인라인 저장 버튼 숨김 */
        .section-save-btn-wrap {
            display: none !important;
        }

        /* 5.6. PC 환경 표준 사각 박스 인풋 규격 (44px) */
        .app-form-input,
        .form-control,
        .form-select {
            min-height: 44px !important;
            height: 44px !important;
            font-size: 0.95rem !important;
            border-radius: var(--radius-fixed, 6px) !important;
            border: 1px solid #cbd5e1 !important;
            padding-left: 12px !important;
            padding-right: 12px !important;
            background-color: #ffffff !important;
            color: #0f172a !important;
        }
        .app-form-input:focus,
        .form-control:focus,
        .form-select:focus {
            border-color: var(--primary-color, #b18977) !important;
            box-shadow: 0 0 0 0.2rem rgba(177, 137, 119, 0.15) !important;
        }
    }

    /* =============================================================================
       [06. 모바일 환경 (767.98px 이하): 12px 소프트 카드 & 심리스 언더라인(밑줄) 폼]
       ============================================================================= */
    @media (max-width: 767.98px) {
        /* 6.1. 각 섹션 12px 모던 카드 박스 */
        .custom-accordion .accordion-item,
        .app-form-card {
            border: 1px solid #e2e8f0 !important;
            border-radius: 12px !important;
            box-shadow: 0 2px 8px rgba(15, 23, 42, 0.05) !important;
            background-color: #ffffff;
            margin-bottom: 16px !important;
            overflow: hidden;
            width: 100% !important;
        }

        /* 6.2. 원터치 아코디언 헤더 (56px 터치 타겟) */
        .custom-accordion .accordion-button {
            padding: 16px 16px !important;
            background-color: #ffffff !important;
            min-height: 56px !important;
            border-radius: 0 !important;
        }

        /* 6.3. 아코디언 타이틀 (17px 딥블랙) */
        .custom-accordion .custom-accordion-title {
            font-size: 1.05rem !important;
            font-weight: 700 !important;
            color: #0f172a !important;
            letter-spacing: -0.02em;
        }

        /* 6.4. 본문 영역 패딩 및 상단 구분선 */
        .custom-accordion .accordion-body,
        .app-card-body {
            background-color: #ffffff !important;
            border-top: 1px solid #edf2f7 !important;
            padding: 14px 16px 20px 16px !important;
        }

        /* 6.5. 폼 라벨 (15px 딥블랙 세미볼드) */
        .form-label,
        .form-label.small,
        .custom-form-label,
        .custom-accordion .form-label {
            font-size: 0.95rem !important;
            font-weight: 600 !important;
            color: #111827 !important;
            margin-bottom: 4px !important;
            letter-spacing: -0.01em;
        }

        /* 6.6. 모바일 사각 테두리 박스 완전 배제 -> 심리스 밑줄(언더라인) 폼 */
        .app-form-input,
        .form-control:not([type="hidden"]),
        .form-select {
            border: none !important;
            border-bottom: 1px solid #cbd5e1 !important;
            border-radius: 0 !important;
            background-color: transparent !important;
            color: #0f172a !important;
            font-size: 1rem !important;
            font-weight: 500 !important;
            min-height: 46px !important;
            height: 46px !important;
            padding-left: 4px !important;
            padding-right: 4px !important;
            box-shadow: none !important;
            transition: border-color 0.2s ease;
        }

        /* 6.7. 터치/포커스 시 브랜드 모카 2px 밑줄 강조 */
        .app-form-input:focus,
        .form-control:focus,
        .form-select:focus {
            border-bottom: 2px solid var(--primary-color, #b18977) !important;
            background-color: transparent !important;
            box-shadow: none !important;
        }

        /* 6.8. 읽기 전용 인풋 (기본주소, 우편번호, 사업자번호 등) 점선 밑줄 */
        .app-form-input[readonly],
        .form-control[readonly] {
            border-bottom: 1px dashed #94a3b8 !important;
            background-color: transparent !important;
            color: #64748b !important;
        }

        /* 6.9. 인풋 그룹 내부 (아이콘 접두사 등) 언더라인 일체화 */
        .input-group {
            border: none !important;
            border-bottom: 1px solid #cbd5e1 !important;
            border-radius: 0 !important;
            box-shadow: none !important;
        }
        .input-group:focus-within {
            border-bottom: 2px solid var(--primary-color, #b18977) !important;
        }
        .input-group .input-group-text {
            background-color: transparent !important;
            border: none !important;
            padding-left: 2px !important;
            padding-right: 8px !important;
            color: #64748b !important;
        }
        .input-group .form-control {
            border-bottom: none !important;
        }

        /* 6.10. 플레이스홀더 텍스트 */
        .app-form-input::placeholder,
        .form-control::placeholder {
            color: #94a3b8 !important;
            font-size: 0.95rem !important;
            font-weight: 400 !important;
        }

        /* 6.11. 도움말 안내 텍스트 */
        .form-text,
        .custom-accordion .form-text,
        .text-muted.small {
            font-size: 0.85rem !important;
            color: #475569 !important;
            margin-top: 6px !important;
            line-height: 1.45 !important;
        }
    }

---

## 5. 공용 멀티 이미지 슬롯 엔진 (`public/js/admin/image_multi_slot.js`)

ResizeObserver 기반 실시간 슬라이드 수량 계산, 롱프레스 뷰포트 절대좌표 LERP 추종, 순번 및 삭제 동기화 기능을 전담하는 단일 공용 스크립트 소스코드입니다.

    /**
     * =============================================================================
     * [GLOBEAU ADMIN] 공용 멀티 이미지 슬롯 (Swiper + 롱프레스 정렬) 엔진
     * 파일 경로: /public/js/admin/image_multi_slot.js
     * =============================================================================
     */

    // 1. 순번 인풋(image_sorts) 및 aria-label 순차 동기화
    window.refreshMultiSlotSortOrders = function (wrapper) {
        if (!wrapper) wrapper = document.getElementById('marketingImagesWrapper');
        if (!wrapper) return;

        const slides = wrapper.querySelectorAll('.marketing-slide-item');
        slides.forEach((slide, index) => {
            const imgId = slide.dataset.imageId || slide.querySelector('input[name*="_image_ids[]"]')?.value;
            if (!imgId) return;

            const calculatedOrder = index + 1;
            const sortInput = slide.querySelector('.input-sort-order, input[name^="image_sorts"]');
            if (sortInput) {
                sortInput.name = `image_sorts[${imgId}]`;
                sortInput.value = calculatedOrder;
            }
            slide.setAttribute('aria-label', `${calculatedOrder} / ${slides.length}`);
        });
    };

    // 2. 수량 뱃지 및 추가 버튼 상태 갱신
    window.updateMultiSlotCount = function (slotKey = 'marketing', maxCount = 30) {
        const wrapper = document.getElementById(`${slotKey}ImagesWrapper`) || document.getElementById('marketingImagesWrapper');
        const badge = document.getElementById(`${slotKey}CountBadge`) || document.getElementById('marketingCountBadge');
        const addBtn = document.getElementById(`btnOpen${slotKey.charAt(0).toUpperCase() + slotKey.slice(1)}Media`) || document.getElementById('btnOpenMarketingMedia');

        if (!wrapper) return;
        const currentCount = wrapper.querySelectorAll('.marketing-slide-item').length;

        if (badge) {
            badge.textContent = `${currentCount} / ${maxCount}`;
        }
        if (addBtn) {
            addBtn.disabled = (currentCount >= maxCount);
        }
        if (window.marketingSwiperInstance && typeof window.marketingSwiperInstance.update === 'function') {
            window.marketingSwiperInstance.update();
        }
    };

    // 3. Swiper 슬라이더 공용 초기화 (ResizeObserver 기반 실시간 슬라이드 수량 제어)
    window.initMultiSlotSwiper = function (selector = '.shop-marketing-swiper, .marketing-swiper') {
        const swiperEl = document.querySelector(selector);
        if (!swiperEl || typeof Swiper === 'undefined') return;

        if (window.marketingSwiperInstance && typeof window.marketingSwiperInstance.destroy === 'function') {
            window.marketingSwiperInstance.destroy(true, true);
        }

        // 컴포넌트 실제 가로폭에 따른 적정 슬라이드 개수 산출 함수
        function getSlidesPerViewByContainerWidth(width) {
            if (width < 480) return 2;       // 좁은 모바일/컬럼: 2개
            if (width < 700) return 3;       // 모바일 가로/중간 폭: 3개
            if (width < 1000) return 4;      // 일반 PC 아코디언 폭: 4개
            if (width < 1300) return 5;      // 넓은 PC 컨테이너: 5개
            return 6;                        // 대형 와이드 화면: 6개
        }

        const currentWidth = swiperEl.clientWidth || window.innerWidth;
        const initialSlidesPerView = getSlidesPerViewByContainerWidth(currentWidth);

        window.marketingSwiperInstance = new Swiper(swiperEl, {
            slidesPerView: initialSlidesPerView,
            slidesPerGroup: 1,
            spaceBetween: 12,
            freeMode: false,
            watchOverflow: true,
            observer: true,
            observeParents: true,
            mousewheel: { forceToAxis: true },
            navigation: {
                nextEl: '.marketing-next',
                prevEl: '.marketing-prev',
                disabledClass: 'swiper-button-disabled',
                lockClass: 'swiper-button-lock'
            },
            resistance: true,
            resistanceRatio: 0.85
        });

        // ResizeObserver를 통한 컴포넌트 크기 실시간 감지 및 동적 수량 변경
        if (window.ResizeObserver) {
            if (swiperEl._containerResizeObserver) {
                swiperEl._containerResizeObserver.disconnect();
            }

            const resizeObserver = new ResizeObserver(entries => {
                for (let entry of entries) {
                    const newWidth = entry.contentRect.width;
                    if (!newWidth || !window.marketingSwiperInstance) return;

                    const targetSlides = getSlidesPerViewByContainerWidth(newWidth);
                    if (window.marketingSwiperInstance.params.slidesPerView !== targetSlides) {
                        window.marketingSwiperInstance.params.slidesPerView = targetSlides;
                        window.marketingSwiperInstance.update();
                    }
                }
            });

            resizeObserver.observe(swiperEl);
            swiperEl._containerResizeObserver = resizeObserver;
        }
    };

    // 4. 단일 슬라이드 DOM 조립 헬퍼 (무패딩 + 1:1 이미지 중앙 정렬 핏)
    window.createMultiSlotSlideElement = function (img, slotKey = 'marketing', currentIdx = 0) {
        const fileName = img.original_name || img.name || '이미지';
        const previewSrc = img.thumb_url || img.webp_url || (img.path ? `/storage/${img.path.replace(/^\/?storage\//, '')}` : '');

        const slideDiv = document.createElement('div');
        slideDiv.className = 'swiper-slide marketing-slide-item';
        slideDiv.dataset.imageId = img.id;
        slideDiv.style.width = '';

        slideDiv.innerHTML = `
            <div class="h-100 d-flex flex-column justify-content-between position-relative marketing-slide-card p-0">
                <button type="button" 
                        class="btn btn-sm btn-danger position-absolute top-0 end-0 m-1 p-0 rounded-circle d-flex align-items-center justify-content-center btn-remove-marketing shadow-sm" 
                        style="width: 22px; height: 22px; z-index: 5;" 
                        data-image-id="${img.id}" 
                        title="삭제">
                    <i class="fa-solid fa-xmark" style="font-size: 0.7rem;"></i>
                </button>
                <div class="preview-wrap position-relative w-100">
                    <img src="${previewSrc}" 
                         alt="${fileName}" 
                         class="marketing-img-thumb"
                         loading="lazy">
                </div>
                <div class="marketing-filename-clamp text-center text-muted fw-semibold small text-truncate" title="${fileName}">
                    ${fileName}
                </div>
                <input type="hidden" name="${slotKey}_image_ids[]" value="${img.id}">
                <input type="hidden" name="image_sorts[${img.id}]" value="${currentIdx + 1}" class="input-sort-order">
            </div>
        `;
        return slideDiv;
    };

    // 5. 롱프레스 FLIP 드래그 정렬 엔진 (뷰포트 절대좌표 LERP 추종)
    window.initMultiSlotSortable = function (wrapperId = 'marketingImagesWrapper') {
        const wrapper = document.getElementById(wrapperId);
        if (!wrapper) return;

        wrapper.style.userSelect = 'none';
        wrapper.style.webkitUserSelect = 'none';
        wrapper.style.touchAction = 'pan-y';

        if (wrapper._sortableBound) return;
        wrapper._sortableBound = true;

        let activeSlide = null;
        let placeholder = null;
        let pressTimer = null;
        let isDragging = false;

        let initialX = 0, initialY = 0;
        let targetX = 0, targetY = 0;
        let currentX = 0, currentY = 0;
        let initialRect = null;
        let animFrameId = null;

        const LONG_PRESS_DURATION = 220; // 0.22초

        function getSwiper() {
            return window.marketingSwiperInstance;
        }

        function smoothReorder(actionCallback) {
            const siblings = Array.from(wrapper.querySelectorAll('.marketing-slide-item')).filter(s => s !== activeSlide && s !== placeholder);
            const firstPositions = new Map();

            siblings.forEach(s => firstPositions.set(s, s.getBoundingClientRect().left));
            actionCallback();

            siblings.forEach(s => {
                const deltaX = firstPositions.get(s) - s.getBoundingClientRect().left;
                if (deltaX !== 0) {
                    s.style.transition = 'none';
                    s.style.transform = `translate3d(${deltaX}px, 0, 0)`;

                    requestAnimationFrame(() => {
                        s.style.transition = 'transform 0.25s cubic-bezier(0.25, 1, 0.5, 1)';
                        s.style.transform = 'translate3d(0, 0, 0)';
                    });

                    const onEnd = () => {
                        s.style.transition = '';
                        s.style.transform = '';
                        s.removeEventListener('transitionend', onEnd);
                    };
                    s.addEventListener('transitionend', onEnd);
                }
            });
        }

        wrapper.addEventListener('pointerdown', function (e) {
            if (e.pointerType === 'mouse' && e.button !== 0) return;
            if (e.target.closest('.btn-remove-marketing, button, a, input, select')) return;

            const slide = e.target.closest('.marketing-slide-item');
            if (!slide || slide.parentElement !== wrapper) return;

            initialX = e.clientX;
            initialY = e.clientY;
            const pointerId = e.pointerId;

            pressTimer = setTimeout(() => {
                startDrag(slide, initialX, initialY, pointerId);
            }, LONG_PRESS_DURATION);

            function onPointerMove(moveEvt) {
                if (!isDragging && Math.hypot(moveEvt.clientX - initialX, moveEvt.clientY - initialY) > 12) {
                    clearTimeout(pressTimer);
                    cleanup();
                }
            }

            function onPointerUp() {
                clearTimeout(pressTimer);
                cleanup();
            }

            function cleanup() {
                window.removeEventListener('pointermove', onPointerMove);
                window.removeEventListener('pointerup', onPointerUp);
                window.removeEventListener('pointercancel', onPointerUp);
            }

            window.addEventListener('pointermove', onPointerMove, { passive: true });
            window.addEventListener('pointerup', onPointerUp, { once: true });
            window.addEventListener('pointercancel', onPointerUp, { once: true });
        });

        function startDrag(slide, startX, startY, pointerId) {
            isDragging = true;
            activeSlide = slide;
            slide.classList.add('is-dragging');

            const swiper = getSwiper();
            if (swiper) swiper.allowTouchMove = false;

            try { wrapper.setPointerCapture(pointerId); } catch (_) {}
            if (navigator.vibrate) navigator.vibrate(50);

            initialRect = slide.getBoundingClientRect();

            placeholder = slide.cloneNode(true);
            placeholder.className = 'swiper-slide sortable-placeholder';
            placeholder.querySelectorAll('button, input').forEach(el => el.remove());
            placeholder.style.cssText = `
                width: ${initialRect.width}px !important;
                height: ${initialRect.height}px !important;
                margin-right: ${window.getComputedStyle(slide).marginRight} !important;
                opacity: 0.45 !important;
                border: 1.5px dashed #3b82f6 !important;
                border-radius: var(--radius-fixed, 6px) !important;
                box-sizing: border-box !important;
                filter: grayscale(40%) !important;
                pointer-events: none !important;
                flex-shrink: 0 !important;
                transition: all 0.22s cubic-bezier(0.25, 1, 0.5, 1) !important;
            `;
            wrapper.insertBefore(placeholder, slide);

            currentX = 0; currentY = 0; targetX = 0; targetY = 0;

            slide.style.cssText += `
                position: fixed !important;
                width: ${initialRect.width}px !important;
                height: ${initialRect.height}px !important;
                left: ${initialRect.left}px !important;
                top: ${initialRect.top}px !important;
                margin: 0 !important;
                z-index: 10099 !important;
                pointer-events: none !important;
                opacity: 0.95 !important;
                box-sizing: border-box !important;
                transform-origin: center center !important;
                transform: translate3d(0, 0, 0) scale(1.03) !important;
                box-shadow: 0 12px 28px rgba(0, 0, 0, 0.2) !important;
                cursor: grabbing !important;
            `;

            function renderLoop() {
                if (!isDragging || !activeSlide) return;
                currentX += (targetX - currentX) * 0.35;
                currentY += (targetY - currentY) * 0.35;
                activeSlide.style.transform = `translate3d(${currentX}px, ${currentY}px, 0) scale(1.03)`;
                animFrameId = requestAnimationFrame(renderLoop);
            }
            animFrameId = requestAnimationFrame(renderLoop);

            function onDragMove(moveEvt) {
                if (!isDragging || !activeSlide) return;
                moveEvt.preventDefault();

                targetX = moveEvt.clientX - startX;
                targetY = moveEvt.clientY - startY;

                const elementsUnder = document.elementsFromPoint(moveEvt.clientX, moveEvt.clientY);
                let targetSlide = null;
                for (const el of elementsUnder) {
                    const s = el.closest('.marketing-slide-item');
                    if (s && s !== activeSlide && s !== placeholder && s.parentElement === wrapper) {
                        targetSlide = s;
                        break;
                    }
                }

                if (targetSlide) {
                    const targetRect = targetSlide.getBoundingClientRect();
                    const midX = targetRect.left + targetRect.width / 2;

                    if (moveEvt.clientX < midX && placeholder.nextElementSibling !== targetSlide) {
                        smoothReorder(() => wrapper.insertBefore(placeholder, targetSlide));
                    } else if (moveEvt.clientX >= midX && placeholder.previousElementSibling !== targetSlide) {
                        smoothReorder(() => wrapper.insertBefore(placeholder, targetSlide.nextSibling));
                    }
                }
            }

            function onDragEnd() {
                window.removeEventListener('pointermove', onDragMove);
                window.removeEventListener('pointerup', onDragEnd);
                window.removeEventListener('pointercancel', onDragEnd);

                if (animFrameId) cancelAnimationFrame(animFrameId);
                try { wrapper.releasePointerCapture(pointerId); } catch (_) {}

                if (!activeSlide) return;

                const snapX = placeholder.getBoundingClientRect().left - initialRect.left;
                const snapY = placeholder.getBoundingClientRect().top - initialRect.top;

                activeSlide.style.transition = 'transform 0.2s cubic-bezier(0.2, 0, 0, 1), box-shadow 0.2s ease';
                activeSlide.style.transform = `translate3d(${snapX}px, ${snapY}px, 0) scale(1)`;

                setTimeout(() => {
                    if (placeholder && placeholder.parentNode === wrapper) {
                        wrapper.insertBefore(activeSlide, placeholder);
                        placeholder.remove();
                    }

                    activeSlide.classList.remove('is-dragging');
                    activeSlide.style.position = '';
                    activeSlide.style.width = '';
                    activeSlide.style.height = '';
                    activeSlide.style.left = '';
                    activeSlide.style.top = '';
                    activeSlide.style.margin = '';
                    activeSlide.style.zIndex = '';
                    activeSlide.style.pointerEvents = '';
                    activeSlide.style.opacity = '';
                    activeSlide.style.transform = '';
                    activeSlide.style.boxShadow = '';
                    activeSlide.style.transition = '';
                    activeSlide.style.cursor = '';

                    isDragging = false;
                    activeSlide = null;
                    placeholder = null;

                    const swiper = getSwiper();
                    if (swiper) {
                        swiper.allowTouchMove = true;
                        swiper.update();
                    }

                    window.refreshMultiSlotSortOrders(wrapper);
                }, 200);
            }

            window.addEventListener('pointermove', onDragMove, { passive: false });
            window.addEventListener('pointerup', onDragEnd, { once: true });
            window.addEventListener('pointercancel', onDragEnd, { once: true });
        }
    };

    // 6. 삭제 버튼 이벤트 위임 등록
    window.bindMultiSlotDeleteHandler = function (wrapperId = 'marketingImagesWrapper', deleteContainerId = 'deleteImageIdsContainer') {
        const wrapper = document.getElementById(wrapperId);
        const deleteIdsContainer = document.getElementById(deleteContainerId);
        if (!wrapper || wrapper._deleteBound) return;
        wrapper._deleteBound = true;

        wrapper.addEventListener('click', function (e) {
            const removeBtn = e.target.closest('.btn-remove-marketing');
            if (!removeBtn) return;

            const slideItem = removeBtn.closest('.marketing-slide-item');
            const imageId = removeBtn.dataset.imageId;

            if (imageId && deleteIdsContainer) {
                const hiddenInput = document.createElement('input');
                hiddenInput.type = 'hidden';
                hiddenInput.name = 'delete_image_ids[]';
                hiddenInput.value = imageId;
                deleteIdsContainer.appendChild(hiddenInput);
            }

            if (slideItem) {
                slideItem.remove();
                window.updateMultiSlotCount('marketing', 30);
                window.refreshMultiSlotSortOrders(wrapper);
            }
        });
    };

    // 7. 자동 로드
    document.addEventListener('DOMContentLoaded', function () {
        window.initMultiSlotSwiper();
        window.initMultiSlotSortable('marketingImagesWrapper');
        window.bindMultiSlotDeleteHandler('marketingImagesWrapper', 'deleteImageIdsContainer');
        window.refreshMultiSlotSortOrders();
    });

---

## 6. 자립형 멀티 슬롯 컴포넌트 (`resources/views/components/shop_admin/image-multi-slot.blade.php`)

Swiper 11 CDN 및 공용 엔진 스크립트를 `@pushOnce`로 스스로 주입하여 어느 뷰에서나 독립적으로 동작하는 표준 컴포넌트 소스코드입니다.

    @props([
        'name' => 'marketing',
        'label' => '마케팅 갤러리 이미지 관리',
        'model' => null,
        'maxCount' => 30,
        'badgeText' => '최대 30장 등록 가능',
        'buttonText' => '사진 추가'
    ])

    @php
        $slotKey = $name;
        $existingImages = collect();
        if ($model && method_exists($model, 'getSlotImages')) {
            $existingImages = $model->getSlotImages($slotKey);
        }
        $currentCount = $existingImages->count();
    @endphp

    <div class="multi-slot-edge-to-edge mb-3 mb-md-4" data-slot-name="{{ $slotKey }}" data-max-count="{{ $maxCount }}">
        <!-- 1. 헤더 영역 (버튼 및 수량 안내) -->
        <div class="multi-slot-header px-3 px-md-0 mb-2">
            <div class="d-flex justify-content-between align-items-center mb-2">
                <span class="fw-bold text-dark small">
                    <i class="fa-solid fa-images me-1 text-primary"></i> {{ $label }}
                </span>
                <span class="badge bg-primary-subtle text-primary border border-primary-subtle small" id="{{ $slotKey }}CountBadge">
                    {{ $currentCount }} / {{ $maxCount }}
                </span>
            </div>

            <div class="multi-slot-action-header d-flex flex-wrap align-items-center gap-2">
                <button type="button" 
                        class="btn btn-outline-primary btn-sm fw-bold shadow-sm text-nowrap flex-shrink-0" 
                        id="btnOpen{{ ucfirst($slotKey) }}Media"
                        onclick="openMediaModal('{{ $slotKey }}', 'multiple')"
                        style="white-space: nowrap !important; height: 34px;">
                    <i class="fa-solid fa-cloud-arrow-up me-1"></i> {{ $buttonText }}
                </button>
                <span class="text-muted small multi-slot-guide-text" style="font-size: 0.75rem; line-height: 1.35; word-break: keep-all;">
                    <i class="fa-solid fa-hand-pointer me-1"></i>카드를 꾹 눌러서(롱프레스) 좌우 순서를 변경할 수 있습니다.
                </span>
            </div>
        </div>

        <!-- 2. Swiper 슬라이더 (모바일 화면 좌우 100% 엣지투엣지 전폭) -->
        <div class="multi-slot-swiper-outer position-relative">
            <div class="swiper marketing-swiper shop-marketing-swiper position-relative">
                <div class="swiper-wrapper" id="{{ $slotKey }}ImagesWrapper">
                    @foreach($existingImages as $index => $img)
                        @php
                            $imgSrc = $img->preview_url ?: ($img->thumb_url ?: asset('storage/' . $img->path));
                            $sortOrder = $index + 1;
                        @endphp
                        <div class="swiper-slide marketing-slide-item" data-image-id="{{ $img->id }}">
                            <div class="h-100 d-flex flex-column justify-content-between position-relative marketing-slide-card p-0">
                                <!-- 개별 삭제 버튼 -->
                                <button type="button" 
                                        class="btn btn-sm btn-danger position-absolute top-0 end-0 m-1 p-0 rounded-circle d-flex align-items-center justify-content-center btn-remove-marketing shadow-sm" 
                                        style="width: 22px; height: 22px; z-index: 5;" 
                                        data-image-id="{{ $img->id }}" 
                                        title="삭제">
                                    <i class="fa-solid fa-xmark" style="font-size: 0.7rem;"></i>
                                </button>

                                <!-- 1:1 미리보기 박스 (패딩 제로, 가로/세로 정중앙 핏) -->
                                <div class="preview-wrap position-relative w-100">
                                    <img src="{{ $imgSrc }}" 
                                         alt="{{ $img->original_name }}" 
                                         class="marketing-img-thumb"
                                         loading="lazy">
                                </div>

                                <!-- 파일명 -->
                                <div class="marketing-filename-clamp text-center text-muted fw-semibold small text-truncate" title="{{ $img->original_name }}">
                                    {{ $img->original_name }}
                                </div>

                                <!-- 히든 인풋 -->
                                <input type="hidden" name="{{ $slotKey }}_image_ids[]" value="{{ $img->id }}">
                                <input type="hidden" name="image_sorts[{{ $img->id }}]" value="{{ $sortOrder }}" class="input-sort-order">
                            </div>
                        </div>
                    @endforeach
                </div>

                <!-- 모바일/PC 공용 화살표 버튼 (넘길 슬라이드가 없을 때 자동 숨김) -->
                <div class="swiper-button-prev marketing-prev"></div>
                <div class="swiper-button-next marketing-next"></div>
            </div>
        </div>

        <!-- 3. 삭제 대상 ID 보관 컨테이너 -->
        <div id="deleteImageIdsContainer"></div>
    </div>

    <!-- Swiper 11 CSS (페이지 전체 최초 1회만 로드) -->
    @pushOnce('styles')
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css" />
    @endpushOnce

    <!-- Swiper 11 JS & 공용 멀티 슬롯 엔진 (페이지 전체 최초 1회만 순서대로 로드) -->
    @pushOnce('scripts')
    <script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
    <script src="{{ asset('js/admin/image_multi_slot.js') }}?v={{ time() }}"></script>
    @endpushOnce

---

## 7. 뷰티샵 관리자 레이아웃 (`resources/views/layouts/shop_admin.blade.php`)

인라인 스타일을 100% 제거하고 순수 마크업 구조로 경량화된 레이아웃 템플릿입니다.

    <!DOCTYPE html>
    <html lang="ko">

    <head>
        <meta charset="UTF-8">
        {{-- 원장님 모바일 기기 터치 시 브라우저 강제 줌인(Zoom-in)을 원천 차단하는 뷰포트 --}}
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
        <meta name="csrf-token" content="{{ csrf_token() }}">
        <title>@yield('title', '뷰티샵 관리자') - GLOBEAU</title>

        <!-- 데스크톱 사이드바 FOUC 방지 즉시 실행 스크립트 -->
        <script>
            (function() {
                const isMobile = {{ !empty($isMobileDevice) ? 'true' : 'false' }};
                if (!isMobile) {
                    const saved = localStorage.getItem('sidebarCollapsed');
                    if (saved === 'true' || (saved === null && window.innerWidth <= 1200)) {
                        document.documentElement.classList.add('preload-collapsed');
                    }
                }
            })();
        </script>

        <!-- Bootstrap 5 CSS -->
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
        <!-- FontAwesome 6 CDN -->
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
        <!-- Flatpickr 한국어 달력 CSS -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">

        <!-- 관리자 공용 커스텀 스타일 (디자인 토큰, 공용 컴포넌트, 주소 검색 등) -->
        <link rel="stylesheet" href="{{ asset('css/admin_custom.css') }}?v={{ time() }}">

        <!-- 뷰티샵 관리자 모바일 퍼스트 전용 스타일시트 -->
        <link rel="stylesheet" href="{{ asset('css/shop_admin_custom.css') }}?v={{ time() }}">

        @stack('styles')
    </head>

    <body class="{{ $platformClass ?? 'platform-pc' }} is-shop-admin">

        <!-- 1. 뷰티샵 관리자 전용 좌측 사이드바 -->
        @include('shop_admin.partials.shop_sidebar')

        <!-- 2. 우측 메인 작업 영역 -->
        <div id="main-content">
            <!-- 상단 Topbar -->
            @include('admin.partials.topbar')

            <!-- 뷰티샵 전용 메인 본문 컨테이너 (.content-body 간섭 원천 배제) -->
            <main class="shop-main-body">
                <div class="shop-mobile-container">
                    @yield('content')
                </div>
            </main>

            <!-- 하단 푸터 -->
            @include('admin.partials.footer')
        </div>

        <!-- 3. 공용 모바일 하단 탭바 (스마트폰 접속 시 노출) -->
        @include('admin.partials.bottom_nav')

        <!-- 4. 페이지 상단 이동 플로팅 버튼 -->
        <button id="scrollTopBtn" title="맨 위로">
            <i class="fa-solid fa-arrow-up"></i>
        </button>

        <!-- 5. 중앙 DAM 미디어 라이브러리 모달 컴포넌트 -->
        <x-admin.modal-image 
            upload-route="/shop-admin/images"
            index-route="/shop-admin/images"
            folder-route="/shop-admin/image-folders"
        />

        <!-- 6. 뷰티샵 온보딩 4단계 모달 게이트 -->
        @auth
            @if(!empty($showPhoneVerifyModal))
                @include('auth.modals.verify-phone')
                <script>
                    document.addEventListener('DOMContentLoaded', function () {
                        if (typeof showModalOnboarding === 'function') {
                            showModalOnboarding('phoneVerifyModal', false);
                        }
                    });
                </script>
            @elseif(!empty($showShopCreateModal))
                @include('shops.modals.create')
                <script>
                    document.addEventListener('DOMContentLoaded', function () {
                        if (typeof showModalOnboarding === 'function') {
                            showModalOnboarding('shopCreateModal', false);
                        }
                    });
                </script>
            @elseif(!empty($showShopPendingModal))
                @include('shops.modals.pending', ['shop' => $currentShop ?? null])
                <script>
                    document.addEventListener('DOMContentLoaded', function () {
                        if (typeof showModalOnboarding === 'function') {
                            showModalOnboarding('shopPendingModal', false);
                        }
                    });
                </script>
            @elseif(!empty($showShopRejectedModal))
                @include('shops.modals.rejected', ['shop' => $currentShop ?? null])
                <script>
                    document.addEventListener('DOMContentLoaded', function () {
                        if (typeof showModalOnboarding === 'function') {
                            showModalOnboarding('shopRejectedModal', false);
                        }
                    });
                </script>
            @endif
        @endauth

        <!-- 글로벌 자바스크립트 라이브러리 -->
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
        <script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
        <script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/ko.js"></script>

        <!-- 모달 온보딩 헬퍼 스크립트 -->
        <script src="{{ asset('js/modal_helper.js') }}?v={{ time() }}"></script>
        <!-- 관리자 공용 커스텀 스크립트 -->
        <script src="{{ asset('js/admin_custom.js') }}?v={{ time() }}"></script>
        <!-- 중앙 DAM 미디어 라이브러리 엔진 스크립트 -->
        <script src="{{ asset('js/image_library.js') }}?v={{ time() }}"></script>
        
        @stack('scripts')

        <!-- 전역 로딩 마스크 컴포넌트 -->
        <x-loading-mask />
    </body>

    </html>

---

## 8. 기본 정보 관리 블레이드 적용 결과 (`resources/views/shop_admin/settings/basic.blade.php`)

길게 늘어져 있던 인라인 Swiper 마크업 및 수동 CDN 호출을 완전히 걷어내고, 자립형 컴포넌트 호출로 초경량화된 최종 블레이드 소스코드입니다.

    @extends('layouts.shop_admin')

    @section('title', '기본 정보 관리')

    @section('content')

    <!-- 상단 메인 타이틀 및 액션 헤더 -->
    <div class="content-header-box mb-3 px-0 d-flex justify-content-between align-items-center">
        <div class="content-title-wrap d-flex align-items-center">
            <span class="content-title-indicator"></span>
            <h1 class="content-title mb-0">@yield('title')</h1>
        </div>
        <div class="content-btn-wrap d-flex align-items-center gap-2">
            <a href="{{ route('shop_admin.index') }}" class="btn btn-outline-secondary btn-app-sm fw-bold">
                <i class="fa-solid fa-arrow-left me-1"></i> 목록
            </a>
            <button type="submit" form="shopForm" class="btn btn-admin-primary btn-app-sm fw-bold shadow-sm">
                <i class="fa-solid fa-check me-1"></i> 저장
            </button>
        </div>
    </div>

    <!-- 공통 알림 컴포넌트 -->
    <x-admin.alerts-display />

    <div class="w-100">
        <form action="{{ route('shop_admin.settings.basic.update') }}" method="POST" id="shopForm">
            @csrf
            @method('PUT')

            <div class="accordion custom-accordion" id="shopSettingsAccordion">

                <!-- 1. 기본 매장 프로필 -->
                <div class="accordion-item app-form-card mb-3 mb-md-4">
                    <h2 class="accordion-header" id="headingProfile">
                        <button class="accordion-button py-3 px-3 px-md-4 fw-bold bg-white text-dark d-flex justify-content-between align-items-center shadow-none"
                                type="button" data-bs-toggle="collapse" data-bs-target="#collapseProfile" aria-expanded="true" aria-controls="collapseProfile">
                            <div class="d-flex align-items-center gap-2">
                                <span class="badge px-2 py-1 bg-danger text-white rounded-pill small badge-required">필수</span>
                                <span class="custom-accordion-title fw-bold text-dark">
                                    <i class="fa-solid fa-id-card me-2 text-primary icon-theme"></i> 기본 매장 프로필
                                </span>
                            </div>
                        </button>
                    </h2>
                    <div id="collapseProfile" class="accordion-collapse collapse show" aria-labelledby="headingProfile" data-bs-parent="#shopSettingsAccordion">
                        <div class="accordion-body app-card-body px-3 px-md-4 py-3 border-top">
                            <div class="row g-2">
                                <div class="col-12 col-md-6 mb-3">
                                    <x-admin.forms.input name="name" label="뷰티샵 명칭" :value="old('name', $shop->name)" placeholder="예: GLOBEAU 강남본점" class="app-form-input" required />
                                </div>
                                <div class="col-12 col-md-6 mb-3">
                                    <x-admin.forms.input name="ceo_name" label="대표자 성명" :value="old('ceo_name', $shop->ceo_name)" placeholder="홍길동" class="app-form-input" required />
                                </div>
                                <div class="col-12 col-md-6 mb-3">
                                    <x-admin.forms.input name="business_number_display" label="사업자 등록번호" :value="$shop->business_number ?? '미등록'" readonly class="app-form-input bg-light" prepend='<i class="fa-solid fa-building"></i>' helpText="사업자번호 변경은 본사 고객센터 심사를 통해 가능합니다." />
                                    <input type="hidden" name="business_number" value="{{ $shop->business_number }}">
                                </div>
                                <div class="col-12 col-md-6 mb-3">
                                    <x-admin.forms.input name="tel" label="매장 대표 연락처 (TEL)" :value="old('tel', $shop->tel)" placeholder="02-000-0000" class="app-form-input" prepend='<i class="fa-solid fa-phone"></i>' required />
                                </div>
                                <div class="col-12 col-md-6 mb-3">
                                    <x-admin.forms.input name="ceo_phone" label="대표자 휴대폰 번호" :value="old('ceo_phone', $shop->ceo_phone)" placeholder="010-0000-0000" prepend='<i class="fa-solid fa-mobile-screen"></i>' class="app-form-input input-phone" />
                                </div>
                                <div class="col-12 col-md-6 mb-3">
                                    <x-admin.forms.input type="email" name="ceo_email" label="대표자 이메일" :value="old('ceo_email', $shop->ceo_email)" placeholder="owner@globeau.kr" class="app-form-input" prepend='<i class="fa-solid fa-envelope"></i>' />
                                </div>
                                @if(View::exists('components.admin.category-picker'))
                                <div class="col-12 mt-1 mb-3">
                                    <x-admin.category-picker :selected-categories="$shop->categories ?? null" type="shop" max-depth="1" variant="secondary" title="뷰티샵 전문 분야" />
                                </div>
                                @endif
                            </div>
                            <div class="section-save-btn-wrap d-flex justify-content-end mt-3 pt-3 border-top">
                                <button type="submit" form="shopForm" class="btn btn-admin-primary btn-app-section shadow-sm">
                                    <i class="fa-solid fa-check me-1"></i> 프로필 정보 저장
                                </button>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 2. 매장 위치 및 주소 -->
                <div class="accordion-item app-form-card mb-3 mb-md-4">
                    <h2 class="accordion-header" id="headingLocation">
                        <button class="accordion-button collapsed py-3 px-3 px-md-4 fw-bold bg-white text-dark d-flex justify-content-between align-items-center shadow-none"
                                type="button" data-bs-toggle="collapse" data-bs-target="#collapseLocation" aria-expanded="false" aria-controls="collapseLocation">
                            <div class="d-flex align-items-center gap-2">
                                <span class="badge px-2 py-1 bg-danger text-white rounded-pill small badge-required">필수</span>
                                <span class="custom-accordion-title fw-bold text-dark">
                                    <i class="fa-solid fa-location-dot me-2 text-danger"></i> 매장 위치 및 주소
                                </span>
                            </div>
                        </button>
                    </h2>
                    <div id="collapseLocation" class="accordion-collapse collapse" aria-labelledby="headingLocation" data-bs-parent="#shopSettingsAccordion">
                        <div class="accordion-body app-card-body px-3 px-md-4 py-3 border-top">
                            <div class="row g-2">
                                <div class="col-12 mb-3">
                                    <label class="form-label fw-bold mb-2 custom-form-label">우편번호 및 기본 주소 <span class="text-danger">*</span></label>
                                    <div class="d-flex align-items-center gap-2 mb-2">
                                        <div class="zip-input-wrap">
                                            <input type="text" class="form-control zip-input-field" id="zipcode" name="zipcode" value="{{ old('zipcode', $shop->zipcode ?? '') }}" placeholder="우편번호" readonly required>
                                        </div>
                                        <button type="button" class="btn btn-admin-find-addr" id="btn-address">
                                            <i class="fa-solid fa-magnifying-glass me-1"></i> 우편번호 찾기
                                        </button>
                                        <button type="button" class="btn btn-outline-secondary btn-admin-close-addr d-none" id="btnCloseAddressWrap" style="display: none !important;" title="주소 검색창 닫기" aria-label="닫기">
                                            <i class="fa-solid fa-xmark"></i>
                                        </button>
                                    </div>
                                    <div id="wrap" class="zipcode-embed-box"></div>
                                    <div class="mb-2">
                                        <input type="text" class="form-control app-form-input bg-light @error('address1') is-invalid @enderror" id="address1" name="address1" value="{{ old('address1', $shop->address1) }}" placeholder="기본 주소" readonly data-required="true" data-label="기본 주소" />
                                        @error('address1')
                                        <div class="invalid-feedback">{{ $message }}</div>
                                        @enderror
                                    </div>
                                    <div class="mb-2">
                                        <x-admin.forms.input name="address2" id="address2" :value="old('address2', $shop->address2)" class="app-form-input" placeholder="상세 주소를 입력해주세요 (층수, 호수 등)" />
                                    </div>
                                    <input type="hidden" name="region_sido" id="region_sido" value="{{ old('region_sido', $shop->region_sido) }}">
                                    <input type="hidden" name="region_sigungu" id="region_sigungu" value="{{ old('region_sigungu', $shop->region_sigungu) }}">
                                    <input type="hidden" name="region_category" id="region_category" value="{{ old('region_category', $shop->region_category) }}">
                                    <input type="hidden" name="latitude" id="latitude" value="{{ old('latitude', $shop->latitude) }}">
                                    <input type="hidden" name="longitude" id="longitude" value="{{ old('longitude', $shop->longitude) }}">
                                    <input type="hidden" name="location_coords" id="location_coords" value="{{ old('location_coords', $shop->location_coords) }}">
                                </div>
                                <div class="col-12 col-md-6 mb-3">
                                    <x-admin.forms.input name="fax" label="팩스 번호 (FAX)" :value="old('fax', $shop->fax)" placeholder="02-000-0001" class="app-form-input" prepend='<i class="fa-solid fa-fax"></i>' />
                                </div>
                            </div>
                            <div class="section-save-btn-wrap d-flex justify-content-end mt-3 pt-3 border-top">
                                <button type="submit" form="shopForm" class="btn btn-admin-primary btn-app-section shadow-sm">
                                    <i class="fa-solid fa-check me-1"></i> 위치 정보 저장
                                </button>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 3. 매장 소개 및 홍보 채널 -->
                <div class="accordion-item app-form-card mb-3 mb-md-4">
                    <h2 class="accordion-header" id="headingIntro">
                        <button class="accordion-button collapsed py-3 px-3 px-md-4 fw-bold bg-white text-dark d-flex justify-content-between align-items-center shadow-none" 
                                type="button" data-bs-toggle="collapse" data-bs-target="#collapseIntro" aria-expanded="false" aria-controls="collapseIntro">
                            <div class="d-flex align-items-center gap-2">
                                <span class="badge px-2 py-1 bg-secondary text-white rounded-pill small badge-required">선택</span>
                                <span class="custom-accordion-title fw-bold text-dark">
                                    <i class="fa-solid fa-bullhorn me-2 text-success"></i> 매장 소개 및 홍보 채널
                                </span>
                            </div>
                        </button>
                    </h2>
                    <div id="collapseIntro" class="accordion-collapse collapse" aria-labelledby="headingIntro" data-bs-parent="#shopSettingsAccordion">
                        <div class="accordion-body app-card-body px-3 px-md-4 py-3 border-top">
                            <div class="row g-2">
                                <div class="col-12 mb-3">
                                    <x-admin.forms.input name="introduction" label="한 줄 소개 (요약)" :value="old('introduction', $shop->introduction)" class="app-form-input" placeholder="고객에게 노출될 매장의 핵심 매력을 한 줄로 작성해 주세요." />
                                </div>
                                <div class="col-12 mb-3">
                                    <label for="editor" class="form-label fw-bold mb-2 custom-form-label">매장 상세 소개글</label>
                                    <textarea name="description" id="editor" class="form-control" rows="6" placeholder="매장의 상세한 프로그램과 시설을 안내해 주세요.">{{ old('description', $shop->description) }}</textarea>
                                    @error('description')
                                    <div class="invalid-feedback d-block">{{ $message }}</div>
                                    @enderror
                                </div>
                                <div class="col-12 col-md-6 mb-3">
                                    <x-admin.forms.input type="url" name="naver_place_url" label="네이버 플레이스 URL" :value="old('naver_place_url', $shop->naver_place_url)" placeholder="https://m.place.naver.com/..." class="app-form-input" prepend='<i class="fa-solid fa-map-pin"></i>' />
                                </div>
                                <div class="col-12 col-md-6 mb-3">
                                    <x-admin.forms.input name="youtube_id" label="유튜브 영상 ID (홍보 영상 코드)" :value="old('youtube_id', $shop->youtube_id)" placeholder="예: dQw4w9WgXcQ" class="app-form-input" prepend='<i class="fa-brands fa-youtube text-danger"></i>' />
                                </div>
                                <div class="col-12 mb-3">
                                    <x-admin.forms.input name="tags" label="검색 태그" :value="old('tags', is_array($shop->tags) ? implode(', ', $shop->tags) : $shop->tags)" placeholder="예: 두피케어, 에너지테라피" class="tag-input-field app-form-input" helpText="쉼표(,)로 구분하여 입력하세요." prepend='<i class="fa-solid fa-tags"></i>' />
                                </div>
                            </div>
                            <div class="section-save-btn-wrap d-flex justify-content-end mt-3 pt-3 border-top">
                                <button type="submit" form="shopForm" class="btn btn-admin-primary btn-app-section shadow-sm">
                                    <i class="fa-solid fa-check me-1"></i> 소개 정보 저장
                                </button>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 4. 매장 브랜딩 및 갤러리 이미지 -->
                <div class="accordion-item app-form-card mb-3 mb-md-4">
                    <h2 class="accordion-header" id="headingVisualMedia">
                        <button class="accordion-button collapsed py-3 px-3 px-md-4 fw-bold bg-white text-dark d-flex justify-content-between align-items-center shadow-none" 
                                type="button" data-bs-toggle="collapse" data-bs-target="#collapseVisualMedia" aria-expanded="false" aria-controls="collapseVisualMedia">
                            <div class="d-flex align-items-center gap-2">
                                <span class="badge px-2 py-1 bg-secondary text-white rounded-pill small badge-required">선택</span>
                                <span class="custom-accordion-title fw-bold text-dark">
                                    <i class="fa-solid fa-photo-film me-2 text-info"></i> 매장 브랜딩 및 갤러리 이미지
                                </span>
                            </div>
                        </button>
                    </h2>
                    <div id="collapseVisualMedia" class="accordion-collapse collapse" aria-labelledby="headingVisualMedia" data-bs-parent="#shopSettingsAccordion">
                        <div class="accordion-body app-card-body px-3 px-md-4 py-3 border-top">
                            <!-- 4-1. 대표 브랜딩 이미지 (단일 슬롯 3종) -->
                            <div class="mb-4">
                                <div class="d-none d-md-flex justify-content-between align-items-center mb-3">
                                    <div>
                                        <h6 class="fw-bold mb-1 text-dark">
                                            <i class="fa-solid fa-id-badge me-2 text-primary icon-theme"></i> 매장 대표 브랜딩 이미지
                                        </h6>
                                        <span class="text-muted small">홈페이지, 모바일 웹, SNS 공유 시 노출되는 대표 비주얼을 등록하세요.</span>
                                    </div>
                                </div>
                                <div class="row g-2 align-items-stretch">
                                    <div class="col-12 col-sm-6 col-lg-4 mb-2">
                                        <x-shop_admin.image-single-slot name="logo" label="로고 이미지 (Logo - 1:1)" :model="$shop ?? null" width="60" height="60" ratioText="권장 규격: 1:1 정방형 (1200×1200)" />
                                    </div>
                                    <div class="col-12 col-sm-6 col-lg-4 mb-2">
                                        <x-shop_admin.image-single-slot name="banner" label="배너 이미지 (Banner - 3:1)" :model="$shop ?? null" width="120" height="40" ratioText="권장 규격: 3:1 와이드 (1200×400)" />
                                    </div>
                                    <div class="col-12 col-sm-6 col-lg-4 mb-2">
                                        <x-shop_admin.image-single-slot name="og_image" label="모바일 배너 (Og Image - 2:1)" :model="$shop ?? null" width="100" height="50" ratioText="권장 규격: 2:1 와이드 (1200×630)" />
                                    </div>
                                </div>
                            </div>

                            <!-- 4-2. 뷰티샵 마케팅 갤러리 이미지 (자립형 멀티 슬롯 컴포넌트 호출) -->
                            <div class="pt-3 border-top">
                                <x-shop_admin.image-multi-slot 
                                    name="marketing" 
                                    label="마케팅 갤러리 이미지" 
                                    :model="$shop ?? null" 
                                    :maxCount="$maxMarketingImages ?? 30" 
                                    buttonText="사진 추가" />
                            </div>

                            <div class="section-save-btn-wrap d-flex justify-content-end mt-3 pt-3 border-top">
                                <button type="submit" form="shopForm" class="btn btn-admin-primary btn-app-section shadow-sm">
                                    <i class="fa-solid fa-check me-1"></i> 이미지 정보 저장
                                </button>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 5. 정산 입금 계좌 정보 -->
                <div class="accordion-item app-form-card mb-4">
                    <h2 class="accordion-header" id="headingBank">
                        <button class="accordion-button collapsed py-3 px-3 px-md-4 fw-bold bg-white text-dark d-flex justify-content-between align-items-center shadow-none"
                                type="button" data-bs-toggle="collapse" data-bs-target="#collapseBank" aria-expanded="false" aria-controls="collapseBank">
                            <div class="d-flex align-items-center gap-2">
                                <span class="badge px-2 py-1 bg-secondary text-white rounded-pill small badge-required">선택</span>
                                <span class="custom-accordion-title fw-bold text-dark">
                                    <i class="fa-solid fa-calculator me-2 text-primary icon-theme"></i> 정산 입금 계좌
                                </span>
                            </div>
                            <span class="badge bg-light text-muted small fw-normal border d-none d-md-inline-block">시술 대금 정산 계좌</span>
                        </button>
                    </h2>
                    <div id="collapseBank" class="accordion-collapse collapse" aria-labelledby="headingBank" data-bs-parent="#shopSettingsAccordion">
                        <div class="accordion-body app-card-body px-3 px-md-4 py-3 border-top">
                            <div class="row g-2">
                                <div class="col-12 col-md-4 mb-3">
                                    @php
                                    $bankOptions = [
                                        'KB국민은행' => 'KB국민은행', '신한은행' => '신한은행', '우리은행' => '우리은행', '하나은행' => '하나은행',
                                        'NH농협은행' => 'NH농협은행', 'IBK기업은행' => 'IBK기업은행', '카카오뱅크' => '카카오뱅크', '토스뱅크' => '토스뱅크',
                                        '케이뱅크' => '케이뱅크', 'SC제일은행' => 'SC제일은행', '우체국' => '우체국', '새마을금고' => '새마을금고',
                                        '신협' => '신협', '수협은행' => '수협은행', '부산은행' => '부산은행', '대구은행' => '대구은행',
                                        '광주은행' => '광주은행', '경남은행' => '경남은행', '전북은행' => '전북은행', '제주은행' => '제주은행',
                                    ];
                                    @endphp
                                    @if(View::exists('components.admin.forms.select'))
                                    <x-admin.forms.select name="bank_name" label="은행명" :options="$bankOptions" :selected="old('bank_name', $shop->bank_name)" class="app-form-input" placeholder="은행을 선택해 주세요" />
                                    @else
                                    <label for="bank_name" class="form-label fw-bold mb-2 custom-form-label">은행명</label>
                                    <select name="bank_name" id="bank_name" class="form-select app-form-input">
                                        <option value="">은행을 선택해 주세요</option>
                                        @foreach($bankOptions as $val => $txt)
                                        <option value="{{ $val }}" @selected(old('bank_name', $shop->bank_name) === $val)>{{ $txt }}</option>
                                        @endforeach
                                    </select>
                                    @endif
                                </div>
                                <div class="col-12 col-md-4 mb-3">
                                    <x-admin.forms.input name="bank_account" id="bank_account" label="계좌번호" :value="old('bank_account', $shop->bank_account)" placeholder="예: 110123456789" helpText="(- 없이 숫자만 입력)" class="app-form-input" prepend='<i class="fa-solid fa-credit-card"></i>' maxlength="35" oninput="this.value = this.value.replace(/[^0-9]/g, '');" />
                                </div>
                                <div class="col-12 col-md-4 mb-3">
                                    <x-admin.forms.input name="bank_holder" id="bank_holder" label="예금주" :value="old('bank_holder', $shop->bank_holder)" placeholder="예금주 성명 또는 상호명" class="app-form-input" prepend='<i class="fa-solid fa-user-check"></i>' maxlength="50" />
                                </div>
                                <div class="col-12 mt-2">
                                    <div class="p-3 bg-light border rounded small text-dark d-flex align-items-center">
                                        <i class="fa-solid fa-circle-info text-primary me-2 icon-theme"></i>
                                        <span class="account-notice-text">정산 입금 계좌는 세무 증빙 및 원활한 대금 입금을 위해 등록된 사업자등록증 상의 <strong>상호명 또는 대표자명과 일치</strong>해야 합니다.</span>
                                    </div>
                                </div>
                            </div>
                            <div class="section-save-btn-wrap d-flex justify-content-end mt-3 pt-3 border-top">
                                <button type="submit" form="shopForm" class="btn btn-admin-primary btn-app-section shadow-sm">
                                    <i class="fa-solid fa-check me-1"></i> 계좌 정보 저장
                                </button>
                            </div>
                        </div>
                    </div>
                </div>

            </div>

            <!-- 하단 PC 전용 42px 최종 저장 버튼 -->
            <div class="d-none d-md-flex justify-content-end mb-4">
                <button type="submit" class="btn btn-admin-primary btn-app-md shadow-sm">
                    <i class="fa-solid fa-check me-2"></i> 기본 정보 저장
                </button>
            </div>
        </form>
    </div>

    @endsection

    @push('scripts')
    <!-- TinyMCE CDN & 한글팩 -->
    <script src="https://cdn.jsdelivr.net/npm/tinymce@6/tinymce.min.js" referrerpolicy="origin"></script>
    <script src="{{ asset('js/tinymce-ko.js') }}?v={{ time() }}"></script>
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            if (typeof initTinymce === 'function') {
                initTinymce('#editor', 350, '');
            }
        });
    </script>

    <!-- Daum 우편번호 서비스 CDN & 카카오 지도 Web API -->
    <script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
    <script src="//dapi.kakao.com/v2/maps/sdk.js?appkey={{ env('KAKAO_MAP_API_KEY') }}&libraries=services&autoload=false"></script>

    <!-- 공통 주소 검색 및 카카오 Geocoder LBS 자동 연동 스크립트 -->
    <script src="{{ asset('js/address_search.js') }}?v={{ time() }}"></script>
    <!-- 카테고리 선택 전용 스크립트 -->
    <script src="{{ asset('js/admin/category_picker.js') }}"></script>
    <!-- 뷰티샵관리자 매장 전용 비즈니스 스크립트 -->
    <script src="{{ asset('js/shop_admin/shop_admin_shop.js') }}?v={{ time() }}"></script>
    @endpush