/* global React, GOLA, REAL_FINDINGS, ObjRail */
// =========================================================
// Findings (real) — renders authored Findings from the live
// MakerSights claim graph (survey 69f4f3be8c1bee84ade9c9ce, v11)
// grouped by research objective. Reuses the ObjRail sidebar.
// =========================================================

function FindingMetric({ c }) {
  return (
    <div className="gl-ev__metric">
      <span className="gl-ev__metric-val">{c.metricVal}</span>
      <span className="gl-ev__metric-label">{c.metricLabel}</span>
    </div>);

}

// =========================================================
// Finding → "Explore the data" deep link.
// Every finding is a cut of one underlying survey view:
//   · sentiment_score findings  → the Consumer sentiment chart,
//       filtered to one segment (brand affinity q1 / retailer q2 / age q20)
//   · overall findings          → a single survey question, all respondents
// CUT_MAP / QTEXT_MAP translate the finding id + question text into the
// exact section + filter spec the Explore-the-data tab understands.
// =========================================================
const CUT_MAP = {
  ">=55": { qid: "q20", label: ">=55", human: "Age 55+" },
  "18-24": { qid: "q20", label: "18-24", human: "Age 18–24" },
  "ALOHAS": { qid: "q1", label: "ALOHAS", human: "ALOHAS affinity" },
  "Gola": { qid: "q1", label: "Gola", human: "Gola affinity" },
  "Salomon": { qid: "q1", label: "Salomon", human: "Salomon affinity" },
  "Vans": { qid: "q1", label: "Vans", human: "Vans affinity" },
  "Veja": { qid: "q1", label: "Veja", human: "Veja affinity" },
  "Autry": { qid: "q1", label: "Autry", human: "Autry affinity" },
  "Puma": { qid: "q1", label: "Puma", human: "Puma affinity" },
  "Anthropologie": { qid: "q2", label: "Anthropologie", human: "Anthropologie shoppers" },
  "Free People": { qid: "q2", label: "Free People", human: "Free People shoppers" },
  "Department stores": { qid: "q2", label: "Department stores (e.g., Nordstrom, Bloomingdale's)", human: "Department-store shoppers" },
  "Small boutiques": { qid: "q2", label: "Small boutiques or independent shops", human: "Small-boutique shoppers" },
  "Amazon": { qid: "q2", label: "Amazon or online marketplaces", human: "Amazon / online shoppers" },
  "Specialty": { qid: "q2", label: "Specialty shoe retailers (e.g., DSW, Foot Locker, Zappos)", human: "Specialty-retailer shoppers" }
};
const QTEXT_MAP = [
{ re: /lifestyle sneaker brands/i, qid: "q1", short: "Q1 · Brands purchased / considered" },
{ re: /buy shoes in-store or online/i, qid: "q3", short: "Q3 · In-store vs. online" },
{ re: /full price or wait for a sale/i, qid: "q12", short: "Q12 · Full price vs. sale" }];


function findingDataLink(f) {
  const head = String(f.id).split("::")[0];
  const parts = head.split("|");
  if (parts[0] === "product_treatment") {
    // Design-treatment findings: all-respondent product sentiment, trimmed by
    // the products the finding names (handled downstream in FindingDataViz).
    return {
      section: "sentiment",
      filter: { demo: {}, answers: {} },
      qNum: "P1",
      sourceLabel: "Consumer sentiment",
      cutLabel: "All respondents",
      statement: f.statement
    };
  }
  if (parts[0] === "sentiment_score") {
    const m = CUT_MAP[parts[2]];
    if (!m) return null;
    return {
      section: "sentiment",
      filter: { demo: {}, answers: { [m.qid]: [m.label] } },
      qNum: m.qid.toUpperCase(),
      sourceLabel: "Consumer sentiment",
      cutLabel: m.human,
      statement: f.statement
    };
  }
  const qm = QTEXT_MAP.find((x) => x.re.test(f.question || ""));
  if (qm) {
    return {
      section: "question",
      qid: qm.qid,
      sourceLabel: qm.short,
      cutLabel: "All respondents",
      statement: f.statement
    };
  }
  return null;
}

function TraceToData({ link }) {
  const store = React.useContext(window.PinContext);
  if (!link) return null;
  return (
    <button
      className="gl-rf-trace"
      onClick={() => store && store.navigateToData && store.navigateToData(link)}
      title={"Open in Explore the data — " + link.sourceLabel + " · " + link.cutLabel}>
      
      <span className="gl-rf-trace__txt">Explore the data →</span>
    </button>);

}

