/* Folclore Latin Fund I — Deal pipeline.
   Level 1: counts-only snapshot. Level 2: project names and detail.
   House names open at Level 4. Sample book until the sourcing file replaces it. */

const PL_DAY = 864e5;
const plD = (s) => Date.parse(s + "T12:00:00Z");
const PL_START = plD("2026-01-01");
const PL_TODAY = plD("2026-11-03");

const PL_STAGES = [
  { code: "01", name: "Analysis", desc: "Desk analysis, thesis fit and a first model.", target: 45 },
  { code: "02", name: "Engagement", desc: "Founder and family meetings under NDA.", target: 60 },
  { code: "03", name: "LOI", desc: "Non-binding letter, price and exclusivity.", target: 30 },
  { code: "04", name: "Diligence", desc: "Earnings, brand rights, ateliers.", target: 75 },
  { code: "05", name: "Documentation", desc: "Purchase agreement and final committee.", target: 45 },
  { code: "06", name: "Closed", desc: "Funded and held by Fund I.", target: 0 },
];

const PL_WS = [
  "Quality of earnings",
  "Brand and trademark rights",
  "Legal and tax",
  "Atelier and supply audit",
  "Heritage and ESG protocol",
];

const PL_NW = "Nick Walker";
const PL_DM = "Dolly Moorhead";

const PIPELINE_HOUSES = [
  { id: "bananaquist", cn: "Bananaquist", name: "Maré Alta", v: "Swimwear", city: "Rio de Janeiro", ctry: "Brazil", est: 1983, desc: "Swimwear and resort, cut and sewn in the house’s own Rio atelier since the early eighties.", rev: 18, m: 19, ev: 30, eq: 9.0, pos: "Minority · 30%", lead: PL_DM, h: ["2026-03-02", "2026-04-08", "2026-10-14"], ws: [1, 0, 0, 0, 0], next: ["LOI countersignature expected", "14 Nov 2026"] },
  { id: "capybara", cn: "Capybara", name: "Curtiduría Delgado", v: "Leather goods", city: "León", ctry: "Mexico", est: 1961, desc: "A family tannery that has supplied European leather houses for decades, now building a label of its own.", rev: 22, m: 17, ev: 28, eq: 9.5, pos: "Control · 51%", lead: PL_NW, h: ["2026-02-16", "2026-03-30", "2026-09-08"], ws: [1, 1, 0, 0, 0], next: ["Exclusivity extended to", "30 Nov 2026"] },
  { id: "vicuna", cn: "Vicuña", name: "Tejidos Altiplano", v: "Fashion", city: "Arequipa", ctry: "Peru", est: 1975, desc: "Alpaca and vicuña knitwear from a house that spins its own yarn in the southern Andes.", rev: 31, m: 22, ev: 52, eq: 9.4, pos: "Minority · 18%", lead: PL_DM, h: ["2026-02-03", "2026-03-10", "2026-05-26", "2026-09-01"], ws: [2, 2, 1, 1, 0], next: ["Quality of earnings report due", "20 Nov 2026"] },
  { id: "quetzal", cn: "Quetzal", name: "Platería Ordaz", v: "Jewelry", city: "Mexico City", ctry: "Mexico", est: 1948, desc: "A silversmith atelier founded by a Taxco master; fine silver and gold, made by hand.", rev: 14, m: 26, ev: 32, eq: 8.0, pos: "Minority · 25%", lead: PL_NW, h: ["2026-01-20", "2026-02-24", "2026-04-21", "2026-05-19", "2026-09-22"], ws: [2, 2, 2, 2, 1], next: ["Final investment committee", "18 Nov 2026"] },
  { id: "tapir", cn: "Tapir", name: "Bodega Cruz del Uco", v: "Spirits and wine", city: "Mendoza", ctry: "Argentina", est: 1912, desc: "A fourth-generation winery in the Uco Valley, with a single-estate label sold in forty markets.", rev: 19.5, m: 24, ev: 36, eq: 7.9, pos: "Minority · 22%", lead: PL_DM, h: ["2026-01-08", "2026-02-10", "2026-03-17", "2026-04-14", "2026-07-07", "2026-08-28"], ws: [2, 2, 2, 2, 2], next: ["First board meeting as shareholder", "9 Dec 2026"] },
  { id: "ocelot", cn: "Ocelot", name: "Casa Ybirá", v: "Beauty", city: "São Paulo", ctry: "Brazil", est: 1991, desc: "Botanical fragrance and body care, sold through the house’s own boutiques.", rev: 26, m: 15, ev: 34, eq: 8.5, pos: "Minority · 25%", lead: PL_DM, h: ["2026-08-25", "2026-10-06"], next: ["Second visit to the boutiques", "12 Nov 2026"] },
  { id: "condor", cn: "Condor", name: "Sastrería Valdés", v: "Fashion", city: "Santiago", ctry: "Chile", est: 1968, desc: "A tailoring house that has dressed three generations of Chilean families.", rev: 12, m: 18, ev: 18, eq: 6.0, pos: "Control · 51%", lead: PL_NW, h: ["2026-07-14", "2026-09-08"], next: ["Family council on outside capital", "21 Nov 2026"] },
  { id: "kinkajou", cn: "Kinkajou", name: "Destilería Arandas Alto", v: "Spirits and wine", city: "Arandas", ctry: "Mexico", est: 1936, desc: "Highland tequila from stone ovens and a single family estate of agave.", rev: 16, m: 28, ev: 38, eq: 9.0, pos: "Minority · 24%", lead: PL_NW, h: ["2026-09-15", "2026-10-22"], next: ["Distillery visit, Jalisco highlands", "17 Nov 2026"] },
  { id: "agouti", cn: "Agouti", name: "Gemas Serro", v: "Jewelry", city: "Belo Horizonte", ctry: "Brazil", est: 1972, desc: "A gemstone jeweller cutting Minas Gerais tourmaline and topaz in-house.", rev: 9.5, m: 23, ev: 16, eq: 5.0, pos: "Minority · 30%", lead: PL_DM, h: ["2026-06-30", "2026-08-11"], next: ["Founder meeting, rescheduled", "25 Nov 2026"] },
  { id: "coati", cn: "Coati", name: "Telar Usaquén", v: "Home goods", city: "Bogotá", ctry: "Colombia", est: 1979, desc: "Hand-loomed textiles and furniture from a single Bogotá workshop.", rev: 7.5, m: 16, ev: 10, eq: 3.0, pos: "Minority · 30%", lead: PL_NW, h: ["2026-10-09"], next: ["First model to the partners", "10 Nov 2026"] },
  { id: "margay", cn: "Margay", name: "Óptica Palermo", v: "Eyewear", city: "Buenos Aires", ctry: "Argentina", est: 1957, desc: "Acetate frames, hand-finished in a Palermo workshop.", rev: 6, m: 20, ev: 9, eq: 4.5, pos: "Control · 51%", lead: PL_DM, h: ["2026-09-02"], next: ["Decision to engage or pass", "7 Nov 2026"] },
  { id: "guanaco", cn: "Guanaco", name: "Abrigos del Sur", v: "Fashion", city: "Bariloche", ctry: "Argentina", est: 1984, desc: "Wool outerwear from the fleece of Patagonian estancias.", rev: 11, m: 21, ev: 19, eq: 5.5, pos: "Minority · 29%", lead: PL_NW, h: ["2026-10-20"], next: ["Introduction through an estancia owner", "13 Nov 2026"] },
  { id: "rhea", cn: "Rhea", name: "Talabartería Ríos", v: "Leather goods", city: "Montevideo", ctry: "Uruguay", est: 1950, desc: "A saddlery turned leather-goods house, still stitching by hand.", rev: 8, m: 17, ev: 11, eq: 3.5, pos: "Minority · 32%", lead: PL_DM, h: ["2026-10-27"], next: ["Initial screen", "6 Nov 2026"] },
  { id: "hoatzin", cn: "Hoatzin", name: "Bahía Swim", v: "Swimwear", city: "Cartagena", ctry: "Colombia", est: 1998, desc: "Swim and resort, designed in Cartagena and made in Medellín.", rev: 10, m: 14, ev: 13, eq: 4.0, pos: "Minority · 30%", lead: PL_NW, h: ["2026-09-24"], next: ["First model to the partners", "9 Nov 2026"] },
  { id: "puma", cn: "Puma", name: "Casa Arenales", v: "Fashion", city: "Buenos Aires", ctry: "Argentina", est: 1938, desc: "A ready-to-wear house with a long history of licensing abroad.", rev: 15, m: 12, ev: 20, eq: 6.0, pos: "Minority · 30%", lead: PL_NW, h: ["2026-02-12"], pass: { at: 0, d: "2026-03-20", why: "Brand licensed in four markets; the rights are not recoverable." } },
  { id: "armadillo", cn: "Armadillo", name: "Barro Tonalá", v: "Home goods", city: "Tonalá", ctry: "Mexico", est: 1966, desc: "Burnished ceramics from a Jalisco family workshop.", rev: 4.2, m: 11, ev: 5, eq: 2.0, pos: "Control · 51%", lead: PL_DM, h: ["2026-03-05"], pass: { at: 0, d: "2026-04-10", why: "Below scale — revenue under $5M." } },
  { id: "tamarin", cn: "Tamarin", name: "Flora Paulista", v: "Beauty", city: "São Paulo", ctry: "Brazil", est: 1987, desc: "Soap and fragrance from Atlantic Forest botanicals.", rev: 21, m: 13, ev: 27, eq: 8.0, pos: "Minority · 28%", lead: PL_DM, h: ["2026-03-23", "2026-05-04"], pass: { at: 1, d: "2026-06-12", why: "The family was not aligned on outside capital." } },
  { id: "axolotl", cn: "Axolotl", name: "Mezcalería Tlacolula", v: "Spirits and wine", city: "Oaxaca", ctry: "Mexico", est: 1958, desc: "Small-batch mezcal from a Oaxaca valley palenque.", rev: 13, m: 25, ev: 30, eq: 8.0, pos: "Minority · 25%", lead: PL_NW, h: ["2026-02-02", "2026-03-16"], pass: { at: 1, d: "2026-05-28", why: "The agave supply contract is held by a third party." } },
  { id: "manatee", cn: "Manatee", name: "Praia Funda", v: "Swimwear", city: "Florianópolis", ctry: "Brazil", est: 1993, desc: "Swimwear with a wholesale footprint across Europe.", rev: 24, m: 18, ev: 60, eq: 10.0, pos: "Minority · 20%", lead: PL_DM, h: ["2026-02-09", "2026-03-12", "2026-05-18"], ws: [1, 0, 0, 0, 0], pass: { at: 2, d: "2026-06-30", why: "Valuation gap after the LOI — the seller sought 14× EBITDA." } },
  { id: "jaguarundi", cn: "Jaguarundi", name: "Marroquinería Belgrano", v: "Leather goods", city: "Buenos Aires", ctry: "Argentina", est: 1949, desc: "Leather goods sold through department stores across the Southern Cone.", rev: 17, m: 16, ev: 24, eq: 7.5, pos: "Control · 51%", lead: PL_NW, h: ["2026-01-14", "2026-02-17", "2026-04-01", "2026-05-12"], ws: [2, 1, 1, 0, 0], pass: { at: 3, d: "2026-08-14", why: "Diligence found unrecorded tax liabilities." } },
];

