/* =============================================================================
   노바바레 — 화면 본체
   -----------------------------------------------------------------------------
   글자는 전부 src/content.js 에 있다. 이 파일은 구조와 디자인만 담당한다.
   ========================================================================== */

const C = window.CONTENT;
const { useState, useEffect, useRef } = React;

// 주소 뒤에 ?shot=1 을 붙이면 스크롤 없이 전부 바로 보이게 한다 (스크린샷 검증용).
const SHOT = window.location.search.indexOf("shot=1") >= 0;
const LAZY = SHOT ? "eager" : "lazy";

/* ── 공통 유틸 ─────────────────────────────────────────────────────────── */

function useReveal() {
  useEffect(() => {
    const els = document.querySelectorAll(".reveal:not(.in)");
    if (SHOT || !("IntersectionObserver" in window)) {
      els.forEach((el) => el.classList.add("in"));
      return;
    }
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => {
          if (e.isIntersecting) {
            e.target.classList.add("in");
            io.unobserve(e.target);
          }
        });
      },
      { threshold: 0.12, rootMargin: "0px 0px -8% 0px" }
    );
    els.forEach((el) => io.observe(el));
    return () => io.disconnect();
  });
}

// **별표 두 개**로 감싼 부분을 굵게 렌더링한다.
function rich(text, strongClass) {
  const parts = String(text == null ? "" : text).split("**");
  return parts.map((p, i) =>
    i % 2 === 1 ? <strong key={i} className={strongClass || "font-semibold text-ink"}>{p}</strong> : <React.Fragment key={i}>{p}</React.Fragment>
  );
}

function scrollTo(id) {
  const el = document.getElementById(id);
  if (el) el.scrollIntoView({ behavior: "smooth", block: "start" });
}

function SectionHead({ eyebrow, title, desc, align = "center", light = false }) {
  const lines = Array.isArray(title) ? title : [title];
  const a = align === "left" ? "text-left items-start" : "text-center items-center";
  return (
    <div className={"flex flex-col " + a + " reveal"}>
      {eyebrow ? (
        <p className={"font-thin text-[13px] tracking-[0.28em] uppercase mb-3 " + (light ? "text-yellow" : "text-gold")}>
          {eyebrow}
        </p>
      ) : null}
      <h2
        className={
          "text-[30px] sm:text-[40px] lg:text-[46px] leading-[1.24] font-bold tracking-[-0.015em] break-keep " +
          (light ? "text-cream" : "text-ink")
        }
      >
        {lines.map((l, i) => (
          <span key={i} className="block">{l}</span>
        ))}
      </h2>
      {desc ? (
        <p className={"mt-4 max-w-2xl text-[16.5px] sm:text-[17.5px] leading-[1.8] " + (light ? "text-cream/85" : "text-ink/75") + (align === "center" ? " mx-auto" : "")}>
          {desc}
        </p>
      ) : null}
    </div>
  );
}

function Avatar({ name, image, size = "h-full w-full" }) {
  if (image) {
    return (
      <div className={size + " bg-ink/5 flex items-center justify-center"}>
        <img src={image} alt={name} loading={LAZY} className="h-full w-full object-contain" />
      </div>
    );
  }
  const initial = name ? name[0] : "?";
  return (
    <div className={size + " flex items-center justify-center bg-ink/90 text-yellow text-3xl font-bold"}>
      {initial}
    </div>
  );
}

/* ── 헤더 ──────────────────────────────────────────────────────────────── */

const NAV = [
  { id: "programs", label: "프로그램" },
  { id: "branches", label: "지점 안내" },
  { id: "trainers", label: "강사진" },
  { id: "pricing", label: "요금" },
  { id: "ibfa", label: "IBFA 자격" },
  { id: "faq", label: "FAQ" },
  { hash: "#/column", label: "저널" },
];

function Header({ alwaysSolid }) {
  const [scrolled, setScrolled] = useState(false);
  const [open, setOpen] = useState(false);

  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 40);
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  const solid = alwaysSolid || scrolled || open;

  // 칼럼 페이지에 있을 때 홈 섹션을 누르면, 홈으로 먼저 돌아간 뒤 해당 섹션으로 내려간다
  const go = (item) => {
    setOpen(false);
    if (item.hash) {
      window.location.hash = item.hash;
      return;
    }
    const id = item.id || item;
    const jump = () => scrollTo(id);
    if (window.location.hash && window.location.hash !== "#/") {
      window.location.hash = "";
      setTimeout(jump, 80);
    } else {
      jump();
    }
  };

  return (
    <header className={"fixed inset-x-0 top-0 z-50 transition-all duration-500 " + (solid ? "bg-ink/95 backdrop-blur-md py-3" : "py-5")}>
      <div className="mx-auto max-w-8xl px-5 sm:px-8 flex items-center justify-between gap-6">
        <button onClick={() => { if (window.location.hash) { window.location.hash = ""; } window.scrollTo({ top: 0, behavior: "smooth" }); }} className="text-left leading-none">
          <span className="block font-serif italic text-[20px] sm:text-[22px] tracking-wide text-cream">NOVA BARRE</span>
          <span className="block font-thin text-[10px] tracking-[0.22em] text-yellow mt-1">국제바레플로우협회(IBFA)</span>
        </button>

        <nav className="hidden lg:flex items-center gap-7">
          {NAV.map((n) => (
            <button key={n.label} onClick={() => go(n)} className="text-[14.5px] text-cream/80 hover:text-yellow transition-colors">
              {n.label}
            </button>
          ))}
          <button onClick={() => go({ id: "booking" })} className="rounded-full bg-yellow px-5 py-2.5 text-[14.5px] font-semibold text-ink hover:brightness-95 transition">
            예약·상담
          </button>
        </nav>

        <button onClick={() => setOpen((v) => !v)} aria-label="메뉴" className="lg:hidden flex flex-col gap-[5px] p-2">
          <span className={"block h-px w-6 bg-cream transition-transform " + (open ? "translate-y-[6px] rotate-45" : "")} />
          <span className={"block h-px w-6 bg-cream transition-opacity " + (open ? "opacity-0" : "")} />
          <span className={"block h-px w-6 bg-cream transition-transform " + (open ? "-translate-y-[6px] -rotate-45" : "")} />
        </button>
      </div>

      {open ? (
        <div className="lg:hidden mt-4 mx-5 rounded-2xl bg-ink border border-cream/10 p-4 shadow-lg">
          {NAV.map((n) => (
            <button key={n.label} onClick={() => go(n)} className="block w-full text-left px-3 py-3 text-[16px] text-cream/85 border-b border-cream/10 last:border-0">
              {n.label}
            </button>
          ))}
          <button onClick={() => go({ id: "booking" })} className="mt-3 block w-full text-center rounded-full bg-yellow px-5 py-3 text-[15px] font-semibold text-ink">
            예약·상담
          </button>
        </div>
      ) : null}
    </header>
  );
}