// Renders eyebrow context as design-system badges (one per segment).
function VizBadges({ parts }) {
  return (
    <span className="gl-rf-vizbadges">
      {parts.filter((p) => p && p.label).map((p, i) =>
      <span key={i} className={"gl-rf-vizbadge gl-rf-vizbadge--" + (p.tone || "gray")}>{p.label}</span>
      )}
    </span>);

}

// Inline mini bar chart — surfaces the finding's underlying data on the card.
// sentiment findings → the segment's product sentiment scores (top products);
// overall findings   → the question's answer distribution.
function FindingDataViz({ link, study, bench, finding }) {
  const viz = React.useMemo(() => {
    if (!study || !link || !window.StudyData) return null;
    // Text the finding actually discusses — used to trim the chart to mentioned items.
    const text = (finding ? (finding.statement || "") + " " + (finding.prose || "") : "").toLowerCase();
    const mentions = (rows, keyOf) => {
      if (!text) return [];
      return rows.filter((r) => {
        const key = String(keyOf(r)).split(" (")[0].trim().toLowerCase();
        if (key.length < 3) return false;
        const re = new RegExp("\\b" + key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "\\b");
        return re.test(text);
      });
    };
    if (link.section === "sentiment") {
      if (!window.csScore) return null;
      const f = { demo: {}, answers: {} };
      Object.entries(link.filter.answers || {}).forEach(([k, v]) => {f.answers[k] = new Set(v);});
      const resp = StudyData.filterRespondents(f);
      const prods = StudyData.aggregateAllProducts(resp).
      filter((p) => p.n > 0).
      map((p) => ({ key: p.id, id: p.id, label: p.title, score: window.csScore(p.meanRating) })).
      sort((a, b) => b.score - a.score);
      const named = mentions(prods, (p) => p.label);
      const rows = named.length > 0 && named.length < prods.length ? named.slice(0, 8) : prods.slice(0, 6);
      return { kind: "sentiment", rows, n: resp.length, focused: named.length > 0 && named.length < prods.length };
    }
    const agg = StudyData.aggregateQuestion(link.qid, study.respondents);
    if (!agg || !agg.options) return null;
    const all = agg.options.
    map((o) => ({ key: o.label, label: o.label, pct: o.pct })).
    sort((a, b) => b.pct - a.pct);
    const named = mentions(all, (o) => o.label);
    const rows = named.length > 0 && named.length < all.length ? named.slice(0, 12) : all.slice(0, 7);
    return { kind: "question", rows, n: agg.total, focused: named.length > 0 && named.length < all.length };
  }, [study, link, finding]);

  if (!viz || viz.rows.length === 0) return null;
  const tier = (s) => bench ? s >= bench.q75 ? "top" : s <= bench.q25 ? "low" : "mid" : "mid";
  const maxPct = Math.max(...viz.rows.map((r) => r.pct || 0), 1);

  // Sentiment findings render as product tiles (mirrors the Explore-the-data tile view).
  if (viz.kind === "sentiment") {
    return (
      <div className="gl-rf-viz">
        <div className="gl-rf-viz__head">
          <VizBadges parts={[
          { label: "Sentiment score", tone: "gray" },
          { label: link.cutLabel, tone: "accent" },
          ...(viz.focused ? [] : [{ label: "Top products", tone: "gray" }])]
          } />
          <span className="gl-rf-viz__n">n&nbsp;=&nbsp;{viz.n.toLocaleString()}</span>
        </div>
        <div className="gl-rf-tiles">
          {viz.rows.map((r) => {
            const img = window.PRODUCT_IMAGES && window.PRODUCT_IMAGES.url(r.id);
            const fam = window.productFamily ? window.productFamily(r.label) : null;
            return (
              <div className="gl-rf-tile" key={r.key} title={r.label + " · score " + r.score}>
                <div className="gl-rf-tile__card">
                  {img ?
                  <img src={img} alt={r.label} loading="lazy" /> :
                  <span className="gl-rf-tile__abbr" style={{ color: fam ? fam.fg : "var(--ms-fg-muted)" }}>{fam ? fam.abbrev : "?"}</span>}
                  <span className={"cs-tile__badge cs-tile__badge--" + tier(r.score)}>{r.score}</span>
                </div>
                <div className="gl-rf-tile__name">{r.label}</div>
              </div>);

          })}
        </div>
        {bench &&
        <div className="gl-rf-viz__foot">
            <span className="gl-rf-viz__legend"><i className="gl-rf-viz__dot gl-rf-viz__dot--top"></i>Top 25%</span>
            <span className="gl-rf-viz__legend"><i className="gl-rf-viz__dot gl-rf-viz__dot--mid"></i>Mid</span>
            <span className="gl-rf-viz__legend"><i className="gl-rf-viz__dot gl-rf-viz__dot--low"></i>Lower 25%</span>
            <span className="gl-rf-viz__bench">Benchmark avg {bench.mean}</span>
          </div>
        }
      </div>);

  }

  // Overall question findings render as a horizontal distribution bar list.
  return (
    <div className="gl-rf-viz">
      <div className="gl-rf-viz__head">
        <VizBadges parts={String(link.sourceLabel || "").split("·").map((s, i) => ({ label: s.trim(), tone: i === 0 ? "accent" : "gray" }))} />
        <span className="gl-rf-viz__n">n&nbsp;=&nbsp;{viz.n.toLocaleString()}</span>
      </div>
      <div className="gl-rf-viz__rows">
        {viz.rows.map((r, i) =>
        <div className="gl-rf-vizrow" key={r.key}>
            <span className="gl-rf-vizrow__label" title={r.label}>{r.label}</span>
            <span className="gl-rf-vizrow__track">
              <span
              className={"gl-rf-vizrow__fill gl-rf-vizrow__fill--" + (i === 0 ? "lead" : "rest")}
              style={{ width: r.pct / maxPct * 100 + "%" }}>
            </span>
            </span>
            <span className="gl-rf-vizrow__val">{r.pct}%</span>
          </div>
        )}
      </div>
    </div>);

}