const PL_VERTS = [...new Set(PIPELINE_HOUSES.map((h) => h.v))];
const PL_COUNTRIES = ["Mexico", "Brazil", "Argentina", "Colombia", "Peru", "Chile", "Uruguay", "Ecuador", "Guatemala"];
const PL_VORDER = ["Fashion", "Leather goods", "Jewelry", "Beauty", "Spirits and wine", "Swimwear", "Home goods", "Eyewear"];
const PL_SOURCES = ["Family and founder network", "Proprietary research", "Advisors and bankers", "Ateliers and trade fairs", "LP introductions", "Inbound"];

const PL_UNI = (() => {
  let sd = 11;
  const rnd = () => (sd = (sd * 16807) % 2147483647) / 2147483647;
  const pick = (ws) => {
    let x = rnd() * ws.reduce((a, b) => a + b, 0);
    for (let i = 0; i < ws.length; i++) if ((x -= ws[i]) < 0) return i;
    return ws.length - 1;
  };
  const HS = [0, 1, 0, 2, 0, 4, 0, 1, 3, 3, 1, 0, 5, 2, 2, 1, 0, 3, 2, 2];
  const u = PIPELINE_HOUSES.map((h, i) => ({
    v: h.v,
    c: h.ctry,
    src: HS[i],
    add: plD(h.h[0]) - (14 + Math.round(rnd() * 40)) * PL_DAY,
    a: plD(h.h[0]),
  }));
  for (let i = 0; i < 92; i++) {
    u.push({
      v: i < 8 ? PL_VORDER[i] : PL_VORDER[pick([22, 14, 12, 12, 12, 9, 11, 5])],
      c: i < 9 ? PL_COUNTRIES[i] : PL_COUNTRIES[pick([30, 26, 16, 10, 7, 5, 4, 3, 2])],
      src: pick([20, 34, 18, 14, 4, 10]),
      add: i < 38 ? PL_START - Math.round(rnd() * 110 + 5) * PL_DAY : PL_START + Math.round(rnd() * 300) * PL_DAY,
      a: null,
    });
  }
  return u;
})();

