// HQ Admin 추가 화면 — 발행 상품 리스트, 매장 관리(엑셀), 네이버 지도, 게시판
const { useState: useStateHQ2, useEffect: useEffHQ2, useRef: useRefHQ2 } = React;

// ═══════════════════════════════════════════════════════════
// 06 — 발행 상품 리스트
// ═══════════════════════════════════════════════════════════
function HQPublishedList() {
  const [items, setItems] = useStateHQ2([]);
  const [loading, setLoading] = useStateHQ2(true);
  const [msg, setMsg] = useStateHQ2('');
  const [uploading, setUploading] = useStateHQ2(false);
  const [detailProduct, setDetailProduct] = useStateHQ2(null);
  const folderRef = useRefHQ2(null);

  const load = async () => {
    setLoading(true);
    try { const list = await getPublished(); setItems(list); }
    catch(e) { console.error(e); }
    setLoading(false);
  };
  useEffHQ2(() => { load(); }, []);

  const flash = (t) => { setMsg(t); setTimeout(() => setMsg(null), 3000); };

  const handleDelete = async (id) => {
    if (!confirm('이 상품을 삭제하시겠습니까?')) return;
    await deletePublished(id);
    flash('삭제 완료');
    load();
  };

  // 이미지 원본 읽기 (Firebase Storage에 원본 업로드)
  const readFileAsBase64 = (file) => new Promise((res) => {
    const reader = new FileReader();
    reader.onload = () => res(reader.result);
    reader.readAsDataURL(file);
  });

  // 팝업 상태
  const [uploadReport, setUploadReport] = React.useState(null); // { success: [], failed: [] }

  // 멀티폴더 큐 시스템
  const [folderQueue, setFolderQueue] = React.useState([]); // [{name, files:[File]}]
  const [batchUploading, setBatchUploading] = React.useState(false);
  const [batchProgress, setBatchProgress] = React.useState({ current: 0, total: 0, currentName: '' });
  const multiFolderRef = useRefHQ2(null);

  // 하위폴더 선택 피커
  const [subfolderPicker, setSubfolderPicker] = React.useState(null); // { entries: [{name,files,hasMedia}], checked: Set }

  // 폴더 선택 → 하위폴더 피커 표시
  const addFoldersToQueue = (e) => {
    const files = Array.from(e.target.files || []);
    if (!files.length) return;

    const imgExts = ['.jpg','.jpeg','.png','.gif','.webp'];
    const vidExts = ['.mp4','.mov','.webm','.avi'];

    // 파일을 하위폴더별로 그룹핑
    const folders = {};
    files.forEach(f => {
      const rel = f.webkitRelativePath || f.name;
      const parts = rel.split('/');
      let folderName;
      if (parts.length >= 3) folderName = parts[1];
      else if (parts.length === 2) folderName = parts[0];
      else return;
      if (!folders[folderName]) folders[folderName] = [];
      folders[folderName].push(f);
    });

    const newEntries = Object.entries(folders).map(([name, fileList]) => {
      const imgCount = fileList.filter(f => { const ext = '.' + f.name.split('.').pop().toLowerCase(); return imgExts.includes(ext); }).length;
      const vidCount = fileList.filter(f => { const ext = '.' + f.name.split('.').pop().toLowerCase(); return vidExts.includes(ext); }).length;
      const hasTxt = fileList.some(f => f.name.toLowerCase().endsWith('.txt'));
      const hasMedia = imgCount > 0 || vidCount > 0;
      return { name, files: fileList, hasMedia, imgCount, vidCount, hasTxt };
    }).filter(e => e.hasMedia);

    if (newEntries.length === 0) {
      flash('미디어 파일이 있는 폴더가 없습니다');
      if (multiFolderRef.current) multiFolderRef.current.value = '';
      return;
    }

    // 이미 큐에 있는 폴더 제외 표시
    const existingNames = new Set(folderQueue.map(q => q.name));
    const sorted = newEntries.sort((a, b) => a.name.localeCompare(b.name, 'ko'));
    // 기본: 큐에 없는 폴더만 선택
    const defaultChecked = new Set(sorted.filter(e => !existingNames.has(e.name)).map(e => e.name));
    setSubfolderPicker({ entries: sorted, checked: defaultChecked, existingNames });
    if (multiFolderRef.current) multiFolderRef.current.value = '';
  };

  // 피커에서 체크 토글
  const toggleSubfolder = (name) => {
    setSubfolderPicker(prev => {
      if (!prev) return prev;
      const next = new Set(prev.checked);
      if (next.has(name)) next.delete(name); else next.add(name);
      return { ...prev, checked: next };
    });
  };

  // 피커 전체 선택/해제
  const toggleAllSubfolders = (selectAll) => {
    setSubfolderPicker(prev => {
      if (!prev) return prev;
      const next = selectAll ? new Set(prev.entries.filter(e => !prev.existingNames.has(e.name)).map(e => e.name)) : new Set();
      return { ...prev, checked: next };
    });
  };

  // 피커에서 확인 → 큐에 추가
  const confirmSubfolderPick = () => {
    if (!subfolderPicker) return;
    const toAdd = subfolderPicker.entries.filter(e => subfolderPicker.checked.has(e.name));
    if (toAdd.length === 0) { flash('선택된 폴더가 없습니다'); setSubfolderPicker(null); return; }
    setFolderQueue(prev => [...prev, ...toAdd.filter(e => !prev.some(q => q.name === e.name))]);
    flash(toAdd.length + '개 폴더 추가됨');
    setSubfolderPicker(null);
  };

  // 큐에서 개별 폴더 제거
  const removeFromQueue = (name) => setFolderQueue(prev => prev.filter(q => q.name !== name));

  // 큐 전체 업로드 시작
  const startBatchUpload = async () => {
    if (folderQueue.length === 0) return;
    setBatchUploading(true);
    const success = [];
    const failed = [];
    const total = folderQueue.length;

    for (let idx = 0; idx < folderQueue.length; idx++) {
      const entry = folderQueue[idx];
      setBatchProgress({ current: idx + 1, total, currentName: entry.name });

      try {
        await processSingleFolder(entry.name, entry.files, success, failed);
      } catch (err) {
        console.error('폴더 처리 실패:', entry.name, err);
        failed.push({ name: entry.name, reason: err.message || '알 수 없는 오류' });
      }
    }

    setBatchUploading(false);
    setBatchProgress({ current: 0, total: 0, currentName: '' });
    setFolderQueue([]);
    setUploadReport({ success, failed, total });
    load();
  };

  // 단일 폴더 처리 (기존 로직 분리)
  const processSingleFolder = async (folderName, fileList, success, failed) => {
    const imgExts = ['.jpg','.jpeg','.png','.gif','.webp'];
    const vidExts = ['.mp4','.mov','.webm','.avi'];

    const images = [];
    const vids = [];
    let txtFile = null;

    fileList.forEach(f => {
      const name = f.name || (f.webkitRelativePath || '').split('/').pop();
      const ext = '.' + name.split('.').pop().toLowerCase();
      if (imgExts.includes(ext)) images.push(f);
      else if (vidExts.includes(ext)) vids.push(f);
      else if (ext === '.txt') txtFile = f;
    });

    if (images.length === 0 && vids.length === 0) {
      failed.push({ name: folderName, reason: '이미지/영상 파일이 없습니다' });
      return;
    }

    // 이미지 읽기 (최대 20장)
    images.sort((a, b) => a.name.localeCompare(b.name));
    const maxPhotos = Math.min(images.length, 20);
    const photoPromises = [];
    for (let i = 0; i < maxPhotos; i++) {
      photoPromises.push(readFileAsBase64(images[i]).catch(() => null));
    }
    const photos = (await Promise.all(photoPromises)).filter(Boolean);

    // 영상 읽기 (최대 2개)
    const videos = [];
    for (let i = 0; i < Math.min(vids.length, 2); i++) {
      try {
        const vidData = await new Promise((res, rej) => {
          const reader = new FileReader();
          reader.onload = (ev) => res(ev.target.result);
          reader.onerror = rej;
          reader.readAsDataURL(vids[i]);
        });
        videos.push(vidData);
      } catch (e) { /* skip */ }
    }

    if (photos.length === 0 && videos.length === 0) {
      failed.push({ name: folderName, reason: '파일을 읽을 수 없습니다' });
      return;
    }

    let title = folderName;
    let parsed = { brand: '', retail: 0, wholesale: 0, code: '', kr: title, name: title, sizes: '', colors_kr: '', description: '' };

    // txt 파일 파싱
    if (txtFile) {
      try {
        const txt = await txtFile.text();
        const lines = txt.split('\n').map(l => l.trim()).filter(Boolean);
        const descLines = [];
        lines.forEach(line => {
          const cleaned = line.replace(/^[☞✔•\-\*►▶→]+\s*/, '');
          const m = cleaned.match(/^(.+?)\s*[:：=]\s*(.+)$/);
          if (m) {
            const key = m[1].trim().replace(/\s+/g, '');
            const val = m[2].trim();
            if (/공급|도매|원가|매입|입고/i.test(key)) parsed.wholesale = parsePrice(val);
            else if (/판매|소매|정가|출고|소비자/i.test(key)) parsed.retail = parsePrice(val);
            else if (/사이즈|SIZE|규격/i.test(key)) parsed.sizes = val;
            else if (/색\s*상|COLOR|컬러/i.test(key)) parsed.colors_kr = val;
            else if (/브랜드|BRAND|제조/i.test(key)) parsed.brand = val;
            else if (/코드|CODE|SKU|품번|모델/i.test(key)) parsed.code = val;
            else if (/입수|MOQ|최소/i.test(key)) parsed.moq = val;
            else if (/카테고리|분류/i.test(key)) parsed.parts = val;
            else if (/상품\s*명|제품\s*명|NAME/i.test(key)) { title = val; parsed.kr = val; parsed.name = val; }
            else descLines.push(line);
          } else {
            const priceOnly = cleaned.match(/^[₩]?\s*[\d,.\s]+\s*원?\s*$/);
            if (!priceOnly) descLines.push(line);
          }
        });
        parsed.description = descLines.join('\n');
      } catch (e) { /* txt 읽기 실패 무시 */ }
    }

    const media = [];
    videos.forEach(v => media.push({ src: v, type: 'video' }));

    await publishProduct({ title, parsed, photos, videos, media, body: parsed.description || '', highlights: [] });

    const warnings = [];
    if (!parsed.retail && !parsed.wholesale) warnings.push('가격 정보 없음');
    if (!txtFile) warnings.push('txt 파일 없음');
    success.push({ name: folderName, photos: photos.length, videos: videos.length, warnings });
  };

  // 가격 문자열 → 숫자 파싱 (다양한 형식 지원)
  const parsePrice = (val) => {
    if (!val) return 0;
    if (typeof val === 'number') return val;
    // "9,600원", "₩9600", "9600", "9.600원", "9 600원" 등 처리
    const cleaned = String(val).replace(/[₩\\,\s원원]/g, '').replace(/\./g, '');
    const num = parseInt(cleaned, 10);
    return isNaN(num) ? 0 : num;
  };

  // 폴더에서 상품 일괄 업로드
  const handleFolderUpload = async (e) => {
    const files = Array.from(e.target.files || []);
    if (!files.length) return;
    setUploading(true);

    const imgExts = ['.jpg','.jpeg','.png','.gif','.webp'];
    const vidExts = ['.mp4','.mov','.webm','.avi'];

    // 파일을 하위폴더별로 그룹핑
    const folders = {};
    files.forEach(f => {
      const rel = f.webkitRelativePath || f.name;
      const parts = rel.split('/');
      let folderName, fileName;
      if (parts.length >= 3) {
        folderName = parts[1];
        fileName = parts.slice(2).join('/');
      } else if (parts.length === 2) {
        folderName = parts[0];
        fileName = parts[1];
      } else {
        return;
      }
      if (!folders[folderName]) folders[folderName] = { images: [], videos: [], txt: null };
      const ext = '.' + fileName.split('.').pop().toLowerCase();
      if (imgExts.includes(ext)) {
        folders[folderName].images.push(f);
      } else if (vidExts.includes(ext)) {
        folders[folderName].videos.push(f);
      } else if (ext === '.txt') {
        folders[folderName].txt = f;
      }
    });

    const folderNames = Object.keys(folders);
    if (folderNames.length === 0) {
      flash('하위 폴더가 없습니다. 상품 폴더가 있는 상위 폴더를 선택하세요.');
      setUploading(false);
      return;
    }

    const success = [];
    const failed = [];

    for (const folderName of folderNames) {
      const group = folders[folderName];

      // 이미지도 영상도 없으면 실패 기록
      if (group.images.length === 0 && group.videos.length === 0) {
        failed.push({ name: folderName, reason: '이미지/영상 파일이 없습니다 (jpg, png, mp4 등)' });
        continue;
      }

      try {
        // 이미지 정렬 & 원본 읽기 (최대 20장)
        group.images.sort((a, b) => a.name.localeCompare(b.name));
        const maxPhotos = Math.min(group.images.length, 20);
        const photoPromises = [];
        for (let i = 0; i < maxPhotos; i++) {
          photoPromises.push(
            readFileAsBase64(group.images[i]).catch(err => {
              console.warn('이미지 읽기 실패:', group.images[i].name, err);
              return null;
            })
          );
        }
        const photos = (await Promise.all(photoPromises)).filter(Boolean);

        // 영상은 base64로 (최대 2개, 용량 주의)
        const videos = [];
        const maxVids = Math.min(group.videos.length, 2);
        for (let i = 0; i < maxVids; i++) {
          try {
            const vidData = await new Promise((res, rej) => {
              const reader = new FileReader();
              reader.onload = (ev) => res(ev.target.result);
              reader.onerror = rej;
              reader.readAsDataURL(group.videos[i]);
            });
            videos.push(vidData);
          } catch (vidErr) {
            console.warn('영상 읽기 실패:', group.videos[i].name, vidErr);
          }
        }

        if (photos.length === 0 && videos.length === 0) {
          failed.push({ name: folderName, reason: '이미지/영상 파일을 읽을 수 없습니다' });
          continue;
        }

        // 상품명 = 폴더명
        let title = folderName;
        let parsed = {
          brand: '', retail: 0, wholesale: 0,
          code: '', kr: title, name: title, sizes: '', colors_kr: '',
          description: ''
        };

        // txt 파일 파싱
        if (group.txt) {
          try {
            const txt = await group.txt.text();
            const lines = txt.split('\n').map(l => l.trim()).filter(Boolean);
            const descLines = [];

            lines.forEach(line => {
              const cleaned = line.replace(/^[☞✔•\-\*►▶→]+\s*/, '');
              // "키 : 값" 또는 "키: 값" 패턴
              const m = cleaned.match(/^(.+?)\s*[:：=]\s*(.+)$/);
              if (m) {
                const key = m[1].trim().replace(/\s+/g, '');
                const val = m[2].trim();
                if (/공급|도매|원가|매입|입고/i.test(key)) parsed.wholesale = parsePrice(val);
                else if (/판매|소매|정가|출고|소비자/i.test(key)) parsed.retail = parsePrice(val);
                else if (/사이즈|SIZE|규격/i.test(key)) parsed.sizes = val;
                else if (/색\s*상|COLOR|컬러/i.test(key)) parsed.colors_kr = val;
                else if (/브랜드|BRAND|제조/i.test(key)) parsed.brand = val;
                else if (/코드|CODE|SKU|품번|모델/i.test(key)) parsed.code = val;
                else if (/입수|MOQ|최소/i.test(key)) parsed.moq = val;
                else if (/카테고리|분류/i.test(key)) parsed.parts = val;
                else if (/상품\s*명|제품\s*명|NAME/i.test(key)) { title = val; parsed.kr = val; parsed.name = val; }
                else descLines.push(line);
              } else {
                // "가격만 있는 라인" 감지: "9,600원" 같은 단독 가격
                const priceOnly = cleaned.match(/^[₩]?\s*[\d,.\s]+\s*원?\s*$/);
                if (!priceOnly) descLines.push(line);
              }
            });
            parsed.description = descLines.join('\n');
          } catch (txtErr) {
            console.warn('txt 파일 읽기 실패:', group.txt.name, txtErr);
          }
        } else {
          // txt 파일 없음 → 가격 정보 없이 등록 (경고는 하지만 등록은 진행)
        }

        // 미디어 배열 생성 (영상만 — 이미지는 photos에서 관리, 중복 업로드 방지)
        const media = [];
        videos.forEach(v => media.push({ src: v, type: 'video' }));

        await publishProduct({
          title,
          parsed,
          photos,
          videos,
          media,
          body: parsed.description || '',
          highlights: [],
        });

        const warnings = [];
        if (!parsed.retail && !parsed.wholesale) warnings.push('가격 정보 없음');
        if (!group.txt) warnings.push('txt 파일 없음');
        success.push({ name: folderName, photos: photos.length, videos: videos.length, warnings });

      } catch(err) {
        console.error('상품 업로드 실패:', folderName, err);
        failed.push({ name: folderName, reason: err.message || '알 수 없는 오류' });
      }
    }

    setUploading(false);
    if (folderRef.current) folderRef.current.value = '';

    // 결과 팝업 표시
    setUploadReport({ success, failed, total: folderNames.length });
    load();
  };

  // 상품 상세 — 이미지 라이트박스 상태
  const [lbOpen, setLbOpen] = useStateHQ2(false);
  const [lbIdx, setLbIdx] = useStateHQ2(0);
  const [mainIdx, setMainIdx] = useStateHQ2(0);
  const thumbRef = useRefHQ2(null);

  // 편집 모드
  const [editMode, setEditMode] = useStateHQ2(false);
  const [editData, setEditData] = useStateHQ2(null);
  const [saving, setSaving] = useStateHQ2(false);
  const editImgRef = useRefHQ2(null);

  // 수동 업로드 모드
  const [showManual, setShowManual] = useStateHQ2(false);
  const [manualData, setManualData] = useStateHQ2(null);
  const [manualSaving, setManualSaving] = useStateHQ2(false);
  const manualImgRef = useRefHQ2(null);

  // 검색 + 일괄 선택 + 일괄 카테고리 수정
  const [listSearch, setListSearch] = useStateHQ2('');
  const [selectedIds, setSelectedIds] = useStateHQ2({}); // { id: true }
  const [showBulkCat, setShowBulkCat] = useStateHQ2(false);
  const [bulkSaving, setBulkSaving] = useStateHQ2(false);
  const [showCatMgr, setShowCatMgr] = useStateHQ2(false);
  const [newCatInput, setNewCatInput] = useStateHQ2('');
  const [catVer, setCatVer] = useStateHQ2(0); // force re-render on category change
  const [showBrandMgr, setShowBrandMgr] = useStateHQ2(false);
  const [newBrandInput, setNewBrandInput] = useStateHQ2('');

  const filteredItems = React.useMemo(() => {
    if (!listSearch) return items;
    const q = listSearch.toLowerCase();
    return items.filter(p => {
      const pp = p.parsed || {};
      const t = (p.title || pp.kr || pp.name || '').toLowerCase();
      const b = (pp.brand || p.brand || '').toLowerCase();
      const c = (pp.code || p.code || '').toLowerCase();
      const rawCat = pp.category || p.category || '';
      const catStr = Array.isArray(rawCat) ? rawCat.join(' ').toLowerCase() : String(rawCat).toLowerCase();
      const season = (pp.season_tag || '').toLowerCase();
      return t.includes(q) || b.includes(q) || c.includes(q) || catStr.includes(q) || season.includes(q);
    });
  }, [items, listSearch]);

  const selectedCount = Object.values(selectedIds).filter(Boolean).length;
  const allSelected = filteredItems.length > 0 && filteredItems.every(p => selectedIds[p.id]);

  const toggleSelect = (id) => setSelectedIds(prev => ({ ...prev, [id]: !prev[id] }));
  const toggleSelectAll = () => {
    if (allSelected) {
      setSelectedIds({});
    } else {
      const next = {};
      filteredItems.forEach(p => { next[p.id] = true; });
      setSelectedIds(next);
    }
  };

  const handleBulkCategory = async (cat) => {
    const ids = Object.keys(selectedIds).filter(k => selectedIds[k]);
    if (ids.length === 0) return;
    setBulkSaving(true);
    try {
      for (const id of ids) {
        const p = items.find(x => x.id === id);
        if (!p) continue;
        const updated = { ...p, category: [cat], parsed: { ...(p.parsed || {}), category: [cat] } };
        await updatePublished(updated);
      }
      flash(ids.length + '개 상품 카테고리 → ' + cat);
      setSelectedIds({});
      setShowBulkCat(false);
      load();
    } catch (e) {
      alert('일괄 수정 실패: ' + e.message);
    }
    setBulkSaving(false);
  };

  // 카테고리 관리
  const handleAddCategory = async () => {
    const name = newCatInput.trim();
    if (!name) return;
    if (WU_DATA.categories.includes(name)) { alert('이미 존재하는 카테고리입니다'); return; }
    const custom = [...(WU_DATA._customCategories || []), name];
    await saveCustomCategories(custom);
    setNewCatInput('');
    setCatVer(v => v + 1);
    flash('카테고리 "' + name + '" 추가됨');
  };

  const handleRemoveCategory = async (name) => {
    if (WU_DATA._defaultCategories.includes(name)) { alert('기본 카테고리는 삭제할 수 없습니다'); return; }
    const custom = (WU_DATA._customCategories || []).filter(c => c !== name);
    await saveCustomCategories(custom);
    setCatVer(v => v + 1);
    flash('카테고리 "' + name + '" 삭제됨');
  };

  // 브랜드 관리
  const handleAddBrand = async () => {
    const name = newBrandInput.trim();
    if (!name) return;
    if (WU_DATA.brands.includes(name)) { alert('이미 존재하는 브랜드입니다'); return; }
    const custom = [...(WU_DATA._customBrands || []), name];
    await saveCustomBrands(custom);
    setNewBrandInput('');
    setCatVer(v => v + 1);
    flash('브랜드 "' + name + '" 추가됨');
  };

  const handleRemoveBrand = async (name) => {
    if (WU_DATA._defaultBrands.includes(name)) { alert('기본 브랜드는 삭제할 수 없습니다'); return; }
    const custom = (WU_DATA._customBrands || []).filter(b => b !== name);
    await saveCustomBrands(custom);
    setCatVer(v => v + 1);
    flash('브랜드 "' + name + '" 삭제됨');
  };

  // 편집 모드 진입
  const startEdit = (dp) => {
    const pp = dp.parsed || {};
    setEditData({
      title: dp.title || pp.kr || pp.name || '',
      brand: pp.brand || dp.brand || '',
      code: pp.code || dp.code || '',
      retail: String(pp.retail || dp.retail || ''),
      wholesale: String(pp.wholesale || dp.wholesale || ''),
      sizes: pp.sizes ? String(pp.sizes) : '',
      colors: pp.colors_kr ? String(pp.colors_kr) : '',
      moq: pp.moq ? String(pp.moq) : '',
      season: pp.season_tag || '',
      category: Array.isArray(pp.category || dp.category) ? (pp.category || dp.category) : (pp.category || dp.category) ? [pp.category || dp.category] : [],
      body: dp.body || dp.caption || '',
      photos: [...(dp.photos || [])],
      videos: [...(dp.videos || [])],
    });
    setEditMode(true);
  };

  // 이미지 파일 → base64 변환 (원본 유지, Storage에 업로드 후 URL로 교체됨)
  const fileToBase64 = (file) => new Promise((res) => {
    const reader = new FileReader();
    reader.onload = () => res(reader.result);
    reader.readAsDataURL(file);
  });

  // 편집 — 이미지 추가
  const handleEditAddImages = async (e) => {
    const files = Array.from(e.target.files || []);
    if (!files.length) return;
    const newPhotos = [];
    for (const f of files) {
      const b64 = await fileToBase64(f);
      newPhotos.push(b64);
    }
    setEditData(prev => ({ ...prev, photos: [...prev.photos, ...newPhotos].slice(0, 20) }));
    if (editImgRef.current) editImgRef.current.value = '';
  };

  // 편집 — 이미지 삭제
  const handleEditRemoveImage = (idx) => {
    setEditData(prev => ({ ...prev, photos: prev.photos.filter((_, i) => i !== idx) }));
  };

  // 편집 — 이미지 순서 이동
  const handleEditMoveImage = (idx, dir) => {
    setEditData(prev => {
      const arr = [...prev.photos];
      const newIdx = idx + dir;
      if (newIdx < 0 || newIdx >= arr.length) return prev;
      [arr[idx], arr[newIdx]] = [arr[newIdx], arr[idx]];
      return { ...prev, photos: arr };
    });
  };

  // 편집 저장
  const handleEditSave = async () => {
    if (!detailProduct || !editData) return;
    setSaving(true);
    try {
      const updated = { ...detailProduct };
      updated.title = editData.title;
      updated.brand = editData.brand;
      updated.category = editData.category || [];
      updated.brand = editData.brand;
      updated.body = editData.body;
      updated.photos = editData.photos;
      updated.videos = editData.videos;
      updated.parsed = {
        ...(updated.parsed || {}),
        brand: editData.brand,
        kr: editData.title,
        name: editData.title,
        code: editData.code,
        retail: parsePrice(editData.retail),
        wholesale: parsePrice(editData.wholesale),
        sizes: editData.sizes,
        colors_kr: editData.colors,
        moq: editData.moq,
        season_tag: editData.season,
        category: editData.category || [],
      };
      // media 배열도 갱신
      const media = [];
      if (editData.videos) editData.videos.forEach(v => media.push({ src: v, type: 'video' }));
      if (editData.photos) editData.photos.forEach(p => media.push({ src: p, type: 'image' }));
      updated.media = media;
      await updatePublished(updated);
      setDetailProduct(updated);
      setEditMode(false);
      flash('상품이 수정되었습니다');
      load();
    } catch (err) {
      alert('저장 실패: ' + err.message);
    }
    setSaving(false);
  };

  // 수동 업로드 초기화
  const initManual = () => {
    setManualData({
      title: '', brand: '', code: '',
      retail: '', wholesale: '',
      sizes: '', colors: '', moq: '', season: '',
      category: [], body: '', photos: [], videos: [],
    });
    setShowManual(true);
  };

  // 수동 — 이미지 추가
  const handleManualAddImages = async (e) => {
    const files = Array.from(e.target.files || []);
    if (!files.length) return;
    const newPhotos = [];
    for (const f of files) {
      const b64 = await fileToBase64(f);
      newPhotos.push(b64);
    }
    setManualData(prev => ({ ...prev, photos: [...prev.photos, ...newPhotos].slice(0, 20) }));
    if (manualImgRef.current) manualImgRef.current.value = '';
  };

  // 수동 — 저장
  const handleManualSave = async () => {
    if (!manualData || !manualData.title) { alert('상품명을 입력하세요'); return; }
    setManualSaving(true);
    try {
      const product = {
        title: manualData.title,
        brand: manualData.brand,
        category: manualData.category || [],
        body: manualData.body,
        photos: manualData.photos,
        videos: manualData.videos,
        tone: 'pro',
        parsed: {
          brand: manualData.brand,
          kr: manualData.title,
          name: manualData.title,
          code: manualData.code,
          retail: parsePrice(manualData.retail),
          wholesale: parsePrice(manualData.wholesale),
          sizes: manualData.sizes,
          colors_kr: manualData.colors,
          moq: manualData.moq,
          season_tag: manualData.season,
          category: manualData.category || [],
        },
        media: [
          ...manualData.videos.map(v => ({ src: v, type: 'video' })),
          ...manualData.photos.map(p => ({ src: p, type: 'image' })),
        ],
      };
      await publishProduct(product);
      setShowManual(false);
      setManualData(null);
      flash('상품이 등록되었습니다');
      load();
    } catch (err) {
      alert('등록 실패: ' + err.message);
    }
    setManualSaving(false);
  };

  // 키보드 핸들러 — hooks는 반드시 조건문 밖에서 호출해야 함
  const _dpMedia = React.useMemo(() => {
    if (!detailProduct) return [];
    const dp = detailProduct;
    if (dp.media && dp.media.length > 0) return dp.media;
    const arr = [];
    if (dp.videos) dp.videos.forEach(v => arr.push({ src: v, type: 'video' }));
    if (dp.photos) dp.photos.forEach(p => arr.push({ src: p, type: 'image' }));
    return arr.length > 0 ? arr : (dp.photos || []).map(p => ({ src: p, type: 'image' }));
  }, [detailProduct]);

  const lbKeyHandler = React.useCallback((e) => {
    if (!lbOpen) return;
    if (e.key === 'Escape') setLbOpen(false);
    if (e.key === 'ArrowLeft') setLbIdx(i => (i - 1 + _dpMedia.length) % _dpMedia.length);
    if (e.key === 'ArrowRight') setLbIdx(i => (i + 1) % _dpMedia.length);
  }, [lbOpen, _dpMedia.length]);
  React.useEffect(() => { window.addEventListener('keydown', lbKeyHandler); return () => window.removeEventListener('keydown', lbKeyHandler); }, [lbKeyHandler]);

  // 상품 상세 보기
  if (detailProduct) {
    const dp = detailProduct;
    const pp = dp.parsed || {};
    const dpMedia = _dpMedia;
    const _pn = (v) => typeof v === 'number' ? v : parseInt(String(v).replace(/[,\s원]/g, ''), 10) || 0;
    const dpRetail = _pn(pp.retail || dp.retail);
    const dpWholesale = _pn(pp.wholesale || dp.wholesale);
    const dpSizes = pp.sizes ? String(pp.sizes) : '';
    const dpColors = pp.colors_kr ? String(pp.colors_kr) : '';

    const openLightbox = (idx) => { setLbIdx(idx); setLbOpen(true); };
    const lbPrev = () => setLbIdx(i => (i - 1 + dpMedia.length) % dpMedia.length);
    const lbNext = () => setLbIdx(i => (i + 1) % dpMedia.length);
    const selectMain = (idx) => { setMainIdx(idx); };

    const arrowBtn = (dir, onClick) => (
      <button onClick={(e) => { e.stopPropagation(); onClick(); }} style={{ position: 'absolute', top: '50%', [dir === 'left' ? 'left' : 'right']: 12, transform: 'translateY(-50%)', width: 44, height: 44, borderRadius: 999, background: 'rgba(0,0,0,0.55)', color: '#fff', border: 'none', fontSize: 22, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', backdropFilter: 'blur(4px)', zIndex: 2 }}>
        {dir === 'left' ? '‹' : '›'}
      </button>
    );

    const renderMedia = (item, style, controls) => {
      if (item.type === 'video') return <video src={item.src} style={style} autoPlay muted loop playsInline controls={controls} />;
      return <img src={item.src} style={style} />;
    };

    return (
      <HQChrome active="published" title="상품 상세" subtitle="HQ · PRODUCT DETAIL">

        {/* ── 풀스크린 라이트박스 ── */}
        {lbOpen && dpMedia.length > 0 && (
          <div onClick={() => setLbOpen(false)} style={{ position: 'fixed', inset: 0, zIndex: 9999, background: 'rgba(0,0,0,0.92)', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center' }}>
            {/* 닫기 */}
            <button onClick={() => setLbOpen(false)} style={{ position: 'absolute', top: 16, right: 20, width: 40, height: 40, borderRadius: 999, background: 'rgba(255,255,255,0.12)', color: '#fff', border: 'none', fontSize: 24, cursor: 'pointer', zIndex: 3 }}>×</button>
            {/* 카운터 */}
            <div className="mono" style={{ position: 'absolute', top: 20, left: '50%', transform: 'translateX(-50%)', color: 'rgba(255,255,255,0.7)', fontSize: 13, zIndex: 3 }}>{lbIdx + 1} / {dpMedia.length}</div>

            {/* 메인 이미지/영상 */}
            <div onClick={e => e.stopPropagation()} style={{ position: 'relative', maxWidth: '88vw', maxHeight: '78vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
              {dpMedia.length > 1 && arrowBtn('left', lbPrev)}
              {dpMedia[lbIdx].type === 'video' ? (
                <video src={dpMedia[lbIdx].src} style={{ maxWidth: '88vw', maxHeight: '78vh', objectFit: 'contain' }} autoPlay muted loop playsInline controls />
              ) : (
                <img src={dpMedia[lbIdx].src} style={{ maxWidth: '88vw', maxHeight: '78vh', objectFit: 'contain' }} />
              )}
              {dpMedia.length > 1 && arrowBtn('right', lbNext)}
            </div>

            {/* 하단 썸네일 */}
            {dpMedia.length > 1 && (
              <div onClick={e => e.stopPropagation()} style={{ display: 'flex', gap: 6, marginTop: 16, overflowX: 'auto', maxWidth: '90vw', padding: '4px 8px' }}>
                {dpMedia.map((m, i) => (
                  <div key={i} onClick={() => setLbIdx(i)} style={{ width: 56, height: 56, flexShrink: 0, cursor: 'pointer', border: i === lbIdx ? '2px solid var(--wu-orange)' : '2px solid transparent', opacity: i === lbIdx ? 1 : 0.5, transition: 'all 0.15s', position: 'relative' }}>
                    {m.type === 'video' ? (
                      <React.Fragment>
                        <video src={m.src} style={{ width: '100%', height: '100%', objectFit: 'cover' }} muted />
                        <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'rgba(0,0,0,0.3)' }}><span style={{ fontSize: 18 }}>▶</span></div>
                      </React.Fragment>
                    ) : (
                      <img src={m.src} style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
                    )}
                  </div>
                ))}
              </div>
            )}
          </div>
        )}

        <div style={{ padding: 28, maxWidth: 960 }}>
          <div style={{ display: 'flex', gap: 8, marginBottom: 20 }}>
            <button onClick={() => { setDetailProduct(null); setMainIdx(0); setEditMode(false); }} style={{ padding: '8px 18px', fontSize: 12, fontWeight: 700, fontFamily: 'Pretendard', background: 'var(--wu-bg)', border: '1px solid var(--wu-line)', cursor: 'pointer', borderRadius: 4 }}>← 목록으로</button>
            {!editMode && <button onClick={() => startEdit(dp)} style={{ padding: '8px 18px', fontSize: 12, fontWeight: 700, fontFamily: 'Pretendard', background: 'var(--wu-orange)', color: '#fff', border: 'none', cursor: 'pointer', borderRadius: 4 }}>✏️ 수정</button>}
          </div>

          {/* ═══ 편집 모드 ═══ */}
          {editMode && editData ? (
            <div style={{ display: 'flex', gap: 32, flexWrap: 'wrap' }}>
              {/* 좌측 — 이미지 관리 */}
              <div style={{ flex: '0 0 400px', maxWidth: 400 }}>
                <div className="mono" style={{ fontSize: 10, color: 'var(--wu-orange)', fontWeight: 700, marginBottom: 8 }}>이미지 관리 (최대 20장) · 현재 {editData.photos.length}장</div>
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 6 }}>
                  {editData.photos.map((src, i) => (
                    <div key={i} style={{ position: 'relative', aspectRatio: '1/1', border: i === 0 ? '2px solid var(--wu-orange)' : '1px solid var(--wu-line)', overflow: 'hidden' }}>
                      <img src={src} style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
                      {i === 0 && <div className="mono" style={{ position: 'absolute', top: 0, left: 0, padding: '1px 6px', background: 'var(--wu-orange)', color: '#fff', fontSize: 8, fontWeight: 700 }}>대표</div>}
                      <div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, display: 'flex', background: 'rgba(0,0,0,0.6)' }}>
                        <button onClick={() => handleEditMoveImage(i, -1)} disabled={i === 0} style={{ flex: 1, border: 'none', background: 'none', color: '#fff', fontSize: 12, cursor: 'pointer', padding: '3px 0', opacity: i === 0 ? 0.3 : 1 }}>◀</button>
                        <button onClick={() => handleEditRemoveImage(i)} style={{ flex: 1, border: 'none', background: 'none', color: '#f44', fontSize: 12, cursor: 'pointer', padding: '3px 0' }}>✕</button>
                        <button onClick={() => handleEditMoveImage(i, 1)} disabled={i === editData.photos.length - 1} style={{ flex: 1, border: 'none', background: 'none', color: '#fff', fontSize: 12, cursor: 'pointer', padding: '3px 0', opacity: i === editData.photos.length - 1 ? 0.3 : 1 }}>▶</button>
                      </div>
                    </div>
                  ))}
                  {/* 추가 버튼 */}
                  {editData.photos.length < 20 && (
                    <label style={{ aspectRatio: '1/1', border: '2px dashed var(--wu-line)', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', background: 'var(--wu-bg)' }}>
                      <span style={{ fontSize: 24, color: 'var(--wu-mute)' }}>+</span>
                      <span className="mono" style={{ fontSize: 8, color: 'var(--wu-mute)' }}>추가</span>
                      <input ref={editImgRef} type="file" accept="image/*" multiple onChange={handleEditAddImages} style={{ display: 'none' }} />
                    </label>
                  )}
                </div>
              </div>

              {/* 우측 — 정보 편집 폼 */}
              <div style={{ flex: 1, minWidth: 280 }}>
                {[
                  ['상품명', 'title', '상품명을 입력하세요'],
                  ['상품코드', 'code', 'SKU / 품번'],
                  ['판매가', 'retail', '예: 14800'],
                  ['공급가', 'wholesale', '예: 9600'],
                  ['사이즈', 'sizes', '예: XS ~ 3XL 또는 S, M, L'],
                  ['색상', 'colors', '예: 네이비, 민트'],
                  ['입수량', 'moq', '예: 5장'],
                  ['시즌', 'season', '예: 25SS, 24FW'],
                ].map(([label, key, ph]) => (
                  <div key={key} style={{ marginBottom: 12 }}>
                    <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 4, fontWeight: 600 }}>{label}</div>
                    <input value={editData[key]} onChange={e => setEditData(prev => ({ ...prev, [key]: e.target.value }))} placeholder={ph} className="kr" style={{ width: '100%', padding: '10px 14px', border: '1.5px solid var(--wu-line)', fontSize: 14, fontWeight: 600, background: 'var(--wu-paper)', outline: 'none', borderRadius: 4, boxSizing: 'border-box' }} />
                  </div>
                ))}
                {/* 카테고리 선택 (다중) */}
                <div style={{ marginBottom: 12 }}>
                  <div style={{ display: 'flex', gap: 8, alignItems: 'center', marginBottom: 6 }}>
                    <div className="mono" style={{ fontSize: 10, color: 'var(--wu-orange)', fontWeight: 700 }}>카테고리 (복수 선택 가능)</div>
                    <button onClick={() => {
                      const tempProduct = { ...detailProduct, parsed: { ...(detailProduct.parsed || {}), category: [] } };
                      const aiCats = aiAutoCategory(tempProduct);
                      if (aiCats.length > 0) { setEditData(prev => ({ ...prev, category: aiCats })); flash('AI 추천: ' + aiCats.join(', ')); }
                      else { flash('AI 분류 실패 — 직접 선택하세요'); }
                    }} className="mono" style={{ padding: '3px 10px', fontSize: 9, fontWeight: 700, background: '#7C3AED', color: '#fff', border: 'none', cursor: 'pointer', borderRadius: 4 }}>🤖 AI 추천</button>
                  </div>
                  <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                    {(WU_DATA.categories || []).filter(c => c !== '전체' && c !== '신상').map(cat => {
                      const sel = Array.isArray(editData.category) && editData.category.includes(cat);
                      return <button key={cat} onClick={() => setEditData(prev => {
                        const arr = Array.isArray(prev.category) ? [...prev.category] : [];
                        return { ...prev, category: sel ? arr.filter(c => c !== cat) : [...arr, cat] };
                      })} className="kr" style={{ padding: '6px 12px', fontSize: 11, fontWeight: 600, background: sel ? 'var(--wu-ink)' : 'var(--wu-bg)', color: sel ? 'var(--wu-lime)' : 'var(--wu-ink)', border: '1px solid var(--wu-line)', cursor: 'pointer', borderRadius: 4 }}>{cat}</button>;
                    })}
                  </div>
                </div>
                {/* 브랜드 선택 */}
                <div style={{ marginBottom: 12 }}>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--wu-orange)', marginBottom: 6, fontWeight: 700 }}>브랜드</div>
                  <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                    {(WU_DATA.brands || []).map(b => (
                      <button key={b} onClick={() => setEditData(prev => ({ ...prev, brand: prev.brand === b ? '' : b }))} className="mono" style={{ padding: '6px 12px', fontSize: 10, fontWeight: 700, background: editData.brand === b ? 'var(--wu-ink)' : 'var(--wu-bg)', color: editData.brand === b ? 'var(--wu-lime)' : 'var(--wu-ink)', border: '1px solid var(--wu-line)', cursor: 'pointer', borderRadius: 4 }}>{b}</button>
                    ))}
                  </div>
                </div>
                <div style={{ marginBottom: 12 }}>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 4, fontWeight: 600 }}>상품 설명</div>
                  <textarea value={editData.body} onChange={e => setEditData(prev => ({ ...prev, body: e.target.value }))} placeholder="상품에 대한 상세 설명" className="kr" rows={5} style={{ width: '100%', padding: '10px 14px', border: '1.5px solid var(--wu-line)', fontSize: 14, lineHeight: 1.7, background: 'var(--wu-paper)', outline: 'none', resize: 'vertical', borderRadius: 4, boxSizing: 'border-box' }} />
                </div>
                <div style={{ display: 'flex', gap: 8, marginTop: 16 }}>
                  <button onClick={handleEditSave} disabled={saving} style={{ flex: 1, padding: '14px', fontSize: 14, fontWeight: 700, fontFamily: 'Pretendard', background: 'var(--wu-orange)', color: '#fff', border: 'none', cursor: 'pointer', borderRadius: 4 }}>{saving ? '저장 중...' : '저장'}</button>
                  <button onClick={() => setEditMode(false)} style={{ padding: '14px 24px', fontSize: 14, fontWeight: 700, fontFamily: 'Pretendard', background: 'var(--wu-bg)', border: '1px solid var(--wu-line)', cursor: 'pointer', borderRadius: 4 }}>취소</button>
                </div>
              </div>
            </div>
          ) : (
          /* ═══ 보기 모드 (기존) ═══ */
          <div style={{ display: 'flex', gap: 32, flexWrap: 'wrap' }}>
            {/* 좌측 — 이미지 갤러리 */}
            <div style={{ flex: '0 0 400px', maxWidth: 400 }}>
              {dpMedia.length > 0 ? (
                <div style={{ position: 'relative', cursor: 'pointer' }} onClick={() => openLightbox(mainIdx)}>
                  {dpMedia[mainIdx].type === 'video' ? (
                    <video src={dpMedia[mainIdx].src} style={{ width: '100%', aspectRatio: '4/5', objectFit: 'cover', background: '#1a1a18', display: 'block' }} autoPlay muted loop playsInline />
                  ) : (
                    <img src={dpMedia[mainIdx].src} style={{ width: '100%', aspectRatio: '4/5', objectFit: 'cover', background: '#E9E5DC', display: 'block' }} />
                  )}
                  <div style={{ position: 'absolute', bottom: 12, right: 12, width: 36, height: 36, borderRadius: 999, background: 'rgba(0,0,0,0.5)', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 18, backdropFilter: 'blur(4px)' }}>⛶</div>
                  {dpMedia.length > 1 && (
                    <React.Fragment>
                      <button onClick={(e) => { e.stopPropagation(); setMainIdx(i => (i - 1 + dpMedia.length) % dpMedia.length); }} style={{ position: 'absolute', top: '50%', left: 8, transform: 'translateY(-50%)', width: 34, height: 34, borderRadius: 999, background: 'rgba(0,0,0,0.4)', color: '#fff', border: 'none', fontSize: 18, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>‹</button>
                      <button onClick={(e) => { e.stopPropagation(); setMainIdx(i => (i + 1) % dpMedia.length); }} style={{ position: 'absolute', top: '50%', right: 8, transform: 'translateY(-50%)', width: 34, height: 34, borderRadius: 999, background: 'rgba(0,0,0,0.4)', color: '#fff', border: 'none', fontSize: 18, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>›</button>
                    </React.Fragment>
                  )}
                  {dpMedia[mainIdx].type === 'video' && (
                    <div className="mono" style={{ position: 'absolute', top: 10, left: 10, padding: '3px 8px', background: 'var(--wu-orange)', color: '#fff', fontSize: 9, fontWeight: 700, borderRadius: 3 }}>VIDEO</div>
                  )}
                </div>
              ) : (
                <div style={{ width: '100%', aspectRatio: '4/5', background: '#E9E5DC', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><span className="mono" style={{ color: 'var(--wu-mute)', fontSize: 14 }}>NO IMAGE</span></div>
              )}
              {dpMedia.length > 1 && (
                <div ref={thumbRef} style={{ display: 'flex', gap: 6, marginTop: 10, overflowX: 'auto', paddingBottom: 4 }}>
                  {dpMedia.map((m, i) => (
                    <div key={i} onClick={() => selectMain(i)} style={{ width: 68, height: 68, flexShrink: 0, cursor: 'pointer', border: i === mainIdx ? '2px solid var(--wu-orange)' : '2px solid transparent', transition: 'border-color 0.15s', position: 'relative' }}>
                      {m.type === 'video' ? (
                        <React.Fragment>
                          <video src={m.src} style={{ width: '100%', height: '100%', objectFit: 'cover' }} muted />
                          <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'rgba(0,0,0,0.3)' }}><span style={{ color: '#fff', fontSize: 20 }}>▶</span></div>
                        </React.Fragment>
                      ) : (
                        <img src={m.src} style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
                      )}
                    </div>
                  ))}
                </div>
              )}
              <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginTop: 8, textAlign: 'center' }}>클릭하면 크게 볼 수 있습니다</div>
            </div>

            {/* 우측 — 상품 정보 */}
            <div style={{ flex: 1, minWidth: 280 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                {(pp.brand || dp.brand) && <span className="mono" style={{ fontSize: 11, padding: '4px 10px', background: 'var(--wu-ink)', color: 'var(--wu-orange)', fontWeight: 700, letterSpacing: 0.5 }}>{pp.brand || dp.brand}</span>}
                {(() => { const rc = pp.category || dp.category || ''; const ca = Array.isArray(rc) ? rc : rc ? [rc] : []; return ca.map(c => <span key={c} className="mono" style={{ fontSize: 10, padding: '3px 8px', background: 'var(--wu-orange)', color: '#fff', fontWeight: 700, borderRadius: 3 }}>{c}</span>); })()}
                {(pp.code || dp.code) && <span className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)' }}>{pp.code || dp.code}</span>}
              </div>
              <div className="kr" style={{ fontSize: 24, fontWeight: 800, marginTop: 12, lineHeight: 1.35 }}>{dp.title || pp.kr || pp.name || dp.kr || '상품'}</div>
              <div style={{ marginTop: 20, padding: 20, background: 'var(--wu-ink)', color: 'var(--wu-paper)', borderRadius: 4 }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--wu-orange)', fontWeight: 700, letterSpacing: 1 }}>판매가 · RETAIL</div>
                  <div className="display" style={{ fontSize: 26 }}>₩{dpRetail.toLocaleString()}</div>
                </div>
                {dpWholesale > 0 && (
                  <React.Fragment>
                    <div style={{ height: 1, background: '#2A2A26', margin: '12px 0' }} />
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                      <div className="mono" style={{ fontSize: 10, color: 'var(--wu-lime)', fontWeight: 700, letterSpacing: 1 }}>공급가 · WHOLESALE</div>
                      <div className="display" style={{ fontSize: 26, color: 'var(--wu-lime)' }}>₩{dpWholesale.toLocaleString()}</div>
                    </div>
                  </React.Fragment>
                )}
                {dpWholesale > 0 && dpRetail > 0 && (
                  <div style={{ marginTop: 14, paddingTop: 12, borderTop: '1px dashed #3A3A36', display: 'flex', justifyContent: 'space-between' }}>
                    <span className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)' }}>마진율</span>
                    <span className="mono" style={{ fontSize: 13, color: 'var(--wu-orange)', fontWeight: 700 }}>{Math.round(((dpRetail - dpWholesale) / dpRetail) * 100)}% · ₩{(dpRetail - dpWholesale).toLocaleString()}</span>
                  </div>
                )}
              </div>
              {(dpSizes || dpColors || pp.moq) && (
                <div style={{ marginTop: 16, padding: 16, background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', borderRadius: 4 }}>
                  <table style={{ width: '100%', borderCollapse: 'collapse' }}><tbody>
                    {dpSizes && <tr><td className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)', padding: '6px 0', width: 70 }}>사이즈</td><td className="kr" style={{ fontSize: 14, fontWeight: 600, padding: '6px 0' }}>{dpSizes}</td></tr>}
                    {dpColors && <tr><td className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)', padding: '6px 0', width: 70 }}>색상</td><td className="kr" style={{ fontSize: 14, fontWeight: 600, padding: '6px 0' }}>{dpColors}</td></tr>}
                    {pp.moq && <tr><td className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)', padding: '6px 0', width: 70 }}>입수량</td><td className="kr" style={{ fontSize: 14, fontWeight: 600, padding: '6px 0' }}>{pp.moq}</td></tr>}
                  </tbody></table>
                </div>
              )}
              {dp.body && (
                <div style={{ marginTop: 16, padding: 18, background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', borderRadius: 4 }}>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--wu-orange)', fontWeight: 700, marginBottom: 10, letterSpacing: 1 }}>상품 설명</div>
                  <div className="kr" style={{ fontSize: 14, lineHeight: 1.8, whiteSpace: 'pre-wrap', color: 'var(--wu-ink)' }}>{dp.body}</div>
                </div>
              )}
              <div style={{ marginTop: 16, padding: 14, background: 'var(--wu-bg)', borderRadius: 4, display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 8 }}>
                <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)' }}>발행일: {new Date(dp.publishedAt).toLocaleString('ko-KR')}{dp.updatedAt ? ' · 수정: ' + new Date(dp.updatedAt).toLocaleString('ko-KR') : ''}</div>
                <div style={{ display: 'flex', gap: 6 }}>
                  {dpMedia.filter(m => m.type === 'image').length > 0 && <span className="mono" style={{ fontSize: 10, padding: '3px 8px', background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', fontWeight: 600 }}>사진 {dpMedia.filter(m => m.type === 'image').length}장</span>}
                  {dpMedia.filter(m => m.type === 'video').length > 0 && <span className="mono" style={{ fontSize: 10, padding: '3px 8px', background: 'var(--wu-orange)', color: '#fff', fontWeight: 700 }}>영상 {dpMedia.filter(m => m.type === 'video').length}개</span>}
                </div>
              </div>
            </div>
          </div>
          )}
        </div>
      </HQChrome>
    );
  }

  return (
    <HQChrome active="published" title="발행 상품 관리" subtitle="HQ · PUBLISHED PRODUCTS">
      {msg && <div style={{ position: 'fixed', top: 16, right: 16, zIndex: 999, padding: '10px 18px', background: 'var(--wu-orange)', color: '#fff', fontFamily: 'Pretendard', fontSize: 13, fontWeight: 700, boxShadow: '0 8px 24px rgba(0,0,0,0.2)' }}>{msg}</div>}

      {/* 업로드 결과 팝업 */}
      {uploadReport && (
        <div style={{ position: 'fixed', inset: 0, zIndex: 1000, background: 'rgba(0,0,0,0.6)', display: 'flex', alignItems: 'center', justifyContent: 'center' }} onClick={() => setUploadReport(null)}>
          <div onClick={e => e.stopPropagation()} style={{ width: 520, maxHeight: '80vh', background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', boxShadow: '0 20px 60px rgba(0,0,0,0.3)', overflow: 'auto' }}>
            <div style={{ padding: '20px 24px', background: 'var(--wu-ink)', color: 'var(--wu-paper)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
              <div>
                <div className="display" style={{ fontSize: 18 }}>업로드 결과</div>
                <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginTop: 4 }}>전체 {uploadReport.total}개 폴더 · 성공 {uploadReport.success.length} · 실패 {uploadReport.failed.length}</div>
              </div>
              <button onClick={() => setUploadReport(null)} style={{ width: 32, height: 32, borderRadius: 999, background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', cursor: 'pointer', fontSize: 16 }}>×</button>
            </div>

            {uploadReport.success.length > 0 && (
              <div style={{ padding: '16px 24px', borderBottom: '1px solid var(--wu-line)' }}>
                <div className="mono" style={{ fontSize: 10, color: 'var(--wu-lime)', fontWeight: 700, marginBottom: 8, display: 'flex', alignItems: 'center', gap: 6 }}>
                  <span style={{ width: 8, height: 8, borderRadius: 999, background: 'var(--wu-lime)', display: 'inline-block' }} /> 등록 성공 ({uploadReport.success.length}건)
                </div>
                {uploadReport.success.map((s, i) => (
                  <div key={i} style={{ padding: '8px 12px', background: i % 2 === 0 ? 'var(--wu-bg)' : 'transparent', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                    <div>
                      <div className="kr" style={{ fontSize: 13, fontWeight: 600 }}>{s.name}</div>
                      <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginTop: 2 }}>사진 {s.photos}장{s.videos > 0 ? ' · 영상 ' + s.videos + '개' : ''}</div>
                    </div>
                    {s.warnings && s.warnings.length > 0 && (
                      <div>
                        {s.warnings.map((w, wi) => (
                          <span key={wi} className="mono" style={{ fontSize: 9, padding: '2px 6px', background: '#FFF3CD', color: '#856404', fontWeight: 700, marginLeft: 4 }}>⚠ {w}</span>
                        ))}
                      </div>
                    )}
                  </div>
                ))}
              </div>
            )}

            {uploadReport.failed.length > 0 && (
              <div style={{ padding: '16px 24px', borderBottom: '1px solid var(--wu-line)' }}>
                <div className="mono" style={{ fontSize: 10, color: '#C44', fontWeight: 700, marginBottom: 8, display: 'flex', alignItems: 'center', gap: 6 }}>
                  <span style={{ width: 8, height: 8, borderRadius: 999, background: '#C44', display: 'inline-block' }} /> 등록 실패 ({uploadReport.failed.length}건)
                </div>
                {uploadReport.failed.map((f, i) => (
                  <div key={i} style={{ padding: '10px 12px', background: '#FFF5F5', borderLeft: '3px solid #C44', marginBottom: 6 }}>
                    <div className="kr" style={{ fontSize: 13, fontWeight: 700, color: '#C44' }}>{f.name}</div>
                    <div className="kr" style={{ fontSize: 12, color: '#666', marginTop: 4 }}>사유: {f.reason}</div>
                  </div>
                ))}
              </div>
            )}

            <div style={{ padding: '16px 24px', textAlign: 'right' }}>
              <button onClick={() => setUploadReport(null)} className="wu-btn" style={{ padding: '10px 24px', fontSize: 13, background: 'var(--wu-orange)', color: '#fff', border: 'none', cursor: 'pointer', fontFamily: 'Pretendard', fontWeight: 700 }}>확인</button>
            </div>
          </div>
        </div>
      )}

      {/* ═══ 하위폴더 선택 피커 ═══ */}
      {subfolderPicker && (
        <div style={{ position: 'fixed', inset: 0, zIndex: 1000, background: 'rgba(0,0,0,0.6)', display: 'flex', alignItems: 'center', justifyContent: 'center' }} onClick={() => setSubfolderPicker(null)}>
          <div onClick={e => e.stopPropagation()} style={{ width: 560, maxHeight: '80vh', background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', boxShadow: '0 20px 60px rgba(0,0,0,0.3)', display: 'flex', flexDirection: 'column' }}>
            <div style={{ padding: '20px 24px', background: 'var(--wu-ink)', color: 'var(--wu-paper)', display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexShrink: 0 }}>
              <div>
                <div className="display" style={{ fontSize: 18 }}>업로드할 폴더 선택</div>
                <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginTop: 4 }}>
                  {subfolderPicker.entries.length}개 폴더 발견 · {subfolderPicker.checked.size}개 선택됨
                </div>
              </div>
              <button onClick={() => setSubfolderPicker(null)} style={{ width: 32, height: 32, borderRadius: 999, background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', cursor: 'pointer', fontSize: 16 }}>×</button>
            </div>

            <div style={{ padding: '12px 24px', borderBottom: '1px solid var(--wu-line)', display: 'flex', gap: 12, alignItems: 'center', flexShrink: 0 }}>
              <button onClick={() => toggleAllSubfolders(true)} style={{ padding: '6px 14px', fontSize: 12, fontFamily: 'Pretendard', fontWeight: 700, background: 'var(--wu-orange)', color: '#fff', border: 'none', cursor: 'pointer', borderRadius: 4 }}>전체 선택</button>
              <button onClick={() => toggleAllSubfolders(false)} style={{ padding: '6px 14px', fontSize: 12, fontFamily: 'Pretendard', fontWeight: 700, background: 'var(--wu-bg)', color: 'var(--wu-ink)', border: '1px solid var(--wu-line)', cursor: 'pointer', borderRadius: 4 }}>전체 해제</button>
            </div>

            <div style={{ flex: 1, overflow: 'auto', padding: '0' }}>
              {subfolderPicker.entries.map((entry, i) => {
                const isDup = subfolderPicker.existingNames.has(entry.name);
                const isChecked = subfolderPicker.checked.has(entry.name);
                return (
                  <div key={entry.name} onClick={() => !isDup && toggleSubfolder(entry.name)} style={{
                    display: 'flex', alignItems: 'center', gap: 12, padding: '12px 24px',
                    borderBottom: i < subfolderPicker.entries.length - 1 ? '1px solid var(--wu-line)' : 'none',
                    background: isDup ? '#f5f5f5' : isChecked ? '#FFF7ED' : '#fff',
                    cursor: isDup ? 'not-allowed' : 'pointer', opacity: isDup ? 0.5 : 1
                  }}>
                    <input type="checkbox" checked={isChecked} disabled={isDup} onChange={() => !isDup && toggleSubfolder(entry.name)} style={{ width: 18, height: 18, accentColor: 'var(--wu-orange)', cursor: isDup ? 'not-allowed' : 'pointer' }} />
                    <span style={{ fontSize: 18 }}>📁</span>
                    <div style={{ flex: 1 }}>
                      <div className="kr" style={{ fontSize: 13, fontWeight: 600 }}>{entry.name}</div>
                      <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginTop: 2 }}>
                        사진 {entry.imgCount}장{entry.vidCount > 0 ? ' · 영상 ' + entry.vidCount + '개' : ''}{entry.hasTxt ? ' · TXT' : ''}
                        {isDup ? ' · 이미 큐에 있음' : ''}
                      </div>
                    </div>
                  </div>
                );
              })}
            </div>

            <div style={{ padding: '16px 24px', borderTop: '1px solid var(--wu-line)', display: 'flex', justifyContent: 'flex-end', gap: 12, flexShrink: 0 }}>
              <button onClick={() => setSubfolderPicker(null)} style={{ padding: '10px 20px', fontSize: 13, fontFamily: 'Pretendard', fontWeight: 700, background: 'var(--wu-bg)', color: 'var(--wu-ink)', border: '1px solid var(--wu-line)', cursor: 'pointer', borderRadius: 4 }}>취소</button>
              <button onClick={confirmSubfolderPick} style={{ padding: '10px 24px', fontSize: 13, fontFamily: 'Pretendard', fontWeight: 700, background: 'var(--wu-orange)', color: '#fff', border: 'none', cursor: 'pointer', borderRadius: 4 }}>
                선택한 폴더 추가 ({subfolderPicker.checked.size}개)
              </button>
            </div>
          </div>
        </div>
      )}

      {/* ═══ 수동 등록 폼 팝업 ═══ */}
      {showManual && manualData && (
        <div style={{ position: 'fixed', inset: 0, zIndex: 1000, background: 'rgba(0,0,0,0.6)', display: 'flex', alignItems: 'center', justifyContent: 'center' }} onClick={() => setShowManual(false)}>
          <div onClick={e => e.stopPropagation()} style={{ width: 680, maxHeight: '90vh', background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', boxShadow: '0 20px 60px rgba(0,0,0,0.3)', overflow: 'auto' }}>
            <div style={{ padding: '20px 24px', background: 'var(--wu-ink)', color: 'var(--wu-paper)', display: 'flex', justifyContent: 'space-between', alignItems: 'center', position: 'sticky', top: 0, zIndex: 2 }}>
              <div>
                <div className="display" style={{ fontSize: 18 }}>수동 상품 등록</div>
                <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginTop: 4 }}>직접 정보를 입력해서 상품을 발행합니다</div>
              </div>
              <button onClick={() => setShowManual(false)} style={{ width: 32, height: 32, borderRadius: 999, background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', cursor: 'pointer', fontSize: 16 }}>×</button>
            </div>
            <div style={{ padding: '20px 24px' }}>
              {/* 이미지 첨부 */}
              <div className="mono" style={{ fontSize: 10, color: 'var(--wu-orange)', fontWeight: 700, marginBottom: 8 }}>이미지 첨부 (최대 20장) · 현재 {manualData.photos.length}장</div>
              <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 20 }}>
                {manualData.photos.map((src, i) => (
                  <div key={i} style={{ width: 80, height: 80, position: 'relative', border: '1px solid var(--wu-line)', overflow: 'hidden' }}>
                    <img src={src} style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
                    <button onClick={() => setManualData(prev => ({ ...prev, photos: prev.photos.filter((_, j) => j !== i) }))} style={{ position: 'absolute', top: 2, right: 2, width: 18, height: 18, borderRadius: 999, background: 'rgba(0,0,0,0.6)', color: '#fff', border: 'none', cursor: 'pointer', fontSize: 10, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>×</button>
                  </div>
                ))}
                {manualData.photos.length < 20 && (
                  <label style={{ width: 80, height: 80, border: '2px dashed var(--wu-line)', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', background: 'var(--wu-bg)' }}>
                    <span style={{ fontSize: 20, color: 'var(--wu-mute)' }}>+</span>
                    <span className="mono" style={{ fontSize: 8, color: 'var(--wu-mute)' }}>사진</span>
                    <input ref={manualImgRef} type="file" accept="image/*" multiple onChange={handleManualAddImages} style={{ display: 'none' }} />
                  </label>
                )}
              </div>
              {/* 정보 입력 폼 */}
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px 16px' }}>
                <div style={{ gridColumn: '1 / -1' }}>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 4, fontWeight: 600 }}>상품명 *</div>
                  <input value={manualData.title} onChange={e => setManualData(prev => ({ ...prev, title: e.target.value }))} placeholder="상품명을 입력하세요" className="kr" style={{ width: '100%', padding: '10px 14px', border: '1.5px solid var(--wu-line)', fontSize: 14, fontWeight: 600, background: 'var(--wu-paper)', outline: 'none', borderRadius: 4, boxSizing: 'border-box' }} />
                </div>
                {[
                  ['상품코드', 'code', 'SKU / 품번'],
                  ['판매가', 'retail', '예: 14800'],
                  ['공급가', 'wholesale', '예: 9600'],
                  ['사이즈', 'sizes', '예: XS ~ 3XL'],
                  ['색상', 'colors', '예: 네이비, 민트'],
                  ['입수량', 'moq', '예: 5장'],
                  ['시즌', 'season', '예: 25SS'],
                ].map(([label, key, ph]) => (
                  <div key={key}>
                    <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 4, fontWeight: 600 }}>{label}</div>
                    <input value={manualData[key]} onChange={e => setManualData(prev => ({ ...prev, [key]: e.target.value }))} placeholder={ph} className="kr" style={{ width: '100%', padding: '10px 14px', border: '1.5px solid var(--wu-line)', fontSize: 13, background: 'var(--wu-paper)', outline: 'none', borderRadius: 4, boxSizing: 'border-box' }} />
                  </div>
                ))}
                {/* 카테고리 선택 (다중) */}
                <div style={{ gridColumn: '1 / -1' }}>
                  <div style={{ display: 'flex', gap: 8, alignItems: 'center', marginBottom: 6 }}>
                    <div className="mono" style={{ fontSize: 10, color: 'var(--wu-orange)', fontWeight: 700 }}>카테고리 (복수 선택 가능)</div>
                    <button onClick={() => {
                      const tempProduct = { title: manualData.title, body: '', parsed: { kr: manualData.title, brand: manualData.brand, parts: [], category: [] } };
                      const aiCats = aiAutoCategory(tempProduct);
                      if (aiCats.length > 0) { setManualData(prev => ({ ...prev, category: aiCats })); flash('AI 추천: ' + aiCats.join(', ')); }
                      else { flash('AI 분류 실패 — 직접 선택하세요'); }
                    }} className="mono" style={{ padding: '3px 10px', fontSize: 9, fontWeight: 700, background: '#7C3AED', color: '#fff', border: 'none', cursor: 'pointer', borderRadius: 4 }}>🤖 AI 추천</button>
                  </div>
                  <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                    {(WU_DATA.categories || []).filter(c => c !== '전체' && c !== '신상').map(cat => {
                      const sel = Array.isArray(manualData.category) && manualData.category.includes(cat);
                      return <button key={cat} onClick={() => setManualData(prev => {
                        const arr = Array.isArray(prev.category) ? [...prev.category] : [];
                        return { ...prev, category: sel ? arr.filter(c => c !== cat) : [...arr, cat] };
                      })} className="kr" style={{ padding: '7px 14px', fontSize: 12, fontWeight: 600, background: sel ? 'var(--wu-ink)' : 'var(--wu-bg)', color: sel ? 'var(--wu-lime)' : 'var(--wu-ink)', border: '1px solid var(--wu-line)', cursor: 'pointer', borderRadius: 4 }}>{cat}</button>;
                    })}
                  </div>
                </div>
                {/* 브랜드 선택 */}
                <div style={{ gridColumn: '1 / -1' }}>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--wu-orange)', marginBottom: 6, fontWeight: 700 }}>브랜드</div>
                  <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                    {(WU_DATA.brands || []).map(b => (
                      <button key={b} onClick={() => setManualData(prev => ({ ...prev, brand: prev.brand === b ? '' : b }))} className="mono" style={{ padding: '7px 14px', fontSize: 11, fontWeight: 700, background: manualData.brand === b ? 'var(--wu-ink)' : 'var(--wu-bg)', color: manualData.brand === b ? 'var(--wu-lime)' : 'var(--wu-ink)', border: '1px solid var(--wu-line)', cursor: 'pointer', borderRadius: 4 }}>{b}</button>
                    ))}
                  </div>
                </div>
              </div>
              <div style={{ marginTop: 12 }}>
                <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 4, fontWeight: 600 }}>상품 설명</div>
                <textarea value={manualData.body} onChange={e => setManualData(prev => ({ ...prev, body: e.target.value }))} placeholder="상품에 대한 상세 설명" className="kr" rows={4} style={{ width: '100%', padding: '10px 14px', border: '1.5px solid var(--wu-line)', fontSize: 13, lineHeight: 1.7, background: 'var(--wu-paper)', outline: 'none', resize: 'vertical', borderRadius: 4, boxSizing: 'border-box' }} />
              </div>
              <div style={{ display: 'flex', gap: 8, marginTop: 20 }}>
                <button onClick={handleManualSave} disabled={manualSaving} style={{ flex: 1, padding: '14px', fontSize: 15, fontWeight: 700, fontFamily: 'Pretendard', background: 'var(--wu-orange)', color: '#fff', border: 'none', cursor: 'pointer', borderRadius: 4 }}>{manualSaving ? '등록 중...' : '상품 발행'}</button>
                <button onClick={() => setShowManual(false)} style={{ padding: '14px 24px', fontSize: 14, fontWeight: 700, fontFamily: 'Pretendard', background: 'var(--wu-bg)', border: '1px solid var(--wu-line)', cursor: 'pointer', borderRadius: 4 }}>취소</button>
              </div>
            </div>
          </div>
        </div>
      )}

      <div style={{ padding: 28 }}>
        {/* 폴더 업로드 영역 — 멀티 폴더 큐 */}
        <div style={{ marginBottom: 24, padding: 20, background: 'var(--wu-paper)', border: '1px solid var(--wu-line)' }}>
          <div className="display" style={{ fontSize: 16, marginBottom: 4 }}>폴더에서 상품 가져오기</div>
          <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginBottom: 12, lineHeight: 1.6 }}>
            상위 폴더를 선택하면 하위 폴더 목록이 표시됩니다. 원하는 폴더를 체크해서 큐에 추가하세요.<br/>
            폴더명 = 상품명 / 이미지(최대 20장)+영상 + .txt = 상품정보 · 실패 건은 건너뛰고 계속 진행됩니다.
          </div>
          <div style={{ display: 'flex', gap: 12, alignItems: 'center', flexWrap: 'wrap' }}>
            <label style={{ display: 'inline-flex', alignItems: 'center', gap: 8, padding: '10px 20px', background: 'var(--wu-orange)', color: '#fff', fontFamily: 'Pretendard', fontSize: 13, fontWeight: 700, cursor: batchUploading ? 'not-allowed' : 'pointer', borderRadius: 4, opacity: batchUploading ? 0.5 : 1 }}>
              📁 폴더 추가
              <input ref={multiFolderRef} type="file" webkitdirectory="true" directory="" multiple onChange={addFoldersToQueue} disabled={batchUploading} style={{ display: 'none' }} />
            </label>
            {folderQueue.length > 0 && !batchUploading && (
              <button onClick={startBatchUpload} style={{ padding: '10px 20px', background: '#16A34A', color: '#fff', fontFamily: 'Pretendard', fontSize: 13, fontWeight: 700, cursor: 'pointer', border: 'none', borderRadius: 4 }}>
                ▶ 일괄 업로드 ({folderQueue.length}개)
              </button>
            )}
            {folderQueue.length > 0 && !batchUploading && (
              <button onClick={() => setFolderQueue([])} style={{ padding: '10px 16px', background: 'var(--wu-bg)', color: '#C44', fontFamily: 'Pretendard', fontSize: 12, fontWeight: 700, cursor: 'pointer', border: '1px solid #C44', borderRadius: 4 }}>전체 취소</button>
            )}
            <button onClick={load} className="wu-btn" style={{ fontSize: 11, padding: '8px 14px' }}>↻ 새로고침</button>
            <button onClick={initManual} style={{ padding: '10px 20px', background: 'var(--wu-ink)', color: 'var(--wu-lime)', fontFamily: 'Pretendard', fontSize: 13, fontWeight: 700, cursor: 'pointer', border: 'none', borderRadius: 4 }}>+ 수동 등록</button>
          </div>

          {/* 배치 업로드 진행 표시 */}
          {batchUploading && (
            <div style={{ marginTop: 16, padding: 16, background: '#F0FDF4', border: '1px solid #16A34A', borderRadius: 6 }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
                <div className="kr" style={{ fontSize: 14, fontWeight: 700, color: '#16A34A' }}>업로드 중...</div>
                <div className="mono" style={{ fontSize: 12, fontWeight: 700 }}>{batchProgress.current} / {batchProgress.total}</div>
              </div>
              <div style={{ width: '100%', height: 8, background: '#E5E7EB', borderRadius: 4, overflow: 'hidden' }}>
                <div style={{ width: (batchProgress.total > 0 ? (batchProgress.current / batchProgress.total * 100) : 0) + '%', height: '100%', background: '#16A34A', transition: 'width 0.3s ease', borderRadius: 4 }} />
              </div>
              <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginTop: 6 }}>현재: {batchProgress.currentName}</div>
            </div>
          )}

          {/* 폴더 큐 목록 */}
          {folderQueue.length > 0 && !batchUploading && (
            <div style={{ marginTop: 16 }}>
              <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 8 }}>업로드 대기 목록 ({folderQueue.length}개)</div>
              <div style={{ maxHeight: 200, overflow: 'auto', border: '1px solid var(--wu-line)', borderRadius: 4 }}>
                {folderQueue.map((q, i) => (
                  <div key={q.name + i} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '8px 12px', borderBottom: i < folderQueue.length - 1 ? '1px solid var(--wu-line)' : 'none', background: i % 2 === 0 ? '#fff' : 'var(--wu-bg)' }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                      <span className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', width: 24 }}>{i + 1}.</span>
                      <span style={{ fontSize: 14 }}>📁</span>
                      <span className="kr" style={{ fontSize: 13, fontWeight: 600 }}>{q.name}</span>
                      <span className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)' }}>{q.files.length}개 파일</span>
                    </div>
                    <button onClick={() => removeFromQueue(q.name)} style={{ fontSize: 11, color: '#C44', background: 'none', border: 'none', cursor: 'pointer', fontWeight: 700 }}>✕</button>
                  </div>
                ))}
              </div>
            </div>
          )}

          <div style={{ marginTop: 12, padding: 12, background: 'var(--wu-bg)', borderLeft: '3px solid var(--wu-orange)' }}>
            <div className="mono" style={{ fontSize: 9, color: 'var(--wu-orange)', marginBottom: 4 }}>TXT 파일 형식 예시 (폴더명과 같은 이름.txt)</div>
            <pre className="mono" style={{ fontSize: 11, color: 'var(--wu-ink)', margin: 0, lineHeight: 1.6 }}>{'☞ 공급가 : 9,600원\n☞ 판매가 : 14,800원\n☞ 사이즈 : XS ~ 3XL\n☞ 색상 : 네이비 민트\n☞ 입수량 : 5장\n\n코튼 100% 소재로 부드럽고 쾌적한 착용감'}</pre>
          </div>
        </div>

        {/* ═══ 검색 바 ═══ */}
        <div style={{ marginBottom: 16, display: 'flex', gap: 12, alignItems: 'center' }}>
          <div style={{ flex: 1, background: 'var(--wu-paper)', border: '1.5px solid var(--wu-line)', borderRadius: 4, padding: '10px 16px', display: 'flex', alignItems: 'center', gap: 10 }}>
            <svg width="14" height="14" viewBox="0 0 20 20" fill="none" stroke="var(--wu-mute)" strokeWidth="2"><circle cx="9" cy="9" r="6"/><path d="M14 14l4 4"/></svg>
            <input value={listSearch} onChange={e => setListSearch(e.target.value)} placeholder="상품명 · 브랜드 · SKU · 카테고리 검색" className="kr" style={{ flex: 1, border: 0, outline: 0, background: 'transparent', fontSize: 13, fontWeight: 600 }} />
            {listSearch && <button onClick={() => setListSearch('')} style={{ color: 'var(--wu-mute)', background: 'none', border: 'none', cursor: 'pointer', fontSize: 14 }}>✕</button>}
          </div>
          <button onClick={() => setShowCatMgr(true)} className="kr" style={{ padding: '10px 16px', fontSize: 12, fontWeight: 700, background: 'var(--wu-ink)', color: 'var(--wu-lime)', border: 'none', cursor: 'pointer', borderRadius: 4, flexShrink: 0, whiteSpace: 'nowrap' }}>카테고리 관리</button>
          <button onClick={() => setShowBrandMgr(true)} className="kr" style={{ padding: '10px 16px', fontSize: 12, fontWeight: 700, background: 'var(--wu-orange)', color: '#fff', border: 'none', cursor: 'pointer', borderRadius: 4, flexShrink: 0, whiteSpace: 'nowrap' }}>브랜드 관리</button>
          <button onClick={async () => {
            if (!confirm('카테고리가 없는 상품에 AI 자동 분류를 적용하시겠습니까?')) return;
            let cnt = 0;
            for (const item of items) {
              const parsed = item.parsed || {};
              if (parsed.category && Array.isArray(parsed.category) && parsed.category.length > 0) continue;
              const cats = aiAutoCategory(item);
              if (cats.length > 0) {
                if (!item.parsed) item.parsed = {};
                item.parsed.category = cats;
                item._aiCategorized = true;
                await updatePublished(item);
                cnt++;
              }
            }
            flash(cnt > 0 ? cnt + '개 상품 AI 자동 분류 완료' : '분류할 상품이 없습니다');
            load();
          }} className="kr" style={{ padding: '10px 16px', fontSize: 12, fontWeight: 700, background: '#7C3AED', color: '#fff', border: 'none', cursor: 'pointer', borderRadius: 4, flexShrink: 0, whiteSpace: 'nowrap' }}>🤖 AI 자동 분류</button>
          <div className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)', flexShrink: 0 }}>
            {listSearch ? filteredItems.length + '/' + items.length + '건' : '총 ' + items.length + '건'}
          </div>
        </div>

        {/* ═══ 카테고리 관리 팝업 ═══ */}
        {showCatMgr && (
          <div style={{ position: 'fixed', inset: 0, zIndex: 1000, background: 'rgba(0,0,0,0.5)', display: 'flex', alignItems: 'center', justifyContent: 'center' }} onClick={() => setShowCatMgr(false)}>
            <div onClick={e => e.stopPropagation()} style={{ width: 480, maxHeight: '80vh', background: 'var(--wu-paper)', boxShadow: '0 20px 60px rgba(0,0,0,0.3)', overflow: 'auto' }}>
              <div style={{ padding: '20px 24px', background: 'var(--wu-ink)', color: '#fff', display: 'flex', justifyContent: 'space-between', alignItems: 'center', position: 'sticky', top: 0, zIndex: 1 }}>
                <div>
                  <div className="display" style={{ fontSize: 18 }}>카테고리 관리</div>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--wu-lime)', marginTop: 4 }}>상품 분류 카테고리를 추가하거나 삭제합니다</div>
                </div>
                <button onClick={() => setShowCatMgr(false)} style={{ width: 32, height: 32, borderRadius: 999, background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', cursor: 'pointer', fontSize: 16 }}>×</button>
              </div>

              {/* 새 카테고리 추가 */}
              <div style={{ padding: '16px 24px', borderBottom: '1px solid var(--wu-line)', display: 'flex', gap: 8 }}>
                <input value={newCatInput} onChange={e => setNewCatInput(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') handleAddCategory(); }} placeholder="새 카테고리명 입력" className="kr" style={{ flex: 1, padding: '10px 14px', border: '1.5px solid var(--wu-line)', fontSize: 13, fontWeight: 600, outline: 'none', borderRadius: 4, background: 'var(--wu-bg)' }} />
                <button onClick={handleAddCategory} className="kr" style={{ padding: '10px 20px', fontSize: 13, fontWeight: 700, background: 'var(--wu-orange)', color: '#fff', border: 'none', cursor: 'pointer', borderRadius: 4, flexShrink: 0 }}>+ 추가</button>
              </div>

              {/* 기본 카테고리 */}
              <div style={{ padding: '16px 24px', borderBottom: '1px solid var(--wu-line)' }}>
                <div className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)', fontWeight: 700, marginBottom: 10, letterSpacing: '0.08em' }}>기본 카테고리 (삭제 불가)</div>
                <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
                  {(WU_DATA._defaultCategories || []).map(cat => (
                    <span key={cat} className="kr" style={{ padding: '7px 14px', fontSize: 12, fontWeight: 600, background: 'var(--wu-bg)', color: 'var(--wu-ink)', border: '1px solid var(--wu-line)', borderRadius: 4 }}>{cat}</span>
                  ))}
                </div>
              </div>

              {/* 커스텀 카테고리 */}
              <div style={{ padding: '16px 24px' }}>
                <div className="mono" style={{ fontSize: 9, color: 'var(--wu-orange)', fontWeight: 700, marginBottom: 10, letterSpacing: '0.08em' }}>직접 추가한 카테고리</div>
                {(WU_DATA._customCategories || []).length === 0 ? (
                  <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', padding: '16px 0' }}>추가한 카테고리가 없습니다</div>
                ) : (
                  <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
                    {(WU_DATA._customCategories || []).map(cat => (
                      <span key={cat} style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '7px 14px', fontSize: 12, fontWeight: 600, fontFamily: 'var(--wu-kr)', background: 'var(--wu-orange)', color: '#fff', borderRadius: 4 }}>
                        {cat}
                        <button onClick={() => handleRemoveCategory(cat)} style={{ width: 18, height: 18, borderRadius: 999, background: 'rgba(0,0,0,0.2)', color: '#fff', border: 'none', cursor: 'pointer', fontSize: 11, display: 'flex', alignItems: 'center', justifyContent: 'center', lineHeight: 1 }}>×</button>
                      </span>
                    ))}
                  </div>
                )}
              </div>

              <div style={{ padding: '12px 24px 20px', textAlign: 'right' }}>
                <button onClick={() => setShowCatMgr(false)} className="kr" style={{ padding: '10px 24px', fontSize: 13, fontWeight: 600, background: 'var(--wu-ink)', color: 'var(--wu-lime)', border: 'none', cursor: 'pointer', borderRadius: 4 }}>닫기</button>
              </div>
            </div>
          </div>
        )}

        {/* ═══ 브랜드 관리 팝업 ═══ */}
        {showBrandMgr && (
          <div style={{ position: 'fixed', inset: 0, zIndex: 1000, background: 'rgba(0,0,0,0.5)', display: 'flex', alignItems: 'center', justifyContent: 'center' }} onClick={() => setShowBrandMgr(false)}>
            <div onClick={e => e.stopPropagation()} style={{ width: 480, maxHeight: '80vh', background: 'var(--wu-paper)', boxShadow: '0 20px 60px rgba(0,0,0,0.3)', overflow: 'auto' }}>
              <div style={{ padding: '20px 24px', background: 'var(--wu-ink)', color: '#fff', display: 'flex', justifyContent: 'space-between', alignItems: 'center', position: 'sticky', top: 0, zIndex: 1 }}>
                <div>
                  <div className="display" style={{ fontSize: 18 }}>브랜드 관리</div>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--wu-lime)', marginTop: 4 }}>브랜드를 추가하거나 삭제합니다</div>
                </div>
                <button onClick={() => setShowBrandMgr(false)} style={{ width: 32, height: 32, borderRadius: 999, background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', cursor: 'pointer', fontSize: 16 }}>×</button>
              </div>

              {/* 새 브랜드 추가 */}
              <div style={{ padding: '16px 24px', borderBottom: '1px solid var(--wu-line)', display: 'flex', gap: 8 }}>
                <input value={newBrandInput} onChange={e => setNewBrandInput(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') handleAddBrand(); }} placeholder="새 브랜드명 입력" className="kr" style={{ flex: 1, padding: '10px 14px', border: '1.5px solid var(--wu-line)', fontSize: 13, fontWeight: 600, outline: 'none', borderRadius: 4, background: 'var(--wu-bg)' }} />
                <button onClick={handleAddBrand} className="kr" style={{ padding: '10px 20px', fontSize: 13, fontWeight: 700, background: 'var(--wu-orange)', color: '#fff', border: 'none', cursor: 'pointer', borderRadius: 4, flexShrink: 0 }}>+ 추가</button>
              </div>

              {/* 기본 브랜드 */}
              <div style={{ padding: '16px 24px', borderBottom: '1px solid var(--wu-line)' }}>
                <div className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)', fontWeight: 700, marginBottom: 10, letterSpacing: '0.08em' }}>기본 브랜드 (삭제 불가)</div>
                <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
                  {(WU_DATA._defaultBrands || []).map(b => (
                    <span key={b} className="mono" style={{ padding: '7px 14px', fontSize: 11, fontWeight: 700, background: 'var(--wu-bg)', color: 'var(--wu-ink)', border: '1px solid var(--wu-line)', borderRadius: 4 }}>{b}</span>
                  ))}
                </div>
              </div>

              {/* 커스텀 브랜드 */}
              <div style={{ padding: '16px 24px' }}>
                <div className="mono" style={{ fontSize: 9, color: 'var(--wu-orange)', fontWeight: 700, marginBottom: 10, letterSpacing: '0.08em' }}>직접 추가한 브랜드</div>
                {(WU_DATA._customBrands || []).length === 0 ? (
                  <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', padding: '16px 0' }}>추가한 브랜드가 없습니다</div>
                ) : (
                  <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
                    {(WU_DATA._customBrands || []).map(b => (
                      <span key={b} style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '7px 14px', fontSize: 12, fontWeight: 600, fontFamily: 'var(--wu-kr)', background: 'var(--wu-orange)', color: '#fff', borderRadius: 4 }}>
                        {b}
                        <button onClick={() => handleRemoveBrand(b)} style={{ width: 18, height: 18, borderRadius: 999, background: 'rgba(0,0,0,0.2)', color: '#fff', border: 'none', cursor: 'pointer', fontSize: 11, display: 'flex', alignItems: 'center', justifyContent: 'center', lineHeight: 1 }}>×</button>
                      </span>
                    ))}
                  </div>
                )}
              </div>

              <div style={{ padding: '12px 24px 20px', textAlign: 'right' }}>
                <button onClick={() => setShowBrandMgr(false)} className="kr" style={{ padding: '10px 24px', fontSize: 13, fontWeight: 600, background: 'var(--wu-ink)', color: 'var(--wu-lime)', border: 'none', cursor: 'pointer', borderRadius: 4 }}>닫기</button>
              </div>
            </div>
          </div>
        )}

        {/* ═══ 전체선택 + 일괄 액션 바 ═══ */}
        <div style={{ marginBottom: 12, display: 'flex', alignItems: 'center', gap: 12, padding: '10px 16px', background: selectedCount > 0 ? 'var(--wu-ink)' : 'var(--wu-paper)', border: '1px solid var(--wu-line)', borderRadius: 4, transition: 'background 0.2s' }}>
          <label style={{ display: 'flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
            <input type="checkbox" checked={allSelected} onChange={toggleSelectAll} style={{ width: 16, height: 16, cursor: 'pointer', accentColor: 'var(--wu-orange)' }} />
            <span className="kr" style={{ fontSize: 12, fontWeight: 600, color: selectedCount > 0 ? '#fff' : 'var(--wu-ink)' }}>
              {selectedCount > 0 ? selectedCount + '개 선택됨' : '전체 선택'}
            </span>
          </label>
          {selectedCount > 0 && (
            <div style={{ display: 'flex', gap: 8, marginLeft: 'auto' }}>
              <button onClick={() => setShowBulkCat(true)} className="kr" style={{ padding: '6px 14px', fontSize: 11, fontWeight: 700, background: 'var(--wu-orange)', color: '#fff', border: 'none', cursor: 'pointer', borderRadius: 4 }}>카테고리 일괄 변경</button>
              <button onClick={() => setSelectedIds({})} className="kr" style={{ padding: '6px 14px', fontSize: 11, fontWeight: 600, background: 'rgba(255,255,255,0.15)', color: '#fff', border: '1px solid rgba(255,255,255,0.3)', cursor: 'pointer', borderRadius: 4 }}>선택 해제</button>
            </div>
          )}
        </div>

        {/* ═══ 일괄 카테고리 변경 팝업 ═══ */}
        {showBulkCat && (
          <div style={{ position: 'fixed', inset: 0, zIndex: 1000, background: 'rgba(0,0,0,0.5)', display: 'flex', alignItems: 'center', justifyContent: 'center' }} onClick={() => setShowBulkCat(false)}>
            <div onClick={e => e.stopPropagation()} style={{ width: 420, background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', boxShadow: '0 20px 60px rgba(0,0,0,0.3)', padding: 28 }}>
              <div className="display" style={{ fontSize: 18, marginBottom: 4 }}>카테고리 일괄 변경</div>
              <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginBottom: 20 }}>{selectedCount}개 상품의 카테고리를 선택하세요</div>
              <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
                {(WU_DATA.categories || []).filter(c => c !== '전체' && c !== '신상').map(cat => (
                  <button key={cat} onClick={() => handleBulkCategory(cat)} disabled={bulkSaving} className="kr" style={{ padding: '10px 18px', fontSize: 13, fontWeight: 700, background: 'var(--wu-bg)', color: 'var(--wu-ink)', border: '1.5px solid var(--wu-line)', cursor: bulkSaving ? 'wait' : 'pointer', borderRadius: 6, transition: 'all 0.15s' }} onMouseEnter={e => { e.currentTarget.style.background = 'var(--wu-ink)'; e.currentTarget.style.color = 'var(--wu-lime)'; }} onMouseLeave={e => { e.currentTarget.style.background = 'var(--wu-bg)'; e.currentTarget.style.color = 'var(--wu-ink)'; }}>{cat}</button>
                ))}
              </div>
              {bulkSaving && <div className="kr" style={{ marginTop: 16, fontSize: 12, color: 'var(--wu-orange)', fontWeight: 600 }}>저장 중... {selectedCount}개 상품 업데이트 중</div>}
              <div style={{ marginTop: 20, textAlign: 'right' }}>
                <button onClick={() => setShowBulkCat(false)} className="kr" style={{ padding: '8px 20px', fontSize: 12, fontWeight: 600, background: 'var(--wu-bg)', border: '1px solid var(--wu-line)', cursor: 'pointer', borderRadius: 4 }}>취소</button>
              </div>
            </div>
          </div>
        )}

        {loading ? (
          <div style={{ padding: '60px 20px', textAlign: 'center' }}>
            <div className="display" style={{ fontSize: 18, color: 'var(--wu-mute)' }}>로딩 중...</div>
          </div>
        ) : filteredItems.length === 0 ? (
          <div style={{ padding: '60px 20px', background: 'var(--wu-paper)', border: '2px dashed var(--wu-line)', textAlign: 'center' }}>
            <div style={{ fontSize: 40, marginBottom: 12 }}>📦</div>
            <div className="display" style={{ fontSize: 18, color: 'var(--wu-mute)' }}>{listSearch ? '검색 결과가 없습니다' : '발행된 상품이 없습니다'}</div>
            <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginTop: 6 }}>{listSearch ? '다른 검색어를 시도해보세요' : 'AI 상세페이지에서 상품을 발행하세요'}</div>
          </div>
        ) : (
          <div style={{ display: 'grid', gap: 12 }}>
            {filteredItems.map(p => {
              const parsed = p.parsed || {};
              const photo = (p.photos || [])[0];
              const isChecked = !!selectedIds[p.id];
              const rawCat = parsed.category || p.category || '';
              const catArr = Array.isArray(rawCat) ? rawCat : rawCat ? [rawCat] : [];
              return (
                <div key={p.id} style={{ background: isChecked ? '#F5F3EE' : 'var(--wu-paper)', border: isChecked ? '2px solid var(--wu-orange)' : '1px solid var(--wu-line)', display: 'flex', overflow: 'hidden', cursor: 'pointer', transition: 'all 0.15s' }} onMouseEnter={e => e.currentTarget.style.boxShadow = '0 4px 16px rgba(0,0,0,0.1)'} onMouseLeave={e => e.currentTarget.style.boxShadow = 'none'}>
                  {/* 체크박스 */}
                  <div onClick={e => { e.stopPropagation(); toggleSelect(p.id); }} style={{ width: 44, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, background: isChecked ? 'var(--wu-orange)' : 'transparent', cursor: 'pointer' }}>
                    <input type="checkbox" checked={isChecked} onChange={() => {}} style={{ width: 16, height: 16, cursor: 'pointer', accentColor: 'var(--wu-orange)' }} />
                  </div>
                  <div onClick={() => setDetailProduct(p)} style={{ width: 100, height: 100, flexShrink: 0, background: '#E9E5DC' }}>
                    {photo ? <img src={photo} style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> : <div style={{ width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><span className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>NO IMG</span></div>}
                  </div>
                  <div onClick={() => setDetailProduct(p)} style={{ flex: 1, padding: '10px 16px', display: 'flex', alignItems: 'center', gap: 16 }}>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
                        {parsed.brand && <span className="mono" style={{ fontSize: 9, padding: '2px 6px', background: 'var(--wu-ink)', color: 'var(--wu-lime)', fontWeight: 700 }}>{parsed.brand}</span>}
                        {catArr.map(c => <span key={c} className="mono" style={{ fontSize: 9, padding: '2px 6px', background: 'var(--wu-orange)', color: '#fff', fontWeight: 700 }}>{c}</span>)}
                        {p._aiCategorized && <span className="mono" style={{ fontSize: 8, padding: '2px 5px', background: '#7C3AED', color: '#fff', fontWeight: 700, borderRadius: 3 }}>AI</span>}
                        <span className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>📷 {(p.photos || []).length}장</span>
                      </div>
                      <div className="kr" style={{ fontSize: 15, fontWeight: 700, marginTop: 4 }}>{p.title || parsed.name || '제목 없음'}</div>
                      <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginTop: 2 }}>{parsed.code || ''}{parsed.code ? ' · ' : ''}발행 {new Date(p.publishedAt).toLocaleDateString('ko-KR')}</div>
                      {(parsed.sizes || parsed.colors_kr) && <div className="kr" style={{ fontSize: 11, color: 'var(--wu-mute)', marginTop: 2 }}>{parsed.sizes && ('사이즈: ' + parsed.sizes)}{parsed.sizes && parsed.colors_kr ? ' / ' : ''}{parsed.colors_kr && ('색상: ' + parsed.colors_kr)}</div>}
                    </div>
                    <div style={{ textAlign: 'right', flexShrink: 0 }}>
                      <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)' }}>판매가</div>
                      <div className="display" style={{ fontSize: 18 }}>₩{String(parsed.retail || 0).replace(/\B(?=(\d{3})+(?!\d))/g, ',')}</div>
                      {parsed.wholesale && (
                        <>
                          <div className="mono" style={{ fontSize: 10, color: 'var(--wu-lime)', marginTop: 4 }}>공급가</div>
                          <div className="mono" style={{ fontSize: 14, fontWeight: 700 }}>₩{String(parsed.wholesale || 0).replace(/\B(?=(\d{3})+(?!\d))/g, ',')}</div>
                        </>
                      )}
                    </div>
                    <button onClick={(e) => { e.stopPropagation(); handleDelete(p.id); }} style={{ padding: '8px 12px', fontSize: 10, fontWeight: 700, fontFamily: 'Archivo', background: 'var(--wu-bg)', border: '1px solid #C44', color: '#C44', cursor: 'pointer', borderRadius: 4, flexShrink: 0 }}>삭제</button>
                  </div>
                </div>
              );
            })}
          </div>
        )}
      </div>
    </HQChrome>
  );
}