// Inline hover chip — holds the bracketed data, shown only on hover/focus.
function DataHover({ data }) {
  return (
    <span className="gl-rf-datachip" tabIndex={0} role="button" aria-label={"Data: " + data}>
      <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round">
        <line x1="6" y1="20" x2="6" y2="13"></line>
        <line x1="12" y1="20" x2="12" y2="6"></line>
        <line x1="18" y1="20" x2="18" y2="10"></line>
      </svg>
      <span className="gl-rf-datatip">{data}</span>
    </span>);

}

// Render finding prose with every "(...)" pulled into a hover chip.
function ProseWithHovers({ text }) {
  const nodes = [];
  const re = /\s*\(([^)]*)\)/g;
  let last = 0,m,key = 0;
  while ((m = re.exec(text)) !== null) {
    if (m.index > last) nodes.push(text.slice(last, m.index));
    nodes.push(<DataHover key={key++} data={m[1]} />);
    last = m.index + m[0].length;
  }
  if (last < text.length) nodes.push(text.slice(last));
  return <React.Fragment>{nodes}</React.Fragment>;
}

function RealClaimCard({ c, objId, study, bench, showVerbatim }) {
  const sigMeta = GOLA.SIG_META[c.sig];
  const [open, setOpen] = React.useState(false);
  const link = findingDataLink(c);
  // Design-treatment findings carry a franchise verbatim synthesis block.
  const franchiseKey = c.lens === "design" ? String(c.id).split("::")[0].split("|")[1] : null;
  const fv = franchiseKey && window.VERBATIM ? window.VERBATIM.BY_FRANCHISE[franchiseKey] : null;
  const hasMetric = !/effect size/i.test(c.metricLabel || "");

  return (
    <article className="gl-ev gl-cc">
      <div className="gl-cc__top">
        <div className="gl-cc__statement">{c.statement}</div>
        <span
          className={"gl-sigflag gl-sigflag--" + c.sig}
          data-tip={sigMeta.short + " significance — " + sigMeta.tip}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"></path>
            <line x1="4" y1="22" x2="4" y2="15"></line>
          </svg>
        </span>
      </div>

      <button className={"gl-rf-detailbtn gl-rf-detailbtn--inline gl-cc__detailbtn" + (open ? " is-open" : "")} onClick={() => setOpen((o) => !o)}>
        Details
        <svg className="gl-rf-detailbtn__caret" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M6 9l6 6 6-6" /></svg>
      </button>
      {open &&
      <div className="gl-cc__details" style={{ margin: "0px 0px 16px" }}>
          <div className="gl-cc__prose"><ProseWithHovers text={c.prose} /></div>
        </div>
      }
      {hasMetric && <div className="gl-cc__metricrow"><FindingMetric c={c} /></div>}
      <div className="gl-cc__viz">
        <FindingDataViz link={link} study={study} bench={bench} finding={c} />
      </div>

      {fv && showVerbatim &&
      <div className="gl-rf-verbatim">
          <div className="gl-rf-verbatim__head">
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" /></svg>
            <span className="gl-rf-verbatim__label">Design feedback · open-text synthesis</span>
          </div>
          <div className="gl-rf-verbatim__headline">{fv.headline}</div>
          <div className="gl-rf-verbatim__prose"><ProseWithHovers text={fv.prose} /></div>
          {fv.quotes &&
        <div className="gl-rf-verbatim__quotes">
              {fv.quotes.map((q, i) => <span key={i} className="gl-rf-quote">“{q}”</span>)}
            </div>
        }
        </div>
      }

      <div className="gl-cc__foot">
        <TraceToData link={link} />
      </div>
    </article>);

}