const plFm = (v) => "$" + Math.round(v) + "M";
const plFe = (v) => "$" + v.toFixed(1) + "M";
const plFS = (d) => new Date(d).toLocaleDateString("en-GB", { day: "numeric", month: "short", timeZone: "UTC" });
const plFM = (d) => new Date(d).toLocaleDateString("en-GB", { day: "numeric", month: "short", year: "numeric", timeZone: "UTC" });
const plFL = (d) => new Date(d).toLocaleDateString("en-GB", { day: "numeric", month: "long", year: "numeric", timeZone: "UTC" });
const plDays = (n) => (n === 1 ? "1 day" : n + " days");

function plAccessCopy(t) {
  if (typeof window.accessCopy === "function") return window.accessCopy(t);
  return (t && t.dataroom && t.dataroom.access) || {};
}

function PipelineDrawer({ sel, level4, access, onClose }) {
  const closeRef = React.useRef(null);
  React.useEffect(() => {
    if (closeRef.current) closeRef.current.focus();
  }, [sel.title]);

  const Action = window.AccessActionButton;
  const Mark = window.AccessLevelMark;

  return (
    <div className="pl-drawer-root">
      <button type="button" className="pl-backdrop" aria-label="Close" onClick={onClose} />
      <aside className="pl-drawer" role="dialog" aria-modal="true" aria-labelledby="pl-drawer-title">
        <div className="pl-drawer-top">
          <div className="pl-drawer-head">
            <span className="pl-eyebrow">{sel.eyebrow}</span>
            <h2 id="pl-drawer-title">{sel.title}</h2>
            <span className="pl-drawer-sub">{sel.sub}</span>
          </div>
          <button type="button" className="pl-icon-btn" aria-label="Close" ref={closeRef} onClick={onClose}>
            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
              <path d="M18 6 6 18" /><path d="m6 6 12 12" />
            </svg>
          </button>
        </div>

        {level4 ? (
          <div className="pl-name-open">
            <span className="pl-eyebrow">House · Level 4</span>
            <span className="pl-name-italic">{sel.name}</span>
          </div>
        ) : (
          <div className="pl-name-locked">
            <div className="pl-name-locked-row">
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--gold-500)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                <rect width="18" height="11" x="3" y="11" rx="2" ry="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" />
              </svg>
              <div>
                <span className="pl-eyebrow">House name · Opens at Level 4</span>
                <p className="pl-prose-tight">Granted under a signed NDA, after a call with the Fund I team.</p>
              </div>
            </div>
            {typeof Mark === "function" && <Mark level={4} />}
            {typeof Action === "function" && <Action level={4} access={access} />}
          </div>
        )}

        <p className="pl-prose">{sel.desc}</p>

        {sel.isPassed && (
          <div className="pl-pass-box">
            <span className="pl-eyebrow muted">Passed · {sel.passDate}</span>
            <span className="pl-prose-tight">{sel.passWhy}</span>
          </div>
        )}

        <div className="pl-figs">
          {sel.figs.map((f) => (
            <div key={f.k}>
              <span className="pl-fig-k">{f.k}</span>
              <span className="pl-fig-v">{f.v}</span>
            </div>
          ))}
        </div>

        <div className="pl-path">
          <span className="pl-eyebrow muted">Path through the funnel</span>
          {sel.path.map((s) => (
            <div key={s.code} className={"pl-path-row" + (s.cur ? " is-cur" : "")}>
              <span className="pl-path-mark" style={{ background: s.mark, border: s.markBd }} />
              <span className="pl-path-code">{s.code}</span>
              <span className="pl-path-copy">
                <span style={{ color: s.fg }}>{s.name}</span>
                <span className="pl-muted-num">{s.date}</span>
              </span>
              <span className="pl-path-dur" style={{ color: s.durFg }}>{s.dur}</span>
            </div>
          ))}
        </div>

        {sel.hasWs && (
          <div className="pl-ws">
            <span className="pl-eyebrow muted">Diligence workstreams</span>
            {sel.ws.map((w) => (
              <div key={w.n} className="pl-ws-row">
                <span className="pl-ws-mark" style={{ background: w.fill, border: w.bd }} />
                <span className="pl-ws-name">{w.n}</span>
                <span className="pl-ws-lbl" style={{ color: w.fg }}>{w.lbl}</span>
              </div>
            ))}
          </div>
        )}

        {sel.hasNext && (
          <div className="pl-next-grid">
            <div>
              <span className="pl-fig-k">Next</span>
              <span className="pl-next-v">{sel.next}</span>
              <span className="pl-gold-num">{sel.nextDate}</span>
            </div>
            <div>
              <span className="pl-fig-k">Lead partner</span>
              <span className="pl-next-v">{sel.lead}</span>
            </div>
          </div>
        )}

        <p className="pl-drawer-hint">Esc to close</p>
      </aside>
    </div>
  );
}

