/* eslint-disable */
const { useState, useMemo, useEffect, useCallback } = React;

/* ---------- Helpers ---------- */
const FESTIVALS = (window.FESTIVALS || []).map((f, i) => ({ id: `f-${i}`, ...f }));
const PATHWAYS = window.PATHWAYS || { artists: [], archetypes: {} };
const TARGETS = (window.TARGETS || []).map((t, i) => ({ id: `t-${i}`, ...t }));

const TAG_CLASS = {
  "Film & TV": "tag-film",
  Theater: "tag-theater",
  Music: "tag-music",
  Dance: "tag-dance",
  "Multi-disciplinary": "tag-multi",
  "Conservatory / Intensive": "tag-multi",
};

const STATUS_OPTIONS = [
  { key: "spotted", label: "Spotted" },
  { key: "watching", label: "Watching" },
  { key: "reached", label: "Reached Out" },
  { key: "signed", label: "Signed" },
  { key: "passed", label: "Passed" },
];

const MONTHS_ORDER = [
  "January","February","March","April","May","June",
  "July","August","September","October","November","December",
];

function monthSortKey(monthStr) {
  if (!monthStr) return 99;
  const lower = monthStr.toLowerCase();
  for (let i = 0; i < MONTHS_ORDER.length; i++) {
    if (lower.includes(MONTHS_ORDER[i].toLowerCase())) return i;
  }
  return 99;
}

/* ---------- Icons ---------- */
const Icon = {
  search: () => (
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
  ),
  close: () => (
    <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
  ),
  external: () => (
    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
  ),
  sun: () => (
    <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
  ),
  moon: () => (
    <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
  ),
  plus: () => (
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
  ),
  empty: () => (
    <svg width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
  ),
};

/* ---------- Brand Mark (SVG logo) ---------- */
const BrandMark = () => (
  <div className="brand-mark" aria-hidden="true">
    <span style={{ transform: "translateY(-1px)" }}>oa</span>
  </div>
);

/* ---------- Header ---------- */
function Header({ tab, setTab, scoutCount, theme, toggleTheme }) {
  return (
    <header className="header">
      <div className="header-inner">
        <div className="brand">
          <BrandMark />
          <div className="brand-text">
            <span className="brand-name">Ocean Avenue</span>
            <span className="brand-sub">Talent Scout</span>
          </div>
        </div>
        <nav className="nav-tabs" aria-label="primary">
          <button
            className={`nav-tab ${tab === "targets" ? "active" : ""}`}
            onClick={() => setTab("targets")}
          >
            Targets
            <span className="count">{TARGETS.length}</span>
          </button>
          <button
            className={`nav-tab ${tab === "established" ? "active" : ""}`}
            onClick={() => setTab("established")}
          >
            Established
            <span className="count">{(window.ESTABLISHED || []).length}</span>
          </button>
          <button
            className={`nav-tab ${tab === "scout" ? "active" : ""}`}
            onClick={() => setTab("scout")}
          >
            Scouting
            <span className="count">{scoutCount}</span>
          </button>
          <button
            className={`nav-tab ${tab === "calendar" ? "active" : ""}`}
            onClick={() => setTab("calendar")}
          >
            Calendar
            <span className="count">{(window.FEEDER_CALENDAR || []).filter(e => new Date(e.date) >= new Date(new Date().toDateString())).length}</span>
          </button>
          <button
            className={`nav-tab ${tab === "discover" ? "active" : ""}`}
            onClick={() => setTab("discover")}
          >
            Feeders
            <span className="count">{FESTIVALS.length}</span>
          </button>
          <button
            className={`nav-tab ${tab === "pathways" ? "active" : ""}`}
            onClick={() => setTab("pathways")}
          >
            Pathways
            <span className="count">{PATHWAYS.artists.length}</span>
          </button>
          <button
            className={`nav-tab ${tab === "ranking" ? "active" : ""}`}
            onClick={() => setTab("ranking")}
          >
            Ranking
          </button>
        </nav>
        <button
          className="theme-toggle"
          onClick={toggleTheme}
          aria-label={`Switch to ${theme === "dark" ? "light" : "dark"} mode`}
        >
          {theme === "dark" ? <Icon.sun /> : <Icon.moon />}
        </button>
      </div>
    </header>
  );
}

/* ---------- Calendar ---------- */
function FeederCalendar() {
  const [filter, setFilter] = useState("upcoming");
  const [typeFilter, setTypeFilter] = useState("all");

  const events = useMemo(() => {
    const all = (window.FEEDER_CALENDAR || []).slice();
    const today = new Date(new Date().toDateString());
    return all
      .map((e) => ({ ...e, _d: new Date(e.date), _days: Math.round((new Date(e.date) - today) / (1000 * 60 * 60 * 24)) }))
      .sort((a, b) => a._d - b._d);
  }, []);

  const filtered = useMemo(() => {
    let list = events;
    if (filter === "upcoming") list = list.filter((e) => e._days >= 0);
    if (filter === "past") list = list.filter((e) => e._days < 0);
    if (typeFilter !== "all") list = list.filter((e) => e.event_type === typeFilter);
    return list;
  }, [events, filter, typeFilter]);

  const upcomingCount = events.filter((e) => e._days >= 0).length;
  const next30 = events.filter((e) => e._days >= 0 && e._days <= 30).length;
  const types = Array.from(new Set(events.map((e) => e.event_type))).sort();

  const fmt = (iso) => {
    const d = new Date(iso);
    return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
  };
  const dayLabel = (days) => {
    if (days < 0) return `${Math.abs(days)}d ago`;
    if (days === 0) return "Today";
    if (days === 1) return "Tomorrow";
    if (days <= 7) return `${days}d`;
    if (days <= 30) return `${days}d`;
    return `${days}d`;
  };
  const urgencyClass = (days) => {
    if (days < 0) return "cal-past";
    if (days <= 7) return "cal-imminent";
    if (days <= 30) return "cal-soon";
    return "cal-future";
  };

  return (
    <>
      <section className="discovery-hero hero-compact">
        <h1 className="hero-title-sm">Calendar <span className="hero-count">{upcomingCount}</span></h1>
        <div className="hero-stats">
          <div className="stat">
            <div className="stat-num">{upcomingCount}</div>
            <div className="stat-label">Upcoming</div>
          </div>
          <div className="stat">
            <div className="stat-num">{next30}</div>
            <div className="stat-label">Next 30 days</div>
          </div>
          <div className="stat">
            <div className="stat-num">{types.length}</div>
            <div className="stat-label">Event types</div>
          </div>
        </div>
      </section>

      <div className="filter-bar">
        <div className="chips">
          {["upcoming", "past", "all"].map((f) => (
            <button
              key={f}
              className={`chip ${filter === f ? "active" : ""}`}
              onClick={() => setFilter(f)}
            >
              {f === "upcoming" ? "Upcoming" : f === "past" ? "Past" : "All"}
            </button>
          ))}
          <span style={{ width: 1, height: 24, background: "var(--color-border)", margin: "0 8px" }} />
          <button
            className={`chip ${typeFilter === "all" ? "active" : ""}`}
            onClick={() => setTypeFilter("all")}
          >
            All types
          </button>
          {types.map((t) => (
            <button
              key={t}
              className={`chip ${typeFilter === t ? "active" : ""}`}
              onClick={() => setTypeFilter(t)}
            >
              {t}
            </button>
          ))}
        </div>
      </div>

      <section className="cards-grid">
        {filtered.length === 0 ? (
          <div className="no-results">
            <Icon.empty />
            <p>No events match those filters.</p>
          </div>
        ) : (
          filtered.map((e) => (
            <article key={e.feeder + e.date + e.title} className={`card ${urgencyClass(e._days)}`}>
              <div className="card-head">
                <span className={`tag tag-multi`}>{e.event_type}</span>
                <span className="card-month" style={{ fontWeight: 600 }}>{dayLabel(e._days)}</span>
              </div>
              <h3 className="card-title" style={{ fontSize: "1.15rem" }}>{e.title}</h3>
              <div className="card-location">
                <span>{fmt(e.date)}{e.date_end ? ` – ${fmt(e.date_end)}` : ""}</span>
                <span className="dot" />
                <span>{e.city}</span>
              </div>
              <p className="card-desc" style={{ marginTop: 8 }}>
                <strong>{e.feeder}</strong>
                {e.notes ? <><br /><span style={{ color: "var(--color-text-muted)" }}>{e.notes}</span></> : null}
              </p>
              <div className="card-foot">
                <a href={e.source} target="_blank" rel="noopener noreferrer" style={{ fontSize: "0.85rem", color: "var(--color-accent)" }}>
                  Source ↗
                </a>
              </div>
            </article>
          ))
        )}
      </section>
    </>
  );
}