/* ── 1. 히어로 (G1-F 확정안 — 와이드 인증서 스틸 + 차분한 페이드) ───────── */

function Hero() {
  const h = C.hero;
  return (
    <section id="hero" className="relative min-h-[64svh] sm:min-h-[92svh] flex items-end overflow-hidden bg-ink">
      <div className="absolute inset-0">
        <img src={h.image} alt="국제바레플로우협회 인증서" fetchpriority="high" decoding="async" className="h-full w-full object-cover hero-ken" />
      </div>
      <div className="absolute inset-0" style={{ background: "linear-gradient(0deg, rgba(15,15,15,.86) 0%, rgba(15,15,15,.3) 52%, rgba(15,15,15,.38) 100%)" }} />

      <Header />

      {/* 우상단 회전 인증 스탬프 */}
      <div className="hidden sm:flex absolute right-[6%] top-[17%] w-[13%] max-w-[150px] min-w-[104px] aspect-square rounded-full border-2 border-yellow items-center justify-center text-center z-10" style={{ background: "rgba(15,15,15,.45)" }}>
        <div className="text-[9px] leading-[1.55] tracking-[0.1em] text-yellow font-bold px-2">
          {h.sealLines.map((l, i) => <div key={i}>{l}</div>)}
        </div>
      </div>

      <div className="relative z-10 w-full max-w-8xl mx-auto px-5 sm:px-8 pb-12 sm:pb-20 pt-24 sm:pt-40">
        <div className="max-w-2xl reveal in">
          <span className="inline-flex items-center gap-2 rounded-full border border-goldBr/60 px-4 py-1.5 text-[12.5px] text-cream">
            <i className="h-1.5 w-1.5 rounded-full bg-goldBr inline-block" />
            {h.badge}
          </span>
          <p className="mt-5 font-thin text-[11.5px] sm:text-[12.5px] tracking-[0.24em] uppercase text-gold">{h.eyebrow}</p>
          <h1 className="mt-3 text-cream font-bold text-[34px] sm:text-[48px] lg:text-[56px] leading-[1.18] break-keep">
            {h.lines.map((l, i) => <span key={i} className="block">{l}</span>)}
          </h1>
          <p className="mt-4 text-[16px] sm:text-[18px] text-cream/80">{h.sub}</p>
          <div className="mt-8 flex flex-col sm:flex-row gap-3">
            <button onClick={() => scrollTo("booking")} className="rounded-full bg-yellow px-8 py-4 text-[15.5px] font-semibold text-ink hover:brightness-95 transition">
              {h.ctaPrimary}
            </button>
            <button onClick={() => scrollTo("ibfa")} className="rounded-full border border-cream/50 px-8 py-4 text-[15.5px] text-cream hover:border-yellow hover:text-yellow transition">
              {h.ctaSecondary} →
            </button>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ── 2. 대표님 한마디 ─────────────────────────────────────────────────── */

function Founder() {
  const f = C.founder;
  return (
    <section className="py-20 sm:py-28 bg-cream">
      <div className="mx-auto max-w-8xl px-5 sm:px-8 grid lg:grid-cols-[0.85fr_1.15fr] gap-12 items-center">
        <div className="reveal">
          <div className="aspect-[4/5] w-full max-w-md mx-auto lg:mx-0 overflow-hidden rounded-sm shadow-xl">
            <Avatar name={f.name} image={f.image} />
          </div>
        </div>
        <div className="reveal">
          <p className="font-thin text-[13px] tracking-[0.28em] uppercase text-gold mb-4">{f.eyebrow}</p>
          <blockquote className="text-[26px] sm:text-[32px] font-bold leading-[1.4] text-ink break-keep">
            “{f.quote}”
          </blockquote>
          <p className="mt-3 text-[15.5px] text-ink/60">{f.quoteSub}</p>
          <p className="mt-6 text-[16px] leading-[1.9] text-ink/80 break-keep">{f.body}</p>
          <p className="mt-6 text-[15px] font-semibold text-ink">{f.name} <span className="font-normal text-ink/60">— {f.role}</span></p>
        </div>
      </div>
    </section>
  );
}

/* ── 3. 신뢰 포인트 ───────────────────────────────────────────────────── */

function TrustPoints() {
  const t = C.trustPoints;
  return (
    <section className="relative py-20 sm:py-24 bg-ink overflow-hidden">
      <div className="orb drift bg-yellow/25" style={{ width: 460, height: 460, top: "-16%", left: "-10%" }} />
      <div className="orb drift2 bg-gold/30" style={{ width: 360, height: 360, bottom: "-16%", right: "4%" }} />
      <div className="orb drift3 bg-yellow/15" style={{ width: 280, height: 280, top: "30%", right: "22%" }} />
      <div className="relative z-10 mx-auto max-w-8xl px-5 sm:px-8">
        <SectionHead title={t.title} light align="left" />
        <div className="mt-12 grid sm:grid-cols-3 gap-6">
          {t.items.map((it, i) => (
            <div key={i} className="reveal rounded-sm border border-cream/10 p-7" style={{ transitionDelay: i * 90 + "ms" }}>
              <div className="text-[13px] font-bold tracking-[0.1em] text-yellow border border-yellow/50 rounded-full inline-flex px-3 py-1">{it.mark}</div>
              <h3 className="mt-5 text-[19px] font-bold text-cream">{it.title}</h3>
              <p className="mt-2 text-[15px] leading-[1.75] text-cream/70">{rich(it.desc, "font-semibold text-yellow")}</p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ── 3-2. 시설 갤러리 (가로로 끊김 없이 흐르는 마퀴) ──────────────────── */

function Gallery() {
  const g = C.gallery;
  const row = g.images.concat(g.images); // 끊김 없이 흐르도록 2배 복제
  return (
    <section className="bg-cream py-16 sm:py-24 overflow-hidden">
      <div className="mx-auto max-w-8xl px-5 sm:px-8">
        <SectionHead eyebrow={g.eyebrow} title={g.title} desc={g.desc} />
      </div>
      <div className="mt-10 sm:mt-14 relative">
        <div className="flex gap-4 w-max" style={{ animation: "marquee 55s linear infinite" }}>
          {row.map((src, i) => (
            <div key={i} className="w-[240px] sm:w-[340px] shrink-0">
              <img src={src} alt="" aria-hidden="true" loading={LAZY} className="h-[170px] sm:h-[230px] w-full object-cover rounded-sm" />
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ── 4. 프로그램 ──────────────────────────────────────────────────────── */

function Programs() {
  const p = C.programs;
  const [featured, ...rest] = p.list;
  return (
    <section id="programs" className="py-20 sm:py-28 bg-cream">
      <div className="mx-auto max-w-8xl px-5 sm:px-8">
        <SectionHead eyebrow={p.eyebrow} title={p.title} desc={p.desc} />
        <div className="mt-14 grid lg:grid-cols-2 gap-6">
          <div className="reveal group rounded-sm overflow-hidden bg-white shadow-sm border border-ink/5 flex flex-col">
            <div className="aspect-[4/3] lg:aspect-auto lg:flex-1 overflow-hidden">
              <img src={featured.image} alt={featured.name} loading={LAZY} className="h-full w-full object-cover group-hover:scale-105 transition duration-700" />
            </div>
            <div className="p-7 sm:p-9">
              <span className="text-[11px] font-bold tracking-[0.12em] text-gold">{featured.tag} · 시그니처</span>
              <h3 className="mt-2 text-[24px] sm:text-[28px] font-bold text-ink">{featured.name}</h3>
              <p className="mt-3 text-[15.5px] leading-[1.85] text-ink/70">{featured.desc}</p>
            </div>
          </div>
          <div className="grid sm:grid-cols-2 gap-6">
            {rest.map((prog, i) => (
              <div key={i} className="reveal group rounded-sm overflow-hidden bg-white shadow-sm border border-ink/5" style={{ transitionDelay: i * 80 + "ms" }}>
                <div className="aspect-[4/3] overflow-hidden">
                  <img src={prog.image} alt={prog.name} loading={LAZY} className="h-full w-full object-cover group-hover:scale-105 transition duration-700" />
                </div>
                <div className="p-5">
                  <span className="text-[11px] font-bold tracking-[0.12em] text-gold">{prog.tag}</span>
                  <h3 className="mt-2 text-[17px] font-bold text-ink">{prog.name}</h3>
                  <p className="mt-2 text-[13.5px] leading-[1.7] text-ink/70">{prog.desc}</p>
                </div>
              </div>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
}

/* ── 5. 지점 안내 ─────────────────────────────────────────────────────── */

function Branches() {
  const list = C.branches;
  return (
    <section id="branches" className="py-20 sm:py-28 bg-ivory">
      <div className="mx-auto max-w-8xl px-5 sm:px-8">
        <SectionHead eyebrow="BRANCHES" title="지점 안내" desc="대전 유성구 관평동 본점과 신성점, 두 곳에서 만나실 수 있습니다." />

        <div className="mt-14 space-y-16">
          {list.map((b, bi) => (
            <div key={b.id} className="reveal grid lg:grid-cols-2 gap-8 items-stretch" style={{ transitionDelay: bi * 100 + "ms" }}>
              <div className={"grid grid-cols-2 gap-2 " + (bi % 2 === 1 ? "lg:order-2" : "")}>
                {b.images.map((src, i) => (
                  <div key={i} className={"overflow-hidden rounded-sm " + (i === 0 ? "col-span-2 aspect-[16/9]" : "aspect-square")}>
                    <img src={src} alt={b.name} loading={LAZY} className="h-full w-full object-cover" />
                  </div>
                ))}
              </div>
              <div className="bg-white rounded-sm p-8 sm:p-10 flex flex-col justify-center">
                <span className="text-[12px] font-bold tracking-[0.1em] text-gold">{b.menuLabel.toUpperCase()}</span>
                <h3 className="mt-1 text-[24px] font-bold text-ink">{b.name}</h3>
                <dl className="mt-6 space-y-4 text-[15.5px]">
                  <div className="flex gap-3"><dt className="w-16 shrink-0 text-ink/50">주소</dt><dd className="text-ink/85">{b.addr}</dd></div>
                  <div className="flex gap-3"><dt className="w-16 shrink-0 text-ink/50">전화</dt><dd className="text-ink/85"><a href={"tel:" + b.phone} className="hover:text-gold">{b.phone}</a></dd></div>
                  <div className="flex gap-3"><dt className="w-16 shrink-0 text-ink/50">운영시간</dt><dd className="text-ink/85">{b.hours}</dd></div>
                  {b.note ? <div className="flex gap-3"><dt className="w-16 shrink-0 text-ink/50">참고</dt><dd className="text-ink/70">{b.note}</dd></div> : null}
                </dl>
                <div className="mt-7 flex flex-wrap gap-3">
                  <a href={b.kakao} target="_blank" rel="noreferrer noopener" className="rounded-full bg-[#FEE500] px-5 py-2.5 text-[14px] font-semibold text-ink/90">카카오 상담</a>
                  {b.naver ? <a href={b.naver} target="_blank" rel="noreferrer noopener" className="rounded-full bg-[#03C75A] px-5 py-2.5 text-[14px] font-semibold text-white">네이버 플레이스</a> : null}
                  <a href={b.instagram} target="_blank" rel="noreferrer noopener" className="rounded-full border border-ink/15 px-5 py-2.5 text-[14px] text-ink/80 hover:border-gold hover:text-gold">인스타그램</a>
                </div>
              </div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ── 6. 강사진 ────────────────────────────────────────────────────────── */

function Trainers() {
  const t = C.trainers;
  return (
    <section id="trainers" className="py-20 sm:py-28 bg-cream">
      <div className="mx-auto max-w-8xl px-5 sm:px-8">
        <SectionHead eyebrow={t.eyebrow} title={t.title} desc={t.desc} />
        <div className="mt-14 grid sm:grid-cols-2 lg:grid-cols-4 gap-6">
          {t.list.map((tr, i) => (
            <div key={i} className="reveal" style={{ transitionDelay: (i % 4) * 80 + "ms" }}>
              <div className="aspect-[4/5] overflow-hidden rounded-sm bg-ink/5">
                <Avatar name={tr.name} image={tr.image} />
              </div>
              <h3 className="mt-4 text-[17px] font-bold text-ink">{tr.name} <span className="text-[13px] font-normal text-ink/50">· {tr.role}</span></h3>
              {tr.years ? <p className="text-[12.5px] text-gold font-semibold mt-0.5">경력 {tr.years}</p> : null}
              <p className="mt-2 text-[14px] leading-[1.7] text-ink/70">{tr.desc}</p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ── 7. 요금 ──────────────────────────────────────────────────────────── */

function Pricing() {
  const p = C.pricing;
  return (
    <section id="pricing" className="py-20 sm:py-28 bg-ink">
      <div className="mx-auto max-w-8xl px-5 sm:px-8">
        <SectionHead eyebrow={p.eyebrow} title={p.title} desc={p.note} light />
        <div className="mt-14 grid sm:grid-cols-2 lg:grid-cols-4 gap-5">
          {p.plans.map((pl, i) => (
            <div key={i} className={"reveal rounded-sm p-7 border " + (pl.highlight ? "bg-yellow border-yellow" : "border-cream/15")} style={{ transitionDelay: i * 80 + "ms" }}>
              <p className={"text-[14px] font-semibold " + (pl.highlight ? "text-ink/70" : "text-cream/60")}>{pl.name} · {pl.count}</p>
              <p className={"mt-3 text-[28px] font-bold " + (pl.highlight ? "text-ink" : "text-cream")}>
                {pl.price}<span className="text-[16px] font-normal">{pl.unit}</span>
              </p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ── 8. 후기 ──────────────────────────────────────────────────────────── */

function Reviews() {
  const r = C.reviews;
  if (!r.list.length) return null;
  return (
    <section className="py-20 bg-ivory">
      <div className="mx-auto max-w-8xl px-5 sm:px-8">
        <SectionHead eyebrow={r.eyebrow} title={r.title} />
        <div className="mt-12 grid sm:grid-cols-2 gap-6 max-w-4xl mx-auto">
          {r.list.map((rv, i) => (
            <div key={i} className="reveal bg-white rounded-sm p-8 text-[16px] leading-[1.85] text-ink/80 break-keep" style={{ transitionDelay: i * 100 + "ms" }}>
              “{rv.text}”
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ── 9-1. IBFA 합격자 조회 ───────────────────────────────────────────────
   국적·레벨·연도·월·이름을 입력하고 "조회" 버튼을 눌러야 결과가 표시된다
   (전체 명단을 그냥 다 보여주지 않음 — 다른 합격자 개인정보 노출 방지).
   목록은 src/content.js 의 ibfa.passList 에 있다 — 새 합격자가 나오면 그
   배열에 { nation, level, year, month, name } 객체를 추가하면 된다.
   ※ 자격번호(certNo)는 원본 자료에 없는 항목이라 넣지 않는다 — 지어낸
   번호를 실제 자격번호처럼 보여주면 안 된다. */

const LOOKUP_FIELD_CLS = "w-full rounded-sm border border-ink/15 bg-white px-4 py-2.5 text-[14px] text-ink placeholder:text-ink/40 outline-none focus:border-gold";

function LookupRow({ label, children }) {
  return (
    <div className="grid grid-cols-[96px_1fr] sm:grid-cols-[140px_1fr] border-t border-ink/10 first:border-t-0">
      <div className="flex items-center bg-ivory px-4 py-3 text-[13.5px] font-semibold text-ink/70">{label}</div>
      <div className="px-4 py-2.5 bg-white">{children}</div>
    </div>
  );
}

function PassLookup({ list }) {
  const [nation, setNation] = useState("전체");
  const [level, setLevel] = useState("전체");
  const [year, setYear] = useState("전체");
  const [month, setMonth] = useState("전체");
  const [name, setName] = useState("");
  const [submitted, setSubmitted] = useState(false);
  const [error, setError] = useState("");

  const uniq = (arr) => Array.from(new Set(arr));
  const nations = ["전체"].concat(uniq(list.map((p) => p.nation)));
  const levels = ["전체"].concat(uniq(list.map((p) => p.level)).sort());
  const years = ["전체"].concat(uniq(list.map((p) => p.year)).sort());
  const months = ["전체"].concat(uniq(list.map((p) => p.month)).sort());

  const onChange = (setter) => (e) => {
    setter(e.target.value);
    setSubmitted(false);
    setError("");
  };

  const search = (e) => {
    e.preventDefault();
    if (!name.trim()) {
      setError("이름을 입력해 주세요.");
      setSubmitted(false);
      return;
    }
    setError("");
    setSubmitted(true);
  };

  const q = name.trim().toLowerCase();
  const results = submitted
    ? list.filter(
        (p) =>
          (nation === "전체" || p.nation === nation) &&
          (level === "전체" || String(p.level) === String(level)) &&
          (year === "전체" || p.year === year) &&
          (month === "전체" || p.month === month) &&
          p.name.toLowerCase().indexOf(q) >= 0
      )
    : [];

  return (
    <div className="reveal mt-20">
      <p className="text-[13px] tracking-[0.2em] text-gold font-bold uppercase">Certificate Holders</p>
      <h3 className="mt-2 text-[24px] sm:text-[28px] font-bold text-ink">합격자 조회</h3>
      <p className="mt-3 text-[15px] leading-[1.8] text-ink/70">국적·레벨·연도·월·이름을 입력하고 조회 버튼을 누르면 해당하는 합격 내역을 확인하실 수 있습니다.</p>

      <form onSubmit={search} className="mt-8 overflow-hidden rounded-sm border border-ink/15">
        <div className="bg-ink px-5 py-3.5 text-center text-[15px] font-bold text-cream tracking-[0.05em]">합격자 조회</div>
        <LookupRow label="국적">
          <select value={nation} onChange={onChange(setNation)} className={LOOKUP_FIELD_CLS}>
            {nations.map((v) => <option key={v} value={v}>{v === "전체" ? "전체" : v}</option>)}
          </select>
        </LookupRow>
        <LookupRow label="레벨">
          <select value={level} onChange={onChange(setLevel)} className={LOOKUP_FIELD_CLS}>
            {levels.map((v) => <option key={v} value={v}>{v === "전체" ? "전체" : "레벨 " + v}</option>)}
          </select>
        </LookupRow>
        <LookupRow label="연도">
          <select value={year} onChange={onChange(setYear)} className={LOOKUP_FIELD_CLS}>
            {years.map((v) => <option key={v} value={v}>{v === "전체" ? "전체" : v + "년"}</option>)}
          </select>
        </LookupRow>
        <LookupRow label="월">
          <select value={month} onChange={onChange(setMonth)} className={LOOKUP_FIELD_CLS}>
            {months.map((v) => <option key={v} value={v}>{v === "전체" ? "전체" : v + "월"}</option>)}
          </select>
        </LookupRow>
        <LookupRow label="이름">
          <input value={name} onChange={onChange(setName)} placeholder="이름을 입력하세요" className={LOOKUP_FIELD_CLS} />
        </LookupRow>
        <div className="border-t border-ink/10 bg-ivory px-5 py-4 text-center">
          <button type="submit" className="rounded-full bg-yellow px-10 py-3 text-[14.5px] font-semibold text-ink hover:brightness-95 transition">
            조회
          </button>
        </div>
      </form>

      {error ? <p className="mt-4 text-center text-[14px] text-red-600">{error}</p> : null}

      {submitted ? (
        results.length ? (
          <div className="mt-6">
            <p className="text-[13px] text-ink/50">총 {results.length}명</p>
            <div className="mt-3 overflow-hidden rounded-sm border border-ink/10">
              <div className="grid grid-cols-[1fr_auto_auto_auto] gap-3 bg-ivory px-5 py-3 text-[12.5px] font-semibold text-ink/60">
                <span>이름</span><span>국적</span><span>레벨</span><span>취득연월</span>
              </div>
              {results.map((p, i) => (
                <div key={i} className="grid grid-cols-[1fr_auto_auto_auto] gap-3 border-t border-ink/8 bg-white px-5 py-3.5 text-[14.5px] text-ink/85">
                  <span className="font-medium text-ink">{p.name}</span>
                  <span className="text-ink/60">{p.nation}</span>
                  <span className="text-ink/60">레벨 {p.level}</span>
                  <span className="text-ink/60">{p.year}.{p.month}</span>
                </div>
              ))}
            </div>
          </div>
        ) : (
          <p className="mt-6 rounded-sm border border-ink/10 bg-white px-5 py-8 text-center text-[14.5px] text-ink/55">조회 결과가 없습니다. 입력하신 정보를 다시 확인해 주세요.</p>
        )
      ) : null}
    </div>
  );
}

/* ── 9. IBFA ──────────────────────────────────────────────────────────── */

function Ibfa() {
  const i = C.ibfa;
  return (
    <section id="ibfa" className="py-20 sm:py-28 bg-cream">
      <div className="mx-auto max-w-8xl px-5 sm:px-8">
        <div className="reveal max-w-2xl">
          <p className="font-thin text-[13px] tracking-[0.28em] uppercase text-gold mb-4">{i.eyebrow}</p>
          <h2 className="text-[30px] sm:text-[38px] font-bold text-ink leading-[1.3]">{i.title}</h2>
          <p className="mt-1 font-serif italic text-[16px] text-ink/50">{i.titleEn}</p>
          <p className="mt-6 text-[16px] leading-[1.9] text-ink/80 break-keep">{i.desc}</p>
          <p className="mt-5 text-[15px] text-ink/60">협회장 — <span className="font-semibold text-ink">{i.president}</span></p>
        </div>

        <div className="reveal mt-16">
          <p className="text-[13px] tracking-[0.2em] text-gold font-bold uppercase">Partner Studios</p>
          <h3 className="mt-2 text-[24px] sm:text-[28px] font-bold text-ink">협력 스튜디오</h3>
          <div className="mt-10 flex flex-wrap items-center justify-center gap-x-12 gap-y-10 sm:gap-x-16">
            {i.partners.filter((p) => p.logo).map((p, idx) => (
              <img
                key={idx}
                src={p.logo}
                alt={p.name}
                title={p.name}
                loading={LAZY}
                className="h-12 sm:h-14 w-auto object-contain opacity-85 hover:opacity-100 transition-opacity duration-300"
              />
            ))}
          </div>
        </div>

        {i.passList && i.passList.length ? <PassLookup list={i.passList} /> : null}
      </div>
    </section>
  );
}

/* ── 10. FAQ ──────────────────────────────────────────────────────────── */

function Faq() {
  const f = C.faq;
  const [openIdx, setOpenIdx] = useState(0);
  return (
    <section id="faq" className="py-20 sm:py-28 bg-ivory">
      <div className="mx-auto max-w-3xl px-5 sm:px-8">
        <SectionHead eyebrow={f.eyebrow} title={f.title} />
        <div className="mt-12 space-y-3">
          {f.items.map((it, i) => {
            const isOpen = openIdx === i;
            return (
              <div key={i} className="reveal bg-white rounded-sm border border-ink/5" style={{ transitionDelay: i * 60 + "ms" }}>
                <button onClick={() => setOpenIdx(isOpen ? -1 : i)} className="w-full flex items-center justify-between gap-4 px-6 py-5 text-left">
                  <span className="text-[16px] font-semibold text-ink">{it.q}</span>
                  <span className={"text-[20px] text-gold transition-transform " + (isOpen ? "rotate-45" : "")}>+</span>
                </button>
                {isOpen ? <p className="px-6 pb-5 text-[15px] leading-[1.8] text-ink/70">{it.a}</p> : null}
              </div>
            );
          })}
        </div>
      </div>
    </section>
  );
}

/* ── 11. 예약 문의 ────────────────────────────────────────────────────── */

function Booking() {
  const b = C.booking;
  const [form, setForm] = useState({ name: "", phone: "", branch: C.branches[0].menuLabel, msg: "" });
  const set = (k) => (e) => setForm((f) => ({ ...f, [k]: e.target.value }));

  const submit = (e) => {
    e.preventDefault();
    const subject = encodeURIComponent("[노바바레] 무료 체험 예약 문의 — " + form.name);
    const body = encodeURIComponent(
      "이름: " + form.name + "\n연락처: " + form.phone + "\n희망 지점: " + form.branch + "\n문의 내용: " + form.msg
    );
    window.location.href = "mailto:" + b.submitTo + "?subject=" + subject + "&body=" + body;
  };

  return (
    <section id="booking" className="relative py-20 sm:py-28 bg-ink overflow-hidden">
      <div className="orb drift2 bg-yellow/25" style={{ width: 420, height: 420, top: "-14%", right: "-8%" }} />
      <div className="orb drift bg-gold/25" style={{ width: 320, height: 320, bottom: "-18%", left: "2%" }} />
      <div className="orb drift3 bg-yellow/15" style={{ width: 240, height: 240, top: "38%", left: "30%" }} />
      <div className="relative z-10 mx-auto max-w-3xl px-5 sm:px-8">
        <SectionHead eyebrow={b.eyebrow} title={b.title} desc={b.desc} light />
        <form onSubmit={submit} className="mt-12 reveal grid sm:grid-cols-2 gap-4">
          <input required value={form.name} onChange={set("name")} placeholder="이름" className="rounded-sm bg-cream/5 border border-cream/20 px-5 py-4 text-cream placeholder:text-cream/40 outline-none focus:border-yellow" />
          <input required value={form.phone} onChange={set("phone")} placeholder="연락처" className="rounded-sm bg-cream/5 border border-cream/20 px-5 py-4 text-cream placeholder:text-cream/40 outline-none focus:border-yellow" />
          <select value={form.branch} onChange={set("branch")} className="rounded-sm bg-cream/5 border border-cream/20 px-5 py-4 text-cream outline-none focus:border-yellow sm:col-span-2">
            {C.branches.map((br) => <option key={br.id} value={br.menuLabel} className="text-ink">{br.menuLabel}</option>)}
          </select>
          <textarea value={form.msg} onChange={set("msg")} placeholder="문의 내용 (선택)" rows={4} className="rounded-sm bg-cream/5 border border-cream/20 px-5 py-4 text-cream placeholder:text-cream/40 outline-none focus:border-yellow sm:col-span-2" />
          <button type="submit" className="sm:col-span-2 rounded-full bg-yellow px-8 py-4 text-[16px] font-semibold text-ink hover:brightness-95 transition">
            문의 보내기
          </button>
        </form>
        <p className="mt-5 text-center text-[14px] text-cream/50">전화 상담을 원하시면 문자 {b.smsContact} 로 남겨주세요.</p>
      </div>
    </section>
  );
}

/* ── 12. 푸터 ─────────────────────────────────────────────────────────── */

function Footer() {
  const f = C.footer;
  return (
    <footer className="bg-ink2 py-10">
      <div className="mx-auto max-w-8xl px-5 sm:px-8 flex flex-col sm:flex-row items-center justify-between gap-4 text-[13px] text-cream/45">
        <p>{f.company} · 대표 {f.ceo}</p>
        <p>{f.copyright}</p>
      </div>
    </footer>
  );
}

/* ── 13. 칼럼(저널) ───────────────────────────────────────────────────────
   데이터는 src/columns.js 에 있다. 칼럼봇(~/automation/nova-barre-column)이 매일 갱신한다.
   ────────────────────────────────────────────────────────────────────────── */

const J = window.COLUMNS || { meta: {}, categories: [], photoPools: {}, posts: [] };

// "2026.09.14" → 오늘 날짜와 비교할 수 있는 숫자
function dateNum(str) {
  const m = String(str || "").match(/(\d{4})\D(\d{1,2})\D(\d{1,2})/);
  if (!m) return 0;
  return Number(m[1]) * 10000 + Number(m[2]) * 100 + Number(m[3]);
}
function todayNum() {
  const d = new Date();
  return d.getFullYear() * 10000 + (d.getMonth() + 1) * 100 + d.getDate();
}

// 화면에 내보낼 글: 초안 제외, 발행일이 오늘 이후인 글 제외(예약 발행), 최신순
function publishedPosts() {
  const t = todayNum();
  return (J.posts || [])
    .filter((p) => !p.draft && dateNum(p.date) <= t)
    .sort((a, b) => dateNum(b.date) - dateNum(a.date));
}

function findPost(id) {
  return (J.posts || []).find((p) => p.id === id);
}

// image 가 "auto" 면 카테고리 사진 중에서 고른다. id 를 기준으로 고르므로 항상 같은 사진이 나온다.
function postImage(p) {
  if (p.image && p.image !== "auto") return p.image;
  const pool = (J.photoPools || {})[p.cat] || (J.photoPools || {})._default || [];
  if (!pool.length) return "img/hero-cert.jpg";
  let h = 0;
  for (let i = 0; i < String(p.id).length; i++) h = (h * 31 + String(p.id).charCodeAt(i)) >>> 0;
  return pool[h % pool.length];
}

/* 본문 중간에 자동으로 들어가는 사진.
   카테고리 사진 묶음이 세 장씩이라, 대표 사진 1장 + 본문 2장 = 한 편에 3장이 된다. */
function bodyPhotos(p, count = 2) {
  const pool = (J.photoPools || {})[p.cat] || (J.photoPools || {})._default || [];
  const hero = postImage(p);
  const rest = pool.filter((src) => src !== hero);
  const out = [];
  for (let i = 0; i < count && rest.length; i++) out.push(rest[i % rest.length]);
  return out;
}

/* 사진 자리 고르기 — 소제목 바로 앞에 넣는다. 소제목이 모자라면 그냥 그 자리 문단 사이에 넣는다. */
function photoSlots(body, count) {
  const n = body.length;
  const heads = [];
  body.forEach((b, i) => {
    if (i > 0 && b && typeof b === "object" && b.h2) heads.push(i);
  });
  const slots = [];
  for (let k = 1; k <= count; k++) {
    const target = Math.round((n * k) / (count + 1));
    let at = heads.find((h) => h >= target && slots.indexOf(h) < 0);
    if (at === undefined) at = heads.filter((h) => slots.indexOf(h) < 0).pop();
    if (at === undefined) at = slots.indexOf(target) < 0 ? target : target + 1;
    if (at > 0 && at < n) slots.push(at);
  }
  return slots;
}

function BodyPhoto({ src }) {
  return (
    <figure className="mt-14 mb-2 -mx-5 sm:mx-0">
      <img src={src} alt="노바바레 내부" loading={LAZY} className="w-full h-[240px] sm:h-[420px] object-cover sm:rounded-sm" />
    </figure>
  );
}

/* noPhoto: 사진 없이 글자만 — 「함께 읽으면 좋은 글」 자리에서 쓴다(사진이 너무 많아 보이지 않게). */
function ColumnCard({ p, wide = false, noPhoto = false }) {
  return (
    <a
      href={"#/column/" + p.id}
      className="reveal group block overflow-hidden rounded-sm bg-white border border-ink/10 transition-transform duration-500 hover:-translate-y-1"
    >
      {noPhoto ? null : (
        <div className={"overflow-hidden " + (wide ? "h-[260px]" : "h-[200px]")}>
          <img src={postImage(p)} alt={p.title} loading={LAZY} className="h-full w-full object-cover transition-transform duration-[1200ms] group-hover:scale-[1.06]" />
        </div>
      )}
      <div className="p-7">
        <p className="font-thin text-[11.5px] tracking-[0.2em] uppercase text-gold">{p.cat}</p>
        <h3 className="mt-3 text-[19px] sm:text-[20px] font-bold text-ink leading-snug">{p.title}</h3>
        <p className="mt-3 text-[14.5px] leading-[1.8] text-ink/70">{p.excerpt}</p>
        <p className="mt-5 text-[13px] text-ink/45">{p.date}</p>
      </div>
    </a>
  );
}

/* 홈에 붙는 최신 3개 미리보기 — 글이 없으면 통째로 숨긴다 */
function JournalPreview() {
  const list = publishedPosts().slice(0, 3);
  if (!list.length) return null;
  return (
    <section className="py-20 sm:py-28 bg-ivory">
      <div className="mx-auto max-w-8xl px-5 sm:px-8">
        <SectionHead eyebrow={J.meta.eyebrow} title={J.meta.title} desc={J.meta.subtitle} />
        <div className="mt-12 grid sm:grid-cols-3 gap-6">
          {list.map((p) => <ColumnCard key={p.id} p={p} />)}
        </div>
        <div className="mt-10 text-center">
          <a href="#/column" className="inline-block rounded-full border border-ink/25 px-8 py-4 text-[15px] text-ink/85 hover:border-gold hover:text-gold transition-colors">
            저널 전체 보기 →
          </a>
        </div>
      </div>
    </section>
  );
}

/* 목록 페이지 */
function ColumnList() {
  const [cat, setCat] = useState("전체");
  const all = publishedPosts();
  const cats = ["전체"].concat((J.categories || []).filter((c) => all.some((p) => p.cat === c)));
  const list = cat === "전체" ? all : all.filter((p) => p.cat === cat);

  return (
    <main className="bg-cream pt-32 sm:pt-40 pb-24 sm:pb-32 min-h-[70svh]">
      <div className="mx-auto max-w-8xl px-5 sm:px-8">
        <SectionHead eyebrow={J.meta.eyebrow} title={J.meta.title} desc={J.meta.subtitle} />

        {all.length === 0 ? (
          <p className="mt-16 text-center text-[16px] leading-[1.9] text-ink/60">
            아직 발행된 글이 없습니다.
            <br />첫 글이 올라오면 이곳에 표시됩니다.
          </p>
        ) : (
          <React.Fragment>
            {cats.length > 2 ? (
              <div className="mt-12 flex flex-wrap justify-center gap-2.5">
                {cats.map((c) => (
                  <button
                    key={c}
                    onClick={() => setCat(c)}
                    className={"rounded-full px-5 py-2.5 text-[14px] transition-colors " + (c === cat ? "bg-ink text-yellow" : "border border-ink/20 text-ink/70 hover:border-gold hover:text-gold")}
                  >
                    {c}
                  </button>
                ))}
              </div>
            ) : null}

            <div className="mt-12 sm:mt-16 grid sm:grid-cols-2 lg:grid-cols-3 gap-6">
              {list.map((p) => <ColumnCard key={p.id} p={p} />)}
            </div>
          </React.Fragment>
        )}
      </div>
    </main>
  );
}

/* 글 한 편 */
function ColumnPost({ id }) {
  const p = findPost(id);

  if (!p || p.draft) {
    return (
      <main className="bg-cream pt-36 sm:pt-44 pb-32 min-h-[70svh]">
        <div className="mx-auto max-w-2xl px-5 text-center">
          <h1 className="text-[32px] font-bold text-ink">글을 찾을 수 없습니다</h1>
          <p className="mt-5 text-[15px] text-ink/65">주소가 바뀌었거나 아직 공개되지 않은 글입니다.</p>
          <a href="#/column" className="mt-9 inline-block rounded-full bg-ink px-7 py-3.5 text-[15px] text-yellow hover:brightness-110 transition-colors">
            저널 목록으로
          </a>
        </div>
      </main>
    );
  }

  const related = (p.related || []).map(findPost).filter((x) => x && !x.draft);
  const photos = bodyPhotos(p);
  const slots = photoSlots(p.body || [], photos.length);

  return (
    <main className="bg-cream pb-24 sm:pb-32 pt-[68px] sm:pt-[76px]">
      <div className="relative h-[46svh] min-h-[300px] overflow-hidden">
        <img src={postImage(p)} alt={p.title} className="h-full w-full object-cover" />
        <div className="absolute inset-0" style={{ background: "linear-gradient(to top, rgba(15,15,15,.92) 0%, rgba(15,15,15,.55) 40%, rgba(15,15,15,.22) 100%)" }} />
        <div className="absolute inset-x-0 bottom-0">
          <div className="mx-auto max-w-3xl px-5 sm:px-8 pb-10 sm:pb-14">
            <p className="font-thin text-[11.5px] tracking-[0.24em] uppercase text-yellow">{p.cat}</p>
            <h1 className="mt-4 text-[27px] sm:text-[38px] font-bold text-cream leading-[1.3] break-keep">{p.title}</h1>
            <p className="mt-4 text-[13.5px] text-cream/70">{p.date}{p.updated ? " · " + p.updated + " 수정" : ""}</p>
          </div>
        </div>
      </div>

      <article className="mx-auto max-w-3xl px-5 sm:px-8">
        <p className="mt-12 text-[17px] sm:text-[18.5px] leading-[1.9] text-ink/85 break-keep">{p.excerpt}</p>
        <div className="mt-8 h-px w-14 bg-gold/60" />

        <div className="mt-10">
          {(p.body || []).map((b, i) => {
            const slot = slots.indexOf(i);
            return (
              <React.Fragment key={i}>
                {slot >= 0 && photos[slot] ? <BodyPhoto src={photos[slot]} /> : null}
                {typeof b === "string" ? (
                  <p className="mt-6 text-[16px] sm:text-[17px] leading-[2.0] text-ink/80 break-keep">{b}</p>
                ) : (
                  <h2 className="mt-14 mb-1 text-[21px] sm:text-[24px] font-bold text-ink leading-snug break-keep">{b.h2}</h2>
                )}
              </React.Fragment>
            );
          })}
        </div>

        <div className="mt-20 rounded-sm bg-ink px-8 py-10 sm:px-12 sm:py-12 text-center">
          <p className="font-thin text-[11px] tracking-[0.2em] uppercase text-cream/60">NOVA BARRE</p>
          <p className="mt-5 text-[19px] sm:text-[22px] leading-[1.6] text-cream break-keep">
            바레가 처음이라도 괜찮습니다.
            <br />무료 체험으로 먼저 만나보세요.
          </p>
          <a href="#booking" onClick={() => { window.location.hash = ""; setTimeout(() => scrollTo("booking"), 80); }} className="mt-8 inline-block rounded-full bg-yellow px-8 py-4 text-[15px] font-semibold text-ink hover:brightness-95 transition-colors">
            무료 체험 예약하기
          </a>
        </div>

        {related.length ? (
          <div className="mt-20">
            <p className="font-thin text-[11.5px] tracking-[0.2em] uppercase text-gold">RELATED</p>
            <h2 className="mt-3 text-[22px] font-bold text-ink">함께 읽으면 좋은 글</h2>
            <div className="mt-7 grid sm:grid-cols-2 gap-5">
              {related.map((r) => <ColumnCard key={r.id} p={r} noPhoto />)}
            </div>
          </div>
        ) : null}

        <div className="mt-16 text-center">
          <a href="#/column" className="inline-block rounded-full border border-ink/25 px-8 py-4 text-[15px] text-ink/85 hover:border-gold hover:text-gold transition-colors">
            ← 저널 목록으로
          </a>
        </div>
      </article>
    </main>
  );
}

/* ── 화면 전환 ─────────────────────────────────────────────────────────────
   주소의 # 뒤만 보고 화면을 고른다. 서버 설정이 필요 없어 정적 호스팅에서 그대로 돈다.
     (없음)              홈
     #/column            저널 목록
     #/column/<글id>     글 한 편
   ────────────────────────────────────────────────────────────────────────── */

function parseHash() {
  const h = (window.location.hash || "").replace(/^#\/?/, "");
  if (h === "column") return { name: "list" };
  if (h.indexOf("column/") === 0) return { name: "post", id: h.slice("column/".length) };
  return { name: "home" };
}

/* ── App ──────────────────────────────────────────────────────────────── */

function App() {
  const [route, setRoute] = useState(parseHash());
  useReveal();

  useEffect(() => {
    const onHash = () => {
      setRoute(parseHash());
      window.scrollTo({ top: 0, behavior: "auto" });
    };
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);

  if (route.name === "list") {
    return (
      <React.Fragment>
        <Header alwaysSolid />
        <ColumnList />
        <Footer />
      </React.Fragment>
    );
  }

  if (route.name === "post") {
    return (
      <React.Fragment>
        <Header alwaysSolid />
        <ColumnPost id={route.id} />
        <Footer />
      </React.Fragment>
    );
  }

  return (
    <React.Fragment>
      <main>
        <Hero />
        <Founder />
        <TrustPoints />
        <Gallery />
        <Programs />
        <Branches />
        <Trainers />
        <Pricing />
        <Reviews />
        <Ibfa />
        <Faq />
        <JournalPreview />
        <Booking />
      </main>
      <Footer />
    </React.Fragment>
  );
}

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