function RealFindings({ showVerbatim, showCarousel }) {
  const RF = window.REAL_FINDINGS;
  const [objFilter, setObjFilter] = React.useState(() => {
    const RF0 = window.REAL_FINDINGS;
    if (!RF0 || !window.GOLA) return null;
    const note0 = RF0.EMPTY_OBJ_NOTE || {};
    const first = GOLA.OBJECTIVES.find((o) =>
    RF0.CLAIMS.some((c) => c.objs.includes(o.id)) || note0[o.id]);
    return first ? first.id : null;
  });
  const [study, setStudy] = React.useState(() => window.StudyData && window.StudyData.get());
  React.useEffect(() => {
    if (!study && window.StudyData) window.StudyData.load().then((d) => setStudy(d));
  }, [study]);

  // Benchmark thresholds (all respondents) — shared by every card's mini chart.
  const bench = React.useMemo(() => {
    if (!study || !window.csScore) return null;
    const all = StudyData.aggregateAllProducts(study.respondents).filter((p) => p.n > 0);
    const scores = all.map((p) => window.csScore(p.meanRating)).sort((a, b) => a - b);
    if (scores.length === 0) return null;
    const q = (p) => scores[Math.floor((scores.length - 1) * p)];
    const mean = Math.round(scores.reduce((s, v) => s + v, 0) / scores.length);
    return { mean, q25: q(0.25), q75: q(0.75) };
  }, [study]);

  if (!RF) return <div style={{ padding: 24, color: "var(--ms-fg-muted)" }}>Loading findings…</div>;

  // "Consumer behavior" — survey-distribution findings that render as bar charts
  // (brand consideration, channel preference, price behavior). Collected into
  // their own pill and removed from the objective groups so they don't double up.
  const CB = "consumer-behavior";
  const isCBFinding = (c) => {
    const l = findingDataLink(c);
    return !!(l && l.section === "question");
  };
  const cbCards = RF.CLAIMS.filter(isCBFinding).
  sort((a, b) => a.objs[0] - b.objs[0] || b.composite - a.composite);

  const note = RF.EMPTY_OBJ_NOTE || {};
  const objCounts = {};
  GOLA.OBJECTIVES.forEach((o) => {objCounts[o.id] = RF.CLAIMS.filter((c) => c.objs.includes(o.id) && !isCBFinding(c)).length;});
  // Objectives offered as pills / rendered: those with findings OR an explicit empty note.
  const pillObjs = GOLA.OBJECTIVES.filter((o) => objCounts[o.id] || note[o.id]);
  const onCB = objFilter === CB;
  const shownObjs = onCB ? [] :
  objFilter ?
  GOLA.OBJECTIVES.filter((o) => o.id === objFilter) :
  pillObjs;
  const activeFilter = objFilter || pillObjs[0] && pillObjs[0].id;

  return (
    <div className="gl gl-raw gl-rf-calm">
      <div className="gl-raw-main">
        <div className="gl-rf-pills">
          {cbCards.length > 0 &&
          <button
            className={"gl-rf-pill" + (onCB ? " is-on" : "")}
            onClick={() => setObjFilter(CB)}
            title="Consumer behavior · how the audience shops — brand consideration, channel, and price">
              Consumer behavior
            </button>
          }
          {pillObjs.map((o) =>
          <button
            key={o.id}
            className={"gl-rf-pill" + (activeFilter === o.id ? " is-on" : "")}
            onClick={() => setObjFilter(o.id)}
            title={"Objective " + o.id + " · " + o.text}>
              {o.short}
            </button>
          )}
        </div>
        {onCB &&
        <div className="gl-rf-objgroup">
            <div className="gl-fam gl-rf-objhead">
              <span className="gl-fam__glyph gl-rf-objglyph">CB</span>
              <span className="gl-fam__title">Consumer behavior</span>
              <span className="gl-fam__sub">· How the audience shops — brand consideration, channel preference, and price behavior</span>
              <span className="gl-fam__count">{cbCards.length} {cbCards.length === 1 ? "finding" : "findings"}</span>
            </div>
            <div className="gl-ev-grid">
              {cbCards.map((c) => <RealClaimCard key={"cb::" + c.id} c={c} objId={c.objs[0]} study={study} bench={bench} showVerbatim={showVerbatim} />)}
            </div>
          </div>
        }
        {shownObjs.map((o) => {
          const sigRank = { high: 2, mid: 1, low: 0 };
          const cards = RF.CLAIMS.
          filter((c) => c.objs.includes(o.id) && !isCBFinding(c)).
          sort((a, b) =>
          sigRank[b.sig] - sigRank[a.sig] || b.composite - a.composite
          );
          return (
            <div key={o.id} className="gl-rf-objgroup">
              <div className="gl-fam gl-rf-objhead">
                <span className="gl-fam__glyph gl-rf-objglyph">{o.id}</span>
                <span className="gl-fam__title">Objective {o.id} · {o.short}</span>
                <span className="gl-fam__sub">· {o.text}</span>
                <span className="gl-fam__count">{cards.length} {cards.length === 1 ? "finding" : "findings"}</span>
              </div>

              {o.id === 3 && showCarousel && <VerbatimCarousel study={study} />}

              {RF.OBJ_NOTE && RF.OBJ_NOTE[o.id] &&
              <div className="gl-rf-objnote">
                  <span className="gl-rf-objnote__badge">Pending · verbatims</span>
                  <div className="gl-rf-objnote__body">
                    <div className="gl-rf-objnote__title">{RF.OBJ_NOTE[o.id].title}</div>
                    <div className="gl-rf-objnote__text">{RF.OBJ_NOTE[o.id].text}</div>
                  </div>
                </div>
              }
              {cards.length > 0 ?
              <div className="gl-ev-grid">
                  {cards.map((c) => <RealClaimCard key={o.id + "::" + c.id} c={c} objId={o.id} study={study} bench={bench} showVerbatim={showVerbatim} />)}
                </div> :

              <div className="gl-empty" style={{ marginTop: 8 }}>
                  <div className="gl-empty__title">No findings authored for this objective</div>
                  <div className="gl-empty__sub">{note[o.id] || "The claim graph hasn't surfaced findings for Objective " + o.id + " at this version."}</div>
                </div>
              }
            </div>);

        })}
      </div>
    </div>);

}

