/* FindMyFrag — Home.
   Wine-Searcher structural model: the search bar IS the product. The home
   page is a tool, not a magazine cover. One input, dead center, with live
   autocomplete and a ranked results list that matches the logic of the
   detail page (landed price, signal, delta). No onboarding copy — the
   input's presence is the instruction.

   Everything below the fold is secondary: today's biggest price drops
   (the one editorial gesture that's operational, not decorative) and the
   three entry points into the reference graph (family · note · perfumer). */

/* global React, FMF, DataStat, Bottle */
const { useMemo: useMemoH, useState: useStateH, useRef: useRefH, useEffect: useEffectH } = React;

function Home() {
  const watch = useMemoH(() => FMF.WATCHLIST.map(FMF.enrichWatch), []);
  const [q, setQ] = useStateH("");
  const [active, setActive] = useStateH(0);
  const inputRef = useRefH(null);

  // Autofocus the search on mount — the page exists to be searched.
  useEffectH(() => { inputRef.current?.focus(); }, []);

  const all = window.FMF?.CATALOG || [];
  const results = useMemoH(() => {
    const needle = q.trim().toLowerCase();
    if (!needle) return [];
    return all
      .map(f => ({ f, score: scoreMatch(f, needle) }))
      .filter(x => x.score > 0)
      .sort((a, b) => b.score - a.score)
      .slice(0, 8)
      .map(x => x.f);
  }, [q, all]);

  function onKey(e) {
    // Command bar takes precedence when input is a known command.
    if (e.key === "Enter") {
      const cmd = FMF.parseCommand?.(q);
      if (cmd) {
        e.preventDefault();
        location.hash = cmd.route.startsWith("#") ? cmd.route.slice(1) : cmd.route;
        setQ("");
        return;
      }
    }
    if (results.length === 0) return;
    if (e.key === "ArrowDown") { e.preventDefault(); setActive((active + 1) % results.length); }
    else if (e.key === "ArrowUp") { e.preventDefault(); setActive((active - 1 + results.length) % results.length); }
    else if (e.key === "Enter") {
      e.preventDefault();
      const pick = results[active];
      if (pick) location.hash = `#/fragrance/${pick.slug}`;
    }
  }

  // Live command hint — renders when user has typed something we recognize.
  const cmdHint = useMemoH(() => (q.trim() ? FMF.parseCommand?.(q) : null), [q]);

  // Top price drops — sorted by most-negative delta7
  const topDrops = useMemoH(() => [...watch].sort((a, b) => a.delta7 - b.delta7).slice(0, 5), [watch]);

  return (
    <main>
      {/* ────── Hero — fills the fold, layered ambient background ────── */}
      <section className="home-hero">
        {/* Ambient layers: warm gradient wash + typographic watermark + bottle
            constellation. All §11-compliant: hand-authored SVG + CSS gradients,
            no AI or stock imagery. Kept behind `aria-hidden` so assistive tech
            doesn't narrate decoration. */}
        <div className="home-hero__bg" aria-hidden="true">
          <div className="home-hero__gradient" />
          <div className="home-hero__grain" />
          <div className="home-hero__mark">
            <span className="home-hero__mark-sub">Issue N°</span>
            <span className="home-hero__mark-num">001</span>
            <span className="home-hero__mark-sub">Est. 2026</span>
          </div>
          <svg className="home-hero__orn home-hero__orn--tl" viewBox="0 0 200 240" aria-hidden="true">
            <path d="M80 20 L80 42 L72 48 L72 190 C72 210, 92 224, 100 224 C108 224, 128 210, 128 190 L128 48 L120 42 L120 20 Z"
                  fill="none" stroke="currentColor" strokeWidth="1" opacity="0.18" />
            <rect x="84" y="6" width="32" height="16" fill="none" stroke="currentColor" strokeWidth="1" opacity="0.14" />
          </svg>
          <svg className="home-hero__orn home-hero__orn--br" viewBox="0 0 200 240" aria-hidden="true">
            <path d="M60 10 L60 40 L50 52 L50 210 C50 225, 70 232, 100 232 C130 232, 150 225, 150 210 L150 52 L140 40 L140 10 Z"
                  fill="none" stroke="currentColor" strokeWidth="1" opacity="0.14" />
            <circle cx="100" cy="130" r="22" fill="none" stroke="currentColor" strokeWidth="1" opacity="0.12" />
          </svg>
          <svg className="home-hero__orn home-hero__orn--tr" viewBox="0 0 180 220" aria-hidden="true">
            <path d="M70 18 L70 40 L62 48 L62 180 C62 198, 80 208, 90 208 C100 208, 118 198, 118 180 L118 48 L110 40 L110 18 Z"
                  fill="none" stroke="currentColor" strokeWidth="1" opacity="0.1" />
          </svg>
        </div>

        <div className="home-hero__content container">
          <div className="home-hero__inner">
            <div className="home-hero__kicker mono">
              <span className="home-hero__dot" aria-hidden="true" /> Live · {FMF.RETAILERS.length} retailers polled · every 4h
            </div>
            <h1 className="fraun home-hero__h1">
              Find <span className="fraun-itl">any</span> fragrance.
            </h1>
            <p className="fraun home-hero__sub">
              Landed price across {FMF.RETAILERS.length} US retailers. Shipping<Cite n={9} check="sourced" /> and tax computed. No affiliate ranking.<Cite n={2} check="independent" />
            </p>

            {/* The input */}
            <div style={{ position: "relative", marginTop: 48 }}>
              <div style={{
                display: "flex",
                alignItems: "center",
                gap: 14,
                borderTop: "1px solid var(--ink)",
                borderBottom: "2px solid var(--ink)",
                padding: "22px 8px 18px",
              }}>
                <span className="mono body-xs" style={{ color: "var(--ink-mute)", letterSpacing: "0.1em", textTransform: "uppercase" }}>Search</span>
                <input
                  ref={inputRef}
                  value={q}
                  onChange={(e) => { setQ(e.target.value); setActive(0); }}
                  onKeyDown={onKey}
                  placeholder="Creed Aventus · Baccarat Rouge 540 · Tom Ford Oud Wood…"
                  className="fraun"
                  style={{
                    flex: 1, border: 0, background: "transparent", outline: "none",
                    fontSize: 28, letterSpacing: "-0.01em", color: "var(--ink)",
                    padding: "4px 0",
                    fontStyle: q ? "normal" : "italic",
                  }}
                />
                {q && (
                  <button onClick={() => { setQ(""); inputRef.current?.focus(); }}
                    className="mono body-xs"
                    style={{ background: "transparent", border: 0, color: "var(--ink-mute)", cursor: "pointer", padding: 6 }}>
                    clear
                  </button>
                )}
              </div>

              {/* Results — inline, not a dropdown. They ARE the page below the input. */}
              {results.length > 0 && (
                <div style={{ marginTop: 0, borderBottom: "1px solid var(--ink)" }}>
                  {results.map((f, i) => (
                    <ResultRow key={f.slug} f={f} active={i === active}
                      onHover={() => setActive(i)} />
                  ))}
                  <div className="mono body-xs" style={{ padding: "14px 8px", color: "var(--ink-mute)", display: "flex", justifyContent: "space-between", borderTop: "1px solid var(--rule)" }}>
                    <span>{results.length} of {all.length} tracked fragrances</span>
                    <span>↑↓ to select · ↵ to open</span>
                  </div>
                </div>
              )}

              {/* Command hint — shown when what the user typed is a routable command */}
              {cmdHint && (
                <div className="mono body-xs" style={{
                  marginTop: 14,
                  padding: "10px 12px",
                  background: "var(--paper-deep)",
                  border: "1px solid var(--ink)",
                  color: "var(--ink-soft)",
                  letterSpacing: "0.02em",
                  display: "flex",
                  justifyContent: "space-between",
                  alignItems: "baseline",
                  flexWrap: "wrap",
                  gap: 12,
                }}>
                  <span>
                    <span style={{ color: "var(--ink-mute)", letterSpacing: "0.08em", textTransform: "uppercase", marginRight: 10 }}>command</span>
                    {cmdHint.hint}
                  </span>
                  <span style={{ color: "var(--ink-mute)" }}>press ↵ to go</span>
                </div>
              )}

              {/* Empty state — single honest link to the catalog, plus command cues */}
              {!q && (
                <div style={{ marginTop: 28, textAlign: "center" }}>
                  <div className="mono body-xs" style={{ color: "var(--ink-mute)", letterSpacing: "0.06em", marginBottom: 14, textTransform: "uppercase" }}>
                    try <span style={{ color: "var(--ink-soft)" }}>aventus</span> · <span style={{ color: "var(--ink-soft)" }}>refusal 4</span> · <span style={{ color: "var(--ink-soft)" }}>breaches</span> · <span style={{ color: "var(--ink-soft)" }}>chypre $300</span>
                  </div>
                  <a href="#/browse" className="mono body-xs"
                     style={{ color: "var(--ink-mute)", letterSpacing: "0.08em", textTransform: "uppercase", textDecoration: "none", borderBottom: "1px solid var(--rule)", paddingBottom: 2 }}>
                    or browse the catalog →
                  </a>
                </div>
              )}
            </div>
          </div>
        </div>
      </section>

      {!q && <AboutStrip />}
      {!q && <SavingsLedger />}
      {!q && <SignalBoard watch={watch} />}
      {!q && <RecommenderCTA />}
      {!q && topDrops.length > 0 && <TopDropsBlock topDrops={topDrops} />}
      {!q && <RefusalsStrip />}
      {!q && <MethodStrip />}
    </main>
  );
}

