// app.jsx — 카탈로그 메인
const { useState, useMemo, useEffect } = React;

const CAT = window.CATALOG;
const fmtKRW = (n) => "₩" + n.toLocaleString("ko-KR");

// ─── 카테고리 라벨 ───────────────────────────────────────
const CAT_LABEL = {
  road: "Road", gravel: "Gravel", mtb: "MTB", ebike: "E-bike", kids: "Kids",
};

// ─── HEADER ──────────────────────────────────────────────
function Header({ search, setSearch }) {
  return (
    <header className="cat-header">
      <div className="cat-header-inner">
        <a className="cat-brand" href="#">
          <img className="cat-brand-mark" src="assets/symbol-brush.svg" alt="" />
          <div>
            <div className="cat-brand-name">김성호바이크 세종점</div>
            <div className="cat-brand-sub">Kim Sungho Bike · Sejong</div>
          </div>
        </a>
        <div className="cat-header-sep" />
        <div className="cat-header-title">
          2026 <b>Specialized</b> Catalog
        </div>
        <div className="cat-header-tools">
          <div className="cat-search">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
            <input
              placeholder="모델명 · SKU · 그룹세트 검색"
              value={search}
              onChange={(e) => setSearch(e.target.value)}
            />
          </div>
          <span>업데이트 <b>{CAT.meta.asOf}</b></span>
          {/* U-A2: 신상 등록 CTA (owner/mechanic 권한) */}
          {(!window.AUTH || ["owner","mechanic"].includes(window.AUTH?.role)) && (
            <button className="cat-print-btn"
              style={{background:"var(--red-500,#E31E26)",color:"#fff",borderColor:"var(--red-500,#E31E26)"}}
              onClick={() => location.href = "재고관리.html#new-bike"}>
              + 신상 등록
            </button>
          )}
          <button className="cat-print-btn" onClick={() => window.print()}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><polyline points="6 9 6 2 18 2 18 9"/><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/><rect width="12" height="8" x="6" y="14"/></svg>
            PDF 출력
          </button>
        </div>
      </div>
    </header>
  );
}

// ─── HERO ────────────────────────────────────────────────
function Hero() {
  const totalModels = CAT.bikes.length;
  const totalStock = CAT.bikes.reduce((a, b) => a + b.stock, 0);
  const minPrice = Math.min(...CAT.bikes.map(b => b.priceShop));
  const minWeight = Math.min(...CAT.bikes.map(b => b.weightKg));

  return (
    <section className="cat-hero">
      <img className="cat-hero-wordmark" src="assets/wordmark-specialized.svg" alt="" />
      <div className="cat-inner cat-hero-inner">
        <div>
          <div className="cat-hero-eyebrow">{CAT.meta.season} · {CAT.meta.shop}</div>
          <h1 className="cat-hero-title">
            가벼움도,<br />
            기록도,<br />
            한 권에서 <i>고른다.</i>
          </h1>
          <p className="cat-hero-sub">
            세종점이 직접 셀렉트한 16 모델의 무게 · 가격 · 재고를 한 페이지에서.
            동호회 라이더에게 추천하는 비교 코멘트와 사장님 세일즈 포인트까지.
          </p>
        </div>
        <div className="cat-hero-stats">
          <div className="cat-hero-stat">
            <div className="cat-hero-stat-l">총 모델</div>
            <div className="cat-hero-stat-v">{totalModels}<small>대</small></div>
          </div>
          <div className="cat-hero-stat">
            <div className="cat-hero-stat-l">즉시 출고</div>
            <div className="cat-hero-stat-v">{totalStock}<small>대</small></div>
          </div>
          <div className="cat-hero-stat">
            <div className="cat-hero-stat-l">최저 시작가</div>
            <div className="cat-hero-stat-v">{(minPrice/10000).toFixed(0)}<small>만원~</small></div>
          </div>
          <div className="cat-hero-stat">
            <div className="cat-hero-stat-l">최경량 (S-Works)</div>
            <div className="cat-hero-stat-v">{minWeight}<small>kg</small></div>
          </div>
        </div>
      </div>
    </section>
  );
}