// =========================================================
// Per-product verbatim synthesis — carousel + drill-in panel.
// Mirrors the Explore-the-data product carousel pattern, but the
// panel shows the distilled design read (stands out / would change)
// instead of raw verbatims.
// =========================================================
function leanMeta(lean) {
  if (lean === "strong") return { label: "Loved", cls: "strong" };
  if (lean === "weak") return { label: "Rejected", cls: "weak" };
  return { label: "Divides", cls: "mixed" };
}

function VerbatimThumb({ p, v, isSel, onClick }) {
  const fam = window.productFamily ? window.productFamily(p.title) : null;
  const img = window.PRODUCT_IMAGES && window.PRODUCT_IMAGES.url(p.id);
  const [ok, setOk] = React.useState(true);
  const lm = leanMeta(v && v.lean);
  return (
    <button className={"gl-vc-thumb" + (isSel ? " is-sel" : "")} onClick={onClick} title={p.title + (v ? " · " + v.t : "")}>
      <span className="gl-vc-thumb__card" style={{ background: fam ? fam.bg : "var(--ms-platinum)" }}>
        {img && ok ?
        <img src={img} alt={p.title} loading="lazy" onError={() => setOk(false)} /> :
        <span className="gl-vc-thumb__abbr" style={{ color: fam ? fam.fg : "var(--ms-fg-muted)" }}>{fam ? fam.abbrev : "?"}</span>}
        <span className={"gl-vc-thumb__dot gl-vc-thumb__dot--" + lm.cls}></span>
      </span>
      <span className="gl-vc-thumb__name">{p.title}</span>
      {v && <span className="gl-vc-thumb__tag">{v.t}</span>}
    </button>);

}