// ═══════════════════════════════════════════════════════════
// 07 — 매장 관리 (엑셀 업로드 + 목록 + 지도)
// ═══════════════════════════════════════════════════════════
// Store functions — now handled by firebase-init.jsx (Firestore)
// getAllStores, saveStoresBulk, deleteStore, clearAllStores are defined in firebase-init.jsx

function HQStoreManager() {
  const [stores, setStores] = useStateHQ2([]);
  const [tab, setTab] = useStateHQ2('list'); // list | upload | add | edit | map
  const [msg, setMsg] = useStateHQ2('');
  const [uploading, setUploading] = useStateHQ2(false);
  const [kakaoKey, setKakaoKey] = useStateHQ2(() => localStorage.getItem('wu-kakao-key') || '');
  const [kakaoRestKey, setKakaoRestKey] = useStateHQ2(() => localStorage.getItem('wu-kakao-rest-key') || '');
  const fileRef = useRefHQ2(null);
  const emptyForm = { name:'', storeId:'', manager:'', email:'', phone:'', mobile:'', shipNum:'', address:'', openDate:'' };
  const [form, setForm] = useStateHQ2({...emptyForm});
  const [editId, setEditId] = useStateHQ2(null);

  const load = async () => { const s = await getAllStores(); setStores(s); };
  useEffHQ2(() => { load(); }, []);

  const flash = (t) => { setMsg(t); setTimeout(() => setMsg(''), 2500); };

  // 개별 매장 추가
  const handleAddSingle = async () => {
    if (!form.name) { flash('대리점명은 필수입니다'); return; }
    await saveStoresBulk([{ ...form, createdAt: new Date().toISOString() }]);
    setForm({...emptyForm});
    await load();
    flash('매장 등록 완료');
    setTab('list');
  };

  // 매장 수정 시작
  const startEdit = (store) => {
    setEditId(store.id);
    setForm({ name: store.name||'', storeId: store.storeId||'', manager: store.manager||'', email: store.email||'', phone: store.phone||'', mobile: store.mobile||'', shipNum: store.shipNum||'', address: store.address||'', openDate: store.openDate||'' });
    setTab('edit');
  };

  // 매장 수정 저장
  const handleEditSave = async () => {
    if (!form.name) { flash('대리점명은 필수입니다'); return; }
    try {
      await wu_db.collection('stores').doc(String(editId)).update(form);
    } catch(e) {
      console.error('Store edit error:', e);
    }
    await load();
    flash('매장 수정 완료');
    setEditId(null);
    setForm({...emptyForm});
    setTab('list');
  };

  // 엑셀 양식 다운로드 (HTML table → .xls)
  const downloadTemplate = () => {
    const headers = ['대리점명','대리점id','담당자명','이메일','전화번호','휴대폰','출고안내번호','주소','오픈일'];
    const sample  = ['포천직영점','WUP001','주이돈','workup0217@gmail.com','--','010-2835-0064','010-2835-0064','경기 포천시 소흘읍 호국로 56 (이동교리) 1층 워크업포천점','20240217'];
    const html = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><meta charset="utf-8"/></head><body><table border="1">'
      + '<tr style="background:#4F6228;color:#fff;font-weight:bold">' + headers.map(h => '<td>' + h + '</td>').join('') + '</tr>'
      + '<tr>' + sample.map(v => '<td>' + v + '</td>').join('') + '</tr>'
      + '</table></body></html>';
    const blob = new Blob(['﻿' + html], { type: 'application/vnd.ms-excel;charset=utf-8' });
    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = 'workup_매장등록_양식.xls';
    a.click();
    URL.revokeObjectURL(a.href);
    flash('양식 다운로드 완료');
  };

  // HTML 테이블 파싱 헬퍼
  const _parseHtmlTable = (html) => {
    const doc = new DOMParser().parseFromString(html, 'text/html');
    const trs = doc.querySelectorAll('tr');
    const result = [];
    trs.forEach(tr => {
      const cells = [];
      tr.querySelectorAll('th, td').forEach(c => cells.push((c.textContent || '').trim()));
      if (cells.length > 0) result.push(cells);
    });
    return result;
  };

  // 행 배열 → 매장 객체 변환 (컬럼 9개: 대리점명, 대리점id, 담당자명, 이메일, 전화번호, 휴대폰, 출고안내번호, 주소, 오픈일)
  const _rowToStore = (cols) => ({
    name: (cols[0] || '').trim(),
    storeId: (cols[1] || '').trim(),
    manager: (cols[2] || '').trim(),
    email: (cols[3] || '').trim(),
    phone: (cols[4] || '').trim(),
    mobile: (cols[5] || '').trim(),
    shipNum: (cols[6] || '').trim(),
    address: (cols[7] || '').trim(),
    openDate: (cols[8] || '').trim(),
    createdAt: new Date().toISOString(),
  });

  // 통합 업로드 핸들러 — HTML table / TSV / XLSX 자동 감지
  const handleXlsx = async (e) => {
    const file = e.target.files[0];
    if (!file) return;
    setUploading(true);
    try {
      const text = await file.text();
      let mapped = [];

      // 1) HTML 테이블 감지 (<table 태그 포함)
      if (text.includes('<table') || text.includes('<TABLE')) {
        const rows = _parseHtmlTable(text);
        // 첫 행은 헤더 → 스킵
        mapped = rows.slice(1).map(cols => _rowToStore(cols)).filter(r => r.name);
      }
      // 2) SheetJS (.xlsx 바이너리)
      else if (window.XLSX && (file.name.endsWith('.xlsx') || file.name.endsWith('.xlsm'))) {
        const ab = await file.arrayBuffer();
        const wb = XLSX.read(ab, { type: 'array' });
        const ws = wb.Sheets[wb.SheetNames[0]];
        const jsonRows = XLSX.utils.sheet_to_json(ws);
        mapped = jsonRows.map(r => ({
          name: r['대리점명'] || r['name'] || '',
          storeId: r['대리점id'] || r['storeId'] || '',
          manager: r['담당자명'] || r['manager'] || '',
          email: r['이메일'] || r['email'] || '',
          phone: r['전화번호'] || r['phone'] || '',
          mobile: r['휴대폰'] || r['mobile'] || '',
          shipNum: r['출고안내번호'] || r['shipNum'] || '',
          address: r['주소'] || r['address'] || '',
          openDate: r['오픈일'] || r['openDate'] || '',
          createdAt: new Date().toISOString(),
        })).filter(r => r.name);
      }
      // 3) TSV / CSV
      else {
        const lines = text.split('\n').map(l => l.trim()).filter(Boolean);
        if (lines.length >= 2) {
          const sep = lines[0].includes('\t') ? '\t' : ',';
          mapped = lines.slice(1).map(line => _rowToStore(line.split(sep))).filter(r => r.name);
        }
      }

      if (mapped.length === 0) { flash('유효한 매장 데이터가 없습니다'); setUploading(false); return; }
      await saveStoresBulk(mapped);
      await load();
      flash(mapped.length + '개 매장 등록 완료');
    } catch(err) {
      flash('업로드 실패: ' + err.message);
    }
    setUploading(false);
    if (fileRef.current) fileRef.current.value = '';
  };

  const handleDeleteStore = async (id) => {
    await deleteStore(id);
    flash('매장 삭제됨');
    load();
  };

  const saveKakaoKey = async () => {
    try { localStorage.setItem('wu-kakao-key', kakaoKey); } catch(e) {}
    try { await saveSettingToCloud('kakao-key', kakaoKey); } catch(e) {}
    flash('JavaScript 키 저장 완료');
  };
  const saveKakaoRestKey = async () => {
    try { localStorage.setItem('wu-kakao-rest-key', kakaoRestKey); } catch(e) {}
    try { await saveSettingToCloud('kakao-rest-key', kakaoRestKey); } catch(e) {}
    flash('REST API 키 저장 완료 (카카오 로그인 활성화)');
  };

  return (
    <HQChrome active="stores" title="매장 관리" subtitle="HQ · STORE MANAGER">
      {msg && <div style={{ position: 'fixed', top: 16, right: 16, zIndex: 999, padding: '10px 18px', background: 'var(--wu-lime)', color: 'var(--wu-ink)', fontFamily: 'Pretendard', fontSize: 13, fontWeight: 700, boxShadow: '0 8px 24px rgba(0,0,0,0.2)' }}>{msg}</div>}
      <div style={{ padding: 28 }}>
        {/* Tab bar */}
        <div style={{ display: 'flex', gap: 2, marginBottom: 20, background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', borderRadius: 6, overflow: 'hidden', width: 'fit-content' }}>
          {[['list', '매장 목록 (' + stores.length + ')'], ['add', '개별 추가'], ['upload', '엑셀 업로드'], ['map', '지도 보기']].map(([k, l]) => (
            <button key={k} onClick={() => setTab(k)} className="kr" style={{ padding: '10px 18px', fontSize: 12, fontWeight: 600, background: tab === k ? 'var(--wu-ink)' : 'transparent', color: tab === k ? 'var(--wu-orange)' : 'var(--wu-ink)', cursor: 'pointer', border: 'none' }}>{l}</button>
          ))}
        </div>

        {/* UPLOAD TAB */}
        {tab === 'upload' && (
          <div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 20 }}>
              {/* Left: upload */}
              <div>
                <div className="display" style={{ fontSize: 18, marginBottom: 8 }}>엑셀 파일 업로드</div>
                <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginBottom: 16, lineHeight: 1.6 }}>
                  엑셀(.xls, .xlsx) 또는 TSV 파일을 업로드하세요.<br/>
                  필수 컬럼: 대리점명, 대리점id, 담당자명, 이메일, 전화번호, 휴대폰, 출고안내번호, 주소, 오픈일
                </div>

                <label style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '40px 20px', border: '2px dashed var(--wu-line)', background: 'var(--wu-paper)', cursor: 'pointer', marginBottom: 16 }}>
                  <div style={{ fontSize: 36, marginBottom: 8 }}>📁</div>
                  <div className="kr" style={{ fontSize: 14, fontWeight: 700 }}>{uploading ? '업로드 중...' : '파일 선택 또는 드래그'}</div>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginTop: 4 }}>.xls · .xlsx · .tsv · .csv</div>
                  <input ref={fileRef} type="file" accept=".xls,.xlsx,.tsv,.csv,.txt" onChange={handleXlsx} style={{ display: 'none' }} />
                </label>

                <button onClick={downloadTemplate} className="wu-btn lime" style={{ width: '100%', padding: '12px', fontSize: 13, fontWeight: 700 }}>📥 엑셀 양식 다운로드</button>
              </div>

              {/* Right: field info */}
              <div>
                <div className="display" style={{ fontSize: 18, marginBottom: 8 }}>등록 필드 안내</div>
                <div style={{ background: 'var(--wu-paper)', border: '1px solid var(--wu-line)' }}>
                  {['대리점명 *', '대리점id *', '담당자명', '이메일', '전화번호', '휴대폰', '출고안내번호', '주소 *', '오픈일'].map((f, i) => (
                    <div key={f} style={{ padding: '10px 14px', borderBottom: i < 8 ? '1px solid var(--wu-line)' : 'none', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                      <span className="kr" style={{ fontSize: 13, fontWeight: 600 }}>{f}</span>
                      <span className="mono" style={{ fontSize: 10, color: f.includes('*') ? 'var(--wu-orange)' : 'var(--wu-mute)' }}>{f.includes('*') ? '필수' : '선택'}</span>
                    </div>
                  ))}
                </div>

                <div style={{ marginTop: 20, padding: 14, background: 'var(--wu-ink)', color: 'var(--wu-paper)' }}>
                  <div className="mono" style={{ fontSize: 9, color: 'var(--wu-lime)', marginBottom: 6 }}>💡 TIP</div>
                  <div className="kr" style={{ fontSize: 12, lineHeight: 1.6 }}>
                    기존 매장 데이터에 추가 등록됩니다.<br/>
                    같은 대리점명이 있으면 새 항목으로 추가됩니다.
                  </div>
                </div>
              </div>
            </div>
          </div>
        )}

        {/* LIST TAB */}
        {tab === 'list' && (
          <div>
            {/* 상단 액션 바 */}
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
              <div className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)' }}>총 {stores.length}개 매장</div>
              <div style={{ display: 'flex', gap: 8 }}>
                <button onClick={() => setTab('add')} className="wu-btn lime" style={{ fontSize: 11, padding: '8px 14px' }}>+ 매장 추가</button>
                {stores.length > 0 && (
                  <button onClick={async () => { if (confirm('모든 매장 데이터를 삭제하시겠습니까?\n이 작업은 되돌릴 수 없습니다.')) { await clearAllStores(); await load(); flash('전체 삭제 완료'); }}} style={{ padding: '8px 14px', fontSize: 11, fontWeight: 700, background: 'none', border: '1px solid #C44', color: '#C44', cursor: 'pointer' }}>전체 삭제</button>
                )}
              </div>
            </div>

            {stores.length === 0 ? (
              <div style={{ padding: '60px 20px', background: 'var(--wu-paper)', border: '2px dashed var(--wu-line)', textAlign: 'center' }}>
                <div style={{ fontSize: 40, marginBottom: 12 }}>🏪</div>
                <div className="display" style={{ fontSize: 18, color: 'var(--wu-mute)' }}>등록된 매장이 없습니다</div>
                <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginTop: 6 }}>"개별 추가" 또는 "엑셀 업로드" 탭에서 매장을 등록하세요</div>
              </div>
            ) : (
              <div style={{ overflowX: 'auto' }}>
                <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12 }}>
                  <thead>
                    <tr style={{ background: 'var(--wu-ink)', color: 'var(--wu-paper)' }}>
                      <th className="kr" style={{ padding: '10px 12px', textAlign: 'left', fontWeight: 600 }}>대리점명</th>
                      <th className="kr" style={{ padding: '10px 12px', textAlign: 'left', fontWeight: 600 }}>대리점id</th>
                      <th className="kr" style={{ padding: '10px 12px', textAlign: 'left', fontWeight: 600 }}>담당자명</th>
                      <th className="kr" style={{ padding: '10px 12px', textAlign: 'left', fontWeight: 600 }}>이메일</th>
                      <th className="kr" style={{ padding: '10px 12px', textAlign: 'left', fontWeight: 600 }}>전화번호</th>
                      <th className="kr" style={{ padding: '10px 12px', textAlign: 'left', fontWeight: 600 }}>휴대폰</th>
                      <th className="kr" style={{ padding: '10px 12px', textAlign: 'left', fontWeight: 600 }}>출고안내번호</th>
                      <th className="kr" style={{ padding: '10px 12px', textAlign: 'left', fontWeight: 600 }}>주소</th>
                      <th className="kr" style={{ padding: '10px 12px', textAlign: 'left', fontWeight: 600 }}>오픈일</th>
                      <th style={{ width: 80 }}></th>
                    </tr>
                  </thead>
                  <tbody>
                    {stores.map((s) => (
                      <tr key={s.id} style={{ borderBottom: '1px solid var(--wu-line)', background: 'var(--wu-paper)' }}>
                        <td className="kr" style={{ padding: '10px 12px', fontWeight: 700, whiteSpace: 'nowrap' }}>{s.name || ''}</td>
                        <td className="mono" style={{ padding: '10px 12px', fontSize: 11 }}>{s.storeId || ''}</td>
                        <td className="kr" style={{ padding: '10px 12px' }}>{s.manager || ''}</td>
                        <td className="mono" style={{ padding: '10px 12px', fontSize: 11 }}>{s.email || ''}</td>
                        <td className="mono" style={{ padding: '10px 12px', fontSize: 11, whiteSpace: 'nowrap' }}>{s.phone || ''}</td>
                        <td className="mono" style={{ padding: '10px 12px', fontSize: 11, whiteSpace: 'nowrap' }}>{s.mobile || ''}</td>
                        <td className="mono" style={{ padding: '10px 12px', fontSize: 11, whiteSpace: 'nowrap' }}>{s.shipNum || ''}</td>
                        <td className="kr" style={{ padding: '10px 12px', fontSize: 11, maxWidth: 220, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{s.address || ''}</td>
                        <td className="mono" style={{ padding: '10px 12px', fontSize: 11 }}>{s.openDate || ''}</td>
                        <td style={{ padding: '10px 8px', textAlign: 'center', whiteSpace: 'nowrap' }}>
                          <button onClick={() => startEdit(s)} style={{ fontSize: 10, color: 'var(--wu-orange)', background: 'none', border: 'none', cursor: 'pointer', fontWeight: 700, marginRight: 6 }}>수정</button>
                          <button onClick={() => handleDeleteStore(s.id)} style={{ fontSize: 10, color: '#C44', background: 'none', border: 'none', cursor: 'pointer', fontWeight: 700 }}>삭제</button>
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}
          </div>
        )}

        {/* ADD SINGLE TAB */}
        {tab === 'add' && (
          <div>
            <div className="display" style={{ fontSize: 18, marginBottom: 16 }}>매장 개별 등록</div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, maxWidth: 700 }}>
              {[
                ['name', '대리점명 *', '예: 포천직영점'],
                ['storeId', '대리점id *', '예: WUP001'],
                ['manager', '담당자명', '예: 홍길동'],
                ['email', '이메일', '예: store@workup.co'],
                ['phone', '전화번호', '예: 02-1234-5678'],
                ['mobile', '휴대폰', '예: 010-1234-5678'],
                ['shipNum', '출고안내번호', '예: 1588-1234'],
                ['openDate', '오픈일', '예: 20240217'],
              ].map(([key, label, ph]) => (
                <div key={key}>
                  <div className="kr" style={{ fontSize: 12, fontWeight: 600, marginBottom: 6 }}>{label}</div>
                  <input value={form[key]} onChange={e => setForm(prev => ({ ...prev, [key]: e.target.value }))} placeholder={ph} className="mono" style={{ width: '100%', padding: '10px 12px', border: '1px solid var(--wu-line)', background: 'var(--wu-paper)', fontSize: 12, outline: 'none', boxSizing: 'border-box' }} />
                </div>
              ))}
              <div style={{ gridColumn: '1 / -1' }}>
                <div className="kr" style={{ fontSize: 12, fontWeight: 600, marginBottom: 6 }}>주소 *</div>
                <input value={form.address} onChange={e => setForm(prev => ({ ...prev, address: e.target.value }))} placeholder="예: 경기 포천시 소흘읍 호국로 56 (이동교리) 1층" className="kr" style={{ width: '100%', padding: '10px 12px', border: '1px solid var(--wu-line)', background: 'var(--wu-paper)', fontSize: 12, outline: 'none', boxSizing: 'border-box' }} />
              </div>
            </div>
            <div style={{ marginTop: 24, display: 'flex', gap: 10 }}>
              <button onClick={handleAddSingle} className="wu-btn lime" style={{ padding: '12px 28px', fontSize: 13, fontWeight: 700 }}>등록</button>
              <button onClick={() => setForm({...emptyForm})} style={{ padding: '12px 28px', fontSize: 13, background: 'none', border: '1px solid var(--wu-line)', cursor: 'pointer', color: 'var(--wu-mute)' }}>초기화</button>
            </div>
          </div>
        )}

        {/* EDIT TAB */}
        {tab === 'edit' && editId && (
          <div>
            <div className="display" style={{ fontSize: 18, marginBottom: 16 }}>매장 정보 수정</div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, maxWidth: 700 }}>
              {[
                ['name', '대리점명 *', '예: 포천직영점'],
                ['storeId', '대리점id *', '예: WUP001'],
                ['manager', '담당자명', '예: 홍길동'],
                ['email', '이메일', '예: store@workup.co'],
                ['phone', '전화번호', '예: 02-1234-5678'],
                ['mobile', '휴대폰', '예: 010-1234-5678'],
                ['shipNum', '출고안내번호', '예: 1588-1234'],
                ['openDate', '오픈일', '예: 20240217'],
              ].map(([key, label, ph]) => (
                <div key={key}>
                  <div className="kr" style={{ fontSize: 12, fontWeight: 600, marginBottom: 6 }}>{label}</div>
                  <input value={form[key]} onChange={e => setForm(prev => ({ ...prev, [key]: e.target.value }))} placeholder={ph} className="mono" style={{ width: '100%', padding: '10px 12px', border: '1px solid var(--wu-line)', background: 'var(--wu-paper)', fontSize: 12, outline: 'none', boxSizing: 'border-box' }} />
                </div>
              ))}
              <div style={{ gridColumn: '1 / -1' }}>
                <div className="kr" style={{ fontSize: 12, fontWeight: 600, marginBottom: 6 }}>주소 *</div>
                <input value={form.address} onChange={e => setForm(prev => ({ ...prev, address: e.target.value }))} placeholder="예: 경기 포천시 소흘읍 호국로 56" className="kr" style={{ width: '100%', padding: '10px 12px', border: '1px solid var(--wu-line)', background: 'var(--wu-paper)', fontSize: 12, outline: 'none', boxSizing: 'border-box' }} />
              </div>
            </div>
            <div style={{ marginTop: 24, display: 'flex', gap: 10 }}>
              <button onClick={handleEditSave} className="wu-btn lime" style={{ padding: '12px 28px', fontSize: 13, fontWeight: 700 }}>수정 저장</button>
              <button onClick={() => { setEditId(null); setForm({...emptyForm}); setTab('list'); }} style={{ padding: '12px 28px', fontSize: 13, background: 'none', border: '1px solid var(--wu-line)', cursor: 'pointer', color: 'var(--wu-mute)' }}>취소</button>
            </div>
          </div>
        )}

        {/* MAP TAB */}
        {tab === 'map' && (
          <div>
            {/* Kakao API keys */}
            <div style={{ marginBottom: 12, padding: 16, background: 'var(--wu-paper)', border: '1px solid var(--wu-line)' }}>
              <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 8 }}>KAKAO JAVASCRIPT KEY (지도용)</div>
              <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
                <input value={kakaoKey} onChange={e => setKakaoKey(e.target.value)} placeholder="카카오 JavaScript 앱 키 입력" className="mono" style={{ flex: 1, padding: '8px 12px', border: '1px solid var(--wu-line)', background: 'var(--wu-bg)', fontSize: 12, outline: 'none' }} />
                <button onClick={saveKakaoKey} className="wu-btn" style={{ fontSize: 11, padding: '8px 14px' }}>저장</button>
              </div>
            </div>
            <div style={{ marginBottom: 20, padding: 16, background: 'var(--wu-paper)', border: '1px solid var(--wu-line)' }}>
              <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 4 }}>KAKAO REST API KEY (카카오 로그인용)</div>
              <div className="kr" style={{ fontSize: 11, color: 'var(--wu-mute)', marginBottom: 8 }}>카카오 개발자 콘솔 → 앱 키 → REST API 키를 입력하세요</div>
              <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
                <input value={kakaoRestKey} onChange={e => setKakaoRestKey(e.target.value)} placeholder="카카오 REST API 키 입력" className="mono" style={{ flex: 1, padding: '8px 12px', border: '1px solid var(--wu-line)', background: 'var(--wu-bg)', fontSize: 12, outline: 'none' }} />
                <button onClick={saveKakaoRestKey} className="wu-btn" style={{ fontSize: 11, padding: '8px 14px', background: '#FEE500', color: '#191919' }}>저장</button>
              </div>
              {kakaoRestKey && <div className="mono" style={{ fontSize: 10, color: 'var(--wu-lime)', marginTop: 6 }}>✓ 카카오 로그인 활성화됨</div>}
            </div>

            {/* Map container */}
            <div style={{ position: 'relative', width: '100%', height: 500, background: '#E9E5DC', border: '1px solid var(--wu-line)', overflow: 'hidden' }}>
              {kakaoKey ? (
                <KakaoMapEmbed apiKey={kakaoKey} stores={stores} />
              ) : (
                <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', gap: 12 }}>
                  <svg width="48" height="48" viewBox="0 0 48 48" fill="none" stroke="var(--wu-mute)" strokeWidth="2"><path d="M24 4a14 14 0 00-14 14c0 12 14 26 14 26s14-14 14-26A14 14 0 0024 4zm0 20a6 6 0 100-12 6 6 0 000 12z"/></svg>
                  <div className="kr" style={{ fontSize: 14, fontWeight: 700, color: 'var(--wu-mute)' }}>카카오맵 API 키를 입력하세요</div>
                  <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)' }}>카카오 개발자 사이트에서 JavaScript 앱 키를 발급받으세요</div>
                  <a href="https://developers.kakao.com" target="_blank" className="mono" style={{ fontSize: 11, color: 'var(--wu-orange)' }}>developers.kakao.com →</a>
                </div>
              )}
            </div>

            {/* Store pins list */}
            {stores.length > 0 && (
              <div style={{ marginTop: 16 }}>
                <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 8 }}>등록 매장 {stores.length}개</div>
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8 }}>
                  {stores.slice(0, 12).map(s => (
                    <div key={s.id} style={{ padding: '10px 12px', background: 'var(--wu-paper)', border: '1px solid var(--wu-line)' }}>
                      <div className="kr" style={{ fontSize: 12, fontWeight: 700 }}>{s.name}</div>
                      <div className="kr" style={{ fontSize: 10, color: 'var(--wu-mute)', marginTop: 2 }}>{s.address}</div>
                    </div>
                  ))}
                </div>
              </div>
            )}
          </div>
        )}
      </div>
    </HQChrome>
  );
}