/* ---------- Discovery ---------- */
function Discovery({ openFestival, presetTags, consumePresetTags, goToTarget }) {
  const FEEDERS_RAW = (window.FEEDERS_DATA && window.FEEDERS_DATA.feeders) || [];
  const CROSSOVERS_RAW = (window.FEEDERS_DATA && window.FEEDERS_DATA.crossovers) || [];
  const TOTAL_TARGETS = (window.FEEDERS_DATA && window.FEEDERS_DATA.total_targets) || 0;

  const [view, setView] = useState("rollup"); // rollup | crossovers | programs
  const [search, setSearch] = useState("");
  const [activeCats, setActiveCats] = useState(new Set());
  const [sortKey, setSortKey] = useState("count");
  const [sortDir, setSortDir] = useState("desc");

  // Legacy state for the static programs grid (kept as reference view)
  const [progSearch, setProgSearch] = useState("");
  const [progActiveTags, setProgActiveTags] = useState(new Set());
  const [progSortBy, setProgSortBy] = useState("name");

  useEffect(() => {
    if (presetTags && presetTags.length > 0) {
      setView("programs");
      setProgActiveTags(new Set(presetTags));
      setProgSearch("");
      window.scrollTo({ top: 0, behavior: "smooth" });
      consumePresetTags && consumePresetTags();
    }
  }, [presetTags]);

  const allCategories = useMemo(() => {
    const cats = new Set();
    FEEDERS_RAW.forEach((f) => cats.add(f.category));
    return Array.from(cats).sort();
  }, [FEEDERS_RAW]);

  const filteredFeeders = useMemo(() => {
    let list = FEEDERS_RAW;
    if (activeCats.size > 0) list = list.filter((f) => activeCats.has(f.category));
    if (search.trim()) {
      const q = search.trim().toLowerCase();
      list = list.filter((f) =>
        [f.name, f.category, (f.disciplines || []).join(" "), (f.sample_names || []).map((s) => (s && typeof s === "object" ? s.name : s)).join(" ")]
          .join(" ")
          .toLowerCase()
          .includes(q)
      );
    }
    list = [...list];
    list.sort((a, b) => {
      let av, bv;
      if (sortKey === "count") { av = a.count; bv = b.count; }
      else if (sortKey === "name") { av = a.name.toLowerCase(); bv = b.name.toLowerCase(); }
      else if (sortKey === "category") { av = a.category.toLowerCase(); bv = b.category.toLowerCase(); }
      else if (sortKey === "disciplines") { av = (a.disciplines || []).length; bv = (b.disciplines || []).length; }
      if (av < bv) return sortDir === "asc" ? -1 : 1;
      if (av > bv) return sortDir === "asc" ? 1 : -1;
      return 0;
    });
    return list;
  }, [FEEDERS_RAW, search, activeCats, sortKey, sortDir]);

  const toggleCat = (cat) => {
    setActiveCats((prev) => {
      const next = new Set(prev);
      if (next.has(cat)) next.delete(cat); else next.add(cat);
      return next;
    });
  };

  const toggleSort = (key) => {
    if (sortKey === key) {
      setSortDir(sortDir === "asc" ? "desc" : "asc");
    } else {
      setSortKey(key);
      setSortDir(key === "name" || key === "category" ? "asc" : "desc");
    }
  };

  const sortArrow = (key) => sortKey === key ? (sortDir === "asc" ? " ▲" : " ▼") : "";

  // Crossover stats
  const crossoverCount = CROSSOVERS_RAW.length;
  const topCrossovers = useMemo(() => {
    return [...CROSSOVERS_RAW].sort((a, b) => (b.feeders || []).length - (a.feeders || []).length);
  }, [CROSSOVERS_RAW]);

  // Legacy programs grid filtering
  const allProgTags = useMemo(() => {
    const tags = new Set();
    FESTIVALS.forEach((f) => tags.add(f.tag));
    return Array.from(tags).sort();
  }, []);

  const filteredPrograms = useMemo(() => {
    let list = FESTIVALS;
    if (progActiveTags.size > 0) list = list.filter((f) => progActiveTags.has(f.tag));
    if (progSearch.trim()) {
      const q = progSearch.trim().toLowerCase();
      list = list.filter((f) =>
        [f.name, f.country, f.city, f.discipline, f.description, f.notable_alumni]
          .filter(Boolean).join(" ").toLowerCase().includes(q)
      );
    }
    list = [...list];
    if (progSortBy === "name") list.sort((a, b) => a.name.localeCompare(b.name));
    else if (progSortBy === "month") list.sort((a, b) => monthSortKey(a.month) - monthSortKey(b.month));
    else if (progSortBy === "country") list.sort((a, b) => (a.country || "").localeCompare(b.country || ""));
    return list;
  }, [progSearch, progActiveTags, progSortBy]);

  const toggleProgTag = (tag) => {
    setProgActiveTags((prev) => {
      const next = new Set(prev);
      if (next.has(tag)) next.delete(tag); else next.add(tag);
      return next;
    });
  };

  return (
    <>
      <section className="discovery-hero hero-compact">
        <h1 className="hero-title-sm">Feeders <span className="hero-count">{FEEDERS_RAW.length}</span></h1>
        <div className="hero-stats">
          <div className="stat">
            <div className="stat-num">{FEEDERS_RAW.length}</div>
            <div className="stat-label">Feeders identified</div>
          </div>
          <div className="stat">
            <div className="stat-num">{TOTAL_TARGETS}</div>
            <div className="stat-label">Targets analyzed</div>
          </div>
          <div className="stat">
            <div className="stat-num">{crossoverCount}</div>
            <div className="stat-label">Multi-feeder targets</div>
          </div>
          <div className="stat">
            <div className="stat-num">{allCategories.length}</div>
            <div className="stat-label">Categories</div>
          </div>
        </div>
      </section>

      <div className="filter-bar" style={{ gap: 8 }}>
        <button className={`chip ${view === "rollup" ? "active" : ""}`} onClick={() => setView("rollup")}>Feeder rollup</button>
        <button className={`chip ${view === "crossovers" ? "active" : ""}`} onClick={() => setView("crossovers")}>Crossover targets ({crossoverCount})</button>
        <button className={`chip ${view === "programs" ? "active" : ""}`} onClick={() => setView("programs")}>Reference programs ({FESTIVALS.length})</button>
      </div>

      {view === "rollup" && (
        <>
          <div className="filter-bar">
            <div className="search-input">
              <Icon.search />
              <input type="text" placeholder="Search feeders, disciplines, names…" value={search} onChange={(e) => setSearch(e.target.value)} />
            </div>
            <div className="chips">
              {allCategories.map((cat) => (
                <button key={cat} className={`chip ${activeCats.has(cat) ? "active" : ""}`} onClick={() => toggleCat(cat)}>{cat}</button>
              ))}
            </div>
          </div>

          <section className="feeders-table-wrap" style={{ overflowX: "auto", marginTop: 12 }}>
            <table className="feeders-table" style={{ width: "100%", borderCollapse: "collapse", fontSize: 14 }}>
              <thead>
                <tr style={{ borderBottom: "2px solid var(--border, #333)", textAlign: "left" }}>
                  <th style={{ padding: "10px 8px", cursor: "pointer", userSelect: "none" }} onClick={() => toggleSort("name")}>Feeder{sortArrow("name")}</th>
                  <th style={{ padding: "10px 8px", cursor: "pointer", userSelect: "none" }} onClick={() => toggleSort("category")}>Category{sortArrow("category")}</th>
                  <th style={{ padding: "10px 8px", cursor: "pointer", userSelect: "none", textAlign: "right" }} onClick={() => toggleSort("count")}>Count{sortArrow("count")}</th>
                  <th style={{ padding: "10px 8px", cursor: "pointer", userSelect: "none" }} onClick={() => toggleSort("disciplines")}>Disciplines{sortArrow("disciplines")}</th>
                  <th style={{ padding: "10px 8px" }}>Sample names</th>
                </tr>
              </thead>
              <tbody>
                {filteredFeeders.length === 0 ? (
                  <tr><td colSpan={5} style={{ padding: 20, textAlign: "center", opacity: 0.6 }}>No feeders match those filters.</td></tr>
                ) : (
                  filteredFeeders.map((f) => (
                    <tr key={f.name} style={{ borderBottom: "1px solid var(--border-subtle, #222)" }}>
                      <td style={{ padding: "10px 8px", fontWeight: 500 }}>{f.name}</td>
                      <td style={{ padding: "10px 8px", opacity: 0.75 }}>{f.category}</td>
                      <td style={{ padding: "10px 8px", textAlign: "right", fontVariantNumeric: "tabular-nums", fontWeight: 600 }}>{f.count}</td>
                      <td style={{ padding: "10px 8px", fontSize: 12 }}>
                        {(f.disciplines || []).map((d) => (
                          <span key={d} className="tag" style={{ marginRight: 4, fontSize: 11, padding: "2px 6px" }}>{d}</span>
                        ))}
                      </td>
                      <td style={{ padding: "10px 8px", fontSize: 12, opacity: 0.95 }}>
                        {(f.sample_names || []).slice(0, 4).map((s, idx) => {
                          const isObj = s && typeof s === "object";
                          const nm = isObj ? s.name : s;
                          const id = isObj ? s.id : null;
                          const src = isObj ? s.source : null;
                          const clickable = id && src === "target" && typeof goToTarget === "function";
                          return (
                            <span key={(id || nm) + "-" + idx}>
                              {clickable ? (
                                <button
                                  type="button"
                                  className="sample-name-link"
                                  onClick={(e) => { e.stopPropagation(); goToTarget(id); }}
                                  style={{ background: "none", border: 0, padding: 0, color: "var(--link, #2563eb)", cursor: "pointer", textDecoration: "underline", font: "inherit" }}
                                  title={src === "target" ? "Open on Targets tab" : src}
                                >{nm}</button>
                              ) : (
                                <span title={src || ""}>{nm}</span>
                              )}
                              {idx < Math.min(3, (f.sample_names || []).length - 1) ? ", " : ""}
                            </span>
                          );
                        })}
                        {(f.sample_names || []).length > 4 ? "…" : ""}
                      </td>
                    </tr>
                  ))
                )}
              </tbody>
            </table>
          </section>
        </>
      )}

      {view === "crossovers" && (
        <section style={{ marginTop: 12 }}>
          <p style={{ opacity: 0.75, fontSize: 13, marginBottom: 12 }}>
            Targets that came through 2+ feeders. These have the highest leverage — they validated through multiple discovery surfaces before reaching us.
          </p>
          <div className="cards-grid">
            {topCrossovers.length === 0 ? (
              <div className="no-results"><Icon.empty /><p>No crossover targets yet.</p></div>
            ) : (
              topCrossovers.map((c) => (
                <article key={c.id} className="card">
                  <div className="card-head">
                    <span className="tag tag-multi">{(c.feeders || []).length} feeders</span>
                    <span className="card-month">{c.id}</span>
                  </div>
                  <h3 className="card-title">{c.name}</h3>
                  <p className="card-desc" style={{ fontSize: 13 }}>{c.discipline}</p>
                  <div className="card-foot" style={{ display: "flex", flexWrap: "wrap", gap: 4 }}>
                    {(c.feeders || []).map((feederName) => (
                      <span key={feederName} className="tag" style={{ fontSize: 11, padding: "2px 6px" }}>{feederName}</span>
                    ))}
                  </div>
                </article>
              ))
            )}
          </div>
        </section>
      )}

      {view === "programs" && (
        <>
          <div className="filter-bar">
            <div className="search-input">
              <Icon.search />
              <input type="text" placeholder="Search programs…" value={progSearch} onChange={(e) => setProgSearch(e.target.value)} />
            </div>
            <div className="chips">
              {allProgTags.map((tag) => (
                <button key={tag} className={`chip ${progActiveTags.has(tag) ? "active" : ""}`} onClick={() => toggleProgTag(tag)}>{tag}</button>
              ))}
            </div>
            <select className="select" value={progSortBy} onChange={(e) => setProgSortBy(e.target.value)}>
              <option value="name">Sort: A–Z</option>
              <option value="month">Sort: By month</option>
              <option value="country">Sort: By country</option>
            </select>
          </div>
          <section className="cards-grid">
            {filteredPrograms.length === 0 ? (
              <div className="no-results"><Icon.empty /><p>No programs match those filters. Try clearing some.</p></div>
            ) : (
              filteredPrograms.map((f) => (
                <article key={f.name} className="card" onClick={() => openFestival(f)} role="button" tabIndex={0} onKeyDown={(e) => (e.key === "Enter" || e.key === " ") && openFestival(f)}>
                  <div className="card-head">
                    <span className={`tag ${TAG_CLASS[f.tag] || "tag-multi"}`}>{f.tag}</span>
                    <span className="card-month">{f.month || "—"}</span>
                  </div>
                  <h3 className="card-title">{f.name}</h3>
                  <div className="card-location">
                    <span>{f.city}</span><span className="dot" /><span>{f.country}</span>
                  </div>
                  <p className="card-desc">{f.description}</p>
                  <div className="card-foot"><span className="age-pill">Ages {f.age_range}</span></div>
                </article>
              ))
            )}
          </section>
        </>
      )}
    </>
  );
}