// ─── PAGE NAV (catalog ↔ inventory) ──────────────────────
function PageNav({ active }) {
  return (
    <nav className="cat-pagenav">
      <div className="cat-pagenav-inner">
        <a className={active === "admin" ? "on" : ""} href="관리자.html">
          관리자 <small>Admin</small>
        </a>
        <a href="스케줄러.html">스케줄러 <small>Scheduler</small></a>
        <a className={active === "catalog" ? "on" : ""} href="2026 카탈로그.html">
          카탈로그 <small>Catalog</small>
        </a>
        <a className={active === "inventory" ? "on" : ""} href="재고관리.html">
          재고관리 <small>Inventory</small>
        </a>
        <a className={active === "quote" ? "on" : ""} href="서비스 견적서.html">
          서비스 견적서 <small>Estimate</small>
        </a>
        <div className="cat-pagenav-r">
          <span>마지막 갱신 · <b>{CAT.meta.asOf}</b> · {CAT.meta.updated}</span>
        </div>
      </div>
    </nav>
  );
}

// ─── SPOTLIGHT — featured bike of the season ─────────────
function Spotlight({ bike, setActive }) {
  if (!bike) return null;
  return (
    <section className="cat-section">
      <div className="cat-inner">
        <div className="cat-section-head">
          <div>
            <div className="cat-section-eyebrow">Spotlight · 이번 시즌 추천</div>
            <h2 className="cat-section-title">사장님 픽 · {bike.name}</h2>
          </div>
          <p className="cat-section-sub">
            동호회 라이더 가장 많이 묻는 모델. 시승 가능, 사이즈별 컬러 보유.
          </p>
        </div>
        <article className="cat-spotlight" onClick={() => setActive(bike)} style={{cursor:"pointer"}}>
          <div className="cat-spotlight-visual" style={{ background: bike.gradient }}>
            <div className="cat-spotlight-num">EDITOR'S PICK · 01</div>
            <div className="cat-spotlight-bignum">{bike.weightKg}</div>
            <img className="cat-spotlight-mark" src="assets/wordmark-specialized.svg" alt="" />
          </div>
          <div className="cat-spotlight-body">
            <div className="cat-spotlight-eyebrow">{bike.eyebrow} · {bike.tier}</div>
            <h3 className="cat-spotlight-title">{bike.name}</h3>
            <p className="cat-spotlight-sub">{bike.sales}</p>
            <ul className="cat-spotlight-bullets">
              <li>{bike.frame} 프레임 — 동급 최경량 클래스</li>
              <li>{bike.group} — 매장에서 즉시 시승 가능</li>
              <li>구매 후 4주 내 사이즈 1회 무료 교환 + 평생 1차 정비</li>
            </ul>
            <div className="cat-spotlight-row">
              <div className="cat-spotlight-stat">
                <small>완차 무게</small>
                <b>{bike.weightKg}<em>kg</em></b>
              </div>
              <div className="cat-spotlight-stat">
                <small>매장 판매가</small>
                <b>{(bike.priceShop/10000).toFixed(0)}<em>만원</em></b>
              </div>
              <div className="cat-spotlight-stat">
                <small>매장 재고</small>
                <b>{bike.stock}<em>대</em></b>
              </div>
            </div>
            <div className="cat-spotlight-cta">
              <button className="cat-btn cat-btn-primary" onClick={(e)=>{e.stopPropagation(); setActive(bike);}}>상세 보기</button>
              <button className="cat-btn cat-btn-secondary" onClick={(e)=>e.stopPropagation()}>시승 예약</button>
            </div>
          </div>
        </article>
      </div>
    </section>
  );
}

