/*
 * Sprout — baby name trends
 * ---------------------------------------------------------------------------
 * A single-file React app. In this preview it runs via Babel-in-the-browser,
 * so it relies on the global `React` / `ReactDOM` (loaded from CDN in
 * index.html). To use it inside a real Vite / CRA / Next project instead:
 *   1.  add  `import React, { useState, useEffect, useMemo, useRef } from 'react'`
 *   2.  delete the two lines under "Globals" below 
 *   3.  `export default App` and render it from your own entry point
 *       (remove the ReactDOM.createRoot(...) call at the very bottom)
 *   4.  put babynames JSON files somewhere fetchable (e.g. /public)
 */

/* ---- Globals (preview only — see note above) ---- */
const { useState, useEffect, useMemo, useRef, useCallback } = React;

const BIG = 4000;

const COUNTRIES = [
  { id: "ew", label: "England & Wales", short: "England & Wales", file: "babynames.json",
    source: "Office for National Statistics" },
  { id: "sc", label: "Scotland", short: "Scotland", file: "babynames-sc.json",
    source: "National Records of Scotland" },
  { id: "ni", label: "N. Ireland", short: "N. Ireland", file: "babynames-ni.json",
    source: "NISRA" },
  { id: "us", label: "USA", short: "USA", file: "babynames-us.json",
    source: "Social Security Administration" },
];

function topChips(all) {
  const girls = all.filter((r) => r.s === "F" && r.cur != null).sort((a, b) => a.cur - b.cur).slice(0, 3);
  const boys = all.filter((r) => r.s === "M" && r.cur != null).sort((a, b) => a.cur - b.cur).slice(0, 3);
  return [...girls, ...boys].map((r) => r.n);
}

/* ------------------------------------------------------------------ helpers */
const nf = (x) => (x == null ? "—" : Number(x).toLocaleString("en-GB"));
const sexWord = (s) => (s === "F" ? "girls'" : "boys'");
const sexName = (s) => (s === "F" ? "Girls" : "Boys");

function enrichOne(r) {
  const map = {};
  let cur = null, curCount = null, eb = null;
  for (const [yi, rank] of r.d) {
    if (yi <= 4 && (eb == null || rank < eb)) eb = rank;
  }
  for (const [yi, rank, cnt] of r.d) map[yi] = { rank, cnt };
  const last = r.d[r.d.length - 1];
  const lastYi = YEARS.length - 1;
  if (map[lastYi]) { cur = map[lastYi].rank; curCount = map[lastYi].cnt; }
  const mom = (r.ob ?? BIG) - (r.rb ?? BIG);
  return {
    ...r,
    key: r.n + "|" + r.s,
    map, cur, curCount, eb, mom,
    latestYear: YEARS[0] + last[0],
    latestRank: last[1],
    latestCount: last[2],
  };
}

function pointsFor(r, kind) {
  return r.d.map(([yi, rank, cnt]) => ({ yi, value: kind === "rank" ? rank : cnt }));
}

function niceTicks(min, max, n = 5) {
  if (min === max) return [min];
  const step = (max - min) / (n - 1);
  return Array.from({ length: n }, (_, i) => Math.round(min + step * i));
}

function story(r) {
  const bits = [];
  bits.push(
    <span key="a">
      <b>{r.n}</b> is a {sexWord(r.s)} name that peaked at <b>#{nf(r.pk)}</b> in <b>{r.py}</b>
    </span>
  );
  let trend;
  if (r.ob != null && r.rb != null) {
    if (r.mom > 150) trend = " and has been climbing strongly this decade";
    else if (r.mom > 20) trend = " and has been gently rising lately";
    else if (r.mom < -150) trend = " but has fallen sharply out of fashion";
    else if (r.mom < -20) trend = " but has slipped a little in recent years";
    else trend = " and has held remarkably steady";
  } else if (r.ob != null && r.rb == null) {
    trend = " and has since faded from the charts — a candidate for a comeback";
  } else if (r.ob == null && r.rb != null) {
    trend = " — a fairly fresh arrival that's found its feet recently";
  } else {
    trend = "";
  }
  bits.push(<span key="b">{trend}. </span>);
  if (r.cur != null) {
    bits.push(
      <span key="c">
        In {YEARS[YEARS.length - 1]} it ranked <b>#{nf(r.cur)}</b> with <b>{nf(r.curCount)}</b> babies. Around <b>{nf(r.t)}</b> have
        been given the name since {YEARS[0]}.
      </span>
    );
  } else {
    bits.push(
      <span key="c">
        It last appeared in the data in <b>{r.latestYear}</b>. Around <b>{nf(r.t)}</b> babies carry it since {YEARS[0]}.
      </span>
    );
  }
  return bits;
}

