const { useState: useState2, useEffect: useEffect2, useRef: useRef2, useCallback: useCallback2 } = React;

// ---------- FactoryFix left rail (from prototype-template.html spec) ----------
function FFRail({ active = "search" }) {
  const I = {
    bell: <svg viewBox="0 0 25 24"><path d="M15.4997 19C15.4997 20.6569 14.1566 22 12.4997 22C10.8429 22 9.49972 20.6569 9.49972 19M18.4997 11.2C18.4997 9.82087 17.8676 8.49823 16.7424 7.52304C15.6171 6.54786 14.091 6 12.4997 6C10.9084 6 9.3823 6.54786 8.25708 7.52304C7.13186 8.49823 6.49972 9.82087 6.49972 11.2C6.49972 13.4818 5.93385 15.1506 5.22778 16.3447C4.42306 17.7056 4.0207 18.3861 4.03659 18.5486C4.05476 18.7346 4.08824 18.7933 4.23906 18.9036C4.37089 19 5.03323 19 6.35791 19H18.6415C19.9662 19 20.6286 19 20.7604 18.9036C20.9112 18.7933 20.9447 18.7346 20.9629 18.5486C20.9787 18.3861 20.5764 17.7056 19.7717 16.3447C19.0656 15.1506 18.4997 13.4818 18.4997 11.2Z"/></svg>,
    jobs: <svg viewBox="0 0 24 24"><path d="M16 7C16 6.07003 16 5.60504 15.8978 5.22354C15.6204 4.18827 14.8117 3.37962 13.7765 3.10222C13.395 3 12.93 3 12 3C11.07 3 10.605 3 10.2235 3.10222C9.18827 3.37962 8.37962 4.18827 8.10222 5.22354C8 5.60504 8 6.07003 8 7M5.2 21H18.8C19.9201 21 20.4802 21 20.908 20.782C21.2843 20.5903 21.5903 20.2843 21.782 19.908C22 19.4802 22 18.9201 22 17.8V10.2C22 9.07989 22 8.51984 21.782 8.09202C21.5903 7.71569 21.2843 7.40973 20.908 7.21799C20.4802 7 19.9201 7 18.8 7H5.2C4.07989 7 3.51984 7 3.09202 7.21799C2.71569 7.40973 2.40973 7.71569 2.21799 8.09202C2 8.51984 2 9.07989 2 10.2V17.8C2 18.9201 2 19.4802 2.21799 19.908C2.40973 20.2843 2.71569 20.5903 3.09202 20.782C3.51984 21 4.0799 21 5.2 21Z"/></svg>,
    candidates: <svg viewBox="0 0 24 24"><path d="M14 23C14.5523 23 15 22.5523 15 22C15 21.4477 14.5523 21 14 21V23ZM11.0635 5.58267L10.358 6.29134L11.0635 5.58267ZM3 20V7H1V20H3ZM4 6H9.65242V4H4V6ZM10.358 6.29134L11.7962 7.72321L13.2073 6.30588L11.7691 4.87401L10.358 6.29134ZM13.9128 8.59722H22V6.59722H13.9128V8.59722ZM14 21H4V23H14V21ZM11.7962 7.72321C12.3584 8.28296 13.1194 8.59722 13.9128 8.59722V6.59722C13.6483 6.59722 13.3947 6.49247 13.2073 6.30588L11.7962 7.72321ZM9.65242 6C9.91687 6 10.1706 6.10475 10.358 6.29134L11.7691 4.87401C11.2068 4.31426 10.4458 4 9.65242 4V6ZM3 7C3 6.44772 3.44772 6 4 6V4C2.34315 4 1 5.34315 1 7H3ZM1 20C1 21.6569 2.34315 23 4 23V21C3.44772 21 3 20.5523 3 20H1Z" fill="currentColor" stroke="none"/><path d="M21 12C21 12.5523 21.4477 13 22 13C22.5523 13 23 12.5523 23 12H21ZM13.1537 3.75055L12.4729 4.48297L13.1537 3.75055ZM11.8463 2.53516L12.5271 1.80274L11.8463 2.53516ZM4 6V4H2V6H4ZM5 3H10.4846V1H5V3ZM11.1654 3.26758L12.4729 4.48297L13.8346 3.01813L12.5271 1.80274L11.1654 3.26758ZM14.5154 5.28571H20V3.28571H14.5154V5.28571ZM21 6.28571V12H23V6.28571H21ZM20 5.28571C20.5523 5.28571 21 5.73343 21 6.28571H23C23 4.62886 21.6569 3.28571 20 3.28571V5.28571ZM12.4729 4.48297C13.0279 4.99892 13.7576 5.28571 14.5154 5.28571V3.28571C14.2628 3.28571 14.0196 3.19012 13.8346 3.01813L12.4729 4.48297ZM10.4846 3C10.7372 3 10.9804 3.0956 11.1654 3.26758L12.5271 1.80274C11.9721 1.28679 11.2424 1 10.4846 1V3ZM4 4C4 3.44772 4.44772 3 5 3V1C3.34315 1 2 2.34315 2 4H4Z" fill="currentColor" stroke="none"/><path d="M20 19.5L22.5 22"/><circle cx="18.5" cy="17.5" r="2.5"/></svg>,
    search: <svg viewBox="0 0 24 24"><path d="M12 15H8C6.13623 15 5.20435 15 4.46927 15.3045C3.48915 15.7105 2.71046 16.4892 2.30448 17.4693C2 18.2044 2 19.1362 2 21M13.5 7C13.5 9.20914 11.7091 11 9.5 11C7.29086 11 5.5 9.20914 5.5 7C5.5 4.79086 7.29086 3 9.5 3C11.7091 3 13.5 4.79086 13.5 7Z"/><path d="M19 18.5L21.5 21"/><circle cx="17.5" cy="16.5" r="2.5"/></svg>,
    dashboard: <svg viewBox="0 0 24 24"><path d="M17.2 14C17.477 14 17.6155 14 17.7278 14.0615C17.8204 14.1122 17.9065 14.2075 17.9478 14.3047C17.9978 14.4225 17.9852 14.5479 17.96 14.7987C17.8296 16.0987 17.3822 17.3514 16.6518 18.4445C15.7727 19.7601 14.5233 20.7855 13.0615 21.391C11.5997 21.9965 9.99113 22.155 8.43928 21.8463C6.88743 21.5376 5.46197 20.7757 4.34315 19.6568C3.22433 18.538 2.4624 17.1126 2.15372 15.5607C1.84504 14.0089 2.00347 12.4003 2.60897 10.9385C3.21447 9.47671 4.23985 8.22728 5.55544 7.34823C6.64856 6.61783 7.90125 6.17039 9.20131 6.03995C9.45207 6.01479 9.57745 6.00221 9.69528 6.0522C9.79249 6.09344 9.88776 6.17964 9.9385 6.27224C10 6.38449 10 6.52299 10 6.79999V13.2C10 13.48 10 13.62 10.0545 13.727C10.1024 13.8211 10.1789 13.8976 10.273 13.9455C10.38 14 10.52 14 10.8 14H17.2Z"/><path d="M14 2.79999C14 2.52298 14 2.38448 14.0615 2.27223C14.1122 2.17963 14.2075 2.09344 14.3047 2.0522C14.4225 2.0022 14.5479 2.01478 14.7987 2.03993C16.6271 2.22333 18.346 3.03229 19.6569 4.34313C20.9677 5.65398 21.7767 7.37289 21.9601 9.20129C21.9852 9.45206 21.9978 9.57744 21.9478 9.69527C21.9066 9.79248 21.8204 9.88774 21.7278 9.93848C21.6155 9.99998 21.477 9.99999 21.2 9.99999L14.8 9.99999C14.52 9.99999 14.38 9.99999 14.273 9.94549C14.1789 9.89755 14.1024 9.82106 14.0545 9.72698C14 9.62003 14 9.48001 14 9.19999V2.79999Z"/></svg>,
    reports: <svg viewBox="0 0 24 24"><path d="M18 12C20 10 22 8.20914 22 6C22 3.79086 20.2091 2 18 2C15.7909 2 14 3.79086 14 6C14 8.20914 16 10 18 12Z"/><circle cx="18" cy="6" r="1" fill="currentColor"/><path d="M2 4C2 2.89543 2.89543 2 4 2H6C7.10457 2 8 2.89543 8 4V22H2V4Z"/><path d="M8 14C8 12.8954 8.89543 12 10 12H12C13.1046 12 14 12.8954 14 14V22H8V14Z"/><path d="M14 19C14 17.8954 14.8954 17 16 17H18C19.1046 17 20 17.8954 20 19V22H14V19Z"/></svg>,
    aiTeam: <svg viewBox="0 0 24 24"><path d="M12 15H8C6.13623 15 5.20435 15 4.46927 15.3045C3.48915 15.7105 2.71046 16.4892 2.30448 17.4693C2 18.2044 2 19.1362 2 21M15.5 3.29076C16.9659 3.88415 18 5.32131 18 7C18 8.67869 16.9659 10.1159 15.5 10.7092M13.5 7C13.5 9.20914 11.7091 11 9.5 11C7.29086 11 5.5 9.20914 5.5 7C5.5 4.79086 7.29086 3 9.5 3C11.7091 3 13.5 4.79086 13.5 7Z"/><path d="M20.3643 11.0513C20.4355 11.0939 20.4905 11.1601 20.5205 11.2391C20.5505 11.3181 20.5536 11.4052 20.5294 11.4863L19.2196 15.8751H21.6362C21.7073 15.875 21.7767 15.8964 21.8361 15.9367C21.8954 15.9769 21.9421 16.0341 21.9702 16.1014C21.9984 16.1686 22.0068 16.2429 21.9945 16.315C21.9822 16.3871 21.9497 16.454 21.9009 16.5073L16.083 22.8819C16.0267 22.9436 15.9518 22.9839 15.8705 22.9961C15.7891 23.0083 15.7062 22.9917 15.6352 22.9491C15.5642 22.9065 15.5092 22.8403 15.4794 22.7614C15.4495 22.6824 15.4464 22.5954 15.4706 22.5144L16.7804 18.1249H14.3638C14.2927 18.125 14.2233 18.1035 14.1639 18.0633C14.1046 18.0231 14.0579 17.9658 14.0298 17.8986C14.0016 17.8314 13.9932 17.7571 14.0055 17.685C14.0178 17.6128 14.0503 17.546 14.0991 17.4927L19.917 11.1181C19.9732 11.0564 20.048 11.0162 20.1292 11.004C20.2104 10.9917 20.2933 11.0088 20.3643 11.0513Z" fill="currentColor" stroke="none"/><path d="M22 20L22.5374 21.4626L24 22L22.5374 22.5374L22 24L21.4626 22.5374L20 22L21.4626 21.4626L22 20Z" fill="currentColor" stroke="none"/></svg>,
    referral: <svg viewBox="0 0 24 24"><path d="M12 6V22M12 6H8.46429C7.94332 6 7.4437 5.78929 7.07533 5.41421C6.70695 5.03914 6.5 4.53043 6.5 4C6.5 3.46957 6.70695 2.96086 7.07533 2.58579C7.4437 2.21071 7.94332 2 8.46429 2C11.2143 2 12 6 12 6ZM12 6H15.5357C16.0567 6 16.5563 5.78929 16.9247 5.41421C17.293 5.03914 17.5 4.53043 17.5 4C17.5 3.46957 17.293 2.96086 16.9247 2.58579C16.5563 2.21071 16.0567 2 15.5357 2C12.7857 2 12 6 12 6ZM20 11V18.8C20 19.9201 20 20.4802 19.782 20.908C19.5903 21.2843 19.2843 21.5903 18.908 21.782C18.4802 22 17.9201 22 16.8 22L7.2 22C6.07989 22 5.51984 22 5.09202 21.782C4.71569 21.5903 4.40973 21.2843 4.21799 20.908C4 20.4802 4 19.9201 4 18.8V11M2 7.6L2 9.4C2 9.96005 2 10.2401 2.10899 10.454C2.20487 10.6422 2.35785 10.7951 2.54601 10.891C2.75992 11 3.03995 11 3.6 11L20.4 11C20.9601 11 21.2401 11 21.454 10.891C21.6422 10.7951 21.7951 10.6422 21.891 10.454C22 10.2401 22 9.96005 22 9.4V7.6C22 7.03995 22 6.75992 21.891 6.54601C21.7951 6.35785 21.6422 6.20487 21.454 6.10899C21.2401 6 20.9601 6 20.4 6L3.6 6C3.03995 6 2.75992 6 2.54601 6.10899C2.35785 6.20487 2.20487 6.35785 2.10899 6.54601C2 6.75992 2 7.03995 2 7.6Z"/></svg>,
    invite: <svg viewBox="0 0 24 24"><path d="M12 15.5H7.5C6.10444 15.5 5.40665 15.5 4.83886 15.6722C3.56045 16.06 2.56004 17.0605 2.17224 18.3389C2 18.9067 2 19.6044 2 21M19 21V15M16 18H22M14.5 7.5C14.5 9.98528 12.4853 12 10 12C7.51472 12 5.5 9.98528 5.5 7.5C5.5 5.01472 7.51472 3 10 3C12.4853 3 14.5 5.01472 14.5 7.5Z"/></svg>,
    eye: <svg viewBox="0 0 24 24"><path d="M2.42 12.7135C2.28795 12.4975 2.22192 12.3895 2.18348 12.2338C2.15539 12.1215 2.15539 11.8785 2.18348 11.7662C2.22192 11.6105 2.28795 11.5025 2.42 11.2865C3.53529 9.50484 6.8155 5 12 5C17.1845 5 20.4647 9.50484 21.58 11.2865C21.7121 11.5025 21.7781 11.6105 21.8165 11.7662C21.8446 11.8785 21.8446 12.1215 21.8165 12.2338C21.7781 12.3895 21.7121 12.4975 21.58 12.7135C20.4647 14.4952 17.1845 19 12 19C6.8155 19 3.53529 14.4952 2.42 12.7135Z"/><path d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z"/></svg>,
  };
  const items = [
    { key: "jobs",       title: "Manage Jobs",              icon: I.jobs },
    { key: "candidates", title: "Candidate Archive",        icon: I.candidates },
    { key: "search",     title: "FactoryFix Talent Search", icon: I.search },
    { key: "dashboard",  title: "Performance Dashboard",    icon: I.dashboard },
    { key: "reports",    title: "Labor Market Reports",     icon: I.reports },
    { key: "ai-team",    title: "My AI Recruiting Team",    icon: I.aiTeam },
  ];
  return (
    <nav className="ff-rail">
      <div className="ff-rail-top">
        <a href="#" className="ff-rail-logo" title="Home" onClick={(e)=>e.preventDefault()}>
          <svg viewBox="0 0 28 24" fill="none">
            <path d="M27.7142 12L20.8571 24H7.14279L0.285645 12L7.14279 0H20.8571L27.7142 12Z" fill="#53D58B"/>
            <path d="M13.9998 4.28564H18.2855L16.1426 8.14279L17.8569 11.9999H16.1426V19.7142H11.8569V8.14279L13.9998 4.28564Z" fill="#0F172A"/>
          </svg>
        </a>
        <button className="ff-drawer-item mb-2" title="Activity Feed">
          {I.bell}
          <span className="ff-rail-badge">10</span>
        </button>
        {items.map(i => (
          <button
            key={i.key}
            className={"ff-drawer-item" + (i.key === active ? " active" : "")}
            title={i.title}
          >{i.icon}</button>
        ))}
      </div>
      <div className="ff-rail-bottom">
        <div className="ff-slots">
          <span className="label">Job Slots</span>
          <span>14/500</span>
        </div>
        <div className="ff-drawer-bottom-item green" title="Referral">{I.referral}</div>
        <button className="ff-drawer-item mb-2" title="Invite Teammate">{I.invite}</button>
        <button className="ff-drawer-item mb-2" title="Hide sensitive data">{I.eye}</button>
        <div className="ff-user-avatar" title="Account"><div className="av">AR</div></div>
      </div>
    </nav>
  );
}