// Kakao Map embed component (with geocoding diagnostics)
function KakaoMapEmbed({ apiKey, stores }) {
  const mapRef = useRefHQ2(null);
  const [loaded, setLoaded] = useStateHQ2(false);
  const [mapError, setMapError] = useStateHQ2('');
  const [geoResults, setGeoResults] = useStateHQ2({ ok: [], noAddr: [], failed: [], total: 0 });
  const [showDiag, setShowDiag] = useStateHQ2(false);

  useEffHQ2(() => {
    if (!apiKey) return;
    try {
      if (window.kakao && window.kakao.maps && window.kakao.maps.LatLng) { setLoaded(true); return; }
      const old = document.getElementById('kakao-map-script');
      if (old) old.remove();
      const script = document.createElement('script');
      script.id = 'kakao-map-script';
      script.src = 'https://dapi.kakao.com/v2/maps/sdk.js?appkey=' + apiKey + '&libraries=services&autoload=false';
      script.onload = () => {
        try {
          if (window.kakao && window.kakao.maps) {
            window.kakao.maps.load(() => { setLoaded(true); setMapError(''); });
          } else { setMapError('카카오맵 초기화 실패. API 키를 확인하세요.'); }
        } catch(err) { setMapError('카카오맵 초기화 오류: ' + err.message); }
      };
      script.onerror = () => { setMapError('카카오맵 스크립트 로드 실패.\n현재 도메인을 카카오 개발자 콘솔에 등록하세요.'); };
      document.head.appendChild(script);
    } catch(err) { setMapError('스크립트 로드 중 오류: ' + err.message); }
  }, [apiKey]);

  useEffHQ2(() => {
    if (!loaded || !mapRef.current) return;
    try {
      if (!window.kakao || !window.kakao.maps) return;
      const map = new kakao.maps.Map(mapRef.current, {
        center: new kakao.maps.LatLng(36.5, 127.5), level: 13,
      });
      map.addControl(new kakao.maps.ZoomControl(), kakao.maps.ControlPosition.RIGHT);

      // 주소 없는 매장 먼저 분류
      const noAddr = stores.filter(s => !s.address || !s.address.trim());
      const withAddr = stores.filter(s => s.address && s.address.trim());
      const ok = []; const failed = [];
      let processed = 0;
      const updateResults = () => {
        setGeoResults({ ok: [...ok], noAddr: [...noAddr], failed: [...failed], total: stores.length });
      };

      if (kakao.maps.services && kakao.maps.services.Geocoder) {
        const geocoder = new kakao.maps.services.Geocoder();
        const places = new kakao.maps.services.Places();
        if (withAddr.length === 0) { updateResults(); return; }
        const _clean = (addr) => {
          if (!addr) return '';
          let c = addr.trim().replace(/\([^)]*\)/g, '').trim();
          c = c.replace(/\s+(?:\d+층|\d+F|B\d+F?|\d+호|\d+동\s*\d*호?|지하\s*\d*층?).*$/i, '').trim();
          c = c.replace(/(\d+[-−]\d+)\s+.+$/, '$1').trim();
          c = c.replace(/,.*$/, '').trim();
          return c;
        };
        const _addMarker = (s, lat, lng) => {
          const pos = new kakao.maps.LatLng(lat, lng);
          const marker = new kakao.maps.Marker({ map, position: pos, title: s.name });
          const iw = new kakao.maps.InfoWindow({
            content: '<div style="padding:6px 10px;font-size:12px;font-family:Pretendard;font-weight:700;white-space:nowrap">' + s.name + '</div>',
          });
          kakao.maps.event.addListener(marker, 'click', () => iw.open(map, marker));
          ok.push(s);
        };
        const _done = () => { processed++; if (processed >= withAddr.length) updateResults(); };
        withAddr.forEach(s => {
          const raw = s.address.trim();
          const clean = _clean(raw);
          try {
            geocoder.addressSearch(raw, (r1, s1) => {
              if (s1 === kakao.maps.services.Status.OK) { _addMarker(s, r1[0].y, r1[0].x); _done(); return; }
              const tryClean = (clean && clean !== raw);
              const step2 = tryClean ? (cb) => geocoder.addressSearch(clean, (r2, s2) => {
                if (s2 === kakao.maps.services.Status.OK) { _addMarker(s, r2[0].y, r2[0].x); _done(); return; }
                cb();
              }) : (cb) => cb();
              step2(() => {
                const kw = s.name + ' ' + (tryClean ? clean : raw);
                places.keywordSearch(kw, (r3, s3) => {
                  if (s3 === kakao.maps.services.Status.OK && r3.length) { _addMarker(s, r3[0].y, r3[0].x); _done(); return; }
                  places.keywordSearch(tryClean ? clean : raw, (r4, s4) => {
                    if (s4 === kakao.maps.services.Status.OK && r4.length) { _addMarker(s, r4[0].y, r4[0].x); }
                    else { failed.push({ ...s, reason: '모든 지오코딩 실패' }); }
                    _done();
                  });
                });
              });
            });
          } catch(e) {
            failed.push({ ...s, reason: '지오코딩 오류: ' + e.message });
            _done();
          }
        });
      }
    } catch(err) { setMapError('지도 렌더링 오류: ' + err.message); }
  }, [loaded, stores]);

  const hasIssues = geoResults.noAddr.length > 0 || geoResults.failed.length > 0;

  if (mapError) return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', gap: 12, padding: 20 }}>
      <div style={{ fontSize: 36 }}>⚠</div>
      <div className="kr" style={{ fontSize: 13, color: '#C44', whiteSpace: 'pre-line', textAlign: 'center', lineHeight: 1.8 }}>{mapError}</div>
      <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginTop: 8, textAlign: 'center', lineHeight: 1.6 }}>
        현재 도메인: <span className="mono" style={{ background: 'var(--wu-bg)', padding: '2px 8px' }}>{window.location.origin}</span><br/>
        이 주소를 카카오 플랫폼 설정에 추가하세요.
      </div>
    </div>
  );

  return (
    <div style={{ position: 'relative', width: '100%', height: '100%' }}>
      <div ref={mapRef} style={{ width: '100%', height: '100%' }} />

      {/* 지도 매핑 상태 표시 */}
      {geoResults.total > 0 && (
        <div style={{ position: 'absolute', top: 10, left: 10, zIndex: 10 }}>
          <button onClick={() => setShowDiag(!showDiag)} className="mono" style={{
            padding: '8px 14px', fontSize: 10, fontWeight: 700, borderRadius: 6, cursor: 'pointer', border: 'none',
            background: hasIssues ? '#C44' : 'var(--wu-ink)', color: '#fff',
            boxShadow: '0 2px 8px rgba(0,0,0,0.3)', display: 'flex', alignItems: 'center', gap: 6,
          }}>
            {hasIssues ? '⚠' : '✓'} {geoResults.ok.length}/{geoResults.total} 매장 표시
            {hasIssues && <span style={{ background: '#fff', color: '#C44', padding: '1px 6px', borderRadius: 999, fontSize: 9 }}>
              {geoResults.noAddr.length + geoResults.failed.length} 미표시
            </span>}
          </button>

          {showDiag && (
            <div style={{ marginTop: 6, width: 380, maxHeight: 400, overflow: 'auto', background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', borderRadius: 8, boxShadow: '0 8px 24px rgba(0,0,0,0.2)', fontSize: 12 }} className="wu-scroll">
              <div style={{ padding: '12px 16px', background: 'var(--wu-ink)', color: '#fff', position: 'sticky', top: 0, zIndex: 1 }}>
                <div className="display" style={{ fontSize: 14 }}>지도 매핑 진단</div>
                <div className="mono" style={{ fontSize: 10, color: 'var(--wu-lime)', marginTop: 4 }}>
                  전체 {geoResults.total} · 표시 {geoResults.ok.length} · 주소없음 {geoResults.noAddr.length} · 실패 {geoResults.failed.length}
                </div>
              </div>

              {geoResults.noAddr.length > 0 && (
                <div style={{ padding: '10px 16px', borderBottom: '1px solid var(--wu-line)' }}>
                  <div className="mono" style={{ fontSize: 9, color: '#C44', fontWeight: 700, marginBottom: 6 }}>주소 없음 ({geoResults.noAddr.length}건)</div>
                  {geoResults.noAddr.map((s, i) => (
                    <div key={i} style={{ padding: '6px 0', borderBottom: i < geoResults.noAddr.length - 1 ? '1px solid #f0f0f0' : 'none' }}>
                      <span className="kr" style={{ fontWeight: 700 }}>{s.name || '이름없음'}</span>
                      <span className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginLeft: 8 }}>{s.storeId || ''}</span>
                      <div className="kr" style={{ fontSize: 10, color: '#C44', marginTop: 2 }}>→ 주소를 입력해주세요</div>
                    </div>
                  ))}
                </div>
              )}

              {geoResults.failed.length > 0 && (
                <div style={{ padding: '10px 16px', borderBottom: '1px solid var(--wu-line)' }}>
                  <div className="mono" style={{ fontSize: 9, color: '#E67E22', fontWeight: 700, marginBottom: 6 }}>지오코딩 실패 ({geoResults.failed.length}건)</div>
                  {geoResults.failed.map((s, i) => (
                    <div key={i} style={{ padding: '6px 0', borderBottom: i < geoResults.failed.length - 1 ? '1px solid #f0f0f0' : 'none' }}>
                      <span className="kr" style={{ fontWeight: 700 }}>{s.name || '이름없음'}</span>
                      <span className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginLeft: 8 }}>{s.storeId || ''}</span>
                      <div className="kr" style={{ fontSize: 10, color: '#E67E22', marginTop: 2 }}>주소: {s.address}</div>
                      <div className="kr" style={{ fontSize: 10, color: '#C44', marginTop: 1 }}>→ {s.reason}</div>
                    </div>
                  ))}
                </div>
              )}

              {geoResults.ok.length > 0 && (
                <div style={{ padding: '10px 16px' }}>
                  <div className="mono" style={{ fontSize: 9, color: 'var(--wu-lime)', fontWeight: 700, marginBottom: 6 }}>표시 성공 ({geoResults.ok.length}건)</div>
                  {geoResults.ok.map((s, i) => (
                    <div key={i} style={{ padding: '4px 0', fontSize: 11 }}>
                      <span className="kr" style={{ fontWeight: 600 }}>{s.name}</span>
                      <span className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginLeft: 8 }}>{s.address}</span>
                    </div>
                  ))}
                </div>
              )}
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// ═══════════════════════════════════════════════════════════
// 08 — 게시판 (장비자랑 · 구하고싶은공구)
// ═══════════════════════════════════════════════════════════
const BOARD_CATEGORIES = ['장비자랑', '구하고싶은공구'];
const BOARD_DB_NAME = 'wu-board-db';
const BOARD_DB_STORE = 'posts';
const BOARD_DB_VER = 1;

function _openBoardDB() {
  return new Promise((resolve, reject) => {
    const req = indexedDB.open(BOARD_DB_NAME, BOARD_DB_VER);
    req.onupgradeneeded = (e) => {
      const db = e.target.result;
      if (!db.objectStoreNames.contains(BOARD_DB_STORE)) db.createObjectStore(BOARD_DB_STORE, { keyPath: 'id' });
    };
    req.onsuccess = () => resolve(req.result);
    req.onerror = () => reject(req.error);
  });
}
async function getAllPosts() {
  const db = await _openBoardDB();
  return new Promise((resolve, reject) => {
    const tx = db.transaction(BOARD_DB_STORE, 'readonly');
    const req = tx.objectStore(BOARD_DB_STORE).getAll();
    req.onsuccess = () => {
      db.close();
      const list = req.result || [];
      list.sort((a, b) => (b.createdAt || '').localeCompare(a.createdAt || ''));
      resolve(list);
    };
    req.onerror = () => { db.close(); reject(req.error); };
  });
}
async function savePost(post) {
  const db = await _openBoardDB();
  return new Promise((resolve, reject) => {
    const tx = db.transaction(BOARD_DB_STORE, 'readwrite');
    tx.objectStore(BOARD_DB_STORE).put(post);
    tx.oncomplete = () => { db.close(); resolve(post); };
    tx.onerror = () => { db.close(); reject(tx.error); };
  });
}
async function deletePost(id) {
  const db = await _openBoardDB();
  return new Promise((resolve, reject) => {
    const tx = db.transaction(BOARD_DB_STORE, 'readwrite');
    tx.objectStore(BOARD_DB_STORE).delete(id);
    tx.oncomplete = () => { db.close(); resolve(); };
    tx.onerror = () => { db.close(); reject(tx.error); };
  });
}

function HQBoard() {
  const [posts, setPosts] = useStateHQ2([]);
  const [view, setView] = useStateHQ2('list'); // list | write | detail
  const [selected, setSelected] = useStateHQ2(null);
  const [msg, setMsg] = useStateHQ2('');

  // Form state
  const [title, setTitle] = useStateHQ2('');
  const [body, setBody] = useStateHQ2('');
  const [category, setCategory] = useStateHQ2('장비자랑');
  const [photos, setPhotos] = useStateHQ2([]);

  const load = async () => { const p = await getAllPosts(); setPosts(p); };
  useEffHQ2(() => { load(); }, []);

  const flash = (t) => { setMsg(t); setTimeout(() => setMsg(''), 2500); };

  const user = typeof getAuth === 'function' ? getAuth() : null;

  const handlePhotoUpload = (e) => {
    const files = Array.from(e.target.files);
    const remaining = 5 - photos.length;
    files.slice(0, remaining).forEach(file => {
      const reader = new FileReader();
      reader.onload = (ev) => setPhotos(prev => prev.length >= 5 ? prev : [...prev, ev.target.result]);
      reader.readAsDataURL(file);
    });
    e.target.value = '';
  };

  const submitPost = async () => {
    if (!title.trim()) { flash('제목을 입력하세요'); return; }
    if (!body.trim()) { flash('내용을 입력하세요'); return; }
    const post = {
      id: 'POST-' + Date.now(),
      title: title.trim(),
      body: body.trim(),
      category,
      photos,
      author: user?.name || '익명',
      authorRole: user?.role || 'consumer',
      createdAt: new Date().toISOString(),
      replies: [],
      status: 'NEW',
    };
    await savePost(post);
    setTitle(''); setBody(''); setPhotos([]);
    setView('list');
    flash('게시글 등록 완료');
    load();
  };

  const handleDelete = async (id) => {
    if (!confirm('이 게시글을 삭제하시겠습니까?')) return;
    await deletePost(id);
    setView('list');
    setSelected(null);
    flash('삭제 완료');
    load();
  };

  const handleReply = async (postId, replyText) => {
    const post = posts.find(p => p.id === postId);
    if (!post) return;
    const reply = {
      id: 'R-' + Date.now(),
      text: replyText,
      author: user?.name || '관리자',
      authorRole: user?.role || 'admin',
      createdAt: new Date().toISOString(),
    };
    post.replies = [...(post.replies || []), reply];
    await savePost(post);
    load();
    flash('답변 등록 완료');
  };

  return (
    <HQChrome active="board" title="게시판" subtitle="HQ · BOARD · 장비자랑 · 구하고싶은공구">
      {msg && <div style={{ position: 'fixed', top: 16, right: 16, zIndex: 999, padding: '10px 18px', background: 'var(--wu-lime)', color: 'var(--wu-ink)', fontFamily: 'Pretendard', fontSize: 13, fontWeight: 700, boxShadow: '0 8px 24px rgba(0,0,0,0.2)' }}>{msg}</div>}
      <div style={{ padding: 28 }}>

        {/* LIST VIEW */}
        {view === 'list' && (
          <div>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20 }}>
              <div className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)' }}>총 {posts.length}건</div>
              <button onClick={() => { setView('write'); setTitle(''); setBody(''); setPhotos([]); setCategory('장비자랑'); }} className="wu-btn lime" style={{ fontSize: 12, padding: '10px 18px' }}>+ 글쓰기</button>
            </div>

            {posts.length === 0 ? (
              <div style={{ padding: '60px 20px', background: 'var(--wu-paper)', border: '2px dashed var(--wu-line)', textAlign: 'center' }}>
                <div style={{ fontSize: 40, marginBottom: 12 }}>💬</div>
                <div className="display" style={{ fontSize: 18, color: 'var(--wu-mute)' }}>게시글이 없습니다</div>
                <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginTop: 6 }}>장비자랑이나 구하고싶은공구 글을 작성해보세요</div>
              </div>
            ) : (
              <div style={{ background: 'var(--wu-paper)', border: '1px solid var(--wu-line)' }}>
                {posts.map((p, i) => (
                  <button key={p.id} onClick={() => { setSelected(p); setView('detail'); }} style={{ display: 'flex', width: '100%', padding: '14px 16px', borderBottom: i < posts.length - 1 ? '1px solid var(--wu-line)' : 'none', cursor: 'pointer', textAlign: 'left', background: 'none', border: 'none', borderBottomStyle: i < posts.length - 1 ? 'solid' : 'none', borderBottomWidth: 1, borderBottomColor: 'var(--wu-line)', gap: 12, alignItems: 'center' }}>
                    {/* Category badge */}
                    <span className="mono" style={{ fontSize: 9, padding: '3px 8px', background: p.category === '장비자랑' ? '#E3F2FD' : p.category === '구하고싶은공구' ? '#FFF3E0' : 'var(--wu-bg)', color: 'var(--wu-ink)', fontWeight: 700, flexShrink: 0, borderRadius: 4 }}>
                      {p.category}
                    </span>
                    {/* Content */}
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div className="kr" style={{ fontSize: 14, fontWeight: 700, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.title}</div>
                      <div className="kr" style={{ fontSize: 11, color: 'var(--wu-mute)', marginTop: 2, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.body.slice(0, 60)}</div>
                    </div>
                    {/* Meta */}
                    <div style={{ textAlign: 'right', flexShrink: 0 }}>
                      <div className="kr" style={{ fontSize: 11, fontWeight: 600 }}>{p.author}</div>
                      <div className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)', marginTop: 2 }}>{new Date(p.createdAt).toLocaleDateString('ko-KR')}</div>
                    </div>
                    {/* Photo indicator + reply count */}
                    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4, flexShrink: 0 }}>
                      {(p.photos || []).length > 0 && <span className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>📷{p.photos.length}</span>}
                      {(p.replies || []).length > 0 && <span className="mono" style={{ fontSize: 9, color: 'var(--wu-orange)' }}>💬{p.replies.length}</span>}
                    </div>
                  </button>
                ))}
              </div>
            )}
          </div>
        )}

        {/* WRITE VIEW */}
        {view === 'write' && (
          <div>
            <button onClick={() => setView('list')} className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)', cursor: 'pointer', marginBottom: 16, background: 'none', border: 'none' }}>← 목록으로</button>

            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 20 }}>
              <div>
                <div className="display" style={{ fontSize: 18, marginBottom: 16 }}>게시글 작성</div>

                {/* Category select */}
                <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 6 }}>카테고리</div>
                <div style={{ display: 'flex', gap: 6, marginBottom: 16 }}>
                  {BOARD_CATEGORIES.map(c => (
                    <button key={c} onClick={() => setCategory(c)} className="kr" style={{ padding: '8px 14px', fontSize: 12, fontWeight: 600, background: category === c ? 'var(--wu-ink)' : 'var(--wu-paper)', color: category === c ? 'var(--wu-lime)' : 'var(--wu-ink)', border: '1px solid var(--wu-line)', cursor: 'pointer', borderRadius: 4 }}>{c}</button>
                  ))}
                </div>

                {/* Title */}
                <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 6 }}>제목 *</div>
                <input value={title} onChange={e => setTitle(e.target.value)} placeholder="제목을 입력하세요" className="kr" style={{ width: '100%', padding: '12px 14px', border: '1px solid var(--wu-line)', background: 'var(--wu-paper)', fontSize: 14, fontWeight: 600, outline: 'none', marginBottom: 16 }} />

                {/* Body */}
                <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 6 }}>내용 *</div>
                <textarea value={body} onChange={e => setBody(e.target.value)} placeholder={"자유롭게 내용을 작성하세요.\n\n장비자랑: 내 장비 소개, 사용 후기 등\n구하고싶은공구: 찾고 있는 공구, 브랜드 등"} className="kr" rows={8} style={{ width: '100%', padding: '12px 14px', border: '1px solid var(--wu-line)', background: 'var(--wu-paper)', fontSize: 13, lineHeight: 1.7, outline: 'none', resize: 'vertical', fontFamily: 'Pretendard' }} />
              </div>

              <div>
                <div className="display" style={{ fontSize: 18, marginBottom: 16 }}>참고 이미지 ({photos.length}/5)</div>
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8, marginBottom: 16 }}>
                  {photos.map((ph, i) => (
                    <div key={i} style={{ position: 'relative', aspectRatio: '1/1', overflow: 'hidden', border: '1px solid var(--wu-line)' }}>
                      <img src={ph} style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
                      <button onClick={() => setPhotos(prev => prev.filter((_, j) => j !== i))} style={{ position: 'absolute', top: 4, right: 4, width: 20, height: 20, background: 'rgba(200,0,0,0.8)', color: '#fff', border: 0, fontSize: 10, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', borderRadius: 999 }}>✕</button>
                    </div>
                  ))}
                  {photos.length < 5 && (
                    <label style={{ aspectRatio: '1/1', border: '2px dashed var(--wu-line)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', flexDirection: 'column', gap: 4 }}>
                      <span style={{ fontSize: 24, opacity: 0.4 }}>+</span>
                      <span className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>추가</span>
                      <input type="file" accept="image/*" multiple onChange={handlePhotoUpload} style={{ display: 'none' }} />
                    </label>
                  )}
                </div>

                {/* Preview */}
                <div style={{ padding: 16, background: 'var(--wu-ink)', color: 'var(--wu-paper)' }}>
                  <div className="mono" style={{ fontSize: 9, color: 'var(--wu-lime)', marginBottom: 8 }}>PREVIEW</div>
                  <div className="kr" style={{ fontSize: 14, fontWeight: 700 }}>{title || '(제목 미입력)'}</div>
                  <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginTop: 4, lineHeight: 1.6 }}>{body ? body.slice(0, 100) + (body.length > 100 ? '...' : '') : '(내용 미입력)'}</div>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginTop: 8 }}>작성자: {user?.name || '익명'} · {category}</div>
                </div>

                <button onClick={submitPost} className="wu-btn lime" style={{ width: '100%', padding: '14px', fontSize: 14, fontWeight: 700, marginTop: 16 }}>게시글 등록</button>
              </div>
            </div>
          </div>
        )}

        {/* DETAIL VIEW */}
        {view === 'detail' && selected && (
          <BoardDetailView post={selected} user={user} onBack={() => { setView('list'); setSelected(null); }} onDelete={handleDelete} onReply={handleReply} />
        )}
      </div>
    </HQChrome>
  );
}

