/* global React, SparkTrj, StripTrj, Citation, Discussions, ChatPanel */
// pages.jsx — Homepage (search-first), StockDetail (PRODUCT.md order),
// RequestStock (uncovered ticker capture).
// Exposes window.Homepage, window.StockDetail, window.RequestStock.

const { useState, useEffect, useMemo, useRef } = React;

// Tiny markdown-bold renderer: splits on **…** and renders <strong>.
function renderBold(text) {
  if (!text) return null;
  const parts = String(text).split(/(\*\*[^*]+\*\*)/g);
  return parts.map((p, i) =>
    p.startsWith("**") && p.endsWith("**")
      ? <strong key={i}>{p.slice(2, -2)}</strong>
      : <React.Fragment key={i}>{p}</React.Fragment>
  );
}

// Inline "↗ Ask the agent" link — pre-fills + opens the floating chat panel.
// Bridges the durable brief to the conversational surface via a custom event.
function AskAgentLink({ prefill, children }) {
  function onClick(e) {
    e.preventDefault();
    window.dispatchEvent(new CustomEvent("cct:ask-agent", {
      detail: { prefill, autosend: true }
    }));
  }
  return (
    <button type="button" className="ask-agent-link" data-prefill={prefill} onClick={onClick}>
      <span className="arr">↗</span>
      <span>{children || "Ask the agent about this"}</span>
    </button>
  );
}

// Sources strip — one chip per quarter linking to the source PDF, plus an
// "All filings" fallback chip. Closes the trust loop the methodology page
// describes: any quote → original document in one click.
function SourcesStrip({ ticker, quarters }) {
  const perQ = (window.CCT_SOURCE_URLS || {})[ticker] || {};
  const fallback = (window.CCT_IR_FALLBACK || {})[ticker];
  const qList = (quarters && quarters.length ? quarters : Object.keys(perQ)).slice();
  // Don't render an empty strip — happens if both source map and fallback miss.
  if (qList.every(q => !perQ[q]) && !fallback) return null;
  return (
    <div className="sources-strip" aria-label="Source filings">
      <span className="sources-label mono">Sources</span>
      {qList.map(q => {
        const url = perQ[q];
        if (url) {
          return (
            <a key={q} className="src-chip" href={url} target="_blank" rel="noopener noreferrer">
              <span className="src-q mono">{q}</span>
              <span className="src-kind mono">PDF ↗</span>
            </a>
          );
        }
        return null;
      })}
      {fallback && (
        <a className="src-chip src-fallback" href={fallback} target="_blank" rel="noopener noreferrer">
          <span className="src-q mono">All filings</span>
          <span className="src-kind mono">IR site ↗</span>
        </a>
      )}
    </div>
  );
}

// "Flag this finding" — small link at the bottom of each finding card.
// Encodes {subject, url} as base64 JSON in the methodology hash so the form
// pre-fills. Stable contract: MethodologyPage decodes the same shape.
function FlagFindingLink({ ticker, kind, topic }) {
  function onClick(e) {
    e.preventDefault();
    const subject = `${ticker} · ${kind}: ${topic || "(unspecified)"}`.slice(0, 140);
    const url = location.origin + location.pathname + `#stock:${ticker}`;
    const payload = { subject, url, ticker, kind, topic };
    const flag = encodeURIComponent(btoa(JSON.stringify(payload)));
    location.hash = `methodology?flag=${flag}`;
    window.scrollTo({ top: 0, behavior: "instant" });
  }
  return (
    <button type="button" className="flag-link" onClick={onClick}>
      <span className="arr">⚑</span>
      <span>Flag this finding</span>
    </button>
  );
}

// ============================================================================
//  Search — covered tickers vs uncovered → request flow
// ============================================================================
const COVERED_INDEX = (() => {
  return (window.CCT_DATA?.stocks || []).map(s => ({
    ticker: s.ticker,
    company: s.company,
    sector: s.sector,
    drift: window.CCT_ONELINE?.[s.ticker] || s.drift_summary
  }));
})();

