/* FindMyFrag — Browse surfaces.
   /family/:slug, /note/:slug, /perfumer/:slug
   Fragrantica's IA, our voice: Fraunces + mono + paper + oxblood. */

/* global React, FMF, Bottle, DataStat */
const { useMemo: useMemoB } = React;

function Browse({ kind, axis, slug, q }) {
  const query = (q || "").trim();
  if (kind === "family")   return <FamilyPage slug={slug} />;
  if (kind === "note")     return <NotePage slug={slug} />;
  if (kind === "perfumer") return <PerfumerPage slug={slug} />;
  if (kind === "axis")     return <AxisPage axis={axis} />;
  if (kind === "tag")      return <TagPage axis={axis} slug={slug} />;
  if (query) return <SearchResults q={query} />;
  return <BrowseHub />;
}

/* ────── Search results (text query over catalog) ────── */
function SearchResults({ q }) {
  const needle = q.toLowerCase();
  const hits = useMemoB(() => {
    return (FMF.CATALOG_ALL || FMF.CATALOG).filter(f => {
      const hay = [
        f.brand, f.name, f.family, (f.perfumers || []).join(" "),
        ...f.notes.top, ...f.notes.heart, ...f.notes.base,
      ].join(" ").toLowerCase();
      return hay.includes(needle);
    });
  }, [needle]);

  const [sort, setSort] = React.useState("score");
  const sorted = useMemoB(() => {
    const c = hits.slice();
    if (sort === "score") c.sort((a, b) => b.community.score - a.community.score);
    else if (sort === "landed-asc") c.sort((a, b) => a.landed - b.landed);
    else if (sort === "landed-desc") c.sort((a, b) => b.landed - a.landed);
    else if (sort === "year") c.sort((a, b) => b.year - a.year);
    return c;
  }, [hits, sort]);

  return (
    <main>
      <BrowseMast
        kicker={`Search · ${hits.length} ${hits.length === 1 ? "match" : "matches"}`}
        title={<>Results for <span className="fraun-itl">"{q}"</span></>}
        lead={hits.length ? "Every catalog entry that mentions your query in brand, house, family, perfumer, or notes. Sorted the same ways as family pages." : "Nothing in the catalog matches that. Try a note (oud, bergamot, iris), a house (Chanel, Creed), or a perfumer surname."}
        stat={hits.length ? `${hits.length} of ${(FMF.CATALOG_ALL || FMF.CATALOG).length} in catalog` : `0 of ${(FMF.CATALOG_ALL || FMF.CATALOG).length} in catalog`}
      />
      {hits.length > 0 && (
        <section className="container" style={{ padding: "32px 32px 64px" }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 18, flexWrap: "wrap", gap: 16 }}>
            <div className="kicker">Matches</div>
            <div style={{ display: "flex", gap: 16, alignItems: "baseline", flexWrap: "wrap" }}>
              <span className="mono body-xs" style={{ color: "var(--ink-mute)", letterSpacing: "0.06em", textTransform: "uppercase" }}>Sort</span>
              <SortPills value={sort} onChange={setSort} options={[
                { v: "score", l: "Community" },
                { v: "landed-asc", l: "Landed ↑" },
                { v: "landed-desc", l: "Landed ↓" },
                { v: "year", l: "Year" },
              ]} />
            </div>
          </div>
          <div style={{ borderTop: "1px solid var(--ink)", borderBottom: "1px solid var(--ink)" }}>
            {sorted.map((f, i) => <FragranceRow key={f.slug} f={f} i={i} />)}
          </div>
        </section>
      )}
      {hits.length === 0 && (
        <section className="container" style={{ padding: "40px 32px 80px" }}>
          <a href="#/browse" className="mono body-s" style={{ borderBottom: "1px solid var(--ink)", paddingBottom: 2 }}>← Back to the catalog</a>
        </section>
      )}
    </main>
  );
}

