/* ============================================================
   shared.jsx — icons, dummy data, BannerMock component
   ============================================================ */

/* ---------------- Icons (lucide-ish, stroke) ---------------- */
const ICON_PATHS = {
  layers: '<path d="M12 2 2 7l10 5 10-5-10-5Z"/><path d="m2 17 10 5 10-5"/><path d="m2 12 10 5 10-5"/>',
  wand: '<path d="m3 21 9-9"/><path d="M15 4V2"/><path d="M15 10V8"/><path d="M12.5 6.5h-2"/><path d="M19.5 6.5h-2"/><path d="m18 9-1.5-1.5"/><path d="M18 4 16.5 5.5"/><path d="m13.5 6.5 7 7a1.4 1.4 0 0 1 0 2l-1 1a1.4 1.4 0 0 1-2 0l-7-7"/>',
  library: '<rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/>',
  plus: '<path d="M12 5v14M5 12h14"/>',
  link: '<path d="M10 13a5 5 0 0 0 7.5.5l3-3a5 5 0 0 0-7-7l-1.8 1.7"/><path d="M14 11a5 5 0 0 0-7.5-.5l-3 3a5 5 0 0 0 7 7l1.7-1.7"/>',
  arrowRight: '<path d="M5 12h14M13 5l7 7-7 7"/>',
  arrowLeft: '<path d="M19 12H5M11 19l-7-7 7-7"/>',
  check: '<path d="M20 6 9 17l-5-5"/>',
  search: '<circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/>',
  image: '<rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.5-3.5a2 2 0 0 0-2.8 0L6 20"/>',
  type: '<path d="M4 7V5h16v2"/><path d="M9 19h6"/><path d="M12 5v14"/>',
  palette: '<circle cx="13.5" cy="6.5" r="1"/><circle cx="17.5" cy="10.5" r="1"/><circle cx="8.5" cy="7.5" r="1"/><circle cx="6.5" cy="12.5" r="1"/><path d="M12 2a10 10 0 0 0 0 20 2.5 2.5 0 0 0 2.5-2.5c0-.7-.3-1.3-.7-1.7-.4-.5-.7-1-.7-1.7A2.5 2.5 0 0 1 15.5 14H18a4 4 0 0 0 4-4 8 8 0 0 0-10-8Z"/>',
  ruler: '<path d="M21.3 8.7 8.7 21.3a1 1 0 0 1-1.4 0l-4.6-4.6a1 1 0 0 1 0-1.4L15.3 2.7a1 1 0 0 1 1.4 0l4.6 4.6a1 1 0 0 1 0 1.4Z"/><path d="m7.5 10.5 2 2"/><path d="m10.5 7.5 2 2"/><path d="m13.5 4.5 2 2"/><path d="m4.5 13.5 2 2"/>',
  layout: '<rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/><path d="M9 21V9"/>',
  sparkles: '<path d="m12 3-1.9 5.1L5 10l5.1 1.9L12 17l1.9-5.1L19 10l-5.1-1.9Z"/><path d="M19 15.5 18.2 18 16 18.8 18.2 19.5 19 22l.8-2.5L22 18.8 19.8 18Z"/>',
  download: '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M7 10l5 5 5-5"/><path d="M12 15V3"/>',
  x: '<path d="M18 6 6 18M6 6l12 12"/>',
  chevronRight: '<path d="m9 18 6-6-6-6"/>',
  chevronDown: '<path d="m6 9 6 6 6-6"/>',
  upload: '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M17 8l-5-5-5 5"/><path d="M12 3v12"/>',
  sliders: '<path d="M4 21v-7M4 10V3M12 21v-9M12 8V3M20 21v-5M20 12V3M1 14h6M9 8h6M17 16h6"/>',
  trash: '<path d="M3 6h18"/><path d="M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M10 11v6M14 11v6"/>',
  star: '<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2Z"/>',
  user: '<circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-6 8-6s8 2 8 6"/>',
  globe: '<circle cx="12" cy="12" r="9"/><path d="M3 12h18"/><path d="M12 3a14 14 0 0 1 0 18 14 14 0 0 1 0-18Z"/>',
  more: '<circle cx="5" cy="12" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="19" cy="12" r="1.5"/>',
  bell: '<path d="M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.7 21a2 2 0 0 1-3.4 0"/>',
  zap: '<path d="M13 2 3 14h9l-1 8 10-12h-9l1-8Z"/>',
  scan: '<path d="M3 7V5a2 2 0 0 1 2-2h2M17 3h2a2 2 0 0 1 2 2v2M21 17v2a2 2 0 0 1-2 2h-2M7 21H5a2 2 0 0 1-2-2v-2"/><path d="M7 12h10"/>',
  crop: '<path d="M6 2v14a2 2 0 0 0 2 2h14"/><path d="M18 22V8a2 2 0 0 0-2-2H2"/>',
  copy: '<rect x="9" y="9" width="12" height="12" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>',
  refresh: '<path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/><path d="M3 21v-5h5"/>',
  eye: '<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/>',
  dollar: '<path d="M12 1v22"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>',
  calendar: '<rect x="3" y="4" width="18" height="18" rx="2"/><path d="M16 2v4M8 2v4M3 10h18"/>',
  text: '<path d="M17 6.1H3M21 12.1H3M15.1 18H3"/>',
  cursor: '<path d="m4 4 7.07 17 2.51-7.39L21 11.07 4 4Z"/>',
  shadow: '<rect x="3" y="3" width="14" height="14" rx="2"/><path d="M21 8v11a2 2 0 0 1-2 2H8"/>',
  gradient: '<rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 12h18M12 3v18" opacity="0.3"/>',
  folder: '<path d="M4 20a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h5l2 3h7a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2Z"/>',
  images: '<rect x="8" y="3" width="13" height="13" rx="2"/><circle cx="12" cy="7.5" r="1.4"/><path d="m21 12-3-3a1.7 1.7 0 0 0-2.4 0L9 16"/><path d="M16 21H5a2 2 0 0 1-2-2V8"/>',
  grid: '<rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/>',
};

