// Control Room: Listing detail (keyed by listing — every row lands on its own
// evidence) + Team productivity. v2: per-listing demand profile via D.detailFor,
// cold-start detail for day-2 listings, sr-only chart summaries, named agents in
// the showing log link to Recruiting, team modal listings link to listing detail.
;(function(){
const DS = window.DoorpassDesignSystem_eaad52;
const { Button, Avatar, Badge } = DS;
const D = window.CRData;
const { CRIcon, CRPage, CRChip, CRSpark, CRCard, CRTh, CRRow, CRLink, CRPhoto, CRDef,
        CRLatency, CREmpty, useCRSort, crSorted, crMono } = window;

/* ============ 03 · Listing detail — demand profile ============ */

function VelocityChart({ velo, comp, w = 560, h = 170 }) {
  const padL = 30, padB = 22, padT = 12, padR = 10;
  const iw = w - padL - padR, ih = h - padT - padB;
  const max = Math.max(...velo, ...comp.map((c) => c * 1.3), 1);
  const n = velo.length;
  const x = (i) => padL + (n < 2 ? iw / 2 : (i / (n - 1)) * iw);
  const y = (v) => padT + ih - (v / max) * ih;
  const bandTop = comp.map((c, i) => `${x(i)},${y(c * 1.3)}`).join(" ");
  const bandBot = comp.map((c, i) => `${x(i)},${y(c * 0.7)}`).reverse().join(" ");
  return (
    <svg width={w} height={h} style={{ display: "block", maxWidth: "100%" }} aria-hidden="true">
      {[0, Math.round(max / 2), max].map((v, i) => (
        <g key={i}>
          <line x1={padL} x2={w - padR} y1={y(v)} y2={y(v)} stroke="var(--line-200)" strokeWidth="1" />
          <text x={padL - 7} y={y(v) + 4} textAnchor="end" fontSize="12" fontFamily="var(--font-mono)" fill="var(--neutral-500)">{v}</text>
        </g>
      ))}
      {comp.length > 1 && <polygon points={`${bandTop} ${bandBot}`} fill="var(--mist-100)" opacity="0.9" />}
      {comp.length > 1 && <polyline points={comp.map((c, i) => `${x(i)},${y(c)}`).join(" ")} fill="none" stroke="var(--neutral-300)" strokeWidth="1.4" strokeDasharray="3 4" />}
      {velo.length > 1 && <polyline points={velo.map((v, i) => `${x(i)},${y(v)}`).join(" ")} fill="none" stroke="var(--green-800)" strokeWidth="2.2" strokeLinejoin="round" strokeLinecap="round" />}
      {velo.map((v, i) => <circle key={i} cx={x(i)} cy={y(v)} r="3" fill="var(--green-800)" stroke="var(--surface-card)" strokeWidth="1.5" />)}
      {velo.map((v, i) => (
        <text key={"t" + i} x={x(i)} y={h - 6} textAnchor="middle" fontSize="12" fontFamily="var(--font-mono)" fill="var(--neutral-500)">W{i + 1}</text>
      ))}
    </svg>
  );
}

// Narrative insight under the chart — generated from the row's own numbers,
// and doubling as the chart's screen-reader summary.
function velocityInsight(l) {
  const wk = l.velo.length;
  if (l.cat === "uc") return <>Showings wound down into week {wk} — <strong style={{ color: "var(--blue-700)" }}>under contract</strong>. History is retained for the seller report.</>;
  if (l.vsComp >= 10) return <>Week {wk} ran <strong style={{ color: "var(--green-800)" }}>+{l.vsComp}% above</strong> the comp-set median — demand is accelerating, not decaying.</>;
  if (l.vsComp <= -10) return <>Week {wk} ran <strong style={{ color: "var(--red-600)" }}>{l.vsComp}% below</strong> the comp-set median — the price-cut pattern. Listings on this curve cut within 21 days, 78% of the time.</>;
  return <>Week {wk} is tracking <strong style={{ color: "var(--green-800)" }}>within ±10%</strong> of the comp-set median — on pace for this price band.</>;
}

function HeatLegendDot({ bg, ring, label }) {
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 11, fontWeight: 500, color: "var(--neutral-500)" }}>
      <span style={{ width: 10, height: 10, borderRadius: 3, background: bg, boxShadow: ring ? `inset 0 0 0 1.2px ${ring}` : "inset 0 0 0 1px var(--line-200)" }}></span>{label}
    </span>
  );
}