// Board detail sub-component
function BoardDetailView({ post, user, onBack, onDelete, onReply }) {
  const [replyText, setReplyText] = React.useState('');

  const doReply = () => {
    if (!replyText.trim()) return;
    onReply(post.id, replyText.trim());
    setReplyText('');
  };

  return (
    <div>
      <button onClick={onBack} className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)', cursor: 'pointer', marginBottom: 16, background: 'none', border: 'none' }}>← 목록으로</button>

      <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 20 }}>
        {/* Main content */}
        <div>
          <div style={{ display: 'flex', gap: 8, alignItems: 'center', marginBottom: 12 }}>
            <span className="mono" style={{ fontSize: 9, padding: '3px 8px', background: post.category === '상품 제안' ? '#E8F5E9' : post.category === '입고 요청' ? '#FFF3E0' : 'var(--wu-bg)', color: 'var(--wu-ink)', fontWeight: 700, borderRadius: 4 }}>{post.category}</span>
            <span className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>{new Date(post.createdAt).toLocaleString('ko-KR')}</span>
          </div>
          <div className="kr" style={{ fontSize: 22, fontWeight: 800 }}>{post.title}</div>
          <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginTop: 4 }}>작성자: {post.author} ({post.authorRole === 'admin' ? '관리자' : post.authorRole === 'owner' ? '점주' : '회원'})</div>

          <div className="kr" style={{ marginTop: 20, fontSize: 14, lineHeight: 1.8, whiteSpace: 'pre-wrap' }}>{post.body}</div>

          {/* Photos */}
          {(post.photos || []).length > 0 && (
            <div style={{ display: 'flex', gap: 8, marginTop: 20, overflowX: 'auto' }}>
              {post.photos.map((ph, i) => (
                <img key={i} src={ph} style={{ width: 200, height: 200, objectFit: 'cover', border: '1px solid var(--wu-line)', flexShrink: 0 }} />
              ))}
            </div>
          )}

          {/* Delete button */}
          <div style={{ marginTop: 24, paddingTop: 16, borderTop: '1px solid var(--wu-line)' }}>
            <button onClick={() => onDelete(post.id)} style={{ padding: '8px 14px', fontSize: 11, fontWeight: 700, background: 'var(--wu-bg)', border: '1px solid #C44', color: '#C44', cursor: 'pointer', borderRadius: 4 }}>게시글 삭제</button>
          </div>
        </div>

        {/* Replies sidebar */}
        <div>
          <div className="display" style={{ fontSize: 16, marginBottom: 12 }}>답변 ({(post.replies || []).length})</div>

          {(post.replies || []).map(r => (
            <div key={r.id} style={{ padding: 14, background: r.authorRole === 'admin' ? 'var(--wu-ink)' : 'var(--wu-paper)', color: r.authorRole === 'admin' ? 'var(--wu-paper)' : 'var(--wu-ink)', border: '1px solid var(--wu-line)', marginBottom: 8 }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 6 }}>
                <span className="kr" style={{ fontSize: 12, fontWeight: 700 }}>{r.author}</span>
                <span className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>{new Date(r.createdAt).toLocaleDateString('ko-KR')}</span>
              </div>
              <div className="kr" style={{ fontSize: 13, lineHeight: 1.6, whiteSpace: 'pre-wrap' }}>{r.text}</div>
            </div>
          ))}

          {/* Reply input */}
          <div style={{ marginTop: 12, padding: 14, background: 'var(--wu-paper)', border: '1px solid var(--wu-line)' }}>
            <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 6 }}>답변 작성</div>
            <textarea value={replyText} onChange={e => setReplyText(e.target.value)} placeholder="답변을 입력하세요" className="kr" rows={4} style={{ width: '100%', padding: 10, border: '1px solid var(--wu-line)', background: 'var(--wu-bg)', fontSize: 13, lineHeight: 1.6, resize: 'vertical', outline: 'none', fontFamily: 'Pretendard' }} />
            <button onClick={doReply} className="wu-btn lime" style={{ width: '100%', padding: '10px', fontSize: 12, fontWeight: 700, marginTop: 8 }}>답변 등록</button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════════