function S2Icon({ name, size = 18, className, style, strokeWidth = 1.7 }) {
  const d = ICON_PATHS[name] || '';
  return (
    <svg
      width={size} height={size} viewBox="0 0 24 24" fill="none"
      stroke="currentColor" strokeWidth={strokeWidth}
      strokeLinecap="round" strokeLinejoin="round"
      className={className} style={style}
      dangerouslySetInnerHTML={{ __html: d }}
    />
  );
}

/* ---------------- Dummy data ---------------- */

// Banners "collected" from the analyzed site (종합몰 — mixed categories)
const COLLECTED = [
  { id: 'b1', cat: '패션', kind: 'sale', bg: 'linear-gradient(110deg,#1f1147,#3b1d6e)', fg: '#fff', accent: '#ffd84d', head: '겨울 패션 위크', sub: '아우터 최대 70%', badge: '70%', cta: '지금 쇼핑', w: 1920, h: 600 },
  { id: 'b2', cat: '뷰티', kind: 'product', bg: 'linear-gradient(120deg,#ffe3ec,#ffd0e0)', fg: '#7a1f3d', accent: '#e5487f', head: '글로우 스킨케어', sub: '1+1 기획세트', badge: '1+1', cta: '구매하기', w: 750, h: 400 },
  { id: 'b3', cat: '식품', kind: 'fresh', bg: 'linear-gradient(120deg,#0f5132,#1a7a4c)', fg: '#fff', accent: '#ffe066', head: '산지직송 신선식품', sub: '새벽배송 무료', badge: 'NEW', cta: '담기', w: 640, h: 200 },
  { id: 'b4', cat: '가전', kind: 'tech', bg: 'linear-gradient(125deg,#0b1d33,#13345c)', fg: '#fff', accent: '#4cc9f0', head: '봄맞이 가전 페어', sub: '카드 5% 즉시할인', badge: '5%', cta: '혜택 보기', w: 1200, h: 400 },
  { id: 'b5', cat: '리빙', kind: 'sale', bg: 'linear-gradient(120deg,#3a2618,#6b4226)', fg: '#fff', accent: '#ffb347', head: '홈 인테리어 위크', sub: '러그·조명 특가', badge: 'SALE', cta: '구경하기', w: 750, h: 400 },
  { id: 'b6', cat: '패션', kind: 'product', bg: 'linear-gradient(120deg,#eef2ff,#dfe5ff)', fg: '#28306b', accent: '#4f46e5', head: '데일리 슈즈 컬렉션', sub: '신상품 입고', badge: 'NEW', cta: '보러가기', w: 300, h: 300 },
  { id: 'b7', cat: '식품', kind: 'product', bg: 'linear-gradient(120deg,#fff4e0,#ffe0b3)', fg: '#7a4a12', accent: '#f08c00', head: '베이커리 페스타', sub: '오늘만 단독가', badge: '단독', cta: '주문', w: 640, h: 200 },
  { id: 'b8', cat: '뷰티', kind: 'sale', bg: 'linear-gradient(120deg,#2b0a3d,#52146b)', fg: '#fff', accent: '#ff7eb6', head: '향수 브랜드 위크', sub: '전 품목 30%', badge: '30%', cta: '쇼핑하기', w: 1920, h: 600 },
];

