/* /broker — PRIVATE broker-portal demonstration (WO-2026-08-25-broker-portal).
 *
 * UNLISTED BY DESIGN: reachable only by deep link (…/#/broker?k=<access-key>).
 * Never referenced from nav, footer, homepage or sitemap. The access key rides
 * the hash query and is enforced SERVER-SIDE by /api/demo-quote (same gate as
 * the quoteflow demo); this page only decides which empty-state to show.
 *
 * DEMONSTRATION POSTURE (CCO Phase 1, 2026-08-25): every firm, person,
 * address and figure on this surface is fictional; book premiums are
 * fabricated round numbers labelled illustrative; the only live computation
 * is the New-quote pane, which prices through the same /api/demo-quote bridge
 * — and posture — as the cleared quoteflow demonstration. No live CTAs: the
 * client-view confirm control is a disabled specimen.
 *
 * Register: the professional register of the one Solas system (broker.css).
 * A broker works a book, not a journey — the workbench is tables, statuses,
 * referrals and documents; the guided flow survives only inside New quote and
 * the client view. Copy lives in content.js (window.solasContent.brokerPortal).
 */

const CB = window.solasContent.brokerPortal;

const bpReadKey = () => {
  const hash = window.location.hash || "";
  const qIdx = hash.indexOf("?");
  if (qIdx === -1) return "";
  const params = new URLSearchParams(hash.slice(qIdx + 1));
  return (params.get("k") || "").trim();
};

const bpGbp = (v) => {
  const n = Number(v);
  if (!Number.isFinite(n)) return "£—";
  return n.toLocaleString("en-GB", { style: "currency", currency: "GBP", maximumFractionDigits: 0 });
};

/* The Status Spine — the closed set of book states. Every record shows
   exactly one. Order here is display order for the filter row. */
const BP_STATUSES = [
  "Draft", "Quoted", "Referred", "MTA pending", "Renewal due", "Bound", "Declined",
];
const BP_ATTENTION = new Set(["Referred", "MTA pending", "Renewal due"]);

/* Synthetic book — FICTIONAL people, firms, properties and figures throughout
   (see CB.demoLine). Premiums are fabricated round numbers, labelled. */