/* ────── Masthead used by browse pages ────── */
function BrowseMast({ kicker, title, lead, stat }) {
  return (
    <>
      <section className="container" style={{ paddingTop: 28, paddingBottom: 14 }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
          <div className="kicker">{kicker}</div>
          <div className="mono body-xs" style={{ color: "var(--ink-mute)" }}>{stat}</div>
        </div>
      </section>
      <hr className="hairline-k" />
      <section className="container" style={{ padding: "56px 32px 40px" }}>
        <div className="stack-mobile" style={{ display: "grid", gridTemplateColumns: "1.1fr 0.9fr", gap: 72, alignItems: "end" }}>
          <h1 className="display-xl" style={{ margin: 0, maxWidth: "14ch" }}>
            {title}
          </h1>
          <p className="fraun" style={{ fontSize: 22, lineHeight: 1.4, letterSpacing: "-0.01em", color: "var(--ink-soft)", margin: 0, maxWidth: "40ch" }}>
            {lead}
          </p>
        </div>
      </section>
      <hr className="hairline" />
    </>
  );
}

/* ────── Fragrance row (shared across browse pages) ────── */
function FragranceRow({ f, i }) {
  return (
    <a href={`#/fragrance/${f.slug}`}
       className="ledger-row"
       style={{
         display: "grid",
         gridTemplateColumns: "44px 58px 2.2fr 1fr 1fr 1fr 80px",
         alignItems: "center",
         gap: 20,
         padding: "16px 0",
         borderTop: i === 0 ? 0 : "1px solid var(--rule)",
         textDecoration: "none",
         color: "inherit",
       }}
       onMouseEnter={e => e.currentTarget.style.background = "var(--paper-deep)"}
       onMouseLeave={e => e.currentTarget.style.background = "transparent"}
    >
      <div className="mono body-xs" style={{ color: "var(--ink-mute)" }}>{String(i + 1).padStart(2, "0")}</div>
      <Bottle slug={f.slug} label={f.name} style={{ width: 58, height: 74, background: "var(--paper-deep)" }} />
      <div>
        <div className="fraun" style={{ fontSize: 22, letterSpacing: "-0.012em", lineHeight: 1.15 }}>
          {f.brand} <span style={{ color: "var(--ink-soft)" }}>·</span> <span className="fraun-itl">{f.name}</span>
        </div>
        <div className="mono body-xs" style={{ color: "var(--ink-mute)", marginTop: 3 }}>
          {f.size} · {f.year} · {f.family}
        </div>
      </div>
      <div className="mono body-s" style={{ color: "var(--ink-soft)" }}>
        <DataStat value={f.community.score} n={f.community.n} sigma={f.community.sigma} />
      </div>
      <div className="mono" style={{ fontSize: 18, letterSpacing: "-0.01em" }}>
        {FMF.fmtUsd(f.landed)}
        <div className="body-xs" style={{ color: "var(--ink-mute)", marginTop: 2 }}>landed</div>
      </div>
      <div className="mono body-s strike" style={{ color: "var(--ink-mute)" }}>
        {FMF.fmtUsdNoCents(f.msrp)}
        <div className="body-xs" style={{ color: "var(--ink-mute)", marginTop: 2, textDecoration: "none" }}>msrp</div>
      </div>
      <div style={{ textAlign: "right" }}>
        <span className={`signal signal-${f.signal}`}>{f.signal}</span>
      </div>
    </a>
  );
}

/* ══════════════════════════════════════════════════════════════════════
   FAMILY PAGE
   ══════════════════════════════════════════════════════════════════════ */
function FamilyPage({ slug }) {
  const fam = FMF.FAMILY_BY_SLUG[slug];
  const items = useMemoB(() => FMF.byFamilySlug(slug), [slug]);
  const [sort, setSort] = React.useState("score"); // score | landed-asc | landed-desc | year
  if (!fam) return <FamilyIndex />;

  const sorted = useMemoB(() => {
    const copy = items.slice();
    if (sort === "score") copy.sort((a, b) => b.community.score - a.community.score);
    else if (sort === "landed-asc") copy.sort((a, b) => a.landed - b.landed);
    else if (sort === "landed-desc") copy.sort((a, b) => b.landed - a.landed);
    else if (sort === "year") copy.sort((a, b) => b.year - a.year);
    return copy;
  }, [items, sort]);

  // Aggregate note frequency within this family
  const noteFreq = useMemoB(() => {
    const m = new Map();
    for (const f of items) {
      for (const n of [...f.notes.top, ...f.notes.heart, ...f.notes.base]) {
        m.set(n, (m.get(n) || 0) + 1);
      }
    }
    return [...m.entries()].sort((a, b) => b[1] - a[1]).slice(0, 14);
  }, [items]);

  const avgScore = items.length
    ? (items.reduce((a, f) => a + f.community.score, 0) / items.length).toFixed(2)
    : "—";
  const avgLanded = items.length
    ? items.reduce((a, f) => a + f.landed, 0) / items.length
    : 0;

  return (
    <main>
      <BrowseMast
        kicker={`Family · ${items.length} in catalog`}
        title={<>{fam.label.split(" — ")[0]} <span className="fraun-itl">— {fam.label.split(" — ")[1]}</span></>}
        lead={fam.blurb}
        stat={`mean community ${avgScore} · mean landed ${FMF.fmtUsd(avgLanded)}`}
      />

      {/* Defining notes strip */}
      <section className="container" style={{ padding: "40px 32px 48px" }}>
        <div className="kicker" style={{ marginBottom: 18 }}>Defining notes · frequency</div>
        <div style={{ display: "flex", flexWrap: "wrap", gap: "10px 24px" }}>
          {noteFreq.map(([name, freq]) => (
            <a key={name} href={`#/note/${FMF.slugify(name)}`}
               className="mono body-s"
               style={{ color: "var(--ink-soft)", borderBottom: "1px solid var(--rule)", paddingBottom: 4 }}>
              {name.toLowerCase()} <span style={{ color: "var(--ink-mute)" }}>·{freq}</span>
            </a>
          ))}
        </div>
      </section>

      <hr className="hairline" />

      {/* Fragrance list */}
      <section className="container" style={{ padding: "32px 32px 64px" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 18, flexWrap: "wrap", gap: 16 }}>
          <div className="kicker">In this family</div>
          <div style={{ display: "flex", gap: 16, alignItems: "baseline", flexWrap: "wrap" }}>
            <span className="mono body-xs" style={{ color: "var(--ink-mute)", letterSpacing: "0.06em", textTransform: "uppercase" }}>Sort</span>
            <SortPills value={sort} onChange={setSort} options={[
              { v: "score", l: "Community" },
              { v: "landed-asc", l: "Landed ↑" },
              { v: "landed-desc", l: "Landed ↓" },
              { v: "year", l: "Year" },
            ]} />
          </div>
        </div>
        <div style={{ borderTop: "1px solid var(--ink)", borderBottom: "1px solid var(--ink)" }}>
          {sorted.map((f, i) => <FragranceRow key={f.slug} f={f} i={i} />)}
        </div>
      </section>
    </main>
  );
}

/* ────── Sort pill control ────── */
function SortPills({ value, onChange, options }) {
  return (
    <div style={{ display: "inline-flex", border: "1px solid var(--ink)" }}>
      {options.map((o, i) => (
        <button key={o.v} onClick={() => onChange(o.v)}
          style={{
            background: value === o.v ? "var(--ink)" : "var(--paper)",
            color: value === o.v ? "var(--paper)" : "var(--ink)",
            border: 0,
            borderLeft: i === 0 ? 0 : "1px solid var(--ink)",
            padding: "6px 12px",
            font: "inherit",
            fontFamily: "var(--font-mono)",
            fontSize: 11,
            letterSpacing: "0.06em",
            textTransform: "uppercase",
            cursor: "pointer",
          }}>
          {o.l}
        </button>
      ))}
    </div>
  );
}

/* ══════════════════════════════════════════════════════════════════════
   NOTE PAGE
   ══════════════════════════════════════════════════════════════════════ */
function NotePage({ slug }) {
  const entry = FMF.NOTE_INDEX[slug];
  if (!entry) return <NoteIndex />;

  // Which tier (top/heart/base) does this note appear in, across items?
  const tiers = useMemoB(() => {
    const t = { top: 0, heart: 0, base: 0 };
    for (const f of entry.items) {
      if (f.notes.top.includes(entry.label))   t.top++;
      if (f.notes.heart.includes(entry.label)) t.heart++;
      if (f.notes.base.includes(entry.label))  t.base++;
    }
    return t;
  }, [entry]);
  const totalTier = tiers.top + tiers.heart + tiers.base || 1;

  return (
    <main>
      <BrowseMast
        kicker={`Note · appears in ${entry.items.length}`}
        title={<span className="fraun-itl">{entry.label.toLowerCase()}.</span>}
        lead={`A single raw material, traced across every fragrance in the catalog where it appears. Where it sits — top, heart, base — is what changes.`}
        stat={`top ${tiers.top} · heart ${tiers.heart} · base ${tiers.base}`}
      />

      {/* Tier distribution */}
      <section className="container" style={{ padding: "40px 32px 36px" }}>
        <div className="kicker" style={{ marginBottom: 14 }}>Where it sits</div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 18 }}>
          {["top", "heart", "base"].map(k => (
            <div key={k} style={{ borderTop: "1px solid var(--ink)", paddingTop: 12 }}>
              <div className="mono body-xs" style={{ color: "var(--ink-mute)", letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 8 }}>{k}</div>
              <div className="mono" style={{ fontSize: 28, letterSpacing: "-0.015em" }}>
                {tiers[k]} <span className="body-xs" style={{ color: "var(--ink-mute)" }}>/ {totalTier}</span>
              </div>
              <div style={{ height: 6, background: "var(--paper-deep)", border: "1px solid var(--rule)", marginTop: 10, position: "relative" }}>
                <div style={{ position: "absolute", inset: 0, width: `${(tiers[k] / totalTier) * 100}%`, background: "var(--ink)" }} />
              </div>
            </div>
          ))}
        </div>
      </section>

      <hr className="hairline" />

      <section className="container" style={{ padding: "32px 32px 64px" }}>
        <div className="kicker" style={{ marginBottom: 18 }}>Fragrances where it appears</div>
        <div style={{ borderTop: "1px solid var(--ink)", borderBottom: "1px solid var(--ink)" }}>
          {entry.items.map((f, i) => <FragranceRow key={f.slug} f={f} i={i} />)}
        </div>
      </section>
    </main>
  );
}