// The generated Guide A spec
const GUIDE_A = {
  id: 'guide-a',
  name: '가이드 A',
  category: '패션',
  via: 'url',
  source: 'myshop.com',
  date: '2026.06.01',
  banners: 47,
  confidence: 92,
  sizes: [
    { name: '메인 히어로', w: 1920, h: 600, usage: 'PC 상단 메인', ratio: '3.2:1' },
    { name: '카테고리 배너', w: 750, h: 400, usage: '카테고리 상단', ratio: '1.88:1' },
    { name: '프로모션 띠', w: 1200, h: 200, usage: '기획전 상단', ratio: '6:1' },
    { name: '모바일 배너', w: 640, h: 200, usage: '모바일 리스트', ratio: '3.2:1' },
    { name: '상품 썸네일', w: 300, h: 300, usage: '상품 카드', ratio: '1:1' },
  ],
  palette: [
    { role: 'Primary', hex: '#3B1D6E', name: '딥 퍼플' },
    { role: 'Accent', hex: '#FFD84D', name: '옐로우' },
    { role: 'Sub', hex: '#E5487F', name: '핑크' },
    { role: 'Text', hex: '#1A1530', name: '잉크' },
    { role: 'Surface', hex: '#FFFFFF', name: '화이트' },
    { role: 'Muted', hex: '#9B8FC2', name: '라일락' },
  ],
  typo: [
    { role: '메인 카피', size: 64, weight: 800, lh: 1.1, ls: '-0.03em', sample: '겨울 패션 위크' },
    { role: '서브 카피', size: 28, weight: 600, lh: 1.3, ls: '-0.01em', sample: '아우터 최대 70% 할인' },
    { role: 'CTA', size: 20, weight: 700, lh: 1, ls: '0', sample: '지금 쇼핑하기' },
    { role: '캡션', size: 15, weight: 500, lh: 1.4, ls: '0', sample: '6.1 ~ 6.14 한정' },
  ],
  layout: [
    { label: '텍스트 정렬', value: '좌측 정렬', icon: 'text' },
    { label: '상품 이미지', value: '우측 배치', icon: 'image' },
    { label: '안전 여백', value: '48 px', icon: 'crop' },
    { label: 'CTA 위치', value: '좌하단', icon: 'cursor' },
    { label: '로고 위치', value: '좌상단', icon: 'layers' },
    { label: '그리드', value: '12 컬럼', icon: 'grid' },
  ],
  effects: [
    { name: '텍스트 그림자', desc: '0 2px 8px rgba(0,0,0,.35)', icon: 'shadow', css: '0 2px 8px rgba(0,0,0,.35)' },
    { name: '하단 그라데이션', desc: '상품 위 가독성 오버레이', icon: 'gradient', css: 'linear-gradient(0deg,rgba(0,0,0,.45),transparent 60%)' },
    { name: 'CTA 라운드', desc: 'radius 99px · 솔리드', icon: 'crop', css: '' },
    { name: '배지 강조', desc: '옐로우 솔리드 · 회전 -4°', icon: 'zap', css: '' },
  ],
  logo: { brand: '브랜드', advertiser: '콜라보 로고', position: '우측 상단', max: 2 },
  // ── 배너 타입 속성 (실제 가이드 기준) ──
  bannerType: '상품배너 H1',
  spec: { size: '776×388', w: 776, h: 388, bg: '#FFFFFF', file: 'JPG · web q100', flag: '좌상단 시스템 (모델 우측)', margin: '50px' },
  layoutTypes: ['누끼형', '분할+누끼형', '분할형(2·3분할)', '풀이미지형'],
  composition: { base: ['상품 이미지', '모델 이미지', '화보 이미지'], extra: ['이미지 표기', '컬러칩', '부가 텍스트', '부가 이미지'] },
  copyRule: ['이미지 내 문구 최대 10자', '혜택 1~2개 · 숫자로 구체화', '이미지 비중 60~70%'],
};