// ─── SERIES LADDER — 시리즈 계보 ────────────────────────
function SeriesLadder({ setActive }) {
  // Tarmac / Roubaix / Diverge / Epic / Stumpjumper / Turbo Creo — top 6
  const focusSeries = ["Tarmac", "Roubaix", "Diverge", "Epic", "Stumpjumper", "Turbo Creo"];
  const byBike = (sku) => CAT.bikes.find(b => b.sku === sku);

  return (
    <section className="cat-section">
      <div className="cat-inner">
        <div className="cat-section-head">
          <div>
            <div className="cat-section-eyebrow">Line-up ladder · 시리즈 계보</div>
            <h2 className="cat-section-title">같은 이름, 다른 등급</h2>
          </div>
          <p className="cat-section-sub">
            한 시리즈 안에서 등급(S-Works → Pro → Expert → Comp)에 따라 프레임 · 구동계 · 가격이 어떻게 달라지는지.
          </p>
        </div>
        <div className="cat-ladder-grid">
          {focusSeries.map(series => {
            const meta = CAT.seriesMeta[series];
            const list = CAT.bikes.filter(b => b.series === series).sort((a,b) => b.priceShop - a.priceShop);
            if (list.length === 0) return null;
            return (
              <div key={series} className="cat-ladder-card">
                <div className="cat-ladder-cat">{CAT_LABEL[meta.cat]}</div>
                <div className="cat-ladder-name">{series}</div>
                <div className="cat-ladder-tagline">{meta.tagline}</div>
                <div className="cat-ladder-rows">
                  {list.map(b => (
                    <div key={b.sku} className="cat-ladder-row" onClick={() => setActive(b)} style={{cursor:"pointer"}}>
                      <b>{b.tier}</b>
                      <span>
                        {b.weightKg}kg
                        <small>{b.group}</small>
                      </span>
                      <em>{(b.priceShop/10000).toFixed(0)}만</em>
                    </div>
                  ))}
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </section>
  );
}

// ─── EDITORIALS — 비교 사설 ─────────────────────────────
function Editorials() {
  return (
    <section className="cat-section">
      <div className="cat-inner">
        <div className="cat-section-head">
          <div>
            <div className="cat-section-eyebrow">From the shop floor</div>
            <h2 className="cat-section-title">사장님의 비교 노트</h2>
          </div>
          <p className="cat-section-sub">
            10년 넘게 매장에서 듣고 답해온 질문을 그대로 정리했다. 같이 망설이는 차종이 있다면 먼저 읽어보길.
          </p>
        </div>
        <div className="cat-edit-grid">
          {CAT.editorials.map((ed, i) => (
            <article className="cat-edit" key={i}>
              <div className="cat-edit-tags">
                {ed.tags.map(t => <span key={t} className="cat-edit-tag">{t}</span>)}
              </div>
              <h3 className="cat-edit-title">{ed.title}</h3>
              <p className="cat-edit-lead">{ed.lead}</p>
              <div className="cat-edit-body">
                {ed.body.map((p, j) => (
                  <p key={j}><span className="cat-edit-num">0{j+1}</span>{p}</p>
                ))}
              </div>
            </article>
          ))}
        </div>
      </div>
    </section>
  );
}

// ─── SALES POINTS — 매장 직원이 외워야 할 한 줄 ──────
function SalesPoints() {
  return (
    <section className="cat-section">
      <div className="cat-inner">
        <div className="cat-section-head">
          <div>
            <div className="cat-section-eyebrow">Why 세종점</div>
            <h2 className="cat-section-title">매장 전용 세일즈 포인트</h2>
          </div>
          <p className="cat-section-sub">
            카탈로그를 보는 손님에게 반드시 한 번씩 짚어드릴 것. 가격으로만 경쟁하지 않는다.
          </p>
        </div>
        <div className="cat-sales-grid">
          {CAT.salesPoints.map((sp, i) => (
            <div className="cat-sales-cell" key={i}>
              <div className="cat-sales-k">{sp.k}</div>
              <div className="cat-sales-v">{sp.v}</div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// ─── WEIGHT COMPARISON CHART ─────────────────────────────
function WeightChart() {
  // 무게: 6 kg ~ 24 kg 범위 — 한 화면에 정렬해서 비교
  const sorted = useMemo(
    () => [...CAT.bikes].sort((a, b) => a.weightKg - b.weightKg),
    []
  );
  const MIN = 5, MAX = 24;
  const ticks = [5, 10, 15, 20, 24];

  return (
    <section className="cat-section">
      <div className="cat-inner">
        <div className="cat-section-head">
          <div>
            <div className="cat-section-eyebrow">Weight at a glance</div>
            <h2 className="cat-section-title">무게 비교 · 16 모델 한 눈에</h2>
          </div>
          <p className="cat-section-sub">
            사이즈 56 (로드/그래블) / M (MTB/E-bike) · 페달 제외 · 카탈로그 스펙 기준.
          </p>
        </div>
        <div className="cat-weight-card">
          <div className="cat-weight-head">
            <div className="cat-weight-h">단위 · kg · 가벼운 순</div>
            <div className="cat-weight-legend">
              <span><i style={{background:"#1B1B1F"}} />Road</span>
              <span><i style={{background:"#FF6B00"}} />Gravel</span>
              <span><i style={{background:"#74777F"}} />MTB</span>
              <span><i style={{background:"#3B82F6"}} />E-bike</span>
              <span><i style={{background:"#22C55E"}} />Kids</span>
            </div>
          </div>
          <div className="cat-weight-rows">
            {sorted.map((b) => {
              const pct = ((b.weightKg - MIN) / (MAX - MIN)) * 100;
              return (
                <div className="cat-weight-row" key={b.sku}>
                  <div className="cat-weight-name">
                    <b>{b.name}</b>
                    <small>{CAT_LABEL[b.cat]} · {b.tier}</small>
                  </div>
                  <div className="cat-weight-track">
                    <div className={"cat-weight-fill cat-" + b.cat} style={{ width: pct + "%" }} />
                  </div>
                  <div className="cat-weight-val">{b.weightKg}<small>kg</small></div>
                </div>
              );
            })}
          </div>
          <div className="cat-weight-axis">
            <div />
            <div className="cat-weight-axis-ticks">
              {ticks.map(t => <span key={t}>{t} kg</span>)}
            </div>
            <div />
          </div>
        </div>
      </div>
    </section>
  );
}

// ─── PRODUCT GRID ────────────────────────────────────────
function ProductGrid({ filterCat, setActive }) {
  const list = useMemo(
    () => CAT.bikes.filter(b => filterCat === "all" || b.cat === filterCat),
    [filterCat]
  );

  return (
    <section className="cat-section" id="grid">
      <div className="cat-inner">
        <div className="cat-section-head">
          <div>
            <div className="cat-section-eyebrow">Product list · {list.length} 모델</div>
            <h2 className="cat-section-title">제품 목록</h2>
          </div>
          <p className="cat-section-sub">
            카드 하나에 핵심 스펙(무게 · 그룹세트 · 재고)과 세일즈 포인트가 함께. 카드 클릭 시 상세.
          </p>
        </div>
        <div className="cat-pgrid">
          {list.map(b => (
            <article key={b.sku} className="cat-pcard" onClick={() => setActive(b)}>
              <div className="cat-pcard-img" style={{ background: b.gradient }}>
                <span className="cat-pcard-img-tier">{b.tier}</span>
                <span className={"cat-pcard-status " + b.statusTone}>{b.status}</span>
                <img className="cat-pcard-img-mark" src="assets/wordmark-specialized.svg" alt="" />
              </div>
              <div className="cat-pcard-body">
                <div className="cat-pcard-eyebrow">{b.eyebrow}</div>
                <div className="cat-pcard-title">{b.name}</div>
                <div className="cat-pcard-group">{b.group}</div>
                <div className="cat-pcard-sales">{b.sales}</div>
                <div className="cat-pcard-stats">
                  <div className="cat-pcard-stat">
                    <b>{b.weightKg}<small>kg</small></b>
                    <span>무게</span>
                  </div>
                  <div className="cat-pcard-stat">
                    <b>{b.sizes.length}<small>종</small></b>
                    <span>사이즈</span>
                  </div>
                  <div className="cat-pcard-stat">
                    <b>{b.stock}<small>대</small></b>
                    <span>재고</span>
                  </div>
                </div>
              </div>
              <div className="cat-pcard-bottom">
                <div className="cat-pcard-price">
                  <small>매장가</small>
                  <div>
                    {b.priceRetail !== b.priceShop && <s>{fmtKRW(b.priceRetail)}</s>}
                    <b>{fmtKRW(b.priceShop)}</b>
                  </div>
                </div>
                <div className="cat-pcard-colors">
                  {b.colors.map((c, i) => <span key={i} className="cat-pcard-color" style={{ background: c }} />)}
                </div>
              </div>
            </article>
          ))}
        </div>
      </div>
    </section>
  );
}

// ─── INVENTORY TABLE ─────────────────────────────────────
const COLUMNS = [
  { id: "sku",       label: "SKU",       cls: "mono", w: 124 },
  { id: "name",      label: "모델",       w: 280 },
  { id: "cat",       label: "카테고리",   w: 92 },
  { id: "group",     label: "구동계",     w: 200 },
  { id: "frame",     label: "프레임",     w: 180 },
  { id: "weightKg",  label: "무게",       cls: "num", num: true, w: 78 },
  { id: "sizes",     label: "사이즈",     w: 160 },
  { id: "colors",    label: "컬러",       w: 80 },
  { id: "stock",     label: "재고",       cls: "num", num: true, w: 70 },
  { id: "status",    label: "상태",       w: 100 },
  { id: "priceShop", label: "매장가",     cls: "num", num: true, w: 130 },
];

function InventoryTable({ filterCat, search }) {
  const [sortBy, setSortBy] = useState({ key: "name", dir: "asc" });

  const rows = useMemo(() => {
    const q = search.trim().toLowerCase();
    let r = CAT.bikes.filter(b =>
      (filterCat === "all" || b.cat === filterCat) &&
      (!q ||
        b.name.toLowerCase().includes(q) ||
        b.sku.toLowerCase().includes(q) ||
        b.group.toLowerCase().includes(q) ||
        b.series.toLowerCase().includes(q))
    );
    const dir = sortBy.dir === "asc" ? 1 : -1;
    r = [...r].sort((a, b) => {
      const av = a[sortBy.key], bv = b[sortBy.key];
      if (typeof av === "number") return (av - bv) * dir;
      return String(av).localeCompare(String(bv), "ko") * dir;
    });
    return r;
  }, [filterCat, search, sortBy]);

  const totalValue = rows.reduce((a, b) => a + b.priceShop * b.stock, 0);
  const totalStock = rows.reduce((a, b) => a + b.stock, 0);

  const toggleSort = (key) => {
    setSortBy(s => s.key === key ? { key, dir: s.dir === "asc" ? "desc" : "asc" } : { key, dir: "asc" });
  };

  return (
    <section className="cat-section" id="inventory">
      <div className="cat-inner">
        <div className="cat-section-head">
          <div>
            <div className="cat-section-eyebrow">Inventory · all visible</div>
            <h2 className="cat-section-title">재고표 · {rows.length} 라인</h2>
          </div>
          <p className="cat-section-sub">
            컬럼 헤더 클릭 시 정렬. 검색 / 카테고리 필터는 표 위에서 적용.
          </p>
        </div>
        <div className="cat-tbl-wrap">
          <div className="cat-tbl-header">
            <div className="cat-tbl-h">재고 합계 · 매장 단가 기준</div>
            <div className="cat-tbl-meta">
              <span>표시 <b>{rows.length}</b> 라인</span>
              <span>재고 <b>{totalStock}</b>대</span>
              <span>총 평가액 <b>{fmtKRW(totalValue)}</b></span>
            </div>
          </div>
          <table className="cat-tbl">
            <thead>
              <tr>
                {COLUMNS.map(c => (
                  <th
                    key={c.id}
                    style={{ width: c.w }}
                    className={(c.num ? "num " : "") + (sortBy.key === c.id ? "sorted" : "")}
                    onClick={() => toggleSort(c.id)}
                  >
                    {c.label}
                    <span className="sort-arrow">
                      {sortBy.key === c.id ? (sortBy.dir === "asc" ? "▲" : "▼") : "↕"}
                    </span>
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              {rows.map(b => (
                <tr key={b.sku}>
                  <td className="mono">{b.sku}</td>
                  <td>
                    <div className="cat-tbl-name">
                      <div className="cat-tbl-sw" style={{ background: b.gradient }} />
                      <div>
                        <b>{b.name}</b>
                        <small>{b.tier} · {b.series}</small>
                      </div>
                    </div>
                  </td>
                  <td><span className={"cat-tbl-cat " + b.cat}>{CAT_LABEL[b.cat]}</span></td>
                  <td>{b.group}</td>
                  <td style={{color:"var(--fg-secondary)"}}>{b.frame}</td>
                  <td className="num"><b>{b.weightKg}</b> <small style={{color:"var(--fg-tertiary)"}}>kg</small></td>
                  <td>
                    <div className="cat-tbl-sizes">
                      {b.sizes.map(s => <span key={s}>{s}</span>)}
                    </div>
                  </td>
                  <td>
                    <div className="cat-tbl-colors">
                      {b.colors.map((c, i) => <span key={i} className="cat-tbl-color" style={{ background: c }} />)}
                    </div>
                  </td>
                  <td className="num">
                    <span className={"cat-tbl-stock " + (b.stock === 0 ? "out" : b.stock <= 1 ? "low" : "ok")}>
                      {b.stock === 0 ? "—" : b.stock}
                    </span>
                  </td>
                  <td>
                    <span className={"cat-tbl-status " + b.statusTone}>{b.status}</span>
                  </td>
                  <td className="num cat-tbl-price">
                    <b>{fmtKRW(b.priceShop)}</b>
                    {b.priceRetail !== b.priceShop && <s>{fmtKRW(b.priceRetail)}</s>}
                  </td>
                </tr>
              ))}
              {rows.length === 0 && (
                <tr><td colSpan={COLUMNS.length} style={{padding:"48px", textAlign:"center", color:"var(--fg-tertiary)"}}>검색 결과 없음.</td></tr>
              )}
            </tbody>
          </table>
        </div>
      </div>
    </section>
  );
}

// ─── PRODUCT DRAWER ──────────────────────────────────────
// v3.16: 신장 입력 → 사이즈 자동 추천 위젯 (회의록 v3.16 §3.2)
function HeightRecommender({ bike }) {
  const [height, setHeight] = React.useState(() => {
    try { return localStorage.getItem("sejong-my-height") || ""; } catch { return ""; }
  });

  // size_height_map은 Supabase view에서 오거나, bike.sizeHeightMap (mock)에서 옴
  const heightMap = React.useMemo(() => {
    // Supabase 형식: [{size, height_min_cm, height_max_cm, note}, ...]
    if (Array.isArray(bike.size_height_map)) return bike.size_height_map;
    // mock/내부 형식: {size: {h1, h2}}
    if (bike.sizeHeightMap && typeof bike.sizeHeightMap === "object") {
      return Object.entries(bike.sizeHeightMap).map(([size, h]) => ({
        size, height_min_cm: h.h1, height_max_cm: h.h2,
      }));
    }
    return [];
  }, [bike]);

  const hasHeightData = heightMap.some(h => h.height_min_cm && h.height_max_cm);

  // 추천 사이즈 (중심값 최근접)
  const recommended = React.useMemo(() => {
    const h = Number(height);
    if (!h || !hasHeightData) return null;
    const matches = heightMap
      .filter(x => x.height_min_cm && x.height_max_cm && h >= x.height_min_cm && h <= x.height_max_cm)
      .map(x => ({ ...x, distance: Math.abs(((x.height_min_cm + x.height_max_cm) / 2) - h) }))
      .sort((a, b) => a.distance - b.distance);
    return matches[0] || null;
  }, [height, heightMap, hasHeightData]);

  React.useEffect(() => {
    if (height) { try { localStorage.setItem("sejong-my-height", height); } catch {} }
  }, [height]);

  if (!hasHeightData) {
    return (
      <div className="cat-drawer-row" style={{flexDirection:"column", alignItems:"flex-start", gap:6}}>
        <span className="cat-drawer-row-l">📏 추천 신장</span>
        <div style={{fontSize:12, color:"var(--fg-quaternary)", padding:"8px 12px", background:"var(--neutral-50,#F9F9F9)", borderRadius:6, width:"100%"}}>
          신장 정보가 아직 입력되지 않았습니다. 사장님께 문의해주세요.
        </div>
      </div>
    );
  }

  return (
    <div className="cat-drawer-row" style={{flexDirection:"column", alignItems:"flex-start", gap:8}}>
      <span className="cat-drawer-row-l">📏 사이즈 추천</span>

      {/* 사이즈별 신장 범위 표 */}
      <div style={{display:"flex", flexWrap:"wrap", gap:4, width:"100%"}}>
        {heightMap.map(h => {
          const isMatch = recommended && recommended.size === h.size;
          return (
            <div key={h.size} style={{
              padding:"6px 10px", borderRadius:6,
              border:"1px solid " + (isMatch ? "#E31E26" : "var(--grey-200,#E5E8EB)"),
              background: isMatch ? "var(--red-50,#FFE5E6)" : "#fff",
              fontSize:11, lineHeight:1.3, minWidth:64, textAlign:"center",
            }}>
              <div style={{fontSize:12, fontWeight:700, color: isMatch ? "#E31E26" : "var(--fg-primary)"}}>{h.size}</div>
              {h.height_min_cm && h.height_max_cm
                ? <div style={{color: isMatch ? "#9A0E14" : "var(--fg-tertiary)"}}>{h.height_min_cm}~{h.height_max_cm}cm</div>
                : <div style={{color:"var(--fg-quaternary)", fontSize:10}}>—</div>
              }
            </div>
          );
        })}
      </div>

      {/* 신장 입력 + 자동 추천 */}
      <div style={{display:"flex", gap:6, alignItems:"center", width:"100%"}}>
        <input
          type="number"
          value={height}
          onChange={e=>setHeight(e.target.value)}
          placeholder="내 신장 입력 (cm)"
          min="80" max="230"
          style={{width:130, padding:"6px 10px", border:"1px solid var(--grey-300,#D1D6DB)", borderRadius:6, fontSize:13}}
        />
        <span style={{fontSize:12, color:"var(--fg-tertiary)"}}>cm</span>
        {recommended && (
          <span style={{
            marginLeft:8, padding:"4px 10px", background:"#E31E26", color:"#fff",
            borderRadius:14, fontSize:12, fontWeight:700,
          }}>💡 추천 사이즈: {recommended.size}</span>
        )}
        {height && !recommended && hasHeightData && (
          <span style={{marginLeft:8, fontSize:11, color:"var(--fg-quaternary)"}}>
            범위 밖 — 시승 추천
          </span>
        )}
      </div>

      <div style={{fontSize:10, color:"var(--fg-quaternary)"}}>
        ※ 참고용 · 시승 후 최종 확정 권장 · 고관절 유연성/팔 길이에 따라 1cm 위/아래 사이즈 적합 가능
      </div>
    </div>
  );
}

function Drawer({ bike, onClose }) {
  if (!bike) return null;
  useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  return (
    <>
      <div className="cat-drawer-scrim" onClick={onClose} />
      <aside className="cat-drawer">
        <div className="cat-drawer-hero" style={{ background: bike.gradient }}>
          <button className="cat-drawer-x" onClick={onClose}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#1B1B1F" strokeWidth="2"><path d="M18 6 6 18M6 6l12 12"/></svg>
          </button>
          <span className={"cat-pcard-status " + bike.statusTone + " cat-drawer-hero-status"}>{bike.status}</span>
          <img className="cat-drawer-hero-mark" src="assets/wordmark-specialized.svg" alt="" />
        </div>
        <div className="cat-drawer-body">
          <div className="cat-drawer-eyebrow">{bike.eyebrow}</div>
          <div>
            <div className="cat-drawer-title">{bike.name}</div>
            <div className="cat-drawer-group">{bike.tier} · {bike.group}</div>
          </div>
          <div className="cat-drawer-sales">{bike.sales}</div>

          <div className="cat-drawer-specs">
            <div className="cat-drawer-spec">
              <div className="cat-drawer-spec-l">무게</div>
              <div className="cat-drawer-spec-v">{bike.weightKg} kg</div>
            </div>
            <div className="cat-drawer-spec">
              <div className="cat-drawer-spec-l">프레임</div>
              <div className="cat-drawer-spec-v">{bike.frame}</div>
            </div>
            <div className="cat-drawer-spec">
              <div className="cat-drawer-spec-l">휠셋</div>
              <div className="cat-drawer-spec-v">{bike.wheels}</div>
            </div>
            <div className="cat-drawer-spec">
              <div className="cat-drawer-spec-l">브레이크</div>
              <div className="cat-drawer-spec-v">{bike.brake}</div>
            </div>
            <div className="cat-drawer-spec">
              <div className="cat-drawer-spec-l">SKU</div>
              <div className="cat-drawer-spec-v" style={{fontFamily:"var(--font-mono)",fontSize:13}}>{bike.sku}</div>
            </div>
            <div className="cat-drawer-spec">
              <div className="cat-drawer-spec-l">매장 재고</div>
              <div className="cat-drawer-spec-v">{bike.stock === 0 ? "입고 대기" : bike.stock + "대"}</div>
            </div>
          </div>

          <div className="cat-drawer-row">
            <span className="cat-drawer-row-l">사이즈</span>
            <div className="cat-tbl-sizes">{bike.sizes.map(s => <span key={s}>{s}</span>)}</div>
          </div>

          {/* v3.16: 신장별 사이즈 추천 위젯 */}
          <HeightRecommender bike={bike} />

          <div className="cat-drawer-row">
            <span className="cat-drawer-row-l">컬러</span>
            <div className="cat-pcard-colors">{bike.colors.map((c,i) => <span key={i} className="cat-pcard-color" style={{background:c, width:22, height:22}} />)}</div>
          </div>

          <div className="cat-drawer-prices">
            <div className="cat-drawer-price">
              <small>권장 소비자가</small>
              <b style={{textDecoration: bike.priceRetail !== bike.priceShop ? "line-through" : "none", color: bike.priceRetail !== bike.priceShop ? "var(--fg-quaternary)" : ""}}>{fmtKRW(bike.priceRetail)}</b>
            </div>
            <div className="cat-drawer-price shop">
              <small>매장 판매가</small>
              <b>{fmtKRW(bike.priceShop)}</b>
            </div>
          </div>

          {/* U-A1: 운영자 액션 (owner/mechanic 권한) */}
          {(!window.AUTH || ["owner","mechanic"].includes(window.AUTH?.role)) && (
            <div className="cat-drawer-actions" style={{borderTop:"1px solid var(--grey-200,#E5E8EB)",paddingTop:12,marginTop:8}}>
              <button className="cat-btn cat-btn-secondary"
                onClick={() => alert("수정 모달 — v1.3 출시 예정\nDAL.updateBike 통합 필요")}
                title="가격/스펙 수정">✏️ 수정</button>
              <button className="cat-btn cat-btn-secondary"
                onClick={() => alert("이미지 변경 — v1.3 출시 예정\nSTORAGE.registerBikeMedia 통합")}
                title="이미지 변경">🖼 이미지</button>
              <button className="cat-btn cat-btn-secondary"
                onClick={() => { location.href = `재고관리.html#sku=${encodeURIComponent(bike.sku||bike.base_sku||"")}`; }}
                title="재고 페이지로">📦 입고</button>
            </div>
          )}
          <div className="cat-drawer-actions">
            <button className="cat-btn cat-btn-secondary">시승 예약</button>
            <button className="cat-btn cat-btn-primary">구매 문의</button>
          </div>
        </div>
      </aside>
    </>
  );
}

// ─── CATEGORY STRIP ──────────────────────────────────────
function CategoryStrip({ cat, setCat, view, setView }) {
  return (
    <div className="cat-cats">
      <div className="cat-cats-inner">
        {CAT.categories.map(c => (
          <button
            key={c.id}
            className={"cat-cat-chip " + (cat === c.id ? "active" : "")}
            onClick={() => setCat(c.id)}
          >
            {c.label} <small>{c.hint}</small>
          </button>
        ))}
        <div className="cat-cats-r">
          <span>보기</span>
          <div className="cat-view-toggle">
            <button className={view === "both" ? "on" : ""} onClick={() => setView("both")}>전체</button>
            <button className={view === "grid" ? "on" : ""} onClick={() => setView("grid")}>카드만</button>
            <button className={view === "table" ? "on" : ""} onClick={() => setView("table")}>표만</button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ─── FOOTER ──────────────────────────────────────────────
function Footer() {
  return (
    <footer className="cat-footer">
      <div className="cat-inner cat-footer-inner">
        <div className="cat-footer-brand">
          <img className="cat-footer-mark" src="assets/symbol-brush-sejong.svg" alt="" />
          <div>
            <div className="cat-footer-name">김성호바이크 세종점 · 2026 카탈로그</div>
            <div className="cat-footer-sub">세종특별자치시 한누리대로 1234 · 044-865-0000 · 월–토 10:00~19:00</div>
          </div>
        </div>
        <div className="cat-footer-meta">
          <span>모든 가격 · 사양은 카탈로그 발행일 기준이며 사전 고지 없이 변경될 수 있습니다.</span>
          <img className="cat-footer-wordmark" src="assets/wordmark-specialized.svg" alt="Specialized" />
        </div>
      </div>
    </footer>
  );
}

// ─── APP ─────────────────────────────────────────────────
function App() {
  const [cat, setCat] = useState("all");
  const [search, setSearch] = useState("");
  const [view, setView] = useState("both"); // both | grid | table
  const [active, setActive] = useState(null);

  const spotlight = CAT.bikes.find(b => b.sku === "TSL8-EXP-56");

  return (
    <div className="cat-app">
      <Header search={search} setSearch={setSearch} />
      {/* Hero 섹션 제거 (v3.7 사용자 요청) */}
      <PageNav active="catalog" />
      <Spotlight bike={spotlight} setActive={setActive} />
      <SalesPoints />
      <Editorials />
      <SeriesLadder setActive={setActive} />
      <WeightChart />
      <CategoryStrip cat={cat} setCat={setCat} view={view} setView={setView} />
      {(view === "both" || view === "grid") && <ProductGrid filterCat={cat} setActive={setActive} />}
      {(view === "both" || view === "table") && <InventoryTable filterCat={cat} search={search} />}
      <Footer />
      <Drawer bike={active} onClose={() => setActive(null)} />
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