function Heatmap({ data }) {
  const { dayparts, days, values, outside } = data;
  const max = Math.max(...values.flat(), 1);
  const total = values.flat().reduce((a, b) => a + b, 0);
  const isOut = (r, c) => outside.some(([or, oc]) => or === r && oc === c);
  return (
    <div>
      <span className="sr-only">{total} requests this month, concentrated on weekend afternoons.{outside.length ? " Some Sunday-morning requests fall outside the showing windows." : ""}</span>
      <div aria-hidden="true" style={{ display: "grid", gridTemplateColumns: `72px repeat(${days.length}, 1fr)`, gap: 4 }}>
        <span></span>
        {days.map((d) => <span key={d} style={{ textAlign: "center", fontSize: 11.5, fontFamily: "var(--font-mono)", fontWeight: 500, color: "var(--neutral-500)" }}>{d}</span>)}
        {values.map((row, r) => (
          <React.Fragment key={r}>
            <span style={{ fontSize: 11, fontWeight: 600, color: "var(--neutral-700)", alignSelf: "center" }}>{dayparts[r]}</span>
            {row.map((v, c) => (
              <span key={c} title={`${v} requests`} style={{
                height: 26, borderRadius: 5,
                background: v === 0 ? "var(--mist-100)" : `rgba(47,140,106,${0.16 + (v / max) * 0.74})`,
                boxShadow: isOut(r, c) ? "inset 0 0 0 1.5px var(--amber-600)" : "inset 0 0 0 1px rgba(5,31,17,0.04)",
                display: "grid", placeItems: "center",
              }}>
                {v > 0 && <span style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, fontWeight: 600, color: v / max > 0.55 ? "#fff" : "var(--green-900)" }}>{v}</span>}
              </span>
            ))}
          </React.Fragment>
        ))}
      </div>
      <div style={{ display: "flex", gap: 14, marginTop: 10 }}>
        <HeatLegendDot bg="rgba(47,140,106,0.6)" label="requests" />
        {outside.length > 0 && <HeatLegendDot bg="var(--mist-100)" ring="var(--amber-600)" label="outside showing windows" />}
      </div>
    </div>
  );
}

function Funnel({ data }) {
  const max = data[0].n || 1;
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 7 }}>
      <span className="sr-only">{data.map((s) => `${s.stage}: ${s.n}`).join(", ")}.</span>
      {data.map((s, i) => (
        <div key={s.stage} aria-hidden="true" style={{ display: "grid", gridTemplateColumns: "84px 1fr 30px", gap: 10, alignItems: "center" }}>
          <span style={{ fontSize: 12, fontWeight: 600, color: "var(--neutral-700)" }}>{s.stage}</span>
          <span style={{ height: 16, borderRadius: 4, background: "var(--mist-100)", overflow: "hidden", display: "block" }}>
            <span style={{ display: "block", height: "100%", width: `${Math.max((s.n / max) * 100, 3)}%`, background: i < 3 ? "var(--green-600)" : "var(--green-800)", borderRadius: 4 }}></span>
          </span>
          <span style={{ ...crMono(12.5), textAlign: "right" }}>{s.n}</span>
        </div>
      ))}
    </div>
  );
}