// Guide generated from uploaded deliverable images (방법 2)
const GUIDE_IMG = {
  ...GUIDE_A,
  id: 'guide-img',
  name: '가이드 B',
  via: 'image',
  source: '업로드 이미지 8장',
  date: '2026.06.02',
  banners: 8,
  confidence: 88,
};

// ── Guide B = 앱푸시 (다른 배너 타입 → 다른 속성) ──
const GUIDE_B = {
  ...GUIDE_A,
  id: 'guide-b',
  name: '가이드 B',
  category: '종합·혜택',
  via: 'url',
  source: 'myshop.com',
  date: '2026.06.02',
  banners: 31,
  confidence: 89,
  bannerType: '앱푸시',
  spec: { size: '720×380', w: 720, h: 380, bg: '화이트 금지', file: 'JPG · web q100', flag: '—', margin: '—' },
  layoutTypes: ['기본타입', '동시간 거래타입', '로고강조 타입', '지원타입', '쿠폰타입'],
  composition: { base: ['화보컷'], extra: ['누끼컷(지양)', '컬러칩', '부가 텍스트'] },
  copyRule: ['이미지 내 문구 최대 10자', '광고문구 이미지 중복 금지', '혜택 1~2개 · 숫자로 구체화'],
  palette: [
    { role: 'Chip 1', hex: '#F1F0DB', name: '라이트 옐로우' },
    { role: 'Chip 2', hex: '#F2E9DA', name: '크림' },
    { role: 'Chip 3', hex: '#F1DAE4', name: '라이트 핑크' },
    { role: 'Chip 4', hex: '#DEDAF3', name: '라이트 퍼플' },
    { role: 'Chip 5', hex: '#E0EBDA', name: '라이트 그린' },
    { role: 'Chip 6', hex: '#DCEBE8', name: '민트' },
    { role: 'Chip 7', hex: '#DAE3F4', name: '라이트 블루' },
    { role: 'Chip 8', hex: '#E3E3E3', name: '라이트 그레이' },
  ],
  typo: [
    { role: '제목', size: 32, weight: 700, lh: 1.2, ls: '-0.02em', sample: '맛있는家 첫 론칭기념' },
    { role: '광고 문구', size: 20, weight: 600, lh: 1.3, ls: '-0.01em', sample: 'TV LIVE 최대 17% 할인' },
    { role: '이미지 내 문구', size: 18, weight: 700, lh: 1.2, ls: '0', sample: '첫 론칭기념 이벤트' },
  ],
  logo: { brand: '브랜드', advertiser: '콜라보 로고', position: '좌·우 상단', max: 2 },
  channel: ['TV', 'TV+', 'LIVE'],
};

// ── Guide C = 상품배너 550 (또 다른 배너 타입) ──
const GUIDE_C = {
  ...GUIDE_A,
  id: 'guide-c',
  name: '가이드 C',
  category: '리빙·뷰티',
  via: 'url',
  source: 'myshop.com',
  date: '2026.06.02',
  banners: 26,
  confidence: 90,
  bannerType: '상품배너 550',
  spec: { size: '550×550', w: 550, h: 550, bg: '#FFFFFF', file: 'JPG · web q100', flag: '좌상단 시스템 (모델 우측)', margin: '50 / 40' },
  layoutTypes: ['누끼형', '분할+누끼형', '분할형', '풀이미지형'],
  composition: { base: ['상품 이미지', '모델 이미지', '화보 이미지'], extra: ['로고', '이미지 표기'] },
  copyRule: ['간결 카피', '혜택 1~2개 · 숫자로 구체화', '정사각 5:6 모듈 · 우측여백 50px'],
  palette: [
    { role: 'Primary', hex: '#0E7A5F', name: '딥 그린' },
    { role: 'Accent', hex: '#FF6B4A', name: '코랄' },
    { role: 'Sub', hex: '#FFC857', name: '머스타드' },
    { role: 'Text', hex: '#10231C', name: '포레스트 잉크' },
    { role: 'Surface', hex: '#FFFFFF', name: '화이트' },
    { role: 'Muted', hex: '#8FB8AC', name: '세이지' },
  ],
  typo: [
    { role: '메인 카피', size: 48, weight: 800, lh: 1.12, ls: '-0.03em', sample: '홈 스타일링 위크' },
    { role: '서브 카피', size: 22, weight: 600, lh: 1.3, ls: '-0.01em', sample: '러그·조명 최대 40%' },
    { role: 'CTA', size: 18, weight: 700, lh: 1, ls: '0', sample: '구경하기' },
  ],
  logo: { brand: '브랜드', advertiser: '콜라보 로고', position: '우측 상단', max: 2 },
};