/* ══════════════════════════════════════════════════════════════════════
   ABOUT STRIP — "what is this site?" Three-column explainer + headline.
   Editorial-magazine feel, typographic imagery only (no stock photos, §11).
   ══════════════════════════════════════════════════════════════════════ */
function AboutStrip() {
  const cols = [
    {
      num: "01",
      k: "Ledger",
      h: "Landed, not sticker.",
      body: "For every fragrance we track, every retailer, every day: sticker − coupon + shipping + tax. The one number your card actually gets charged. Timestamped, computed, auditable.",
    },
    {
      num: "02",
      k: "Method",
      h: "The formula is public.",
      body: "No black-box \"deal score\" we can quietly tune. Buy / Hold / Wait is deterministic — discount depth, retailer trust, stock health — and every detail page shows the math on the row it's scoring.",
    },
    {
      num: "03",
      k: "Refusals",
      h: "Twelve things we won't do.",
      body: "No affiliate ranking. No simulated community. No inflated MSRPs. No AI imagery. The list is signed, dated, version-controlled — and it's why this site exists instead of another review aggregator.",
    },
  ];
  return (
    <section className="home-about">
      <div className="container home-about__inner">
        <header className="home-about__head">
          <div className="mono body-xs home-about__kicker">A fragrance reference with honest prices</div>
          <h2 className="fraun home-about__h">
            We compute what you'll <span className="fraun-itl">actually</span> pay.
          </h2>
          <p className="home-about__sub">
            FindMyFrag is a reference site for people who are tired of fragrance retail.
            The MSRPs are inflated. The "deals" aren't deals. The reviews are written by
            affiliates. We publish the one number that matters — the landed price — and the
            twelve things we refuse to do to your attention.
          </p>
        </header>
        <div className="home-about__cols">
          {cols.map(c => (
            <div key={c.num} className="home-about__col">
              <div className="mono home-about__num">{c.num}</div>
              <div className="mono body-xs home-about__k">{c.k}</div>
              <h3 className="fraun home-about__h3">{c.h}</h3>
              <p className="home-about__body">{c.body}</p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ══════════════════════════════════════════════════════════════════════
   SAVINGS LEDGER — live chart showing $ below MSRP across the tracked
   catalog. Gives the reader a concrete, at-a-glance answer to "is this
   site actually saving people money?" using real numbers, not marketing.
   Data is computed from the CATALOG at render time; no static claims.
   ══════════════════════════════════════════════════════════════════════ */
function SavingsLedger() {
  const cat = (FMF.CATALOG || []).filter(f => f.landed && f.msrp && f.msrp > f.landed);
  if (cat.length === 0) return null;

  const entries = cat
    .map(f => ({
      ...f,
      savings: f.msrp - f.landed,
      pctOff: ((f.msrp - f.landed) / f.msrp) * 100,
    }))
    .sort((a, b) => b.savings - a.savings);

  const totalSavings = entries.reduce((s, e) => s + e.savings, 0);
  const avgPctOff = entries.reduce((s, e) => s + e.pctOff, 0) / entries.length;
  const medianPctOff = (() => {
    const sorted = [...entries].map(e => e.pctOff).sort((a, b) => a - b);
    const m = Math.floor(sorted.length / 2);
    return sorted.length % 2 ? sorted[m] : (sorted[m - 1] + sorted[m]) / 2;
  })();
  const topSaver = entries[0];
  const maxSavings = entries[0].savings;

  return (
    <section className="home-savings">
      <div className="container home-savings__inner">
        <header className="home-savings__head">
          <div className="mono body-xs home-savings__kicker">Live savings ledger · computed now</div>
          <h2 className="fraun home-savings__h">
            The reader saves <span className="fraun-itl">{FMF.fmtUsdNoCents(totalSavings)}</span> across today's catalog.
          </h2>
          <p className="home-savings__sub">
            Summed delta between MSRP and landed price for every tracked fragrance, across {FMF.RETAILERS?.length || 32} retailers,
            at this moment. No curation, no cherry-picked examples — just the computed total.
          </p>
        </header>

        {/* Stat cards */}
        <div className="home-savings__stats">
          <StatCard
            k="Total below MSRP"
            v={FMF.fmtUsdNoCents(totalSavings)}
            sub={`Across ${entries.length} fragrances tracked today`}
            accent
          />
          <StatCard
            k="Median discount"
            v={`${medianPctOff.toFixed(1)}%`}
            sub={`Mean ${avgPctOff.toFixed(1)}% — landed vs sticker MSRP`}
          />
          <StatCard
            k="Biggest single saver"
            v={FMF.fmtUsdNoCents(topSaver.savings)}
            sub={`${topSaver.brand} ${topSaver.name} · ${topSaver.pctOff.toFixed(0)}% off`}
            href={`#/fragrance/${topSaver.slug}`}
          />
        </div>

        {/* Horizontal bar chart */}
        <div className="home-savings__chart">
          <div className="mono body-xs home-savings__chart-head">
            <span>Fragrance · landed vs MSRP</span>
            <span>$ saved</span>
          </div>
          {entries.slice(0, 8).map(e => {
            const pct = (e.savings / maxSavings) * 100;
            return (
              <a key={e.slug} href={`#/fragrance/${e.slug}`} className="home-savings__row">
                <div className="home-savings__row-name">
                  <span className="mono body-xs home-savings__row-brand">{e.brand}</span>
                  <span className="fraun home-savings__row-frag">
                    <span className="fraun-itl">{e.name}</span>
                  </span>
                </div>
                <div className="home-savings__row-bar" role="progressbar" aria-valuemin="0" aria-valuemax={maxSavings} aria-valuenow={e.savings}>
                  <div className="home-savings__row-fill" style={{ width: `${pct}%` }} />
                  <span className="home-savings__row-msrp mono">
                    msrp {FMF.fmtUsdNoCents(e.msrp)}
                  </span>
                  <span className="home-savings__row-landed mono">
                    landed {FMF.fmtUsdNoCents(e.landed)}
                  </span>
                </div>
                <div className="home-savings__row-amt">
                  <span className="mono home-savings__row-save">{FMF.fmtUsdNoCents(e.savings)}</span>
                  <span className="mono body-xs home-savings__row-pct">−{e.pctOff.toFixed(0)}%</span>
                </div>
              </a>
            );
          })}
        </div>

        <div className="mono body-xs home-savings__foot">
          <Cite n={3} check="verified" /> MSRPs sourced from brand-direct retailers · landed prices recomputed every 4 hours · every number is timestamped on the detail page.
        </div>
      </div>
    </section>
  );
}

function StatCard({ k, v, sub, accent, href }) {
  const Tag = href ? "a" : "div";
  return (
    <Tag href={href} className={`home-stat ${accent ? "home-stat--accent" : ""} ${href ? "home-stat--link" : ""}`}>
      <div className="mono body-xs home-stat__k">{k}</div>
      <div className="home-stat__v">{v}</div>
      <div className="mono body-xs home-stat__sub">{sub}</div>
    </Tag>
  );
}

/* Signal board — today's Buy / Hold / Wait picks across the watchlist.
   Gives the reader an at-a-glance "what's the action today" without needing
   to scroll through the full catalog. Each cell clicks into the detail page. */
function SignalBoard({ watch }) {
  if (!watch || watch.length === 0) return null;
  const buys  = watch.filter(w => w.signal === "buy").slice(0, 2);
  const holds = watch.filter(w => w.signal === "hold").slice(0, 2);
  const waits = watch.filter(w => w.signal === "wait").slice(0, 2);
  const cols = [
    { label: "Buy",  blurb: "Below 90d median · trusted retailer", items: buys,  klass: "signal-buy"  },
    { label: "Hold", blurb: "Near median · wait for a dip",        items: holds, klass: "signal-hold" },
    { label: "Wait", blurb: "Elevated vs 90d · room to drop",      items: waits, klass: "signal-wait" },
  ];
  return (
    <section className="home-board">
      <div className="container">
        <div className="home-board__head">
          <div className="kicker">Today's signal board</div>
          <div className="mono body-xs home-board__meta">
            Poll interval 4h · deterministic scoring · <a href="#/refusals#inflated-msrp">method</a>
          </div>
        </div>
        <div className="home-board__grid">
          {cols.map(c => (
            <div key={c.label} className="home-board__col">
              <div className="home-board__col-head">
                <span className={`signal ${c.klass}`}>{c.label}</span>
                <span className="mono body-xs home-board__col-blurb">{c.blurb}</span>
              </div>
              <ul className="home-board__list">
                {c.items.length === 0 ? (
                  <li className="mono body-xs home-board__empty">nothing in this bucket today</li>
                ) : c.items.map(it => (
                  <li key={it.slug}>
                    <a href={`#/fragrance/${it.slug}`} className="home-board__item">
                      <Bottle slug={it.slug} label={it.name} showLabel={false}
                              style={{ width: 46, height: 58, padding: "6% 12%", flexShrink: 0 }} />
                      <div className="home-board__item-body">
                        <div className="mono body-xs home-board__item-brand">{it.brand}</div>
                        <div className="fraun home-board__item-name"><span className="fraun-itl">{it.name}</span></div>
                        <div className="mono body-xs home-board__item-price">
                          {FMF.fmtUsd(it.priced.total)}
                          <span className={it.delta7 < 0 ? "home-board__delta--down" : "home-board__delta--up"}>
                            {" · "}{it.delta7 === 0 ? "—" : FMF.fmtUsd(it.delta7, { signed: true })}
                          </span>
                        </div>
                      </div>
                    </a>
                  </li>
                ))}
              </ul>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* Recommender CTA — bold editorial block pointing to the quiz. Addresses
   the "I don't know what I want" reader the search can't help. */
function RecommenderCTA() {
  return (
    <section className="home-recommender">
      <div className="container home-recommender__inner">
        <div className="home-recommender__big">
          <div className="mono body-xs home-recommender__kicker">Recommender · 6 questions</div>
          <h2 className="fraun home-recommender__h">
            Don't know what you <span className="fraun-itl">want?</span>
          </h2>
          <p className="home-recommender__sub">
            Answer six questions — occasion, season, how you want to be read, scent family,
            shelf, budget — and we'll rank the catalog against your answers. Scored fit.
            Honest reasoning. No paid placement.
          </p>
          <a href="#/recommend" className="shop-btn shop-btn--primary home-recommender__cta">
            Take the quiz
            <svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true" style={{ marginLeft: 8 }}>
              <path d="M1 5 H9 M5 1 L9 5 L5 9" stroke="currentColor" strokeWidth="1.4" fill="none" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          </a>
        </div>
        <div className="home-recommender__ornament" aria-hidden="true">
          <div className="home-recommender__ring"><span>01</span></div>
          <div className="home-recommender__ring"><span>02</span></div>
          <div className="home-recommender__ring"><span>03</span></div>
          <div className="home-recommender__ring"><span>04</span></div>
          <div className="home-recommender__ring"><span>05</span></div>
          <div className="home-recommender__ring"><span>06</span></div>
        </div>
      </div>
    </section>
  );
}

function TopDropsBlock({ topDrops }) {
  return (
    <>
      <section className="container" style={{ padding: "64px 32px 18px" }}>
        <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", flexWrap: "wrap", gap: 14 }}>
          <div>
            <div className="kicker" style={{ marginBottom: 10 }}>Today · ledger</div>
            <h2 className="fraun" style={{ fontSize: "clamp(28px, 3.6vw, 48px)", letterSpacing: "-0.018em", lineHeight: 1.05, margin: 0, textWrap: "balance" }}>
              One fragrance <span className="fraun-itl">fell hardest</span> this week.
            </h2>
          </div>
          <div className="mono body-xs" style={{ color: "var(--ink-mute)" }}>
            Snapshot 09:14 ET<Cite n={8} check="verified" /> · {FMF.RETAILERS.length} retailers polled · {FMF.CATALOG.length} fragrances tracked
          </div>
        </div>
      </section>
      <section className="container" style={{ padding: "18px 32px 24px" }}>
        <div style={{ borderTop: "1px solid var(--ink)", borderBottom: "1px solid var(--ink)" }}>
          <DropRow it={topDrops[0]} i={0} />
        </div>
      </section>
      {topDrops.length > 1 && (
        <section className="container" style={{ padding: "0 32px 48px" }}>
          <a href="#/browse" className="mono body-xs" style={{
            color: "var(--ink-mute)", letterSpacing: "0.08em", textTransform: "uppercase",
            textDecoration: "none", borderBottom: "1px solid var(--rule)", paddingBottom: 2,
          }}>
            {topDrops.length - 1} more drops · see the catalog →
          </a>
        </section>
      )}
    </>
  );
}

/* Refusals strip — all 12 numbered refusals in a dense editorial grid.
   The brand moat rendered as a billboard, not a footnote. */
function RefusalsStrip() {
  const refusals = (FMF.REFUSALS || []).slice(0, 12);
  return (
    <section className="home-refusals">
      <div className="container">
        <div className="home-refusals__head">
          <div>
            <div className="mono body-xs home-refusals__kicker">The list · signed</div>
            <h2 className="fraun home-refusals__h">
              Twelve things we <span className="fraun-itl">refuse</span> to do.
            </h2>
          </div>
          <a href="#/refusals" className="mono body-xs home-refusals__all">Read the full refusals →</a>
        </div>
        <ol className="home-refusals__grid">
          {refusals.map((r, i) => (
            <li key={r.slug || i}>
              <a href={`#/refusals#${r.slug || ""}`} className="home-refusals__card">
                <span className="home-refusals__num mono">§{String(i + 1).padStart(2, "0")}</span>
                <span className="home-refusals__title fraun">{r.title}</span>
                {r.oneLine && <span className="home-refusals__line mono body-xs">{r.oneLine}</span>}
              </a>
            </li>
          ))}
        </ol>
      </div>
    </section>
  );
}

function MethodStrip() {
  return (
    <>
      <hr className="hairline" />
      <section className="container" style={{ padding: "40px 32px 48px" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", gap: 32, flexWrap: "wrap" }}>
          <div>
            <div className="kicker">Method</div>
            <p className="mono body-s" style={{ color: "var(--ink-soft)", maxWidth: 620, lineHeight: 1.6, marginTop: 10 }}>
              Landed = sticker − coupons + shipping + tax. Computed per-retailer, timestamped, auditable.
              Signal is deterministic; the formula is public. We don't predict next week.
            </p>
          </div>
          <a href="#/refusals" className="mono body-s" style={{ color: "var(--ink)", textDecoration: "none", borderBottom: "1px solid var(--ink)", paddingBottom: 2, whiteSpace: "nowrap" }}>
            The {FMF.REFUSALS.length} things we refuse to do →
          </a>
        </div>
      </section>
    </>
  );
}

/* ────── Search scoring — startsWith > wordStart > contains ────── */
function scoreMatch(f, needle) {
  const hay = (f.brand + " " + f.name).toLowerCase();
  if (hay === needle) return 100;
  if (hay.startsWith(needle)) return 80;
  // word start
  const words = hay.split(/\s+/);
  if (words.some(w => w.startsWith(needle))) return 60;
  if (hay.includes(needle)) return 40;
  return 0;
}

/* ────── A result row in the inline autocomplete — matches detail-page logic ────── */
function ResultRow({ f, active, onHover }) {
  // Only enriched watchlist items have priced data. For others, show a graceful
  // placeholder that still communicates "reference page exists."
  const watch = window.FMF?.WATCHLIST?.find(w => w.slug === f.slug);
  const enriched = watch ? FMF.enrichWatch(watch) : null;

  return (
    <a
      href={`#/fragrance/${f.slug}`}
      onMouseEnter={onHover}
      className="ledger-row"
      style={{
        display: "grid",
        gridTemplateColumns: "56px 2.4fr 1fr 1fr 80px",
        alignItems: "center",
        padding: "16px 8px",
        borderTop: "1px solid var(--rule)",
        textDecoration: "none",
        color: "inherit",
        background: active ? "var(--paper-deep)" : "transparent",
        gap: 16,
      }}
    >
      <Bottle slug={f.slug} label={f.name} showLabel={false}
              style={{ width: 44, height: 56, padding: "6% 10%" }} />
      <div>
        <div className="fraun" style={{ fontSize: 20, letterSpacing: "-0.012em", lineHeight: 1.1 }}>
          {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: 4 }}>
          {f.year} · {f.family || "—"} {f.perfumer ? `· ${f.perfumer}` : ""}
        </div>
      </div>
      <div className="mono body-s" style={{ textAlign: "right" }}>
        {enriched ? (
          <>
            <div style={{ fontSize: 16, letterSpacing: "-0.01em" }}>{FMF.fmtUsd(enriched.priced.total)}</div>
            <div className="body-xs" style={{ color: "var(--ink-mute)", marginTop: 2 }}>landed · {enriched.retailerObj.name.toLowerCase()}</div>
          </>
        ) : (
          <div className="body-xs" style={{ color: "var(--ink-faint)" }}>price pending</div>
        )}
      </div>
      <div className="mono body-s" style={{ textAlign: "right" }}>
        {enriched ? (
          <div style={{ color: enriched.delta7 < 0 ? "var(--sig-buy)" : enriched.delta7 > 0 ? "var(--oxblood-ink)" : "var(--ink-mute)" }}>
            {enriched.delta7 === 0 ? "—" : FMF.fmtUsd(enriched.delta7, { signed: true })}
          </div>
        ) : "—"}
        <div className="body-xs" style={{ color: "var(--ink-mute)", marginTop: 2 }}>Δ 7d</div>
      </div>
      <div style={{ textAlign: "right" }}>
        {enriched ? (
          <span
            className={`signal signal-${enriched.signal}`}
            title={FMF.signalFormula({
              discountDepth: Math.min(100, Math.max(0, ((enriched.msrp - enriched.priced.total) / enriched.msrp) * 100 * 2)),
              retailerTrust: enriched.retailerObj.trust,
              stockHealth: 85,
              dealScore: enriched.dealScore,
            })}
          >
            {enriched.signal}
          </span>
        ) : null}
      </div>
    </a>
  );
}

/* ────── Biggest-drops row ────── */
function DropRow({ it, i }) {
  return (
    <a href={`#/fragrance/${it.slug}`} className="ledger-row" style={{
      display: "grid",
      gridTemplateColumns: "40px 80px 2.2fr 1fr 1fr 1fr 90px",
      alignItems: "center",
      padding: "18px 0",
      borderTop: i === 0 ? 0 : "1px solid var(--rule)",
      textDecoration: "none",
      color: "inherit",
      gap: 16,
    }}>
      <div className="mono body-xs" style={{ color: "var(--ink-mute)" }}>0{i + 1}</div>
      <Bottle slug={it.slug} label={it.name} showLabel={false}
              style={{ width: 64, height: 82, padding: "8% 14%" }} />
      <div>
        <div className="fraun" style={{ fontSize: 24, letterSpacing: "-0.012em", lineHeight: 1.1 }}>
          {it.brand} <span style={{ color: "var(--ink-soft)" }}>·</span> <span className="fraun-itl">{it.name}</span>
        </div>
        <div className="mono body-xs" style={{ color: "var(--ink-mute)", marginTop: 4 }}>
          {it.size} · {it.year} · community <DataStat value={it.community.score} n={it.community.n} sigma={it.community.sigma} />
        </div>
      </div>
      <div className="mono body-s">
        <div className="strike" style={{ fontSize: 12 }}>{FMF.fmtUsdNoCents(it.msrp)}</div>
        <div className="body-xs" style={{ color: "var(--ink-mute)", marginTop: 2 }}>msrp</div>
      </div>
      <div className="mono">
        <div style={{ fontSize: 20, letterSpacing: "-0.01em" }}>{FMF.fmtUsd(it.priced.total)}</div>
        <div className="body-xs" style={{ color: "var(--ink-mute)", marginTop: 2 }}>landed · {it.retailerObj.name.toLowerCase()}</div>
      </div>
      <div className="mono body-s">
        <div style={{ color: it.delta7 < 0 ? "var(--sig-buy)" : it.delta7 > 0 ? "var(--oxblood-ink)" : "var(--ink-mute)", fontSize: 15 }}>
          {it.delta7 === 0 ? "—" : FMF.fmtUsd(it.delta7, { signed: true })}
        </div>
        <div className="body-xs" style={{ color: "var(--ink-mute)", marginTop: 2 }}>Δ 7d</div>
      </div>
      <div style={{ textAlign: "right" }}>
        <span
          className={`signal signal-${it.signal}`}
          title={FMF.signalFormula({
            discountDepth: Math.min(100, Math.max(0, ((it.msrp - it.priced.total) / it.msrp) * 100 * 2)),
            retailerTrust: it.retailerObj.trust,
            stockHealth: 85,
            dealScore: it.dealScore,
          })}
        >
          {it.signal}
        </span>
      </div>
    </a>
  );
}

Object.assign(window, { Home });