const BP_BOOK = [
  {
    id: "FT-2101", client: "Halloran", property: "Detached · Georgian · Guildford",
    status: "Renewal due", premium: 2400, updated: "22 Aug 2026", handledBy: "E. Whitcombe",
    prov: {
      received: [["EPC band", "D"], ["Flood zone", "Zone 1 — low"], ["Elevation", "38m"]],
      derived: [["Rebuild estimate", "£720,000 · index basis"]],
      missing: [["Claims history", "broker-declared"]],
    },
  },
  {
    id: "FT-2098", client: "Osei-Bennett", property: "Semi-detached · Victorian · Harrogate",
    status: "Referred", premium: null, updated: "22 Aug 2026", handledBy: "J. Patel",
    referral: {
      underwriter: "R. Adeyemi · Property underwriting",
      due: "Tomorrow, 12:00",
      reasons: [
        "Flood history declared — two events within ten years",
        "Rebuild estimate diverges from declared value by more than the tolerance band",
      ],
      thread: [
        { who: "J. Patel", when: "22 Aug, 09:41", note: "Client has installed flood barriers since the 2019 event — survey attached as evidence." },
        { who: "R. Adeyemi", when: "22 Aug, 11:05", note: "Reviewing the survey against the enriched flood record. Response before the commitment above." },
      ],
    },
    prov: {
      received: [["EPC band", "E"], ["Flood zone", "Zone 3a — high"], ["Ground stability", "Moderate"]],
      derived: [["Rebuild estimate", "£540,000 · index basis"]],
      missing: [["Flood mitigation evidence", "under review — supplied by broker"]],
    },
  },
  {
    id: "FT-2095", client: "Marchetti", property: "Terraced · Edwardian · Richmond",
    status: "MTA pending", premium: 1840, updated: "21 Aug 2026", handledBy: "E. Whitcombe",
    mta: {
      note: "Contents sum insured increased following a valuation.",
      rows: [
        { field: "Contents sum insured", before: "£60,000", after: "£85,000", changed: true },
        { field: "Buildings sum insured", before: "£640,000", after: "£640,000", changed: false },
        { field: "Accidental damage", before: "Included", after: "Included", changed: false },
        { field: "Annual premium (illustrative)", before: "£1,840", after: "£1,975", changed: true },
      ],
    },
    prov: {
      received: [["EPC band", "C"], ["Flood zone", "Zone 2 — moderate"], ["Local crime index", "Below average"]],
      derived: [["Rebuild estimate", "£610,000 · index basis"]],
      missing: [],
    },
  },
  {
    id: "FT-2093", client: "Adeboyo", property: "Detached · 1930s · Tunbridge Wells",
    status: "Quoted", premium: 1650, updated: "20 Aug 2026", handledBy: "J. Patel",
    prov: {
      received: [["EPC band", "C"], ["Flood zone", "Zone 1 — low"], ["Elevation", "72m"]],
      derived: [["Rebuild estimate", "£580,000 · index basis"]],
      missing: [["Contents schedule", "broker-declared"]],
    },
  },
  {
    id: "FT-2090", client: "Whitlock", property: "Bungalow · 1960s · Chichester",
    status: "Quoted", premium: 980, updated: "19 Aug 2026", handledBy: "E. Whitcombe",
    prov: {
      received: [["EPC band", "D"], ["Flood zone", "Zone 1 — low"], ["Ground stability", "Low"]],
      derived: [["Rebuild estimate", "£410,000 · index basis"]],
      missing: [],
    },
  },
  {
    id: "FT-2086", client: "Fenwick-Hale", property: "Detached · Arts and Crafts · Winchester",
    status: "Bound", premium: 2950, updated: "15 Aug 2026", handledBy: "E. Whitcombe",
    prov: {
      received: [["EPC band", "D"], ["Flood zone", "Zone 1 — low"], ["Elevation", "54m"]],
      derived: [["Rebuild estimate", "£890,000 · index basis"]],
      missing: [],
    },
  },
  {
    id: "FT-2081", client: "Nakamura", property: "Flat · Mansion block · Bath",
    status: "Bound", premium: 760, updated: "11 Aug 2026", handledBy: "J. Patel",
    prov: {
      received: [["EPC band", "C"], ["Flood zone", "Zone 2 — moderate"], ["Local crime index", "Around average"]],
      derived: [["Rebuild estimate", "share of block · index basis"]],
      missing: [],
    },
  },
  {
    id: "FT-2104", client: "Broadhurst", property: "Semi-detached · 1980s · Sevenoaks",
    status: "Draft", premium: null, updated: "23 Aug 2026", handledBy: "J. Patel",
    prov: {
      received: [["EPC band", "B"], ["Flood zone", "Zone 1 — low"]],
      derived: [],
      missing: [["Sums insured", "not yet entered"], ["Claims history", "not yet entered"]],
    },
  },
  {
    id: "FT-2072", client: "Considine", property: "Detached · Thatched · Dorset",
    status: "Declined", premium: null, updated: "4 Aug 2026", handledBy: "E. Whitcombe",
    declineNote: "Outside appetite at launch: thatched roof construction. Banded reason supplied; revisit as appetite widens.",
    prov: {
      received: [["EPC band", "F"], ["Flood zone", "Zone 1 — low"]],
      derived: [["Rebuild estimate", "£970,000 · heritage basis"]],
      missing: [],
    },
  },
];

const BP_SIGNAL_LABELS = {
  flood_risk_zone: "Flood zone",
  lidar_elevation_m: "Elevation (LiDAR)",
  soil_shrink_swell: "Ground stability",
  crime_score: "Local crime index",
  epc_rating: "Energy performance (EPC)",
};
const BP_SIGNAL_VALUES = {
  zone_1: "Zone 1 — low risk", zone_2: "Zone 2 — moderate", zone_3a: "Zone 3a — high", zone_3b: "Zone 3b — highest",
  under_5m: "Under 5m above sea level", "5_15m": "5–15m above sea level", "15_50m": "15–50m above sea level", over_50m: "Over 50m above sea level",
  low: "Below average", medium: "Around average", high: "Above average", moderate: "Moderate", unknown: "Not available",
  a: "Band A", b: "Band B", c: "Band C", d: "Band D", e: "Band E", f: "Band F", g: "Band G",
};
const BP_PERIL_LABELS = {
  fire: "Fire", flood: "Flood", escape_of_water: "Escape of water",
  subsidence: "Subsidence", theft: "Theft", property_owners_liability: "Property owners' liability",
};