// ── Guide 1E = 1E 기술서상단 (360×100) ──
const GUIDE_1E = {
  ...GUIDE_C,
  id: 'guide-1e',
  name: '가이드 1E',
  bannerType: '1E 기술서상단',
  spec: { size: '360×100', w: 360, h: 100, bg: '#FFFFFF', file: 'PNG · web', flag: '좌측 텍스트존 (누끼 우측)', margin: '좌 26' },
  layoutTypes: ['화보형', '누끼형'],
};

/* ---------------- BannerMock — CSS promotional banner ---------------- */
function BannerMock({ d, scale = 1, showProduct = true, style }) {
  // d: a COLLECTED-like object. Renders a faux promo banner sized by aspect.
  const wide = d.w / d.h;
  const pad = wide > 4 ? '0 7%' : '0 8%';
  return (
    <div style={{
      width: '100%', height: '100%', background: d.bg, color: d.fg,
      position: 'relative', overflow: 'hidden', display: 'flex',
      alignItems: 'center', padding: pad, ...style,
    }}>
      {/* product block */}
      {showProduct && (
        <div style={{
          position: 'absolute', right: wide > 4 ? '4%' : '7%', top: '50%',
          transform: 'translateY(-50%)',
          width: wide > 4 ? '18%' : (wide > 2 ? '30%' : '40%'),
          aspectRatio: '1', borderRadius: '50%',
          background: 'rgba(255,255,255,0.14)',
          border: '1px solid rgba(255,255,255,0.22)',
          boxShadow: 'inset 0 0 40px rgba(255,255,255,0.1)',
        }} />
      )}
      {/* badge */}
      <div style={{
        position: 'absolute', top: wide > 4 ? '50%' : '14%',
        left: wide > 4 ? 'auto' : '8%', right: wide > 4 ? '4%' : 'auto',
        transform: wide > 4 ? 'translateY(-50%) rotate(-4deg)' : 'rotate(-4deg)',
        background: d.accent, color: '#1a1530',
        fontWeight: 800, fontSize: `${Math.max(10, 13 * scale)}px`,
        padding: '3px 9px', borderRadius: '6px', letterSpacing: '-0.02em',
        boxShadow: '0 3px 10px rgba(0,0,0,0.2)',
      }}>{d.badge}</div>
      {/* text */}
      <div style={{ position: 'relative', zIndex: 2, maxWidth: '62%' }}>
        <div style={{
          fontWeight: 800, fontSize: `${Math.max(13, 30 * scale)}px`,
          lineHeight: 1.08, letterSpacing: '-0.03em',
          textShadow: '0 2px 8px rgba(0,0,0,0.3)', marginBottom: `${6 * scale}px`,
        }}>{d.head}</div>
        <div style={{
          fontWeight: 600, fontSize: `${Math.max(9, 15 * scale)}px`,
          opacity: 0.92, letterSpacing: '-0.01em', marginBottom: `${10 * scale}px`,
        }}>{d.sub}</div>
        <div style={{
          display: 'inline-flex', alignItems: 'center', gap: '5px',
          background: d.accent, color: '#1a1530',
          fontWeight: 700, fontSize: `${Math.max(8, 12 * scale)}px`,
          padding: `${5 * scale}px ${12 * scale}px`, borderRadius: '99px',
        }}>{d.cta} →</div>
      </div>
    </div>
  );
}