function CRListingDetail({ go, listingId }) {
  const detail = D.detailFor(listingId || "oakmont");
  const l = detail.listing;
  const a = D.byId(l.agent);
  const head = (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 10, whiteSpace: "nowrap" }}>
      <span>{l.hood} · {l.price} · day {l.days}</span>
      <span style={{ display: "inline-flex", alignItems: "center", gap: 5 }}><Avatar name={a.name} size={18} /><CRLink onClick={() => go("team")} size={13.5} weight={600} color="var(--neutral-700)">{a.name}</CRLink></span>
      {l.cat === "uc" ? <Badge tone="neutral">Under contract</Badge> : <Badge tone="live" dot>Active</Badge>}
      <CRChip tone="neutral">Rules · {l.rules}</CRChip>
    </span>
  );

  if (detail.cold) {
    return (
      <CRPage
        label="03 Listing detail"
        eyebrow={<button className="cr-ia cr-link" onClick={() => go("listings")} style={{ display: "inline-flex", whiteSpace: "nowrap", fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.08em", color: "var(--neutral-500)", textTransform: "uppercase" }}>← Listings</button>}
        title={<span style={{ display: "inline-flex", alignItems: "center", gap: 12 }}><CRPhoto listing={l} w={44} h={34} radius={9} />{l.addr}</span>}
        sub={head}
        actions={<Button variant="primary" size="sm" leadingIcon={<CRIcon name="lock" size={14} />}>Finish lock setup</Button>}
      >
        <CRCard>
          {/* Day-2 listing: the showings that could exist here — ghost Pass empty state */}
          <CREmpty ghost title="No verified events yet — day 2 of this listing"
            body="The demand profile builds itself from the first verified showing: velocity vs comps, request heatmap, conversion ladder, and the showing log. Lock pairing is the only step left."
            action={<Button variant="secondary" size="sm" onClick={() => go("operations")}>View lock status</Button>} />
        </CRCard>
      </CRPage>
    );
  }

  const requested = detail.funnel[0].n;
  return (
    <CRPage
      label="03 Listing detail"
      eyebrow={<button className="cr-ia cr-link" onClick={() => go("listings")} style={{ display: "inline-flex", whiteSpace: "nowrap", fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.08em", color: "var(--neutral-500)", textTransform: "uppercase" }}>← Listings</button>}
      title={<span style={{ display: "inline-flex", alignItems: "center", gap: 12 }}><CRPhoto listing={l} w={44} h={34} radius={9} />{l.addr}</span>}
      sub={head}
      actions={
        <>
          <Button variant="secondary" size="sm" leadingIcon={<CRIcon name="sliders-horizontal" size={14} />}>Review rules</Button>
          <Button variant="primary" size="sm" leadingIcon={<CRIcon name="file-text" size={14} />}>Generate seller report</Button>
        </>
      }
    >
      <div style={{ display: "grid", gridTemplateColumns: "1.35fr 1fr", gap: 16, marginBottom: 16 }}>
        <CRCard title="Showing velocity vs comp set" info="velocity" hint="band = comp-set range · verified showings/wk">
          <VelocityChart velo={l.velo} comp={l.comp} />
          <div style={{ marginTop: 8, fontSize: 12.5, fontWeight: 500, color: "var(--neutral-700)" }}>
            {velocityInsight(l)}
          </div>
        </CRCard>
        <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
          <CRCard title="Conversion ladder" hint="lifetime — deviates from global period">
            <Funnel data={detail.funnel} />
          </CRCard>
          {detail.suppressed ? (
            <CRCard title="Suppressed demand" style={{ background: "var(--cream-100)", boxShadow: "var(--shadow-ring), 0 2px 4px rgba(5,31,17,0.08)" }}
              action={<Button variant="secondary" size="sm">Review rules</Button>}>
              <div style={{ display: "flex", gap: 12, alignItems: "flex-start" }}>
                <span style={{ ...crMono(26, "var(--amber-700)"), lineHeight: "30px" }}>{detail.suppressed.n}</span>
                <span style={{ fontSize: 12.5, fontWeight: 500, color: "var(--neutral-700)", lineHeight: "17px" }}>
                  {detail.suppressed.lead}<strong style={{ color: "var(--amber-700)" }}>{detail.suppressed.em}</strong>{detail.suppressed.rest}
                </span>
              </div>
            </CRCard>
          ) : (
            <CRCard pad={14} style={{ background: "var(--surface-tint)", boxShadow: "inset 0 0 0 1px var(--green-300)" }}>
              <div style={{ display: "flex", gap: 10, alignItems: "flex-start" }}>
                <CRIcon name="badge-check" size={16} color="var(--green-800)" style={{ marginTop: 1 }} />
                <span style={{ fontSize: 12.5, fontWeight: 600, color: "var(--green-900)", lineHeight: "17px" }}>
                  No suppressed demand — every request this month landed inside the showing windows and was decided in time.
                </span>
              </div>
            </CRCard>
          )}
        </div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "1fr 1.35fr", gap: 16 }}>
        <CRCard title="Requests by day & daypart" hint={`this month · ${requested} requests`}>
          <Heatmap data={detail.heatmap} />
        </CRCard>
        <CRCard title="Showing log" info="duration" hint="true durations from verified entry/exit" pad={10}>
          <CRTh cols="118px 1fr 130px 70px 84px" labels={["Verified", "Agent", "Brokerage", "Duration", ""]} aligns={["left", "left", "left", "right", "left"]} />
          {detail.log.map((s, i) => (
            <CRRow key={i} cols="118px 1fr 130px 70px 84px" last={i === detail.log.length - 1}>
              <span style={crMono(11.5, "var(--neutral-700)", 500)}>{s.ts}</span>
              <CRLink onClick={() => go("recruiting")}>{s.agent}</CRLink>
              <span style={{ fontSize: 12, fontWeight: 500, color: "var(--neutral-500)" }}>{s.brokerage}</span>
              <span style={{ ...crMono(12.5), textAlign: "right" }}>{s.dur}</span>
              <span>{s.repeat ? <CRChip tone="good">{s.note}</CRChip> : null}</span>
            </CRRow>
          ))}
        </CRCard>
      </div>
    </CRPage>
  );
}

/* ============ 04 · Team — true productivity ============ */

const TCOLS = "minmax(150px,1.2fr) 70px 112px 145px 118px 140px 24px";
const TSORT = {
  name: (a) => a.name, listings: (a) => a.listings, showings: (a) => a.showings,
  latency: (a) => a.latency, approval: (a) => a.approval,
};

function MiniLadder({ ladder }) {
  const max = ladder[0];
  return (
    <span aria-hidden="true" style={{ display: "inline-flex", alignItems: "flex-end", gap: 2.5, height: 20 }}>
      {ladder.map((n, i) => (
        <span key={i} style={{ width: 7, height: Math.max((n / max) * 20, 2), borderRadius: 2, background: i < 3 ? "var(--green-600)" : "var(--green-800)" }}></span>
      ))}
    </span>
  );
}

function AgentDrill({ agent, onClose, go, focus }) {
  const lst = D.listings.filter((l) => l.agent === agent.id);
  const openListing = (id) => { onClose(); go("listing", id); };
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);
  return (
    <div onClick={onClose} style={{
      position: "fixed", inset: 0, zIndex: 50, background: "rgba(5,31,17,0.45)",
      display: "flex", alignItems: "center", justifyContent: "center",
    }}>
      <div onClick={(e) => e.stopPropagation()} role="dialog" aria-label={`${agent.name} details`} style={{
        width: 680, background: "var(--surface-card)", borderRadius: "var(--radius-lg)",
        boxShadow: "var(--shadow-float)", padding: 26,
      }}>
        <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
          <Avatar name={agent.name} size={44} />
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 17, fontWeight: 800, color: "var(--green-950)" }}>{agent.name}</div>
            <div style={{ fontSize: 12, fontWeight: 500, color: "var(--neutral-500)" }}>{agent.role} · {agent.listings} listings</div>
          </div>
          <button className="cr-ia cr-def-btn" onClick={onClose} aria-label="Close" style={{ padding: 8 }}><CRIcon name="x" size={16} color="currentColor" /></button>
        </div>

        <div style={{ display: "grid", gridTemplateColumns: "240px 1fr", gap: 24, marginTop: 20 }}>
          <div>
            <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
              <div style={{ background: "var(--mist-100)", borderRadius: "var(--radius-sm)", padding: "10px 12px" }}>
                <div style={{ fontSize: 11, fontWeight: 600, color: "var(--neutral-500)", display: "flex", alignItems: "center", gap: 4 }}>Showings · wk <CRDef k="showings" align="left" /></div>
                <div style={crMono(20)}>{agent.showings}</div>
              </div>
              <div style={{ background: "var(--mist-100)", borderRadius: "var(--radius-sm)", padding: "10px 12px" }}>
                <div style={{ fontSize: 11, fontWeight: 600, color: "var(--neutral-500)", display: "flex", alignItems: "center", gap: 4 }}>Approval rate <CRDef k="approval" align="left" /></div>
                <div style={crMono(20)}>{agent.approval}%</div>
              </div>
            </div>
            {/* The coaching metric — the Coach CTA on Overview lands here, pre-focused (A9). */}
            <div style={focus === "latency" ? { margin: "16px -10px 0", padding: "10px 10px 12px", borderRadius: "var(--radius-sm)", background: "var(--cream-100)", boxShadow: "inset 0 0 0 1.5px var(--amber-600)" } : { marginTop: 16 }}>
              <div style={{ fontSize: 12, fontWeight: 700, color: "var(--green-950)", margin: "0 0 6px", display: "inline-flex", alignItems: "center", gap: 5 }}>Response latency · 8 wks {focus === "latency" && <CRDef k="drift" align="left" />}</div>
              <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
                <CRSpark data={agent.latencyTrend} w={160} h={36} color={agent.latency > 20 ? "var(--red-600)" : "var(--green-600)"} baseline={9} />
                <CRLatency min={agent.latency} />
              </div>
              {focus === "latency" && (
                <div style={{ marginTop: 8, fontSize: 12, fontWeight: 500, color: "var(--neutral-700)", lineHeight: "16px" }}>
                  Rising 8 weeks against a team median of 9 — est. 2 showings lost last week. Open-windows rules on {agent.name.split(" ")[0] === "D." ? "Okafor's" : "their"} 2 listings would decide these instantly.
                </div>
              )}
            </div>
          </div>

          <div>
            <div style={{ fontSize: 12, fontWeight: 700, color: "var(--green-950)", marginBottom: 4 }}>Listings — each opens its detail</div>
            {lst.map((l, i) => (
              <CRRow key={l.id} cols="30px 1fr 70px 110px" last={i === lst.length - 1} onClick={() => openListing(l.id)} ariaLabel={`${l.addr} — open listing detail`}>
                <CRPhoto listing={l} w={30} h={24} radius={6} />
                <span style={{ minWidth: 0 }}>
                  <span style={{ display: "block", fontSize: 12.5, fontWeight: 700, color: "var(--green-950)" }}>{l.addr}</span>
                  <span style={{ display: "block", fontSize: 11, fontWeight: 500, color: "var(--neutral-500)" }}>{l.hood}</span>
                </span>
                <span style={{ ...crMono(12), textAlign: "right" }}>{l.wk}/wk</span>
                <span style={{ textAlign: "right" }}><CRChip tone={l.forecast.tone} style={{ fontSize: 11 }}>{l.forecast.label}</CRChip></span>
              </CRRow>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

function CRTeam({ go, initial }) {
  const [open, setOpen] = React.useState((initial && initial.open) ? D.byId(initial.open) : null);
  const focus = initial && initial.focus;
  const [sort, onSort] = useCRSort((initial && initial.sort) || "showings", (initial && initial.sort) === "latency" ? "desc" : "desc");
  const rows = crSorted(D.agents, sort, TSORT);
  return (
    <CRPage
      label="04 Team"
      eyebrow="5 agents · Brooks Group"
      title="Team"
      sub={sort.key === "latency" ? "Sorted by response latency — the coaching metric." : "Productivity from verified showing events — not manual logging."}
    >
      <div style={{ position: "relative" }}>
        {/* Comparison lens — team rates vs the same categories at the selected scope */}
        <window.CRBenchBand keys={["response", "approval", "perListing"]} style={{ marginBottom: 12 }} />
        <CRCard pad={10}>
          <CRTh cols={TCOLS}
            labels={["Agent", "Listings", "Showings · wk", "Median response", "Approval rate", "Conversion ladder", ""]}
            aligns={["left", "right", "right", "left", "right", "left", "left"]}
            keys={["name", "listings", "showings", "latency", "approval", null, null]}
            defs={[null, null, "showings", "latency", "approval", "conversion", null]}
            sort={sort} onSort={onSort} />
          {rows.map((a, i) => (
            <CRRow key={a.id} cols={TCOLS} last={i === rows.length - 1} onClick={() => setOpen(a)} ariaLabel={`${a.name} — open agent details`}>
              <span style={{ display: "flex", alignItems: "center", gap: 10 }}>
                <Avatar name={a.name} size={28} />
                <span>
                  <span style={{ display: "block", fontSize: 13, fontWeight: 700, color: "var(--green-950)" }}>{a.name}</span>
                  <span style={{ display: "block", fontSize: 11, fontWeight: 500, color: "var(--neutral-500)" }}>{a.role}</span>
                </span>
              </span>
              <span style={{ ...crMono(12.5), textAlign: "right" }}>{a.listings}</span>
              <span style={{ ...crMono(12.5), textAlign: "right" }}>{a.showings}</span>
              <span><CRLatency min={a.latency} /></span>
              <span style={{ ...crMono(12.5), textAlign: "right" }}>{a.approval}%</span>
              <span><MiniLadder ladder={a.ladder} /></span>
              <span className="cr-row-ch"><CRIcon name="chevron-right" size={14} color="var(--neutral-300)" /></span>
            </CRRow>
          ))}
        </CRCard>

        <div style={{
          marginTop: 14, display: "flex", gap: 12, alignItems: "center",
          background: "var(--surface-tint)", borderRadius: "var(--radius-md)",
          boxShadow: "inset 0 0 0 1px var(--green-300)", padding: "13px 16px",
        }}>
          <CRIcon name="badge-check" size={17} color="var(--green-800)" />
          <span style={{ fontSize: 12.5, fontWeight: 600, color: "var(--green-900)", lineHeight: "17px" }}>
            Measured from verified showing events — not manual logging. Response latency is the coaching metric: every 10 minutes of approval delay costs ~6% of requests.
          </span>
        </div>

        {open && <AgentDrill agent={open} onClose={() => setOpen(null)} go={go} focus={open.id === (initial && initial.open) ? focus : undefined} />}
      </div>
    </CRPage>
  );
}

Object.assign(window, { CRListingDetail, CRTeam });
})();