// 홈 화면 관리 — 히어로, 신제품, 베스트, 이벤트, 신규매장 편집
// ═══════════════════════════════════════════════════════════
const HOME_CLOUD_KEY = 'home-config';
const HOME_DEFAULTS = {
  heroSlides: [
    { image: '', title: 'WORK\nWEAR\nUP.', subtitle: 'FW 2차 드롭 · 6종\n11.22 오전 11시', productId: '' },
  ],
  ticker: '★ FREE SHIPPING ₩50,000+ ★ WORKUP PREMIUM WORKWEAR ★ NEW DROP',
  topMenus: [],      // 상단 고정 카테고리 메뉴 (비어있으면 WU_DATA.categories 사용)
  newProducts: [],   // [{id, title, photo, retail}] 발행상품에서 선택
  bestProducts: [],  // [{id, title, photo, retail}]
  events: [
    { title: '5월 이벤트', body: '전 매장 5% 할인', color: '#FF6B35', image: '' },
  ],
  newStores: [],     // [{name, address}] 매장목록에서 선택
};

function HQHomeEditor() {
  const [cfg, setCfg] = React.useState({ ...HOME_DEFAULTS });
  const [pubProducts, setPubProducts] = React.useState([]);
  const [allStores, setAllStores] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [msg, setMsg] = React.useState('');
  const [picker, setPicker] = React.useState(null); // { field, multi, max }
  const [storePicker, setStorePicker] = React.useState(false);
  const [slidePicker, setSlidePicker] = React.useState(null); // slide index for product pick
  const [splashUrl, setSplashUrl] = React.useState('');
  const splashImgRef = React.useRef(null);
  const heroImgRefs = React.useRef([]);
  const eventImgRefs = React.useRef([]);

  // 로드
  React.useEffect(() => {
    (async () => {
      try {
        const [cloud, prods, stores] = await Promise.all([
          getSettingFromCloud(HOME_CLOUD_KEY),
          typeof getPublished === 'function' ? getPublished() : [],
          typeof getAllStores === 'function' ? getAllStores() : [],
        ]);
        if (cloud) {
          // 구버전 호환: hero 단일 → heroSlides 배열
          if (cloud.hero && !cloud.heroSlides) {
            cloud.heroSlides = [cloud.hero];
            delete cloud.hero;
          }
          setCfg(prev => ({ ...HOME_DEFAULTS, ...cloud }));
        }
        setPubProducts(prods || []);
        setAllStores(stores || []);
        // 스플래시 이미지 로드
        const splashData = await getSettingFromCloud('splash-image');
        if (splashData && splashData.url) setSplashUrl(splashData.url);
      } catch (e) { console.error(e); }
      setLoading(false);
    })();
  }, []);

  const flash = (t) => { setMsg(t); setTimeout(() => setMsg(''), 2500); };
  const updateCfg = (path, val) => {
    setCfg(prev => {
      const next = { ...prev };
      if (path.includes('.')) {
        const [a, b] = path.split('.');
        next[a] = { ...next[a], [b]: val };
      } else {
        next[path] = val;
      }
      return next;
    });
  };

  // 이미지 → base64 리사이즈 (고화질)
  const imgToBase64 = (file, maxW = 1200) => new Promise((res) => {
    const reader = new FileReader();
    reader.onload = () => {
      const img = new Image();
      img.onload = () => {
        const scale = Math.min(1, maxW / img.width);
        const c = document.createElement('canvas');
        c.width = img.width * scale; c.height = img.height * scale;
        c.getContext('2d').drawImage(img, 0, 0, c.width, c.height);
        res(c.toDataURL('image/jpeg', 0.88));
      };
      img.src = reader.result;
    };
    reader.readAsDataURL(file);
  });

  // 히어로 슬라이드 관리 함수들
  const updateSlide = (idx, key, val) => {
    setCfg(prev => {
      const slides = [...(prev.heroSlides || [])];
      slides[idx] = { ...slides[idx], [key]: val };
      return { ...prev, heroSlides: slides };
    });
  };
  const addSlide = () => {
    setCfg(prev => {
      const slides = prev.heroSlides || [];
      if (slides.length >= 10) return prev;
      return { ...prev, heroSlides: [...slides, { image: '', title: '', subtitle: '', productId: '' }] };
    });
  };
  const removeSlide = (idx) => {
    setCfg(prev => ({ ...prev, heroSlides: (prev.heroSlides || []).filter((_, i) => i !== idx) }));
  };
  const moveSlide = (idx, dir) => {
    setCfg(prev => {
      const slides = [...(prev.heroSlides || [])];
      const ni = idx + dir;
      if (ni < 0 || ni >= slides.length) return prev;
      [slides[idx], slides[ni]] = [slides[ni], slides[idx]];
      return { ...prev, heroSlides: slides };
    });
  };
  const handleSlideImg = async (idx, e) => {
    const f = e.target.files?.[0];
    if (!f) return;
    const b64 = await imgToBase64(f);
    updateSlide(idx, 'image', b64);
  };
  const handleSlideFromProduct = (p) => {
    if (slidePicker === null) return;
    updateSlide(slidePicker, 'image', (p.photos || [])[0] || '');
    updateSlide(slidePicker, 'title', p.title || (p.parsed || {}).kr || '');
    updateSlide(slidePicker, 'productId', p.id);
    setSlidePicker(null);
  };

  // 상품 선택 → 특정 필드에 추가
  const handlePickProducts = (field, products) => {
    const items = products.map(p => ({
      id: p.id,
      title: p.title || (p.parsed || {}).kr || (p.parsed || {}).name || '상품',
      photo: (p.photos || [])[0] || '',
      retail: (p.parsed || {}).retail || p.retail || 0,
      brand: (p.parsed || {}).brand || p.brand || '',
    }));
    updateCfg(field, items);
    setPicker(null);
  };

  // 이벤트 수정
  const updateEvent = (idx, key, val) => {
    setCfg(prev => {
      const evts = [...prev.events];
      evts[idx] = { ...evts[idx], [key]: val };
      return { ...prev, events: evts };
    });
  };
  const addEvent = () => {
    setCfg(prev => ({ ...prev, events: [...prev.events, { title: '', body: '', color: '#FF6B35', image: '' }] }));
  };
  const removeEvent = (idx) => {
    setCfg(prev => ({ ...prev, events: prev.events.filter((_, i) => i !== idx) }));
  };
  const handleEventImg = async (idx, e) => {
    const f = e.target.files?.[0];
    if (!f) return;
    const b64 = await imgToBase64(f, 600);
    updateEvent(idx, 'image', b64);
  };

  // 매장 선택
  const handlePickStores = (stores) => {
    updateCfg('newStores', stores.map(s => ({ name: s.name, address: s.address || '' })));
    setStorePicker(false);
  };

  // 스플래시 이미지 업로드
  const handleSplashImg = async (e) => {
    const f = e.target.files?.[0];
    if (!f) return;
    const b64 = await imgToBase64(f, 800);
    setSplashUrl(b64);
    if (splashImgRef.current) splashImgRef.current.value = '';
  };
  const removeSplashImg = () => { setSplashUrl(''); };

  // 저장
  const handleSave = async () => {
    try {
      await saveSettingToCloud(HOME_CLOUD_KEY, cfg);
      // 스플래시 이미지 저장
      await saveSettingToCloud('splash-image', splashUrl ? { url: splashUrl } : null);
      // localStorage도 동기화 (현재 기기 즉시 적용)
      if (splashUrl) localStorage.setItem('wu-splash-image', splashUrl);
      else localStorage.removeItem('wu-splash-image');
      flash('홈 화면 설정이 클라우드에 저장되었습니다');
    } catch (err) {
      alert('저장 실패: ' + err.message);
    }
  };

  // 슬라이드용 상품 선택 피커
  const renderSlidePicker = () => {
    if (slidePicker === null) return null;
    return (
      <div style={{ position: 'fixed', inset: 0, zIndex: 1000, background: 'rgba(0,0,0,0.6)', display: 'flex', alignItems: 'center', justifyContent: 'center' }} onClick={() => setSlidePicker(null)}>
        <div onClick={e => e.stopPropagation()} style={{ width: 640, maxHeight: '80vh', background: 'var(--wu-paper)', boxShadow: '0 20px 60px rgba(0,0,0,0.3)', overflow: 'auto' }}>
          <div style={{ padding: '16px 24px', background: 'var(--wu-ink)', color: '#fff', display: 'flex', justifyContent: 'space-between', alignItems: 'center', position: 'sticky', top: 0, zIndex: 2 }}>
            <div className="display" style={{ fontSize: 16 }}>슬라이드 {slidePicker + 1} — 상품 선택</div>
            <button onClick={() => setSlidePicker(null)} style={{ color: '#fff', background: 'none', border: 'none', fontSize: 18, cursor: 'pointer' }}>×</button>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 8, padding: 16 }}>
            {pubProducts.map(p => {
              const photo = (p.photos || [])[0];
              return (
                <div key={p.id} onClick={() => handleSlideFromProduct(p)} style={{ cursor: 'pointer', border: '1px solid var(--wu-line)', overflow: 'hidden' }}>
                  <div style={{ width: '100%', aspectRatio: '1/1', background: '#E9E5DC' }}>
                    {photo ? <img src={photo} style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> : null}
                  </div>
                  <div style={{ padding: '6px 8px' }}>
                    <div className="kr" style={{ fontSize: 10, fontWeight: 700, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.title || (p.parsed||{}).kr || '상품'}</div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      </div>
    );
  };

  // 상품 선택 피커 컴포넌트
  const renderProductPicker = () => {
    if (!picker) return null;
    const selected = new Set((cfg[picker.field] || []).map(p => p.id));
    const toggleProduct = (p) => {
      const cur = cfg[picker.field] || [];
      if (selected.has(p.id)) {
        handlePickProducts(picker.field, cur.filter(x => x.id !== p.id));
      } else if (cur.length < picker.max) {
        handlePickProducts(picker.field, [...pubProducts.filter(x => [...cur.map(c=>c.id), p.id].includes(x.id))]);
      }
    };
    return (
      <div style={{ position: 'fixed', inset: 0, zIndex: 1000, background: 'rgba(0,0,0,0.6)', display: 'flex', alignItems: 'center', justifyContent: 'center' }} onClick={() => setPicker(null)}>
        <div onClick={e => e.stopPropagation()} style={{ width: 640, maxHeight: '80vh', background: 'var(--wu-paper)', boxShadow: '0 20px 60px rgba(0,0,0,0.3)', overflow: 'auto' }}>
          <div style={{ padding: '16px 24px', background: 'var(--wu-ink)', color: '#fff', display: 'flex', justifyContent: 'space-between', alignItems: 'center', position: 'sticky', top: 0, zIndex: 2 }}>
            <div>
              <div className="display" style={{ fontSize: 16 }}>상품 선택</div>
              <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)' }}>최대 {picker.max}개 · 선택됨 {selected.size}개</div>
            </div>
            <button onClick={() => setPicker(null)} style={{ color: '#fff', background: 'none', border: 'none', fontSize: 18, cursor: 'pointer' }}>×</button>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 8, padding: 16 }}>
            {pubProducts.map(p => {
              const isSelected = selected.has(p.id);
              const photo = (p.photos || [])[0];
              return (
                <div key={p.id} onClick={() => toggleProduct(p)} style={{ cursor: 'pointer', border: isSelected ? '3px solid var(--wu-orange)' : '1px solid var(--wu-line)', overflow: 'hidden', position: 'relative', opacity: !isSelected && selected.size >= picker.max ? 0.4 : 1 }}>
                  <div style={{ width: '100%', aspectRatio: '1/1', background: '#E9E5DC' }}>
                    {photo ? <img src={photo} style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> : <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%' }}><span className="mono" style={{ fontSize: 8, color: 'var(--wu-mute)' }}>NO IMG</span></div>}
                  </div>
                  <div style={{ padding: '6px 8px' }}>
                    <div className="kr" style={{ fontSize: 10, fontWeight: 700, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.title || (p.parsed||{}).kr || '상품'}</div>
                    <div className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>₩{((p.parsed||{}).retail || 0).toLocaleString()}</div>
                  </div>
                  {isSelected && <div style={{ position: 'absolute', top: 4, right: 4, width: 22, height: 22, borderRadius: 999, background: 'var(--wu-orange)', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 12, fontWeight: 700 }}>✓</div>}
                </div>
              );
            })}
          </div>
          {pubProducts.length === 0 && <div className="kr" style={{ padding: 40, textAlign: 'center', color: 'var(--wu-mute)' }}>발행된 상품이 없습니다</div>}
        </div>
      </div>
    );
  };

  // 매장 선택 피커
  const renderStorePicker = () => {
    if (!storePicker) return null;
    const selected = new Set((cfg.newStores || []).map(s => s.name));
    const toggleStore = (s) => {
      const cur = cfg.newStores || [];
      if (selected.has(s.name)) {
        handlePickStores(allStores.filter(x => cur.some(c => c.name === x.name) && x.name !== s.name));
      } else {
        handlePickStores([...allStores.filter(x => [...cur.map(c=>c.name), s.name].includes(x.name))]);
      }
    };
    return (
      <div style={{ position: 'fixed', inset: 0, zIndex: 1000, background: 'rgba(0,0,0,0.6)', display: 'flex', alignItems: 'center', justifyContent: 'center' }} onClick={() => setStorePicker(false)}>
        <div onClick={e => e.stopPropagation()} style={{ width: 500, maxHeight: '70vh', background: 'var(--wu-paper)', boxShadow: '0 20px 60px rgba(0,0,0,0.3)', overflow: 'auto' }}>
          <div style={{ padding: '16px 24px', background: 'var(--wu-ink)', color: '#fff', position: 'sticky', top: 0, zIndex: 2, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <div className="display" style={{ fontSize: 16 }}>신규 매장 선택</div>
            <button onClick={() => setStorePicker(false)} style={{ color: '#fff', background: 'none', border: 'none', fontSize: 18, cursor: 'pointer' }}>×</button>
          </div>
          {allStores.map(s => (
            <div key={s.name} onClick={() => toggleStore(s)} style={{ padding: '12px 24px', display: 'flex', justifyContent: 'space-between', alignItems: 'center', cursor: 'pointer', borderBottom: '1px solid var(--wu-line)', background: selected.has(s.name) ? 'rgba(255,107,53,0.08)' : 'transparent' }}>
              <div>
                <div className="kr" style={{ fontSize: 14, fontWeight: 600 }}>{s.name}</div>
                <div className="kr" style={{ fontSize: 11, color: 'var(--wu-mute)' }}>{s.address || ''}</div>
              </div>
              {selected.has(s.name) && <span style={{ color: 'var(--wu-orange)', fontSize: 16, fontWeight: 700 }}>✓</span>}
            </div>
          ))}
        </div>
      </div>
    );
  };

  // 스타일 상수
  const sectionStyle = { marginBottom: 32, padding: 24, background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', borderRadius: 4 };
  const sectionHead = (title, sub) => (
    <div style={{ marginBottom: 16 }}>
      <div className="display" style={{ fontSize: 18 }}>{title}</div>
      <div className="kr" style={{ fontSize: 11, color: 'var(--wu-mute)', marginTop: 2 }}>{sub}</div>
    </div>
  );
  const inputStyle = { width: '100%', padding: '10px 14px', border: '1.5px solid var(--wu-line)', background: 'var(--wu-bg)', fontSize: 14, outline: 'none', borderRadius: 4, boxSizing: 'border-box' };

  if (loading) return <HQChrome active="home-edit" title="홈 화면 관리" subtitle="HQ · HOME EDITOR"><div style={{ padding: 40, textAlign: 'center' }}><div className="kr" style={{ color: 'var(--wu-mute)' }}>로딩 중...</div></div></HQChrome>;

  return (
    <HQChrome active="home-edit" title="홈 화면 관리" subtitle="HQ · HOME EDITOR">
      {msg && <div style={{ position: 'fixed', top: 16, right: 16, zIndex: 999, padding: '10px 18px', background: 'var(--wu-orange)', color: '#fff', fontFamily: 'Pretendard', fontSize: 13, fontWeight: 700, boxShadow: '0 8px 24px rgba(0,0,0,0.2)' }}>{msg}</div>}
      {renderSlidePicker()}
      {renderProductPicker()}
      {renderStorePicker()}

      <div style={{ padding: 28, maxWidth: 860 }}>

        {/* ═══ 1. 히어로 배너 슬라이드 (최대 10장) ═══ */}
        <div style={sectionStyle}>
          {sectionHead('히어로 배너 슬라이드', '메인 화면 최상단 캐러셀 · 최대 10장 · 자동 슬라이드 + 스와이프')}
          <div className="mono" style={{ fontSize: 11, color: 'var(--wu-orange)', marginBottom: 16, fontWeight: 700 }}>현재 {(cfg.heroSlides || []).length}장 / 최대 10장</div>

          {(cfg.heroSlides || []).map((slide, idx) => (
            <div key={idx} style={{ display: 'flex', gap: 16, padding: 16, background: 'var(--wu-bg)', marginBottom: 12, borderRadius: 6, position: 'relative', border: '1px solid var(--wu-line)' }}>
              {/* 순서 번호 */}
              <div style={{ position: 'absolute', top: -10, left: 12, background: 'var(--wu-ink)', color: 'var(--wu-lime)', padding: '2px 10px', borderRadius: 999, fontSize: 11, fontWeight: 700, fontFamily: 'var(--wu-mono)' }}>{idx + 1}</div>
              {/* 이미지 미리보기 */}
              <div style={{ width: 140, flexShrink: 0 }}>
                <div style={{ width: '100%', aspectRatio: '4/5', background: slide.image ? 'none' : 'var(--wu-ink)', overflow: 'hidden', position: 'relative', borderRadius: 4 }}>
                  {slide.image ? (
                    <img src={slide.image} style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
                  ) : (
                    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%' }}>
                      <span className="mono" style={{ color: 'var(--wu-mute)', fontSize: 10 }}>이미지 없음</span>
                    </div>
                  )}
                </div>
                <div style={{ display: 'flex', gap: 4, marginTop: 6 }}>
                  <label style={{ flex: 1, textAlign: 'center', padding: '6px 4px', background: 'var(--wu-orange)', color: '#fff', fontSize: 10, fontWeight: 700, cursor: 'pointer', borderRadius: 3, fontFamily: 'Pretendard' }}>
                    업로드
                    <input type="file" accept="image/*" onChange={e => handleSlideImg(idx, e)} style={{ display: 'none' }} />
                  </label>
                  <button onClick={() => setSlidePicker(idx)} style={{ flex: 1, padding: '6px 4px', background: 'var(--wu-ink)', color: 'var(--wu-lime)', fontSize: 10, fontWeight: 700, border: 'none', cursor: 'pointer', borderRadius: 3, fontFamily: 'Pretendard' }}>상품선택</button>
                </div>
              </div>
              {/* 텍스트 설정 */}
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ marginBottom: 8 }}>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 3 }}>배너 타이틀</div>
                  <textarea value={slide.title || ''} onChange={e => updateSlide(idx, 'title', e.target.value)} rows={2} className="display" style={{ ...inputStyle, fontSize: 16, lineHeight: 1.2 }} />
                </div>
                <div>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 3 }}>서브타이틀</div>
                  <input value={slide.subtitle || ''} onChange={e => updateSlide(idx, 'subtitle', e.target.value)} className="kr" style={{ ...inputStyle, fontSize: 12 }} />
                </div>
              </div>
              {/* 순서 이동 / 삭제 버튼 */}
              <div style={{ display: 'flex', flexDirection: 'column', gap: 4, flexShrink: 0 }}>
                <button onClick={() => moveSlide(idx, -1)} disabled={idx === 0} style={{ width: 28, height: 28, borderRadius: 4, background: idx === 0 ? 'var(--wu-bg)' : 'var(--wu-ink)', color: idx === 0 ? 'var(--wu-mute)' : '#fff', border: '1px solid var(--wu-line)', cursor: idx === 0 ? 'default' : 'pointer', fontSize: 12 }}>↑</button>
                <button onClick={() => moveSlide(idx, 1)} disabled={idx === (cfg.heroSlides || []).length - 1} style={{ width: 28, height: 28, borderRadius: 4, background: idx === (cfg.heroSlides || []).length - 1 ? 'var(--wu-bg)' : 'var(--wu-ink)', color: idx === (cfg.heroSlides || []).length - 1 ? 'var(--wu-mute)' : '#fff', border: '1px solid var(--wu-line)', cursor: idx === (cfg.heroSlides || []).length - 1 ? 'default' : 'pointer', fontSize: 12 }}>↓</button>
                <div style={{ flex: 1 }} />
                {(cfg.heroSlides || []).length > 1 && (
                  <button onClick={() => removeSlide(idx)} style={{ width: 28, height: 28, borderRadius: 4, background: '#fff', border: '1px solid #C44', color: '#C44', cursor: 'pointer', fontSize: 12 }}>×</button>
                )}
              </div>
            </div>
          ))}

          {(cfg.heroSlides || []).length < 10 && (
            <button onClick={addSlide} style={{ padding: '12px 24px', fontSize: 13, fontWeight: 700, fontFamily: 'Pretendard', background: 'var(--wu-bg)', border: '2px dashed var(--wu-line)', cursor: 'pointer', borderRadius: 4, width: '100%', marginTop: 4 }}>+ 슬라이드 추가 ({(cfg.heroSlides || []).length}/10)</button>
          )}

          {/* 티커 문구는 히어로 섹션 하단에 유지 */}
          <div style={{ marginTop: 20, paddingTop: 16, borderTop: '1px solid var(--wu-line)' }}>
            <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 4 }}>TICKER 문구 (띠 배너)</div>
            <input value={cfg.ticker} onChange={e => updateCfg('ticker', e.target.value)} className="mono" style={{ ...inputStyle, fontSize: 11 }} />
          </div>
        </div>

        {/* ═══ 1.5 상단 메뉴 ═══ */}
        <div style={sectionStyle}>
          {sectionHead('상단 메뉴', '홈 화면 로고 아래 고정되는 카테고리 메뉴 (드래그로 순서 변경, 비어있으면 기본 카테고리 표시)')}
          {/* 현재 선택된 메뉴 */}
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 16 }}>
            {(cfg.topMenus || []).map((m, i) => (
              <div key={m + i} style={{ display: 'flex', alignItems: 'center', gap: 4, padding: '8px 14px', background: 'var(--wu-ink)', color: 'var(--wu-paper)', borderRadius: 999, fontSize: 13, fontWeight: 600, fontFamily: 'var(--wu-kr)' }}>
                {i > 0 && <button onClick={() => {
                  const arr = [...(cfg.topMenus || [])];
                  [arr[i - 1], arr[i]] = [arr[i], arr[i - 1]];
                  updateCfg('topMenus', arr);
                }} style={{ background: 'none', border: 'none', color: 'var(--wu-lime)', cursor: 'pointer', fontSize: 11, padding: 0 }}>←</button>}
                <span>{m}</span>
                {i < (cfg.topMenus || []).length - 1 && <button onClick={() => {
                  const arr = [...(cfg.topMenus || [])];
                  [arr[i], arr[i + 1]] = [arr[i + 1], arr[i]];
                  updateCfg('topMenus', arr);
                }} style={{ background: 'none', border: 'none', color: 'var(--wu-lime)', cursor: 'pointer', fontSize: 11, padding: 0 }}>→</button>}
                <button onClick={() => updateCfg('topMenus', (cfg.topMenus || []).filter((_, j) => j !== i))} style={{ background: 'none', border: 'none', color: 'var(--wu-orange)', cursor: 'pointer', fontSize: 12, padding: '0 0 0 4px', fontWeight: 700 }}>×</button>
              </div>
            ))}
            {(cfg.topMenus || []).length === 0 && (
              <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', padding: '8px 0' }}>선택된 메뉴가 없습니다 (기본 카테고리가 표시됩니다)</div>
            )}
          </div>
          {/* 추가할 수 있는 메뉴 목록 */}
          <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 8, fontWeight: 700, letterSpacing: '0.08em' }}>메뉴 추가 (클릭하여 추가)</div>
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginBottom: 12 }}>
            {(() => {
              const allCats = (typeof WU_DATA !== 'undefined' && WU_DATA.categories) || ['전체', '신상', '긴팔', '반팔', '긴바지', '반바지', '자켓', '조끼', '워크부츠', '슬리퍼', '액세서리', '에이프런'];
              const selected = cfg.topMenus || [];
              return allCats.filter(c => !selected.includes(c)).map(c => (
                <button key={c} onClick={() => updateCfg('topMenus', [...selected, c])} className="kr" style={{ padding: '7px 14px', fontSize: 12, fontWeight: 500, background: 'var(--wu-bg)', border: '1px solid var(--wu-line)', borderRadius: 999, cursor: 'pointer' }}>{c}</button>
              ));
            })()}
          </div>
          {/* 직접 입력으로 커스텀 메뉴 추가 */}
          <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
            <input id="wu-custom-menu-input" placeholder="직접 입력 (예: 여름신상)" className="kr" style={{ ...inputStyle, flex: 1, maxWidth: 200 }} onKeyDown={e => {
              if (e.key === 'Enter' && e.target.value.trim()) {
                const val = e.target.value.trim();
                if (!(cfg.topMenus || []).includes(val)) {
                  updateCfg('topMenus', [...(cfg.topMenus || []), val]);
                }
                e.target.value = '';
              }
            }} />
            <button onClick={() => {
              const inp = document.getElementById('wu-custom-menu-input');
              if (inp && inp.value.trim()) {
                const val = inp.value.trim();
                if (!(cfg.topMenus || []).includes(val)) {
                  updateCfg('topMenus', [...(cfg.topMenus || []), val]);
                }
                inp.value = '';
              }
            }} style={{ padding: '10px 16px', background: 'var(--wu-ink)', color: 'var(--wu-lime)', border: 'none', cursor: 'pointer', borderRadius: 4, fontSize: 12, fontWeight: 700, fontFamily: 'Pretendard' }}>추가</button>
          </div>
        </div>

        {/* ═══ 2. 신제품 NEW DROPS ═══ */}
        <div style={sectionStyle}>
          {sectionHead('신제품 · NEW DROPS', '메인 화면에 표시할 신상품 6개를 발행상품에서 선택')}
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 12 }}>
            {(cfg.newProducts || []).map((p, i) => (
              <div key={p.id || i} style={{ width: 120, position: 'relative', border: '1px solid var(--wu-line)', overflow: 'hidden', borderRadius: 4 }}>
                <div style={{ aspectRatio: '4/5', background: '#E9E5DC' }}>
                  {p.photo ? <img src={p.photo} style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> : null}
                </div>
                <div style={{ padding: '6px 8px' }}>
                  <div className="kr" style={{ fontSize: 10, fontWeight: 700, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.title}</div>
                  <div className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>₩{(p.retail || 0).toLocaleString()}</div>
                </div>
                <button onClick={() => updateCfg('newProducts', cfg.newProducts.filter((_, j) => j !== i))} style={{ position: 'absolute', top: 2, right: 2, width: 18, height: 18, borderRadius: 999, background: 'rgba(0,0,0,0.6)', color: '#fff', border: 'none', cursor: 'pointer', fontSize: 10 }}>×</button>
              </div>
            ))}
            {(cfg.newProducts || []).length < 6 && (
              <button onClick={() => setPicker({ field: 'newProducts', max: 6 })} style={{ width: 120, aspectRatio: '3/4', border: '2px dashed var(--wu-line)', background: 'var(--wu-bg)', cursor: 'pointer', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', borderRadius: 4 }}>
                <span style={{ fontSize: 24, color: 'var(--wu-mute)' }}>+</span>
                <span className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>상품 선택</span>
              </button>
            )}
          </div>
        </div>

        {/* ═══ 3. 베스트 상품 BEST ═══ */}
        <div style={sectionStyle}>
          {sectionHead('베스트 상품 · BEST', '인기 상품 6개를 발행상품에서 선택')}
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 12 }}>
            {(cfg.bestProducts || []).map((p, i) => (
              <div key={p.id || i} style={{ width: 120, position: 'relative', border: '1px solid var(--wu-line)', overflow: 'hidden', borderRadius: 4 }}>
                <div style={{ aspectRatio: '4/5', background: '#E9E5DC' }}>
                  {p.photo ? <img src={p.photo} style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> : null}
                </div>
                <div style={{ padding: '6px 8px' }}>
                  <div className="kr" style={{ fontSize: 10, fontWeight: 700, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.title}</div>
                  <div className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>₩{(p.retail || 0).toLocaleString()}</div>
                </div>
                <button onClick={() => updateCfg('bestProducts', cfg.bestProducts.filter((_, j) => j !== i))} style={{ position: 'absolute', top: 2, right: 2, width: 18, height: 18, borderRadius: 999, background: 'rgba(0,0,0,0.6)', color: '#fff', border: 'none', cursor: 'pointer', fontSize: 10 }}>×</button>
              </div>
            ))}
            {(cfg.bestProducts || []).length < 6 && (
              <button onClick={() => setPicker({ field: 'bestProducts', max: 6 })} style={{ width: 120, aspectRatio: '3/4', border: '2px dashed var(--wu-line)', background: 'var(--wu-bg)', cursor: 'pointer', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', borderRadius: 4 }}>
                <span style={{ fontSize: 24, color: 'var(--wu-mute)' }}>+</span>
                <span className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>상품 선택</span>
              </button>
            )}
          </div>
        </div>

        {/* ═══ 4. 이벤트 ═══ */}
        <div style={sectionStyle}>
          {sectionHead('이벤트 · EVENTS', '홈 화면에 표시할 이벤트 카드')}
          {(cfg.events || []).map((evt, i) => (
            <div key={i} style={{ display: 'flex', gap: 12, padding: 14, background: 'var(--wu-bg)', marginBottom: 10, borderRadius: 4, position: 'relative' }}>
              <div style={{ width: 80, height: 80, flexShrink: 0, background: evt.image ? 'none' : (evt.color || '#E9E5DC'), borderRadius: 4, overflow: 'hidden', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                {evt.image ? <img src={evt.image} style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> : (
                  <label style={{ cursor: 'pointer', textAlign: 'center' }}>
                    <span className="mono" style={{ fontSize: 8, color: '#fff' }}>이미지<br/>추가</span>
                    <input type="file" accept="image/*" onChange={e => handleEventImg(i, e)} style={{ display: 'none' }} />
                  </label>
                )}
              </div>
              <div style={{ flex: 1 }}>
                <input value={evt.title} onChange={e => updateEvent(i, 'title', e.target.value)} placeholder="이벤트 제목" className="kr" style={{ ...inputStyle, fontSize: 14, fontWeight: 700, marginBottom: 6 }} />
                <input value={evt.body} onChange={e => updateEvent(i, 'body', e.target.value)} placeholder="이벤트 설명" className="kr" style={{ ...inputStyle, fontSize: 12 }} />
                <div style={{ display: 'flex', gap: 6, marginTop: 6, alignItems: 'center' }}>
                  <span className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>색상:</span>
                  <input type="color" value={evt.color || '#FF6B35'} onChange={e => updateEvent(i, 'color', e.target.value)} style={{ width: 24, height: 24, border: 'none', cursor: 'pointer', padding: 0 }} />
                  {evt.image && <button onClick={() => updateEvent(i, 'image', '')} className="mono" style={{ fontSize: 9, color: '#C44', background: 'none', border: 'none', cursor: 'pointer' }}>이미지 제거</button>}
                </div>
              </div>
              <button onClick={() => removeEvent(i)} style={{ position: 'absolute', top: 6, right: 6, width: 20, height: 20, borderRadius: 999, background: 'var(--wu-paper)', border: '1px solid #C44', color: '#C44', cursor: 'pointer', fontSize: 10 }}>×</button>
            </div>
          ))}
          <button onClick={addEvent} style={{ padding: '10px 20px', fontSize: 12, fontWeight: 700, fontFamily: 'Pretendard', background: 'var(--wu-bg)', border: '1.5px dashed var(--wu-line)', cursor: 'pointer', borderRadius: 4, width: '100%' }}>+ 이벤트 추가</button>
        </div>

        {/* ═══ 5. 신규 매장 ═══ */}
        <div style={sectionStyle}>
          {sectionHead('신규 매장 · NEW STORES', '홈 화면에 표시할 신규/추천 매장')}
          {(cfg.newStores || []).length > 0 && (
            <div style={{ marginBottom: 12 }}>
              {cfg.newStores.map((s, i) => (
                <div key={i} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '8px 12px', background: 'var(--wu-bg)', marginBottom: 4, borderRadius: 4 }}>
                  <div>
                    <span className="kr" style={{ fontSize: 14, fontWeight: 700 }}>{s.name}</span>
                    <span className="kr" style={{ fontSize: 11, color: 'var(--wu-mute)', marginLeft: 8 }}>{s.address}</span>
                  </div>
                  <button onClick={() => updateCfg('newStores', cfg.newStores.filter((_, j) => j !== i))} style={{ background: 'none', border: 'none', color: '#C44', cursor: 'pointer', fontSize: 12 }}>✕</button>
                </div>
              ))}
            </div>
          )}
          <button onClick={() => setStorePicker(true)} style={{ padding: '10px 20px', fontSize: 12, fontWeight: 700, fontFamily: 'Pretendard', background: 'var(--wu-ink)', color: 'var(--wu-lime)', border: 'none', cursor: 'pointer', borderRadius: 4 }}>매장 선택</button>
        </div>

        {/* ═══ 6. 로딩 화면 이미지 ═══ */}
        <div style={sectionStyle}>
          {sectionHead('로딩 화면 이미지', '앱 접속 시 처음 보이는 스플래시 화면 · 이미지를 설정하지 않으면 기본 로고 표시')}
          <div style={{ display: 'flex', gap: 20, alignItems: 'flex-start', flexWrap: 'wrap' }}>
            {/* 미리보기 — 폰 비율 */}
            <div style={{ width: 180, flexShrink: 0 }}>
              <div style={{ width: '100%', aspectRatio: '9/16', background: '#0E0E0C', overflow: 'hidden', borderRadius: 12, position: 'relative', display: 'flex', alignItems: 'center', justifyContent: 'center', border: '2px solid #333' }}>
                {splashUrl ? (
                  <img src={splashUrl} style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
                ) : (
                  <div style={{ textAlign: 'center' }}>
                    <svg width="54" height="27" viewBox="0 0 180 60"><text x="0" y="48" fill="#F4F1EC" fontFamily="Arial,sans-serif" fontSize="48" fontWeight="900" letterSpacing="-2">work</text><text x="108" y="48" fill="#FF6B35" fontFamily="Arial,sans-serif" fontSize="48" fontWeight="900" letterSpacing="-2">up</text></svg>
                    <div className="mono" style={{ fontSize: 9, color: '#555', marginTop: 8 }}>기본 로고</div>
                  </div>
                )}
              </div>
              <div className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)', textAlign: 'center', marginTop: 6 }}>실제 로딩 화면 미리보기</div>
            </div>
            {/* 설정 영역 */}
            <div style={{ flex: 1, minWidth: 200 }}>
              <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>
                <label style={{ flex: 1, textAlign: 'center', padding: '12px', background: 'var(--wu-orange)', color: '#fff', fontSize: 13, fontWeight: 700, cursor: 'pointer', borderRadius: 6, fontFamily: 'Pretendard' }}>
                  이미지 업로드
                  <input ref={splashImgRef} type="file" accept="image/*" onChange={handleSplashImg} style={{ display: 'none' }} />
                </label>
                {splashUrl && (
                  <button onClick={removeSplashImg} style={{ padding: '12px 20px', background: '#fff', border: '1px solid #C44', color: '#C44', fontSize: 13, fontWeight: 700, cursor: 'pointer', borderRadius: 6, fontFamily: 'Pretendard' }}>제거</button>
                )}
              </div>
              <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', lineHeight: 1.6 }}>
                {splashUrl ? '이미지가 설정되었습니다. 저장 후 다음 접속부터 적용됩니다.' : '이미지를 업로드하면 로딩 화면에 기본 로고 대신 선택한 이미지가 전체 화면으로 표시됩니다.'}
              </div>
              <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginTop: 8 }}>권장: 세로 이미지 (9:16 비율) · 최대 800px 리사이즈</div>
            </div>
          </div>
        </div>

        {/* 저장 버튼 */}
        <div style={{ display: 'flex', gap: 10, marginTop: 8 }}>
          <button onClick={handleSave} style={{ flex: 1, padding: '16px', fontSize: 16, fontWeight: 700, fontFamily: 'Pretendard', background: 'var(--wu-orange)', color: '#fff', border: 'none', cursor: 'pointer', borderRadius: 4 }}>클라우드에 저장</button>
        </div>
      </div>
    </HQChrome>
  );
}

Object.assign(window, { HQPublishedList, HQStoreManager, HQBoard, HQHomeEditor, KakaoMapEmbed, getAllPosts, savePost, deletePost, BOARD_CATEGORIES });