function similarNames(r, all, n = 8) {
  const name = r.n.toLowerCase();
  const prefix2 = name.slice(0, 2);
  const prefix3 = name.length >= 3 ? name.slice(0, 3) : "";
  const suffix2 = name.length >= 3 ? name.slice(-2) : "";
  const suffix3 = name.length >= 4 ? name.slice(-3) : "";
  const candidates = all.filter((o) => o.s === r.s && o.n !== r.n && o.t >= 20);
  const scored = candidates.map((o) => {
    const on = o.n.toLowerCase();
    let score = 0;
    if (prefix3 && on.slice(0, 3) === prefix3) score += 5;
    else if (on.slice(0, 2) === prefix2) score += 3;
    if (suffix3 && on.slice(-3) === suffix3) score += 5;
    else if (suffix2 && on.slice(-2) === suffix2) score += 3;
    if (Math.abs(on.length - name.length) <= 1) score += 1;
    if (on[0] === name[0]) score += 1;
    return { r: o, score };
  }).filter((s) => s.score >= 3);
  scored.sort((a, b) => (a.r.cur ?? BIG) - (b.r.cur ?? BIG));
  return scored.slice(0, n).map((s) => s.r);
}

/* ------------------------------------------------------------- TrendChart */
function TrendChart({ series, years, kind }) {
  const invert = kind === "rank";
  const W = 760, H = 360, m = { t: 16, r: 20, b: 34, l: 52 };
  const iw = W - m.l - m.r, ih = H - m.t - m.b;
  const [hoverYi, setHoverYi] = useState(null);

  const allVals = series.flatMap((s) => s.points.map((p) => p.value));
  if (!allVals.length) return <div className="empty">No data to chart.</div>;
  let vmin = Math.min(...allVals), vmax = Math.max(...allVals);
  if (kind === "count") { vmin = 0; vmax = vmax * 1.08; }
  else { const pad = (vmax - vmin) * 0.08 || 1; vmin -= pad; vmax += pad; if (vmin < 1) vmin = 1; }

  const nYears = years.length;
  const x = (yi) => m.l + (yi / (nYears - 1)) * iw;
  const y = (v) => {
    const t = (v - vmin) / (vmax - vmin || 1);
    return invert ? m.t + t * ih : m.t + (1 - t) * ih;
  };

  const yTicks = niceTicks(vmin, vmax, 5);
  const xTickYears = years.filter((yy) => yy % 5 === 0);

  const linePath = (pts) => {
    const sorted = [...pts].sort((a, b) => a.yi - b.yi);
    return sorted.map((p, i) => `${i ? "L" : "M"}${x(p.yi).toFixed(1)},${y(p.value).toFixed(1)}`).join(" ");
  };

  const onMove = (e) => {
    const rect = e.currentTarget.getBoundingClientRect();
    const px = ((e.clientX - rect.left) / rect.width) * W;
    let yi = Math.round(((px - m.l) / iw) * (nYears - 1));
    yi = Math.max(0, Math.min(nYears - 1, yi));
    setHoverYi(yi);
  };

  const hoverRows = hoverYi == null ? [] :
    series.map((s) => ({ s, pt: s.points.find((p) => p.yi === hoverYi) })).filter((o) => o.pt);
  const ttY = hoverRows.length ? Math.min(...hoverRows.map((o) => y(o.pt.value))) : 0;

  return (
    <div className="chartbox">
      {series.length > 1 && (
        <div className="chart-legend">
          {series.map((s) => (
            <span key={s.key}><i style={{ background: s.color }} />{s.label}</span>
          ))}
        </div>
      )}
      <div style={{ position: "relative" }}>
        <svg viewBox={`0 0 ${W} ${H}`} width="100%" style={{ display: "block", height: "auto", overflow: "visible" }}>
          {/* gridlines + y labels */}
          {yTicks.map((t, i) => (
            <g key={i}>
              <line x1={m.l} x2={W - m.r} y1={y(t)} y2={y(t)} stroke="var(--line)" strokeWidth="1" />
              <text x={m.l - 10} y={y(t) + 4} textAnchor="end" fontSize="12" fontWeight="700" fill="var(--muted)">
                {kind === "rank" ? "#" + nf(t) : nf(t)}
              </text>
            </g>
          ))}
          {/* x labels */}
          {xTickYears.map((yy) => (
            <text key={yy} x={x(yy - years[0])} y={H - 10} textAnchor="middle" fontSize="12" fontWeight="700" fill="var(--muted)">
              {yy}
            </text>
          ))}
          {/* crosshair */}
          {hoverYi != null && (
            <line x1={x(hoverYi)} x2={x(hoverYi)} y1={m.t} y2={H - m.b} stroke="var(--muted)" strokeWidth="1" strokeDasharray="3 4" />
          )}
          {/* series lines + markers */}
          {series.map((s) => (
            <g key={s.key}>
              <path d={linePath(s.points)} fill="none" stroke={s.color} strokeWidth="2.5" strokeLinejoin="round" strokeLinecap="round" />
              {s.points.map((p) => (
                <circle key={p.yi} cx={x(p.yi)} cy={y(p.value)} r={hoverYi === p.yi ? 5.5 : 3} fill={s.color}
                  stroke="var(--card)" strokeWidth={hoverYi === p.yi ? 2 : 0} />
              ))}
            </g>
          ))}
          {/* mouse capture */}
          <rect x={m.l} y={m.t} width={iw} height={ih} fill="transparent"
            onMouseMove={onMove} onMouseLeave={() => setHoverYi(null)} />
        </svg>
        {hoverRows.length > 0 && (
          <div className="tooltip" style={{ left: `${(x(hoverYi) / W) * 100}%`, top: `${(ttY / H) * 100}%` }}>
            <div className="tt-yr">{years[0] + hoverYi}</div>
            {hoverRows.map((o) => (
              <div className="tt-row" key={o.s.key}>
                <i style={{ background: o.s.color }} />
                {o.s.label}: {kind === "rank" ? "#" + nf(o.pt.value) : nf(o.pt.value) + " babies"}
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

/* ----------------------------------------------------------- Autocomplete */
function Autocomplete({ all, onPick, placeholder, big, value }) {
  const [q, setQ] = useState(value || "");
  const [open, setOpen] = useState(false);
  const [hi, setHi] = useState(0);
  const wrapRef = useRef(null);

  useEffect(() => {
    const h = (e) => { if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", h);
    return () => document.removeEventListener("mousedown", h);
  }, []);

  const matches = useMemo(() => {
    const s = q.trim().toLowerCase();
    if (s.length < 1) return [];
    const starts = [], contains = [];
    for (const r of all) {
      const ln = r.n.toLowerCase();
      if (ln.startsWith(s)) starts.push(r);
      else if (ln.includes(s)) contains.push(r);
      if (starts.length > 40) break;
    }
    const rank = (a, b) => (b.t || 0) - (a.t || 0);
    return [...starts.sort(rank), ...contains.sort(rank)].slice(0, 8);
  }, [q, all]);

  const choose = (r) => { onPick(r); setQ(r.n); setOpen(false); };

  const onKey = (e) => {
    if (!open || !matches.length) return;
    if (e.key === "ArrowDown") { e.preventDefault(); setHi((h) => Math.min(h + 1, matches.length - 1)); }
    else if (e.key === "ArrowUp") { e.preventDefault(); setHi((h) => Math.max(h - 1, 0)); }
    else if (e.key === "Enter") { e.preventDefault(); choose(matches[hi] || matches[0]); }
    else if (e.key === "Escape") setOpen(false);
  };

  return (
    <div className="searchwrap" ref={wrapRef}>
      <div className="searchbox">
        <span aria-hidden style={{ fontSize: 19 }}>🔍</span>
        <input
          value={q} placeholder={placeholder || "Search a name…"}
          onChange={(e) => { setQ(e.target.value); setOpen(true); setHi(0); }}
          onFocus={() => setOpen(true)} onKeyDown={onKey}
        />
        {big && <button className="go" onClick={() => matches[0] && choose(matches[0])}>Search</button>}
      </div>
      {open && matches.length > 0 && (
        <div className="suggest">
          {matches.map((r, i) => (
            <button key={r.key} className={i === hi ? "hi" : ""}
              onMouseEnter={() => setHi(i)} onClick={() => choose(r)}>
              <span className={"dot " + r.s} />
              <span className="nm">{r.n}</span>
              <span className="meta">
                {sexName(r.s)} · {r.cur != null ? "#" + nf(r.cur) + " in " + YEARS[YEARS.length - 1] : "rare today"}
              </span>
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

/* -------------------------------------------------------------- StatTile */
function Stat({ big, lab, sub }) {
  return (
    <div className="stat">
      <div className="big">{big}</div>
      <div className="lab">{lab}</div>
      {sub && <div className="sub">{sub}</div>}
    </div>
  );
}

/* -------------------------------------------------------------- NamePage */
function NamePage({ r, all, goto }) {
  const [kind, setKind] = useState("rank");
  const alt = all.find((o) => o.n === r.n && o.s !== r.s);
  const series = [{
    key: r.key, label: r.n, color: "var(--coral)", points: pointsFor(r, kind),
  }];
  const trendArrow =
    r.mom > 20 ? <span className="val up">▲ climbing</span> :
    r.mom < -20 ? <span className="val down">▼ cooling</span> :
    <span className="val" style={{ color: "var(--ink-2)" }}>◆ steady</span>;

  return (
    <div>
      <button className="alsolink" style={{ marginBottom: 14 }} onClick={() => goto(null)}>← Search another name</button>
      <div className="card">
        <div className="namehead">
          <h2>{r.n}</h2>
          <span className={"badge " + r.s}><span className={"dot " + r.s} />{sexName(r.s)}' name</span>
          {trendArrow}
        </div>
        <p className="story">{story(r)}</p>
        {alt && (
          <p style={{ marginTop: 10 }}>
            <button className="alsolink" onClick={() => goto(alt)}>Also a {sexWord(alt.s)} name — see it →</button>
          </p>
        )}
        <div className="stats">
          <Stat big={r.cur != null ? "#" + nf(r.cur) : "—"} lab={"Rank in " + YEARS[YEARS.length - 1]} sub={r.cur != null ? nf(r.curCount) + " babies" : "not in top data"} />
          <Stat big={"#" + nf(r.pk)} lab="Best ever rank" sub={"in " + r.py} />
          <Stat big={nf(r.t)} lab={"Babies since " + YEARS[0]} sub="≈ floor (excludes suppressed)" />
          <Stat big={r.d.length + " / " + YEARS.length} lab="Years in the data" sub={r.latestYear === YEARS[YEARS.length - 1] ? "still going" : "last " + r.latestYear} />
        </div>

        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginTop: 22, flexWrap: "wrap", gap: 10 }}>
          <div className="secthead" style={{ margin: 0 }}>
            <h3>{kind === "rank" ? "Popularity rank" : "Babies per year"}</h3>
          </div>
          <div className="toggle">
            <button className={kind === "rank" ? "on" : ""} onClick={() => setKind("rank")}>Rank</button>
            <button className={kind === "count" ? "on" : ""} onClick={() => setKind("count")}>Count</button>
          </div>
        </div>
        {kind === "rank" && <p className="sectsub" style={{ marginTop: 4 }}>Lower is more popular — the line rises as the name climbs.</p>}
        <TrendChart series={series} years={YEARS} kind={kind} />
      </div>

      {(() => {
        const similar = similarNames(r, all);
        if (!similar.length) return null;
        return (
          <div className="card" style={{ marginTop: 20 }}>
            <div className="secthead"><h3>Similar names</h3></div>
            <p className="sectsub">Names with a similar sound or feel to {r.n}.</p>
            <div className="namegrid">
              {similar.map((o) => (
                <button key={o.key} className="ncard" onClick={() => goto(o)}>
                  <span className="nm"><span className={"dot " + o.s} />{o.n}</span>
                  <span className="det">
                    {o.cur != null ? `#${nf(o.cur)} in ${YEARS[YEARS.length - 1]}` : `Best #${nf(o.pk)}`} · {nf(o.t)} babies
                  </span>
                </button>
              ))}
            </div>
          </div>
        );
      })()}
    </div>
  );
}

/* --------------------------------------------------------- InsightList */
function InsightList({ title, emoji, sub, items, render, goto }) {
  return (
    <div className="card">
      <div className="secthead"><span className="em">{emoji}</span><h3>{title}</h3></div>
      <p className="sectsub">{sub}</p>
      <div className="rows">
        {items.slice(0, 8).map((r, i) => (
          <button key={r.key} className="row" onClick={() => goto(r)}>
            <span className="idx">{i + 1}</span>
            <span className={"dot " + r.s} />
            <span className="nm">{r.n}</span>
            {render(r)}
          </button>
        ))}
        {!items.length && <div className="empty">Nothing here yet.</div>}
      </div>
    </div>
  );
}

/* ---------------------------------------------------------------- Trends */
function Trends({ insights, goto }) {
  const arrow = (r) => {
    const from = r.ob != null ? "#" + nf(r.ob) : "new";
    const to = r.rb != null ? "#" + nf(r.rb) : "gone";
    return <span className={"val " + (r.mom > 0 ? "up" : "down")}>{from} → {to}</span>;
  };
  return (
    <div>
      <div className="hero" style={{ paddingBottom: 4 }}>
        <h1>What's <span className="hl">moving</span>?</h1>
        <p>The names rising, falling and breaking through. Tap any name to dig in.</p>
      </div>
      <div className="disc thirds" style={{ marginTop: 20 }}>
        <InsightList emoji="📈" title="Rising stars" goto={goto}
          sub="Biggest climbers from the early 2010s to today." items={insights.rising} render={arrow} />
        <InsightList emoji="📉" title="Falling out of favour" goto={goto}
          sub="Names cooling fastest over the same window." items={insights.fading} render={arrow} />
        <InsightList emoji="✨" title="Fresh arrivals" goto={goto}
          sub="Names that weren't around a decade ago and are catching on."
          items={insights.entrants}
          render={(r) => <span className="val up">now #{nf(r.rb)}</span>} />
      </div>
    </div>
  );
}

/* ------------------------------------------------------------- Throwbacks */
function Throwbacks({ all, goto }) {
  const decades = useMemo(() => {
    if (!YEARS.length) return [];
    const first = Math.floor(YEARS[0] / 10) * 10;
    const last = Math.floor(YEARS[YEARS.length - 1] / 10) * 10;
    const out = [];
    for (let d = first; d <= last - 10; d += 10) out.push(d);
    return out;
  }, [all]);

  const [decade, setDecade] = useState(null);
  useEffect(() => { if (decades.length && decade == null) setDecade(decades[0]); }, [decades]);

  const results = useMemo(() => {
    if (decade == null || !all.length) return { girls: [], boys: [] };
    const decadeStart = decade - YEARS[0];
    const decadeEnd = decade + 9 - YEARS[0];
    const filter = (sex) => all.filter((r) => {
      if (r.s !== sex) return false;
      const inDecade = r.d.filter(([yi]) => yi >= decadeStart && yi <= decadeEnd);
      if (!inDecade.length) return false;
      const bestInDecade = Math.min(...inDecade.map(([, rank]) => rank));
      if (bestInDecade > 250) return false;
      return r.rb == null || r.rb > 900;
    }).map((r) => {
      const inDecade = r.d.filter(([yi]) => yi >= decadeStart && yi <= decadeEnd);
      const bestInDecade = Math.min(...inDecade.map(([, rank]) => rank));
      return { ...r, peakInDecade: bestInDecade };
    }).sort((a, b) => a.peakInDecade - b.peakInDecade).slice(0, 15);
    return { girls: filter("F"), boys: filter("M") };
  }, [all, decade]);

  if (decade == null) return null;

  const label = decade + "s";

  return (
    <div>
      <div className="hero" style={{ paddingBottom: 4 }}>
        <h1>Name <span className="hl">throwbacks</span></h1>
        <p>Names that were popular in the {label} but have since faded — ready for a revival?</p>
      </div>
      <div className="decade-btns">
        {decades.map((d) => (
          <button key={d} className={"decade-btn" + (decade === d ? " on" : "")} onClick={() => setDecade(d)}>{d}s</button>
        ))}
      </div>
      <div className="disc" style={{ marginTop: 20 }}>
        <div className="card">
          <div className="secthead"><h3>Girls from the {label}</h3></div>
          <p className="sectsub">Top-250 in the {label}, rare or gone today.</p>
          <div className="rows">
            {results.girls.map((r, i) => (
              <button key={r.key} className="row" onClick={() => goto(r)}>
                <span className="idx">{i + 1}</span>
                <span className={"dot " + r.s} />
                <span className="nm">{r.n}</span>
                <span className="val" style={{ color: "var(--berry)" }}>was #{nf(r.peakInDecade)}</span>
              </button>
            ))}
            {!results.girls.length && <div className="empty">No faded girls' names from this decade.</div>}
          </div>
        </div>
        <div className="card">
          <div className="secthead"><h3>Boys from the {label}</h3></div>
          <p className="sectsub">Top-250 in the {label}, rare or gone today.</p>
          <div className="rows">
            {results.boys.map((r, i) => (
              <button key={r.key} className="row" onClick={() => goto(r)}>
                <span className="idx">{i + 1}</span>
                <span className={"dot " + r.s} />
                <span className="nm">{r.n}</span>
                <span className="val" style={{ color: "var(--berry)" }}>was #{nf(r.peakInDecade)}</span>
              </button>
            ))}
            {!results.boys.length && <div className="empty">No faded boys' names from this decade.</div>}
          </div>
        </div>
      </div>
    </div>
  );
}

/* ----------------------------------------------------------- UniqueFinder */
function UniqueFinder({ all, goto }) {
  const [thr, setThr] = useState(20);
  const [sex, setSex] = useState("all");
  const [minTotal, setMinTotal] = useState(50);
  const [inUse, setInUse] = useState(true);
  const [letter, setLetter] = useState("");
  const [sort, setSort] = useState("total");

  const results = useMemo(() => {
    let out = all.filter((r) =>
      r.pk > thr &&
      (sex === "all" || r.s === sex) &&
      r.t >= minTotal &&
      (!inUse || r.rb != null) &&
      (!letter || r.n[0].toUpperCase() === letter)
    );
    if (sort === "total") out.sort((a, b) => b.t - a.t);
    else if (sort === "alpha") out.sort((a, b) => a.n.localeCompare(b.n));
    else out.sort((a, b) => (a.pk) - (b.pk)); // "closest to fame" first
    return out;
  }, [all, thr, sex, minTotal, inUse, letter, sort]);

  const LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");

  return (
    <div>
      <div className="hero" style={{ paddingBottom: 4 }}>
        <h1>Find a <span className="hl">hidden gem</span></h1>
        <p>Names that have never cracked the top {thr} — real, used, but wonderfully uncommon. Dial the threshold to taste.</p>
      </div>

      <div className="card" style={{ marginTop: 20 }}>
        <div className="filters">
          <div className="field" style={{ minWidth: 220 }}>
            <label>Never ranked above <b>#{thr}</b></label>
            <input type="range" min="5" max="1000" step="5" value={thr} onChange={(e) => setThr(+e.target.value)} />
            <span className="hint" style={{ fontSize: 12 }}>Higher = rarer, more unique</span>
          </div>
          <div className="field">
            <label>Baby</label>
            <div className="seg">
              {["all", "F", "M"].map((s) => (
                <button key={s} className={sex === s ? "on" : ""} onClick={() => setSex(s)}>
                  {s === "all" ? "Any" : sexName(s)}
                </button>
              ))}
            </div>
          </div>
          <div className="field">
            <label>Min. babies since {YEARS[0]}</label>
            <select value={minTotal} onChange={(e) => setMinTotal(+e.target.value)}>
              <option value={10}>10+ (obscure)</option>
              <option value={50}>50+</option>
              <option value={200}>200+</option>
              <option value={1000}>1,000+ (established)</option>
            </select>
          </div>
          <div className="field">
            <label>Still used today</label>
            <div className="seg">
              <button className={inUse ? "on" : ""} onClick={() => setInUse(true)}>Yes</button>
              <button className={!inUse ? "on" : ""} onClick={() => setInUse(false)}>Any</button>
            </div>
          </div>
          <div className="field">
            <label>Starts with</label>
            <select value={letter} onChange={(e) => setLetter(e.target.value)}>
              <option value="">Any letter</option>
              {LETTERS.map((L) => <option key={L} value={L}>{L}</option>)}
            </select>
          </div>
          <div className="field">
            <label>Sort by</label>
            <div className="seg">
              <button className={sort === "total" ? "on" : ""} onClick={() => setSort("total")}>Popularity</button>
              <button className={sort === "alpha" ? "on" : ""} onClick={() => setSort("alpha")}>A–Z</button>
              <button className={sort === "near" ? "on" : ""} onClick={() => setSort("near")}>Near-famous</button>
            </div>
          </div>
        </div>
      </div>

      <p className="count-note" style={{ marginTop: 18 }}>
        <b>{nf(results.length)}</b> names match — showing {Math.min(results.length, 240)}.
      </p>
      <div className="namegrid">
        {results.slice(0, 240).map((r) => (
          <button key={r.key} className="ncard" onClick={() => goto(r)}>
            <span className="nm"><span className={"dot " + r.s} />{r.n}</span>
            <span className="det">Best #{nf(r.pk)} · {nf(r.t)} babies</span>
          </button>
        ))}
        {!results.length && <div className="empty">No names fit — try loosening the filters.</div>}
      </div>
    </div>
  );
}

/* --------------------------------------------------------------- Compare */
function Compare({ all, a, b, setA, setB, goto }) {
  const [kind, setKind] = useState("rank");
  const series = [];
  if (a) series.push({ key: a.key, label: a.n, color: "var(--s-a)", points: pointsFor(a, kind) });
  if (b) series.push({ key: b.key, label: b.n, color: "var(--s-b)", points: pointsFor(b, kind) });

  const col = (r, color) => (
    <div className="cmpcol">
      <h4><span style={{ width: 12, height: 12, borderRadius: 4, background: color, display: "inline-block" }} />
        <button className="alsolink" onClick={() => goto(r)}>{r.n}</button></h4>
      <div className="stats" style={{ gridTemplateColumns: "1fr 1fr", marginTop: 4 }}>
        <Stat big={r.cur != null ? "#" + nf(r.cur) : "—"} lab={YEARS[YEARS.length - 1] + " rank"} />
        <Stat big={"#" + nf(r.pk)} lab={"Peak · " + r.py} />
        <Stat big={nf(r.t)} lab="Total babies" />
        <Stat big={sexName(r.s)} lab="Given to" />
      </div>
    </div>
  );

  return (
    <div>
      <div className="hero" style={{ paddingBottom: 4 }}>
        <h1>Name <span className="hl">face-off</span></h1>
        <p>Put two names head to head across the decades.</p>
      </div>
      <div className="card" style={{ marginTop: 20 }}>
        <div className="comparepick">
          <div style={{ flex: "1 1 220px" }}>
            <Autocomplete all={all} onPick={setA} value={a ? a.n : ""} placeholder="First name…" />
          </div>
          <span className="vs">vs</span>
          <div style={{ flex: "1 1 220px" }}>
            <Autocomplete all={all} onPick={setB} value={b ? b.n : ""} placeholder="Second name…" />
          </div>
        </div>

        {series.length > 0 ? (
          <>
            <div style={{ display: "flex", justifyContent: "flex-end", marginTop: 18 }}>
              <div className="toggle">
                <button className={kind === "rank" ? "on" : ""} onClick={() => setKind("rank")}>Rank</button>
                <button className={kind === "count" ? "on" : ""} onClick={() => setKind("count")}>Count</button>
              </div>
            </div>
            <TrendChart series={series} years={YEARS} kind={kind} />
            <div className="cmpgrid">
              {a && col(a, "var(--s-a)")}
              {b && col(b, "var(--s-b)")}
            </div>
          </>
        ) : <div className="empty">Pick two names to compare.</div>}
      </div>
    </div>
  );
}

/* --------------------------------------------------------------- Browse */
function Browse({ all, goto }) {
  const [rankCut, setRankCut] = useState(100);
  const [letter, setLetter] = useState("");
  const [sex, setSex] = useState("all");
  const [sort, setSort] = useState("rank");

  const LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");

  const results = useMemo(() => {
    let out = all;
    if (sex !== "all") out = out.filter((r) => r.s === sex);
    if (rankCut !== Infinity) out = out.filter((r) => r.cur != null && r.cur <= rankCut);
    if (letter) out = out.filter((r) => r.n[0].toUpperCase() === letter);
    if (sort === "rank") {
      out.sort((a, b) => (a.cur ?? BIG) - (b.cur ?? BIG));
    } else {
      out.sort((a, b) => a.n.localeCompare(b.n) || a.s.localeCompare(b.s));
    }
    return out;
  }, [all, rankCut, letter, sex, sort]);

  return (
    <div>
      <div className="hero" style={{ paddingBottom: 4 }}>
        <h1>Browse <span className="hl">names</span></h1>
        <p>Explore the full list — filter by rank and letter, then sort however you like.</p>
      </div>

      <div className="card" style={{ marginTop: 20 }}>
        <div className="browse-controls">
          <div className="field">
            <label>Show</label>
            <div className="seg">
              {[10, 50, 100, 200, 500].map((n) => (
                <button key={n} className={rankCut === n ? "on" : ""} onClick={() => setRankCut(n)}>Top {n}</button>
              ))}
              <button className={rankCut === Infinity ? "on" : ""} onClick={() => setRankCut(Infinity)}>All</button>
            </div>
          </div>
          <div className="field">
            <label>Baby</label>
            <div className="seg">
              {["all", "F", "M"].map((s) => (
                <button key={s} className={sex === s ? "on" : ""} onClick={() => setSex(s)}>
                  {s === "all" ? "Any" : sexName(s)}
                </button>
              ))}
            </div>
          </div>
          <div className="field">
            <label>Sort by</label>
            <div className="seg">
              <button className={sort === "rank" ? "on" : ""} onClick={() => setSort("rank")}>Rank</button>
              <button className={sort === "alpha" ? "on" : ""} onClick={() => setSort("alpha")}>A–Z</button>
            </div>
          </div>
          <div className="field" style={{ width: "100%" }}>
            <label>Starting letter</label>
            <div className="letter-grid">
              <button className={"letter-btn" + (letter === "" ? " on" : "")} onClick={() => setLetter("")}>All</button>
              {LETTERS.map((L) => (
                <button key={L} className={"letter-btn" + (letter === L ? " on" : "")} onClick={() => setLetter(L)}>{L}</button>
              ))}
            </div>
          </div>
        </div>
      </div>

      <p className="count-note" style={{ marginTop: 18 }}>
        <b>{nf(results.length)}</b> names{letter ? ` starting with ${letter}` : ""}{rankCut !== Infinity ? ` in the top ${rankCut}` : ""}
      </p>
      <div className="namegrid">
        {results.slice(0, 500).map((r) => (
          <button key={r.key} className="ncard" onClick={() => goto(r)}>
            <span className="nm"><span className={"dot " + r.s} />{r.n}</span>
            <span className="det">
              {r.cur != null ? `#${nf(r.cur)} in ${YEARS[YEARS.length - 1]}` : `Best #${nf(r.pk)}`} · {nf(r.t)} babies
            </span>
          </button>
        ))}
        {!results.length && <div className="empty">No names found — try adjusting the filters.</div>}
      </div>
    </div>
  );
}

/* ------------------------------------------------------------ Explore land */
function TopList({ title, items, goto }) {
  return (
    <div className="card">
      <div className="secthead"><h3>{title}</h3></div>
      <div className="rows">
        {items.map((r, i) => (
          <button key={r.key} className="row" onClick={() => goto(r)}>
            <span className="idx">{i + 1}</span>
            <span className={"dot " + r.s} />
            <span className="nm">{r.n}</span>
            <span className="val" style={{ color: "var(--ink-2)" }}>{nf(r.curCount)} babies</span>
          </button>
        ))}
      </div>
    </div>
  );
}

function ExploreLanding({ all, goto, onPick, country }) {
  const chips = useMemo(() => topChips(all), [all]);
  const topGirls = useMemo(() => all.filter((r) => r.s === "F" && r.cur != null).sort((a, b) => a.cur - b.cur).slice(0, 10), [all]);
  const topBoys = useMemo(() => all.filter((r) => r.s === "M" && r.cur != null).sort((a, b) => a.cur - b.cur).slice(0, 10), [all]);
  return (
    <div>
      <div className="hero">
        <h1>Every baby name, <span className="hl">{YEARS.length} years</span> of trends</h1>
        <p>Search any name given in {country.label} since {YEARS[0]} and watch its story unfold.</p>
        <Autocomplete all={all} onPick={onPick} big placeholder={"Try a name — " + chips.slice(0, 3).join(", ") + "…"} />
      </div>
      <div className="disc" style={{ marginTop: 26 }}>
        <TopList title={"Top 10 girls — " + YEARS[YEARS.length - 1]} items={topGirls} goto={goto} />
        <TopList title={"Top 10 boys — " + YEARS[YEARS.length - 1]} items={topBoys} goto={goto} />
      </div>
    </div>
  );
}

/* ------------------------------------------------------------------- App */
let YEARS = [];

function App() {
  const [countryId, setCountryId] = useState("ew");
  const [raw, setRaw] = useState(null);
  const [err, setErr] = useState(null);
  const [tab, setTab] = useState("explore");
  const [selected, setSelected] = useState(null);
  const [cmpA, setCmpA] = useState(null);
  const [cmpB, setCmpB] = useState(null);

  const country = COUNTRIES.find((c) => c.id === countryId);

  useEffect(() => {
    setRaw(null);
    setErr(null);
    setSelected(null);
    setCmpA(null);
    setCmpB(null);
    fetch(country.file)
      .then((r) => { if (!r.ok) throw new Error("HTTP " + r.status); return r.json(); })
      .then((d) => { YEARS = d.years; setRaw(d); })
      .catch((e) => setErr(String(e)));
  }, [countryId]);

  const all = useMemo(() => (raw ? raw.names.map(enrichOne) : []), [raw]);

  const insights = useMemo(() => {
    if (!all.length) return { rising: [], fading: [], revival: [], entrants: [], gems: [] };
    // "Rising/rising this decade": genuinely popular NOW (top 300) and climbed.
    const rising = all.filter((x) => x.ob != null && x.rb != null && x.rb <= 300 && x.mom > 0).sort((a, b) => b.mom - a.mom);
    // "Falling": were solidly popular (top 400) and have cooled or dropped out.
    const fading = all.filter((x) => x.ob != null && x.ob <= 400 && (x.rb == null || x.mom < 0)).sort((a, b) => a.mom - b.mom);
    // "Ripe for a comeback": top-250 in the late '90s, rare or gone now.
    const revival = all.filter((x) => x.eb != null && x.eb <= 250 && (x.rb == null || x.rb > 900)).sort((a, b) => a.eb - b.eb);
    // "Fresh arrivals": absent in the early 2010s, now in the top 300.
    const entrants = all.filter((x) => x.ob == null && x.rb != null && x.rb <= 300).sort((a, b) => a.rb - b.rb);
    const gems = all.filter((x) => x.pk > 100 && x.pk <= 900 && x.rb != null && x.t >= 300).sort((a, b) => b.t - a.t);
    return { rising, fading, revival, entrants, gems };
  }, [all]);

  useEffect(() => {
    if (all.length) {
      const topGirl = all.filter((r) => r.s === "F" && r.cur != null).sort((a, b) => a.cur - b.cur)[0] || null;
      const topBoy = all.filter((r) => r.s === "M" && r.cur != null).sort((a, b) => a.cur - b.cur)[0] || null;
      setCmpA(topGirl);
      setCmpB(topBoy);
    }
  }, [all]); // eslint-disable-line

  const goto = (r) => {
    setSelected(r);
    setTab("explore");
    if (typeof window !== "undefined") window.scrollTo({ top: 0, behavior: "smooth" });
  };
  const switchTab = (t) => { setTab(t); if (t !== "explore") setSelected(null); };

  if (err) return <div className="loading">Couldn't load the data ({err}).<br />Make sure the data JSON files sit next to index.html.</div>;
  if (!raw) return <div className="loading"><div className="spin" />Warming up the nursery…</div>;

  const TABS = [["explore", "Search"], ["browse", "Browse"], ["trends", "Trends"], ["throwbacks", "Throwbacks"], ["unique", "Hidden gems"], ["compare", "Compare"]];

  return (
    <div>
      <div className="topbar">
        <div className="logo"><span className="leaf">🌱</span>Sprout<small>baby names</small></div>
        <div className="country-bar">
          {COUNTRIES.map((c) => (
            <button key={c.id} className={"country-pill" + (c.id === countryId ? " on" : "")}
              onClick={() => setCountryId(c.id)}>{c.short}</button>
          ))}
        </div>
        <nav className="nav">
          {TABS.map(([id, label]) => (
            <button key={id} className={tab === id ? "on" : ""} onClick={() => switchTab(id)}>{label}</button>
          ))}
        </nav>
      </div>

      <div className="wrap">
        {tab === "explore" && (selected
          ? <NamePage r={selected} all={all} goto={goto} />
          : <ExploreLanding all={all} goto={goto} onPick={goto} country={country} />)}
        {tab === "browse" && <Browse all={all} goto={goto} />}
        {tab === "trends" && <Trends insights={insights} goto={goto} />}
        {tab === "throwbacks" && <Throwbacks all={all} goto={goto} />}
        {tab === "unique" && <UniqueFinder all={all} goto={goto} />}
        {tab === "compare" && <Compare all={all} a={cmpA} b={cmpB} setA={setCmpA} setB={setCmpB} goto={goto} />}

        <div className="footer">
          Data: {country.source} — baby names, {country.label}, {YEARS[0]}–{YEARS[YEARS.length - 1]}.
          Some rare counts are suppressed in the source. Built with 🌱 by Sprout.
        </div>
      </div>
    </div>
  );
}

/* ---- Mount (preview only — remove for a real project; see note at top) ---- */
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