// ---------- FactoryFix insights (candidate-memory signals from dossiers) ----------
// Candidate-stated or behavioral facts from prior FactoryFix interactions.
// Deliberately NOT job-fit claims — see pitch No-Gos.
// Display rules (RoboScop Option 2): drop low-confidence / non-displayable, cap at 3.
function displayableInsights(c) {
  return (c.insights || []).filter(s => s.confidence !== "low" && s.displayable !== false).slice(0, 3);
}

const BASIS_LABEL = {
  stated: "Stated by candidate",
  conversation: "From candidate history",
  inferred: "Inferred",
  estimated: "Estimated",
  application_behavior: "From application activity",
};

function InsightChip({ s }) {
  const basis = BASIS_LABEL[s.basis] || "";
  const dateText = /\d{4}/.test(s.date) ? (s.stale ? "last seen " + s.date + " — may be outdated" : "last confirmed " + s.date) : s.date;
  return (
    <span className={"ins-chip" + (s.dealbreaker ? " negative" : "") + (s.conditional ? " conditional" : "") + (s.stale ? " stale" : "")} tabIndex={0}>
      <Icon name={s.icon} size={13} />
      <span>{s.text}</span>
      {s.basis === "estimated" && <span className="ins-est">(est.)</span>}
      {s.conditional && <span className="ins-cond-tag">· conditional</span>}
      {s.stale && <span className="ins-stale-note">· {s.date.replace(/ \d+,/, "")}</span>}
      <span className="ins-tip">{basis ? basis + " · " : ""}{dateText}</span>
    </span>
  );
}