function VerbatimCarousel({ study }) {
  const VB = window.VERBATIM;
  const products = React.useMemo(() => {
    if (!study || !window.StudyData || !window.csScore) return [];
    return StudyData.aggregateAllProducts(study.respondents).filter((p) => p.n > 0).
    map((p) => ({ ...p, score: window.csScore(p.meanRating), short: p.id.slice(-4) })).
    sort((a, b) => b.score - a.score);
  }, [study]);
  const [selId, setSelId] = React.useState(null);
  if (!VB || products.length === 0) return null;
  const sel = products.find((p) => p.id === selId) || products[0];
  const v = VB.BY_PRODUCT[sel.short];
  const fam = window.productFamily ? window.productFamily(sel.title) : null;
  const img = window.PRODUCT_IMAGES && window.PRODUCT_IMAGES.url(sel.id);
  const lm = leanMeta(v && v.lean);

  return (
    <div className="gl-rf-objgroup gl-vc">
      <div className="gl-fam gl-rf-objhead">
        <span className="gl-fam__title">Design feedback by product · verbatim synthesis</span>
        <span className="gl-fam__sub">· distilled from “what stands out” / “what would you change”, per product</span>
        <span className="gl-fam__count">{products.length} products</span>
      </div>

      <div className="gl-vc-rail">
        {products.map((p) =>
        <VerbatimThumb key={p.id} p={p} v={VB.BY_PRODUCT[p.short]} isSel={p.id === sel.id} onClick={() => setSelId(p.id)} />
        )}
      </div>

      <article className="gl-vc-panel">
        <div className="gl-vc-panel__media" style={{ background: fam ? fam.bg : "var(--ms-platinum)" }}>
          {img ?
          <img src={img} alt={sel.title} /> :
          <span className="gl-vc-panel__abbr" style={{ color: fam ? fam.fg : "var(--ms-fg-muted)" }}>{fam ? fam.abbrev : "?"}</span>}
          <span className="gl-vc-panel__scorebadge">
            <span className="gl-vc-panel__scorebadge-val">{sel.score}</span>
            <span className="gl-vc-panel__scorebadge-n">n {sel.n.toLocaleString()}</span>
          </span>
        </div>
        <div className="gl-vc-panel__body">
          <div className="gl-vc-panel__head">
            <span className="gl-vc-panel__title">{sel.title}</span>
            {v && <span className="gl-vc-panel__tag">{v.t}</span>}
            <span className={"gl-vc-lean gl-vc-lean--" + lm.cls}>{lm.label}</span>
          </div>
          {v ?
          <div className="gl-vc-panel__cols">
              <div className="gl-vc-col">
                <div className="gl-vc-col__label gl-vc-col__label--pos">What stands out</div>
                <div className="gl-vc-col__text">{v.stands}</div>
              </div>
              <div className="gl-vc-col">
                <div className="gl-vc-col__label gl-vc-col__label--neg">What they’d change</div>
                <div className="gl-vc-col__text">{v.change}</div>
              </div>
            </div> :
          <div className="gl-vc-col__text" style={{ color: "var(--ms-fg-muted)" }}>No synthesis for this product yet.</div>}
          {v && v.quote && <div className="gl-vc-panel__quote">“{v.quote}”</div>}
        </div>
      </article>
    </div>);

}

// Shared study + benchmark loader — so other tabs (Insights) can render
// RealClaimCard with the same charts as the Findings tab.
function useFindingsStudyBench() {
  const [study, setStudy] = React.useState(() => window.StudyData && window.StudyData.get());
  React.useEffect(() => {
    if (!study && window.StudyData) window.StudyData.load().then((d) => setStudy(d));
  }, [study]);
  const bench = React.useMemo(() => {
    if (!study || !window.csScore) return null;
    const all = StudyData.aggregateAllProducts(study.respondents).filter((p) => p.n > 0);
    const scores = all.map((p) => window.csScore(p.meanRating)).sort((a, b) => a - b);
    if (scores.length === 0) return null;
    const q = (p) => scores[Math.floor((scores.length - 1) * p)];
    const mean = Math.round(scores.reduce((s, v) => s + v, 0) / scores.length);
    return { mean, q25: q(0.25), q75: q(0.75) };
  }, [study]);
  return { study, bench };
}

Object.assign(window, { RealFindings, VerbatimCarousel, RealClaimCard, useFindingsStudyBench });