// ── 더미 라이브러리 시드 — 카테고리(배너 타입) × 가이드(레이아웃/유형) ──
// 앱푸시 카드 4종(기본형·방송기재·로고형·리딩콘텐츠형). 이전 5종은 아래 주석 참고(복원용).
// const _PUSH_TYPES = ['기본 타입', '방송시간 기재 타입', '로고강조+오늘혜택좋은브랜드 타입', '자유 타입', '쿠폰 타입'];
const _PUSH_TYPES = ['기본형', '방송기재', '로고형', '리딩콘텐츠형'];
// H1 카드 — 분할형(2·3·4분할)을 단일 '분할형' 카드로 통합(에디터는 여전히 2/3/4 후보 모두 생성 → 다양성 유지).
const _PROD_TYPES = ['A 누끼형', 'B 분할+누끼형', 'C 분할형', 'D 풀이미지형'];
// ── 어제 업로드한 실제 더미 배너 이미지 — 타입별 ──
const H1_IMG = Array.from({ length: 11 }, (_, i) => `assets/h1/h1-${String(i + 1).padStart(2, '0')}.jpg`);
const PUSH_IMG = ['assets/push/push-01.jpg', 'assets/push/push-02.jpg', 'assets/push/push-03.jpg', 'assets/push/push-04.jpg', 'assets/push/push-05.jpg', 'assets/push/push-06.png', 'assets/push/push-07.jpg'];
// 앱푸시 카드(배너 만들기) 전용 썸네일 — 유형순: 기본형·방송기재·로고형·리딩콘텐츠형. (PUSH_IMG 공유 풀과 분리)
const _PUSH_CARD_IMG = ['assets/push/card-basic.png', 'assets/push/card-airtime.png', 'assets/push/card-logo.png', 'assets/push/card-reading.png'];
const G550_IMG = Array.from({ length: 8 }, (_, i) => `assets/g550/g550-${String(i + 1).padStart(2, '0')}.jpg`);
const T1E_IMG = ['assets/1e-top/editorial-01.jpg', 'assets/1e-top/nukki-01.jpg']; // 1E: 화보형·누끼형 실제 샘플

// ── 가이드(카드) → 만들기 화면 유형/레이아웃 매핑 (스키마 id) ──
// 카드 선택 시 만들기 페이지 헤더 드롭다운이 이 값으로 초기화된다.
// 기본형·방송기재·로고형·리딩콘텐츠형 = 스키마(schema-push) 실제 유형 id 와 정확히 일치해야 편집기가 해당 유형으로 열림.
//   (과거 'logohit'/'reading' 은 스키마에 없어 무조건 기본형으로 폴백됐음 → 'logo'/'leading' 로 교정.)
// const _PUSH_TYPE_IDS = ['basic', 'airtime', 'logohit', 'free', 'coupon'];
const _PUSH_TYPE_IDS = ['basic', 'airtime', 'logo', 'leading'];
const _ONE_E_TYPE_IDS = ['editorial', 'A'];
const _PROD_VARIANTS = [
  { layoutId: 'nukki' },
  { layoutId: 'split-nukki' },
  { layoutId: 'split' },   // 통합 분할형 — 에디터가 2/3/4 후보 모두 생성
  { layoutId: 'full' },
];
// 상품배너 550 전용 카드 — 분할형(2·3·4분할)을 단일 '분할형' 카드로 통합(에디터는 여전히 2/3/4 후보를 모두 생성 → 다양성 유지).
const _PROD_TYPES_550 = ['A 누끼형', 'B 분할+누끼형', 'C 분할형', 'D 풀이미지형'];
const _PROD_VARIANTS_550 = [
  { layoutId: 'nukki' },
  { layoutId: 'split-nukki' },
  { layoutId: 'split' },
  { layoutId: 'full' },
];
// 카드 썸네일: 누끼·분할+누끼는 기존 이미지, 분할형·풀이미지는 사용자 지정 이미지.
const _G550_CARD_IMG = [G550_IMG[0], G550_IMG[1], 'assets/g550/card-split.png', 'assets/g550/card-full.png'];
// H1 카드 썸네일 — 누끼형=기존(h1-01) 유지 · 분할+누끼=마네킹+모델 · 분할형=4컷 모델 · 풀이미지=폴로 더미(사용자 지정).
const _H1_CARD_IMG = [H1_IMG[0], 'assets/h1/card-split-nukki.png', 'assets/h1/card-split.png', 'assets/h1/card-full.png'];

