// 빌리조 랜딩 — 섹션 컴포넌트 (hooks.jsx, icons.jsx 선행 로드)
// Expects: window.I, window.ProductArt, window.HeroVisual, window.cardDesigns,
//          window.useCountUp, window.useInView

const { useState, useEffect, useRef } = React;

// 카탈로그 제품 → 수집한 admin2 제품키(브랜드+유형 기준 대표 수집 모델). 정확 모델 없으면 가장 가까운 수집 모델.
const REVIEW_MODEL = {
  '코웨이':     { _default: 'coway-icon' },
  '청호나이스': { ice: 'chungho-icetree-fly', _default: 'chungho-self-oatmeal' },
  'LG':        { _default: 'lge-wd323acb' },
  '삼성':       { _default: 'samsung-rwp54421bf7m' },
  '루헨스':     { _default: 'cafe24-whp-5400' },
  '노비타':     { _default: 'cafe24-bd-h710h0' },
  '블루에어':   { _default: 'cafe24-7440i' },
};
function reviewKeyFor(p) {
  const m = p && REVIEW_MODEL[p.brand];
  if (!m) return '';
  return (p.v && m[p.v]) || m._default || '';
}

// admin2 후기 인덱스 — 브랜드별 총수 + 제품키별 수. 모듈 캐시 + 훅.
const _reviewBrandCache = {}; // brand -> { total, products:{key:count} }
function useReviewIndex(brands) {
  const [idx, setIdx] = useState({ brands: {}, products: {} });
  const key = (brands || []).filter(Boolean).join('|');
  useEffect(() => {
    let alive = true;
    const uniq = Array.from(new Set((brands || []).filter(Boolean)));
    Promise.all(uniq.map((b) =>
      _reviewBrandCache[b]
        ? Promise.resolve([b, _reviewBrandCache[b]])
        : fetch('/api/reviews?brand=' + encodeURIComponent(b) + '&limit=100')
            .then((r) => r.json())
            .then((d) => {
              const items = ((d && d.items) || []).filter(visibleReview); // 아정당 등 숨김 출처는 건수에서도 제외
              const products = {};
              items.forEach((it) => { const k = it.product || ''; if (k) products[k] = (products[k] || 0) + 1; });
              const v = { total: items.length, products };
              _reviewBrandCache[b] = v; return [b, v];
            })
            .catch(() => [b, { total: 0, products: {} }])
    )).then((pairs) => {
      if (!alive) return;
      const brandsMap = {}, productsMap = {};
      pairs.forEach(([b, v]) => { brandsMap[b] = v.total; Object.assign(productsMap, v.products); });
      setIdx({ brands: brandsMap, products: productsMap });
    });
    return () => { alive = false; };
  }, [key]);
  return idx;
}
// 카탈로그 제품의 노출 후기수: 매핑된 수집 모델 수 우선, 없으면 브랜드 총수
function reviewCountOf(idx, p) {
  const rk = reviewKeyFor(p);
  if (rk && idx.products[rk] > 0) return idx.products[rk];
  return idx.brands[p.brand] || 0;
}

const LOGO_SRC = 'logo.png';
const MAIN_PHONE = '1577-0000';
const MAIN_PHONE_HREF = 'tel:1577-0000';
const BILLYJO_SITE = 'https://www.billyjo.co.kr/';

/* 영문 이미지 로고 ↔ 한글 워드마크(투명) 교차 노출 */
function BrandLogo({ className }) {
  const [ko, setKo] = useState(false);
  useEffect(() => {
    const t = setInterval(() => setKo((k) => !k), 4500);
    return () => clearInterval(t);
  }, []);
  return ko
    ? <span className={'brand-wordmark' + (className ? ' ' + className : '')} aria-label="빌리조">빌리조</span>
    : <img className={className} src={LOGO_SRC} alt="빌리조" />;
}

/* ---------- Product image (원격/로컬 URL + 로드 실패 시 SVG) ---------- */
function ProductThumb({ variant, image, name }) {
  const [broken, setBroken] = useState(false);
  return (
    <div className="product__thumb-layer">
      {broken || !image ? (
        <ProductArt variant={variant} />
      ) : (
        <img
          className="product__photo"
          src={image}
          alt={name}
          loading="lazy"
          decoding="async"
          onError={() => setBroken(true)}
        />
      )}
    </div>
  );
}