function NoteIndex() {
  const all = Object.values(FMF.NOTE_INDEX).sort((a, b) => b.items.length - a.items.length);
  return (
    <main>
      <BrowseMast
        kicker="Notes · index"
        title="Every note, traced."
        lead="Raw materials cross-referenced against every fragrance in the catalog. Click a note to see where it sits and what it appears in."
        stat={`${all.length} notes · ${(FMF.CATALOG_ALL || FMF.CATALOG).length} fragrances`}
      />
      <section className="container" style={{ padding: "40px 32px 80px" }}>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: "10px 40px" }}>
          {all.map(n => (
            <a key={n.slug} href={`#/note/${n.slug}`}
               style={{ display: "flex", justifyContent: "space-between", padding: "10px 0", borderTop: "1px solid var(--rule)", textDecoration: "none", color: "inherit" }}>
              <span className="fraun body-l">{n.label}</span>
              <span className="mono body-xs" style={{ color: "var(--ink-mute)", alignSelf: "center" }}>{n.items.length}</span>
            </a>
          ))}
        </div>
      </section>
    </main>
  );
}

/* ══════════════════════════════════════════════════════════════════════
   PERFUMER PAGE
   ══════════════════════════════════════════════════════════════════════ */
function PerfumerPage({ slug }) {
  const entry = FMF.PERFUMER_INDEX[slug];
  if (!entry) return null;
  const avgScore = entry.items.length
    ? (entry.items.reduce((a, f) => a + f.community.score, 0) / entry.items.length).toFixed(2)
    : "—";
  return (
    <main>
      <BrowseMast
        kicker={`Perfumer · ${entry.items.length} in catalog`}
        title={<span className="fraun-itl">{entry.label}.</span>}
        lead={`Compositions attributed to ${entry.label} and held in the FindMyFrag reference. Catalog grows as the database grows.`}
        stat={`mean community ${avgScore} · across ${entry.items.length} works`}
      />
      <section className="container" style={{ padding: "40px 32px 64px" }}>
        <div style={{ borderTop: "1px solid var(--ink)", borderBottom: "1px solid var(--ink)" }}>
          {entry.items
            .slice()
            .sort((a, b) => b.community.score - a.community.score)
            .map((f, i) => <FragranceRow key={f.slug} f={f} i={i} />)}
        </div>
      </section>
    </main>
  );
}

