// Consumer events + wishlist + signup screens
function ConsumerEvents({ variant = 'pill' }) {
  const [mode, setMode] = useState('list');
  return (
    <div className="wu wu-scroll wu-consumer-wrap" style={{ height: '100%', overflow: 'auto', background: 'var(--wu-bg)', paddingBottom: 70 }}>
      <div style={{ padding: 'calc(env(safe-area-inset-top, 20px) + 12px) 16px 8px', display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
        <div>
          <div className="display" style={{ fontSize: 32 }}>EVENTS</div>
          <div className="kr mono" style={{ fontSize: 11, color: 'var(--wu-mute)' }}>이벤트 · 프로모션 · 공지</div>
        </div>
        <div style={{ display: 'flex', background: '#fff', borderRadius: 999, padding: 3, border: '1px solid var(--wu-line)' }}>
          {[['list', '목록'], ['cal', '캘린더']].map(([k, l]) => (
            <button key={k} onClick={() => setMode(k)} className="kr" style={{ padding: '6px 12px', borderRadius: 999, fontSize: 11, fontWeight: 700, background: mode === k ? 'var(--wu-ink)' : 'transparent', color: mode === k ? 'var(--wu-paper)' : 'var(--wu-mute)' }}>{l}</button>
          ))}
        </div>
      </div>

      {mode === 'list' ? (
        <div style={{ padding: '12px 16px', display: 'flex', flexDirection: 'column', gap: 14 }}>
          {WU_DATA.events.map((e, i) => (
            <div key={e.id} style={{ background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', overflow: 'hidden' }}>
              <div style={{ display: 'flex', background: e.color, color: e.color === '#D6FF3D' || e.color === '#8B7355' ? 'var(--wu-ink)' : 'var(--wu-paper)', padding: 14 }}>
                <div style={{ flex: 1 }}>
                  <div className="mono" style={{ fontSize: 10, opacity: 0.7 }}>{['CAMPAIGN', 'DROP', 'POPUP', 'CONFERENCE'][i]}</div>
                  <div className="display" style={{ fontSize: 28, marginTop: 4 }}>{e.date}</div>
                </div>
                <div className="display" style={{ fontSize: 32, alignSelf: 'flex-end', opacity: 0.3 }}>{String(i + 1).padStart(2, '0')}</div>
              </div>
              <div style={{ padding: 14 }}>
                <div className="kr" style={{ fontSize: 15, fontWeight: 700 }}>{e.kr}</div>
                <div className="kr mono" style={{ fontSize: 11, color: 'var(--wu-mute)', marginTop: 6 }}>📍 {e.where}</div>
                <div style={{ display: 'flex', gap: 6, marginTop: 12 }}>
                  <button className="wu-btn" style={{ flex: 1, fontSize: 11, padding: '10px' }}>자세히</button>
                  <button className="wu-btn ghost" style={{ flex: 1, fontSize: 11, padding: '10px' }}>알림 설정</button>
                </div>
              </div>
            </div>
          ))}
        </div>
      ) : (
        <div style={{ padding: '12px 16px' }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '12px 4px' }}>
            <div className="display" style={{ fontSize: 18 }}>NOV 2026</div>
            <div style={{ display: 'flex', gap: 6 }}>
              <button style={{ width: 28, height: 28, borderRadius: 999, background: '#fff', border: '1px solid var(--wu-line)' }}>‹</button>
              <button style={{ width: 28, height: 28, borderRadius: 999, background: '#fff', border: '1px solid var(--wu-line)' }}>›</button>
            </div>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 1, background: 'var(--wu-line)', border: '1px solid var(--wu-line)' }}>
            {['일','월','화','수','목','금','토'].map(d => (
              <div key={d} className="kr" style={{ background: 'var(--wu-paper)', padding: 6, textAlign: 'center', fontSize: 10, color: 'var(--wu-mute)' }}>{d}</div>
            ))}
            {Array.from({ length: 35 }, (_, i) => {
              const day = i - 5;
              const inMonth = day > 0 && day <= 30;
              const hasEvent = [15, 22].includes(day);
              const eventColor = day === 15 ? '#FF5A1F' : day === 22 ? '#D6FF3D' : null;
              return (
                <div key={i} style={{ background: 'var(--wu-paper)', padding: '8px 4px', minHeight: 48, position: 'relative', opacity: inMonth ? 1 : 0.25 }}>
                  <div className="mono" style={{ fontSize: 11, fontWeight: hasEvent ? 700 : 400 }}>{inMonth ? day : ''}</div>
                  {hasEvent && <div style={{ position: 'absolute', bottom: 4, left: 4, right: 4, height: 4, background: eventColor }} />}
                </div>
              );
            })}
          </div>
        </div>
      )}
    </div>
  );
}

// ────────────────────────────────────────────────────
// Consumer WISHLIST
// ────────────────────────────────────────────────────
function ConsumerWishlist({ variant = 'pill' }) {
  const [favIds, setFavIds] = useState(() => { try { return JSON.parse(localStorage.getItem('wu-favorites') || '[]'); } catch { return []; } });
  const [allProducts, setAllProducts] = useState([]);
  const [filter, setFilter] = useState('전체');
  const [loading, setLoading] = useState(true);

  // 발행 상품 로드
  React.useEffect(() => {
    const fn = typeof getPublished === 'function' ? getPublished : (typeof getPublishedProducts === 'function' ? getPublishedProducts : null);
    if (fn) {
      fn().then(list => { setAllProducts(list || []); setLoading(false); }).catch(() => setLoading(false));
    } else { setLoading(false); }
  }, []);

  // localStorage 변경 감지 (다른 화면에서 즐겨찾기 변경 시)
  React.useEffect(() => {
    const sync = () => { try { setFavIds(JSON.parse(localStorage.getItem('wu-favorites') || '[]')); } catch {} };
    window.addEventListener('storage', sync);
    const timer = setInterval(sync, 1000); // 같은 탭 내 변경도 감지
    return () => { window.removeEventListener('storage', sync); clearInterval(timer); };
  }, []);

  // 즐겨찾기 상품만 필터
  const favProducts = allProducts.filter(p => {
    const pid = p.id || (p.parsed && p.parsed.code) || p.title || '';
    return favIds.includes(pid);
  });

  // 카테고리별 분류
  const getCat = (p) => {
    const cat = p.parsed?.category || p.category || '';
    if (!cat) return '기타';
    return cat;
  };
  const catCounts = {};
  favProducts.forEach(p => {
    const c = getCat(p);
    catCounts[c] = (catCounts[c] || 0) + 1;
  });
  const catList = ['전체', ...Object.keys(catCounts).sort()];
  const filtered = filter === '전체' ? favProducts : favProducts.filter(p => getCat(p) === filter);

  // 즐겨찾기 해제
  const removeFav = (pid) => {
    const next = favIds.filter(id => id !== pid);
    localStorage.setItem('wu-favorites', JSON.stringify(next));
    setFavIds(next);
  };

  return (
    <div className="wu wu-scroll wu-consumer-wrap" style={{ height: '100%', overflow: 'auto', background: 'var(--wu-bg)', paddingBottom: 70 }}>
      <div style={{ padding: 'calc(env(safe-area-inset-top, 20px) + 12px) 16px 8px' }}>
        <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)' }}>MY · 관심 상품 {favProducts.length}</div>
        <div className="display" style={{ fontSize: 32, marginTop: 4 }}>좋아요</div>
      </div>

      {/* 카테고리 필터 */}
      <div style={{ display: 'flex', gap: 6, padding: '8px 16px 16px', overflowX: 'auto' }} className="wu-scroll">
        {catList.map(c => (
          <WuChip key={c} active={filter === c} onClick={() => setFilter(c)}>
            {c === '전체' ? '전체 ' + favProducts.length : c + ' ' + (catCounts[c] || 0)}
          </WuChip>
        ))}
      </div>

      {loading ? (
        <div style={{ textAlign: 'center', padding: 40 }}>
          <div className="kr" style={{ fontSize: 13, color: 'var(--wu-mute)' }}>불러오는 중...</div>
        </div>
      ) : filtered.length === 0 ? (
        <div style={{ textAlign: 'center', padding: '60px 20px' }}>
          <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="var(--wu-line)" strokeWidth="1.5"><path d="M12 21C12 21 3 13.5 3 8.5 3 5.42 5.42 3 8.5 3c1.74 0 3.41.81 4.5 2.09C14.09 3.81 15.76 3 17.5 3 20.58 3 23 5.42 23 8.5 23 13.5 12 21 12 21z"/></svg>
          <div className="kr" style={{ fontSize: 15, fontWeight: 700, marginTop: 16, color: 'var(--wu-ink)' }}>
            {favProducts.length === 0 ? '좋아요한 상품이 없습니다' : '이 카테고리에 상품이 없습니다'}
          </div>
          <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginTop: 6 }}>
            상품 상세 페이지에서 하트를 눌러 추가해보세요
          </div>
          {favProducts.length === 0 && (
            <button onClick={() => { if (window.__switchTab) window.__switchTab('home'); }} className="wu-btn lime" style={{ marginTop: 20 }}>
              상품 둘러보기 →
            </button>
          )}
        </div>
      ) : (
        <div className="wu-grid-products" style={{ display: 'flex', flexWrap: 'wrap', padding: '0 16px', gap: 10 }}>
          {filtered.map(p => {
            const pid = p.id || (p.parsed && p.parsed.code) || p.title || '';
            const title = p.parsed?.name || p.parsed?.kr || p.kr || p.title || '상품';
            const brand = p.parsed?.brand || p.brand || '';
            const retail = p.parsed?.retail || p.retail;
            const photo = p.photos?.[0];
            return (
              <div key={pid} style={{ width: 'calc(50% - 5px)', position: 'relative' }}>
                <button onClick={() => { if (window.__showProductDetail) window.__showProductDetail(p); }} style={{ textAlign: 'left', cursor: 'pointer', background: 'none', border: 'none', padding: 0, width: '100%' }}>
                  <div style={{ width: '100%', height: 0, paddingBottom: '125%', position: 'relative', background: photo ? '#f0f0f0' : 'linear-gradient(160deg, #E9E5DC, #DCD7CC)', overflow: 'hidden', borderRadius: 4 }}>
                    {photo && <img src={photo} loading="lazy" style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', objectFit: 'cover' }} />}
                  </div>
                  <div style={{ padding: '8px 2px 4px' }}>
                    {brand && <div className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)', letterSpacing: '0.06em' }}>{brand}</div>}
                    <div className="kr" style={{ fontSize: 13, fontWeight: 700, marginTop: 2, lineHeight: 1.3, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{title}</div>
                    {retail && <div className="display" style={{ fontSize: 14, marginTop: 2 }}>₩{Number(retail).toLocaleString()}</div>}
                  </div>
                </button>
                {/* 좋아요 해제 버튼 */}
                <button onClick={() => removeFav(pid)} style={{ position: 'absolute', top: 8, right: 8, width: 32, height: 32, borderRadius: 999, background: 'rgba(0,0,0,0.3)', border: 'none', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="#FF6600" stroke="#FF6600" strokeWidth="2"><path d="M12 21C12 21 3 13.5 3 8.5 3 5.42 5.42 3 8.5 3c1.74 0 3.41.81 4.5 2.09C14.09 3.81 15.76 3 17.5 3 20.58 3 23 5.42 23 8.5 23 13.5 12 21 12 21z"/></svg>
                </button>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

// ────────────────────────────────────────────────────
// Signup (consumer) — quick email
// ────────────────────────────────────────────────────
function SignupConsumer() {
  return (
    <div className="wu" style={{ height: '100%', background: 'var(--wu-bg)', padding: 'calc(env(safe-area-inset-top, 20px) + 12px) 20px 24px', display: 'flex', flexDirection: 'column' }}>
      <button style={{ alignSelf: 'flex-start', fontSize: 20, marginBottom: 24 }}>←</button>
      <WuLogo size={28} />
      <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginTop: 24 }}>STEP 01 / 02 · 일반회원</div>
      <div className="display" style={{ fontSize: 40, marginTop: 8, lineHeight: 0.95 }}>JOIN<br/>WORKUP.</div>
      <div className="kr" style={{ fontSize: 13, color: 'var(--wu-mute)', marginTop: 10, lineHeight: 1.5 }}>이메일만 입력하면 끝. 인증 후<br/>바로 쇼핑을 시작할 수 있어요.</div>

      <div style={{ marginTop: 32, display: 'flex', flexDirection: 'column', gap: 14 }}>
        <div>
          <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', letterSpacing: '0.08em', marginBottom: 6 }}>EMAIL</div>
          <div style={{ borderBottom: '1.5px solid var(--wu-ink)', padding: '8px 0', display: 'flex', alignItems: 'center', gap: 8 }}>
            <input className="kr" defaultValue="hello@" style={{ flex: 1, border: 0, outline: 0, background: 'transparent', fontSize: 18, fontWeight: 600 }} />
            <span className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)' }}>@gmail.com</span>
          </div>
        </div>
        <div>
          <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', letterSpacing: '0.08em', marginBottom: 6 }}>비밀번호</div>
          <div style={{ borderBottom: '1.5px solid var(--wu-line)', padding: '8px 0' }}>
            <input type="password" defaultValue="••••••••" className="kr" style={{ width: '100%', border: 0, outline: 0, background: 'transparent', fontSize: 18, fontWeight: 600 }} />
          </div>
        </div>
        <div>
          <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', letterSpacing: '0.08em', marginBottom: 6 }}>닉네임 · OPTIONAL</div>
          <div style={{ borderBottom: '1.5px solid var(--wu-line)', padding: '8px 0' }}>
            <input placeholder="workup.lover" className="kr" style={{ width: '100%', border: 0, outline: 0, background: 'transparent', fontSize: 18, fontWeight: 600 }} />
          </div>
        </div>
      </div>

      <div style={{ marginTop: 20, display: 'flex', alignItems: 'flex-start', gap: 10 }}>
        <div style={{ width: 18, height: 18, border: '1.5px solid var(--wu-ink)', background: 'var(--wu-ink)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, marginTop: 2 }}>
          <svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="var(--wu-lime)" strokeWidth="2"><path d="M2 5l2 2 4-4"/></svg>
        </div>
        <div className="kr" style={{ fontSize: 11, color: 'var(--wu-mute)', lineHeight: 1.5 }}>이용약관 · 개인정보처리방침에 동의합니다. 마케팅 수신은 선택입니다.</div>
      </div>

      <div style={{ flex: 1 }} />
      <button className="wu-btn lime block">가입 완료 →</button>
      <div className="kr" style={{ textAlign: 'center', fontSize: 11, color: 'var(--wu-mute)', marginTop: 14 }}>점주이신가요? <span style={{ color: 'var(--wu-ink)', fontWeight: 700, borderBottom: '1px solid' }}>점주 가입 →</span></div>
    </div>
  );
}

// ────────────────────────────────────────────────────
// Signup pending (store owner)
// ────────────────────────────────────────────────────
function SignupOwnerPending() {
  return (
    <div className="wu" style={{ height: '100%', background: 'var(--wu-ink)', color: 'var(--wu-paper)', padding: 'calc(env(safe-area-inset-top, 20px) + 12px) 20px 24px', display: 'flex', flexDirection: 'column' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between' }}>
        <WuLogo size={22} color="var(--wu-paper)" />
        <span className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)' }}>OWNER · REVIEW</span>
      </div>

      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', textAlign: 'center' }}>
        {/* Animated badge */}
        <div style={{ width: 140, height: 140, borderRadius: 999, border: '1.5px dashed var(--wu-lime)', display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative' }}>
          <div style={{ width: 108, height: 108, borderRadius: 999, background: 'var(--wu-lime)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <svg width="36" height="36" viewBox="0 0 36 36" fill="none" stroke="var(--wu-ink)" strokeWidth="2.4" strokeLinecap="round">
              <circle cx="18" cy="18" r="14"/>
              <path d="M18 10v8l5 3"/>
            </svg>
          </div>
          <div style={{ position: 'absolute', top: -4, right: -4, background: 'var(--wu-orange)', color: '#fff', padding: '3px 8px', fontSize: 10, fontFamily: 'JetBrains Mono', fontWeight: 600 }}>PENDING</div>
        </div>

        <div className="mono" style={{ fontSize: 11, color: 'var(--wu-lime)', letterSpacing: '0.12em', marginTop: 32 }}>REQUEST SUBMITTED</div>
        <div className="display" style={{ fontSize: 40, marginTop: 10, lineHeight: 0.95, color: 'var(--wu-paper)' }}>심사중<br/>입니다.</div>
        <div className="kr" style={{ fontSize: 14, color: 'rgba(255,255,255,0.7)', marginTop: 14, lineHeight: 1.6, maxWidth: 280 }}>점주 회원가입은 본사 관리자 승인 후 활성화됩니다. 영업일 기준 1–2일 소요돼요.</div>

        <div style={{ marginTop: 28, width: '100%', background: '#1A1A17', padding: 16, textAlign: 'left', borderLeft: '3px solid var(--wu-lime)' }}>
          <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 8 }}>REQUEST #WU-2026-0147</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '6px 14px', fontSize: 12 }}>
            <span style={{ color: 'var(--wu-mute)' }} className="kr">상호</span><span className="kr">서면 워크웨어</span>
            <span style={{ color: 'var(--wu-mute)' }} className="kr">대표자</span><span className="kr">최다은</span>
            <span style={{ color: 'var(--wu-mute)' }} className="kr">사업자번호</span><span className="mono">312-88-02417</span>
            <span style={{ color: 'var(--wu-mute)' }} className="kr">제출일</span><span className="mono">2026.04.21 14:02</span>
          </div>
        </div>
      </div>

      <div style={{ display: 'flex', gap: 8 }}>
        <button className="wu-btn ghost block" style={{ borderColor: 'var(--wu-paper)', color: 'var(--wu-paper)' }}>로그아웃</button>
        <button className="wu-btn lime block">일반회원으로 둘러보기</button>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────
// Consumer SHOP — 무신사 스타일 쇼핑 내비게이션
// ────────────────────────────────────────────────────
function ConsumerShop({ variant = 'pill' }) {
  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(true);
  const [navTab, setNavTab] = useState('category'); // category, brand, new, featured, ranking, soldout
  const [showSearch, setShowSearch] = useState(false);
  const [searchQuery, setSearchQuery] = useState('');
  const [searchResults, setSearchResults] = useState(null);
  const [activeCat, setActiveCat] = useState('전체');
  const [genderFilter, setGenderFilter] = useState('전체');
  const [brandSearch, setBrandSearch] = useState('');
  const [activeBrandConsonant, setActiveBrandConsonant] = useState('인기');
  const [selectedBrand, setSelectedBrand] = useState(null);
  const searchInputRef = React.useRef(null);

  useEffect(() => {
    if (typeof getPublished === 'function') {
      getPublished().then(list => { setItems(list); setLoading(false); }).catch(() => setLoading(false));
    } else { setLoading(false); }
  }, []);

  // 홈 카테고리 칩에서 넘어온 경우 해당 카테고리로 바로 이동
  useEffect(() => {
    const checkPending = () => {
      if (window.__pendingShopCategory) {
        const cat = window.__pendingShopCategory;
        delete window.__pendingShopCategory;
        if (cat === '전체') {
          setNavTab('category');
          setActiveCat('전체');
        } else if (cat === '신상') {
          setNavTab('new');
        } else {
          setNavTab('category');
          setActiveCat(cat);
        }
        setSelectedBrand(null);
        setShowSearch(false);
        setSearchResults(null);
      }
    };
    checkPending();
    // 탭 전환 시에도 체크하도록 visibility change 이벤트 대신 interval 사용
    const timer = setInterval(checkPending, 300);
    return () => clearInterval(timer);
  }, []);

  // ── 헬퍼 ──
  const getField = (p, ...keys) => {
    const parsed = p.parsed || {};
    for (const k of keys) { if (parsed[k]) return parsed[k]; if (p[k]) return p[k]; }
    return '';
  };
  const getTitle = (p) => getField(p, 'kr', 'name') || p.title || '상품';
  const getBrand = (p) => getField(p, 'brand') || '';
  const getRetail = (p) => { const r = (p.parsed || {}).retail || p.retail; return typeof r === 'number' ? r : parseInt(String(r || '0').replace(/[,\s원]/g, ''), 10) || 0; };
  const getPhoto = (p) => (p.photos || [])[0] || '';
  const getCats = (p) => { const c = (p.parsed || {}).category || p.category || ''; return Array.isArray(c) ? c : c ? [c] : []; };
  const getDaysAgo = (p) => { const d = p.publishedAt || p.createdAt; if (!d) return 9999; return (Date.now() - new Date(d).getTime()) / 86400000; };

  // ── 카테고리 목록 (사이드바) — WU_DATA.categories + parts 기반 ──
  const sidebarCats = React.useMemo(() => {
    const base = ['전체', '상의', '하의', '아우터', '풋웨어', '액세서리'];
    // 기본 카테고리 추가
    const allC = (typeof WU_DATA !== 'undefined' && WU_DATA.categories) ? WU_DATA.categories.filter(c => c !== '전체' && c !== '신상') : ['긴팔', '반팔', '긴바지', '반바지', '자켓', '조끼', '워크부츠', '슬리퍼', '에이프런'];
    allC.forEach(c => { if (!base.includes(c)) base.push(c); });
    // 실제 상품에서 카테고리/브랜드 추출하여 추가
    const dynCats = {};
    const dynBrands = {};
    items.forEach(p => {
      const parsed = p.parsed || {};
      const cats = parsed.category || p.category || '';
      const catArr = Array.isArray(cats) ? cats : cats ? [cats] : [];
      catArr.forEach(c => { if (c && !base.includes(c)) dynCats[c] = (dynCats[c] || 0) + 1; });
      const parts = parsed.parts || p.parts || [];
      const partsArr = Array.isArray(parts) ? parts : parts ? [parts] : [];
      partsArr.forEach(pt => { if (pt && !base.includes(pt)) dynCats[pt] = (dynCats[pt] || 0) + 1; });
      const brand = parsed.brand || p.brand || '';
      if (brand) dynBrands[brand] = (dynBrands[brand] || 0) + 1;
    });
    Object.entries(dynCats).sort((a, b) => b[1] - a[1]).forEach(([c]) => { if (!base.includes(c)) base.push(c); });
    // 인기 브랜드를 카테고리 목록에도 추가
    Object.entries(dynBrands).sort((a, b) => b[1] - a[1]).forEach(([b]) => { if (!base.includes(b)) base.push(b); });
    return base;
  }, [items]);

  // ── 브랜드 목록 (상품에서 추출) ──
  const allBrands = React.useMemo(() => {
    const map = {};
    items.forEach(p => {
      const b = getBrand(p);
      if (b) { if (!map[b]) map[b] = 0; map[b]++; }
    });
    return Object.entries(map).sort((a, b) => b[1] - a[1]).map(([name, count]) => ({ name, count }));
  }, [items]);

  // 한글 초성 추출
  const getChosung = (str) => {
    const cho = ['ㄱ','ㄲ','ㄴ','ㄷ','ㄸ','ㄹ','ㅁ','ㅂ','ㅃ','ㅅ','ㅆ','ㅇ','ㅈ','ㅉ','ㅊ','ㅋ','ㅌ','ㅍ','ㅎ'];
    const c = str.charCodeAt(0);
    if (c >= 0xAC00 && c <= 0xD7A3) return cho[Math.floor((c - 0xAC00) / 588)];
    if (/[A-Za-z]/.test(str[0])) return str[0].toUpperCase();
    return '기타';
  };
  const consonants = ['인기', 'ㄱ', 'ㄴ', 'ㄷ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅅ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ', 'A-Z'];

  const filteredBrands = React.useMemo(() => {
    let list = allBrands;
    if (brandSearch) {
      const q = brandSearch.toLowerCase();
      list = list.filter(b => b.name.toLowerCase().includes(q));
    } else if (activeBrandConsonant === '인기') {
      // top 20 by count
      list = list.slice(0, 20);
    } else if (activeBrandConsonant === 'A-Z') {
      list = list.filter(b => /^[A-Za-z]/.test(b.name));
    } else {
      list = list.filter(b => getChosung(b.name) === activeBrandConsonant);
    }
    return list;
  }, [allBrands, brandSearch, activeBrandConsonant]);

  // ── 검색 기록 (localStorage) ──
  const SEARCH_KEY = 'wu-recent-searches';
  const BRAND_VISIT_KEY = 'wu-recent-brands';
  const getRecentSearches = () => { try { return JSON.parse(localStorage.getItem(SEARCH_KEY) || '[]'); } catch { return []; } };
  const addRecentSearch = (q) => {
    if (!q.trim()) return;
    const arr = getRecentSearches().filter(s => s !== q.trim());
    arr.unshift(q.trim());
    localStorage.setItem(SEARCH_KEY, JSON.stringify(arr.slice(0, 20)));
  };
  const clearRecentSearches = () => { localStorage.removeItem(SEARCH_KEY); };
  const getRecentBrands = () => { try { return JSON.parse(localStorage.getItem(BRAND_VISIT_KEY) || '[]'); } catch { return []; } };
  const addRecentBrand = (b) => {
    const arr = getRecentBrands().filter(x => x !== b);
    arr.unshift(b);
    localStorage.setItem(BRAND_VISIT_KEY, JSON.stringify(arr.slice(0, 10)));
  };

  // 인기검색어 / 급상승 (고정 더미 + 실제 브랜드 혼합)
  const popularSearches = React.useMemo(() => {
    const top = allBrands.slice(0, 5).map(b => b.name);
    const extras = ['워크부츠', '카고팬츠', '쿨링셔츠', '에이프런', '자켓'];
    return [...top, ...extras].slice(0, 10);
  }, [allBrands]);

  const risingSearches = React.useMemo(() => {
    const words = ['반팔', '여름작업복', '쿨링', '슬리퍼', '안전화'];
    const tail = allBrands.slice(Math.max(0, allBrands.length - 5)).map(b => b.name);
    return [...words, ...tail].slice(0, 10);
  }, [allBrands]);

  // ── 검색 실행 ──
  const doSearch = (q) => {
    if (!q.trim()) { setSearchResults(null); return; }
    addRecentSearch(q);
    const query = q.toLowerCase();
    const results = items.filter(p => {
      const title = getTitle(p).toLowerCase();
      const brand = getBrand(p).toLowerCase();
      const code = ((p.parsed || {}).code || p.code || '').toLowerCase();
      const cats = getCats(p).join(' ').toLowerCase();
      return title.includes(query) || brand.includes(query) || code.includes(query) || cats.includes(query);
    });
    setSearchResults(results);
    setShowSearch(false);
  };

  // ── 상품 카드 렌더 ──
  const renderProductCard = (p, badge, rankNum) => {
    const photo = getPhoto(p);
    const title = getTitle(p);
    const brand = getBrand(p);
    const retail = getRetail(p);
    const cats = getCats(p);
    return (
      <div key={p.id} onClick={() => { if (window.__showProductDetail) window.__showProductDetail(p); }} style={{ background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', cursor: 'pointer', overflow: 'hidden' }}>
        <div style={{ width: '100%', aspectRatio: '4/5', background: '#E9E5DC', overflow: 'hidden', position: 'relative' }}>
          {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>}
          {badge && <span className="mono" style={{ position: 'absolute', top: 8, left: 8, fontSize: 9, padding: '3px 8px', background: badge === 'NEW' ? 'var(--wu-orange)' : badge === 'BEST' ? 'var(--wu-ink)' : 'var(--wu-orange)', color: '#fff', fontWeight: 700 }}>{badge}</span>}
          {rankNum && <span className="display" style={{ position: 'absolute', top: 8, left: 8, fontSize: 24, color: '#fff', textShadow: '0 2px 8px rgba(0,0,0,0.5)', lineHeight: 1 }}>{rankNum}</span>}
        </div>
        <div style={{ padding: '10px 12px' }}>
          {brand && <div className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)', letterSpacing: '0.06em' }}>{brand}</div>}
          <div className="kr" style={{ fontSize: 13, fontWeight: 700, marginTop: 2, lineHeight: 1.3, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{title}</div>
          {retail > 0 && <div className="mono" style={{ fontSize: 12, fontWeight: 700, marginTop: 4 }}>{retail.toLocaleString()}원</div>}
        </div>
      </div>
    );
  };

  // ── 상품 필터 (카테고리 탭용) ──
  // parts 그룹: 사이드바의 상위 카테고리 → 하위 카테고리 매핑
  const _partsMap = { '상의': ['긴팔', '반팔'], '하의': ['긴바지', '반바지'], '아우터': ['자켓', '조끼'], '풋웨어': ['워크부츠', '슬리퍼'], '액세서리': ['액세서리', '에이프런'] };
  const catFiltered = React.useMemo(() => {
    return items.filter(p => {
      if (activeCat === '전체') return true;
      const cats = getCats(p);
      const parts = (p.parsed || {}).parts || p.parts || [];
      const partsArr = Array.isArray(parts) ? parts : parts ? [parts] : [];
      const brand = getBrand(p).trim().toLowerCase();
      const title = getTitle(p).trim().toLowerCase();
      const allTags = [...cats, ...partsArr].map(t => t.trim().toLowerCase());
      const target = activeCat.trim().toLowerCase();

      // 브랜드명 매칭 (볼텍, 겐타, 디월트 등)
      if (brand && (brand === target || brand.includes(target) || target.includes(brand))) return true;

      // 상품명에 카테고리 키워드 포함 시 매칭
      if (title.includes(target)) return true;

      // 상위 카테고리(상의, 하의 등) 선택 시 하위 카테고리도 포함
      const subCats = _partsMap[activeCat];
      if (subCats) {
        const subs = subCats.map(s => s.toLowerCase());
        return allTags.some(t => t === target || subs.includes(t));
      }
      // 정확히 일치하는 카테고리만 필터
      return allTags.some(t => t === target);
    });
  }, [items, activeCat]);

  // ── 신상 (최근 7일) ──
  const newArrivals = React.useMemo(() => {
    return [...items].filter(p => getDaysAgo(p) <= 7).sort((a, b) => getDaysAgo(a) - getDaysAgo(b));
  }, [items]);

  // ── 랭킹 (가격순 + 즐겨찾기 기반 의사 랭킹) ──
  const ranked = React.useMemo(() => {
    const favs = (() => { try { return JSON.parse(localStorage.getItem('wu-favorites') || '[]'); } catch { return []; } })();
    return [...items].sort((a, b) => {
      const aFav = favs.includes(a.id) ? 1 : 0;
      const bFav = favs.includes(b.id) ? 1 : 0;
      if (bFav !== aFav) return bFav - aFav;
      return getRetail(b) - getRetail(a);
    });
  }, [items]);

  // ── 품절임박 (재고 적은 상품 — MOQ 기반) ──
  const almostSoldOut = React.useMemo(() => {
    return [...items].filter(p => {
      const moq = (p.parsed || {}).moq || p.moq || 0;
      return moq > 0 && moq <= 10;
    }).sort((a, b) => ((a.parsed || {}).moq || a.moq || 0) - ((b.parsed || {}).moq || b.moq || 0));
  }, [items]);

  // ── 기획전 (더미 컬렉션) ──
  const featuredCollections = React.useMemo(() => {
    const collections = [];
    // 시즌별 묶기
    const summer = items.filter(p => { const s = (p.parsed || {}).seasons || []; const t = (p.parsed || {}).season_tag || ''; return s.includes('여름') || t.includes('ss'); });
    if (summer.length > 0) collections.push({ title: '여름 워크웨어 특집', subtitle: 'SUMMER COLLECTION', color: '#FF6B35', items: summer });
    const winter = items.filter(p => { const s = (p.parsed || {}).seasons || []; return s.includes('겨울'); });
    if (winter.length > 0) collections.push({ title: '겨울 방한 아이템', subtitle: 'WINTER ESSENTIALS', color: '#2A3A5A', items: winter });
    // 브랜드별
    allBrands.slice(0, 3).forEach(b => {
      const bItems = items.filter(p => getBrand(p) === b.name);
      if (bItems.length > 0) collections.push({ title: b.name + ' 브랜드관', subtitle: b.name + ' BRAND SHOP', color: '#1A1A17', items: bItems });
    });
    // 가격대별
    const under50k = items.filter(p => { const r = getRetail(p); return r > 0 && r < 50000; });
    if (under50k.length > 0) collections.push({ title: '5만원 이하 가성비템', subtitle: 'UNDER ₩50,000', color: '#6B6157', items: under50k });
    return collections;
  }, [items, allBrands]);

  // ── NAV 탭 목록 ──
  const navTabs = [
    { id: 'category', label: '카테고리' },
    { id: 'brand', label: '브랜드' },
    { id: 'new', label: '신상' },
    { id: 'featured', label: '기획전' },
    { id: 'ranking', label: '랭킹' },
    { id: 'soldout', label: '품절임박' },
  ];

  // ═══ 검색 오버레이 ═══
  if (showSearch) {
    const recentSearches = getRecentSearches();
    const recentBrands = getRecentBrands();
    return (
      <div className="wu" style={{ height: '100%', background: 'var(--wu-bg)', position: 'relative', overflow: 'hidden' }}>
        {/* 검색 입력 바 */}
        <div style={{ padding: 'calc(env(safe-area-inset-top, 20px) + 12px) 16px 12px', background: 'var(--wu-bg)', borderBottom: '1px solid var(--wu-line)' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <div style={{ flex: 1, background: '#fff', border: '1.5px solid var(--wu-ink)', borderRadius: 999, padding: '10px 16px', display: 'flex', alignItems: 'center', gap: 10 }}>
              <svg width="14" height="14" viewBox="0 0 20 20" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="9" cy="9" r="6"/><path d="M14 14l4 4"/></svg>
              <input ref={searchInputRef} autoFocus value={searchQuery} onChange={e => setSearchQuery(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') doSearch(searchQuery); }} placeholder="상품명, 브랜드, 카테고리 검색" className="kr" style={{ flex: 1, border: 0, outline: 0, background: 'transparent', fontSize: 14, fontWeight: 600 }} />
              {searchQuery && <button onClick={() => setSearchQuery('')} style={{ color: 'var(--wu-mute)', background: 'none', border: 'none', cursor: 'pointer' }}>✕</button>}
            </div>
            <button onClick={() => { setShowSearch(false); setSearchQuery(''); }} className="kr" style={{ fontSize: 14, fontWeight: 600, background: 'none', border: 'none', cursor: 'pointer', flexShrink: 0 }}>취소</button>
          </div>
        </div>

        <div className="wu-scroll" style={{ height: 'calc(100% - 110px)', overflow: 'auto', padding: '0 16px' }}>
          {/* 최근 검색어 */}
          {recentSearches.length > 0 && (
            <div style={{ paddingTop: 20 }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
                <span className="kr" style={{ fontSize: 15, fontWeight: 700 }}>최근 검색어</span>
                <button onClick={() => { clearRecentSearches(); setSearchQuery(q => q); /* force re-render */ }} className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', background: 'none', border: 'none', cursor: 'pointer' }}>전체 삭제</button>
              </div>
              <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
                {recentSearches.slice(0, 10).map((s, i) => (
                  <button key={i} onClick={() => { setSearchQuery(s); doSearch(s); }} className="kr" style={{ padding: '8px 14px', background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', borderRadius: 999, fontSize: 13, cursor: 'pointer' }}>{s}</button>
                ))}
              </div>
            </div>
          )}

          {/* 최근 방문한 브랜드 */}
          {recentBrands.length > 0 && (
            <div style={{ paddingTop: 24 }}>
              <span className="kr" style={{ fontSize: 15, fontWeight: 700 }}>최근 방문한 브랜드</span>
              <div style={{ display: 'flex', gap: 12, marginTop: 12, overflowX: 'auto' }} className="wu-scroll">
                {recentBrands.slice(0, 8).map((b, i) => (
                  <button key={i} onClick={() => { setSelectedBrand(b); setNavTab('brand'); setShowSearch(false); setSearchQuery(''); addRecentBrand(b); }} style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6, flexShrink: 0, cursor: 'pointer', background: 'none', border: 'none' }}>
                    <div style={{ width: 52, height: 52, borderRadius: 999, background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                      <span className="mono" style={{ fontSize: 14, fontWeight: 700 }}>{b[0]}</span>
                    </div>
                    <span className="mono" style={{ fontSize: 10, color: 'var(--wu-ink)', maxWidth: 60, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{b}</span>
                  </button>
                ))}
              </div>
            </div>
          )}

          {/* 인기 검색어 TOP 10 / 급상승 검색어 TOP 10 */}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 24, paddingTop: 28, paddingBottom: 40 }}>
            <div>
              <span className="kr" style={{ fontSize: 15, fontWeight: 700 }}>인기검색어 TOP10</span>
              <div style={{ marginTop: 12 }}>
                {popularSearches.map((s, i) => (
                  <button key={i} onClick={() => { setSearchQuery(s); doSearch(s); }} style={{ display: 'flex', alignItems: 'center', gap: 10, width: '100%', padding: '10px 0', borderBottom: '1px solid var(--wu-line)', background: 'none', border: 'none', borderBottom: '1px solid var(--wu-line)', cursor: 'pointer', textAlign: 'left' }}>
                    <span className="display" style={{ fontSize: 14, width: 20, color: i < 3 ? 'var(--wu-orange)' : 'var(--wu-mute)' }}>{i + 1}</span>
                    <span className="kr" style={{ fontSize: 13, fontWeight: i < 3 ? 700 : 400 }}>{s}</span>
                  </button>
                ))}
              </div>
            </div>
            <div>
              <span className="kr" style={{ fontSize: 15, fontWeight: 700 }}>급상승 검색어 TOP10</span>
              <div style={{ marginTop: 12 }}>
                {risingSearches.map((s, i) => (
                  <button key={i} onClick={() => { setSearchQuery(s); doSearch(s); }} style={{ display: 'flex', alignItems: 'center', gap: 10, width: '100%', padding: '10px 0', background: 'none', border: 'none', borderBottom: '1px solid var(--wu-line)', cursor: 'pointer', textAlign: 'left' }}>
                    <span className="display" style={{ fontSize: 14, width: 20, color: i < 3 ? '#FF3B30' : 'var(--wu-mute)' }}>{i + 1}</span>
                    <span className="kr" style={{ fontSize: 13, fontWeight: i < 3 ? 700 : 400 }}>{s}</span>
                    {i < 3 && <span style={{ fontSize: 10, color: '#FF3B30' }}>▲</span>}
                  </button>
                ))}
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  }

  // ═══ 검색 결과 표시 모드 ═══
  if (searchResults !== null) {
    return (
      <div className="wu wu-scroll wu-consumer-wrap" style={{ height: '100%', overflow: 'auto', background: 'var(--wu-bg)', paddingBottom: 70 }}>
        <div style={{ padding: 'calc(env(safe-area-inset-top, 20px) + 12px) 16px 12px', background: 'var(--wu-bg)', position: 'sticky', top: 0, zIndex: 20 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <button onClick={() => setSearchResults(null)} style={{ fontSize: 18, background: 'none', border: 'none', cursor: 'pointer' }}>←</button>
            <div onClick={() => setShowSearch(true)} style={{ flex: 1, background: '#fff', border: '1px solid var(--wu-line)', borderRadius: 999, padding: '10px 16px', display: 'flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
              <svg width="14" height="14" viewBox="0 0 20 20" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="9" cy="9" r="6"/><path d="M14 14l4 4"/></svg>
              <span className="kr" style={{ fontSize: 13, color: 'var(--wu-ink)', fontWeight: 600 }}>{searchQuery || '검색'}</span>
            </div>
          </div>
          <div className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)', marginTop: 10 }}>검색 결과 {searchResults.length}개</div>
        </div>
        <div style={{ padding: '8px 16px 16px' }}>
          {searchResults.length === 0 ? (
            <div style={{ textAlign: 'center', padding: '60px 20px' }}>
              <div style={{ fontSize: 40, marginBottom: 8 }}>🔍</div>
              <div className="kr" style={{ fontSize: 14, color: 'var(--wu-mute)' }}>검색 결과가 없습니다</div>
            </div>
          ) : (
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
              {searchResults.map(p => renderProductCard(p))}
            </div>
          )}
        </div>
      </div>
    );
  }

  // ═══ 브랜드 상세 (특정 브랜드 선택 시) ═══
  if (selectedBrand) {
    const brandItems = items.filter(p => getBrand(p) === selectedBrand);
    return (
      <div className="wu wu-scroll wu-consumer-wrap" style={{ height: '100%', overflow: 'auto', background: 'var(--wu-bg)', paddingBottom: 70 }}>
        <div style={{ padding: 'calc(env(safe-area-inset-top, 20px) + 12px) 16px 12px', background: 'var(--wu-bg)', position: 'sticky', top: 0, zIndex: 20, borderBottom: '1px solid var(--wu-line)' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <button onClick={() => setSelectedBrand(null)} style={{ fontSize: 18, background: 'none', border: 'none', cursor: 'pointer' }}>←</button>
            <div>
              <div className="display" style={{ fontSize: 22 }}>{selectedBrand}</div>
              <div className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)' }}>{brandItems.length}개 상품</div>
            </div>
          </div>
        </div>
        <div style={{ padding: '12px 16px 16px' }}>
          {brandItems.length === 0 ? (
            <div style={{ textAlign: 'center', padding: '60px 20px' }}>
              <div className="kr" style={{ fontSize: 14, color: 'var(--wu-mute)' }}>이 브랜드의 상품이 없습니다</div>
            </div>
          ) : (
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
              {brandItems.map(p => renderProductCard(p))}
            </div>
          )}
        </div>
      </div>
    );
  }

  // ═══ 메인 쇼핑 화면 ═══
  return (
    <div className="wu" style={{ height: '100%', background: 'var(--wu-bg)', display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
      {/* ── 상단 검색바 ── */}
      <div style={{ padding: 'calc(env(safe-area-inset-top, 20px) + 12px) 16px 10px', flexShrink: 0 }}>
        <div onClick={() => setShowSearch(true)} style={{ background: '#fff', border: '1.5px solid var(--wu-line)', borderRadius: 999, padding: '11px 16px', display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer' }}>
          <svg width="16" height="16" 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>
          <span className="kr" style={{ fontSize: 14, color: 'var(--wu-mute)' }}>상품명, 브랜드, 카테고리 검색</span>
        </div>
      </div>

      {/* ── 네비게이션 탭 ── */}
      <div style={{ display: 'flex', borderBottom: '1px solid var(--wu-line)', flexShrink: 0, overflowX: 'auto', background: 'var(--wu-bg)' }} className="wu-scroll">
        {navTabs.map(t => (
          <button key={t.id} onClick={() => setNavTab(t.id)} className="kr" style={{
            padding: '12px 16px', fontSize: 14, fontWeight: navTab === t.id ? 700 : 400,
            color: navTab === t.id ? 'var(--wu-ink)' : 'var(--wu-mute)',
            borderBottom: navTab === t.id ? '2px solid var(--wu-ink)' : '2px solid transparent',
            background: 'none', border: 'none', borderBottom: navTab === t.id ? '2px solid var(--wu-ink)' : '2px solid transparent',
            cursor: 'pointer', whiteSpace: 'nowrap', flexShrink: 0,
          }}>{t.label}</button>
        ))}
      </div>

      {/* ── 콘텐츠 영역 ── */}
      <div style={{ flex: 1, overflow: 'auto', paddingBottom: 70 }} className="wu-scroll">
        {loading ? (
          <div style={{ textAlign: 'center', padding: '60px 20px' }}>
            <div className="kr" style={{ fontSize: 14, color: 'var(--wu-mute)' }}>로딩 중...</div>
          </div>
        ) : (
          <>
            {/* ═══ 카테고리 탭 ═══ */}
            {navTab === 'category' && (
              <div style={{ display: 'flex', height: '100%' }}>
                {/* 사이드바 */}
                <div style={{ width: 90, borderRight: '1px solid var(--wu-line)', background: 'var(--wu-paper)', flexShrink: 0, overflow: 'auto' }} className="wu-scroll">
                  {/* 성별 필터 */}
                  <div style={{ display: 'flex', borderBottom: '1px solid var(--wu-line)' }}>
                    {['전체', '남성', '여성'].map(g => (
                      <button key={g} onClick={() => setGenderFilter(g)} className="kr" style={{
                        flex: 1, padding: '10px 0', fontSize: 11, fontWeight: genderFilter === g ? 700 : 400,
                        color: genderFilter === g ? 'var(--wu-ink)' : 'var(--wu-mute)',
                        borderBottom: genderFilter === g ? '2px solid var(--wu-ink)' : 'none',
                        background: 'none', border: 'none', cursor: 'pointer',
                      }}>{g}</button>
                    ))}
                  </div>
                  {sidebarCats.map(c => (
                    <button key={c} onClick={() => setActiveCat(c)} className="kr" style={{
                      display: 'block', width: '100%', padding: '14px 12px', fontSize: 13,
                      fontWeight: activeCat === c ? 700 : 400,
                      color: activeCat === c ? 'var(--wu-ink)' : 'var(--wu-mute)',
                      background: activeCat === c ? 'var(--wu-bg)' : 'transparent',
                      borderLeft: activeCat === c ? '3px solid var(--wu-ink)' : '3px solid transparent',
                      border: 'none', borderLeft: activeCat === c ? '3px solid var(--wu-ink)' : '3px solid transparent',
                      cursor: 'pointer', textAlign: 'left',
                    }}>{c}</button>
                  ))}
                </div>
                {/* 상품 그리드 */}
                <div style={{ flex: 1, overflow: 'auto', padding: 12 }} className="wu-scroll">
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
                    <span className="kr" style={{ fontSize: 15, fontWeight: 700 }}>{activeCat}</span>
                    <span className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)' }}>{catFiltered.length}개</span>
                  </div>
                  {catFiltered.length === 0 ? (
                    <div style={{ textAlign: 'center', padding: '40px 20px' }}>
                      <div className="kr" style={{ fontSize: 13, color: 'var(--wu-mute)' }}>상품이 없습니다</div>
                    </div>
                  ) : (
                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
                      {catFiltered.map(p => renderProductCard(p))}
                    </div>
                  )}
                </div>
              </div>
            )}

            {/* ═══ 브랜드 탭 ═══ */}
            {navTab === 'brand' && (
              <div style={{ padding: '16px' }}>
                {/* 브랜드 검색 */}
                <div style={{ background: '#fff', border: '1px solid var(--wu-line)', borderRadius: 8, padding: '10px 14px', display: 'flex', alignItems: 'center', gap: 8, marginBottom: 16 }}>
                  <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={brandSearch} onChange={e => setBrandSearch(e.target.value)} placeholder="브랜드를 검색하세요" className="kr" style={{ flex: 1, border: 0, outline: 0, background: 'transparent', fontSize: 13 }} />
                  {brandSearch && <button onClick={() => setBrandSearch('')} style={{ color: 'var(--wu-mute)', background: 'none', border: 'none', cursor: 'pointer', fontSize: 12 }}>✕</button>}
                </div>

                {/* 초성 필터 */}
                {!brandSearch && (
                  <div style={{ display: 'flex', gap: 4, flexWrap: 'wrap', marginBottom: 16 }}>
                    {consonants.map(c => (
                      <button key={c} onClick={() => setActiveBrandConsonant(c)} className="mono" style={{
                        padding: '6px 8px', fontSize: 11, fontWeight: activeBrandConsonant === c ? 700 : 400,
                        background: activeBrandConsonant === c ? 'var(--wu-ink)' : 'transparent',
                        color: activeBrandConsonant === c ? '#fff' : 'var(--wu-ink)',
                        border: 'none', cursor: 'pointer', borderRadius: 4,
                      }}>{c}</button>
                    ))}
                  </div>
                )}

                {!brandSearch && <div className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)', marginBottom: 10 }}>{activeBrandConsonant === '인기' ? '인기 브랜드' : activeBrandConsonant} · {filteredBrands.length}개</div>}

                {/* 브랜드 리스트 */}
                <div>
                  {filteredBrands.map((b, i) => (
                    <button key={b.name} onClick={() => { setSelectedBrand(b.name); addRecentBrand(b.name); }} style={{
                      display: 'flex', alignItems: 'center', width: '100%', padding: '14px 0',
                      borderBottom: '1px solid var(--wu-line)', background: 'none', border: 'none',
                      borderBottom: '1px solid var(--wu-line)', cursor: 'pointer', textAlign: 'left', gap: 14,
                    }}>
                      <div style={{ width: 44, height: 44, borderRadius: 999, background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                        <span className="display" style={{ fontSize: 16 }}>{b.name[0]}</span>
                      </div>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div className="kr" style={{ fontSize: 14, fontWeight: 700 }}>{b.name}</div>
                        <div className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)', marginTop: 2 }}>{b.count}개 상품</div>
                      </div>
                      <svg width="16" height="16" viewBox="0 0 20 20" fill="none" stroke="var(--wu-line)" strokeWidth="1.8"><path d="M8 4l6 6-6 6"/></svg>
                    </button>
                  ))}
                  {filteredBrands.length === 0 && (
                    <div style={{ textAlign: 'center', padding: '40px 20px' }}>
                      <div className="kr" style={{ fontSize: 13, color: 'var(--wu-mute)' }}>해당 브랜드가 없습니다</div>
                    </div>
                  )}
                </div>
              </div>
            )}

            {/* ═══ 신상 탭 ═══ */}
            {navTab === 'new' && (
              <div style={{ padding: 16 }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
                  <div>
                    <div className="display" style={{ fontSize: 22 }}>NEW ARRIVALS</div>
                    <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginTop: 2 }}>최근 2주 이내 등록 상품</div>
                  </div>
                  <span className="mono" style={{ fontSize: 11, color: 'var(--wu-orange)' }}>● {newArrivals.length}개</span>
                </div>
                {newArrivals.length === 0 ? (
                  <div style={{ textAlign: 'center', padding: '60px 20px' }}>
                    <div style={{ fontSize: 40, marginBottom: 8 }}>📦</div>
                    <div className="kr" style={{ fontSize: 14, color: 'var(--wu-mute)' }}>최근 신상품이 없습니다</div>
                  </div>
                ) : (
                  <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
                    {newArrivals.map(p => renderProductCard(p, 'NEW'))}
                  </div>
                )}
              </div>
            )}

            {/* ═══ 기획전 탭 ═══ */}
            {navTab === 'featured' && (
              <div style={{ padding: 16 }}>
                <div className="display" style={{ fontSize: 22, marginBottom: 4 }}>FEATURED</div>
                <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginBottom: 20 }}>테마별 기획전</div>
                {featuredCollections.length === 0 ? (
                  <div style={{ textAlign: 'center', padding: '60px 20px' }}>
                    <div style={{ fontSize: 40, marginBottom: 8 }}>🎯</div>
                    <div className="kr" style={{ fontSize: 14, color: 'var(--wu-mute)' }}>진행중인 기획전이 없습니다</div>
                  </div>
                ) : (
                  featuredCollections.map((col, ci) => (
                    <div key={ci} style={{ marginBottom: 28 }}>
                      {/* 기획전 배너 */}
                      <div style={{ background: col.color, padding: '24px 20px', marginBottom: 12, position: 'relative', overflow: 'hidden' }}>
                        <div className="mono" style={{ fontSize: 10, color: 'rgba(255,255,255,0.6)', letterSpacing: '0.1em' }}>{col.subtitle}</div>
                        <div className="kr" style={{ fontSize: 20, fontWeight: 800, color: '#fff', marginTop: 6 }}>{col.title}</div>
                        <div className="mono" style={{ fontSize: 11, color: 'rgba(255,255,255,0.7)', marginTop: 4 }}>{col.items.length}개 상품</div>
                        <div className="display" style={{ position: 'absolute', right: 16, bottom: 10, fontSize: 48, color: 'rgba(255,255,255,0.08)' }}>{String(ci + 1).padStart(2, '0')}</div>
                      </div>
                      {/* 상품 가로 스크롤 */}
                      <div style={{ display: 'flex', gap: 10, overflowX: 'auto' }} className="wu-scroll">
                        {col.items.slice(0, 8).map(p => (
                          <div key={p.id} onClick={() => { if (window.__showProductDetail) window.__showProductDetail(p); }} style={{ width: 140, flexShrink: 0, cursor: 'pointer' }}>
                            <div style={{ width: 140, aspectRatio: '4/5', background: '#E9E5DC', overflow: 'hidden' }}>
                              {getPhoto(p) ? <img src={getPhoto(p)} 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 className="kr" style={{ fontSize: 12, fontWeight: 600, marginTop: 6, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{getTitle(p)}</div>
                            {getRetail(p) > 0 && <div className="mono" style={{ fontSize: 11, fontWeight: 700, marginTop: 2 }}>{getRetail(p).toLocaleString()}원</div>}
                          </div>
                        ))}
                      </div>
                    </div>
                  ))
                )}
              </div>
            )}

            {/* ═══ 랭킹 탭 ═══ */}
            {navTab === 'ranking' && (
              <div style={{ padding: 16 }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
                  <div>
                    <div className="display" style={{ fontSize: 22 }}>RANKING</div>
                    <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginTop: 2 }}>인기 상품 순위</div>
                  </div>
                </div>
                {ranked.length === 0 ? (
                  <div style={{ textAlign: 'center', padding: '60px 20px' }}>
                    <div className="kr" style={{ fontSize: 14, color: 'var(--wu-mute)' }}>등록된 상품이 없습니다</div>
                  </div>
                ) : (
                  <div style={{ display: 'grid', gap: 12 }}>
                    {ranked.slice(0, 20).map((p, i) => (
                      <div key={p.id} onClick={() => { if (window.__showProductDetail) window.__showProductDetail(p); }} style={{ display: 'flex', gap: 14, padding: 12, background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', cursor: 'pointer', alignItems: 'center' }}>
                        <span className="display" style={{ fontSize: 20, width: 32, textAlign: 'center', color: i < 3 ? 'var(--wu-orange)' : 'var(--wu-mute)', flexShrink: 0 }}>{i + 1}</span>
                        <div style={{ width: 64, height: 64, flexShrink: 0, background: '#E9E5DC', overflow: 'hidden' }}>
                          {getPhoto(p) ? <img src={getPhoto(p)} style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> : null}
                        </div>
                        <div style={{ flex: 1, minWidth: 0 }}>
                          {getBrand(p) && <div className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>{getBrand(p)}</div>}
                          <div className="kr" style={{ fontSize: 14, fontWeight: 700, marginTop: 2, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{getTitle(p)}</div>
                        </div>
                        <div className="mono" style={{ fontSize: 14, fontWeight: 700, flexShrink: 0 }}>{getRetail(p) > 0 ? getRetail(p).toLocaleString() + '원' : ''}</div>
                      </div>
                    ))}
                  </div>
                )}
              </div>
            )}

            {/* ═══ 품절임박 탭 ═══ */}
            {navTab === 'soldout' && (
              <div style={{ padding: 16 }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
                  <div>
                    <div className="display" style={{ fontSize: 22 }}>ALMOST SOLD OUT</div>
                    <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginTop: 2 }}>재고 소진 임박 상품</div>
                  </div>
                  <span className="mono" style={{ fontSize: 11, color: '#FF3B30' }}>● {almostSoldOut.length}개</span>
                </div>
                {almostSoldOut.length === 0 ? (
                  <div style={{ textAlign: 'center', padding: '60px 20px' }}>
                    <div style={{ fontSize: 40, marginBottom: 8 }}>✅</div>
                    <div className="kr" style={{ fontSize: 14, color: 'var(--wu-mute)' }}>품절 임박 상품이 없습니다</div>
                  </div>
                ) : (
                  <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
                    {almostSoldOut.map(p => {
                      const moq = (p.parsed || {}).moq || p.moq || 0;
                      return (
                        <div key={p.id} onClick={() => { if (window.__showProductDetail) window.__showProductDetail(p); }} style={{ background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', cursor: 'pointer', overflow: 'hidden', position: 'relative' }}>
                          <div style={{ width: '100%', aspectRatio: '4/5', background: '#E9E5DC', overflow: 'hidden', position: 'relative' }}>
                            {getPhoto(p) ? <img src={getPhoto(p)} 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 style={{ position: 'absolute', top: 8, left: 8, padding: '4px 8px', background: '#FF3B30', color: '#fff', fontSize: 10, fontFamily: 'JetBrains Mono', fontWeight: 700 }}>잔여 {moq}개</div>
                          </div>
                          <div style={{ padding: '10px 12px' }}>
                            {getBrand(p) && <div className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>{getBrand(p)}</div>}
                            <div className="kr" style={{ fontSize: 13, fontWeight: 700, marginTop: 2, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{getTitle(p)}</div>
                            {getRetail(p) > 0 && <div className="mono" style={{ fontSize: 12, fontWeight: 700, marginTop: 4 }}>{getRetail(p).toLocaleString()}원</div>}
                          </div>
                        </div>
                      );
                    })}
                  </div>
                )}
              </div>
            )}
          </>
        )}
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────
// Consumer BOARD — 게시판 (장비자랑 · 구하고싶은공구)
// 일반 회원: 자기 글 작성/수정/삭제  |  관리자: 모든 글 수정/삭제
// ────────────────────────────────────────────────────
function ConsumerBoard({ variant = 'pill' }) {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [view, setView] = useState('list'); // list | detail | write | edit
  const [selected, setSelected] = useState(null);
  const [filterCat, setFilterCat] = useState('전체');
  const [msg, setMsg] = useState('');

  // write / edit form
  const [fTitle, setFTitle] = useState('');
  const [fBody, setFBody] = useState('');
  const [fCategory, setFCategory] = useState('장비자랑');
  const [fPhotos, setFPhotos] = useState([]);
  const [editId, setEditId] = useState(null);

  const cats = (typeof BOARD_CATEGORIES !== 'undefined') ? BOARD_CATEGORIES : ['장비자랑', '구하고싶은공구'];
  const user = typeof getAuth === 'function' ? getAuth() : null;
  const isAdmin = user && user.role === 'admin';
  const userName = user?.name || '익명';

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

  const load = async () => {
    if (typeof getAllPosts === 'function') {
      try { const p = await getAllPosts(); setPosts(p); } catch {}
    }
    setLoading(false);
  };
  useEffect(() => { load(); }, []);

  const filtered = filterCat === '전체' ? posts : posts.filter(p => p.category === filterCat);

  const canEdit = (p) => isAdmin || p.author === userName;
  const canDelete = (p) => isAdmin || p.author === userName;

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

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

  // submit edited post
  const submitEdit = async () => {
    if (!fTitle.trim()) { flash('제목을 입력하세요'); return; }
    if (!fBody.trim()) { flash('내용을 입력하세요'); return; }
    const orig = posts.find(p => p.id === editId);
    if (!orig) return;
    const updated = { ...orig, title: fTitle.trim(), body: fBody.trim(), category: fCategory, photos: fPhotos };
    await savePost(updated);
    resetForm(); 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: userName, authorRole: user?.role || 'consumer', createdAt: new Date().toISOString() };
    post.replies = [...(post.replies || []), reply];
    await savePost(post);
    load(); flash('댓글 등록 완료');
    // refresh selected
    setSelected({ ...post });
  };

  const handleDeleteReply = async (postId, replyId) => {
    const post = posts.find(p => p.id === postId);
    if (!post) return;
    post.replies = (post.replies || []).filter(r => r.id !== replyId);
    await savePost(post);
    load(); flash('댓글 삭제');
    setSelected({ ...post });
  };

  const resetForm = () => { setFTitle(''); setFBody(''); setFCategory('장비자랑'); setFPhotos([]); setEditId(null); };

  const startEdit = (p) => {
    setFTitle(p.title); setFBody(p.body); setFCategory(p.category); setFPhotos(p.photos || []); setEditId(p.id);
    setView('edit');
  };

  const startWrite = () => { resetForm(); setView('write'); };

  const catBadgeBg = (c) => c === '장비자랑' ? '#1565C0' : '#E65100';

  // ── DETAIL VIEW ──
  if (view === 'detail' && selected) {
    return (
      <div className="wu wu-scroll wu-consumer-wrap" style={{ height: '100%', overflow: 'auto', background: 'var(--wu-bg)', paddingBottom: 70 }}>
        {msg && <div style={{ position: 'fixed', top: 60, left: '50%', transform: 'translateX(-50%)', zIndex: 999, padding: '8px 18px', background: 'var(--wu-orange)', color: '#fff', fontFamily: 'Pretendard', fontSize: 13, fontWeight: 700, borderRadius: 20 }}>{msg}</div>}
        <div style={{ padding: 'calc(env(safe-area-inset-top, 20px) + 12px) 16px 8px' }}>
          <button onClick={() => { setView('list'); setSelected(null); }} style={{ fontSize: 16, cursor: 'pointer', background: 'none', border: 'none', color: 'var(--wu-ink)' }}>← 목록</button>
        </div>
        <div style={{ padding: '8px 16px' }}>
          <div style={{ background: 'var(--wu-paper)', padding: 20, border: '1px solid var(--wu-line)', borderRadius: 8 }}>
            <div style={{ display: 'flex', gap: 8, alignItems: 'center', marginBottom: 12 }}>
              <span className="mono" style={{ fontSize: 9, padding: '3px 8px', background: catBadgeBg(selected.category), color: '#fff', fontWeight: 700, borderRadius: 4 }}>{selected.category}</span>
              <span className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>{new Date(selected.createdAt).toLocaleDateString('ko-KR')}</span>
            </div>
            <div className="kr" style={{ fontSize: 20, fontWeight: 800 }}>{selected.title}</div>
            <div className="kr" style={{ fontSize: 11, color: 'var(--wu-mute)', marginTop: 6 }}>작성자: {selected.author}</div>
            <div className="kr" style={{ marginTop: 20, fontSize: 14, lineHeight: 1.8, whiteSpace: 'pre-wrap' }}>{selected.body}</div>

            {/* photos */}
            {(selected.photos || []).length > 0 && (
              <div style={{ display: 'flex', gap: 8, marginTop: 16, overflowX: 'auto' }} className="wu-scroll">
                {selected.photos.map((ph, i) => (
                  <img key={i} src={ph} alt="" style={{ width: selected.photos.length === 1 ? '100%' : 160, height: selected.photos.length === 1 ? 'auto' : 120, maxHeight: 260, objectFit: 'cover', borderRadius: 6, border: '1px solid var(--wu-line)', flexShrink: 0 }} />
                ))}
              </div>
            )}

            {/* action buttons */}
            {(canEdit(selected) || canDelete(selected)) && (
              <div style={{ display: 'flex', gap: 8, marginTop: 20, paddingTop: 16, borderTop: '1px solid var(--wu-line)' }}>
                {canEdit(selected) && <button onClick={() => startEdit(selected)} className="kr" style={{ padding: '8px 16px', fontSize: 12, fontWeight: 700, background: 'var(--wu-ink)', color: '#fff', border: 'none', borderRadius: 6, cursor: 'pointer' }}>수정</button>}
                {canDelete(selected) && <button onClick={() => handleDelete(selected.id)} className="kr" style={{ padding: '8px 16px', fontSize: 12, fontWeight: 700, background: '#fff', color: '#C44', border: '1px solid #C44', borderRadius: 6, cursor: 'pointer' }}>삭제</button>}
              </div>
            )}

            {/* replies */}
            <div style={{ marginTop: 24, borderTop: '1px solid var(--wu-line)', paddingTop: 16 }}>
              <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 10 }}>REPLIES · {(selected.replies || []).length}</div>
              {(selected.replies || []).map((r, i) => (
                <div key={r.id || i} style={{ padding: '10px 12px', background: 'var(--wu-bg)', marginBottom: 6, borderRadius: 6 }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                    <div className="kr" style={{ fontSize: 12, fontWeight: 600 }}>{r.author} <span className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)', fontWeight: 400 }}>{r.authorRole === 'admin' ? '관리자' : ''}</span></div>
                    {(isAdmin || r.author === userName) && (
                      <button onClick={() => handleDeleteReply(selected.id, r.id)} style={{ fontSize: 10, color: '#C44', background: 'none', border: 'none', cursor: 'pointer' }}>삭제</button>
                    )}
                  </div>
                  <div className="kr" style={{ fontSize: 13, marginTop: 4, lineHeight: 1.6 }}>{r.text}</div>
                  <div className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)', marginTop: 4 }}>{new Date(r.createdAt).toLocaleDateString('ko-KR')}</div>
                </div>
              ))}

              {/* reply input */}
              <ConsumerReplyInput onSubmit={(txt) => handleReply(selected.id, txt)} />
            </div>
          </div>
        </div>
      </div>
    );
  }

  // ── WRITE / EDIT VIEW ──
  if (view === 'write' || view === 'edit') {
    const isEditing = view === 'edit';
    return (
      <div className="wu wu-scroll wu-consumer-wrap" style={{ height: '100%', overflow: 'auto', background: 'var(--wu-bg)', paddingBottom: 70 }}>
        {msg && <div style={{ position: 'fixed', top: 60, left: '50%', transform: 'translateX(-50%)', zIndex: 999, padding: '8px 18px', background: 'var(--wu-orange)', color: '#fff', fontFamily: 'Pretendard', fontSize: 13, fontWeight: 700, borderRadius: 20 }}>{msg}</div>}
        <div style={{ padding: 'calc(env(safe-area-inset-top, 20px) + 12px) 16px 8px' }}>
          <button onClick={() => { setView('list'); resetForm(); }} style={{ fontSize: 16, cursor: 'pointer', background: 'none', border: 'none', color: 'var(--wu-ink)' }}>← 취소</button>
        </div>
        <div style={{ padding: '8px 16px' }}>
          <div className="display" style={{ fontSize: 22, marginBottom: 16 }}>{isEditing ? 'EDIT POST' : 'NEW POST'}</div>

          {/* category selector */}
          <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 6 }}>카테고리</div>
          <div style={{ display: 'flex', gap: 8, marginBottom: 16 }}>
            {cats.map(c => (
              <button key={c} onClick={() => setFCategory(c)} className="kr" style={{ padding: '10px 16px', fontSize: 13, fontWeight: 700, background: fCategory === c ? catBadgeBg(c) : 'var(--wu-paper)', color: fCategory === c ? '#fff' : 'var(--wu-ink)', border: '1px solid var(--wu-line)', cursor: 'pointer', borderRadius: 8, flex: 1 }}>{c}</button>
            ))}
          </div>

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

          {/* body */}
          <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 6 }}>내용</div>
          <textarea value={fBody} onChange={e => setFBody(e.target.value)} placeholder="자유롭게 작성하세요" className="kr" rows={6} style={{ width: '100%', padding: '12px 14px', border: '1px solid var(--wu-line)', background: 'var(--wu-paper)', fontSize: 14, lineHeight: 1.7, outline: 'none', resize: 'vertical', fontFamily: 'Pretendard', marginBottom: 16, borderRadius: 6 }} />

          {/* photos */}
          <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)', marginBottom: 6 }}>사진 ({fPhotos.length}/5)</div>
          <div style={{ display: 'flex', gap: 8, overflowX: 'auto', marginBottom: 16, paddingBottom: 4 }} className="wu-scroll">
            {fPhotos.map((ph, i) => (
              <div key={i} style={{ position: 'relative', width: 80, height: 80, flexShrink: 0, borderRadius: 6, overflow: 'hidden', border: '1px solid var(--wu-line)' }}>
                <img src={ph} style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
                <button onClick={() => setFPhotos(prev => prev.filter((_, j) => j !== i))} style={{ position: 'absolute', top: 2, right: 2, width: 18, height: 18, background: 'rgba(200,0,0,0.85)', color: '#fff', border: 0, fontSize: 9, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', borderRadius: 999 }}>✕</button>
              </div>
            ))}
            {fPhotos.length < 5 && (
              <label style={{ width: 80, height: 80, border: '2px dashed var(--wu-line)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', flexShrink: 0, borderRadius: 6, flexDirection: 'column', gap: 2 }}>
                <span style={{ fontSize: 22, opacity: 0.4 }}>+</span>
                <span className="mono" style={{ fontSize: 8, color: 'var(--wu-mute)' }}>추가</span>
                <input type="file" accept="image/*" multiple onChange={handlePhotoUpload} style={{ display: 'none' }} />
              </label>
            )}
          </div>

          <button onClick={isEditing ? submitEdit : submitPost} className="wu-btn lime" style={{ width: '100%', padding: '14px', fontSize: 14, fontWeight: 700, borderRadius: 8 }}>{isEditing ? '수정 완료' : '게시글 등록'}</button>
        </div>
      </div>
    );
  }

  // ── LIST VIEW ──
  return (
    <div className="wu wu-scroll wu-consumer-wrap" style={{ height: '100%', overflow: 'auto', background: 'var(--wu-bg)', paddingBottom: 70 }}>
      {msg && <div style={{ position: 'fixed', top: 60, left: '50%', transform: 'translateX(-50%)', zIndex: 999, padding: '8px 18px', background: 'var(--wu-orange)', color: '#fff', fontFamily: 'Pretendard', fontSize: 13, fontWeight: 700, borderRadius: 20 }}>{msg}</div>}
      <div style={{ padding: 'calc(env(safe-area-inset-top, 20px) + 12px) 16px 8px' }}>
        <div className="mono" style={{ fontSize: 10, color: 'var(--wu-mute)' }}>BOARD · 게시판</div>
        <div className="display" style={{ fontSize: 32, marginTop: 4 }}>COMMUNITY</div>
      </div>

      {/* category filter tabs */}
      <div style={{ display: 'flex', gap: 0, padding: '0 16px', marginBottom: 8 }}>
        {['전체', ...cats].map(c => (
          <button key={c} onClick={() => setFilterCat(c)} className="kr" style={{ flex: 1, padding: '10px 0', fontSize: 13, fontWeight: filterCat === c ? 800 : 500, color: filterCat === c ? 'var(--wu-ink)' : 'var(--wu-mute)', background: 'none', border: 'none', borderBottom: filterCat === c ? '2px solid var(--wu-ink)' : '2px solid transparent', cursor: 'pointer' }}>{c}</button>
        ))}
      </div>

      {/* write button */}
      <div style={{ padding: '0 16px 8px', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <div className="mono" style={{ fontSize: 11, color: 'var(--wu-mute)' }}>{filtered.length}개 게시글</div>
        <button onClick={startWrite} className="wu-btn lime" style={{ fontSize: 11, padding: '8px 14px', borderRadius: 6 }}>+ 글쓰기</button>
      </div>

      <div style={{ padding: '0 16px' }}>
        {loading ? (
          <div style={{ textAlign: 'center', padding: '60px 20px' }}>
            <div className="kr" style={{ fontSize: 14, color: 'var(--wu-mute)' }}>로딩 중...</div>
          </div>
        ) : filtered.length === 0 ? (
          <div style={{ textAlign: 'center', padding: '60px 20px', background: 'var(--wu-paper)', border: '2px dashed var(--wu-line)', borderRadius: 8 }}>
            <div style={{ fontSize: 40, marginBottom: 8 }}>📋</div>
            <div className="kr" style={{ fontSize: 14, color: 'var(--wu-mute)' }}>등록된 게시글이 없습니다</div>
            <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginTop: 6 }}>첫 번째 글을 작성해보세요!</div>
          </div>
        ) : (
          <div style={{ display: 'grid', gap: 8 }}>
            {filtered.map(p => (
              <button key={p.id} onClick={() => { setSelected(p); setView('detail'); }} style={{ background: 'var(--wu-paper)', border: '1px solid var(--wu-line)', padding: '14px 16px', textAlign: 'left', cursor: 'pointer', width: '100%', borderRadius: 8 }}>
                <div style={{ display: 'flex', gap: 8, alignItems: 'center', marginBottom: 6 }}>
                  <span className="mono" style={{ fontSize: 9, padding: '2px 6px', background: catBadgeBg(p.category), color: '#fff', fontWeight: 700, borderRadius: 4 }}>{p.category}</span>
                  <span className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)' }}>{new Date(p.createdAt).toLocaleDateString('ko-KR')}</span>
                  {(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>
                <div className="kr" style={{ fontSize: 14, fontWeight: 700 }}>{p.title}</div>
                <div className="kr" style={{ fontSize: 12, color: 'var(--wu-mute)', marginTop: 4, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.body ? p.body.slice(0, 60) + '...' : ''}</div>
                <div className="mono" style={{ fontSize: 9, color: 'var(--wu-mute)', marginTop: 6 }}>{p.author}</div>
              </button>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

// Reply input sub-component for consumer board
function ConsumerReplyInput({ onSubmit }) {
  const [txt, setTxt] = useState('');
  return (
    <div style={{ marginTop: 8 }}>
      <textarea value={txt} onChange={e => setTxt(e.target.value)} placeholder="댓글을 입력하세요" className="kr" rows={3} style={{ width: '100%', padding: 10, border: '1px solid var(--wu-line)', background: 'var(--wu-paper)', fontSize: 13, lineHeight: 1.6, resize: 'none', outline: 'none', fontFamily: 'Pretendard', borderRadius: 6 }} />
      <button onClick={() => { if (txt.trim()) { onSubmit(txt.trim()); setTxt(''); }}} className="wu-btn lime" style={{ width: '100%', padding: '10px', fontSize: 12, fontWeight: 700, marginTop: 6, borderRadius: 6 }}>댓글 등록</button>
    </div>
  );
}

Object.assign(window, { ConsumerEvents, ConsumerWishlist, SignupConsumer, SignupOwnerPending, ConsumerShop, ConsumerBoard });