/* ---------- 실시간 방문자 느낌 (스크롤 후 표시) ---------- */
function LiveViewingBar({ hasStickyCta, onPick }) {
  const [visible, setVisible] = useState(false);
  const [count, setCount] = useState(() => 28 + Math.floor(Math.random() * 52));
  const [prod, setProd] = useState({ slug: '', label: '인기 렌탈 제품' });

  useEffect(() => {
    const onScroll = () => {
      if (window.scrollY > 140) setVisible(true);
    };
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, []);

  useEffect(() => {
    if (!visible) return;
    let t;
    const bump = () => {
      setCount((c) => {
        const delta = Math.floor(Math.random() * 9) - 3;
        return Math.min(198, Math.max(9, c + delta));
      });
      t = setTimeout(bump, 2200 + Math.floor(Math.random() * 4200));
    };
    bump();
    return () => clearTimeout(t);
  }, [visible]);

  useEffect(() => {
    if (!visible) return;
    const cat = window.PRODUCT_CATALOG;
    if (!cat || !cat.length) return;
    let t;
    const pick = () => {
      const p = cat[Math.floor(Math.random() * cat.length)];
      setProd({ slug: p.slug, label: p.shortName || p.name });
      t = setTimeout(pick, 4500 + Math.floor(Math.random() * 5500));
    };
    pick();
    return () => clearTimeout(t);
  }, [visible]);

  if (!visible) return null;

  const go = () => { if (prod.slug && onPick) onPick(prod.slug); };
  return (
    <div
      className={'live-viewing live-viewing--clickable' + (hasStickyCta ? ' live-viewing--above-sticky' : '')}
      role="button"
      tabIndex={0}
      aria-label={`${prod.label} 보러가기`}
      onClick={go}
      onKeyDown={(e)=>{ if(e.key==='Enter'||e.key===' '){ e.preventDefault(); go(); } }}
    >
      <span className="live-viewing__pulse" aria-hidden="true"/>
      <span className="live-viewing__text">
        <strong className="live-viewing__num">{count}</strong>
        명이 <span className="live-viewing__product">「{prod.label}」</span> 상세를 보고 있어요
      </span>
      <span className="live-viewing__go" aria-hidden="true">보기 ›</span>
    </div>
  );
}

/* ---------- Header ---------- */
function Header({ onApply }) {
  return (
    <header className="site-header">
      <div className="site-header__inner">
        <div className="brand-lockup">
          <BrandLogo className="brand-lockup__logo"/>
        </div>
        <div className="hdr-actions">
          <a href="#apply" className="hdr-cta" onClick={(e)=>{e.preventDefault(); onApply();}}>
            <I.Phone width="14" height="14"/>무료상담
          </a>
          <a href={BILLYJO_SITE} target="_blank" rel="noopener noreferrer" className="hdr-cta hdr-cta--ghost">
            가전 프로모션 ↗
          </a>
        </div>
      </div>
    </header>
  );
}

/* ---------- Hero (빌리조 자체 디자인 — 샘플 이미지 미사용) ---------- */
function Hero({ onRecommend, recLoading, onBundle }) {
  const [persona, setPersona] = useState('');
  const examples = ['신혼부부 · 좁은 주방', '아이 있는 집 · 미세먼지', '4인 가족 · 얼음 자주', '반려동물 · 공기질'];

  const submit = (e) => {
    e.preventDefault();
    if (onRecommend) onRecommend(persona);
  };

  // 오늘 날짜 기준 인기 조합 (내부 최대혜택가 기준) — 3종 / 4종 2가지 예시
  const wonToNum = (s) => Number(String(s == null ? '' : s).replace(/[^\d]/g, '')) || 0;
  const giftHigh = (g) => { const m = String(g || '').match(/(\d+)\s*만\s*~\s*(\d+)\s*만/); return m ? Number(m[2]) : 0; };
  const cat = window.PRODUCT_CATALOG || [];
  const cross = window.CROSS_SELL || [];
  const pickCat = (c) => cross.find((x) => x.category === c);
  const water = cat[0], air = pickCat('공기청정기'), bidet = pickCat('비데'), dehum = pickCat('제습기');
  const mkBundle = (label, badge, items) => {
    const list = items.filter(Boolean);
    return { label, badge, items: list,
      monthly: list.reduce((s, p) => s + wonToNum(p.card), 0),
      gift: list.reduce((s, p) => s + giftHigh(p.gift), 0) };
  };
  const bundles = [
    mkBundle('인기 BEST 3종', 'HOT', [water, air, bidet]),
    mkBundle('풀세트 4종', '최대혜택', [water, air, bidet, dehum]),
  ].filter((b) => b.items.length >= 3);
  const today = new Date();
  const dateLabel = `${today.getFullYear()}.${String(today.getMonth() + 1).padStart(2, '0')}.${String(today.getDate()).padStart(2, '0')}`;

  return (
    <section className="hero" data-screen-label="01 Hero">
      {/* CSS 배경 장식 (이미지 미사용) */}
      <div className="hero__bg" aria-hidden="true">
        <span className="hero__orb hero__orb--1"></span>
        <span className="hero__orb hero__orb--2"></span>
        <span className="hero__grid"></span>
      </div>
      <div className="hero__inner">
        <div className="hero__ribbon">
          <span className="dot"></span>
          지금 실시간 상담 접수중
        </div>
        <div className="hero__kicker">인수형 렌탈 · 국내 최저가 비교</div>
        <h1 className="hero__title">
          LG·삼성·코웨이·청호<br/>
          <span className="hero__title-accent">인수형 렌탈 국내 최저가 비교<br/>+ 최대 혜택 찾기</span>
        </h1>
        <p className="hero__subtitle">
          타사와 다른 <b>인수형 렌탈</b> — 정수기·공기청정기·비데·제습기까지<br/>
          브랜드·카드할인·사은품을 한 번에 비교해 <b>최대 혜택</b>을 찾아드립니다.
        </p>

        {/* 오늘 한정 인기 조합 쇼케이스 (3종 / 4종) */}
        {bundles.length > 0 && (
          <div className="bundles">
            <div className="bundles__head">
              <span className="bundle__fire">🔥</span>
              <b>{dateLabel} 오늘 한정</b> · 인수형 렌탈 인기 조합 <span className="bundle__tag">추가혜택</span>
            </div>
            <div className="bundles__grid">
              {bundles.map((b) => (
                <div className="bundle" key={b.label}>
                  <div className="bundle__title">{b.label}<span className="bundle__badge">{b.badge}</span></div>
                  <div className="bundle__items">
                    {b.items.map((p, i) => (
                      <React.Fragment key={p.slug}>
                        {i > 0 && <span className="bundle__plus">+</span>}
                        <div className="bundle__item">
                          <div className="bundle__thumb"><ProductThumb variant={p.v} name={p.name}/></div>
                          <div className="bundle__cat">{p.category || '정수기'}</div>
                        </div>
                      </React.Fragment>
                    ))}
                  </div>
                  <div className="bundle__stats">
                    <div className="bundle__stat">
                      <span className="bundle__stat-lbl">최대 지원금</span>
                      <span className="bundle__stat-val">최대 {b.gift}만원</span>
                    </div>
                    <div className="bundle__stat bundle__stat--main">
                      <span className="bundle__stat-lbl">카드적용 월 렌탈료</span>
                      <span className="bundle__stat-val">월 {b.monthly.toLocaleString()}원~</span>
                    </div>
                  </div>
                  <div className="bundle__perday">하루 약 {(Math.round(b.monthly / 30 / 10) * 10).toLocaleString()}원꼴</div>
                  <button type="button" className="bundle__btn" onClick={()=>onBundle && onBundle()}>
                    <I.Gift width="16" height="16"/>이 조합으로 받기
                  </button>
                </div>
              ))}
            </div>
            <div className="bundle__note">※ 내부 최대혜택가(제휴카드 최대 적용·사은금 합산) 기준. 구성은 상담 시 조정 가능합니다.</div>
          </div>
        )}

        {/* AI 페르소나 추천 입력 */}
        <form className="persona" onSubmit={submit}>
          <div className="persona__label">
            <I.Sparkle width="16" height="16"/>
            어떤 분이신가요? 상황을 적어주시면 <b>AI가 맞춤 제품</b>을 추천해 드려요
          </div>
          <div className="persona__row">
            <input
              className="persona__input"
              type="text"
              value={persona}
              onChange={(e)=>setPersona(e.target.value)}
              placeholder="예: 아이 있는 집, 미세먼지 걱정, 좁은 주방, 얼음 자주"
              aria-label="고객 상황·페르소나 입력"
            />
            <button className="persona__btn" type="submit" disabled={recLoading}>
              {recLoading ? '추천 중…' : 'AI 추천받기'}
            </button>
          </div>
          <div className="persona__examples">
            {examples.map((ex) => (
              <button type="button" key={ex} className="persona__chip" onClick={()=>setPersona(ex)}>
                {ex}
              </button>
            ))}
          </div>
        </form>

        <div className="hero__badges">
          <div className="hero__badge gold">제휴카드 최대 할인</div>
          <div className="hero__badge">당일설치 가능</div>
          <div className="hero__badge">본사 최저가+최대 혜택</div>
          <div className="hero__badge">최저가 차액 보장</div>
        </div>
      </div>
    </section>
  );
}

/* ---------- 제품 후기 미리보기 모달 (제품 → 유사제품(동일 브랜드+카테고리) → 동일 브랜드 폴백) ---------- */
function ReviewPeek({ open, brand, category, product, name, onClose, onConsult }) {
  // fallback: false=정확 | 'cat'=유사제품(동일 카테고리) | 'brand'=동일 브랜드
  const [st, setSt] = useState({ loading: true, items: [], fallback: false });
  // 빌리조 분석(브랜드+카테고리 단위 집계 한 줄)
  const [analysis, setAnalysis] = useState(null);
  useEffect(() => {
    if (!open) { setAnalysis(null); return; }
    let alive = true;
    const ALIAS = { LG전자: "LG", LG구독: "LG", 청호: "청호나이스", SK: "SK매직", 웰스: "교원웰스" };
    const nb = ALIAS[brand] || brand;
    fetch('/review-analysis.json')
      .then((r) => r.json())
      .then((j) => { if (alive) setAnalysis(j[(nb || '') + '|' + (category || '')] || null); })
      .catch(() => {});
    return () => { alive = false; };
  }, [open, brand, category]);
  useEffect(() => {
    if (!open) return;
    let alive = true;
    setSt({ loading: true, items: [], fallback: false });
    const get = (qs) => fetch('/api/reviews?' + qs + '&limit=8').then((r) => r.json()).catch(() => ({}));
    const items = (b) => (((b && b.items) || []).filter(visibleReview)); // 아정당 등 숨김 출처 제외
    // 1) 해당 제품 → 2) 동일 브랜드+카테고리(유사 제품) → 3) 동일 브랜드 전체
    get('product=' + encodeURIComponent(product || ''))
      .then((b) => {
        if (!alive) return;
        if (items(b).length) { setSt({ loading: false, items: items(b), fallback: false }); return; }
        if (!brand) { setSt({ loading: false, items: [], fallback: false }); return; }
        const q = 'brand=' + encodeURIComponent(brand) + (category ? '&category=' + encodeURIComponent(category) : '');
        get(q).then((c) => {
          if (!alive) return;
          if (category && items(c).length) { setSt({ loading: false, items: items(c), fallback: 'cat' }); return; }
          // 유사제품 후기도 없으면 동일 브랜드 전체로
          get('brand=' + encodeURIComponent(brand)).then((d) => {
            if (alive) setSt({ loading: false, items: items(d), fallback: 'brand' });
          });
        });
      });
    return () => { alive = false; };
  }, [open, brand, category, product]);
  if (!open) return null;
  const items = st.items;
  return (
    <div className="modal-backdrop" role="dialog" aria-modal="true"
      onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal rv-peek" onClick={(e) => e.stopPropagation()}>
        <button type="button" className="modal__close" onClick={onClose} aria-label="닫기">×</button>
        <h2 className="rv-peek__title">{name || brand} 고객 후기</h2>
        {analysis && (
          <div className="rv-peek__analysis">
            <div className="rv-peek__analysis-head">✨ 빌리조 분석 · 후기 {Number(analysis.count).toLocaleString()}건 · ★ {analysis.avg}</div>
            <div className="rv-peek__analysis-body">{analysis.summary}</div>
          </div>
        )}
        {st.loading && <div className="rv-peek__msg">후기를 불러오는 중…</div>}
        {!st.loading && st.fallback && items.length > 0 && (
          <div className="rv-peek__fallback">
            {st.fallback === 'cat'
              ? <>이 제품은 아직 등록된 후기가 없어, <b>{brand}의 유사 제품({category})</b> 실제 후기를 보여드려요.</>
              : <>이 제품은 아직 등록된 후기가 없어, <b>동일 브랜드({brand})</b>의 실제 후기를 보여드려요.</>}
          </div>
        )}
        {!st.loading && items.length === 0 && (
          <div className="rv-peek__empty">
            <p><b>{brand}</b> 후기는 곧 업데이트될 예정이에요.</p>
            <button className="rv-cta" onClick={() => { onClose(); onConsult && onConsult(); }}>
              <I.Phone width="16" height="16"/>상담받고 먼저 확인하기
            </button>
          </div>
        )}
        {items.length > 0 && (
          <div className="rv-peek__list">
            {items.map((it, i) => (
              <article className="rv-card rv-card--peek" key={i}>
                <ReviewPhoto src={it.photo_url || (it.photos && it.photos[0]) || ''}/>
                <div className="rv-card__top">
                  <span className="rv-card__stars" aria-label={`별점 ${it.stars || 5}점`}>
                    {Array.from({ length: 5 }).map((_, k) => <I.Star key={k} width="13" height="13"/>)}
                  </span>
                  <span className="rv-card__chip">{channelOf(it.source, it.brand)}</span>
                </div>
                <p className="rv-card__text">{it.text}</p>
                <div className="rv-card__src">출처: {channelOf(it.source, it.brand)}{it.reviewed_at ? ` · ${it.reviewed_at}` : ''}</div>
              </article>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

/* ---------- AI 맞춤 추천 결과 (히어로 입력 → 하단 표시) ---------- */
function Recommendations({ recs, loading, error, onApply }) {
  const [peek, setPeek] = useState({ open: false });
  const reviewIdx = useReviewIndex((recs || []).map((r) => r.brand));
  if (!loading && !recs && !error) return null;
  return (
    <section className="section section--subtle recs" id="recs">
      <div className="container">
        <div className="section-kicker">AI 맞춤 추천</div>
        <h2 className="section-title">입력하신 조건에 <span className="mark">딱 맞는 제품</span></h2>
        {loading && <div className="recs__msg">AI가 맞춤 제품을 고르는 중이에요…</div>}
        {error && !loading && <div className="recs__msg">{error}</div>}
        {recs && recs.length > 0 && (
          <div className="recs__grid">
            {recs.map((r, i) => (
              <div
                key={r.slug || i}
                className="rec-card"
                role="button"
                tabIndex={0}
                onClick={()=>onApply && onApply()}
                onKeyDown={(e)=>{ if(e.key==='Enter'||e.key===' '){ e.preventDefault(); onApply && onApply(); } }}
              >
                <div className="rec-card__rank">{i + 1}순위</div>
                <div className="rec-card__img"><ProductThumb variant={r.v} image={r.image} name={r.name}/></div>
                <div className="rec-card__brand">
                  {r.brand}
                  {r.rating && <span className="rec-card__rating"><I.Star/>{r.rating}{reviewCountOf(reviewIdx, r) > 0 ? ` · 후기 ${reviewCountOf(reviewIdx, r).toLocaleString()}` : (r.reviewsLabel ? ` (${r.reviewsLabel})` : '')}</span>}
                </div>
                <div className="rec-card__name">{r.name}</div>
                {r.reason && <div className="rec-card__reason">“{r.reason}”</div>}
                {r.card && <div className="rec-card__price">제휴카드 적용가 <b>{r.card}</b></div>}
                <div className="rec-card__actions">
                  <button type="button" className="rec-card__review"
                    onClick={(e) => { e.stopPropagation(); setPeek({ open: true, brand: r.brand, category: r.category, product: reviewKeyFor(r), name: r.shortName || r.name }); }}>
                    <I.Star width="13" height="13"/>{reviewCountOf(reviewIdx, r) > 0 ? `후기 ${reviewCountOf(reviewIdx, r).toLocaleString()}개 보기` : '후기 보기'}
                  </button>
                  <span className="rec-card__cta">이 제품으로 상담받기 →</span>
                </div>
              </div>
            ))}
          </div>
        )}
        <ReviewPeek
          open={peek.open} brand={peek.brand} category={peek.category} product={peek.product} name={peek.name}
          onClose={() => setPeek({ open: false })} onConsult={onApply}
        />
        {recs && recs.length === 0 && !loading && (
          <div className="recs__msg">조건에 맞는 추천을 찾지 못했어요. 상담으로 직접 문의해 주세요.</div>
        )}
      </div>
    </section>
  );
}

/* ---------- 상단 실시간 신청현황 바 ---------- */
function TopStatusBar() {
  const [n, setN] = useState(() => 58 + Math.floor(Math.random() * 10));
  useEffect(() => {
    let t;
    const bump = () => {
      setN((c) => Math.min(76, c + (Math.random() < 0.6 ? 1 : 0)));
      t = setTimeout(bump, 22000 + Math.floor(Math.random() * 26000));
    };
    t = setTimeout(bump, 22000);
    return () => clearTimeout(t);
  }, []);
  return (
    <div className="topbar" role="status" aria-live="polite">
      <span className="topbar__pulse" aria-hidden="true"></span>
      <span className="topbar__text">
        지금 실시간 상담 접수중 · 오늘 <b>{n}명</b> 신청 · 선착순 <b>77명</b> 한정
      </span>
    </div>
  );
}

/* ---------- Status (실시간 신청 현황) ---------- */
function Status() {
  const LIMIT = 77;
  const ref = useRef(null);
  const inView = useInView(ref);
  const current = useCountUp(64, inView);
  const remaining = Math.max(0, LIMIT - current);
  const pct = (current / LIMIT) * 100;

  const [clock, setClock] = useState('');
  useEffect(() => {
    const p = (x) => String(x).padStart(2, '0');
    const fmt = () => {
      const d = new Date();
      return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ` +
        `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
    };
    setClock(fmt());
    const t = setInterval(() => setClock(fmt()), 1000);
    return () => clearInterval(t);
  }, []);

  return (
    <section className="section section--subtle" ref={ref}>
      <div className="container">
        <div className="status-card">
          <div className="status-card__eyebrow">프로모션 신청현황</div>
          <h2 className="status-card__title">이번 물량 마감되면 종료됩니다</h2>
          <p className="status-card__sub">선착순 {LIMIT}명 한정 특별 혜택</p>

          <div className="status-card__live">
            <span className="status-card__live-dot" aria-hidden="true"></span>
            <span className="status-card__live-label">LIVE</span>
            <span className="status-card__clock">{clock}</span>
            <span className="status-card__since">(오늘 오전 9시부터)</span>
          </div>

          <div className="counter">
            <span className="counter__current">{current}</span>
            <span className="counter__suffix">명 신청중</span>
          </div>
          <p className="counter__total">
            오늘 신청 <b>{current}명</b> · 선착순 {LIMIT}명 마감 임박
          </p>
          <div className="progress">
            <div className="progress__bar" style={{ width: `${pct}%` }}></div>
          </div>

          <div className="status-stats">
            <div className="status-stat is-urgent">
              <div className="status-stat__num">{remaining}</div>
              <div className="status-stat__label">남은 자리</div>
            </div>
            <div className="status-stat">
              <div className="status-stat__num status-stat__num--deadline">⏰ 마감임박</div>
              <div className="status-stat__label">오늘 자정까지</div>
            </div>
          </div>

          <div className="status-notes">
            <ul>
              <li>신청 후 전문 상담사가 직접 연락드립니다. 부재 시 다시 연락드려요.</li>
              <li>만 19세 이상·정상 신용 고객을 대상으로 진행됩니다.</li>
            </ul>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ---------- Notice modal (alert 대체) ---------- */
function NoticeModal({ open, title, message, onClose }) {
  if (!open) return null;
  return (
    <div
      className="modal-backdrop"
      role="dialog"
      aria-modal="true"
      aria-labelledby="notice-modal-title"
      onClick={(e) => {
        if (e.target === e.currentTarget) onClose();
      }}
    >
      <div className="modal" onClick={(e) => e.stopPropagation()}>
        <button type="button" className="modal__close" onClick={onClose} aria-label="닫기">
          ×
        </button>
        <h2 id="notice-modal-title" className="notice-modal__title">
          {title}
        </h2>
        <div className="notice-modal__body">{message}</div>
        <button type="button" className="submit-btn" style={{ marginTop: 22, width: '100%' }} onClick={onClose}>
          확인
        </button>
      </div>
    </div>
  );
}

/* ---------- Inquiry Form ---------- */
function InquiryForm({ onSubmit, onNotice, intent, setIntent }) {
  const products = (window.PRODUCT_CATALOG && window.PRODUCT_CATALOG.length
    ? window.PRODUCT_CATALOG.map((p) => p.name)
    : ['코웨이 얼음냉온정수기','코웨이 냉온정수기','청호나이스 얼음정수기','SK매직 정수기']
  );
  const mode = intent === 'direct' ? 'direct' : 'consult';
  const setMode = (m) => setIntent && setIntent(m);
  const [name, setName] = useState('');
  const [phone, setPhone] = useState('');
  const [product, setProduct] = useState('');
  const [agree, setAgree] = useState(false);

  const formatPhone = (v) => {
    const d = v.replace(/\D/g,'').slice(0,11);
    if (d.length < 4) return d;
    if (d.length < 8) return `${d.slice(0,3)}-${d.slice(3)}`;
    return `${d.slice(0,3)}-${d.slice(3,7)}-${d.slice(7)}`;
  };

  const notice = onNotice || (() => {});

  const submit = (e) => {
    e.preventDefault();
    if (!name.trim()) {
      notice('입력 확인', '성명을 입력해주세요.');
      return;
    }
    if (phone.replace(/\D/g, '').length < 10) {
      notice('입력 확인', '연락처를 정확히 입력해주세요.');
      return;
    }
    if (!agree) {
      notice('동의 필요', '개인정보 수집 및 이용에 동의해주세요.');
      return;
    }
    onSubmit({ name, phone, product, mode });
    setName(''); setPhone(''); setProduct(''); setAgree(false);
  };

  return (
    <section id="apply" className="section section--subtle">
      <div className="container">
        <div className="form-card">
          <div className="form-brand">
            <BrandLogo className="form-brand__logo"/>
            <div className="form-brand__tag">원하는 방식으로 신청하세요 · 1분이면 충분합니다</div>
          </div>

          {/* 상담 / 무상담 경로 선택 */}
          <div className="apply-modes" role="tablist" aria-label="신청 방식">
            <button type="button" role="tab" aria-selected={mode === 'consult'}
              className={`apply-mode ${mode === 'consult' ? 'is-active' : ''}`}
              onClick={()=>setMode('consult')}>
              <span className="apply-mode__t">무료 상담 신청</span>
              <span className="apply-mode__d">전문 상담사가 맞춤 안내</span>
            </button>
            <button type="button" role="tab" aria-selected={mode === 'direct'}
              className={`apply-mode apply-mode--gold ${mode === 'direct' ? 'is-active' : ''}`}
              onClick={()=>setMode('direct')}>
              <span className="apply-mode__badge">추가혜택</span>
              <span className="apply-mode__t">무상담 가입신청</span>
              <span className="apply-mode__d">AI 다이렉트 · 최대 혜택가</span>
            </button>
          </div>

          {mode === 'direct' ? (
            <h2 className="form-title"><span style={{color:'var(--coway)'}}>무상담 가입</span>으로 더 저렴하게</h2>
          ) : (
            <h2 className="form-title">지금 <span style={{color:'var(--coway)'}}>무료 상담</span> 신청하기</h2>
          )}

          {mode === 'direct' && (
            <div className="apply-note">
              💡 <b>AI가 별도의 상담 비용을 줄이고</b>, 렌탈 다이렉트 <b>최대 혜택</b>을 비교·제공합니다. 희망 제품을 선택해 주세요.
            </div>
          )}

          <form onSubmit={submit}>
            <div className="field">
              <label className="field__label">성명<span className="req">*</span></label>
              <input type="text" className="input" placeholder="이름을 입력해주세요"
                value={name} onChange={(e)=>setName(e.target.value)}/>
            </div>
            <div className="field">
              <label className="field__label">연락처<span className="req">*</span></label>
              <input type="tel" className="input" placeholder="010-0000-0000"
                value={phone} onChange={(e)=>setPhone(formatPhone(e.target.value))}/>
            </div>
            <div className="field">
              <label className="field__label">희망제품</label>
              <select className="select" value={product} onChange={(e)=>setProduct(e.target.value)}>
                <option value="">선택 안함 (선택사항)</option>
                {products.map(p => <option key={p} value={p}>{p}</option>)}
              </select>
            </div>

            <div className="agree" onClick={()=>setAgree(!agree)}>
              <div className={`agree__checkbox ${agree?'is-checked':''}`}></div>
              <div className="agree__text">
                <b>개인정보수집 및 이용 동의 (필수)</b><br/>
                상담·가입 안내 목적으로만 사용되며, 안내 완료 후 안전하게 파기됩니다.
              </div>
            </div>

            <button type="submit" className={`submit-btn ${mode === 'direct' ? 'submit-btn--gold' : ''}`}>
              {mode === 'direct'
                ? <><I.Gift width="20" height="20"/>AI 다이렉트로 최대 혜택 신청</>
                : <><I.Phone width="20" height="20"/>무료 상담 신청하기</>}
            </button>
          </form>

          <div className="license-badge">
            <div className="license-badge__seal">
              <I.Seal/>공식 파트너 · 빌리조 정식 안내
            </div>
            <div className="license-badge__sub">사업자·통신판매 등 상세 정보는 상담 시 안내드립니다.</div>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ---------- Only Benefits (빌리조라서 가능한 ONLY 혜택) ---------- */
function OnlyBenefits() {
  const items = [
    { icon:<I.Seal/>,    title:'100% 정품 · 본사 설치', desc:'공식 본사 정품을 전문 기사가 직접 설치합니다.' },
    { icon:<I.Shield/>,  title:'전 제품 새제품 보증',   desc:'모든 제품 미개봉 새제품 + 품질 보증.' },
    { icon:<I.Gift/>,    title:'국내 최대 혜택',         desc:'사은품·제휴카드까지 국내 최대 규모 혜택.' },
    { icon:<I.Coin/>,    title:'최저가 차액 100% 보장',  desc:'최저가가 아니면 차액 100%를 추가 지급합니다.' },
    { icon:<I.Sparkle/>, title:'국내 렌탈 최저가 비교추천', desc:'전 브랜드를 한자리에서 최저가로 비교·추천.' },
  ];
  return (
    <section className="section only-benefits">
      <div className="container">
        <div className="section-kicker">ONLY BILLYJO</div>
        <h2 className="section-title">빌리조라서 가능한 <span className="mark">ONLY 혜택</span></h2>
        <p className="section-sub">다른 곳과 비교해보세요. 빌리조는 다릅니다.</p>
        <div className="only-grid">
          {items.map((it, i) => (
            <div key={i} className="only-card">
              <div className="only-card__icon">{it.icon}</div>
              <div className="only-card__body">
                <div className="only-card__title">{it.title}</div>
                <div className="only-card__desc">{it.desc}</div>
              </div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---------- Benefits ---------- */
function Benefits() {
  // 아이콘/서식 일관: 모든 카드 동일 구조 — 아이콘(단색) + 라벨 + "텍스트 + accent 키워드"
  const items = [
    { n:'01', icon:<I.Gift/>,     label:'맞춤 상담 안내',   main:'당일 ',   key:'설치 안내' },
    { n:'02', icon:<I.Calendar/>, label:'제품별 조건 안내', main:'상담 후 ', key:'맞춤 견적' },
    { n:'03', icon:<I.Percent/>,  label:'결합·동시구매',    main:'동시구매 ', key:'최대 할인' },
    { n:'04', icon:<I.Shield/>,   label:'교체·전환 상담',   main:'안심 ',   key:'전환 안내' },
  ];
  return (
    <section className="section">
      <div className="container">
        <div className="section-kicker is-gold">SPECIAL BENEFITS</div>
        <h2 className="section-title">빌리조만의 <span className="mark-gold">특별한</span><br/>추가 혜택!</h2>
        <p className="section-sub">여기서만 챙길 수 있는 빌리조 단독 혜택을 모았어요.</p>
        <div className="benefits-grid">
          {items.map(it => (
            <div key={it.n} className="benefit">
              <div className="benefit__num">{it.n}</div>
              <div className="benefit__icon">{it.icon}</div>
              <div className="benefit__label">{it.label}</div>
              <div className="benefit__title">{it.main}<span className="accent">{it.key}</span></div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---------- Products ---------- */
function Products({ onApply }) {
  const wonToNum = (s) => Number(String(s == null ? '' : s).replace(/[^\d]/g, '')) || 0;
  const list = window.PRODUCT_CATALOG && window.PRODUCT_CATALOG.length
    ? window.PRODUCT_CATALOG
    : [
        { name:'스위치 무선 정수기', v:'purifier', price:'15,900', card:'월 0원~', tags:['정수','무선'], hot:true },
        { name:'나노직수 미니 정수기', v:'purifier', price:'15,900', card:'월 0원~', tags:['정수','나노직수'] },
        { name:'아이콘2 정수기', v:'purifier', price:'14,200', card:'월 3,400원~', tags:['냉수','온수','정수'] },
        { name:'아이콘3 정수기', v:'purifier', price:'14,450', card:'월 3,900원~', tags:['냉수','온수','정수'] },
        { name:'아이콘 프로 정수기', v:'purifier', price:'14,950', card:'월 4,900원~', tags:['냉수','온수','정수'], hot:true },
        { name:'미니 얼음정수기', v:'ice', price:'21,450', card:'월 17,900원~', tags:['얼음','냉수','온수'] },
        { name:'스탠다드 얼음정수기', v:'ice', price:'22,950', card:'월 20,900원~', tags:['얼음','냉수','온수'] },
        { name:'얼음정수기 RO(지하수)', v:'ice', price:'20,200', card:'월 15,400원~', tags:['얼음','RO','지하수'] },
        { name:'아이콘 스탠드 정수기', v:'purifier', price:'12,950', card:'월 900원~', tags:['냉수','온수','정수'] },
        { name:'스스로케어 비데', v:'bidet', price:'18,400', card:'월 7,900원~', tags:['99% 항균','살균'] },
        { name:'더블케어 비데2', v:'bidet', price:'24,400', card:'월 12,900원~', tags:['터치리모컨','IPX방수'] },
        { name:'노블 제습공기청정기', v:'air', price:'18,950', card:'월 12,900원~', tags:['21L제습','4단필터'] },
      ];
  const reviewIdx = useReviewIndex(list.map((p) => p.brand));
  return (
    <section className="section section--subtle" id="products">
      <div className="container">
        <div className="section-kicker">BEST RENTAL</div>
        <h2 className="section-title"><span className="mark">인기 렌탈</span> 제품</h2>
        <p className="section-sub">지금 가장 많이 상담받는 인기 모델만 골랐어요.</p>
        <div className="product-grid">
          {list.map((p, i) => {
            const origNum = wonToNum(p.price);
            const cardNum = wonToNum(p.card);
            const hasDiscount = origNum > 0 && cardNum < origNum;
            const save = hasDiscount ? origNum - cardNum : 0;
            const perDay = cardNum > 0 ? Math.round(cardNum / 30 / 10) * 10 : 0;
            const open = () => onApply && onApply();
            return (
            <div
              key={p.slug || i}
              id={p.slug ? `product-${p.slug}` : undefined}
              className="product"
              role="button"
              tabIndex={0}
              onClick={open}
              onKeyDown={(e)=>{ if(e.key==='Enter'||e.key===' '){ e.preventDefault(); open(); } }}
            >
              <div className="product__image">
                <ProductThumb variant={p.v} image={p.image} name={p.name}/>
                {p.hot && <div className="product__ribbon">HOT</div>}
                {hasDiscount && <div className="product__save-badge">카드 -{save.toLocaleString()}원</div>}
                <div className="product__rating">
                  <I.Star/>{p.rating || 4.8}
                  <span className="product__reviews">
                    {reviewCountOf(reviewIdx, p) > 0 ? `후기 ${reviewCountOf(reviewIdx, p).toLocaleString()}` : `(${p.reviewsLabel || '100+'})`}
                  </span>
                </div>
              </div>
              <div className="product__brandline">
                {p.brand && <span className="product__brand">{p.brand}</span>}
                {p.grade && <span className="product__grade">종합 {p.grade}</span>}
              </div>
              <h3 className="product__name">{p.name}</h3>
              {p.summary && <div className="product__summary">{p.summary}</div>}
              <div className="product__tags">
                {p.tags.map(t => <span key={t} className="product__tag">{t}</span>)}
              </div>
              {p.noPenalty && <div className="product__nopenalty">⚡ 위약금 0원 가능</div>}
              <div className="product__price">
                {hasDiscount && (
                  <div className="product__price-orig">
                    정상가 <s>월 {origNum.toLocaleString()}원</s>
                  </div>
                )}
                <div className="product__price-label">제휴카드 적용 최저가</div>
                <div className="product__price-main">
                  <span className="permo">월</span>
                  {cardNum.toLocaleString()}<span className="won">원</span><span className="tilde">~</span>
                </div>
                {perDay > 0 && <div className="product__perday">하루 약 {perDay.toLocaleString()}원꼴</div>}
                {hasDiscount && (
                  <div className="product__price-sub">제휴카드 적용 시 월 최대 {save.toLocaleString()}원 할인</div>
                )}
                <div className="product__card-chip"><I.Card/>제휴카드 할인 적용가</div>
                {p.gift && <div className="product__gift"><I.Gift width="13" height="13"/>예상 현금 사은품 <b>{p.gift}</b></div>}
              </div>
              <div className="product__cta">상담 신청하고 조건 확인 →</div>
              {p.detailUrl && (
                <a
                  className="product__detail-link"
                  href={p.detailUrl}
                  target="_blank"
                  rel="noopener noreferrer"
                  onClick={(e)=>e.stopPropagation()}
                >
                  자세히 보기 ↗
                </a>
              )}
            </div>
            );
          })}
        </div>
      </div>
    </section>
  );
}

/* ---------- Trust ---------- */
function Trust() {
  const ref = useRef(null);
  const inView = useInView(ref);
  // TODO(billyjo): 광고 집행 전 검증된 실제 수치로 교체. 표시광고법상 허위·과장 금지.
  const stats = [
    { num:5,   suf:'대 브랜드', label:'공식 제휴' },
    { num:26,  suf:'종',  label:'제휴카드 혜택' },
    { num:100, suf:'%',   label:'무료 상담' },
    { num:0,   suf:'원',  label:'상담 비용' },
    { num:365, suf:'일',  label:'연중 상담' },
    { num:1,   suf:'일',  label:'당일설치 가능' },
  ];
  return (
    <section className="trust-hero" ref={ref} data-screen-label="07 Trust">
      <div className="container trust-hero__inner">
        <div className="trust-hero__kicker">WHY BILLYJO</div>
        <h2 className="trust-hero__title">
          렌탈, 왜<br/>
          <span className="gold">빌리조</span>여야 할까요?
        </h2>
        <p className="trust-hero__sub">인수형 렌탈을 전 브랜드 한자리에서 최저가로 비교하니까, 더 합리적인 선택이 가능합니다.</p>

        <div className="trust-grid">
          {stats.map((s, i) => {
            const val = useCountUp(Math.floor(s.num), inView, 1800);
            const display = s.decimal ? (inView ? s.num.toFixed(1) : '0.0') : val.toLocaleString();
            return (
              <div key={i} className="trust-stat">
                <div className="trust-stat__num">{display}{s.suf}</div>
                <div className="trust-stat__label">{s.label}</div>
              </div>
            );
          })}
        </div>

        <div className="trust-footer">
          <div className="trust-footer__badge">전 브랜드 한자리 비교</div>
          <div className="trust-footer__msg">렌탈 시작 전, 딱 한 번<br/><span style={{color:'var(--gold-400)'}}>빌리조</span>에서 비교하세요.</div>
        </div>
      </div>
    </section>
  );
}

/* ---------- Compare Table ---------- */
function Compare() {
  const rows = [
    { label:'월 비용',   good:'월 1만원대로 무제한', bad:'마실수록 쌓이는 생수값' },
    { label:'온수·얼음', good:'정수·냉수·온수·얼음', bad:'정수(상온)만 가능' },
    { label:'편의',      good:'버튼 한 번이면 끝',  bad:'주문·수령·재고 관리' },
    { label:'무게',      good:'들 일 없음',         bad:'매번 무거운 생수 운반' },
    { label:'위생',      good:'정기 방문관리·필터교체', bad:'개봉 후 변질·세균 우려' },
    { label:'공간',      good:'슬림하게 설치',      bad:'생수 박스 보관 공간' },
    { label:'환경',      good:'페트병 0',           bad:'플라스틱 폐기물 누적' },
  ];
  return (
    <section className="section">
      <div className="container">
        <div className="section-kicker">SMART CHOICE</div>
        <h2 className="section-title">생수 값, <span className="mark">1년치</span> 계산해<br/>보신 적 있으세요?</h2>
        <p className="section-sub">무겁게 들고, 떨어지면 또 주문하고, 쌓이는 페트병까지.<br/>정수기 하나로 이 모든 번거로움이 사라집니다.</p>

        <div className="compare">
          <div className="compare__row compare__head">
            <div className="compare__cell compare__cell--label">항목</div>
            <div className="compare__cell compare__cell--good">정수기</div>
            <div className="compare__cell">생수</div>
          </div>
          {rows.map(r => (
            <div key={r.label} className="compare__row">
              <div className="compare__cell compare__cell--label">{r.label}</div>
              <div className="compare__cell compare__cell--good">
                <span className="compare__mark good">○</span>
                <span>{r.good}</span>
              </div>
              <div className="compare__cell compare__cell--bad">
                <span className="compare__mark bad">✕</span>
                <span>{r.bad}</span>
              </div>
            </div>
          ))}
        </div>

        <div className="compare-outro">
          바꾸는 건 정수기 하나인데<br/>달라지는 건 매일의 번거로움입니다.
        </div>
      </div>
    </section>
  );
}

/* ---------- Cards (제휴카드 안내) ---------- */
function Cards({ onApply }) {
  const [activeCategory, setActiveCategory] = useState('코웨이');
  const [cardsPerPage, setCardsPerPage] = useState(() => (window.innerWidth <= 767 ? 2 : 3));
  const [currentPage, setCurrentPage] = useState(0);
  const railRef = useRef(null);

  const categories = ['ALL', '코웨이', '청호나이스', 'SK매직', 'LG전자', '쿠쿠'];

  // 카드 브랜드(카테고리) → 정수기 카탈로그 브랜드 매핑
  const CARD_BRAND_TO_PRODUCT = { '코웨이': '코웨이', '청호나이스': '청호나이스', 'SK매직': 'SK매직', 'LG전자': 'LG', '쿠쿠': '쿠쿠' };
  const wonToNum = (s) => Number(String(s == null ? '' : s).replace(/[^\d]/g, '')) || 0;
  const brandProducts = (activeCategory === 'ALL'
    ? []
    : (window.PRODUCT_CATALOG || []).filter((p) => p.brand === CARD_BRAND_TO_PRODUCT[activeCategory]));

  const cards = [
    { name:'코웨이 신한카드', image:'images/제휴카드/코웨이/코웨이신한카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>13,000원</b> 할인','전월실적 70만원 이상 시 월 <b>17,000원</b> 할인','전월실적 150만원 이상 시 월 <b>30,000원</b> 할인'], promo:['4월 신규발급 프로모션','30만원 구간 <b>10,000원</b> 추가할인','70만원 구간 <b>6,000원</b> 추가할인'], fee:'국내전용 27,000원 / 해외겸용(MASTER) 30,000원', phone:'02-1833-6013' },
    { name:'코웨이 NH카드', image:'images/제휴카드/코웨이/코웨이NH카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>10,000원</b> 할인','전월실적 100만원 이상 시 월 <b>15,000원</b> 할인','전월실적 200만원 이상 시 월 <b>30,000원</b> 할인'], promo:['4월 신규발급 프로모션','전 구간 <b>10,000원</b> 추가할인'], fee:'연회비 국내전용 10,000원 / 국내외겸용(MASTER) 12,000원', phone:'1644-2866' },
    { name:'코웨이 하나카드', image:'images/제휴카드/코웨이/코웨이하나카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>13,000원</b> 할인','전월실적 80만원 이상 시 월 <b>18,000원</b> 할인','전월실적 150만원 이상 시 월 <b>25,000원</b> 할인'], fee:'국내전용 / 국내외겸용(Master card) 25,000원', phone:'1588-1771' },
    { name:'코웨이 X LOCA 롯데카드', image:'images/제휴카드/코웨이/코웨이XLOCA롯데카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>13,000원</b> 할인','전월실적 70만원 이상 시 월 <b>16,000원</b> 할인','전월실적 150만원 이상 시 월 <b>25,000원</b> 할인'], promo:['4월 신규발급자 대상 프로모션 (60개월간 적용)','30만원 구간 <b>3,000원</b> 추가할인','70만원 구간 <b>2,000원</b> 추가할인'], fee:'국내전용, 해외겸용(MASTER) 20,000원', phone:'1577-5208' },
    { name:'코웨이 ICON 우리카드', image:'images/제휴카드/코웨이/코웨이ICON우리카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>13,000원</b> 할인','전월실적 80만원 이상 시 월 <b>17,000원</b> 할인','전월실적 150만원 이상 시 월 <b>23,000원</b> 할인'], promo:['4월 신규발급 프로모션 (60개월간 적용)','30/80/150 구간 <b>9,000원 / 7,000원 / 7,000원</b> 추가할인'], fee:'국내전용 / 해외겸용(MasterCard) 15,000원', phone:'1800-3182' },
    { name:'코웨이 IBK카드', image:'images/제휴카드/코웨이/코웨이IBK카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>13,000원</b> 할인','전월실적 70만원 이상 시 월 <b>17,000원</b> 할인','전월실적 120만원 이상 시 월 <b>23,000원</b> 할인'], fee:'연회비 국내전용 12,000원 / 국내외겸용 UnionPay 15,000원 / Master 15,000원', phone:'1566-0088' },
    { name:'코웨이 현대카드', image:'images/제휴카드/코웨이/코웨이현대카드/1.png', benefits:['전월실적 50만원 이상 시 월 <b>15,000원</b> 할인','전월실적 100만원 이상 시 월 <b>20,000원</b> 할인'], promo:['4월 신규발급자 대상 프로모션 (36개월간 적용)','50만원/100만원 구간 <b>10,000원</b> 추가할인'], fee:'연회비 국내전용 30,000원 / 국내외겸용(VISA/Master card) 30,000원', phone:'02-2655-5003' },
    { name:'코웨이 삼성카드', image:'images/제휴카드/코웨이/코웨이삼성카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>7,000원</b> 할인','전월실적 70만원 이상 시 월 <b>10,000원</b> 할인','전월실적 120만원 이상 시 월 <b>13,000원</b> 할인'], promo:['4월 신규발급자 대상 프로모션 (60개월 적용)','전 구간 <b>11,000원</b> 추가할인'], fee:'국내전용 15,000원 / 국내외겸용(VISA) 15,000원', phone:'1588-7540' },
    { name:'코웨이 KB국민카드2', image:'images/제휴카드/코웨이/코웨이KB국민카드2/1.png', benefits:['전월실적 40만원 이상 시 월 <b>15,000원</b> 할인','전월실적 80만원 이상 시 월 <b>20,000원</b> 할인'], promo:['4월 신규발급자 대상 프로모션 (60개월간 적용)','전 구간 <b>10,000원</b> 추가할인'], fee:'연회비 국내외겸용(MASTER) 30,000원', phone:'1644-8388' },
    { name:'청호나이스 신한카드', image:'images/제휴카드/청호나이스/청호나이스신한카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>12,000원</b> 할인','전월실적 70만원 이상 시 월 <b>16,000원</b> 할인','전월실적 150만원 이상 시 월 <b>30,000원</b> 할인'], promo:['4월 신규발급 프로모션','30만원 구간 <b>3,000원</b> 추가할인'], fee:'국내전용 15,000원 / 해외겸용 18,000원', phone:'1833-2061' },
    { name:'청호나이스 롯데카드', image:'images/제휴카드/청호나이스/청호나이스롯데카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>10,000원</b> 할인','전월실적 70만원 이상 시 월 <b>15,000원</b> 할인','전월실적 150만원 이상 시 월 <b>25,000원</b> 할인'], promo:['4월 신규발급 프로모션','30만원 구간 <b>8,000원</b> 추가할인','70만원 구간 <b>5,000원</b> 추가할인'], fee:'연회비 국내전용 12,000원 / 국내외겸용 15,000원', phone:'1577-5633' },
    { name:'청호나이스 KB국민카드', image:'images/제휴카드/청호나이스/청호나이스KB국민카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>12,000원</b> 할인','전월실적 70만원 이상 시 월 <b>17,000원</b> 할인'], promo:['4월 신규발급 프로모션','30만원 구간 <b>8,000원</b> 추가할인','70만원 구간 <b>3,000원</b> 추가할인'], fee:'국내외겸용 15,500원', phone:'1644-8466' },
    { name:'청호나이스 삼성카드', image:'images/제휴카드/청호나이스/청호나이스삼성카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>7,000원</b> 할인','전월실적 70만원 이상 시 월 <b>10,000원</b> 할인','전월실적 120만원 이상 시 월 <b>13,000원</b> 할인'], promo:['4월 신규발급 프로모션','전 구간 <b>11,000원</b> 추가할인'], fee:'국내전용 15,000원 / 해외겸용(MASTER) 15,000원', phone:'1588-6076' },
    { name:'SK매직 롯데카드', image:'images/제휴카드/SK매직/SK매직롯데카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>13,000원</b> 할인','전월실적 70만원 이상 시 월 <b>16,000원</b> 할인','전월실적 120만원 이상 시 월 <b>25,000원</b> 할인'], promo:['2026.04 프로모션','30만원 구간 <b>2,000원</b> 추가할인 (60개월)','70만원 구간 <b>1,000원</b> 추가할인 (60개월)'], fee:'국내해외겸용 20,000원', phone:'1577-5320' },
    { name:'SK매직 KB국민카드', image:'images/제휴카드/SK매직/SK매직KB국민카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>11,000원</b> 할인','전월실적 70만원 이상 시 월 <b>15,000원</b> 할인','전월실적 100만원 이상 시 월 <b>20,000원</b> 할인'], promo:['2026.04 프로모션 추가할인','30만원 구간 <b>9,000원</b> 추가할인','70만원 구간 <b>5,000원</b> 추가할인'], fee:'국내전용 12,000원 / 국내외겸용(MasterCard) 15,000원', phone:'1644-8466' },
    { name:'SK매직 삼성카드', image:'images/제휴카드/SK매직/SK매직삼성카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>7,000원</b> 할인','전월실적 70만원 이상 시 월 <b>10,000원</b> 할인','전월실적 120만원 이상 시 월 <b>13,000원</b> 할인'], promo:['2026.04 프로모션','전 구간 <b>10,000원</b> 추가할인'], fee:'연회비 국내전용/해외겸용(Master card) 15,000원', phone:'1599-6758' },
    { name:'SK매직 KJ카드', image:'images/제휴카드/SK매직/SK매직KJ카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>10,000원</b> 할인','전월실적 70만원 이상 시 월 <b>16,000원</b> 할인','전월실적 120만원 이상 시 월 <b>23,000원</b> 할인'], fee:'연회비 국내전용 14,000원 / 국내외겸용(Master card) 15,000원', phone:'1833-3684' },
    { name:'쿠쿠 X 롯데카드', image:'images/제휴카드/쿠쿠/쿠쿠X롯데카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>13,000원</b> 할인','전월실적 70만원 이상 시 월 <b>16,000원</b> 할인','전월실적 150만원 이상 시 월 <b>25,000원</b> 할인'], promo:['2026.04 신규발급 프로모션','30만원 구간 <b>2,000원</b> 추가할인','70만원 구간 <b>1,000원</b> 추가할인'], fee:'국내전용, 해외겸용(MASTER) 20,000원', phone:'1577-7182' },
    { name:'쿠쿠 우리카드', image:'images/제휴카드/쿠쿠/쿠쿠우리카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>10,000원</b> 할인','전월실적 70만원 이상 시 월 <b>15,000원</b> 할인','전월실적 100만원 이상 시 월 <b>20,000원</b> 할인'], promo:['2026.04 신규발급 프로모션','30/70/120 구간 <b>8,000원 / 5,000원 / 3,000원</b> 추가할인'], fee:'연회비 국내 15,000원 / MasterCard 15,000원', phone:'1800-4138' },
    { name:'쿠쿠 삼성카드', image:'images/제휴카드/쿠쿠/쿠쿠삼성카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>7,000원</b> 할인','전월실적 70만원 이상 시 월 <b>10,000원</b> 할인','전월실적 120만원 이상 시 월 <b>13,000원</b> 할인'], promo:['2026.04 신규발급 프로모션','전 구간 <b>10,000원</b> 추가할인'], fee:'국내전용, 해외겸용(VISA) 15,000원', phone:'1588-9260' },
    { name:'쿠쿠 신한카드', image:'images/제휴카드/쿠쿠/쿠쿠신한카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>13,000원</b> 할인','전월실적 70만원 이상 시 월 <b>17,000원</b> 할인','전월실적 150만원 이상 시 월 <b>30,000원</b> 할인'], promo:['2026.04 신규발급 프로모션','30/70만원 구간 <b>2,000원</b> 추가할인'], fee:'국내전용 27,000원 / 해외겸용(VISA) 30,000원', phone:'1833-4303' },
    { name:'[우리] LG전자 우리카드 (Platinum)', image:'images/제휴카드/LG전자/LG전자우리카드(플래티넘)/1.png', benefits:['전월실적 100만원 이상 시 월 <b>29,000원</b> 할인','전월실적 150만원 이상 시 월 <b>34,000원</b> 할인','전월실적 200만원 이상 시 월 <b>40,000원</b> 할인'], promo:['4월 신규발급 프로모션','100/150/200만원 구간 <b>6,000원 / 5,000원 / 2,000원</b> 추가할인'], fee:'국내전용 / 해외겸용(VISA) 25,000원', phone:'1800-4137 / 온라인신청' },
    { name:'[우리] LG전자 우리카드', image:'images/제휴카드/LG전자/LG전자우리카드/1.png', benefits:['전월실적 30만원 이상 시 월 <b>10,000원</b> 할인','전월실적 70만원 이상 시 월 <b>15,000원</b> 할인','전월실적 120만원 이상 시 월 <b>20,000원</b> 할인'], promo:['4월 신규발급 추가할인 프로모션','30/70만원 구간 <b>7,000원</b> 추가할인','120만원 구간 <b>4,000원</b> 추가할인'], fee:'국내전용 15,000원 / 해외겸용(MasterCard) 15,000원', phone:'1800-4137 / 온라인신청' },
    { name:'[롯데] LG전자 롯데카드 구독엔로카', image:'images/제휴카드/LG전자/LG전자롯데카드구독엔로카/1.png', benefits:['전월실적 40만원 이상 시 월 <b>13,000원</b> 할인','전월실적 80만원 이상 시 월 <b>18,000원</b> 할인','전월실적 160만원 이상 시 월 <b>26,000원</b> 할인'], promo:['4월 신규발급 추가할인 프로모션','30만원 구간 <b>6,000원</b> 추가할인','70만원 구간 <b>4,000원</b> 추가할인'], fee:'국내전용, 해외겸용(MASTER/AMEX) 20,000원', phone:'1577-9469' },
    { name:'[신한] LG전자 신한카드 더구독케어', image:'images/제휴카드/LG전자/LG전자신한카드더구독케어/1.png', benefits:['전월실적 30만원 이상 시 월 <b>13,000원</b> 할인','전월실적 70만원 이상 시 월 <b>16,000원</b> 할인','전월실적 130만원 이상 시 월 <b>20,000원</b> 할인'], promo:['4월 신규발급 추가할인 프로모션','30만원 구간 <b>4,000원</b> 추가할인','70만원 구간 <b>1,000원</b> 추가할인'], fee:'연회비 국내전용 22,000원 / 국내외겸용(Mastercard) 25,000원', phone:'온라인신청', link:'https://cardapply.shinhancard.com/apply/CardInfoSelect?EntryLoc=4440&empSeq=502&targetID=&dat' },
  ].map((card) => {
    const match = card.image.match(/^images\/제휴카드\/([^/]+)\//);
    return { ...card, brand: match ? match[1] : 'ALL' };
  });

  const filteredCards = activeCategory === 'ALL'
    ? cards
    : cards.filter((card) => card.brand === activeCategory);
  const stripHtml = (text) => text.replace(/<[^>]+>/g, '');
  const parseTier = (line) => {
    const plain = stripHtml(line);
    const cond = plain.match(/전월실적\s*([0-9/]+만원)\s*이상/);
    const amount = plain.match(/([0-9,]+원)/);
    if (!cond || !amount) return null;
    return { condition: cond[1] + ' 이상', amount: amount[1], raw: amount[1].replace(/[^\d]/g, '') };
  };
  const compactCards = filteredCards.map((card) => {
    const tiers = (card.benefits || []).map(parseTier).filter(Boolean);
    const max = tiers.reduce((acc, t) => Math.max(acc, Number(t.raw || 0)), 0);
    return {
      ...card,
      tiers,
      maxText: max > 0 ? `${max.toLocaleString('ko-KR')}원` : '-',
    };
  });
  const categoryLabel = activeCategory === 'ALL' ? '전체 제휴카드 안내' : `${activeCategory} 제휴카드 안내`;
  const chunkCards = (list, size) => {
    const chunks = [];
    for (let i = 0; i < list.length; i += size) {
      chunks.push(list.slice(i, i + size));
    }
    return chunks;
  };
  const pagedCards = chunkCards(compactCards, cardsPerPage).map((group) => {
    if (group.length < cardsPerPage) {
      return [...group, ...Array.from({ length: cardsPerPage - group.length }, () => ({ isPlaceholder: true, name: '__placeholder__' }))];
    }
    return group;
  });
  const pageCount = Math.max(1, pagedCards.length);

  useEffect(() => {
    const onResize = () => {
      setCardsPerPage(window.innerWidth <= 767 ? 2 : 3);
    };
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);

  useEffect(() => {
    setCurrentPage(0);
    if (railRef.current) railRef.current.scrollTo({ left: 0, behavior: 'auto' });
  }, [activeCategory, cardsPerPage]);

  const scrollToPage = (nextPage) => {
    const rail = railRef.current;
    if (!rail || pageCount <= 1) return;
    const clamped = Math.max(0, Math.min(nextPage, pageCount - 1));
    rail.scrollTo({
      left: rail.clientWidth * clamped,
      behavior: 'smooth',
    });
    setCurrentPage(clamped);
  };

  const onRailScroll = () => {
    const rail = railRef.current;
    if (!rail || !rail.clientWidth || pageCount <= 1) return;
    const page = Math.round(rail.scrollLeft / rail.clientWidth);
    setCurrentPage(Math.max(0, Math.min(page, pageCount - 1)));
  };

  return (
    <section className="section section--subtle">
      <div className="container">
        <div className="section-kicker">PARTNER CARDS</div>
        <h2 className="section-title">카드 하나로 <span className="mark">월 렌탈료</span><br/>확 낮추는 법</h2>
        <p className="section-sub">제휴카드만 잘 골라도 매달 빠져나가는 렌탈료가 눈에 띄게 줄어듭니다.</p>

        <div className="cards-cats" role="tablist" aria-label="제휴카드 카테고리">
          {categories.map((category) => (
            <button
              key={category}
              type="button"
              className={`cards-cat ${activeCategory === category ? 'is-active' : ''}`}
              onClick={() => setActiveCategory(category)}
            >
              {category}
            </button>
          ))}
        </div>

        {activeCategory !== 'ALL' && brandProducts.length > 0 && (
          <div className="cardprods">
            <div className="cardprods__head">
              💧 <b>{activeCategory}</b> 제휴카드로 할인되는 정수기
            </div>
            <div className="cardprods__list">
              {brandProducts.map((p) => {
                const orig = wonToNum(p.price), cardv = wonToNum(p.card);
                return (
                  <button
                    type="button"
                    key={p.slug}
                    className="cardprod"
                    onClick={() => onApply && onApply()}
                  >
                    <div className="cardprod__thumb"><ProductThumb variant={p.v} image={p.image} name={p.name}/></div>
                    <div className="cardprod__info">
                      <div className="cardprod__name">{p.name}</div>
                      <div className="cardprod__price">
                        <s>{orig.toLocaleString()}원</s>
                        <span className="cardprod__arrow">→</span>
                        <b>월 {cardv.toLocaleString()}원~</b>
                      </div>
                    </div>
                  </button>
                );
              })}
            </div>
            <p className="cardprods__note">※ 제휴카드 최대 적용 시 기준. 카드·실적·약정에 따라 달라질 수 있어요.</p>
          </div>
        )}

        <h3 className="cards-headline">{categoryLabel}</h3>

        <div className="cards-rail" ref={railRef} onScroll={onRailScroll}>
          {pagedCards.map((page, pageIdx) => (
            <div key={pageIdx} className="cards-page">
              {page.map((c, i) => (
                <article key={i} className={`pcard ${c.isPlaceholder ? 'is-placeholder' : ''}`}>
                  {c.isPlaceholder ? null : (
                    <>
                      <div className="pcard__media">
                        <img className="pcard__image" src={c.image} alt={c.name} loading="lazy" decoding="async"/>
                      </div>
                      <h4 className="pcard__name">{c.name}</h4>
                      <ul className="pcard__list">
                        {c.tiers.map((tier, idx) => (
                          <li key={idx}>
                            <span>{tier.condition}</span>
                            <b>{tier.amount}</b>
                          </li>
                        ))}
                      </ul>
                      <div className="pcard__max">최대 {c.maxText}</div>
                    </>
                  )}
                </article>
              ))}
            </div>
          ))}
        </div>
        <div className={`cards-controls ${pageCount <= 1 ? 'is-hidden' : ''}`} aria-label="카드 슬라이드 컨트롤">
          <button
            type="button"
            className="cards-navbtn"
            onClick={() => scrollToPage(currentPage - 1)}
            disabled={currentPage <= 0}
            aria-label="이전 카드"
          >
            ‹
          </button>
          <button
            type="button"
            className="cards-navbtn"
            onClick={() => scrollToPage(currentPage + 1)}
            disabled={currentPage >= pageCount - 1}
            aria-label="다음 카드"
          >
            ›
          </button>
        </div>
        <div className={`cards-dots ${pageCount <= 1 ? 'is-hidden' : ''}`} aria-hidden="true">
          {Array.from({ length: pageCount }).map((_, idx) => (
            <span key={idx} className={`cards-dot ${idx === currentPage ? 'is-active' : ''}`}></span>
          ))}
        </div>
        <p className="cards-footnote">※ 카드사 및 프로모션 정책은 변동될 수 있으며, 상세 조건은 카드사 안내 기준을 따릅니다.</p>
      </div>
    </section>
  );
}

/* ---------- Process ---------- */
function Process() {
  const steps = [
    { n:'01', title:'간편 상담 신청',       desc:'이름·연락처만 남기면 1분이면 끝', icon:<I.User/> },
    { n:'02', title:'맞춤 조건 확인',       desc:'원하는 제품·예산을 함께 조율', icon:<I.Gift/> },
    { n:'03', title:'설치 일정 조율',       desc:'전국 어디든 편한 날짜로 설치', icon:<I.Truck/> },
  ];
  return (
    <section className="section">
      <div className="container">
        <div className="section-kicker">EASY PROCESS</div>
        <h2 className="section-title">빌리조<br/><span className="mark">이벤트 절차</span></h2>
        <p className="section-sub">복잡한 절차 없이, 딱 3단계면 충분합니다.</p>
        <div className="process">
          {steps.map(s => (
            <div key={s.n} className="step">
              <div className="step__num">{s.n}</div>
              <div className="step__body">
                <h4 className="step__title">{s.title}</h4>
                <div className="step__desc">{s.desc}</div>
              </div>
              <div className="step__icon">{s.icon}</div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---------- Final CTA (상담 / 무상담 2버튼) ---------- */
function FinalCTA({ onConsult, onDirect }) {
  return (
    <section className="final-cta" data-screen-label="12 Final CTA">
      <div className="container">
        <div className="final-cta__badge">🔥 이번 달 한정 프로모션</div>
        <h2 className="final-cta__title">이번 물량까지,<br/><span className="gold">그 다음은 없습니다</span></h2>
        <p className="final-cta__sub">지금 신청하시면 받으실 수 있는 혜택, 빠짐없이 챙겨드립니다.</p>
        <div className="final-cta__counter">
          <span className="final-cta__counter-lbl">선착순 77명 중 현재</span>
          <span className="final-cta__counter-num">64명</span>
          <span className="final-cta__counter-lbl">참여</span>
        </div>
        <div className="final-cta__btns">
          <button className="final-cta__btn final-cta__btn--ghost" onClick={onConsult}>
            <I.Phone width="20" height="20"/>무료 상담 신청·안내받기
          </button>
          <button className="final-cta__btn final-cta__btn--gold" onClick={onDirect}>
            <I.Gift width="20" height="20"/>무상담 가입신청 (추가혜택)
          </button>
        </div>
      </div>
    </section>
  );
}

/* ---------- Sticky CTA (상담 / 무상담 2버튼) ---------- */
function StickyCTA({ onConsult, onDirect }) {
  return (
    <div className="sticky-cta">
      <div className="sticky-cta__inner">
        <a href={MAIN_PHONE_HREF} className="sticky-cta__call" aria-label={`대표번호 ${MAIN_PHONE} 전화 걸기`}>
          <I.Phone width="22" height="22"/>
        </a>
        <button className="sticky-cta__btn sticky-cta__btn--consult" onClick={onConsult}>
          <I.Phone width="15" height="15"/>
          상담신청
        </button>
        <button className="sticky-cta__btn sticky-cta__btn--direct" onClick={onDirect}>
          <I.Gift width="15" height="15"/>
          <span>무상담 가입<small>추가혜택</small></span>
        </button>
      </div>
    </div>
  );
}

/* ---------- Footer ---------- */
function Footer() {
  return (
    <footer className="footer">
      <div className="container">
        <div><strong>빌리조</strong> · 인수형 렌탈 국내 최저가 비교 + 최대 혜택 찾기</div>
        <div style={{marginTop:6}}>
          대표 <a href={MAIN_PHONE_HREF} className="footer__tel">{MAIN_PHONE}</a>
          {' '}· 평일 09:00–20:00 (주말/공휴일 상담가능)
        </div>
        <div style={{marginTop:6,opacity:0.6}}>© 2026 Billyjo. All rights reserved.</div>
      </div>
    </footer>
  );
}

/* ---------- Submitted Toast ---------- */
function Toast({ show, onDone }) {
  useEffect(() => {
    if (!show) return;
    const t = setTimeout(onDone, 2800);
    return () => clearTimeout(t);
  }, [show, onDone]);
  if (!show) return null;
  return (
    <div className="toast">
      <I.Check width="18" height="18"/>상담 신청이 접수되었습니다!
    </div>
  );
}

/* ---------- 실시간 신청 알림 토스트 (오전 9시~새벽 2시, 세션 30분 한정) ----------
   동시간대 다른 지역 고객이 상담/사은품을 신청하는 것처럼 보여 사회적 증거(social proof) 제공.
   - 노출 시간대: 09:00 ~ 익일 01:59 (그 외 시간엔 아예 표시 안 함)
   - 한 세션(페이지 체류) 동안 최대 30분까지만 주기적 노출
   - 이름은 「성+OO」로 마스킹, 지역/액션/제품은 랜덤 */
function LiveActivityToast() {
  const [item, setItem] = useState(null);
  const [dismissed, setDismissed] = useState(false);
  const LIMIT = 77;

  useEffect(() => {
    const inWindow = () => {
      const h = new Date().getHours();
      return h >= 9 || h < 2; // 9시~새벽2시
    };
    if (!inWindow()) return;

    const SURNAMES = ['김','이','박','최','정','강','조','윤','장','임','한','오','서','신','권','황','안','송','전','홍','문','손','양','배','백','허','유','남','심','노'];
    const GIVEN = ['은','수','아','준','민','지','현','우','연','호','진','영','서','윤','담','경'];
    const REGIONS = ['서울','경기도','인천','부산','대구','광주','대전','울산','세종','강원','충북','충남','전북','전남','경북','경남','제주'];
    const STATUSES = ['상담 접수', '사은품 신청', '무상담 가입', '신청 완료'];
    const cat = window.PRODUCT_CATALOG || [];
    const rand = (arr) => arr[Math.floor(Math.random() * arr.length)];

    const sessionStart = Date.now();
    const SESSION_MS = 30 * 60 * 1000; // 30분
    let remain = 13; // 선착순 남은 자리(시작값)
    let showTimer, hideTimer;

    const tick = () => {
      if (Date.now() - sessionStart > SESSION_MS || !inWindow()) {
        setItem(null);
        return;
      }
      remain = Math.max(3, remain - 1);
      const surname = rand(SURNAMES);
      const prod = cat.length ? rand(cat) : null;
      setItem({
        id: Date.now(),
        surname,
        name: surname + '*' + rand(GIVEN),
        region: rand(REGIONS),
        status: rand(STATUSES),
        product: prod ? (prod.shortName || prod.name) : '정수기',
        ago: 1 + Math.floor(Math.random() * 9),
        concurrent: 1 + Math.floor(Math.random() * 3),
        remain,
        pct: Math.round(((LIMIT - remain) / LIMIT) * 100),
      });
      hideTimer = setTimeout(() => setItem(null), 6500);          // 약 6.5초 노출
      showTimer = setTimeout(tick, 16000 + Math.floor(Math.random() * 34000)); // 16~50초 후 다음
    };

    const firstTimer = setTimeout(tick, 5000 + Math.floor(Math.random() * 5000)); // 첫 알림 5~10초 후
    return () => { clearTimeout(firstTimer); clearTimeout(showTimer); clearTimeout(hideTimer); };
  }, []);

  if (dismissed || !item) return null;
  return (
    <div className="la-toast" role="status" aria-live="polite" key={item.id}>
      <button className="la-close" type="button" aria-label="닫기" onClick={()=>setDismissed(true)}>✕</button>
      <div className="la-kicker">
        <span className="la-flame">🔥</span><span className="la-live-tag">LIVE</span>
        현재 <b>{item.concurrent}명</b>이 고객님과 <b>동시에 상담 신청</b> 중
      </div>
      <div className="la-hdr">
        <div className="la-avatar">{item.surname}</div>
        <div className="la-meta">
          <div className="la-name-line">
            <span className="la-name">{item.name}</span>님
            <span className="la-status">{item.status}</span>· {item.ago}분 전
          </div>
          <div className="la-sub-line"><span className="la-live-mini"></span>{item.region} · 「{item.product}」</div>
        </div>
      </div>
      <div className="la-stock-row">
        <div className="la-big">{item.remain}<span className="la-drop">-1</span></div>
        <div className="la-stock-info">
          <div className="la-t">남은 선착순 자리 <span className="la-red">단 {item.remain}석</span><br/>방금 <span className="la-red">1석 신청</span></div>
          <div className="la-pbar"><div className="la-fill" style={{ width: `${item.pct}%` }}></div></div>
          <div className="la-pct"><b>{item.pct}%</b> 마감</div>
        </div>
      </div>
      <div className="la-trust">
        <div className="la-row la-safe"><span className="la-ic">✓</span>부담 없이 상담만 OK · <b>강매·위약금 없음</b></div>
        <div className="la-row la-urgent"><span className="la-ic">⚡</span>지금 신청 시 <b>오늘 설치일정 안내</b></div>
      </div>
    </div>
  );
}

/* ---------- Cross-sell (비슷한 고객들이 많이 신청한 가전) ---------- */
function CrossSell({ persona, onConsult, onDirect }) {
  const list = window.CROSS_SELL || [];
  const [tab, setTab] = useState('전체');
  if (!list.length) return null;
  const wonToNum = (s) => Number(String(s == null ? '' : s).replace(/[^\d]/g, '')) || 0;
  const p = (persona || '').trim();
  const cats = ['전체'].concat(Array.from(new Set(list.map((x) => x.category))));
  const filtered = tab === '전체' ? list : list.filter((x) => x.category === tab);
  return (
    <section className="section section--subtle cross">
      <div className="container">
        <div className="section-kicker">MORE POPULAR</div>
        <h2 className="section-title">
          {p
            ? <>「{p}」 고객님과 <span className="mark">비슷한 분들이</span><br/>함께 신청한 가전</>
            : <>고객님과 <span className="mark">비슷한 고객님들이</span><br/>많이 신청해요</>}
        </h2>
        <p className="section-sub">유명 브랜드·인기순으로, 네이버·구글에서 많이 찾는 가전을 모았어요.</p>
        <div className="cross__bonus">🎁 <b>2개 이상 함께 신청</b>하면 <b>추가 혜택</b>을 더 드려요!</div>
        <div className="cards-cats" role="tablist" aria-label="가전 카테고리">
          {cats.map((c) => (
            <button key={c} type="button" className={`cards-cat ${tab === c ? 'is-active' : ''}`} onClick={() => setTab(c)}>{c}</button>
          ))}
        </div>
        <div className="cross-grid">
          {filtered.map((it) => {
            const orig = wonToNum(it.price), cardv = wonToNum(it.card);
            return (
              <div
                key={it.slug}
                className="cross-card"
                role="button"
                tabIndex={0}
                onClick={() => onConsult && onConsult()}
                onKeyDown={(e)=>{ if(e.key==='Enter'||e.key===' '){ e.preventDefault(); onConsult && onConsult(); } }}
              >
                <div className="cross-card__cat">{it.category}</div>
                <div className="cross-card__img"><ProductThumb variant={it.v} name={it.name}/></div>
                <div className="cross-card__brand">
                  {it.brand}<span className="cross-card__rating"><I.Star/>{it.rating}</span>
                </div>
                <div className="cross-card__name">{it.name}</div>
                <div className="cross-card__summary">{it.summary}</div>
                <div className="cross-card__price">
                  <s>{orig.toLocaleString()}원</s>
                  <b>{it.card}</b>
                </div>
                {cardv > 0 && <div className="cross-card__perday">하루 약 {(Math.round(cardv / 30 / 10) * 10).toLocaleString()}원꼴</div>}
                {it.gift && <div className="cross-card__gift"><I.Gift width="12" height="12"/>예상 사은품 {it.gift}</div>}
                <div className="cross-card__cta">함께 신청하기 →</div>
              </div>
            );
          })}
        </div>
        <button className="cross__btn" onClick={() => onDirect && onDirect()}>
          <I.Gift width="18" height="18"/>정수기 + 가전 함께 신청하고 추가혜택 받기
        </button>
      </div>
    </section>
  );
}

/* ---------- 포토 후기 (제조사 공식 채널 수집 · 출처 표기) ---------- */
function ReviewPhoto({ src }) {
  const [ok, setOk] = useState(true);
  if (!src || !ok) return null;
  return <img className="rv-card__img" src={src} alt="" loading="lazy" decoding="async" onError={()=>setOk(false)}/>;
}
// 판매자/스토어명 공식성 3구분: 직영(공식몰/공식스토어/'공식') / 공식리셀러(공식대리점·공식파트너·공식인증점 등) / 일반.
const RESELLER_MARK = /파트너|대리점|인증점?|총판|리셀러|판매점|특약점|영업소/;
function isOfficialReseller(name) { // '공식' + 리셀러/대리점 표지 → 공식리셀러(직영 아님, 별도 표기)
  name = name || '';
  return /공식/.test(name) && RESELLER_MARK.test(name);
}
function isOfficialSeller(name) {   // 공식 직영(공식몰·공식스토어·공식판매처·'공식'). 리셀러는 제외.
  name = name || '';
  return /공식/.test(name) && !RESELLER_MARK.test(name);
}
// 표시 라벨 = 「브랜드 · 채널」. 데이터엔 실제 출처(예 "다나와·11번가·삼성전자공식스토어") 보관, 표시만 정리.
// ⚠️ '공식'은 판매자명이 공식인 경우(또는 자사몰/브랜드 공식스토어)에만. 미검증 마켓 후기엔 금지(출처 허위=표시광고법).
// 검증된 공식 채널: 네이버 브랜드스토어(naver-collect는 brand.naver.com/{공식slug}에서만 수집) · 자사몰/공식몰/공식스토어.
function isOfficialChannel(s) {
  s = s || '';
  return /네이버|공식몰|공식\s*스토어|브랜드\s*스토어|자사몰/.test(s) || isOfficialSeller(s);
}
// 제조사 직영몰 판정(다나와 원몰명 기준). 사용자 관찰: 직영몰은 보통 「브랜드명 단독」 또는
// 「브랜드명+(전자/몰/공식/공식몰/공식스토어/판매처/스토어/닷컴/.com/코리아)」 형태로 잡힘.
// ⚠️ '포함'이 아니라 '브랜드+허용접미사로 정확히 끝남'만 인정 — '코웨이렌탈프라자'·'LG가전마트' 같은 리셀러 세탁 차단.
// 오픈마켓/유통(G마켓·11번가·옥션·현대Hmall·CJ온스타일·SK스토아 등)은 브랜드명으로 시작 안 하므로 자연 제외.
const BRAND_ALIASES = { // 변형 표기(없는 브랜드는 brand 값 그대로 사용 → 미지원 브랜드도 동작)
  'LG': ['LG', '엘지'], '삼성': ['삼성', 'samsung'], '코웨이': ['코웨이', 'coway'], '청호나이스': ['청호나이스', '청호'],
  'SK매직': ['SK매직', '에스케이매직'], '쿠쿠': ['쿠쿠', 'cuckoo'], '위닉스': ['위닉스', 'winix'], '교원웰스': ['교원웰스', '교원웰스'],
};
const OFFICIAL_SUFFIX = /^(전자|몰|공식|공식몰|공식스토어|공식판매처|판매처|스토어|샵|닷컴|\.com|official|코리아)?$/i;
function isOfficialMall(mall, brand) {
  mall = (mall || '').replace(/\s/g, '');
  if (isOfficialSeller(mall)) return true;                  // 몰명에 '공식'
  const aliases = BRAND_ALIASES[brand] || (brand ? [brand] : []);
  for (const a of aliases) {
    const an = a.replace(/\s/g, '');
    if (an && mall.toUpperCase().startsWith(an.toUpperCase()) && OFFICIAL_SUFFIX.test(mall.slice(an.length))) return true;
  }
  return false;
}
function channelOf(s, brand) {
  s = s || '';
  const bp = brand ? brand + ' ' : '';                      // 브랜드 접두
  if (/다나와|쿠팡|에누리/.test(s)) {
    const parts = s.split('·').map((x) => x.trim());        // [플랫폼, 몰, (판매자)]
    const seller = parts[parts.length - 1] || '';
    if (parts.length >= 3) {                                // 판매자명이 잡히는 경우 우선 판정
      if (isOfficialReseller(seller)) return bp + '공식리셀러';
      if (isOfficialSeller(seller)) return bp + '공식 판매채널';
    }
    const mall = parts[1] || (s.indexOf('쿠팡') >= 0 ? '쿠팡' : s.indexOf('에누리') >= 0 ? '에누리' : '다나와');
    if (isOfficialReseller(mall)) return bp + '공식리셀러';  // 원몰명이 공식대리점/공식파트너 등
    if (isOfficialMall(mall, brand)) return bp + '공식 판매채널'; // 원몰=제조사 직영 (예: 다나와·LG전자)
    return (brand ? brand + ' · ' : '') + mall;             // 그 외 마켓: 예 로보락 · 11번가
  }
  if (isOfficialReseller(s)) return bp + '공식리셀러';
  if (isOfficialChannel(s)) return brand ? brand + ' 공식 판매채널' : '브랜드 공식 판매채널'; // 검증된 직영/공식만
  return (brand ? brand + ' · ' : '') + (s || '판매처');     // 미검증/미상 출처: '공식' 금지, 채널명 그대로 (아정당·출처미상 등)
}
// 숨김 출처: 아정당(경쟁 리셀러 — 표시 안 함). source 어디에 박혀도 차단.
const HIDDEN_SOURCE = /아정당/;
const visibleReview = (r) => !HIDDEN_SOURCE.test((r && (r.source || r.source_mall)) || '');
function Reviews({ onConsult }) {
  const [list, setList] = useState((window.REVIEWS || []).filter(visibleReview));
  // admin2 Review API(/api/reviews) 우선, 비어있으면 시드(window.REVIEWS) 유지
  useEffect(() => {
    let alive = true;
    fetch('/api/reviews?category=' + encodeURIComponent('정수기') + '&limit=40')
      .then((r) => r.json())
      .then((body) => {
        if (!alive || !body || !body.items || !body.items.length) return;
        setList(body.items.filter(visibleReview).map((it) => ({
          stars: it.stars || 5,
          text: it.text || '',
          photo: it.photo_url || (it.photos && it.photos[0]) || '',
          source: it.source || '',
          brand: it.brand || '',
          sourceUrl: it.source_url || '',
          reviewedAt: it.reviewed_at || '',
        })));
      })
      .catch(() => {});
    return () => { alive = false; };
  }, []);
  if (!list.length) return null;
  const avg = (list.reduce((s, r) => s + (r.stars || 5), 0) / list.length).toFixed(1);
  // 포토리뷰 전면 → 그다음 일반, 각 그룹 내 최신순 (출처 혼합)
  const sorted = [...list].sort((a, b) =>
    (b.photo ? 1 : 0) - (a.photo ? 1 : 0) ||
    String(b.reviewedAt || '').localeCompare(String(a.reviewedAt || ''))
  );
  return (
    <section className="section section--subtle reviews">
      <div className="container">
        <div className="section-kicker">REAL REVIEWS</div>
        <h2 className="section-title">먼저 써본 고객들의 <span className="mark">생생한 후기</span></h2>
        <div className="rv-summary">
          <span className="rv-stars" aria-hidden="true">{'★★★★★'}</span>
          <b>{avg}</b> · 고객 후기 {list.length}건
        </div>
        <div className="rv-rail">
          {sorted.map((r, i) => (
            <article className="rv-card" key={i}>
              <ReviewPhoto src={r.photo}/>
              <div className="rv-card__top">
                <span className="rv-card__stars" aria-label={`별점 ${r.stars}점`}>
                  {Array.from({ length: 5 }).map((_, k) => (
                    <I.Star key={k} width="13" height="13"/>
                  ))}
                </span>
                <span className="rv-card__chip">{channelOf(r.source, r.brand)}</span>
              </div>
              <p className="rv-card__text">{r.text}</p>
              <div className="rv-card__src">출처: {channelOf(r.source, r.brand)}{r.reviewedAt ? ` · ${r.reviewedAt}` : ''}</div>
            </article>
          ))}
        </div>
        <p className="rv-note">
          ※ 후기는 브랜드 공식 채널·다나와 등에서 수집했으며 각 후기에 출처를 표기합니다.
        </p>
        <button className="rv-cta" onClick={()=>onConsult && onConsult()}>
          <I.Phone width="17" height="17"/>나도 상담받고 시작하기
        </button>
      </div>
    </section>
  );
}

/* ---------- Guarantee Bar (리스크 리버설 보장 배너) ---------- */
function GuaranteeBar() {
  const items = [
    { ic:<I.Seal/>,   t:'정품·본사 설치 보증' },
    { ic:<I.Shield/>, t:'안 맞으면 교체·해지 상담' },
    { ic:<I.Coin/>,   t:'위약금 0원 조건 제품 안내' },
    { ic:<I.Check/>,  t:'전 과정 무료 상담' },
  ];
  return (
    <div className="guarantee">
      <div className="container">
        <div className="guarantee__inner">
          {items.map((g, i) => (
            <div key={i} className="guarantee__item"><span className="guarantee__ic">{g.ic}</span>{g.t}</div>
          ))}
        </div>
      </div>
    </div>
  );
}

/* ---------- Buy vs Rental (구매 vs 렌탈 총비용 비교) ---------- */
function BuyVsRental() {
  const rows = [
    { label:'초기 비용', rent:'0원~ 부담 없이 시작', buy:'수십만원 일시불' },
    { label:'필터·관리', rent:'정기 방문관리 포함', buy:'직접 구매·교체' },
    { label:'A/S',       rent:'무상 점검·관리',     buy:'유상 수리' },
    { label:'사은품',    rent:'현금 사은품 제공',   buy:'없음' },
    { label:'최신 모델', rent:'약정 후 교체 가능',  buy:'재구매 필요' },
    { label:'제품 소유', rent:'소유권 이전 · 반납 선택', buy:'감가상각 · 판매/반납 어려움' },
  ];
  return (
    <section className="section">
      <div className="container">
        <div className="section-kicker">BUY vs RENTAL</div>
        <h2 className="section-title">사서 직접 관리 vs <span className="mark">렌탈로 맡기기</span></h2>
        <p className="section-sub">관리·A/S·사은품까지 더하면, 렌탈이 훨씬 가볍습니다.</p>
        <div className="compare">
          <div className="compare__row compare__head">
            <div className="compare__cell compare__cell--label">항목</div>
            <div className="compare__cell compare__cell--good">빌리조 렌탈</div>
            <div className="compare__cell">직접 구매</div>
          </div>
          {rows.map(r => (
            <div key={r.label} className="compare__row">
              <div className="compare__cell compare__cell--label">{r.label}</div>
              <div className="compare__cell compare__cell--good">
                <span className="compare__mark good">○</span><span>{r.rent}</span>
              </div>
              <div className="compare__cell compare__cell--bad">
                <span className="compare__mark bad">✕</span><span>{r.buy}</span>
              </div>
            </div>
          ))}
        </div>
        <div className="compare-outro">
          같은 제품도, 관리까지 맡기면<br/>렌탈이 더 가볍고 합리적입니다.
        </div>
      </div>
    </section>
  );
}

Object.assign(window, {
  Header, Hero, Status, InquiryForm, Benefits, OnlyBenefits, Products,
  Trust, Compare, BuyVsRental, Cards, Process, FinalCTA, StickyCTA, Footer, Toast, NoticeModal,
  LiveViewingBar, LiveActivityToast, Recommendations, TopStatusBar, CrossSell, GuaranteeBar, Reviews,
});