/* ══════════════════════════════════════════════════════════════════════
   BROWSE HUB — intent-first navigation. Occasion, season, vibe, status.
   Family demoted to a "for perfumers" strip at the bottom. Readers think
   in intents ("office", "winter", "bold"), not industry taxonomies.
   ══════════════════════════════════════════════════════════════════════ */
function BrowseHub() {
  return (
    <main>
      <BrowseMast
        kicker="Catalog"
        title={<>Find a fragrance that <span className="fraun-itl">fits.</span></>}
        lead="Five ways in. Pick what matters — the occasion, the season, the community leaderboards, the vibe, or the market position — and drill from there."
        stat={`${(FMF.CATALOG_ALL || FMF.CATALOG).length} fragrances · ${FMF.BROWSE_AXES.length} ways in`}
      />

      {/* Quick catalog — pre-curated shelves above the structured tiles. Shows
          the answers most readers scroll for ("what are the best men's right
          now?") without forcing them through the axis → tag → list drill. */}
      <QuickCatalog />

      <hr className="hairline" />

      {/* Five big tiles — the structured drill-down for readers who know what
          axis they want. */}
      <section className="container" style={{ padding: "40px 32px 64px" }}>
        <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 20, flexWrap: "wrap", gap: 12 }}>
          <h3 className="kicker" style={{ margin: 0 }}>Structured drill-down · {FMF.BROWSE_AXES.length} axes</h3>
          <span className="mono body-xs" style={{ color: "var(--ink-mute)" }}>pick an axis · narrow by tag · land on a list</span>
        </div>
        <div className="browse-tiles">
          {FMF.BROWSE_AXES.map(axis => (
            <a key={axis.id} href={`#/browse/${axis.id}`} className="browse-tile">
              <div className="browse-tile__count">{axis.tags.length} ways</div>
              <div className="browse-tile__title">{axis.label}</div>
              <p className="browse-tile__blurb">{axis.groupBlurb}</p>
              <span className="browse-tile__cta">Open →</span>
            </a>
          ))}
        </div>
      </section>

      <hr className="hairline" />

      {/* Reference axes — small demoted strip. One line, not a grid. */}
      <section className="container" style={{ padding: "28px 32px 48px" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", flexWrap: "wrap", gap: 16 }}>
          <span className="kicker">Looking for a specific family, note, or perfumer?</span>
          <div style={{ display: "flex", gap: 24, flexWrap: "wrap" }}>
            <a href="#/family/chypre-fruity" className="mono body-s" style={{ color: "var(--ink)", borderBottom: "1px solid var(--ink)", paddingBottom: 2 }}>Families ({FMF.FAMILIES.length}) →</a>
            <a href={`#/note/oud`} className="mono body-s" style={{ color: "var(--ink)", borderBottom: "1px solid var(--ink)", paddingBottom: 2 }}>Notes ({Object.keys(FMF.NOTE_INDEX).length}) →</a>
            <a href={`#/perfumer/${Object.keys(FMF.PERFUMER_INDEX)[0]}`} className="mono body-s" style={{ color: "var(--ink)", borderBottom: "1px solid var(--ink)", paddingBottom: 2 }}>Perfumers ({Object.keys(FMF.PERFUMER_INDEX).length}) →</a>
          </div>
        </div>
      </section>
    </main>
  );
}