function searchCovered(q) {
  const t = q.trim().toLowerCase();
  if (!t) return [];
  return COVERED_INDEX.filter(s =>
    s.ticker.toLowerCase().includes(t) ||
    s.company.toLowerCase().includes(t)
  );
}

function SearchBar({ navigate, autoFocus }) {
  const [q, setQ] = useState("");
  const [active, setActive] = useState(0);
  const inputRef = useRef(null);
  const results = useMemo(() => searchCovered(q), [q]);

  useEffect(() => {
    if (autoFocus && inputRef.current) inputRef.current.focus();
  }, [autoFocus]);

  function submit(picked) {
    const choice = picked || results[active];
    if (choice) {
      navigate(`stock:${choice.ticker}`);
    } else if (q.trim()) {
      navigate(`request:${encodeURIComponent(q.trim())}`);
    }
  }

  function onKey(e) {
    if (e.key === "ArrowDown") { e.preventDefault(); setActive(a => Math.min(results.length - 1, a + 1)); }
    else if (e.key === "ArrowUp") { e.preventDefault(); setActive(a => Math.max(0, a - 1)); }
    else if (e.key === "Enter") { e.preventDefault(); submit(); }
    else if (e.key === "Escape") { setQ(""); }
  }

  return (
    <div className="search-wrap">
      <div className="search-shell">
        <span className="glyph">⌕</span>
        <input
          ref={inputRef}
          type="text"
          value={q}
          onChange={e => { setQ(e.target.value); setActive(0); }}
          onKeyDown={onKey}
          placeholder="Search a stock — NSE / BSE ticker or company name"
          spellCheck={false}
          autoComplete="off"
          aria-label="Search covered stocks"
        />
        <span className="hint mono">↵</span>
      </div>
      {q.trim() && (
        <div className="search-results" role="listbox">
          {results.length > 0 && results.map((r, i) => (
            <button
              key={r.ticker}
              role="option"
              aria-selected={i === active}
              className={"result " + (i === active ? "active" : "")}
              onMouseEnter={() => setActive(i)}
              onClick={() => submit(r)}
            >
              <span className="ticker mono">{r.ticker}</span>
              <span className="company">{r.company}</span>
              <span className="sector mono">{r.sector}</span>
              <span className="arr">→</span>
            </button>
          ))}
          <button
            className={"result request " + (results.length === 0 || active === results.length ? "active" : "")}
            onMouseEnter={() => setActive(results.length)}
            onClick={() => navigate(`request:${encodeURIComponent(q.trim())}`)}
          >
            <span className="ticker mono">REQ</span>
            <span className="company">
              {results.length === 0
                ? <>No coverage on <b>{q.trim()}</b> yet — <u>request this stock</u></>
                : <>Don't see it? <u>Request {q.trim()}</u></>}
            </span>
            <span className="arr">→</span>
          </button>
        </div>
      )}
      <div className="coverage-line mono">
        {COVERED_INDEX.length} stocks covered · request the {COVERED_INDEX.length + 1}th
      </div>
    </div>
  );
}

// ============================================================================
//  Homepage — search bar, cross-stock patterns, covered-companies list
// ============================================================================
function Homepage({ navigate }) {
  const data = window.CCT_DATA;
  const patterns = window.CCT_PATTERNS || [];

  return (
    <div className="page home">
      <div className="home-inner">
        <header className="home-hero">
          <div className="eyebrow">Throughline · Issue 01 · {data.latest_quarter || "Q3 FY26"}</div>
          <h1 className="home-title">
            What management is saying.<br />
            <span className="dim">And what they stopped saying.</span>
          </h1>
          <SearchBar navigate={navigate} autoFocus />
        </header>

        {/* Cross-stock patterns — three sentences */}
        <section className="cross-stock">
          <div className="eyebrow">Cross-stock — visible only when you read all seven</div>
          <ol className="patterns">
            {patterns.map((p, i) => (
              <li key={i}>
                <span className="num mono">0{i + 1}</span>
                <div>
                  <h3>{p.title}</h3>
                  <p className="dim">{p.body}</p>
                  <div className="tags">
                    {p.tags.map(t => (
                      <button key={t} className="chip" onClick={() => navigate(`stock:${t}`)}>
                        <span className="swatch" style={{ background: "var(--fg-faint)" }}></span>
                        {t}
                      </button>
                    ))}
                  </div>
                </div>
              </li>
            ))}
          </ol>
        </section>

        {/* Covered companies — one-line drift each */}
        <section className="covered">
          <div className="covered-head">
            <div className="eyebrow">Covered companies · {data.tickers_complete} of {data.tickers_total}</div>
            <span className="dim mono">latest · {data.latest_quarter || "Q3 FY26"}</span>
          </div>
          <ul className="covered-list">
            {data.stocks.map(s => (
              <li key={s.ticker}>
                <button onClick={() => navigate(`stock:${s.ticker}`)} className="covered-row">
                  <span className="ticker mono">{s.ticker}</span>
                  <span className="company">{s.company}</span>
                  <span className="drift">{window.CCT_ONELINE?.[s.ticker] || s.drift_summary}</span>
                  <span className="arr">→</span>
                </button>
              </li>
            ))}
          </ul>
          <div className="deferred">
            <span className="eyebrow">Pipeline</span>
            <span className="dim mono">Next batch · {(data.deferred || []).join(" · ")}</span>
          </div>
        </section>
      </div>
    </div>
  );
}

// ============================================================================
//  Request stock — uncovered ticker capture
// ============================================================================
function RequestStock({ query, navigate }) {
  const decoded = decodeURIComponent(query || "");
  const [email, setEmail] = useState("");
  const [submitted, setSubmitted] = useState(false);

  const [error, setError] = useState(null);

  async function submit(e) {
    e.preventDefault();
    setError(null);
    if (window.CCT_USE_REAL_API) {
      try {
        const base = window.CCT_API_BASE || "";
        const res = await fetch(`${base}/api/requests`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          credentials: "include",
          body: JSON.stringify({ query: decoded, email })
        });
        if (!res.ok) throw new Error(`request ${res.status}`);
        setSubmitted(true);
        return;
      } catch (err) {
        // Fall through to local persistence so the user's signal is never lost.
        setError("Couldn't reach the server — saved your request locally; we'll pick it up next sync.");
      }
    }
    try {
      const k = "cct.requests.v1";
      const all = JSON.parse(localStorage.getItem(k) || "[]");
      all.push({ query: decoded, email, ts: new Date().toISOString() });
      localStorage.setItem(k, JSON.stringify(all));
    } catch {}
    setSubmitted(true);
  }

  return (
    <div className="page">
      <div className="request-inner">
        <div className="crumbs mono">
          <button onClick={() => navigate("home")}>← Home</button>
          <span className="sep">/</span>
          <span>Request</span>
        </div>

        <div className="eyebrow">Not yet covered</div>
        <h1 className="h-display" style={{ marginTop: 12 }}>
          We don't cover <span className="mono ticker-call">{decoded}</span> yet.
        </h1>

        <p className="body-prose dim" style={{ marginTop: 24, fontSize: "var(--fs-md)", maxWidth: 60 + "ch" }}>
          Throughline covers {COVERED_INDEX.length} Indian midcaps today, growing to 25-50.
          Coverage expands based on real demand — your request goes into a signal queue we read every week.
        </p>

        {submitted ? (
          <div className="request-done">
            <div className="eyebrow" style={{ color: "var(--signal-emerged)" }}>✓ Logged</div>
            <p className="body-prose" style={{ marginTop: 8 }}>
              We'll email <b>{email}</b> when <span className="mono">{decoded}</span> goes live.
              <br />
              <span className="dim">Stored locally for now — wired to <span className="mono">POST /api/requests</span> when the backend lands.</span>
            </p>
            <div style={{ marginTop: 24, display: "flex", gap: 12, flexWrap: "wrap" }}>
              <button className="btn primary" onClick={() => navigate("home")}>← Back to home</button>
              <button className="btn ghost" onClick={() => { setSubmitted(false); setEmail(""); }}>Request another</button>
            </div>
          </div>
        ) : (
          <form className="request-form" onSubmit={submit}>
            <label>
              <span className="eyebrow">Email</span>
              <input
                type="email"
                required
                placeholder="you@firm.com"
                value={email}
                onChange={e => setEmail(e.target.value)}
              />
            </label>
            <button type="submit" className="btn primary">Notify me when it's live →</button>
            <div className="dim mono" style={{ fontSize: "var(--fs-mono-xs)", marginTop: 6 }}>
              No marketing. One email when {decoded} ships.
            </div>
            {error && (
              <div className="dim" style={{ fontSize: "var(--fs-sm)", marginTop: 8, color: "var(--signal-disappeared)" }}>
                {error}
              </div>
            )}
          </form>
        )}

        <hr className="hr" style={{ margin: "48px 0 32px" }} />

        <div className="eyebrow">Already covered</div>
        <ul className="covered-list compact" style={{ marginTop: 12 }}>
          {COVERED_INDEX.slice(0, 7).map(s => (
            <li key={s.ticker}>
              <button onClick={() => navigate(`stock:${s.ticker}`)} className="covered-row">
                <span className="ticker mono">{s.ticker}</span>
                <span className="company">{s.company}</span>
                <span className="drift">{s.drift}</span>
                <span className="arr">→</span>
              </button>
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
}

// ============================================================================
//  Stock page — PRODUCT.md section order
//  Header → Drift → What's new → Walked back → People & gov → Dodged →
//  Analyst coverage → Chat (right rail) → Discussions (bottom)
// ============================================================================

// Light internal helpers
function SignalChip({ kind, label }) {
  return (
    <span className={`chip signal-${kind}`}>
      <span className="swatch"></span>
      {label}
    </span>
  );
}

function SeverityTag({ level }) {
  if (!level) return null;
  return (
    <span
      className={`sev sev-${level.toLowerCase()}`}
      title={
        level === "MATERIAL" ? "Material — changes the thesis shape"
        : level === "NOTABLE" ? "Notable — worth tracking"
        : "Context — useful background"
      }
    >{level}</span>
  );
}

function NewItem({ n, kind, fullQ, ticker }) {
  if (!n || !n.topic) return null;
  const ck = kind === "emerged" && n.topic.startsWith("AssistX")
    ? "PERSISTENT_Q3FY26_or_assistx"
    : kind === "disappeared" && n.topic.startsWith("Macro")
    ? "PERSISTENT_Q2FY26_qa_macro"
    : null;
  const askPrefill = kind === "emerged" && n.topic.startsWith("AssistX")
    ? "Walk me through the AssistX Customer Zero pivot"
    : null;
  return (
    <article className="new-item">
      <div className="left">
        <div className="chips-row">
          <SignalChip kind={kind} label={kind === "emerged" ? "EMERGED" : "FADED"} />
          <SeverityTag level={n.severity} />
        </div>
        <h3 className="topic">{n.topic}</h3>
        <StripTrj trj={n.trj} kind={kind} quarters={fullQ} />
      </div>
      <div className="right">
        <blockquote className={`quote ${kind === "emerged" ? "peak" : "disap"}`}>
          "{n.quote || n.peak_quote}"
        </blockquote>
        <div className="significance">{n.significance}</div>
        <div className="actions">
          {ck && (
            <Citation chunk={n.peak_q || n.peak_quote_quarter} label={(n.section || n.peak_quote_section) === "qa_pairs" ? "Q&A" : "opening remarks"} ck={ck} />
          )}
          {askPrefill && <AskAgentLink prefill={askPrefill}>Ask the agent about this</AskAgentLink>}
          <FlagFindingLink ticker={ticker} kind={kind === "emerged" ? "Emerged topic" : "Faded topic"} topic={n.topic} />
        </div>
      </div>
    </article>
  );
}

function WalkedBackItem({ g, ticker }) {
  const featured = g.severity === "MATERIAL";
  const askPrefill = featured && /ebit|margin/i.test(g.metric || "")
    ? "Walk me through the EBIT margin walk-back"
    : null;
  return (
    <article className={`walkback${featured ? " featured" : ""}`}>
      <div className="row top">
        <div className="chips-row">
          <SignalChip kind="walked" label={(g.shape || g.direction).toUpperCase()} />
          <SeverityTag level={g.severity} />
        </div>
        <h3 className="metric">{g.metric}</h3>
        <span className="window mono">{g.from_q} → {g.to_q}</span>
      </div>
      <div className="row from-to">
        <div className="cell from">
          <div className="eyebrow">Was · {g.from_q}</div>
          <div className="val mono">{g.from}</div>
        </div>
        <div className="arrow mono">→</div>
        <div className="cell to">
          <div className="eyebrow">Now · {g.to_q}</div>
          <div className="val mono">{g.to}</div>
        </div>
      </div>
      {g.note && (
        <p className="walkback-note">{g.note}</p>
      )}
      {g.quote && (
        <blockquote className={`quote walked${featured ? " featured-quote" : ""}`}>"{g.quote}"</blockquote>
      )}
      <div className="actions">
        {askPrefill && <AskAgentLink prefill={askPrefill}>Ask the agent about this</AskAgentLink>}
        <FlagFindingLink ticker={ticker} kind="Walk-back" topic={g.metric} />
      </div>
    </article>
  );
}

function GovernanceItem({ g, ticker }) {
  return (
    <article className="gov-item">
      <div className="left">
        <div className="eyebrow">{g.kind}</div>
        <div className="who">{g.who}</div>
        <div className="quarter mono">{g.quarter}</div>
      </div>
      <div className="right">
        <div className="significance">{g.detail}</div>
        {g.quote && <blockquote className="quote">"{g.quote}"</blockquote>}
        <div className="actions">
          <FlagFindingLink ticker={ticker} kind={`Governance · ${g.kind || "change"}`} topic={g.who} />
        </div>
      </div>
    </article>
  );
}

function DodgedItem({ d, ticker }) {
  const ck = d.quarter === "Q3FY26" && /margin/i.test(d.question)
    ? "PERSISTENT_Q3FY26_qa_margin" : null;
  return (
    <article className="dodged-item">
      <div className="left">
        <div className="chips-row">
          <SignalChip kind="dodged" label="DODGED" />
          <SeverityTag level={d.severity} />
        </div>
        <div className="meta mono">{d.quarter} · {d.analyst}</div>
        <h3 className="q">"{d.question}"</h3>
      </div>
      <div className="right">
        <div className="eyebrow">Answer (excerpt)</div>
        <blockquote className="quote dodged">"{d.answer}"</blockquote>
        <div className="eyebrow">Why it's a dodge</div>
        <div className="significance">{d.reason}</div>
        <div className="eyebrow" style={{ marginTop: 12 }}>Why it matters</div>
        <div className="significance">{renderBold(d.why_it_matters)}</div>
        <div className="actions">
          {ck && <Citation chunk={d.quarter} label="Q&A" ck={ck} />}
          <FlagFindingLink ticker={ticker} kind="Dodged question" topic={(d.question || "").slice(0, 80)} />
        </div>
      </div>
    </article>
  );
}

function AnalystCoverageBlock({ analysts, latest }) {
  const list = analysts[latest] || [];
  const newOnes = analysts.new || [];
  const dropped = analysts.dropped || [];
  return (
    <div className="analyst-coverage">
      <div className="all">
        <div className="eyebrow">{latest} coverage · {list.length} analysts</div>
        <div className="grid">
          {list.map(a => {
            const isNew = newOnes.includes(a);
            return (
              <div key={a} className={"analyst " + (isNew ? "new" : "")}>
                <span className="mono">{a}</span>
                {isNew && <span className="tag mono">+ new</span>}
              </div>
            );
          })}
        </div>
      </div>
      <div className="changes">
        <div className="col">
          <div className="eyebrow" style={{ color: "var(--signal-emerged)" }}>+ Joined</div>
          <div className="vals mono">{newOnes.length ? newOnes.join(", ") : "—"}</div>
        </div>
        <div className="col">
          <div className="eyebrow" style={{ color: "var(--signal-disappeared)" }}>− Went silent</div>
          <div className="vals mono">{dropped.length ? dropped.join(", ") : "—"}</div>
        </div>
      </div>
    </div>
  );
}

// Main stock-page component
function StockDetail({ ticker, navigate }) {
  // PERSISTENT has the full hi-fi block; others use CCT_STOCK_DETAIL scaffold.
  const isPersistent = ticker === "PERSISTENT";
  const D = isPersistent ? window.CCT_PERSISTENT : null;
  const S = !isPersistent ? window.CCT_STOCK_DETAIL?.[ticker] : null;
  const stub = COVERED_INDEX.find(s => s.ticker === ticker);

  if (!D && !S && !stub) {
    // Treat as request flow
    return <RequestStock query={ticker} navigate={navigate} />;
  }

  const company = D ? D.company : (S?.company || stub?.company);
  const sector = D ? D.sector : (S?.sector || stub?.sector);
  const latest = D ? D.latest_quarter : (S?.latest_quarter || "Q3FY26");
  const fullQ = D ? D.comparison_quarters : ["Q4FY25","Q1FY26","Q2FY26","Q3FY26"];
  const headline = D ? D.headline : (S?.headline || stub?.drift);

  const whatsNew = D
    ? [...(D.emerged || []).map(e => ({ ...e, _kind: "emerged" })), ...(D.disappeared || []).map(e => ({ ...e, _kind: "disappeared" }))]
    : [
        ...((S?.emerged || S?.whats_new || []).map(e => ({ ...e, _kind: "emerged" }))),
        ...((S?.disappeared || []).map(e => ({ ...e, _kind: "disappeared" }))),
      ];

  const walkedBack = D
    ? (D.guidance_changes || [])
    : (S?.guidance_changes || S?.walked_back || []);

  const governance = D
    ? (window.CCT_GOVERNANCE?.[ticker] || [])
    : (S?.governance || window.CCT_GOVERNANCE?.[ticker] || []);

  const dodged = D ? (D.dodged || []) : (S?.dodged || []);
  const analysts = D ? D.analysts : (S?.analysts || { [latest]: [], new: [], dropped: [] });

  return (
    <div className="page stock">
      <div className="stock-grid">
        {/* Left column — the brief */}
        <main className="stock-main">
          {/* §1 Header */}
          <header className="stock-hd">
            <div className="crumbs mono">
              <button onClick={() => navigate("home")}>← All stocks</button>
              <span className="sep">/</span>
              <span>{ticker}</span>
            </div>
            <div className="ticker-row">
              <span className="ticker mono">{ticker}</span>
              <span className="company">{company}</span>
              <span className="sector mono">{sector}</span>
            </div>
            <div className="qline mono dim">Latest quarter analyzed · {latest}</div>
            <SourcesStrip ticker={ticker} quarters={fullQ} />
          </header>

          {/* §2 Drift summary — display serif, prominent (coral bar marks pull-quote) */}
          <section className="drift-summary">
            <div className="eyebrow">Drift summary · {latest}</div>
            <p className="drift-line">{headline}</p>
          </section>

          {/* §2b What this implies — renders for any stock with implications. */}
          {(() => {
            const src = D ?? S;
            if (!src?.implications || src.implications.length === 0) return null;
            return (
              <section className="implications">
                <div className="eyebrow">What this implies for the thesis</div>
                {src.implications_audience && (
                  <p className="implications-audience">{src.implications_audience}</p>
                )}
                <ul>
                  {src.implications.map((line, i) => (
                    <li key={i}>{line}</li>
                  ))}
                </ul>
              </section>
            );
          })()}

          {/* §3 What's new this quarter */}
          <section className="block whats-new">
            <header className="block-head">
              <div className="num mono">§ 01</div>
              <div>
                <div className="eyebrow">What's new this quarter</div>
                <h2 className="h-1">Topics they started — and stopped — talking about.</h2>
              </div>
            </header>
            {whatsNew.length === 0 ? (
              <div className="empty"><div className="glyph">[ — ]</div><div>No emergent narratives this quarter.</div></div>
            ) : whatsNew.map((n, i) => <NewItem key={i} n={n} kind={n._kind} fullQ={fullQ} ticker={ticker} />)}
          </section>

          {/* §4 What management walked back — visually distinct */}
          <section className="block walked-back">
            <header className="block-head walked">
              <div className="num mono">§ 02</div>
              <div>
                <div className="eyebrow walked-eyebrow">What management walked back</div>
                <h2 className="h-1">Goalposts that moved — quietly.</h2>
                <p className="dim" style={{ marginTop: 6 }}>Specific commitments management made, then retreated from. From-value, to-value, the verbatim quote, the quarter where it shifted.</p>
              </div>
            </header>
            {walkedBack.length === 0 ? (
              <div className="empty"><div className="glyph">[ — ]</div><div>No guidance walk-backs this quarter.</div></div>
            ) : walkedBack.map((g, i) => <WalkedBackItem key={i} g={g} ticker={ticker} />)}
          </section>

          {/* §5 People & governance — only renders when non-empty */}
          {governance.length > 0 && (
            <section className="block governance">
              <header className="block-head">
                <div className="num mono">§ 03</div>
                <div>
                  <div className="eyebrow">People & governance</div>
                  <h2 className="h-1">Leadership moves that matter.</h2>
                </div>
              </header>
              {governance.map((g, i) => <GovernanceItem key={i} g={g} ticker={ticker} />)}
            </section>
          )}

          {/* §6 What got dodged */}
          <section className="block dodged">
            <header className="block-head">
              <div className="num mono">§ {governance.length > 0 ? "04" : "03"}</div>
              <div>
                <div className="eyebrow">What got dodged</div>
                <h2 className="h-1">Questions where management gave non-answers.</h2>
              </div>
            </header>
            {dodged.length === 0 ? (
              <div className="empty"><div className="glyph">[ — ]</div><div>No flagged dodges this quarter.</div></div>
            ) : dodged.map((d, i) => <DodgedItem key={i} d={d} ticker={ticker} />)}
          </section>

          {/* §7 Analyst coverage */}
          <section className="block analysts">
            <header className="block-head">
              <div className="num mono">§ {governance.length > 0 ? "05" : "04"}</div>
              <div>
                <div className="eyebrow">Analyst coverage</div>
                <h2 className="h-1">Who's showing up to ask.</h2>
              </div>
            </header>
            <AnalystCoverageBlock analysts={analysts} latest={latest} />
          </section>

          {/* §9 Discussions — bottom of page */}
          <section className="block discussions-block">
            <header className="block-head">
              <div className="num mono">§ {governance.length > 0 ? "06" : "05"}</div>
              <div>
                <div className="eyebrow">Discussions</div>
                <h2 className="h-1">Other investors on this stock.</h2>
              </div>
            </header>
            <Discussions ticker={ticker} quarter={latest} />
          </section>
        </main>
      </div>

      {/* Floating chat — collapsed pill bottom-right; expands into a panel.
          Lives outside .stock-grid so it stays anchored to the viewport, not
          the brief column. */}
      <FloatingChat ticker={ticker} latest={latest} navigate={navigate} />
    </div>
  );
}

Object.assign(window, { Homepage, StockDetail, RequestStock, SearchBar });