function PipelinePage({ t, accessLevel, initialCompanyId }) {
  const level = Number(accessLevel || 1);
  const detail = level >= 2;
  const level4 = level >= 4;
  const showPassed = true;
  const access = plAccessCopy(t);

  const [tAsOf, setTAsOf] = React.useState(PL_TODAY);
  const [playing, setPlaying] = React.useState(false);
  const [hover, setHover] = React.useState(null);
  const [cell, setCell] = React.useState(null);
  const [selected, setSelected] = React.useState(initialCompanyId || null);
  const [vert, setVert] = React.useState("All");
  const [sizeBy, setSizeBy] = React.useState("Enterprise value");
  const [vw, setVw] = React.useState(typeof window !== "undefined" ? window.innerWidth : 1440);

  const trackRef = React.useRef(null);
  const uniRef = React.useRef(null);
  const ivRef = React.useRef(null);

  React.useEffect(() => {
    if (initialCompanyId && detail) setSelected(initialCompanyId);
  }, [initialCompanyId, detail]);

  React.useEffect(() => {
    const onResize = () => setVw(window.innerWidth);
    const onKey = (e) => {
      if (e.key === "Escape") setSelected(null);
    };
    window.addEventListener("resize", onResize);
    window.addEventListener("keydown", onKey);
    return () => {
      window.removeEventListener("resize", onResize);
      window.removeEventListener("keydown", onKey);
      clearInterval(ivRef.current);
    };
  }, []);

  const stop = React.useCallback(() => {
    clearInterval(ivRef.current);
    ivRef.current = null;
    setPlaying(false);
  }, []);

  const setFromX = React.useCallback((x) => {
    const el = trackRef.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const f = Math.max(0, Math.min(1, (x - r.left) / r.width));
    setTAsOf(PL_START + Math.round((f * (PL_TODAY - PL_START)) / PL_DAY) * PL_DAY);
  }, []);

  const onTrackDown = (e) => {
    stop();
    setFromX(e.clientX);
    const mv = (ev) => setFromX(ev.clientX);
    const up = () => {
      window.removeEventListener("pointermove", mv);
      window.removeEventListener("pointerup", up);
    };
    window.addEventListener("pointermove", mv);
    window.addEventListener("pointerup", up);
  };

  const togglePlay = () => {
    if (playing) return stop();
    setPlaying(true);
    setTAsOf((x) => (x >= PL_TODAY ? PL_START : x));
    clearInterval(ivRef.current);
    ivRef.current = setInterval(() => {
      setTAsOf((x) => {
        const nt = x + 2 * PL_DAY;
        if (nt >= PL_TODAY) {
          clearInterval(ivRef.current);
          setPlaying(false);
          return PL_TODAY;
        }
        return nt;
      });
    }, 60);
  };

  const goUniverse = () => {
    const el = uniRef.current;
    const root = document.querySelector(".dr-main");
    if (!el) return;
    if (root) {
      const top = el.getBoundingClientRect().top - root.getBoundingClientRect().top + root.scrollTop - 24;
      root.scrollTo({ top: Math.max(0, top), behavior: "smooth" });
    } else {
      window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 88, behavior: "smooth" });
    }
  };

  const asOf = detail ? tAsOf : PL_TODAY;
  const live = asOf >= PL_TODAY;
  const colW = 100 / 7;
  const T0 = 52;
  const BH = 400;
  const cy = T0 + BH / 2;
  const SED = T0 + BH + 30;

  const rows = PIPELINE_HOUSES.map((h) => {
    const hist = h.h.map(plD);
    const ps = h.pass ? { at: h.pass.at, d: plD(h.pass.d), why: h.pass.why } : null;
    let st = -1;
    hist.forEach((d, i) => {
      if (d <= asOf) st = i;
    });
    const passed = !!ps && ps.d <= asOf;
    const age = st >= 0 ? Math.round(((passed ? ps.d : asOf) - hist[st]) / PL_DAY) : 0;
    return {
      h,
      hist,
      ps,
      st,
      passed,
      age,
      present: st >= 0,
      active: st >= 0 && !passed,
      match: vert === "All" || h.v === vert,
    };
  });
  const byId = Object.fromEntries(rows.map((r) => [r.h.id, r]));
  const nextOf = (r) => r.h.next || ["—", ""];

  const uNow = PL_UNI.filter((u) => u.add <= asOf);
  const isAdv = (u) => u.a != null && u.a <= asOf;
  const reached = PL_STAGES.map((_, i) => rows.filter((r) => r.hist[i] != null && r.hist[i] <= asOf).length);
  const reachAll = [uNow.length, ...reached];
  const bandH = reachAll.map((r) => 64 + 336 * Math.sqrt(r / Math.max(reachAll[0], 1)));
  const bands = reachAll.map((_, j) => ({
    left: j * colW + "%",
    width: colW + "%",
    top: cy - bandH[j] / 2 + "px",
    height: bandH[j] + "px",
    bl: j === 0 ? "1px solid rgba(169,178,196,.22)" : "0",
    br: j === 2 ? "1px solid rgba(197,160,89,.75)" : "1px solid rgba(169,178,196,.22)",
  }));
  const gates = [1, 2, 3, 4, 5, 6].map((j) => ({
    left: j * colW + "%",
    pct: reachAll[j - 1] ? Math.round((reachAll[j] / reachAll[j - 1]) * 100) + "%" : "—",
    gold: j >= 3,
  }));

  const maxEv = Math.max(...PIPELINE_HOUSES.map((h) => h.ev));
  const maxEq = Math.max(...PIPELINE_HOUSES.map((h) => h.eq));
  const sizeOf = (r) => {
    const d = sizeBy === "Equal" ? 14 : 10 + 22 * Math.sqrt(sizeBy === "Fund I equity" ? r.h.eq / maxEq : r.h.ev / maxEv);
    return r.passed ? Math.max(8, d * 0.7) : d;
  };

  const pos = {};
  PL_STAGES.forEach((sg, i) => {
    const col = rows.filter((r) => r.active && r.st === i).sort((a, b) => a.hist[0] - b.hist[0]);
    col.forEach((r, k) => {
      const frac = i === 5 ? 0.5 : Math.min(r.age / sg.target, 1);
      const bh = bandH[i + 1];
      pos[r.h.id] = {
        x: (i + 1.16 + 0.68 * frac) * colW,
        y: cy - bh / 2 + ((k + 0.5) * bh) / col.length,
        frac,
        over: i < 5 && r.age > sg.target,
      };
    });
    const pc = rows.filter((r) => r.passed && r.ps.at === i).sort((a, b) => a.ps.d - b.ps.d);
    pc.forEach((r, k) => {
      pos[r.h.id] = { x: (i + 1 + (k + 1) / (pc.length + 1)) * colW, y: SED + 36, frac: 0.5 };
    });
  });

  const dots = detail
    ? rows.map((r) => {
        const h = r.h;
        const q = pos[h.id];
        const sel = selected === h.id;
        const hov = hover === h.id;
        const hidden = !r.present || (r.passed && !showPassed);
        const late = r.active && r.st >= 2;
        const flipL = q && !r.passed && q.frac > 0.6;
        const fill = !r.match ? "var(--sapphire-600)" : late ? "var(--gold-500)" : "var(--sapphire-200)";
        const ring = sel
          ? "0 0 0 3px var(--sapphire-700), 0 0 0 4px var(--alabaster)"
          : hov
            ? "0 0 0 3px var(--sapphire-700), 0 0 0 4px var(--gold-200)"
            : q && q.over && r.match
              ? "0 0 0 3px var(--sapphire-700), 0 0 0 4px var(--gold-400)"
              : "0 0 0 0 transparent";
        return {
          id: h.id,
          left: (q ? q.x : 1) + "%",
          top: (q ? q.y : cy) + "px",
          size: sizeOf(r) + "px",
          bg: r.passed ? "transparent" : fill,
          bd: r.passed ? "1px solid " + (r.match ? "var(--sapphire-200)" : "var(--sapphire-600)") : "0",
          ring,
          op: hidden ? 0 : 1,
          pe: hidden ? "none" : "auto",
          z: sel || hov ? 4 : 3,
          label: h.cn,
          lL: r.passed ? "50%" : flipL ? "auto" : "calc(100% + 8px)",
          lR: flipL ? "calc(100% + 8px)" : "auto",
          lT: r.passed ? "calc(100% + 6px)" : "50%",
          lTf: r.passed ? "translateX(-50%)" : "translateY(-50%)",
          lFs: r.passed ? "10.5px" : "11.5px",
          lFg: !r.match
            ? "var(--sapphire-400)"
            : sel
              ? "var(--alabaster)"
              : late
                ? "var(--gold-200)"
                : r.passed
                  ? "var(--sapphire-200)"
                  : "var(--alabaster)",
        };
      })
    : [];

  const fid = hover || selected;
  const fr = fid && byId[fid];
  let thread = { on: false, ticks: [] };
  if (detail && fr && fr.active && pos[fid]) {
    const q = pos[fid];
    thread = {
      on: true,
      left: colW + "%",
      top: q.y + "px",
      w: q.x - colW + "%",
      bg: selected === fid ? "var(--gold-500)" : "rgba(197,160,89,.55)",
      ticks: fr.hist.slice(0, fr.st + 1).map((d, i) => ({
        left: (i + 1) * colW + "%",
        top: q.y + "px",
        date: plFS(d),
        tf: i === 0 ? "translate(2px,-130%)" : "translate(-50%,-140%)",
      })),
    };
  }

  const hr = hover && byId[hover];
  let tip = { on: false };
  if (detail && hr && pos[hover] && hr.present && !(hr.passed && !showPassed)) {
    const q = pos[hover];
    const h = hr.h;
    tip = {
      on: true,
      left: Math.min(90, Math.max(10, q.x)) + "%",
      top: q.y - sizeOf(hr) / 2 - 12 + "px",
      title: "Project " + h.cn,
      sub: h.v + " · " + h.city,
      line: hr.passed
        ? "Passed at " + PL_STAGES[hr.ps.at].name + " · " + plFS(hr.ps.d)
        : hr.st === 5
          ? plFm(h.ev) + " EV · Closed " + plFS(hr.hist[5])
          : plFm(h.ev) + " EV · " + plDays(hr.age) + " in " + PL_STAGES[hr.st].name,
    };
  }

  const act = rows.filter((r) => r.active);
  const actM = act.filter((r) => r.match);
  const nCtry = new Set(uNow.map((u) => u.c)).size;
  const heads = [
    {
      code: "00",
      name: "Universe",
      desc: "Screened against the thesis. Counts only.",
      gold: false,
      count: uNow.length + " houses",
      ev: nCtry + " countries",
    },
    ...PL_STAGES.map((sg, i) => {
      const here = actM.filter((r) => r.st === i);
      return {
        code: sg.code,
        name: sg.name,
        desc: sg.desc,
        gold: i >= 2,
        count: here.length === 1 ? "1 house" : here.length + " houses",
        ev: here.length ? plFm(here.reduce((a, r) => a + r.h.ev, 0)) + " EV" : "—",
      };
    }),
  ];

  const advN = uNow.filter(isAdv).length;
  const cellsOf = (v, c) => uNow.filter((u) => u.v === v && u.c === c);
  const maxCell = Math.max(1, ...PL_VORDER.flatMap((v) => PL_COUNTRIES.map((c) => cellsOf(v, c).length)));
  const mRows = PL_VORDER.map((v) => {
    const rowU = uNow.filter((u) => u.v === v);
    return {
      label: v,
      total: String(rowU.length),
      op: vert === "All" || vert === v ? 1 : 0.32,
      hot: cell && cell.v === v,
      cells: PL_COUNTRIES.map((c) => {
        const cu = rowU.filter((u) => u.c === c);
        const n = cu.length;
        const a = cu.filter(isAdv).length;
        const on = !!cell && cell.v === v && cell.c === c;
        return {
          n: n ? String(n) : "—",
          empty: !n,
          bg: on
            ? "var(--sapphire-600)"
            : n
              ? "color-mix(in oklab, var(--sapphire-600) " + Math.round(14 + (58 * n) / maxCell) + "%, transparent)"
              : "transparent",
          ring: on ? "inset 0 0 0 1px var(--gold-500)" : "none",
          ticks: Array.from({ length: n }, (_, k) => (k < a ? "gold" : "plain")),
          v,
          c,
        };
      }),
    };
  });
  const mHeads = PL_COUNTRIES.map((c) => ({ n: c, hot: cell && cell.c === c }));
  const mTotals = PL_COUNTRIES.map((c) => String(uNow.filter((u) => u.c === c).length));
  let readout = { k: "All houses", v: uNow.length + " screened · " + advN + " reached Analysis" };
  if (cell) {
    const cu = cellsOf(cell.v, cell.c);
    const a = cu.filter(isAdv).length;
    readout = {
      k: cell.v + " · " + cell.c,
      v: cu.length ? cu.length + " screened · " + a + " reached Analysis" : "None screened yet",
    };
  }
  const uniKpis = [
    { k: "Screened", v: String(uNow.length), gold: false },
    { k: "Countries", v: String(nCtry), gold: false },
    { k: "Verticals", v: String(new Set(uNow.map((u) => u.v)).size), gold: false },
    { k: "Reach Analysis", v: uNow.length ? Math.round((advN / uNow.length) * 100) + "%" : "—", gold: true },
  ];
  const srcAll = PL_SOURCES.map((k, i) => {
    const su = uNow.filter((u) => u.src === i);
    return { k, n: su.length, a: su.filter(isAdv).length };
  });
  const maxSrc = Math.max(1, ...srcAll.map((x) => x.n));
  const srcRows = srcAll
    .slice()
    .sort((x, y) => y.n - x.n)
    .map((x) => ({
      k: x.k,
      n: String(x.n),
      a: String(x.a),
      rate: x.n ? Math.round((x.a / x.n) * 100) + "%" : "—",
      w: (x.n / maxSrc) * 100 + "%",
      aw: (x.a / maxSrc) * 100 + "%",
      hot: x.n && x.a / x.n >= 0.25,
    }));

  const pre = actM.filter((r) => r.st < 2).length;
  const post = actM.filter((r) => r.st >= 2).length;
  const loiToClose = act.filter((r) => r.st >= 2 && r.st < 5);
  const kpis = [
    { k: "Screened", v: String(uNow.length), gold: false },
    { k: "In analysis", v: String(act.filter((r) => r.st < 2).length), gold: false },
    { k: "LOI to close", v: String(loiToClose.length), gold: true },
    { k: "Fund I equity · LOI to close", v: plFe(loiToClose.reduce((a, r) => a + r.h.eq, 0)), gold: true },
    { k: "Closed", v: String(act.filter((r) => r.st === 5).length), gold: false },
  ];

  const span = PL_TODAY - PL_START;
  const pctOf = (d) => ((d - PL_START) / span) * 100 + "%";
  const events = [];
  if (detail) {
    rows.forEach((r) => {
      if (r.hist[2] != null) events.push({ left: pctOf(r.hist[2]), gold: true });
      if (r.hist[5] != null) events.push({ left: pctOf(r.hist[5]), soft: true });
      if (r.ps) events.push({ left: pctOf(r.ps.d), pass: true });
    });
  }
  const months = Array.from({ length: 10 }, (_, m) => ({
    left: pctOf(Date.UTC(2026, m, 1, 12)),
    label: new Date(Date.UTC(2026, m, 1)).toLocaleDateString("en-GB", { month: "short", timeZone: "UTC" }),
  }));

  const listW = vw - 48 * 2;
  const showWide = detail && listW >= 940;
  const showDesc = listW >= 1000;
  const canvasH = (showPassed ? SED + 92 : T0 + BH + 20) + "px";

  const ledger = detail
    ? actM
        .slice()
        .sort((a, b) => b.st - a.st || b.age - a.age)
        .map((r) => {
          const h = r.h;
          const sg = PL_STAGES[r.st];
          const over = r.st < 5 && r.age > sg.target;
          const on = selected === h.id || hover === h.id;
          const nx = nextOf(r);
          return {
            id: h.id,
            cn: "Project " + h.cn,
            sub: h.v + " · " + h.city,
            name: h.name,
            code: sg.code,
            stage: sg.name,
            gold: r.st >= 2,
            days: r.st === 5 ? plFS(r.hist[5]) : plDays(r.age),
            daysSub: r.st === 5 ? "Closed" : "Target " + sg.target,
            over,
            ev: plFm(h.ev),
            eq: plFe(h.eq),
            next: nx[0],
            nextDate: nx[1],
            on,
          };
        })
    : [];

  const srow = selected && byId[selected];
  let sel = null;
  if (detail && srow) {
    const r = srow;
    const h = r.h;
    const eb = (h.rev * h.m) / 100;
    const nx = nextOf(r);
    sel = {
      eyebrow: !r.present
        ? "Not yet in the pipeline on this date"
        : r.passed
          ? "Passed at " + PL_STAGES[r.ps.at].code + " · " + PL_STAGES[r.ps.at].name
          : "Stage " + PL_STAGES[r.st].code + " · " + PL_STAGES[r.st].name,
      title: "Project " + h.cn,
      name: h.name,
      sub: h.v + " · " + h.city + ", " + h.ctry + " · Founded " + h.est,
      desc: h.desc,
      figs: [
        { k: "Revenue · LTM", v: plFe(h.rev) },
        { k: "EBITDA margin", v: h.m + "%" },
        { k: r.st >= 2 ? "Enterprise value · LOI" : "Enterprise value · est.", v: plFm(h.ev) },
        { k: "EV / EBITDA", v: (h.ev / eb).toFixed(1) + "×" },
        { k: "Fund I equity", v: plFe(h.eq) },
        { k: "Position", v: h.pos },
      ],
      path: PL_STAGES.map((g, i) => {
        const d = r.hist[i];
        const done = d != null && d <= asOf;
        const cur = done && i === r.st && !r.passed;
        const dur =
          done && i < r.st
            ? plDays(Math.round((r.hist[i + 1] - d) / PL_DAY))
            : cur
              ? i === 5
                ? "Held"
                : "Day " + r.age + " · target " + g.target
              : done && r.passed && i === r.st
                ? plDays(r.age) + ", then passed"
                : "";
        return {
          code: g.code,
          name: g.name,
          date: done ? plFM(d) : "—",
          dur,
          mark: cur ? "var(--gold-500)" : done ? "var(--sapphire-200)" : "transparent",
          markBd: done ? "0" : "1px solid var(--sapphire-400)",
          fg: done ? "var(--alabaster)" : "var(--sapphire-400)",
          cur,
          durFg: cur && i < 5 && r.age > g.target ? "var(--gold-400)" : "var(--sapphire-200)",
        };
      }),
      hasWs: r.st >= 2,
      ws: PL_WS.map((n, i) => {
        const v = (h.ws || [])[i] || 0;
        return {
          n,
          lbl: ["Not started", "In progress", "Complete"][v],
          fill: v === 2 ? "var(--gold-500)" : v === 1 ? "rgba(197,160,89,.3)" : "transparent",
          bd: v === 0 ? "1px solid var(--sapphire-400)" : "1px solid var(--gold-500)",
          fg: v === 2 ? "var(--gold-200)" : v === 1 ? "var(--gold-400)" : "var(--sapphire-200)",
        };
      }),
      hasNext: r.active,
      next: nx[0],
      nextDate: nx[1],
      lead: h.lead,
      isPassed: r.passed,
      passWhy: r.passed ? r.ps.why : "",
      passDate: r.passed ? plFL(r.ps.d) : "",
    };
  }

  const Action = window.AccessActionButton;
  const Mark = window.AccessLevelMark;
  const activeCount = act.filter((r) => r.st < 5).length;
  const ledgerCount = actM.length === 1 ? "1 house" : actM.length + " houses";
  const lead = detail
    ? "Every house screened for Folclore Latin Fund I, from the wider universe to close. Screened houses appear as counts; from Analysis on, under project names. The names of the houses open at Level 4."
    : "A counts-only view of every house screened for Folclore Latin Fund I. Project names and the interactive book open at Level 2, after the NDA.";

  return (
    <React.Fragment>
      <article className={"pl" + (sel ? " is-drawer" : "")}>
        <header className="pl-hero">
          <div className="pl-hero-copy">
            <span className="pl-eyebrow">Fund I · Pipeline{detail ? " · Under NDA" : " · Snapshot"}</span>
            <h1>Deal pipeline</h1>
            <p className="pl-lead">{lead}</p>
            <p className="pl-note">Illustrative sample book until the sourcing file replaces it.</p>
          </div>
          <div className="pl-kpis">
            {kpis.map((k) => (
              <div key={k.k} className="pl-kpi">
                <span className="pl-kpi-k">{k.k}</span>
                <span className={"pl-kpi-v" + (k.gold ? " is-gold" : "")}>{k.v}</span>
              </div>
            ))}
          </div>
        </header>

        {detail && (
          <div className="pl-toolbar">
            <div className="pl-chips">
              {["All", ...PL_VERTS].map((v) => {
                const on = vert === v;
                const n = act.filter((r) => v === "All" || r.h.v === v).length;
                return (
                  <button
                    key={v}
                    type="button"
                    className={"pl-chip" + (on ? " is-on" : "")}
                    onClick={() => setVert(v)}
                  >
                    <span>{v}</span>
                    <span className="pl-chip-n">{n}</span>
                  </button>
                );
              })}
            </div>
            <div className="pl-size">
              <span className="pl-kpi-k">Size by</span>
              <div className="pl-seg">
                {["Enterprise value", "Fund I equity", "Equal"].map((o) => (
                  <button
                    key={o}
                    type="button"
                    className={"pl-seg-btn" + (sizeBy === o ? " is-on" : "")}
                    onClick={() => setSizeBy(o)}
                  >
                    {o}
                  </button>
                ))}
              </div>
            </div>
          </div>
        )}

        {detail && (
          <div className="pl-scrub">
            <button
              type="button"
              className={"pl-play" + (playing ? " is-on" : "")}
              aria-label="Replay the year"
              onClick={togglePlay}
            >
              {playing ? (
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
                  <rect x="6" y="4" width="4" height="16" /><rect x="14" y="4" width="4" height="16" />
                </svg>
              ) : (
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
                  <polygon points="6 3 20 12 6 21 6 3" />
                </svg>
              )}
            </button>
            <div className="pl-asof">
              <span className="pl-kpi-k">As of</span>
              <span className="pl-asof-v">{plFL(asOf)}</span>
              {!live ? (
                <button
                  type="button"
                  className="pl-text-btn"
                  onClick={() => {
                    stop();
                    setTAsOf(PL_TODAY);
                  }}
                >
                  Return to today
                </button>
              ) : (
                <span className="pl-asof-hint">Today · replay the year</span>
              )}
            </div>
            <div
              ref={trackRef}
              className="pl-track"
              onPointerDown={onTrackDown}
              role="slider"
              aria-valuemin={0}
              aria-valuemax={100}
              aria-valuenow={Math.round(((asOf - PL_START) / span) * 100)}
              aria-label="Pipeline as-of date"
            >
              <div className="pl-track-line" />
              <div className="pl-track-fill" style={{ width: pctOf(asOf) }} />
              {events.map((e, i) => (
                <span
                  key={i}
                  className={"pl-track-ev" + (e.gold ? " is-gold" : e.soft ? " is-soft" : " is-pass")}
                  style={{ left: e.left }}
                />
              ))}
              {months.map((m) => (
                <span key={m.label} className="pl-track-mo" style={{ left: m.left }}>
                  {m.label}
                </span>
              ))}
              <span className="pl-track-knob" style={{ left: pctOf(asOf) }} />
            </div>
          </div>
        )}

        <div className="pl-funnel-scroll">
          <div className="pl-funnel">
            <div className="pl-phases">
              <div className="pl-phase pl-phase-uni">
                <span className="pl-phase-name is-muted">Universe</span>
                <span className="pl-phase-n">{uNow.length}</span>
              </div>
              <div className="pl-phase pl-phase-pre">
                <span className="pl-phase-name">Analysis</span>
                <span className="pl-phase-n">{pre === 1 ? "1 house" : pre + " houses"}</span>
              </div>
              <div className="pl-phase pl-phase-post">
                <span className="pl-phase-name is-gold">LOI to close</span>
                <span className="pl-phase-n is-gold">{post === 1 ? "1 house" : post + " houses"}</span>
              </div>
            </div>

            <div className="pl-heads">
              {heads.map((h) => (
                <div key={h.code} className="pl-head">
                  <div className="pl-head-top">
                    <span className={"pl-head-code" + (h.gold ? " is-gold" : "")}>{h.code}</span>
                    <span className="pl-head-name">{h.name}</span>
                  </div>
                  {showDesc && <span className="pl-head-desc">{h.desc}</span>}
                  <span className="pl-head-meta">
                    {h.count} · {h.ev}
                  </span>
                </div>
              ))}
            </div>

            <div
              className="pl-canvas"
              style={{ height: canvasH }}
              onMouseLeave={() => setHover(null)}
            >
              {bands.map((b, i) => (
                <div
                  key={i}
                  className="pl-band"
                  style={{
                    left: b.left,
                    width: b.width,
                    top: b.top,
                    height: b.height,
                    borderLeft: b.bl,
                    borderRight: b.br,
                  }}
                />
              ))}
              {gates.map((g, i) => (
                <div key={i} className="pl-gate" style={{ left: g.left }}>
                  <span className={g.gold ? "is-gold" : ""}>{g.pct}</span>
                </div>
              ))}
              <button type="button" className="pl-uni-mark" onClick={goUniverse}>
                <span className="pl-uni-n">{uNow.length}</span>
                <span className="pl-kpi-k">Screened</span>
                <span className="pl-uni-link">See the universe</span>
              </button>
              {showPassed && (
                <div className="pl-passed" style={{ top: SED + "px" }}>
                  <span className="pl-passed-lbl">Passed · {rows.filter((r) => r.passed).length}</span>
                </div>
              )}
              {thread.on && (
                <React.Fragment>
                  <div
                    className="pl-thread"
                    style={{ left: thread.left, top: thread.top, width: thread.w, background: thread.bg }}
                  />
                  {thread.ticks.map((k, i) => (
                    <React.Fragment key={i}>
                      <span className="pl-tick" style={{ left: k.left, top: k.top }} />
                      <span className="pl-tick-lbl" style={{ left: k.left, top: k.top, transform: k.tf }}>
                        {k.date}
                      </span>
                    </React.Fragment>
                  ))}
                </React.Fragment>
              )}
              {dots.map((d) => (
                <div
                  key={d.id}
                  className="pl-dot"
                  style={{
                    left: d.left,
                    top: d.top,
                    width: d.size,
                    height: d.size,
                    background: d.bg,
                    border: d.bd,
                    boxShadow: d.ring,
                    opacity: d.op,
                    pointerEvents: d.pe,
                    zIndex: d.z,
                  }}
                  onClick={() => setSelected(d.id)}
                  onMouseEnter={() => setHover(d.id)}
                >
                  <span
                    className="pl-dot-lbl"
                    style={{
                      left: d.lL,
                      right: d.lR,
                      top: d.lT,
                      transform: d.lTf,
                      fontSize: d.lFs,
                      color: d.lFg,
                    }}
                  >
                    {d.label}
                  </span>
                </div>
              ))}
              {tip.on && (
                <div className="pl-tip" style={{ left: tip.left, top: tip.top }}>
                  <span className="pl-tip-title">{tip.title}</span>
                  <span className="pl-tip-sub">{tip.sub}</span>
                  <span className="pl-tip-line">{tip.line}</span>
                </div>
              )}
            </div>
          </div>
        </div>

        <div className="pl-legend">
          <span><i className="pl-swatch is-plain" />Analysis</span>
          <span><i className="pl-swatch is-gold" />LOI to close</span>
          <span><i className="pl-swatch is-over" />Past stage target</span>
          <span><i className="pl-swatch is-pass" />Passed</span>
          <span><strong>54%</strong> Share reaching the next stage</span>
          {detail && (
            <em>Within each stage, a house drifts toward the next gate as the days pass.</em>
          )}
        </div>

        <section className="pl-uni" ref={uniRef}>
          <div className="pl-uni-head">
            <div>
              <span className="pl-eyebrow">Stage 00 · Universe</span>
              <h2>The universe</h2>
              <p className="pl-lead-sm">
                Every house screened against the Fund I thesis, by vertical and country. Shown as counts; the names of screened houses are not shared.
              </p>
            </div>
            <div className="pl-kpis">
              {uniKpis.map((k) => (
                <div key={k.k} className="pl-kpi">
                  <span className="pl-kpi-k">{k.k}</span>
                  <span className={"pl-kpi-v sm" + (k.gold ? " is-gold" : "")}>{k.v}</span>
                </div>
              ))}
            </div>
          </div>

          <div className="pl-matrix-head">
            <span className="pl-italic">By vertical and country</span>
            <div className="pl-readout">
              <span className="pl-eyebrow gold">{readout.k}</span>
              <span>{readout.v}</span>
            </div>
          </div>
          <div className="pl-matrix-scroll" onMouseLeave={() => setCell(null)}>
            <div className="pl-matrix">
              <div className="pl-matrix-row is-head">
                <span />
                {mHeads.map((c) => (
                  <span key={c.n} className={c.hot ? "is-hot" : ""}>
                    {c.n}
                  </span>
                ))}
                <span className="pl-matrix-total-h">Total</span>
              </div>
              {mRows.map((r) => (
                <div key={r.label} className="pl-matrix-row" style={{ opacity: r.op }}>
                  <div className={"pl-matrix-label" + (r.hot ? " is-hot" : "")}>{r.label}</div>
                  {r.cells.map((c) => (
                    <div
                      key={c.c}
                      className="pl-matrix-cell"
                      style={{ background: c.bg, boxShadow: c.ring }}
                      onMouseEnter={() => setCell({ v: c.v, c: c.c })}
                    >
                      <span className={c.empty ? "is-empty" : ""}>{c.n}</span>
                      <div className="pl-ticks">
                        {c.ticks.map((k, i) => (
                          <span key={i} className={k === "gold" ? "is-gold" : ""} />
                        ))}
                      </div>
                    </div>
                  ))}
                  <div className="pl-matrix-total">{r.total}</div>
                </div>
              ))}
              <div className="pl-matrix-row is-foot">
                <span className="pl-kpi-k">All verticals</span>
                {mTotals.map((n, i) => (
                  <span key={PL_COUNTRIES[i]} className="pl-matrix-foot-n">
                    {n}
                  </span>
                ))}
                <span className="pl-matrix-grand">{uNow.length}</span>
              </div>
            </div>
          </div>
          <div className="pl-legend tight">
            <span><i className="pl-tick-swatch" />One house screened</span>
            <span><i className="pl-tick-swatch is-gold" />Reached Analysis or beyond</span>
          </div>

          <div className="pl-src-head">
            <span className="pl-italic">Where houses come from</span>
            <span className="pl-src-note">By first introduction · rate is the share reaching Analysis</span>
          </div>
          <div className="pl-src-scroll">
            <div className="pl-src">
              <div className="pl-src-row is-head">
                <span>Source</span>
                <span />
                <span className="num">Screened</span>
                <span className="num">To Analysis</span>
                <span className="num">Rate</span>
              </div>
              {srcRows.map((x) => (
                <div key={x.k} className="pl-src-row">
                  <span className="pl-src-k">{x.k}</span>
                  <div className="pl-src-bar">
                    <span style={{ width: x.w }} />
                    <span className="is-gold" style={{ width: x.aw }} />
                  </div>
                  <span className="num">{x.n}</span>
                  <span className="num is-gold">{x.a}</span>
                  <span className={"num" + (x.hot ? " is-gold" : "")}>{x.rate}</span>
                </div>
              ))}
            </div>
          </div>
        </section>

        <div className="pl-ledger-head">
          <div>
            <h2>Active houses</h2>
            <span className="pl-ledger-sub">
              {detail ? "Closest to close first." : "Named projects open at Level 2."}
            </span>
          </div>
          <span className="pl-kpi-k">{ledgerCount}</span>
        </div>

        {!detail ? (
          <div className="pl-l1-gate">
            <div>
              <span className="pl-eyebrow">Level 2 · Qualified LP diligence</span>
              <p className="pl-prose">
                {activeCount} active houses sit in the book today. Sign the NDA to see project names, the year scrubber, and each house’s path through the funnel.
              </p>
            </div>
            {typeof Mark === "function" && <Mark level={2} />}
            {typeof Action === "function" && <Action level={2} access={access} prominent />}
            {access.ndaNote && <p className="pl-caption">{access.ndaNote}</p>}
            {typeof window.NdaCopyLink === "function" && (
              <window.NdaCopyLink label={access.ndaCopyLink} />
            )}
          </div>
        ) : (
          <React.Fragment>
            <div className={"pl-ledger-cols" + (showWide ? " is-wide" : "")}>
              <span>Project</span>
              <span>House</span>
              <span>Stage</span>
              <span className="num">In stage</span>
              <span className="num">EV</span>
              {showWide && <span className="num">Fund I</span>}
              {showWide && <span>Next</span>}
            </div>
            {ledger.map((r) => (
              <button
                key={r.id}
                type="button"
                className={"pl-ledger-row" + (showWide ? " is-wide" : "") + (r.on ? " is-on" : "")}
                onClick={() => setSelected(r.id)}
                onMouseEnter={() => setHover(r.id)}
                onMouseLeave={() => setHover(null)}
              >
                <div className="pl-ledger-proj">
                  <span className="pl-ledger-cn">{r.cn}</span>
                  <span className="pl-ledger-sub">{r.sub}</span>
                </div>
                <div className="pl-ledger-house">
                  {level4 ? (
                    <span className="pl-name-italic sm">{r.name}</span>
                  ) : (
                    <span className="pl-locked-pill">
                      <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                        <rect width="18" height="11" x="3" y="11" rx="2" ry="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" />
                      </svg>
                      Level 4
                    </span>
                  )}
                </div>
                <div className="pl-ledger-stage">
                  <span className={r.gold ? "is-gold" : ""}>{r.code}</span>
                  <span>{r.stage}</span>
                </div>
                <div className="pl-ledger-days">
                  <span className={r.over ? "is-over" : ""}>{r.days}</span>
                  <span>{r.daysSub}</span>
                </div>
                <span className="pl-ledger-ev">{r.ev}</span>
                {showWide && <span className="pl-ledger-eq">{r.eq}</span>}
                {showWide && (
                  <div className="pl-ledger-next">
                    <span>{r.next}</span>
                    <span>{r.nextDate}</span>
                  </div>
                )}
              </button>
            ))}
          </React.Fragment>
        )}
      </article>

      {sel &&
        ReactDOM.createPortal(
          <PipelineDrawer
            sel={sel}
            level4={level4}
            access={access}
            onClose={() => setSelected(null)}
          />,
          document.body
        )}
    </React.Fragment>
  );
}

Object.assign(window, {
  PipelinePage,
  PIPELINE_HOUSES,
});