/* ══════════════════════════════════════════════════════════════════════
   AXIS PAGE — /browse/:axis (middle layer of the 3-level flow)
   Shows only the tags for ONE axis, so the reader isn't overwhelmed.
   ══════════════════════════════════════════════════════════════════════ */
function AxisPage({ axis }) {
  const axisData = FMF.BROWSE_AXES.find(a => a.id === axis);
  if (!axisData) return <BrowseHub />;
  const otherAxes = FMF.BROWSE_AXES.filter(a => a.id !== axis);

  return (
    <main>
      {/* Breadcrumb */}
      <section className="container" style={{ paddingTop: 20, paddingBottom: 0 }}>
        <div className="mono body-xs" style={{ color: "var(--ink-mute)", letterSpacing: "0.04em" }}>
          <a href="#/browse" style={{ color: "var(--ink-mute)", borderBottom: "1px solid var(--rule)" }}>Browse</a>
          <span style={{ margin: "0 10px", color: "var(--ink-faint)" }}>/</span>
          <span style={{ color: "var(--ink)" }}>{axisData.label}</span>
        </div>
      </section>

      <BrowseMast
        kicker={`${axisData.label} · ${axisData.tags.length} ways to filter`}
        title={<>{axisData.label}<span className="fraun-itl">.</span></>}
        lead={axisData.groupBlurb}
        stat={`${(FMF.CATALOG_ALL || FMF.CATALOG).length} fragrances total`}
      />

      {/* Tags for this axis — clean vertical list */}
      <section className="container" style={{ padding: "40px 32px 48px" }}>
        <div style={{ borderTop: "1px solid var(--ink)" }}>
          {axisData.tags.map(tag => {
            const count = FMF.byTag(axisData.id, tag.slug).length;
            return (
              <a key={tag.slug} href={`#/browse/${axisData.id}/${tag.slug}`}
                 style={{
                   display: "grid",
                   gridTemplateColumns: "220px 1fr 110px",
                   gap: 32,
                   padding: "24px 0",
                   borderBottom: "1px solid var(--rule)",
                   textDecoration: "none",
                   color: "inherit",
                   alignItems: "baseline",
                 }}
                 onMouseEnter={e => e.currentTarget.style.background = "var(--paper-deep)"}
                 onMouseLeave={e => e.currentTarget.style.background = "transparent"}>
                <div className="fraun" style={{ fontSize: 28, letterSpacing: "-0.015em", lineHeight: 1.1 }}>
                  {tag.label}
                </div>
                <p className="body-l" style={{ color: "var(--ink-soft)", margin: 0, maxWidth: "60ch" }}>
                  {tag.blurb}
                </p>
                <div className="mono body-s" style={{ color: count > 0 ? "var(--ink-mute)" : "var(--ink-faint)", textAlign: "right", alignSelf: "center" }}>
                  {count} {count === 1 ? "entry" : "entries"}
                </div>
              </a>
            );
          })}
        </div>
      </section>

      <hr className="hairline" />

      {/* Other axes — lateral nav, no clutter */}
      <section className="container" style={{ padding: "28px 32px 56px" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", flexWrap: "wrap", gap: 16 }}>
          <span className="kicker">Other ways to browse</span>
          <div style={{ display: "flex", gap: 22, flexWrap: "wrap" }}>
            {otherAxes.map(a => (
              <a key={a.id} href={`#/browse/${a.id}`} className="mono body-s" style={{ color: "var(--ink-mute)", borderBottom: "1px solid var(--rule)", paddingBottom: 2 }}>
                {a.label} →
              </a>
            ))}
          </div>
        </div>
      </section>
    </main>
  );
}

function RefAxisCell({ label, count, hint, topFew, seeAll, border = true }) {
  return (
    <div style={{ padding: "24px 28px", borderLeft: border ? "1px solid var(--rule)" : 0 }}>
      <div className="kicker" style={{ marginBottom: 12 }}>{label}</div>
      <div className="mono" style={{ fontSize: 32, letterSpacing: "-0.02em", lineHeight: 1, marginBottom: 10 }}>{count}</div>
      <div className="mono body-xs" style={{ color: "var(--ink-mute)", marginBottom: 16 }}>{hint}</div>
      <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
        {topFew.map(x => (
          <a key={x.slug} href={x.slug} className="fraun body-m" style={{ color: "var(--ink)", textDecoration: "underline", textDecorationColor: "var(--rule)", textUnderlineOffset: 3 }}>
            {x.label}
          </a>
        ))}
      </div>
    </div>
  );
}

/* ══════════════════════════════════════════════════════════════════════
   TAG PAGE — /browse/:axis/:tag (office · summer · bold · best-seller)
   ══════════════════════════════════════════════════════════════════════ */
function TagPage({ axis, slug }) {
  const meta = FMF.tagMeta(axis, slug);
  const baseItems = useMemoB(() => meta ? FMF.byTag(axis, slug) : [], [axis, slug, meta]);
  const [gender, setGender] = React.useState("all");
  const items = useMemoB(() => FMF.filterByGender(baseItems, gender), [baseItems, gender]);
  // Community-Awards axis pre-sorts by compute fn; keep that order unless user picks a different sort.
  const defaultSort = axis === "awards" ? "computed" : "score";
  const [sort, setSort] = React.useState(defaultSort);

  if (!meta) return <BrowseHub />;

  const sorted = useMemoB(() => {
    const copy = items.slice();
    if (sort === "computed")         { /* preserve order from compute() */ }
    else if (sort === "score")       copy.sort((a, b) => b.community.score - a.community.score);
    else if (sort === "landed-asc")  copy.sort((a, b) => a.landed - b.landed);
    else if (sort === "landed-desc") copy.sort((a, b) => b.landed - a.landed);
    else if (sort === "year")        copy.sort((a, b) => b.year - a.year);
    return copy;
  }, [items, sort]);

  const avgScore = items.length ? (items.reduce((a, f) => a + f.community.score, 0) / items.length).toFixed(2) : "—";
  const avgLanded = items.length ? items.reduce((a, f) => a + f.landed, 0) / items.length : 0;

  // Gender counts for the toggle labels
  const genderCounts = useMemoB(() => ({
    all:    baseItems.length,
    men:    baseItems.filter(f => f.gender === "men").length,
    women:  baseItems.filter(f => f.gender === "women").length,
    unisex: baseItems.filter(f => f.gender === "unisex").length,
  }), [baseItems]);

  return (
    <main>
      <BrowseMast
        kicker={`${meta.axis.label.toLowerCase()} · ${items.length} ${items.length === 1 ? "fragrance" : "fragrances"}`}
        title={<>{meta.tag.label.split(" ").slice(0, -1).join(" ") || ""} <span className="fraun-itl">{meta.tag.label.split(" ").slice(-1)[0]}.</span></>}
        lead={meta.tag.blurb}
        stat={items.length ? `mean community ${avgScore} · mean landed ${FMF.fmtUsd(avgLanded)}` : `0 of ${(FMF.CATALOG_ALL || FMF.CATALOG).length} in catalog`}
      />

      {/* Other tags on this axis — lateral navigation */}
      <section className="container" style={{ padding: "24px 32px 0" }}>
        <div className="kicker" style={{ marginBottom: 12 }}>Other {meta.axis.label.toLowerCase().replace(/^by /, "")}</div>
        <div style={{ display: "flex", flexWrap: "wrap", gap: "8px 10px" }}>
          {meta.axis.tags.map(t => (
            <a key={t.slug} href={`#/browse/${axis}/${t.slug}`} className="mono body-xs" style={{
              padding: "5px 10px",
              border: "1px solid " + (t.slug === slug ? "var(--ink)" : "var(--rule)"),
              color: t.slug === slug ? "var(--paper)" : "var(--ink-soft)",
              background: t.slug === slug ? "var(--ink)" : "transparent",
              letterSpacing: "0.06em",
              textTransform: "uppercase",
              textDecoration: "none",
            }}>
              {t.label}
            </a>
          ))}
        </div>
      </section>

      {/* Gender filter — Men / Women / Unisex / All */}
      {baseItems.length > 0 && (
        <section className="container" style={{ padding: "20px 32px 0" }}>
          <div style={{ display: "flex", alignItems: "baseline", gap: 14, flexWrap: "wrap" }}>
            <span className="kicker">Filter by gender</span>
            <div style={{ display: "inline-flex", border: "1px solid var(--ink)" }}>
              {[
                { k: "all",    l: "All" },
                { k: "men",    l: "Men" },
                { k: "women",  l: "Women" },
                { k: "unisex", l: "Unisex" },
              ].map((opt, i) => (
                <button key={opt.k} onClick={() => setGender(opt.k)}
                  style={{
                    background: gender === opt.k ? "var(--ink)" : "var(--paper)",
                    color: gender === opt.k ? "var(--paper)" : "var(--ink-soft)",
                    border: 0,
                    borderLeft: i === 0 ? 0 : "1px solid var(--ink)",
                    padding: "6px 14px",
                    font: "inherit",
                    fontFamily: "var(--font-mono)",
                    fontSize: 11,
                    letterSpacing: "0.06em",
                    textTransform: "uppercase",
                    cursor: genderCounts[opt.k] === 0 ? "not-allowed" : "pointer",
                    opacity: genderCounts[opt.k] === 0 ? 0.4 : 1,
                  }}
                  disabled={genderCounts[opt.k] === 0}>
                  {opt.l} <span style={{ color: gender === opt.k ? "color-mix(in oklab, var(--paper) 60%, transparent)" : "var(--ink-faint)", marginLeft: 4 }}>· {genderCounts[opt.k]}</span>
                </button>
              ))}
            </div>
          </div>
        </section>
      )}

      {items.length === 0 ? (
        <section className="container" style={{ padding: "48px 32px 80px" }}>
          <p className="fraun body-l" style={{ color: "var(--ink-soft)", maxWidth: "50ch" }}>
            Nothing in Issue 001's catalog is tagged <strong>{meta.tag.label.toLowerCase()}</strong> yet. As the catalog expands, new tags populate.
          </p>
          <div style={{ marginTop: 24 }}>
            <a href="#/browse" className="shop-btn shop-btn--ghost">Back to browse</a>
          </div>
        </section>
      ) : (
        <section className="container" style={{ padding: "32px 32px 64px" }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 18, flexWrap: "wrap", gap: 16 }}>
            <div className="kicker">Fragrances</div>
            <div style={{ display: "flex", gap: 16, alignItems: "baseline", flexWrap: "wrap" }}>
              <span className="mono body-xs" style={{ color: "var(--ink-mute)", letterSpacing: "0.06em", textTransform: "uppercase" }}>Sort</span>
              <SortPills value={sort} onChange={setSort} options={[
                ...(axis === "awards" ? [{ v: "computed", l: "Ranked" }] : []),
                { v: "score", l: "Community" },
                { v: "landed-asc", l: "Landed ↑" },
                { v: "landed-desc", l: "Landed ↓" },
                { v: "year", l: "Year" },
              ]} />
            </div>
          </div>
          <div style={{ borderTop: "1px solid var(--ink)", borderBottom: "1px solid var(--ink)" }}>
            {sorted.map((f, i) => <FragranceRow key={f.slug} f={f} i={i} />)}
          </div>
        </section>
      )}
    </main>
  );
}

/* ══════════════════════════════════════════════════════════════════════
   QUICK CATALOG — pre-curated shelves for the browse landing page.
   Each shelf is a question most visitors already have ("what's the best
   men's right now?"), pre-answered with a horizontal card strip — so the
   reader gets to a result without having to drill axis → tag → list.
   Modeled on Fragrantica's awards-by-category UX but authored by us.
   ══════════════════════════════════════════════════════════════════════ */
function QuickCatalog() {
  const cat = FMF.CATALOG_ALL || FMF.CATALOG || [];
  const byCommunity = (a, b) => ((b.community?.score || 0) * Math.log((b.community?.n || 1) + 1))
                               - ((a.community?.score || 0) * Math.log((a.community?.n || 1) + 1));

  const shelves = [
    {
      title: "Bestsellers",
      blurb: "Highest sample size across the catalog — where cultural gravity lives.",
      fragrances: [...cat].sort((a, b) => (b.community?.n || 0) - (a.community?.n || 0)).slice(0, 4),
      href: "#/browse/awards/most-talked-about",
      badge: "Volume",
    },
    {
      title: "Trending now",
      blurb: "Rising releases and current-decade best-sellers — the shape of the 2020s canon.",
      fragrances: cat
        .filter(f => f.tags?.trend?.includes("rising") || f.tags?.trend?.includes("best-seller") || (f.year || 0) >= 2020)
        .sort(byCommunity)
        .slice(0, 4),
      href: "#/browse/awards/best-of-2020s",
      badge: "Rising",
    },
    {
      title: "Best Men's",
      blurb: "Top-ranked masculine releases, weighted by score × volume.",
      fragrances: cat.filter(f => f.gender === "men").sort(byCommunity).slice(0, 4),
      href: "#/browse/awards/all-time-best",
      badge: "Shelf",
    },
    {
      title: "Best Women's",
      blurb: "Top-ranked feminine and unisex picks for a women's shelf.",
      fragrances: cat.filter(f => f.gender === "women" || f.gender === "unisex").sort(byCommunity).slice(0, 4),
      href: "#/browse/awards/all-time-best",
      badge: "Shelf",
    },
    {
      title: "Best budget · under $100",
      blurb: "Highest-rated picks that land under $100 all-in — coupon + shipping + tax included.",
      fragrances: cat.filter(f => (f.landed || 9999) < 100).sort(byCommunity).slice(0, 4),
      href: "#/browse",
      badge: "Value",
    },
    {
      title: "New arrivals",
      blurb: "Released in the last three years — the freshest additions to the reference catalog.",
      fragrances: [...cat]
        .filter(f => (f.year || 0) >= (new Date().getFullYear() - 3))
        .sort((a, b) => (b.year || 0) - (a.year || 0))
        .slice(0, 4),
      href: "#/browse/awards/best-of-2020s",
      badge: "Fresh",
    },
    {
      title: "Iconic & essentials",
      blurb: "Market-defining pieces paired with the bestseller canon — the fragrances that shaped what 'normal' smells like.",
      fragrances: cat
        .filter(f => f.tags?.trend?.includes("iconic") || f.tags?.trend?.includes("best-seller"))
        .sort(byCommunity)
        .slice(0, 4),
      href: "#/browse/awards/all-time-best",
      badge: "Canon",
    },
  ].filter(s => s.fragrances.length > 0);

  return (
    <section className="container" style={{ padding: "32px 32px 48px" }}>
      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 24, flexWrap: "wrap", gap: 12 }}>
        <h3 className="kicker" style={{ margin: 0 }}>Quick catalog · {shelves.length} shelves</h3>
        <span className="mono body-xs" style={{ color: "var(--ink-mute)" }}>pre-curated · no drill-down needed</span>
      </div>
      <div className="quick-catalog">
        {shelves.map(shelf => <QuickShelf key={shelf.title} {...shelf} />)}
      </div>
    </section>
  );
}