const BpChip = ({ status }) => (
  <span className={"bp-chip" + (BP_ATTENTION.has(status) ? " bp-chip--attention" : "")}>{status}</span>
);

const BpProvenance = ({ prov }) => (
  <div className="bp-panel bp-panel--well">
    <p className="bp-panel__eyebrow">{CB.provenanceTitle}</p>
    <ul className="bp-prov">
      {prov.received.map(([k, v]) => (
        <li key={"r" + k}><span>{k} · <strong>{v}</strong></span><span className="bp-prov__src">{CB.provReceived}</span></li>
      ))}
      {prov.derived.map(([k, v]) => (
        <li key={"d" + k}><span>{k} · <strong>{v}</strong></span><span className="bp-prov__src">{CB.provDerived}</span></li>
      ))}
      {prov.missing.map(([k, v]) => (
        <li key={"m" + k}><span>{k} · {v}</span><span className="bp-prov__src">{CB.provMissing}</span></li>
      ))}
    </ul>
    <p className="bp-note" style={{ marginTop: 12, marginBottom: 0 }}>{CB.provenanceNote}</p>
  </div>
);

/* ── Record detail (inside The Book) ───────────────────────────────────── */

const BpRecordDetail = ({ rec, onBack }) => (
  <React.Fragment>
    <button type="button" className="bp-backlink" onClick={onBack}>{CB.backToBook}</button>
    <div className="bp-cols" style={{ marginTop: 16 }}>
      <div>
        <div className="bp-panel">
          <p className="bp-panel__eyebrow">{rec.id} · <BpChip status={rec.status} /></p>
          <h3>{rec.client} — {rec.property}</h3>
          <dl className="bp-kv">
            <div><dt>{CB.thHandledBy}</dt><dd>{rec.handledBy}</dd></div>
            <div><dt>{CB.thUpdated}</dt><dd>{rec.updated}</dd></div>
            {rec.premium != null && (
              <div><dt>{CB.thPremium} ({CB.premiumIllustrative})</dt><dd className="bp-num">{bpGbp(rec.premium)}</dd></div>
            )}
          </dl>
          {rec.declineNote && <p className="bp-note" style={{ marginTop: 12, marginBottom: 0 }}>{rec.declineNote}</p>}
        </div>

        {rec.referral && (
          <div className="bp-panel bp-section">
            <p className="bp-panel__eyebrow">{CB.tabs.referrals}</p>
            <dl className="bp-kv">
              <div><dt>{CB.referralUnderwriter}</dt><dd>{rec.referral.underwriter}</dd></div>
              <div><dt>{CB.referralSla}</dt><dd>{rec.referral.due}</dd></div>
            </dl>
            <h3 style={{ marginTop: 16 }}>{CB.referralReasons}</h3>
            <ul className="bp-prov">
              {rec.referral.reasons.map((r) => <li key={r}><span>{r}</span></li>)}
            </ul>
            <ul className="bp-thread" style={{ marginTop: 8 }}>
              {rec.referral.thread.map((t, i) => (
                <li key={i}>
                  <span className="bp-thread__who">{t.who}</span>{" "}
                  <span className="bp-thread__when">· {t.when}</span>
                  <div>{t.note}</div>
                </li>
              ))}
            </ul>
          </div>
        )}

        {rec.mta && (
          <div className="bp-panel bp-section">
            <p className="bp-panel__eyebrow">{CB.mtaTitle}</p>
            <p className="bp-note">{rec.mta.note}</p>
            <div className="bp-tablewrap">
              <table className="bp-delta">
                <thead>
                  <tr><th>{CB.mtaField}</th><th>{CB.mtaBefore}</th><th>{CB.mtaAfter}</th></tr>
                </thead>
                <tbody>
                  {rec.mta.rows.map((r) => (
                    <tr key={r.field}>
                      <td>{r.field}</td>
                      <td>{r.before}</td>
                      <td className={r.changed ? "bp-delta__changed" : undefined}>{r.after}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
            <p className="bp-note" style={{ marginTop: 12, marginBottom: 0 }}>{CB.mtaNote}</p>
          </div>
        )}
      </div>
      <BpProvenance prov={rec.prov} />
    </div>
  </React.Fragment>
);

/* ── The Book ──────────────────────────────────────────────────────────── */

const BpBook = ({ selected, onSelect }) => {
  const [filter, setFilter] = React.useState("All");
  if (selected) return <BpRecordDetail rec={selected} onBack={() => onSelect(null)} />;
  const rows = BP_BOOK.filter((r) => filter === "All" || r.status === filter);
  return (
    <React.Fragment>
      <p className="bp-note" style={{ marginBottom: 20 }}>{CB.bookIntro}</p>
      <div className="bp-toolbar" role="group" aria-label={CB.thStatus}>
        {["All", ...BP_STATUSES].map((s) => (
          <button key={s} type="button" className="bp-filter" aria-pressed={filter === s} onClick={() => setFilter(s)}>
            {s === "All" ? CB.filterAll : s}
          </button>
        ))}
        <span className="bp-toolbar__count bp-num">{rows.length} {CB.bookCountSuffix}</span>
      </div>
      <div className="bp-tablewrap">
        <table className="bp-table">
          <thead>
            <tr>
              <th>{CB.thClient}</th><th>{CB.thProperty}</th><th>{CB.thStatus}</th>
              <th>{CB.thPremium}</th><th>{CB.thUpdated}</th><th>{CB.thHandledBy}</th>
            </tr>
          </thead>
          <tbody>
            {rows.map((r) => (
              <tr
                key={r.id} className="bp-row" tabIndex={0} role="button"
                aria-label={`${r.client} — ${r.status}`}
                onClick={() => onSelect(r)}
                onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onSelect(r); } }}
              >
                <td><strong>{r.client}</strong> <span style={{ color: "var(--fg-muted)" }}>· {r.id}</span></td>
                <td className="bp-td--wrap">{r.property}</td>
                <td><BpChip status={r.status} /></td>
                <td className="bp-num">{r.premium != null ? `${bpGbp(r.premium)} · ${CB.premiumIllustrative}` : "—"}</td>
                <td>{r.updated}</td>
                <td>{r.handledBy}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </React.Fragment>
  );
};

/* ── Referrals ─────────────────────────────────────────────────────────── */

const BpReferrals = ({ onSelect }) => {
  const referred = BP_BOOK.filter((r) => r.status === "Referred");
  return (
    <React.Fragment>
      <p className="bp-note" style={{ marginBottom: 20 }}>{CB.referralIntro}</p>
      {referred.map((rec) => <BpRecordDetail key={rec.id} rec={rec} onBack={() => onSelect("book")} />)}
    </React.Fragment>
  );
};

/* ── New quote (the guided flow survives here) ─────────────────────────── */

const BpNewQuote = ({ accessKey }) => {
  const [fields, setFields] = React.useState({
    postcode: "", property_type: "detached", year_built: 1925, bedrooms: 4,
    sum_insured_buildings: 650000, sum_insured_contents: 85000, claims_count_5yr: 0,
  });
  const [lookup, setLookup] = React.useState({ phase: "idle", addresses: [] });
  const [confirmed, setConfirmed] = React.useState(false);
  const [state, setState] = React.useState({ phase: "idle" });
  const set = (k) => (e) => setFields((f) => ({ ...f, [k]: e.target.value }));
  const CQ = window.solasContent.quoteflow;

  const onFindAddress = async () => {
    setLookup({ phase: "searching", addresses: [] });
    setConfirmed(false);
    try {
      const resp = await fetch("/api/demo-address", {
        method: "POST", headers: { "content-type": "application/json" },
        body: JSON.stringify({ k: accessKey, action: "addresses", postcode: fields.postcode }),
      });
      if (resp.status === 503) { setLookup({ phase: "dark", addresses: [] }); return; }
      if (resp.status === 400) { setLookup({ phase: "error", addresses: [], msg: CQ.errorPostcode }); return; }
      if (!resp.ok) { setLookup({ phase: "error", addresses: [], msg: CQ.lookupError }); return; }
      const data = await resp.json();
      const addresses = data.addresses || [];
      setLookup({ phase: addresses.length ? "found" : "empty", addresses });
    } catch (err) {
      setLookup({ phase: "error", addresses: [], msg: CQ.lookupError });
    }
  };

  const onPickAddress = async (e) => {
    const id = e.target.value;
    if (!id) return;
    try {
      const resp = await fetch("/api/demo-address", {
        method: "POST", headers: { "content-type": "application/json" },
        body: JSON.stringify({ k: accessKey, action: "prefill", certificate_number: id }),
      });
      if (!resp.ok) { setLookup((l) => ({ ...l, phase: "error", msg: CQ.lookupError })); return; }
      const data = await resp.json();
      setFields((f) => ({ ...f, ...(data.prefill || {}) }));
      const label = (lookup.addresses.find((a) => a.id === id) || {}).label;
      setLookup((l) => ({ ...l, phase: "prefilled", selected: id, selectedLabel: label }));
      setConfirmed(false);
    } catch (err) {
      setLookup((l) => ({ ...l, phase: "error", msg: CQ.lookupError }));
    }
  };

  const onSubmit = async (e) => {
    e.preventDefault();
    setState({ phase: "working" });
    try {
      const resp = await fetch("/api/demo-quote", {
        method: "POST", headers: { "content-type": "application/json" },
        body: JSON.stringify({ k: accessKey, risk: fields }),
      });
      if (resp.status === 400) { setState({ phase: "error", msg: CQ.errorPostcode }); return; }
      if (resp.status === 403) { setState({ phase: "error", msg: CB.lockedBody }); return; }
      if (!resp.ok) { setState({ phase: "error", msg: CQ.errorGeneric }); return; }
      const data = await resp.json();
      setState({ phase: "done", mode: data.mode, quote: data.quote });
      window.__bpLastQuote = data.quote;   // feeds the client-view preview
    } catch (err) {
      setState({ phase: "error", msg: CQ.errorGeneric });
    }
  };

  const quote = state.phase === "done" ? state.quote : null;
  const signals = quote
    ? (() => {
        const fs = (quote.rating_audit && quote.rating_audit.feature_set) || {};
        const seen = new Map();
        Object.values(fs).forEach((features) => {
          Object.entries(features || {}).forEach(([feature, value]) => {
            if (!seen.has(feature)) seen.set(feature, { feature, value });
          });
        });
        return [...seen.values()];
      })()
    : [];
  const perils = quote ? quote.peril_breakdown || [] : [];
  const maxPeril = Math.max(...perils.map((p) => Number(p.gross_premium)), 1);

  return (
    <div className="bp-cols">
      <div>
        <p className="bp-note" style={{ marginBottom: 20 }}>{CB.newQuoteIntro}</p>
        <form className="bp-form" onSubmit={onSubmit} data-form="broker-demo-quote">
          <div className="bp-field">
            <label className="bp-field__lbl" htmlFor="bp-postcode">{CQ.postcodeLabel}</label>
            <div style={{ display: "flex", gap: 10 }}>
              <input id="bp-postcode" type="text" required autoComplete="off" placeholder={CQ.postcodePlaceholder}
                value={fields.postcode} onChange={set("postcode")} style={{ textTransform: "uppercase", flex: 1 }} />
              {lookup.phase !== "dark" && (
                <button type="button" className="btn" onClick={onFindAddress}
                  disabled={lookup.phase === "searching" || !fields.postcode.trim()}>
                  {lookup.phase === "searching" ? CQ.findingAddress : CQ.findAddress}
                </button>
              )}
            </div>
          </div>

          {(lookup.phase === "found" || lookup.phase === "prefilled") && (
            <div className="bp-field">
              <label className="bp-field__lbl" htmlFor="bp-address">{CQ.addressLabel}</label>
              <select id="bp-address" defaultValue="" onChange={onPickAddress}>
                <option value="" disabled>{CQ.addressPlaceholder}</option>
                {lookup.addresses.map((a) => <option key={a.id} value={a.id}>{a.label}</option>)}
              </select>
            </div>
          )}
          {lookup.phase === "empty" && <span className="bp-field__hint">{CQ.lookupEmpty}</span>}
          {lookup.phase === "error" && <span className="bp-field__hint">{lookup.msg || CQ.lookupError}</span>}

          {/* UPRN discipline: the broker confirms the matched property against
              what the record shows before anything prices. */}
          {lookup.phase === "prefilled" && (
            <div className="bp-panel bp-panel--well">
              <p className="bp-panel__eyebrow">{CB.uprnConfirmLabel}</p>
              {lookup.selectedLabel && <p className="bp-note" style={{ marginBottom: 8 }}><strong>{lookup.selectedLabel}</strong></p>}
              <p className="bp-note">{CB.uprnConfirmNote}</p>
              <label style={{ display: "flex", gap: 8, alignItems: "center", fontSize: "var(--size-caption)", minHeight: 32, cursor: "pointer" }}>
                <input type="checkbox" checked={confirmed} onChange={(e) => setConfirmed(e.target.checked)} style={{ minHeight: 0, width: 16, height: 16 }} />
                {CB.uprnConfirmLabel}
              </label>
            </div>
          )}

          <div className="bp-form__row">
            <div className="bp-field">
              <label className="bp-field__lbl" htmlFor="bp-type">{CQ.typeLabel}</label>
              <select id="bp-type" value={fields.property_type} onChange={set("property_type")}>
                {CQ.typeOptions.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}
              </select>
            </div>
            <div className="bp-field">
              <label className="bp-field__lbl" htmlFor="bp-year">{CQ.yearLabel}</label>
              <input id="bp-year" type="number" min="1600" max="2030" value={fields.year_built} onChange={set("year_built")} />
            </div>
            <div className="bp-field">
              <label className="bp-field__lbl" htmlFor="bp-beds">{CQ.bedroomsLabel}</label>
              <input id="bp-beds" type="number" min="0" max="20" value={fields.bedrooms} onChange={set("bedrooms")} />
            </div>
          </div>
          <div className="bp-form__row">
            <div className="bp-field">
              <label className="bp-field__lbl" htmlFor="bp-build">{CQ.buildingsLabel}</label>
              <input id="bp-build" type="number" min="50000" max="5000000" step="10000" value={fields.sum_insured_buildings} onChange={set("sum_insured_buildings")} />
            </div>
            <div className="bp-field">
              <label className="bp-field__lbl" htmlFor="bp-cont">{CQ.contentsLabel}</label>
              <input id="bp-cont" type="number" min="0" max="500000" step="5000" value={fields.sum_insured_contents} onChange={set("sum_insured_contents")} />
            </div>
            <div className="bp-field">
              <label className="bp-field__lbl" htmlFor="bp-claims">{CQ.claimsLabel}</label>
              <input id="bp-claims" type="number" min="0" max="20" value={fields.claims_count_5yr} onChange={set("claims_count_5yr")} />
            </div>
          </div>

          <div className="bp-actions">
            <button type="submit" className="btn btn--primary"
              disabled={state.phase === "working" || (lookup.phase === "prefilled" && !confirmed)}>
              {state.phase === "working" ? CQ.working : CQ.submit}
            </button>
            {lookup.phase === "prefilled" && !confirmed && (
              <span className="bp-field__hint">{CB.uprnConfirmLabel}</span>
            )}
          </div>
          {state.phase === "error" && <p role="status" className="form-response">{state.msg}</p>}
        </form>
      </div>

      <div>
        {quote ? (
          <div className="bp-panel" aria-live="polite">
            <p className="bp-panel__eyebrow">{CQ.resultEyebrow.replace("§ ", "")}</p>
            <div className="bp-client__premium">{bpGbp(quote.total_premium_incl_ipt)}</div>
            <div className="bp-client__qualifier">{CQ.annualLabel}</div>
            {state.mode === "fixture" && <p className="bp-note" style={{ marginTop: 10 }}>{CQ.fixtureNote}</p>}
            <p className="bp-note" style={{ marginTop: 14 }}>{CB.resultCaveat}</p>
            <h3 style={{ marginTop: 20 }}>{CQ.breakdownTitle}</h3>
            <dl className="bp-kv">
              {perils.map((p) => (
                <div key={p.peril_name}>
                  <dt>{BP_PERIL_LABELS[p.peril_name] || p.peril_name}</dt>
                  <dd className="bp-num">{bpGbp(p.gross_premium)}</dd>
                </div>
              ))}
            </dl>
            {signals.length > 0 && (
              <React.Fragment>
                <h3 style={{ marginTop: 20 }}>{CQ.signalsTitle}</h3>
                <dl className="bp-kv">
                  {signals.map((sg) => (
                    <div key={sg.feature}>
                      <dt>{BP_SIGNAL_LABELS[sg.feature] || sg.feature}</dt>
                      <dd>{BP_SIGNAL_VALUES[sg.value] || sg.value}</dd>
                    </div>
                  ))}
                </dl>
              </React.Fragment>
            )}
          </div>
        ) : (
          <div className="bp-panel bp-panel--well">
            <p className="bp-panel__eyebrow">{CQ.resultEyebrow.replace("§ ", "")}</p>
            <p className="bp-note" style={{ margin: 0 }}>
              {state.phase === "working" ? CQ.working : CQ.resultPlaceholder}
            </p>
          </div>
        )}
      </div>
    </div>
  );
};

/* ── Documents ─────────────────────────────────────────────────────────── */

const BP_DOCS = [
  { name: "Quote schedule", version: "v1.0 · 22 Aug 2026" },
  { name: "Statement of fact", version: "v1.0 · 22 Aug 2026" },
  { name: "Insurance product information document (IPID)", version: "v1.0 · 22 Aug 2026" },
  { name: "Policy wording", version: "v1.0 · 22 Aug 2026" },
];

const BpDocuments = () => (
  <React.Fragment>
    <p className="bp-note" style={{ marginBottom: 20 }}>{CB.docsIntro}</p>
    <div className="bp-tablewrap">
      <table className="bp-table">
        <thead><tr><th>Document</th><th>Version</th><th>{CB.thStatus}</th></tr></thead>
        <tbody>
          {BP_DOCS.map((d) => (
            <tr key={d.name}>
              <td className="bp-td--wrap"><strong>{d.name}</strong></td>
              <td>{d.version}</td>
              <td><span className="bp-chip bp-chip--specimen">{CB.docsSpecimen}</span></td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
    <p className="bp-note" style={{ marginTop: 16 }}>{CB.docsSpecimenNote}</p>
  </React.Fragment>
);

/* ── Appetite ──────────────────────────────────────────────────────────── */

const BP_APPETITE = {
  inside: [
    "Owner-occupied houses and flats, England and Wales",
    "Rebuild value £250,000 – £1,500,000",
    "Standard construction · post-1850",
    "Up to two claims in five years",
  ],
  refer: [
    "Listed buildings (Grade II)",
    "Flood Zone 3 or declared flood history",
    "Rebuild value £1,500,000 – £2,500,000",
    "Subsidence history with completed remediation",
  ],
  outside: [
    "Thatched roofs · timber-frame heritage construction",
    "Unoccupied or holiday-let occupancy",
    "Grade I and Grade II* listed",
  ],
};

const BpAppetite = () => (
  <React.Fragment>
    <p className="bp-note" style={{ marginBottom: 20 }}>{CB.appetiteIntro}</p>
    <div className="bp-cols" style={{ gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))" }}>
      {[[CB.appetiteInside, BP_APPETITE.inside], [CB.appetiteRefer, BP_APPETITE.refer], [CB.appetiteOutside, BP_APPETITE.outside]].map(([title, items]) => (
        <div key={title} className="bp-panel">
          <p className="bp-panel__eyebrow">{title}</p>
          <ul className="bp-prov">
            {items.map((i) => <li key={i}><span>{i}</span></li>)}
          </ul>
        </div>
      ))}
    </div>
    <p className="bp-note" style={{ marginTop: 16 }}>{CB.appetiteFloodRe}</p>
    <div className="bp-panel bp-panel--well bp-section" style={{ maxWidth: 640 }}>
      <p className="bp-panel__eyebrow">{CB.commissionTitle}</p>
      <p className="bp-note" style={{ margin: 0 }}>{CB.commissionNote}</p>
    </div>
  </React.Fragment>
);

/* ── Client view (the customer register, previewed) ────────────────────── */

const BpClientView = () => {
  const q = window.__bpLastQuote;
  const premium = q ? Number(q.total_premium_incl_ipt) : 1650;
  const fromLive = Boolean(q);
  return (
    <React.Fragment>
      <p className="bp-note" style={{ marginBottom: 8 }}>{CB.clientIntro}</p>
      <p className="bp-note" style={{ marginBottom: 24 }}><strong>{CB.clientWalkthroughNote}</strong></p>
      <div className="bp-clientframe">
        <div className="bp-client__wordmark">Solas</div>
        <p className="bp-client__prepared">{CB.clientPrepared} {CB.brokerName} · {CB.brokerFirm}</p>
        <p className="bp-note" style={{ marginBottom: 0 }}>{CB.clientReviewNote}</p>
        <div className="bp-client__premium">{bpGbp(premium)}{!fromLive && "*"}</div>
        <div className="bp-client__qualifier">
          {CB.clientAnnualLabel}{!fromLive && ` · *${CB.premiumIllustrative}`}
        </div>
        <p className="bp-note" style={{ margin: "20px 0" }}>{CB.resultCaveat}</p>
        {/* No live CTA on any demo surface: the confirm control is a disabled specimen. */}
        <button type="button" className="btn btn--primary" disabled style={{ width: "100%" }}>
          {CB.clientCta}
        </button>
      </div>
    </React.Fragment>
  );
};

/* ── Page ──────────────────────────────────────────────────────────────── */

const BrokerPortalPage = () => {
  const [accessKey, setAccessKey] = React.useState(bpReadKey);
  React.useEffect(() => {
    const onHash = () => setAccessKey(bpReadKey());
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);
  const [tab, setTab] = React.useState("book");
  const [selected, setSelected] = React.useState(null);

  if (!accessKey) {
    return <PageHero eyebrow={`§ ${CB.surfaceLabel}`} title={CB.lockedTitle} standfirst={CB.lockedBody} />;
  }

  const TABS = [
    ["book", CB.tabs.book], ["newQuote", CB.tabs.newQuote], ["referrals", CB.tabs.referrals],
    ["documents", CB.tabs.documents], ["appetite", CB.tabs.appetite], ["client", CB.tabs.client],
  ];

  return (
    <div className="bp-shell">
      <div className="bp-demobar" role="note">
        <span className="bp-demobar__badge">{CB.demoBadge}</span>
        <p className="bp-demobar__line">{CB.demoLine}</p>
      </div>

      <header className="bp-masthead">
        <div className="bp-masthead__brand">
          <span className="bp-masthead__wordmark">Solas</span>
          <span className="bp-masthead__surface">{CB.surfaceLabel}</span>
        </div>
        <div className="bp-masthead__hands">
          {CB.signedInAs} <strong>{CB.brokerName}</strong> · {CB.brokerFirm} · {CB.agencyCode}
        </div>
      </header>

      <nav className="bp-tabs" role="tablist" aria-label={CB.surfaceLabel}>
        {TABS.map(([id, label]) => (
          <button key={id} type="button" role="tab" className="bp-tab" aria-selected={tab === id}
            onClick={() => { setTab(id); setSelected(null); }}>
            {label}
          </button>
        ))}
      </nav>

      {tab === "book" && <BpBook selected={selected} onSelect={setSelected} />}
      {tab === "newQuote" && <BpNewQuote accessKey={accessKey} />}
      {tab === "referrals" && <BpReferrals onSelect={(t) => { setTab(t); setSelected(null); }} />}
      {tab === "documents" && <BpDocuments />}
      {tab === "appetite" && <BpAppetite />}
      {tab === "client" && <BpClientView />}
    </div>
  );
};

Object.assign(window, { BrokerPortalPage });