function InsightsBlock({ insights, labelMode = "icon" }) {
  return (
    <div className="ins-block">
      {labelMode === "full" && <div className="ins-label"><Icon name="spark" size={11} /> FactoryFix insights</div>}
      <div className="ins-chips">
        {labelMode === "icon" && <span className="ins-marker" title="FactoryFix insights"><Icon name="spark" size={14} /></span>}
        {insights.map((s, i) => <InsightChip key={i} s={s} />)}
      </div>
    </div>
  );
}

function InsightsBand({ insights }) {
  const fresh = insights.filter((s) => !s.stale && s.date.includes(","));
  const dateLabel = fresh.length
    ? "Last confirmed " + fresh[0].date.replace(/ \d+,/, "")
    : "From " + insights[0].date.replace(/ \d+,/, "") + " — may be outdated";
  return (
    <div className="ins-band">
      <span className="ins-band-spark"><Icon name="spark" size={13} /></span>
      <span>
        <span className="ins-band-lead">FactoryFix insights:</span>{" "}
        {insights.map((s, i) => (
          <React.Fragment key={i}>
            {i > 0 && <span className="ins-band-sep">·</span>}
            <span className={"ins-band-item" + (s.dealbreaker ? " negative" : "") + (s.stale ? " stale" : "")}>
              {s.text.charAt(0).toLowerCase() + s.text.slice(1)}{s.basis === "estimated" ? " (est.)" : ""}
            </span>
          </React.Fragment>
        ))}
      </span>
      <span className="ins-band-date">{dateLabel}</span>
    </div>
  );
}