let _gid = 0;
// thumb = 실제 업로드 이미지(어제 적용한 17개). BannerMock CSS 프리뷰는 사용하지 않음.
const _g = (base, name, banners, conf, thumb, variant) => ({
  ...base, id: 'd-' + (++_gid), name, category: base.bannerType,
  layoutTypes: [name], thumb, banners, confidence: conf, ...(variant || {}),
});
const DUMMY_GUIDES = [
  // 1. 앱푸시 (4) — 기본형·방송기재·로고형·리딩콘텐츠형 (카드 전용 썸네일 _PUSH_CARD_IMG)
  ..._PUSH_TYPES.map((t, i) => _g(GUIDE_B, t, 12 - i, 90 - i, _PUSH_CARD_IMG[i], { pushType: _PUSH_TYPE_IDS[i] })),
  // 2. 상품배너 550 (5) — 분할형 통합 + 분할형/풀이미지 카드 이미지 지정 + 보험형(E)
  ..._PROD_TYPES_550.map((t, i) => _g(GUIDE_C, t, 16 - i, 91 - i, _G550_CARD_IMG[i], _PROD_VARIANTS_550[i])),
  _g(GUIDE_C, 'E 보험형', 12, 87, 'assets/g550/card-insurance.png', { layoutId: 'insurance' }), // 보험(E) — 이름 '보험'으로 편집기 E 진입(guideToTypeId)
  // 3. 상품배너 H1 (5) — 분할형 통합(4종) + 보험형(E). 카드 이미지 = _H1_CARD_IMG.
  ..._PROD_TYPES.map((t, i) => _g(GUIDE_A, t, 22 - i, 93 - i, _H1_CARD_IMG[i], _PROD_VARIANTS[i])),
  _g(GUIDE_A, 'E 보험형', 15, 87, 'assets/h1/card-insurance.png', { layoutId: 'insurance' }), // 보험(E) — 이름 '보험'으로 편집기 E 진입(guideToTypeId)
  // 4. 1E 기술서상단 (2) — 화보형·누끼형
  ...['화보형', '누끼형'].map((t, i) => _g(GUIDE_1E, t, 9 - i, 92 - i, T1E_IMG[i], { oneEType: _ONE_E_TYPE_IDS[i] })),
];

// ── H1 / 550 배너 유형 분류 (작업요청서 기준) ──
const BANNER_TYPES = [
  { id: 'A', name: '누끼형', subs: [
    { id: 'A1', label: '모델', model: true, product: false },
    { id: 'A2', label: '상품+모델', model: true, product: true },
    { id: 'A3', label: '상품', model: false, product: true },
  ] },
  { id: 'B', name: '분할+누끼형', subs: [
    { id: 'B1', label: '상품+화보', model: false, product: true },
  ] },
  { id: 'C', name: '분할형', subs: [
    { id: 'C1', label: '2분할' },
    { id: 'C2', label: '3분할' },
    { id: 'C3', label: '4분할' },
  ] },
  { id: 'D', name: '풀이미지형', subs: [
    { id: 'D1', label: '풀이미지' },
  ] },
  { id: 'E', name: '보험', note: '보험만 가능', subs: [
    { id: 'E1', label: '보험명' },
    { id: 'E2', label: '보험명+모델' },
  ] },
];

/* ---------------- TypeSelect — 유형 선택 드롭다운 (현재 유형 표시) ---------------- */
function TypeSelect({ value, options, onChange, placeholder }) {
  const [open, setOpen] = React.useState(false);
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [open]);
  const cur = options.find((o) => o.id === value) || options[0];
  return (
    <div className={`type-select${open ? ' open' : ''}`} ref={ref}>
      <button type="button" className="type-select-btn" onClick={() => setOpen((o) => !o)}>
        <span className="type-select-cur">{cur ? cur.label : (placeholder || '선택')}</span>
        <S2Icon name="chevronDown" size={16} style={{ color: 'var(--text-subtle)', flexShrink: 0, transition: 'transform .15s', transform: open ? 'rotate(180deg)' : 'none' }} />
      </button>
      {open &&
        <div className="type-select-menu">
          {options.map((o) =>
            <button key={o.id} type="button" className={`type-select-item${o.id === (cur && cur.id) ? ' on' : ''}`} onClick={() => { onChange(o.id); setOpen(false); }}>
              <span className="type-select-item-label">{o.label}{o.sub ? <span className="type-select-item-sub"> · {o.sub}</span> : null}</span>
              {o.id === (cur && cur.id) && <S2Icon name="check" size={15} strokeWidth={2.4} style={{ color: 'var(--accent)', flexShrink: 0 }} />}
            </button>)}
        </div>}
    </div>);
}

Object.assign(window, { S2Icon, TypeSelect, COLLECTED, GUIDE_A, GUIDE_B, GUIDE_C, GUIDE_IMG, DUMMY_GUIDES, BannerMock, H1_IMG, PUSH_IMG, G550_IMG, BANNER_TYPES });