/* ---------- Festival detail modal ---------- */
function FestivalModal({ festival, onClose, onAddTalent }) {
  useEffect(() => {
    const handler = (e) => e.key === "Escape" && onClose();
    document.addEventListener("keydown", handler);
    return () => document.removeEventListener("keydown", handler);
  }, [onClose]);

  if (!festival) return null;
  const f = festival;
  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal" onClick={(e) => e.stopPropagation()}>
        <div className="modal-head">
          <div>
            <h2 className="modal-title">{f.name}</h2>
            <div className="modal-meta-row">
              <span className={`tag ${TAG_CLASS[f.tag] || "tag-multi"}`}>{f.tag}</span>
              <span className="tag" style={{ background: "var(--color-surface-offset)", color: "var(--color-text-muted)" }}>
                {f.format || "program"}
              </span>
            </div>
          </div>
          <button className="modal-close" onClick={onClose} aria-label="Close">
            <Icon.close />
          </button>
        </div>
        <div className="modal-body">
          <div className="detail-grid">
            <div className="detail-item">
              <div className="label">Location</div>
              <div className="value">{f.city}, {f.country}</div>
            </div>
            <div className="detail-item">
              <div className="label">Discipline</div>
              <div className="value">{f.discipline}</div>
            </div>
            <div className="detail-item">
              <div className="label">Ages</div>
              <div className="value">{f.age_range}</div>
            </div>
            <div className="detail-item">
              <div className="label">Typical Month</div>
              <div className="value">{f.month || "—"}</div>
            </div>
          </div>

          <div className="modal-section">
            <h3>Why it matters</h3>
            <p>{f.description}</p>
          </div>

          {f.notable_alumni && (
            <div className="modal-section">
              <h3>Reputation & alumni</h3>
              <p>{f.notable_alumni}</p>
            </div>
          )}

          <div className="modal-actions">
            <button
              className="btn btn-primary"
              onClick={() => {
                onAddTalent(f);
                onClose();
              }}
            >
              <Icon.plus /> Log talent from here
            </button>
            {f.website && (
              <a
                className="btn btn-secondary"
                href={f.website}
                target="_blank"
                rel="noopener noreferrer"
              >
                Official site <Icon.external />
              </a>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

/* ---------- Scouting CRM ---------- */
function Scouting({ talents, addTalent, updateTalent, removeTalent, openTalent }) {
  const [showForm, setShowForm] = useState(false);

  const grouped = useMemo(() => {
    const map = {};
    STATUS_OPTIONS.forEach((s) => (map[s.key] = []));
    talents.forEach((t) => {
      if (map[t.status]) map[t.status].push(t);
      else map.spotted.push(t);
    });
    return map;
  }, [talents]);

  return (
    <section className="crm-shell">
      <div className="crm-header">
        <div>
          <h1 className="hero-title-sm">Scouting <span className="hero-count">{talents.length}</span></h1>
        </div>
        <button className="btn btn-primary" onClick={() => setShowForm(true)}>
          <Icon.plus /> Add talent
        </button>
      </div>

      {talents.length === 0 ? (
        <div className="crm-empty">
          <h3>No talent logged yet</h3>
          <p>
            Spot a young performer in your Feeders tab? Tap "Log talent from
            here" inside any program, or add one manually now.
          </p>
          <button className="btn btn-primary" onClick={() => setShowForm(true)}>
            <Icon.plus /> Add your first
          </button>
        </div>
      ) : (
        <div className="talent-board">
          {STATUS_OPTIONS.map((s) => (
            <div className="lane" key={s.key}>
              <div className="lane-head">
                <span className="lane-name">{s.label}</span>
                <span className="lane-count">{grouped[s.key].length}</span>
              </div>
              {grouped[s.key].map((t) => (
                <article
                  key={t.id}
                  className="talent-card"
                  onClick={() => openTalent(t)}
                >
                  <div className="talent-name">{t.name}</div>
                  <div className="talent-discipline">{t.discipline} · age {t.age || "?"}</div>
                  {t.sourceName && (
                    <div className="talent-source">via {t.sourceName}</div>
                  )}
                </article>
              ))}
            </div>
          ))}
        </div>
      )}

      {showForm && (
        <AddTalentModal
          onClose={() => setShowForm(false)}
          onSave={(t) => {
            addTalent(t);
            setShowForm(false);
          }}
        />
      )}
    </section>
  );
}

/* ---------- Add Talent Modal ---------- */
function AddTalentModal({ onClose, onSave, prefillSource }) {
  const [form, setForm] = useState({
    name: "",
    age: "",
    discipline: "",
    location: "",
    sourceName: prefillSource?.name || "",
    sourceCountry: prefillSource?.country || "",
    notes: "",
    contact: "",
    status: "spotted",
  });

  useEffect(() => {
    const handler = (e) => e.key === "Escape" && onClose();
    document.addEventListener("keydown", handler);
    return () => document.removeEventListener("keydown", handler);
  }, [onClose]);

  const update = (k, v) => setForm((p) => ({ ...p, [k]: v }));

  const submit = (e) => {
    e.preventDefault();
    if (!form.name.trim()) return;
    onSave({
      id: `t-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
      createdAt: Date.now(),
      ...form,
    });
  };

  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal" onClick={(e) => e.stopPropagation()}>
        <div className="modal-head">
          <div>
            <h2 className="modal-title">Log new talent</h2>
            <p style={{ color: "var(--color-text-muted)", fontSize: "var(--text-sm)", marginTop: 6 }}>
              {prefillSource ? `Source: ${prefillSource.name}` : "Add a young performer to your roster"}
            </p>
          </div>
          <button className="modal-close" onClick={onClose} aria-label="Close">
            <Icon.close />
          </button>
        </div>
        <form className="modal-body" onSubmit={submit}>
          <div className="form-row">
            <label htmlFor="t-name">Name *</label>
            <input
              id="t-name"
              className="form-input"
              value={form.name}
              onChange={(e) => update("name", e.target.value)}
              autoFocus
              required
            />
          </div>
          <div className="form-grid">
            <div className="form-row">
              <label htmlFor="t-age">Age</label>
              <input
                id="t-age"
                className="form-input"
                type="number"
                min="3" max="25"
                value={form.age}
                onChange={(e) => update("age", e.target.value)}
              />
            </div>
            <div className="form-row">
              <label htmlFor="t-disc">Discipline</label>
              <select
                id="t-disc"
                className="form-select"
                value={form.discipline}
                onChange={(e) => update("discipline", e.target.value)}
              >
                <option value="">Choose…</option>
                <option>Film & TV</option>
                <option>Theater</option>
                <option>Musical Theater</option>
                <option>Music</option>
                <option>Dance</option>
                <option>Multi-disciplinary</option>
              </select>
            </div>
          </div>
          <div className="form-grid">
            <div className="form-row">
              <label htmlFor="t-loc">Location</label>
              <input
                id="t-loc"
                className="form-input"
                placeholder="City, country"
                value={form.location}
                onChange={(e) => update("location", e.target.value)}
              />
            </div>
            <div className="form-row">
              <label htmlFor="t-status">Stage</label>
              <select
                id="t-status"
                className="form-select"
                value={form.status}
                onChange={(e) => update("status", e.target.value)}
              >
                {STATUS_OPTIONS.map((s) => (
                  <option key={s.key} value={s.key}>{s.label}</option>
                ))}
              </select>
            </div>
          </div>
          <div className="form-grid">
            <div className="form-row">
              <label htmlFor="t-src">Spotted at</label>
              <input
                id="t-src"
                className="form-input"
                placeholder="Festival or program"
                value={form.sourceName}
                onChange={(e) => update("sourceName", e.target.value)}
              />
            </div>
            <div className="form-row">
              <label htmlFor="t-contact">Guardian / rep contact</label>
              <input
                id="t-contact"
                className="form-input"
                placeholder="Email or phone"
                value={form.contact}
                onChange={(e) => update("contact", e.target.value)}
              />
            </div>
          </div>
          <div className="form-row">
            <label htmlFor="t-notes">Notes</label>
            <textarea
              id="t-notes"
              className="form-textarea"
              placeholder="What stood out? Performance, range, presence…"
              value={form.notes}
              onChange={(e) => update("notes", e.target.value)}
            />
          </div>
          <div className="modal-actions">
            <button type="submit" className="btn btn-primary">
              Save to roster
            </button>
            <button type="button" className="btn btn-secondary" onClick={onClose}>
              Cancel
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}

/* ---------- Talent detail modal ---------- */
function TalentModal({ talent, onClose, onUpdate, onRemove }) {
  const [form, setForm] = useState(talent);
  const [editing, setEditing] = useState(false);

  useEffect(() => setForm(talent), [talent]);
  useEffect(() => {
    const handler = (e) => e.key === "Escape" && onClose();
    document.addEventListener("keydown", handler);
    return () => document.removeEventListener("keydown", handler);
  }, [onClose]);

  if (!talent) return null;
  const update = (k, v) => setForm((p) => ({ ...p, [k]: v }));

  const save = () => {
    onUpdate(form);
    setEditing(false);
  };

  const remove = () => {
    if (confirm(`Remove ${talent.name} from your roster?`)) {
      onRemove(talent.id);
      onClose();
    }
  };

  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal" onClick={(e) => e.stopPropagation()}>
        <div className="modal-head">
          <div>
            <h2 className="modal-title">{talent.name}</h2>
            <div className="modal-meta-row">
              <span className={`status-badge status-${talent.status}`}>
                {STATUS_OPTIONS.find((s) => s.key === talent.status)?.label}
              </span>
              {talent.discipline && (
                <span className="tag" style={{ background: "var(--color-surface-offset)", color: "var(--color-text-muted)" }}>
                  {talent.discipline}
                </span>
              )}
            </div>
          </div>
          <button className="modal-close" onClick={onClose} aria-label="Close">
            <Icon.close />
          </button>
        </div>
        <div className="modal-body">
          {!editing ? (
            <>
              <div className="detail-grid">
                <div className="detail-item">
                  <div className="label">Age</div>
                  <div className="value">{talent.age || "—"}</div>
                </div>
                <div className="detail-item">
                  <div className="label">Location</div>
                  <div className="value">{talent.location || "—"}</div>
                </div>
                <div className="detail-item">
                  <div className="label">Stage</div>
                  <div className="value">
                    {STATUS_OPTIONS.find((s) => s.key === talent.status)?.label}
                  </div>
                </div>
                <div className="detail-item">
                  <div className="label">Contact</div>
                  <div className="value">{talent.contact || "—"}</div>
                </div>
              </div>

              {talent.sourceName && (
                <div className="talent-detail-section">
                  <div className="label">Spotted at</div>
                  <div className="value">{talent.sourceName}</div>
                </div>
              )}

              {talent.notes && (
                <div className="talent-detail-section">
                  <div className="label">Notes</div>
                  <div className="value" style={{ whiteSpace: "pre-wrap" }}>{talent.notes}</div>
                </div>
              )}

              <div className="form-row">
                <label>Move to stage</label>
                <select
                  className="form-select"
                  value={talent.status}
                  onChange={(e) => onUpdate({ ...talent, status: e.target.value })}
                >
                  {STATUS_OPTIONS.map((s) => (
                    <option key={s.key} value={s.key}>{s.label}</option>
                  ))}
                </select>
              </div>

              <div className="modal-actions">
                <button className="btn btn-primary" onClick={() => setEditing(true)}>
                  Edit details
                </button>
                <button className="btn btn-secondary" onClick={remove}>
                  Remove
                </button>
              </div>
            </>
          ) : (
            <>
              <div className="form-row">
                <label>Name</label>
                <input className="form-input" value={form.name} onChange={(e) => update("name", e.target.value)} />
              </div>
              <div className="form-grid">
                <div className="form-row">
                  <label>Age</label>
                  <input className="form-input" type="number" value={form.age} onChange={(e) => update("age", e.target.value)} />
                </div>
                <div className="form-row">
                  <label>Discipline</label>
                  <select className="form-select" value={form.discipline} onChange={(e) => update("discipline", e.target.value)}>
                    <option value="">Choose…</option>
                    <option>Film & TV</option>
                    <option>Theater</option>
                    <option>Musical Theater</option>
                    <option>Music</option>
                    <option>Dance</option>
                    <option>Multi-disciplinary</option>
                  </select>
                </div>
              </div>
              <div className="form-row">
                <label>Location</label>
                <input className="form-input" value={form.location} onChange={(e) => update("location", e.target.value)} />
              </div>
              <div className="form-row">
                <label>Spotted at</label>
                <input className="form-input" value={form.sourceName} onChange={(e) => update("sourceName", e.target.value)} />
              </div>
              <div className="form-row">
                <label>Contact</label>
                <input className="form-input" value={form.contact} onChange={(e) => update("contact", e.target.value)} />
              </div>
              <div className="form-row">
                <label>Notes</label>
                <textarea className="form-textarea" value={form.notes} onChange={(e) => update("notes", e.target.value)} />
              </div>
              <div className="modal-actions">
                <button className="btn btn-primary" onClick={save}>Save changes</button>
                <button className="btn btn-secondary" onClick={() => { setForm(talent); setEditing(false); }}>Cancel</button>
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  );
}

/* ---------- Pathways ---------- */
function parseSourceLinks(sourcesStr) {
  // Parse markdown-style links: [Name](url), [Name](url), ...
  if (!sourcesStr) return [];
  const re = /\[([^\]]+)\]\(([^)]+)\)/g;
  const out = [];
  let m;
  while ((m = re.exec(sourcesStr)) !== null) {
    out.push({ name: m[1], url: m[2] });
  }
  return out;
}

function Pathways({ goToDiscovery }) {
  const { artists, archetypes } = PATHWAYS;
  const [highlightTags, setHighlightTags] = useState(null);

  const onArchetypeClick = (key) => {
    const arc = archetypes[key];
    if (!arc) return;
    // Switch to discover with these tags pre-selected
    goToDiscovery(arc.relevant_tags || []);
  };

  return (
    <section className="pathways-shell">
      <h1 className="hero-title-sm" style={{ marginBottom: 32 }}>Pathways <span className="hero-count">{artists.length}</span></h1>

      <div className="pathway-list">
        {artists.map((a) => {
          const sources = parseSourceLinks(a.sources);
          return (
            <article key={a.name} className="pathway-card">
              <div className="pathway-meta">
                <h3 className="pathway-name">{a.name}</h3>
                <div className="pathway-stat-row">
                  <div className="label">Born</div>
                  <div className="value">{a.birth_year}</div>
                </div>
                <div className="pathway-stat-row">
                  <div className="label">First Break</div>
                  <div className="value">Age {a.discovery_age}</div>
                </div>
                <div className="pathway-stat-row">
                  <div className="label">Channel</div>
                  <div className="value" style={{ fontSize: "0.8125rem", lineHeight: 1.4 }}>
                    {a.discovery_channel}
                  </div>
                </div>
              </div>
              <div className="pathway-body">
                <div className="pathway-section">
                  <h4>Early training</h4>
                  <p>{a.early_training}</p>
                </div>
                <div className="pathway-section">
                  <h4>The break</h4>
                  <p>{a.the_break}</p>
                </div>
                <div className="pathway-section">
                  <h4>Key people</h4>
                  <p>{a.key_people}</p>
                </div>
                <div className="pathway-lesson">
                  <h4>Lesson for scouts</h4>
                  <p>{a.lesson_for_scouts}</p>
                </div>
                <div>
                  <h4 style={{
                    fontSize: "0.6875rem", letterSpacing: "0.14em",
                    textTransform: "uppercase", color: "var(--color-text-muted)",
                    fontWeight: 600, marginBottom: 8
                  }}>
                    Pathway archetypes
                  </h4>
                  <div className="pathway-archetypes">
                    {(a.archetypes || []).map((key) => (
                      <button
                        key={key}
                        className="archetype-pill"
                        onClick={() => onArchetypeClick(key)}
                        title="Click to filter Discovery by matching program types"
                      >
                        {archetypes[key]?.label || key}
                      </button>
                    ))}
                  </div>
                </div>
                {sources.length > 0 && (
                  <div className="pathway-sources">
                    Sources: {sources.map((s, i) => (
                      <React.Fragment key={i}>
                        <a href={s.url} target="_blank" rel="noopener noreferrer">{s.name}</a>
                        {i < sources.length - 1 ? ", " : ""}
                      </React.Fragment>
                    ))}
                  </div>
                )}
              </div>
            </article>
          );
        })}
      </div>

      <div className="archetypes-section">
        <h2 className="section-title">Archetypes</h2>
        <div className="archetypes-grid">
          {Object.entries(archetypes).map(([key, arc]) => (
            <article
              key={key}
              className="archetype-card"
              onClick={() => goToDiscovery(arc.relevant_tags || [])}
              role="button"
              tabIndex={0}
              style={{ cursor: "pointer" }}
            >
              <h3>{arc.label}</h3>
              <p>{arc.description}</p>
              <div className="archetype-tags">
                {(arc.relevant_tags || []).map((t) => (
                  <span key={t} className={`tag ${TAG_CLASS[t] || "tag-multi"}`}>{t}</span>
                ))}
              </div>
              <div className="watch">
                <strong>Watch for</strong>
                {arc.watch_for}
              </div>
            </article>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---------- App ---------- */
/* ---------- Targets (signing pipeline) ---------- */
function stripMarkdownLink(s) {
  if (!s) return "";
  // Convert [label](url) to "label"
  return String(s).replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1");
}
function firstUrl(s) {
  if (!s) return null;
  const m = String(s).match(/https?:\/\/[^\s)]+/);
  return m ? m[0] : null;
}

/* Initials avatar fallback when photo fails to load. */
function Initials({ name }) {
  const parts = String(name || "?").trim().split(/\s+/);
  const initials = (parts[0]?.[0] || "") + (parts[parts.length - 1]?.[0] || "");
  return <div className="target-photo-fallback" aria-hidden="true">{initials.toUpperCase()}</div>;
}

function TargetPhotoSquare({ target }) {
  const [photoError, setPhotoError] = React.useState(false);
  const photo = target.photo_url;
  const showImage = photo && !photoError;

  return (
    <div className="feed-photo">
      {showImage ? (
        <img
          src={photo}
          alt={target.name}
          loading="lazy"
          onError={() => setPhotoError(true)}
        />
      ) : (
        <Initials name={target.name} />
      )}
    </div>
  );
}

function TargetMedia({ target }) {
  const [playing, setPlaying] = React.useState(false);
  const [photoError, setPhotoError] = React.useState(false);
  const photo = target.photo_url;
  const photoSource = target.photo_source_page;
  const video = target.video_url;
  const platform = (target.video_platform || "").toLowerCase();
  const ytId = target.youtube_id;
  const caption = target.video_caption;

  const platformLabel =
    platform === "youtube" ? "YouTube" :
    platform === "tiktok" ? "TikTok" :
    platform === "instagram" ? "Instagram" :
    platform === "vimeo" ? "Vimeo" :
    platform ? "Video" : "";

  // Photo cell — link to source page if we have one
  const PhotoCell = (
    <div className="target-photo">
      {photo && !photoError ? (
        photoSource ? (
          <a href={photoSource} target="_blank" rel="noopener noreferrer" aria-label={`Photo source for ${target.name}`}>
            <img src={photo} alt={target.name} loading="lazy" onError={() => setPhotoError(true)} />
          </a>
        ) : (
          <img src={photo} alt={target.name} loading="lazy" onError={() => setPhotoError(true)} />
        )
      ) : (
        <Initials name={target.name} />
      )}
    </div>
  );

  // Video cell
  let VideoCell;
  if (ytId) {
    const thumb = `https://i.ytimg.com/vi/${ytId}/hqdefault.jpg`;
    VideoCell = (
      <div className="target-video">
        {playing ? (
          <iframe
            src={`https://www.youtube.com/embed/${ytId}?autoplay=1&rel=0`}
            title={`${target.name} — signature clip`}
            frameBorder="0"
            allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
            allowFullScreen
          />
        ) : (
          <button
            type="button"
            className="target-video-play"
            onClick={() => setPlaying(true)}
            aria-label={`Play signature clip for ${target.name}`}
          >
            <img src={thumb} alt="" loading="lazy" />
            <span className="target-video-play-icon" aria-hidden="true">
              <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
                <circle cx="24" cy="24" r="24" fill="rgba(0,0,0,0.55)" />
                <path d="M19 16 L34 24 L19 32 Z" fill="#fff" />
              </svg>
            </span>
            <span className="target-video-badge">YouTube</span>
          </button>
        )}
      </div>
    );
  } else if (video) {
    VideoCell = (
      <a className="target-video target-video-link" href={video} target="_blank" rel="noopener noreferrer">
        <div className="target-video-platform">
          <span className="target-video-platform-name">{platformLabel}</span>
          <span className="target-video-platform-cta">Watch clip <Icon.external /></span>
        </div>
      </a>
    );
  } else {
    VideoCell = (
      <div className="target-video target-video-empty">
        <span>No clip on file</span>
      </div>
    );
  }

  return (
    <div className="target-media">
      {PhotoCell}
      {VideoCell}
      {caption && <p className="target-video-caption">{caption}</p>}
    </div>
  );
}

// Top-level discipline buckets — rare/long-tail disciplines collapse into "Multi / Other"
const DISCIPLINE_BUCKETS = {
  "Music": (d) => d === "Music",
  "Theater": (d) => d === "Theater" || d === "Theater / Musical Theater" || d === "Musical Theater" || d === "Musical Theater / Acting",
  "Acting": (d) => d === "Acting",
  "Film": (d) => d === "Film" || d === "Acting / Film",
  "Dance": (d) => d === "Dance / Crossover",
  "Comedy": (d) => d === "Comedy",
};
const DISCIPLINE_BUCKET_ORDER = ["Music", "Theater", "Acting", "Film", "Dance", "Comedy"];

function Targets({ rosterIds, addToScouting, focusTargetId, consumeFocusTargetId }) {
  const [search, setSearch] = useState("");
  const [activeChannel, setActiveChannel] = useState("All");
  const [activeDiscipline, setActiveDiscipline] = useState("All");
  const [sortBy, setSortBy] = useState("score");
  const [showNewOnly, setShowNewOnly] = useState(false);
  const [activeTag, setActiveTag] = useState("All");
  const [filterSheetOpen, setFilterSheetOpen] = useState(false);
  // Pursue / Watch / Skip tags, keyed by target name (stable across redeploys)
  const [tags, setTags] = useState(() => {
    try { return JSON.parse(localStorage.getItem("oa_target_tags") || "{}"); }
    catch { return {}; }
  });
  const setTag = (name, tag) => {
    setTags((prev) => {
      const next = { ...prev };
      if (!tag || prev[name] === tag) delete next[name];
      else next[name] = tag;
      try { localStorage.setItem("oa_target_tags", JSON.stringify(next)); } catch {}
      return next;
    });
  };

  const today = useMemo(() => new Date(new Date().toDateString()), []);
  const isNew = (t) => {
    if (!t.added_at) return false;
    const days = Math.round((today - new Date(t.added_at)) / (1000 * 60 * 60 * 24));
    return days >= 0 && days <= 7;
  };
  const newCount = useMemo(() => TARGETS.filter(isNew).length, []);

  const [highlightId, setHighlightId] = useState(null);
  useEffect(() => {
    if (!focusTargetId) return;
    // Clear filters so the target is definitely visible
    setSearch("");
    setActiveChannel("All");
    setActiveDiscipline("All");
    setShowNewOnly(false);
    setActiveTag("All");
    // Wait for the next paint so the card exists in the DOM
    const t1 = setTimeout(() => {
      const el = document.getElementById(`target-${focusTargetId}`);
      if (el) {
        el.scrollIntoView({ behavior: "smooth", block: "center" });
        setHighlightId(focusTargetId);
        const t2 = setTimeout(() => setHighlightId(null), 2400);
        return () => clearTimeout(t2);
      }
    }, 60);
    if (typeof consumeFocusTargetId === "function") consumeFocusTargetId();
    return () => clearTimeout(t1);
  }, [focusTargetId]);

  const channels = useMemo(() => {
    const set = new Set();
    TARGETS.forEach((t) => t.channel_group && set.add(t.channel_group));
    return ["All", ...Array.from(set).sort()];
  }, []);

  const disciplines = useMemo(() => {
    const set = new Set();
    TARGETS.forEach((t) => t.discipline && set.add(t.discipline));
    return ["All", ...Array.from(set).sort()];
  }, []);

  const filtered = useMemo(() => {
    let list = TARGETS.slice();
    if (showNewOnly) list = list.filter(isNew);
    if (activeChannel !== "All")
      list = list.filter((t) => t.channel_group === activeChannel);
    if (activeDiscipline !== "All") {
      const matcher = DISCIPLINE_BUCKETS[activeDiscipline];
      if (matcher) {
        list = list.filter((t) => matcher(t.discipline || ""));
      } else if (activeDiscipline === "Multi / Other") {
        list = list.filter((t) => {
          const d = t.discipline || "";
          return !Object.values(DISCIPLINE_BUCKETS).some((fn) => fn(d));
        });
      } else {
        list = list.filter((t) => t.discipline === activeDiscipline);
      }
    }
    if (activeTag !== "All") {
      if (activeTag === "Untagged") list = list.filter((t) => !tags[t.name]);
      else list = list.filter((t) => tags[t.name] === activeTag);
    }
    if (search.trim()) {
      const q = search.trim().toLowerCase();
      list = list.filter((t) =>
        [t.name, t.why_they_matter, t.channel, t.contact_path, t.discipline]
          .filter(Boolean)
          .join(" ")
          .toLowerCase()
          .includes(q)
      );
    }
    if (sortBy === "score") {
      list.sort((a, b) => (b.score || 0) - (a.score || 0));
    } else if (sortBy === "newest") {
      list.sort((a, b) => (b.added_at || "").localeCompare(a.added_at || ""));
    } else if (sortBy === "name") {
      list.sort((a, b) => (a.name || "").localeCompare(b.name || ""));
    }
    return list;
  }, [search, activeChannel, activeDiscipline, sortBy, showNewOnly, activeTag, tags]);

  const counts = useMemo(() => {
    const byGroup = {};
    TARGETS.forEach((t) => {
      const g = t.channel_group || "Other";
      byGroup[g] = (byGroup[g] || 0) + 1;
    });
    return byGroup;
  }, []);

  // Channel chips — short labels for the visible row, full names in titles
  const CHANNEL_SHORT = {
    "Online / Social": "Online",
    "Festival / Competition": "Festival",
    "Conservatory Showcase": "Conservatory",
    "Industry List": "Industry List",
    "Recurring TV / Film": "TV / Film",
  };
  const visibleChannels = useMemo(
    () => channels.filter((c) => c !== "All"),
    [channels]
  );

  // Count active filters that live in the sheet (for the "Filter" button badge)
  const sheetActiveCount =
    (activeDiscipline !== "All" ? 1 : 0) +
    (activeTag !== "All" ? 1 : 0) +
    (showNewOnly ? 1 : 0);

  const clearSheetFilters = () => {
    setActiveDiscipline("All");
    setActiveTag("All");
    setShowNewOnly(false);
  };

  // Close sheet on Escape
  useEffect(() => {
    if (!filterSheetOpen) return;
    const onKey = (e) => { if (e.key === "Escape") setFilterSheetOpen(false); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [filterSheetOpen]);

  return (
    <>
      <section className="targets-header">
        <div className="targets-header-top">
          <h1 className="targets-title">Targets <span className="targets-title-count">{filtered.length}</span></h1>
          <div className="targets-header-tools">
            <div className="search-input search-input-slim">
              <Icon.search />
              <input
                type="search"
                placeholder="Search…"
                value={search}
                onChange={(e) => setSearch(e.target.value)}
              />
            </div>
            <button
              type="button"
              className={`filter-trigger ${sheetActiveCount > 0 ? "is-active" : ""}`}
              onClick={() => setFilterSheetOpen(true)}
              aria-label="Open filters"
            >
              Filter
              {sheetActiveCount > 0 && <span className="filter-trigger-count">{sheetActiveCount}</span>}
            </button>
            <select
              className="select select-slim"
              value={sortBy}
              onChange={(e) => setSortBy(e.target.value)}
              aria-label="Sort targets"
            >
              <option value="score">Highest score</option>
              <option value="newest">Recently added</option>
              <option value="name">A–Z</option>
            </select>
          </div>
        </div>
        <div className="channel-row" role="tablist" aria-label="Channel filter">
          <button
            role="tab"
            aria-selected={activeChannel === "All"}
            className={`channel-chip ${activeChannel === "All" ? "active" : ""}`}
            onClick={() => setActiveChannel("All")}
          >
            All
          </button>
          {visibleChannels.map((c) => (
            <button
              role="tab"
              aria-selected={activeChannel === c}
              key={c}
              className={`channel-chip ${activeChannel === c ? "active" : ""}`}
              onClick={() => setActiveChannel(c)}
              title={c}
            >
              {CHANNEL_SHORT[c] || c}
            </button>
          ))}
        </div>
      </section>

      {filterSheetOpen && (
        <div className="filter-sheet-overlay" onClick={() => setFilterSheetOpen(false)}>
          <div
            className="filter-sheet"
            role="dialog"
            aria-label="Filter targets"
            onClick={(e) => e.stopPropagation()}
          >
            <div className="filter-sheet-header">
              <h2>Filters</h2>
              <button
                type="button"
                className="filter-sheet-close"
                onClick={() => setFilterSheetOpen(false)}
                aria-label="Close filters"
              >×</button>
            </div>

            <div className="filter-sheet-group">
              <h3>When</h3>
              <div className="filter-sheet-chips">
                <button
                  type="button"
                  className={`sheet-chip ${!showNewOnly ? "active" : ""}`}
                  onClick={() => setShowNewOnly(false)}
                >
                  All time
                </button>
                <button
                  type="button"
                  className={`sheet-chip ${showNewOnly ? "active" : ""}`}
                  onClick={() => setShowNewOnly(true)}
                >
                  New this week <span className="sheet-chip-count">{newCount}</span>
                </button>
              </div>
            </div>

            <div className="filter-sheet-group">
              <h3>Discipline</h3>
              <div className="filter-sheet-chips">
                <button
                  type="button"
                  className={`sheet-chip ${activeDiscipline === "All" ? "active" : ""}`}
                  onClick={() => setActiveDiscipline("All")}
                >
                  All
                </button>
                {DISCIPLINE_BUCKET_ORDER.map((d) => (
                  <button
                    key={d}
                    type="button"
                    className={`sheet-chip ${activeDiscipline === d ? "active" : ""}`}
                    onClick={() => setActiveDiscipline(d)}
                  >
                    {d}
                  </button>
                ))}
                <button
                  type="button"
                  className={`sheet-chip ${activeDiscipline === "Multi / Other" ? "active" : ""}`}
                  onClick={() => setActiveDiscipline("Multi / Other")}
                >
                  Multi / Other
                </button>
              </div>
            </div>

            <div className="filter-sheet-group">
              <h3>Tag</h3>
              <div className="filter-sheet-chips">
                {["All", "Pursue", "Watch", "Skip", "Untagged"].map((tg) => (
                  <button
                    key={tg}
                    type="button"
                    className={`sheet-chip ${activeTag === tg ? "active" : ""}`}
                    onClick={() => setActiveTag(tg)}
                  >
                    {tg === "Pursue" ? "🎯 " : tg === "Watch" ? "👁 " : tg === "Skip" ? "⏭ " : ""}
                    {tg}
                    {tg !== "All" && tg !== "Untagged" && (
                      <span className="sheet-chip-count">
                        {Object.values(tags).filter((v) => v === tg).length}
                      </span>
                    )}
                  </button>
                ))}
              </div>
            </div>

            <div className="filter-sheet-footer">
              <button
                type="button"
                className="btn btn-ghost"
                onClick={clearSheetFilters}
                disabled={sheetActiveCount === 0}
              >
                Clear
              </button>
              <button
                type="button"
                className="btn btn-primary"
                onClick={() => setFilterSheetOpen(false)}
              >
                Show {filtered.length} target{filtered.length === 1 ? "" : "s"}
              </button>
            </div>
          </div>
        </div>
      )}

      {filtered.length === 0 ? (
        <div className="crm-empty">
          <h3>No targets match</h3>
          <p>Try clearing filters or broadening your search.</p>
        </div>
      ) : (
        <section className="targets-grid">
          {filtered.map((t) => {
            const onRoster = rosterIds.has(t.id);
            const socialUrl = firstUrl(t.social_or_link);
            const sourceUrl = firstUrl(t.source_url);
            const videoUrl = t.youtube_id
              ? `https://www.youtube.com/watch?v=${t.youtube_id}`
              : t.video_url || "";
            // Primary link priority: performance video > social profile > source article
            const primaryUrl = videoUrl || socialUrl || sourceUrl || "";
            const primaryLabel = videoUrl
              ? "Watch performance"
              : socialUrl
              ? "View profile"
              : sourceUrl
              ? "Read source"
              : "";
            const photoSource = t.photo_source_page;
            return (
              <article key={t.id} id={`target-${t.id}`} className={`feed-card${highlightId === t.id ? " feed-card-flash" : ""}`}>
                {primaryUrl ? (
                  <a
                    className="feed-card-link"
                    href={primaryUrl}
                    target="_blank"
                    rel="noopener noreferrer"
                    aria-label={`${primaryLabel} for ${t.name}`}
                  >
                    <div className="feed-card-media">
                      <TargetPhotoSquare target={t} />
                      <span className={`target-pill feed-pill ${t.channel_group === "Online / Social" ? "pill-online" : t.channel_group === "Festival / Competition" ? "pill-festival" : t.channel_group === "Conservatory Showcase" ? "pill-conservatory" : t.channel_group === "Industry List" ? "pill-industry-list" : t.channel_group === "Recurring TV / Film" ? "pill-recurring" : "pill-other"}`}>
                        {t.channel_group}
                      </span>
                      {isNew(t) && <span className="feed-new-badge">NEW</span>}
                    </div>
                    <div className="feed-card-body">
                      <div className="feed-card-name-row">
                        <h3 className="feed-card-name">{t.name}</h3>
                        {typeof t.score === "number" && (
                          <span className={`score-badge ${t.score >= 70 ? "score-hot" : t.score >= 60 ? "score-warm" : "score-cool"}`} title="Composite signal score (channel + discipline + signals + freshness + media)">
                            {t.score}
                          </span>
                        )}
                      </div>
                      <div className="feed-card-meta">
                        <span>{t.discipline}</span>
                        {t.age_or_birth_year && <span> · {t.age_or_birth_year}</span>}
                      </div>
                      {t.representation && (
                        <div className={`rep-badge ${t.representation === "unknown" ? "rep-none" : "rep-signed"}`} title={`Representation: ${t.representation}`}>
                          {t.representation === "unknown" ? "○ rep unknown" : `● ${t.representation}`}
                        </div>
                      )}
                      {t.velocity_check_status && (
                        <div className={`velocity-badge ${t.velocity_check_status.toLowerCase().includes("pending") ? "velocity-pending" : t.velocity_check_status.toLowerCase().includes("drop") || t.velocity_check_status.toLowerCase().includes("flat") ? "velocity-cold" : "velocity-hot"}`} title={`Chartmetric review: ${t.velocity_check_status}`}>
                          ⚡ {t.velocity_check_status}
                        </div>
                      )}
                      <p className="feed-card-why">{t.why_they_matter}</p>
                      <div className="feed-card-primary-hint">{primaryLabel} ↗</div>
                    </div>
                  </a>
                ) : (
                  <div className="feed-card-link feed-card-nolink">
                    <div className="feed-card-media">
                      <TargetPhotoSquare target={t} />
                      <span className={`target-pill feed-pill ${t.channel_group === "Online / Social" ? "pill-online" : t.channel_group === "Festival / Competition" ? "pill-festival" : t.channel_group === "Conservatory Showcase" ? "pill-conservatory" : t.channel_group === "Industry List" ? "pill-industry-list" : t.channel_group === "Recurring TV / Film" ? "pill-recurring" : "pill-other"}`}>
                        {t.channel_group}
                      </span>
                      {isNew(t) && <span className="feed-new-badge">NEW</span>}
                    </div>
                    <div className="feed-card-body">
                      <div className="feed-card-name-row">
                        <h3 className="feed-card-name">{t.name}</h3>
                        {typeof t.score === "number" && (
                          <span className={`score-badge ${t.score >= 70 ? "score-hot" : t.score >= 60 ? "score-warm" : "score-cool"}`} title="Composite signal score (channel + discipline + signals + freshness + media)">
                            {t.score}
                          </span>
                        )}
                      </div>
                      <div className="feed-card-meta">
                        <span>{t.discipline}</span>
                        {t.age_or_birth_year && <span> · {t.age_or_birth_year}</span>}
                      </div>
                      {t.representation && (
                        <div className={`rep-badge ${t.representation === "unknown" ? "rep-none" : "rep-signed"}`} title={`Representation: ${t.representation}`}>
                          {t.representation === "unknown" ? "○ rep unknown" : `● ${t.representation}`}
                        </div>
                      )}
                      {t.velocity_check_status && (
                        <div className={`velocity-badge ${t.velocity_check_status.toLowerCase().includes("pending") ? "velocity-pending" : t.velocity_check_status.toLowerCase().includes("drop") || t.velocity_check_status.toLowerCase().includes("flat") ? "velocity-cold" : "velocity-hot"}`} title={`Chartmetric review: ${t.velocity_check_status}`}>
                          ⚡ {t.velocity_check_status}
                        </div>
                      )}
                      <p className="feed-card-why">{t.why_they_matter}</p>
                    </div>
                  </div>
                )}
                <div className="feed-card-footer">
                  <div className="feed-card-footer-links">
                    {videoUrl && socialUrl && (
                      <a className="feed-footer-link" href={socialUrl} target="_blank" rel="noopener noreferrer">
                        Profile
                      </a>
                    )}
                    {(videoUrl || socialUrl) && sourceUrl && (
                      <a className="feed-footer-link" href={sourceUrl} target="_blank" rel="noopener noreferrer">
                        Source
                      </a>
                    )}
                    {photoSource && (
                      <a className="feed-footer-link feed-footer-link-faint" href={photoSource} target="_blank" rel="noopener noreferrer">
                        Photo
                      </a>
                    )}
                    {t.chartmetric_url && (
                      <a className="feed-footer-link feed-footer-link-chartmetric" href={t.chartmetric_url} target="_blank" rel="noopener noreferrer" title={t.velocity_check_status ? `Velocity: ${t.velocity_check_status}` : "Check 7-day velocity on Chartmetric"}>
                        Chartmetric ↗
                      </a>
                    )}
                  </div>
                  <div className="feed-card-actions">
                    <div className="tag-buttons" role="group" aria-label="Tag this target">
                      {["Pursue", "Watch", "Skip"].map((tg) => (
                        <button
                          key={tg}
                          type="button"
                          className={`tag-btn tag-${tg.toLowerCase()} ${tags[t.name] === tg ? "tag-active" : ""}`}
                          onClick={() => setTag(t.name, tg)}
                          title={tags[t.name] === tg ? `Clear ${tg} tag` : `Mark ${tg}`}
                        >
                          {tg === "Pursue" ? "🎯" : tg === "Watch" ? "👁" : "⏭"}
                        </button>
                      ))}
                    </div>
                    <button
                      className={`btn feed-add-btn ${onRoster ? "btn-ghost on-roster" : "btn-primary"}`}
                      onClick={() => !onRoster && addToScouting(t)}
                      disabled={onRoster}
                    >
                      {onRoster ? "On roster ✓" : (<><Icon.plus /> Add</>)}
                    </button>
                  </div>
                </div>
              </article>
            );
          })}
        </section>
      )}
    </>
  );
}

/* ---------- Established (already at tier-1: CAA / WME / UTA) ---------- */
function Established() {
  const list = window.ESTABLISHED || [];
  return (
    <>
      <div className="targets-header">
        <div className="targets-header-left">
          <h1 className="targets-title">Established <span className="targets-title-count">{list.length}</span></h1>
          <p className="targets-subtitle">Tracked for reference. Already signed at CAA, WME, or UTA.</p>
        </div>
      </div>

      {list.length === 0 ? (
        <div className="crm-empty">
          <h3>Nothing here yet</h3>
          <p>When a target turns up already signed to CAA, WME, or UTA, the weekly scan moves them here so we can keep tracking without confusing them with active pursuit.</p>
        </div>
      ) : (
        <section className="targets-grid">
          {list.map((t) => {
            const socialUrl = firstUrl(t.social_or_link);
            const sourceUrl = firstUrl(t.source_url);
            const videoUrl = t.youtube_id
              ? `https://www.youtube.com/watch?v=${t.youtube_id}`
              : t.video_url || "";
            const primaryUrl = videoUrl || socialUrl || sourceUrl || "";
            const primaryLabel = videoUrl
              ? "Watch performance"
              : socialUrl
              ? "View profile"
              : sourceUrl
              ? "Read source"
              : "";
            const photoSource = t.photo_source_page;
            const Inner = (
              <>
                <div className="feed-card-media">
                  <TargetPhotoSquare target={t} />
                  <span className="target-pill feed-pill pill-established">Established</span>
                </div>
                <div className="feed-card-body">
                  <div className="feed-card-name-row">
                    <h3 className="feed-card-name">{t.name}</h3>
                  </div>
                  <div className="feed-card-meta">
                    <span>{t.discipline}</span>
                    {t.age_or_birth_year && <span> · {t.age_or_birth_year}</span>}
                  </div>
                  {t.representation && (
                    <div className="rep-badge rep-signed" title={`Representation: ${t.representation}`}>
                      ● {t.representation}
                    </div>
                  )}
                  <p className="feed-card-why">{t.why_they_matter}</p>
                  {primaryUrl && <div className="feed-card-primary-hint">{primaryLabel} ↗</div>}
                </div>
              </>
            );
            return (
              <article key={t.id} className="feed-card feed-card-readonly">
                {primaryUrl ? (
                  <a
                    className="feed-card-link"
                    href={primaryUrl}
                    target="_blank"
                    rel="noopener noreferrer"
                    aria-label={`${primaryLabel} for ${t.name}`}
                  >
                    {Inner}
                  </a>
                ) : (
                  <div className="feed-card-link feed-card-nolink">{Inner}</div>
                )}
                <div className="feed-card-footer">
                  <div className="feed-card-footer-links">
                    {videoUrl && socialUrl && (
                      <a className="feed-footer-link" href={socialUrl} target="_blank" rel="noopener noreferrer">
                        Profile
                      </a>
                    )}
                    {(videoUrl || socialUrl) && sourceUrl && (
                      <a className="feed-footer-link" href={sourceUrl} target="_blank" rel="noopener noreferrer">
                        Source
                      </a>
                    )}
                    {photoSource && (
                      <a className="feed-footer-link feed-footer-link-faint" href={photoSource} target="_blank" rel="noopener noreferrer">
                        Photo
                      </a>
                    )}
                    {t.chartmetric_url && (
                      <a className="feed-footer-link feed-footer-link-chartmetric" href={t.chartmetric_url} target="_blank" rel="noopener noreferrer" title={t.velocity_check_status ? `Velocity: ${t.velocity_check_status}` : "Check 7-day velocity on Chartmetric"}>
                        Chartmetric ↗
                      </a>
                    )}
                  </div>
                </div>
              </article>
            );
          })}
        </section>
      )}
    </>
  );
}

/* ---------- Ranking page ---------- */
// Shows the scoring formula from rescore.js so Sharon can see exactly how each
// target's score is computed. Mirrors the logic in rescore.js verbatim; if that
// file changes, this page should be updated to match.
function Ranking() {
  const targets = window.TARGETS || [];

  // ---- Distribution buckets (mirrors rescore.js) ----
  const buckets = useMemo(() => {
    const b = { "110+": 0, "100-109": 0, "90-99": 0, "80-89": 0, "70-79": 0, "60-69": 0, "50-59": 0, "40-49": 0, "<40": 0 };
    targets.forEach((t) => {
      const s = t.score || 0;
      if (s >= 110) b["110+"]++;
      else if (s >= 100) b["100-109"]++;
      else if (s >= 90) b["90-99"]++;
      else if (s >= 80) b["80-89"]++;
      else if (s >= 70) b["70-79"]++;
      else if (s >= 60) b["60-69"]++;
      else if (s >= 50) b["50-59"]++;
      else if (s >= 40) b["40-49"]++;
      else b["<40"]++;
    });
    return b;
  }, [targets]);

  const maxBucket = Math.max(...Object.values(buckets), 1);

  const top10 = useMemo(
    () => [...targets].sort((a, b) => (b.score || 0) - (a.score || 0)).slice(0, 10),
    [targets]
  );

  return (
    <>
      <section className="discovery-hero hero-compact">
        <h1 className="hero-title-sm">
          Ranking <span className="hero-count">scoring formula</span>
        </h1>
        <p className="hero-sub">
          How every target's score is calculated. The formula is intentionally biased toward
          pre-stamp catches — younger, music-leaning, with original output or viral signal,
          and lighter on heavy institutional decoration.
        </p>
      </section>

      <div style={{ maxWidth: 1100, margin: "0 auto", padding: "0 1.5rem 4rem" }}>
        {/* Philosophy */}
        <section style={{ marginTop: "2rem" }}>
          <h2 style={{ fontSize: "1.25rem", marginBottom: "0.5rem" }}>Philosophy</h2>
          <p style={{ color: "var(--muted)", lineHeight: 1.6 }}>
            Catch pre-output / pre-stamp kids, not institutionally-decorated tracks. Music is the strategic priority (Renée Rapp anchor). Younger = more leverage (longer signing window). Heavy institutional decoration is validation, not upside — cap it. Unrepped + active output = the catch zone.
          </p>
        </section>

        {/* The formula */}
        <section style={{ marginTop: "2rem" }}>
          <h2 style={{ fontSize: "1.25rem", marginBottom: "0.5rem" }}>The formula</h2>
          <div style={{ background: "var(--card)", border: "1px solid var(--border)", borderRadius: 12, padding: "1.25rem", fontFamily: "ui-monospace, monospace", fontSize: "0.9rem", lineHeight: 1.7, overflowX: "auto" }}>
            final_score = round(base × age_multiplier × discipline_multiplier)<br/>
            <span style={{ color: "var(--muted)" }}>// then clamped to [0, 120]</span>
          </div>
        </section>

        {/* Base score */}
        <section style={{ marginTop: "2rem" }}>
          <h2 style={{ fontSize: "1.25rem", marginBottom: "0.75rem" }}>Base score</h2>
          <p style={{ color: "var(--muted)", marginBottom: "0.75rem" }}>Everyone starts at <strong>30</strong>. Adjustments below.</p>
          <table style={{ width: "100%", borderCollapse: "collapse", fontSize: "0.92rem" }}>
            <thead>
              <tr style={{ background: "var(--card)", textAlign: "left" }}>
                <th style={{ padding: "0.5rem 0.75rem", border: "1px solid var(--border)" }}>Adjustment</th>
                <th style={{ padding: "0.5rem 0.75rem", border: "1px solid var(--border)", width: 110 }}>Δ</th>
                <th style={{ padding: "0.5rem 0.75rem", border: "1px solid var(--border)" }}>What it captures</th>
              </tr>
            </thead>
            <tbody>
              <tr><td style={cellSty}>Institutional signals × 5 (capped at 25)</td><td style={cellSty}>+0 to +25</td><td style={cellMuted}>YoungArts (esp. Winner with Distinction), Jimmy Awards, Presidential Scholar, regional MT awards (Tommy Tune / Roger Rees / Blumey / Sutton Foster / Bobby G / Helen Hayes), Broadway / national tour credits, album / debut single, Sundance / Tribeca / SXSW / NFFTY shorts, Billboard / Rolling Stone / Spotify RADAR / Apple Up Next, Latin Grammy BNA / Premios Juventud. One point per match, capped at 5 hits.</td></tr>
              <tr><td style={cellSty}>Original output</td><td style={cellPlus}>+12</td><td style={cellMuted}>Self-released / debut single / debut EP / debut album / songwriter / writes own — the Bieber / Eilish signal. Strongest catch indicator for music.</td></tr>
              <tr><td style={cellSty}>Viral / social signal</td><td style={cellPlus}>+10</td><td style={cellMuted}>Numerical followers/views/streams in millions, or the words "viral" / "TikTok" with output context.</td></tr>
              <tr><td style={cellSty}>MT breakout</td><td style={cellPlus}>+10</td><td style={cellMuted}>For Musical Theater / Theater only. Jimmy Awards top 8 / finalist / winner / Best Actor / Best Actress, Sutton Foster Ovation winner, Tommy Tune winner, Roger Rees winner, Blumey winner, Broadway originating / principal / featured, Outer Critics Circle, Drama Desk.</td></tr>
              <tr><td style={cellSty}>Acting breakout</td><td style={cellPlus}>+10</td><td style={cellMuted}>For Acting / Film only. Trade-announced (Deadline / Variety / THR / TVLine), recurring or series-regular, Disney Channel pilot, Disney+ / Netflix / HBO / Amazon series cast, breakout role / guest star.</td></tr>
              <tr><td style={cellSty}>Comedy breakout</td><td style={cellPlus}>+10</td><td style={cellMuted}>For Comedy only. Tim Robinson / ITYSL / Cole Escola / Oh Mary / Nathan Fielder / The Rehearsal / The Curse cast credit, JFL New Faces, SNL writer or cast, late-night writers room.</td></tr>
              <tr><td style={cellSty}>Heavy institutional decoration</td><td style={cellMinus}>−3</td><td style={cellMuted}>3+ institutional stamps means industry already noticed. v3 softened from −5 → −3 so legitimate Jimmy / YoungArts targets aren't punished out of the top 50.</td></tr>
              <tr><td style={cellSty}>Pre-teen (&lt; 11)</td><td style={cellMinus}>−10</td><td style={cellMuted}>Kids under 11 are real but not as actionable. Counterweight to the ≤13 age bonus so the top isn't swept by 9-year-olds.</td></tr>
              <tr><td style={cellSty}>Photo + video</td><td style={cellPlus}>+4</td><td style={cellMuted}>Quality-of-entry indicator. Photo only = +2.</td></tr>
              <tr><td style={cellSty}>Freshness (added in last 8 weeks)</td><td style={cellPlus}>+4</td><td style={cellMuted}>Bias toward recent finds so the cron's new entries surface fast.</td></tr>
              <tr><td style={cellSty}>Representation — CAA / WME / UTA</td><td style={cellMinus}>−30</td><td style={cellMuted}>Shouldn't be in targets at all (routed to Established). Defense-in-depth penalty.</td></tr>
              <tr><td style={cellSty}>Representation — Gersh / Paradigm / Innovative / CESD / Buchwald / A3</td><td style={cellMinus}>−10</td><td style={cellMuted}>Mid-tier already-signed. Less room to add value.</td></tr>
              <tr><td style={cellSty}>Representation — any management</td><td style={cellMinus}>−5</td><td style={cellMuted}>Any rep at all = slight reduction.</td></tr>
            </tbody>
          </table>
        </section>

        {/* Age multiplier */}
        <section style={{ marginTop: "2rem" }}>
          <h2 style={{ fontSize: "1.25rem", marginBottom: "0.75rem" }}>Age multiplier</h2>
          <p style={{ color: "var(--muted)", marginBottom: "0.75rem" }}>Younger = more leverage (longer signing window before tier-1 agencies arrive).</p>
          <table style={{ width: "100%", borderCollapse: "collapse", fontSize: "0.92rem" }}>
            <thead>
              <tr style={{ background: "var(--card)", textAlign: "left" }}>
                <th style={{ padding: "0.5rem 0.75rem", border: "1px solid var(--border)" }}>Age</th>
                <th style={{ padding: "0.5rem 0.75rem", border: "1px solid var(--border)", width: 100 }}>×</th>
              </tr>
            </thead>
            <tbody>
              <tr><td style={cellSty}>≤ 13 (catch window — highest leverage)</td><td style={cellPlus}>× 1.50</td></tr>
              <tr><td style={cellSty}>14 – 16</td><td style={cellPlus}>× 1.30</td></tr>
              <tr><td style={cellSty}>17 – 18</td><td style={cellPlus}>× 1.10</td></tr>
              <tr><td style={cellSty}>19 – 22</td><td style={cellMinus}>× 0.95</td></tr>
              <tr><td style={cellSty}>23+ (past prime catch window)</td><td style={cellMinus}>× 0.80</td></tr>
              <tr><td style={cellSty}>Unknown</td><td style={cellSty}>× 1.00</td></tr>
            </tbody>
          </table>
        </section>

        {/* Discipline multiplier */}
        <section style={{ marginTop: "2rem" }}>
          <h2 style={{ fontSize: "1.25rem", marginBottom: "0.75rem" }}>Discipline multiplier</h2>
          <p style={{ color: "var(--muted)", marginBottom: "0.75rem" }}>v3 rebalance (2026-05-25) softened the music lean so non-singers stay visible in the top 20.</p>
          <table style={{ width: "100%", borderCollapse: "collapse", fontSize: "0.92rem" }}>
            <thead>
              <tr style={{ background: "var(--card)", textAlign: "left" }}>
                <th style={{ padding: "0.5rem 0.75rem", border: "1px solid var(--border)" }}>Discipline</th>
                <th style={{ padding: "0.5rem 0.75rem", border: "1px solid var(--border)", width: 100 }}>×</th>
              </tr>
            </thead>
            <tbody>
              <tr><td style={cellSty}>Music</td><td style={cellPlus}>× 1.20</td></tr>
              <tr><td style={cellSty}>Comedy</td><td style={cellPlus}>× 1.15</td></tr>
              <tr><td style={cellSty}>Acting</td><td style={cellPlus}>× 1.10</td></tr>
              <tr><td style={cellSty}>Musical Theater / Theater / Film</td><td style={cellPlus}>× 1.05</td></tr>
              <tr><td style={cellSty}>Other</td><td style={cellSty}>× 1.00</td></tr>
              <tr><td style={cellSty}>Dance</td><td style={cellMinus}>× 0.90</td></tr>
            </tbody>
          </table>
        </section>

        {/* Distribution */}
        <section style={{ marginTop: "2rem" }}>
          <h2 style={{ fontSize: "1.25rem", marginBottom: "0.75rem" }}>Current distribution ({targets.length} targets)</h2>
          <div style={{ background: "var(--card)", border: "1px solid var(--border)", borderRadius: 12, padding: "1rem" }}>
            {Object.entries(buckets).map(([range, count]) => (
              <div key={range} style={{ display: "flex", alignItems: "center", gap: "0.75rem", marginBottom: "0.4rem" }}>
                <div style={{ width: 76, fontFamily: "ui-monospace, monospace", fontSize: "0.85rem", color: "var(--muted)" }}>{range}</div>
                <div style={{ flex: 1, background: "var(--border)", height: 18, borderRadius: 4, overflow: "hidden" }}>
                  <div style={{ width: `${(count / maxBucket) * 100}%`, height: "100%", background: "var(--accent, #4f46e5)" }}></div>
                </div>
                <div style={{ width: 36, textAlign: "right", fontFamily: "ui-monospace, monospace", fontSize: "0.85rem" }}>{count}</div>
              </div>
            ))}
          </div>
        </section>

        {/* Top 10 */}
        <section style={{ marginTop: "2rem" }}>
          <h2 style={{ fontSize: "1.25rem", marginBottom: "0.75rem" }}>Top 10 right now</h2>
          <table style={{ width: "100%", borderCollapse: "collapse", fontSize: "0.92rem" }}>
            <thead>
              <tr style={{ background: "var(--card)", textAlign: "left" }}>
                <th style={{ padding: "0.5rem 0.75rem", border: "1px solid var(--border)", width: 36 }}>#</th>
                <th style={{ padding: "0.5rem 0.75rem", border: "1px solid var(--border)" }}>Name</th>
                <th style={{ padding: "0.5rem 0.75rem", border: "1px solid var(--border)" }}>Discipline</th>
                <th style={{ padding: "0.5rem 0.75rem", border: "1px solid var(--border)", width: 70 }}>Score</th>
              </tr>
            </thead>
            <tbody>
              {top10.map((t, i) => (
                <tr key={t.id}>
                  <td style={cellSty}>{i + 1}</td>
                  <td style={cellSty}>{t.name}</td>
                  <td style={cellMuted}>{t.discipline}</td>
                  <td style={{ ...cellSty, fontFamily: "ui-monospace, monospace", fontWeight: 600 }}>{t.score}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </section>

        {/* Footnote */}
        <section style={{ marginTop: "2rem", color: "var(--muted)", fontSize: "0.85rem", lineHeight: 1.6 }}>
          <p>Scores are recomputed by running <code>node rescore.js</code> in the project, then <code>node rescore.js --commit</code> to write them back to targets.js. The formula lives in <code>/talent-scout/rescore.js</code> — if it changes, this page should be updated to match.</p>
          <p>Score cap raised from 100 → 120 on 2026-05-25 (v2 fix) so genuinely explosive cases separate from merely-strong ones.</p>
        </section>
      </div>
    </>
  );
}

const cellSty = { padding: "0.5rem 0.75rem", border: "1px solid var(--border)", verticalAlign: "top" };
const cellMuted = { ...cellSty, color: "var(--muted)" };
const cellPlus = { ...cellSty, color: "#15803d", fontFamily: "ui-monospace, monospace", fontWeight: 600 };
const cellMinus = { ...cellSty, color: "#b91c1c", fontFamily: "ui-monospace, monospace", fontWeight: 600 };

function App() {
  const [tab, setTab] = useState("targets");
  const [presetDiscoveryTags, setPresetDiscoveryTags] = useState(null);
  const [focusTargetId, setFocusTargetId] = useState(null);
  const goToTarget = (id) => {
    setFocusTargetId(id);
    setTab("targets");
  };
  const [theme, setTheme] = useState(() =>
    window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
  );
  const [activeFestival, setActiveFestival] = useState(null);
  const [talents, setTalents] = useState([]);
  const [activeTalent, setActiveTalent] = useState(null);
  const [prefillSource, setPrefillSource] = useState(null);
  const [showAddForm, setShowAddForm] = useState(false);

  useEffect(() => {
    document.documentElement.setAttribute("data-theme", theme);
  }, [theme]);

  const toggleTheme = () => setTheme((t) => (t === "dark" ? "light" : "dark"));

  const addTalent = (t) => setTalents((prev) => [...prev, t]);

  const rosterTargetIds = useMemo(
    () => new Set(talents.filter((t) => t._targetId).map((t) => t._targetId)),
    [talents]
  );

  const addTargetToScouting = (target) => {
    const ageMatch = (target.age_or_birth_year || "").match(/\b(1[3-9]|2[0-5])\b/);
    const age = ageMatch ? ageMatch[1] : "";
    const newTalent = {
      id: `tt-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
      _targetId: target.id,
      name: target.name,
      age,
      discipline: target.discipline || "",
      location: "",
      sourceName: stripMarkdownLink(target.channel) || "Targets pipeline",
      sourceCountry: "",
      notes: target.why_they_matter || "",
      contact: stripMarkdownLink(target.contact_path) || "",
      sources: [target.social_or_link, target.source_url].filter(Boolean).join("\n"),
      status: "spotted",
      createdAt: Date.now(),
    };
    addTalent(newTalent);
  };
  const updateTalent = (t) =>
    setTalents((prev) => prev.map((x) => (x.id === t.id ? t : x)));
  const removeTalent = (id) =>
    setTalents((prev) => prev.filter((x) => x.id !== id));

  const onAddTalentFromFestival = (festival) => {
    setPrefillSource({ name: festival.name, country: festival.country });
    setShowAddForm(true);
    setTab("scout");
  };

  return (
    <div className="app">
      <Header
        tab={tab}
        setTab={setTab}
        scoutCount={talents.length}
        theme={theme}
        toggleTheme={toggleTheme}
      />
      {tab === "discover" && (
        <Discovery
          openFestival={setActiveFestival}
          presetTags={presetDiscoveryTags}
          consumePresetTags={() => setPresetDiscoveryTags(null)}
          goToTarget={goToTarget}
        />
      )}
      {tab === "calendar" && <FeederCalendar />}
      {tab === "pathways" && (
        <Pathways
          goToDiscovery={(tags) => {
            setPresetDiscoveryTags(tags);
            setTab("discover");
          }}
        />
      )}
      {tab === "targets" && (
        <Targets
          rosterIds={rosterTargetIds}
          addToScouting={addTargetToScouting}
          focusTargetId={focusTargetId}
          consumeFocusTargetId={() => setFocusTargetId(null)}
        />
      )}
      {tab === "established" && <Established />}
      {tab === "ranking" && <Ranking />}
      {tab === "scout" && (
        <Scouting
          talents={talents}
          addTalent={addTalent}
          updateTalent={updateTalent}
          removeTalent={removeTalent}
          openTalent={setActiveTalent}
        />
      )}

      {activeFestival && (
        <FestivalModal
          festival={activeFestival}
          onClose={() => setActiveFestival(null)}
          onAddTalent={onAddTalentFromFestival}
        />
      )}

      {activeTalent && (
        <TalentModal
          talent={activeTalent}
          onClose={() => setActiveTalent(null)}
          onUpdate={(t) => {
            updateTalent(t);
            setActiveTalent(t);
          }}
          onRemove={removeTalent}
        />
      )}

      {showAddForm && (
        <AddTalentModal
          prefillSource={prefillSource}
          onClose={() => {
            setShowAddForm(false);
            setPrefillSource(null);
          }}
          onSave={(t) => {
            addTalent(t);
            setShowAddForm(false);
            setPrefillSource(null);
          }}
        />
      )}
    </div>
  );
}

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