// ---------- Candidate card ----------
function Card({ c, isSmart, activeQuery, expanded, onToggle, onSkip, skipped, animatingOut, unlocked, onUnlock, onAddToJob, onMessage, signalStyle, insightsLabel }) {
  const [jobPopOpen, setJobPopOpen] = useState2(false);
  const [insightsOpen, setInsightsOpen] = useState2(false);
  const popRef = useRef2(null);
  const ins = signalStyle !== "hidden" ? displayableInsights(c) : [];
  const hasIns = ins.length > 0;

  useEffect2(() => {
    const onClick = (e) => { if (popRef.current && !popRef.current.contains(e.target)) setJobPopOpen(false); };
    document.addEventListener("mousedown", onClick);
    return () => document.removeEventListener("mousedown", onClick);
  }, []);

  const firstWork = c.workExperience[0];
  const restWork = c.workExperience.slice(1);
  const firstEdu = c.education[0];
  const restEdu = c.education.slice(1);

  return (
    <div
      className={
        "card" +
        (expanded ? " expanded" : "") +
        (skipped ? " skipped" : "") +
        (animatingOut ? " animating-out" : "")
      }
      onClick={onToggle}
    >
      <div className="card-head">
        <div className="card-id">
          <span className="card-name">{c.name}</span>
          <span className="card-active">Active {c.active}</span>
          {isSmart && c.smartRank === 1 && (
            <span className="match-pill top-match">
              <Icon name="spark" size={10} />
              Top match
            </span>
          )}
          {hasIns && signalStyle === "pill" && (
            <button
              className={"ins-pill" + (insightsOpen ? " open" : "")}
              onClick={(e) => { e.stopPropagation(); setInsightsOpen(!insightsOpen); }}
              aria-expanded={insightsOpen}
            >
              <Icon name="spark" size={11} />
              {ins.length} insight{ins.length > 1 ? "s" : ""}
              <Icon name="chevron-down" size={11} className="ins-pill-chev" />
            </button>
          )}
        </div>
        <div className="card-actions" onClick={(e) => e.stopPropagation()}>
          {!skipped && (
            <button className="btn btn-danger-ghost" onClick={() => onSkip(c)}>
              <Icon name="skip" size={13} /> Skip
            </button>
          )}
          {skipped && (
            <button className="btn btn-outline" onClick={() => onSkip(c)}>
              <Icon name="undo" size={13} /> Restore
            </button>
          )}
          {unlocked ? (
            <>
              <button className="btn btn-outline" onClick={() => onMessage(c)}>
                <Icon name="message" size={13} /> Message
              </button>
              <div className="rel" ref={popRef}>
                <button className="btn btn-primary" onClick={() => setJobPopOpen(!jobPopOpen)}>
                  <Icon name="plus-job" size={13} /> Add to job
                </button>
                {jobPopOpen && (
                  <div className="pop">
                    <div className="pop-title">Add to a job</div>
                    {window.JOBS.map(j => (
                      <button key={j.id} className="pop-item" onClick={() => { onAddToJob(c, j); setJobPopOpen(false); }}>
                        <span style={{ fontWeight: 600 }}>{j.title}</span>
                        <span className="pop-meta">{j.location} · {j.postedAgo}</span>
                      </button>
                    ))}
                  </div>
                )}
              </div>
            </>
          ) : (
            <button className="btn btn-primary" onClick={() => onUnlock(c)}>
              <Icon name="lock" size={13} /> Unlock
            </button>
          )}
          <button className="btn btn-ghost" aria-label="Toggle details" style={{ padding: "6px 8px" }}>
            <Icon name="chevron-down" size={16} className="chevron" />
          </button>
        </div>
      </div>

      <div className="card-contact">{c.phone} · {c.email} · {c.zip}</div>

      {hasIns && (signalStyle === "chips" || (signalStyle === "pill" && insightsOpen)) && (
        <InsightsBlock insights={ins} labelMode={insightsLabel || "icon"} />
      )}

      {isSmart ? (
        /* NL match-signals chips hidden for now, out of scope per pitch No-Gos.
           Restore by uncommenting:
        <div style={{ marginBottom: 18 }}>
          <div className="signals">
            {c.matchSignals.map((s, i) => (
              <span key={i} className="signal">
                <Icon name="check" size={10} /> {s}
              </span>
            ))}
          </div>
        </div>
        */
        null
      ) : (
        <div>
          <div className="card-section-label">Resume highlight</div>
          <div className="resume-highlight" dangerouslySetInnerHTML={{ __html: highlightText(c.resumeHighlight, activeQuery) }} />
        </div>
      )}

      {/* KB match-summary chips — hidden for now, out of scope per pitch No-Gos.
          Can be restored by re-enabling this block:
      {!isSmart && (() => {
        const tokens = getQueryTokens(activeQuery);
        const matches = countMatches(c, tokens);
        if (!matches.length) return null;
        return (
          <div className="kb-matched">
            <span className="kb-matched-label">Matched:</span>
            {matches.map(m => (
              <span key={m.term} className="kb-match-chip">
                <mark className="kb-match-chip-term">{m.term}</mark>
                <span className="kb-match-chip-count">{m.total}</span>
              </span>
            ))}
          </div>
        );
      })()}
      */}

      <div className="card-body-grid">
        <div>
          <div className="card-section-label">Work experience</div>
          <ExpRow e={firstWork} query={!isSmart ? activeQuery : null} edu={false} />
          {expanded && restWork.map((w, i) => <ExpRow key={i} e={w} query={!isSmart ? activeQuery : null} edu={false} />)}
          {!expanded && restWork.length > 0 && (
            <div className="expand-more">+ {restWork.length} more</div>
          )}
        </div>
        <div>
          <div className="card-section-label">Education & certs</div>
          <ExpRow e={firstEdu} edu query={!isSmart ? activeQuery : null} />
          {expanded && restEdu.map((ed, i) => <ExpRow key={i} e={ed} edu query={!isSmart ? activeQuery : null} />)}
          {!expanded && restEdu.length > 0 && (
            <div className="expand-more">+ {restEdu.length} more</div>
          )}
        </div>
      </div>

      {hasIns && signalStyle === "band" && <InsightsBand insights={ins} />}
    </div>
  );
}