function QuickShelf({ title, blurb, fragrances, href, badge }) {
  return (
    <article className="quick-shelf">
      <header className="quick-shelf__head">
        <div className="quick-shelf__meta">
          {badge && <span className="quick-shelf__badge">{badge}</span>}
          <h4 className="quick-shelf__title fraun">{title}</h4>
        </div>
        <p className="quick-shelf__blurb">{blurb}</p>
        <a href={href} className="quick-shelf__all mono body-xs">See all →</a>
      </header>
      <ol className="quick-shelf__list">
        {fragrances.map((f, i) => (
          <li key={f.slug} className="quick-shelf__item">
            <a href={`#/fragrance/${f.slug}`} className="quick-shelf__card">
              <span className="quick-shelf__rank mono">{String(i + 1).padStart(2, "0")}</span>
              <div className="quick-shelf__art">
                <Bottle slug={f.slug} label={f.name} showLabel={false}
                        style={{ width: "100%", aspectRatio: "4 / 5", padding: "10% 20%" }} />
              </div>
              <div className="quick-shelf__body">
                <div className="mono body-xs quick-shelf__brand">{f.brand}</div>
                <div className="fraun quick-shelf__name"><span className="fraun-itl">{f.name}</span></div>
                <div className="mono body-xs quick-shelf__price">
                  {FMF.fmtUsd(f.landed)}
                  {f.community?.score && <span className="quick-shelf__score"> · {f.community.score.toFixed(1)}</span>}
                </div>
              </div>
            </a>
          </li>
        ))}
      </ol>
    </article>
  );
}

Object.assign(window, { Browse });