function ExpRow({ e, edu, query }) {
  if (!e) return null;
  const titleText = edu ? e.degree : e.title;
  const coText = edu ? e.school : e.company;
  const hl = (s) => query ? { dangerouslySetInnerHTML: { __html: highlightText(s, query) } } : { children: s };
  return (
    <div className="exp-row">
      <div>
        <div className="exp-title" {...hl(titleText)} />
        <div className="exp-co" {...hl(coText)} />
      </div>
      <div className="exp-dates">{edu ? (e.date || "") : e.dates}</div>
    </div>
  );
}

function getQueryTokens(query) {
  if (!query || !query.trim()) return [];
  return [...new Set(
    query
      .replace(/[()"]/g, " ")
      .split(/\s+/)
      .map(t => t.trim())
      .filter(t => t.length > 2 && !/^(AND|OR|NOT|with|who|the|for|and|open|to)$/i.test(t))
  )];
}

function highlightText(text, query) {
  const tokens = getQueryTokens(query);
  if (!tokens.length) return text;
  const esc = tokens.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
  return text.replace(new RegExp("(" + esc + ")", "gi"), "<mark>$1</mark>");
}

function countMatches(c, tokens) {
  if (!tokens.length) return [];
  const workBlob = c.workExperience.map(w => `${w.title || ""} ${w.company || ""}`).join(" ");
  const eduBlob = c.education.map(e => `${e.degree || ""} ${e.school || ""}`).join(" ");
  const resumeBlob = c.resumeHighlight || "";
  return tokens.map(t => {
    const re = new RegExp(t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi");
    const work = (workBlob.match(re) || []).length;
    const edu = (eduBlob.match(re) || []).length;
    const resume = (resumeBlob.match(re) || []).length;
    return { term: t, work, edu, resume, total: work + edu + resume };
  }).filter(m => m.total > 0);
}

// ---------- Loading ----------
function Loading({ mode, style }) {
  if (style === "simple" || mode !== "ai") {
    return (
      <div className="loading-wrap">
        <div className="spinner" style={{ width: 28, height: 28, borderWidth: 3 }}></div>
        <div style={{ color: "var(--b800)", fontSize: 13 }}>Searching…</div>
      </div>
    );
  }

  const [step, setStep] = useState2(0);
  useEffect2(() => {
    setStep(0);
    const t1 = setTimeout(() => setStep(1), 500);
    const t2 = setTimeout(() => setStep(2), 1050);
    return () => { clearTimeout(t1); clearTimeout(t2); };
  }, []);

  const steps = [
    "Understanding your query",
    "Searching across 19,287 candidates",
    "Ranking by fit",
  ];

  return (
    <div className="loading-wrap">
      <div className="loading-steps">
        {steps.map((label, i) => (
          <div key={i} className={"loading-step " + (step > i ? "done" : step === i ? "active" : "")}>
            <div className="dot-box">
              {step > i && <Icon name="check" size={14} />}
              {step === i && <div className="spinner"></div>}
              {step < i && <div style={{ width: 6, height: 6, borderRadius: "50%", background: "var(--b100)" }}></div>}
            </div>
            <span>{label}…</span>
          </div>
        ))}
      </div>
    </div>
  );
}

// ---------- Empty state ----------
function Empty({ onRunRecent }) {
  const runExample = (q) => onRunRecent({ q, mode: window.detectMode(q) === "kb" ? "bool" : "ai" });
  return (
    <div className="empty">
      <div className="empty-title">Find your next hire</div>
      <div className="empty-sub">
        Type naturally, paste a job description, or use keywords and Boolean — we'll figure out what you meant.
      </div>
      <div className="recent-block">
        <div className="recent-title">Recent searches</div>
        {window.RECENT_SEARCHES.map((r, i) => (
          <div key={i} className="recent-item" onClick={() => onRunRecent(r)}>
            <div className="recent-q">
              <span className={"mode-tag " + r.mode}>{r.mode === "ai" ? "Smart" : r.mode === "bool" ? "Boolean" : "Keyword"}</span>
              {r.q}
            </div>
            <div className="recent-meta">{r.count} results · {r.when}</div>
          </div>
        ))}

        <div className="recent-divider" />

        <div className="recent-title">Try an example</div>
        {window.ROTATING_EXAMPLES.map((q, i) => (
          <div key={i} className="recent-item" onClick={() => runExample(q)}>
            <div className="recent-q">
              {q}
            </div>
            <div className="recent-meta recent-try"><Icon name="arrow-right" size={12} /></div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ---------- Pagination ----------
function getPageList(current, total) {
  if (total <= 7) return [...Array(total)].map((_, i) => i + 1);
  const set = new Set([1, total, current, current - 1, current + 1]);
  if (current <= 3) [2, 3, 4].forEach(n => n <= total && set.add(n));
  if (current >= total - 2) [total - 1, total - 2, total - 3].forEach(n => n >= 1 && set.add(n));
  const sorted = [...set].filter(n => n >= 1 && n <= total).sort((a, b) => a - b);
  const out = [];
  sorted.forEach((p, i) => {
    if (i > 0 && p - sorted[i - 1] > 1) out.push("…");
    out.push(p);
  });
  return out;
}

function Pagination({ total, pageSize, currentPage, setPage, setPageSize }) {
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
  if (totalPages <= 1) return null;
  const pages = getPageList(currentPage, totalPages);
  return (
    <nav className="pagination" aria-label="Pagination">
      <button className="pagination-btn" onClick={() => setPage(Math.max(1, currentPage - 1))} disabled={currentPage === 1} aria-label="Previous page">
        <Icon name="chevron-left" size={14} />
      </button>
      {pages.map((p, i) => (
        p === "…"
          ? <span key={`e${i}`} className="pagination-ellipsis">…</span>
          : <button
              key={p}
              className={"pagination-page" + (p === currentPage ? " active" : "")}
              onClick={() => setPage(p)}
              aria-current={p === currentPage ? "page" : undefined}
            >{p}</button>
      ))}
      <button className="pagination-btn" onClick={() => setPage(Math.min(totalPages, currentPage + 1))} disabled={currentPage === totalPages} aria-label="Next page">
        <Icon name="chevron-right" size={14} />
      </button>
      <div className="pagination-per-page">
        <span>Per page</span>
        <select value={pageSize} onChange={(e) => setPageSize(Number(e.target.value))} aria-label="Results per page">
          <option value={10}>10</option>
          <option value={25}>25</option>
          <option value={50}>50</option>
          <option value={100}>100</option>
        </select>
      </div>
    </nav>
  );
}

// ---------- Tweaks panel ----------
function TweaksPanel({ open, onClose, tweaks, setTweaks }) {
  if (!open) return null;
  const update = (k, v) => {
    const next = { ...tweaks, [k]: v };
    setTweaks(next);
    window.parent.postMessage({ type: "__edit_mode_set_keys", edits: { [k]: v } }, "*");
  };

  const Row = ({ k, label, opts }) => (
    <div className="tweak">
      <label>{label}</label>
      <div className="tweak-row">
        {opts.map(o => (
          <button key={o.v} className={"tweak-opt" + (tweaks[k] === o.v ? " active" : "")} onClick={() => update(k, o.v)}>{o.label}</button>
        ))}
      </div>
    </div>
  );

  return (
    <div className="tweaks">
      <div className="tweaks-head">
        Tweaks
        <button className="close" onClick={onClose}><Icon name="x" size={14}/></button>
      </div>
      <div className="tweaks-body">
        <Row k="interpretationStyle" label="Interpretation style" opts={[
          { v: "both", label: "Both" },
          { v: "chips", label: "Chips only" },
          { v: "rephrase", label: "Rephrase only" },
        ]} />
        <Row k="collapseAfterSearch" label="Collapse header after search" opts={[
          { v: true, label: "Collapsed" },
          { v: false, label: "Full" },
        ]} />
        <Row k="loadingStyle" label="Loading state" opts={[
          { v: "staged", label: "Staged" },
          { v: "simple", label: "Simple" },
        ]} />
        <Row k="filtersStyle" label="Filters" opts={[
          { v: "sidebar", label: "Sidebar" },
          { v: "inline", label: "Inline pills" },
          { v: "hidden", label: "Hidden" },
        ]} />
        <Row k="signalStyle" label="Candidate signals" opts={[
          { v: "chips", label: "Chips" },
          { v: "band", label: "Band" },
          { v: "pill", label: "Pill" },
          { v: "hidden", label: "Hidden" },
        ]} />
        <Row k="insightsLabel" label="Insights label (chips)" opts={[
          { v: "icon", label: "Icon only" },
          { v: "full", label: "Full label" },
          { v: "none", label: "None" },
        ]} />
      </div>
    </div>
  );
}

// ---------- App ----------
function App() {
  const [tweaks, setTweaks] = useState2(window.TWEAK_DEFAULTS);
  const [tweaksOpen, setTweaksOpen] = useState2(false);

  const [query, setQuery] = useState2("");
  const [activeJob, setActiveJob] = useState2(null);
  const [activeQuery, setActiveQuery] = useState2("");
  const [activeMode, setActiveMode] = useState2(null);
  const [forcedMode, setForcedMode] = useState2(null);
  const [hasSearched, setHasSearched] = useState2(false);
  const [isSearching, setIsSearching] = useState2(false);
  const [chips, setChips] = useState2([]);
  const [rephraseHtml, setRephraseHtml] = useState2("");

  const [expandedId, setExpandedId] = useState2(null);
  const [skippedIds, setSkippedIds] = useState2(new Set());
  const [unlockedIds, setUnlockedIds] = useState2(new Set());
  const [addedIds, setAddedIds] = useState2(new Set());
  const [animatingOut, setAnimatingOut] = useState2(null);
  const [tab, setTab] = useState2("matches");
  const [placeholderIdx, setPlaceholderIdx] = useState2(0);
  const [toast, setToast] = useState2(null);
  const [currentPage, setCurrentPage] = useState2(1);
  const [pageSize, setPageSize] = useState2(25);

  const [filterState, setFilterState] = useState2({
    distance: "30mi",
    lastActive: "Last 30 days",
    insightsOnly: false,
  });

  // Rotate placeholder
  useEffect2(() => {
    if (query.length > 0) return;
    const iv = setInterval(() => setPlaceholderIdx(i => (i + 1) % window.ROTATING_EXAMPLES.length), 3400);
    return () => clearInterval(iv);
  }, [query]);

  // Edit-mode registration
  useEffect2(() => {
    const onMsg = (e) => {
      if (e.data?.type === "__activate_edit_mode") setTweaksOpen(true);
      else if (e.data?.type === "__deactivate_edit_mode") setTweaksOpen(false);
    };
    window.addEventListener("message", onMsg);
    window.parent.postMessage({ type: "__edit_mode_available" }, "*");
    return () => window.removeEventListener("message", onMsg);
  }, []);

  // Auto-dismiss toast
  useEffect2(() => {
    if (!toast) return;
    const t = setTimeout(() => setToast(null), 3500);
    return () => clearTimeout(t);
  }, [toast]);

  const runSearch = useCallback2((q, job) => {
    const theQ = q ?? query;
    if (!theQ.trim()) return;
    const mode = job ? "ai" : (forcedMode || window.detectMode(theQ));
    setIsSearching(true);
    setHasSearched(false);
    setExpandedId(null);
    setTab("matches");
    setCurrentPage(1);
    const parsedChips = window.interpretQuery(theQ, job || null);
    const delay = mode === "ai" ? 1600 : 500;
    setTimeout(() => {
      setChips(parsedChips);
      setRephraseHtml(mode === "ai" ? window.rephrase(parsedChips, job || null) : "");
      setActiveQuery(theQ);
      setActiveMode(mode);
      setIsSearching(false);
      setHasSearched(true);
    }, delay);
  }, [query]);

  const onSearchBtn = () => {
    const divergedFromJob = activeJob && query.trim() !== activeJob.description.trim();
    if (divergedFromJob) {
      setActiveJob(null);
      runSearch(query, null);
    } else {
      runSearch(query, activeJob);
    }
  };

  const onRunRecent = (r) => {
    setQuery(r.q);
    setTimeout(() => runSearch(r.q, null), 30);
  };

  const onSkip = (c) => {
    if (skippedIds.has(c.id)) {
      // Restore
      const next = new Set(skippedIds); next.delete(c.id); setSkippedIds(next);
      return;
    }
    setAnimatingOut(c.id);
    setTimeout(() => {
      setAnimatingOut(null);
      const next = new Set(skippedIds); next.add(c.id); setSkippedIds(next);
      setToast({ msg: `${c.name} skipped`, action: () => { const n = new Set(next); n.delete(c.id); setSkippedIds(n); setToast(null); } });
    }, 260);
  };
  const onUnlock = (c) => { const next = new Set(unlockedIds); next.add(c.id); setUnlockedIds(next); };
  const onAddToJob = (c, j) => {
    const next = new Set(addedIds); next.add(c.id); setAddedIds(next);
    setToast({ msg: `${c.name} added to ${j.title}`, action: null });
  };
  const onMessage = (c) => setToast({ msg: `Message drafted for ${c.name}`, action: null });

  const isSmart = activeMode === "ai";
  const display = isSmart ? [...window.CANDIDATES].sort((a, b) => a.smartRank - b.smartRank) : window.CANDIDATES;
  const matches = display.filter(c => !skippedIds.has(c.id) && (!filterState.insightsOnly || (c.insights || []).length > 0));
  const skipped = display.filter(c => skippedIds.has(c.id));
  const count = filterState.insightsOnly ? "31" : isSmart ? "847" : activeMode === "boolean" ? "1,204" : "19,287";
  const signalStyle = tweaks.signalStyle || "chips";

  return (
    <div className="app-shell">
      <FFRail active="search" />
      <div className="page">
      <Header
        query={query} setQuery={setQuery}
        onSearch={onSearchBtn}
        isSearching={isSearching}
        hasSearched={hasSearched}
        activeJob={activeJob} setActiveJob={setActiveJob}
        placeholderIdx={placeholderIdx}
        activeQuery={activeQuery}
        activeMode={activeMode}
        collapseAfterSearch={tweaks.collapseAfterSearch !== false}
        forcedMode={forcedMode}
        setForcedMode={setForcedMode}
      />

      <div className="main">
        {/* Understood-as strip removed — filter panel now owns interpreted values */}

        {tweaks.filtersStyle === "sidebar" && hasSearched && !isSearching && (
          <Filters
            state={filterState}
            setState={setFilterState}
            chips={chips}
            setChips={setChips}
          />
        )}

        <div className="results-col" style={{ gridColumn: tweaks.filtersStyle === "sidebar" && hasSearched && !isSearching ? "auto" : "1 / -1" }}>
          {!hasSearched && !isSearching && (
            <Empty onRunRecent={onRunRecent} />
          )}

          {isSearching && <Loading mode={activeJob ? "ai" : (forcedMode || window.detectMode(query))} style={tweaks.loadingStyle} />}

          {hasSearched && !isSearching && (
            <>
              <div className="results-sticky">
                <div className="tabs">
                  <button className={"tab" + (tab === "matches" ? " active" : "")} onClick={() => setTab("matches")}>
                    Matches
                  </button>
                  <button className={"tab" + (tab === "skipped" ? " active" : "")} onClick={() => setTab("skipped")}>
                    Skipped {skipped.length > 0 && <span className="tab-count">{skipped.length}</span>}
                  </button>
                </div>
                <div className="results-meta">
                  <span className="results-count">
                    <strong>{tab === "matches" ? count : skipped.length.toLocaleString()}</strong> candidates
                  </span>
                  {tab === "matches" && signalStyle !== "hidden" && (
                    <span className="ins-meta">
                      <Icon name="spark" size={11} />
                      {filterState.insightsOnly ? "with FactoryFix insights" : "31 with insights"}
                    </span>
                  )}
                  {/* Sort dropdown hidden for now — out of scope per pitch.
                      Restore by uncommenting:
                  <select className="sort-select" defaultValue={isSmart ? "fit" : "recent"}>
                    {isSmart && <option value="fit">Sort: Best fit</option>}
                    <option value="recent">Sort: Most recent activity</option>
                    <option value="distance">Sort: Nearest</option>
                  </select>
                  */}
                </div>
              </div>

              {tab === "matches" && matches.map(c => (
                <Card
                  key={c.id}
                  c={c}
                  isSmart={isSmart}
                  activeQuery={activeQuery}
                  expanded={expandedId === c.id}
                  onToggle={() => setExpandedId(expandedId === c.id ? null : c.id)}
                  onSkip={onSkip}
                  onUnlock={onUnlock}
                  onAddToJob={onAddToJob}
                  onMessage={onMessage}
                  skipped={false}
                  unlocked={unlockedIds.has(c.id)}
                  animatingOut={animatingOut === c.id}
                  signalStyle={signalStyle}
                  insightsLabel={tweaks.insightsLabel}
                />
              ))}
              {tab === "matches" && matches.length === 0 && (
                <div style={{ textAlign: "center", padding: "48px 0", color: "var(--b800)" }}>
                  All candidates skipped. Check the Skipped tab to restore.
                </div>
              )}
              {tab === "matches" && matches.length > 0 && (
                <Pagination
                  total={Number(String(count).replace(/,/g, "")) || matches.length}
                  pageSize={pageSize}
                  currentPage={currentPage}
                  setPage={(p) => { setCurrentPage(p); window.scrollTo({ top: 0, behavior: "smooth" }); }}
                  setPageSize={(s) => { setPageSize(s); setCurrentPage(1); }}
                />
              )}

              {tab === "skipped" && skipped.map(c => (
                <Card key={c.id} c={c} isSmart={isSmart} activeQuery={activeQuery}
                  expanded={expandedId === c.id}
                  onToggle={() => setExpandedId(expandedId === c.id ? null : c.id)}
                  onSkip={onSkip} onUnlock={onUnlock} onAddToJob={onAddToJob} onMessage={onMessage}
                  skipped={true} unlocked={unlockedIds.has(c.id)} animatingOut={false}
                  signalStyle={signalStyle}
                  insightsLabel={tweaks.insightsLabel}
                />
              ))}
              {tab === "skipped" && skipped.length === 0 && (
                <div style={{ textAlign: "center", padding: "48px 0", color: "var(--b800)" }}>
                  No skipped candidates yet.
                </div>
              )}
            </>
          )}
        </div>
      </div>

      {toast && (
        <div className="toast">
          {toast.msg}
          {toast.action && <button onClick={toast.action}>Undo</button>}
        </div>
      )}

      <TweaksPanel open={tweaksOpen} onClose={() => setTweaksOpen(false)} tweaks={tweaks} setTweaks={setTweaks} />
    </div>
    </div>
  );
}

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