/* ================================================================
   coverage-explainer.jsx — "Do we cover it?" lookup tool for the
   Capital Economics marketing site. A prospect searches or browses
   for a country, market, commodity or topic, gets a definitive yes,
   and is sent into a free trial. Lookup only: no selection, no
   basket, no pricing. Coverage is assigned by CE, never chosen.

   Inherits tokens, type ramp, button and card styles from the CE
   design system. Full section + a compressed homepage variant.
================================================================ */
const { MAX, NS, SERIF, SiteHeader, SiteFooter } = window;
const { Button } = window.CapitalEconomicsDesignSystem_f2a5b2;

/* ---------- icons ---------- */
const CI = {
  search: <><circle cx="11" cy="11" r="8" /><path d="m21 21-4.3-4.3" /></>,
  x: <><path d="M18 6 6 18" /><path d="M6 6l12 12" /></>,
  "arrow-right": <><path d="M5 12h14" /><path d="m12 5 7 7-7 7" /></>,
  check: <path d="M20 6 9 17l-5-5" />,
  "chevron-right": <path d="m9 6 6 6-6 6" />,
  "corner-up-right": <><path d="m15 14 5-5-5-5" /><path d="M4 20v-7a4 4 0 0 1 4-4h12" /></>,
};
function CIcon({ name, size = 18, stroke = 2, style }) {
  return <svg style={style} width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">{CI[name]}</svg>;
}

/* ================================================================
   COVERAGE DATA — single structured object, replace with a real
   platform export later. category: Global | Country | Commodities
   | Property. NOTE: several entity/country lists below are SAMPLE
   DATA — partial, and to be replaced with a definitive export
   from the platform.
================================================================ */
const COVERAGE = [
  // ---- Global services ----
  { id: "global-economics", name: "Global Economics", category: "Global", blurb: "World economy overview with growth, trade, inflation and policy forecasts for the largest economies.", entities: ["Global growth", "Trade", "Inflation", "Policy forecasts", "Advanced economies", "Emerging economies"] },
  { id: "global-markets", name: "Global Markets", category: "Global", blurb: "Equities plus local-currency and dollar sovereign and corporate bonds across advanced and emerging economies.", entities: ["Equities", "Local-currency sovereign bonds", "Dollar-denominated bonds", "Corporate bonds"] },
  { id: "asset-allocation", name: "Asset Allocation", category: "Global", blurb: "Projected returns across equities, bonds, commodities and commercial property for the major indices.", entities: ["Equities", "Bonds", "Commodities", "Commercial property", "Major indices"] },
  { id: "fx-markets", name: "FX Markets", category: "Global", blurb: "Forecasts for 30+ advanced and emerging market currencies.", entities: ["US dollar", "Euro", "Japanese yen", "Sterling", "30+ currencies"] },
  { id: "capital-daily", name: "Capital Daily", category: "Global", blurb: "Daily market analysis across the major advanced and emerging economies.", entities: ["Daily market analysis", "Advanced economies", "Emerging economies"] },
  { id: "em-economics", name: "Emerging Markets Economics", category: "Global", blurb: "Cross-cutting themes across the emerging market complex.", entities: ["Emerging market themes"] },
  { id: "climate-economics", name: "Climate Economics", category: "Global", blurb: "The green transition, climate risk, emissions, and the winners and losers from climate change.", entities: ["Green transition", "Climate risk", "Emissions", "Climate winners and losers"] },
  { id: "the-long-run", name: "The Long Run", category: "Global", blurb: "A 30-year outlook for economies and for financial, commodity and commercial property markets.", entities: ["30-year outlook", "Long-run returns", "Financial markets", "Commodity markets", "Commercial property"] },
  // ---- Country and regional services ----
  { id: "us-economics", name: "US Economics", category: "Country", blurb: "The United States economy.", entities: ["United States"] },
  { id: "uk-economics", name: "UK Economics", category: "Country", blurb: "The United Kingdom economy.", entities: ["United Kingdom"] },
  { id: "uk-markets", name: "UK Markets", category: "Country", blurb: "UK financial markets.", entities: ["UK financial markets"] },
  { id: "canada-economics", name: "Canada Economics", category: "Country", blurb: "The Canadian economy.", entities: ["Canada"] },
  { id: "european-economics", name: "European Economics", category: "Country", blurb: "The euro-zone and its member states.", entities: ["Euro-zone", "Germany", "France", "Italy", "Spain", "Netherlands"] /* sample member states */ },
  { id: "nordic-swiss", name: "Nordic and Swiss Economics", category: "Country", blurb: "Switzerland and the Nordic economies.", entities: ["Switzerland", "Sweden", "Norway", "Denmark", "Iceland", "Finland"] },
  { id: "emerging-europe", name: "Emerging Europe Economics", category: "Country", blurb: "13 economies across emerging Europe.", entities: ["Russia", "Turkey", "Poland", "Ukraine", "Czech Republic", "Hungary", "Israel"] /* sample of 13 */ },
  { id: "china-economics", name: "China Economics", category: "Country", blurb: "The Chinese economy.", entities: ["China"] },
  { id: "japan-economics", name: "Japan Economics", category: "Country", blurb: "The Japanese economy.", entities: ["Japan"] },
  { id: "india-economics", name: "India Economics", category: "Country", blurb: "The Indian economy.", entities: ["India"] },
  { id: "emerging-asia", name: "Emerging Asia Economics", category: "Country", blurb: "The emerging economies of Asia.", entities: ["Taiwan", "South Korea", "Singapore", "Vietnam"] /* sample */ },
  { id: "anz", name: "Australia and New Zealand Economics", category: "Country", blurb: "The Australian and New Zealand economies.", entities: ["Australia", "New Zealand"] },
  { id: "latam", name: "Latin American Economics", category: "Country", blurb: "The nine largest Latin American economies.", entities: ["Brazil", "Mexico", "Argentina", "Colombia", "Chile"] /* sample of 9 */ },
  { id: "mena", name: "Middle East and North Africa Economics", category: "Country", blurb: "The 12 largest economies in the region.", entities: ["Saudi Arabia", "Egypt", "United Arab Emirates", "Kuwait"] /* sample of 12 */ },
  { id: "africa", name: "Africa Economics", category: "Country", blurb: "15 Sub-Saharan economies.", entities: ["Nigeria", "South Africa", "Ethiopia", "Uganda", "Zambia"] /* sample of 15 */ },
  // ---- Commodities services ----
  { id: "commodities-overview", name: "Commodities Overview", category: "Commodities", blurb: "Energy, metals, agriculturals and pan-commodity themes.", entities: ["Energy", "Metals", "Agriculturals", "Pan-commodity themes"] },
  { id: "energy", name: "Energy", category: "Commodities", blurb: "Crude oil, natural gas and coal.", entities: ["Crude oil", "Natural gas", "Coal"] },
  { id: "metals", name: "Metals", category: "Commodities", blurb: "Base metals, iron ore, steel and the precious metals.", entities: ["Base metals", "Copper", "Iron ore", "Steel", "Gold", "Silver", "Platinum group"] /* sample */ },
  // ---- Property services ----
  { id: "us-commercial", name: "US Commercial Property", category: "Property", blurb: "US commercial real estate across 17 major metros.", entities: ["US commercial real estate", "17 major metros"] },
  { id: "europe-commercial", name: "European Commercial Property", category: "Property", blurb: "Office, retail and industrial across 21 economies.", entities: ["Office", "Retail", "Industrial", "21 economies"] },
  { id: "uk-commercial", name: "UK Commercial Property", category: "Property", blurb: "UK office, retail and industrial property.", entities: ["Office", "Retail", "Industrial"] },
  { id: "us-housing", name: "US Housing", category: "Property", blurb: "US residential property.", entities: ["US residential"] },
  { id: "uk-housing", name: "UK Housing", category: "Property", blurb: "UK residential property.", entities: ["UK residential"] },
];
const byId = Object.fromEntries(COVERAGE.map((s) => [s.id, s]));

const CAT_LABEL = { Global: "Global service", Country: "Country & regional", Commodities: "Commodities", Property: "Property" };
const CHIP_CAT = { Global: "Global", "Countries and regions": "Country", Commodities: "Commodities", Property: "Property" };
const CHIPS = ["Global", "Countries and regions", "Commodities", "Property"];
const GROUP_ORDER = ["Countries and regions", "Asset classes and markets", "Commodities", "Topics"];

const STATS = [["31", "research services"], ["100+", "economies"], ["30+", "currencies"], ["25", "commodities"], ["70+", "economists"]];
const WHAT_YOU_GET = ["Analysis", "Forecasts", "Data", "Economist access"];
const EXAMPLES = ["Vietnam", "copper", "UK commercial property", "climate risk", "Japanese yen"];

/* ---------- build the search index from the data ---------- */
const ASSET_TERMS = ["equities", "bonds", "sovereign bonds", "corporate bonds", "commercial property", "major indices", "us dollar", "euro", "japanese yen", "sterling", "currencies", "office", "retail", "industrial", "residential", "real estate", "local-currency sovereign bonds", "dollar-denominated bonds"];
const COMMODITY_TERMS = ["commodities", "commodity markets", "energy", "metals", "agriculturals", "crude oil", "natural gas", "coal", "base metals", "copper", "iron ore", "steel", "gold", "silver", "platinum group"];
function entityGroup(service, entity) {
  const e = entity.toLowerCase();
  if (service.category === "Country") return "Countries and regions";
  if (service.category === "Commodities") return "Commodities";
  if (service.category === "Property") return "Asset classes and markets";
  if (COMMODITY_TERMS.includes(e)) return "Commodities";
  if (ASSET_TERMS.some((t) => e.includes(t))) return "Asset classes and markets";
  return "Topics";
}
function nameGroup(category) {
  return category === "Country" ? "Countries and regions" : category === "Commodities" ? "Commodities" : category === "Property" ? "Asset classes and markets" : "Topics";
}
const SEARCH_INDEX = [];
COVERAGE.forEach((s) => {
  SEARCH_INDEX.push({ term: s.name, group: nameGroup(s.category), serviceId: s.id, isName: true });
  s.entities.forEach((e) => SEARCH_INDEX.push({ term: e, group: entityGroup(s, e), serviceId: s.id }));
});

/* synonyms / abbreviations → canonical terms present in the index */
const SYNONYMS = {
  korea: ["South Korea"], uae: ["United Arab Emirates"], emirates: ["United Arab Emirates"],
  oil: ["Crude oil"], crude: ["Crude oil"], gas: ["Natural gas"],
  "real estate": ["Commercial property", "US residential", "UK residential", "Office", "Retail", "Industrial"], property: ["Commercial property"],
  rates: ["Policy forecasts", "Interest rates"], "interest rates": ["Policy forecasts"],
  esg: ["Climate risk", "Green transition"], climate: ["Climate risk"],
  fx: ["30+ currencies", "US dollar", "Euro"], currencies: ["30+ currencies", "US dollar", "Euro", "Japanese yen", "Sterling"], "foreign exchange": ["30+ currencies"],
  yen: ["Japanese yen"], stocks: ["Equities"], shares: ["Equities"], housing: ["US residential", "UK residential"],
};
const norm = (s) => (s || "").toLowerCase().trim().replace(/\s+/g, " ");
function expand(q) {
  const set = new Set([q]);
  (SYNONYMS[q] || []).forEach((t) => set.add(norm(t)));
  Object.keys(SYNONYMS).forEach((k) => { if (q.includes(k)) SYNONYMS[k].forEach((t) => set.add(norm(t))); });
  return [...set];
}
function searchHits(raw, chip) {
  const q = norm(raw);
  if (!q) return [];
  const cands = expand(q);
  const catFilter = chip ? CHIP_CAT[chip] : null;
  const seen = new Set();
  const hits = [];
  SEARCH_INDEX.forEach((e) => {
    if (catFilter && byId[e.serviceId].category !== catFilter) return;
    const t = norm(e.term);
    let score = 0;
    cands.forEach((c) => {
      if (t === c) score = Math.max(score, 4);
      else if (t.startsWith(c)) score = Math.max(score, 3);
      else if (t.includes(c)) score = Math.max(score, 2);
      else if (c.length > 3 && c.includes(t)) score = Math.max(score, 1);
    });
    if (score > 0) {
      const key = e.term + "|" + e.serviceId;
      if (!seen.has(key)) { seen.add(key); hits.push({ ...e, score }); }
    }
  });
  hits.sort((a, b) => b.score - a.score || a.term.length - b.term.length);
  return hits.slice(0, 10);
}
function groupHits(hits) {
  const groups = [];
  GROUP_ORDER.forEach((g) => { const items = hits.filter((h) => h.group === g); if (items.length) groups.push([g, items]); });
  return groups;
}
function relatedTo(serviceId) {
  const s = byId[serviceId];
  const same = COVERAGE.filter((x) => x.category === s.category && x.id !== serviceId);
  const picks = [];
  ["global-economics", "fx-markets", "asset-allocation"].forEach((id) => { if (id !== serviceId && !same.find((x) => x.id === id)) picks.push(byId[id]); });
  return [...same.slice(0, 2), ...picks].slice(0, 3);
}
const CLOSEST = ["global-economics", "em-economics", "asset-allocation"].map((id) => byId[id]);

/* ================================================================
   Service card (compact)
================================================================ */
function ServiceCard({ s, onOpen }) {
  return (
    <a href={"#service-" + s.id} className="cov-card" onClick={(e) => { if (onOpen) { e.preventDefault(); onOpen(s.id); } }}>
      <div className="cov-card-cat">{CAT_LABEL[s.category]}</div>
      <div className="cov-card-name">{s.name}</div>
      <p className="cov-card-blurb">{s.blurb}</p>
      <div className="cov-card-entities">{s.entities.join(" · ")}</div>
    </a>
  );
}

/* ================================================================
   Search box with type-ahead listbox (keyboard + ARIA)
================================================================ */
function SearchBox({ value, onChange, onCommit, chip, autoFocus, compact }) {
  const [open, setOpen] = React.useState(false);
  const [hi, setHi] = React.useState(0);
  const [ph, setPh] = React.useState(0);
  const ref = React.useRef();
  const inputRef = React.useRef();
  const hits = searchHits(value, chip);
  const flat = hits;

  React.useEffect(() => { setHi(0); }, [value, chip]);
  React.useEffect(() => { if (autoFocus && inputRef.current) inputRef.current.focus({ preventScroll: true }); }, [autoFocus]);
  React.useEffect(() => {
    if (value) return;
    const t = setInterval(() => setPh((p) => (p + 1) % EXAMPLES.length), 2600);
    return () => clearInterval(t);
  }, [value]);
  React.useEffect(() => {
    const h = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", h); return () => document.removeEventListener("mousedown", h);
  }, []);

  const commit = (hit) => {
    setOpen(false);
    if (hit) onCommit({ term: hit.term, serviceId: hit.serviceId });
    else if (value.trim()) onCommit({ term: value.trim(), serviceId: flat[0] ? flat[0].serviceId : null });
  };
  const onKey = (e) => {
    if (e.key === "ArrowDown") { e.preventDefault(); setOpen(true); setHi((i) => Math.min(i + 1, flat.length - 1)); }
    else if (e.key === "ArrowUp") { e.preventDefault(); setHi((i) => Math.max(i - 1, 0)); }
    else if (e.key === "Enter") { e.preventDefault(); commit(flat[hi]); }
    else if (e.key === "Escape") { setOpen(false); }
  };
  const grouped = groupHits(flat);
  const showList = open && value.trim().length > 0 && flat.length > 0;
  let optIndex = -1;

  return (
    <div className={"cov-search" + (compact ? " is-compact" : "")} ref={ref}>
      <div className="cov-search-field">
        <CIcon name="search" size={compact ? 20 : 24} />
        <input
          ref={inputRef} type="text" role="combobox" aria-expanded={showList} aria-controls="cov-listbox"
          aria-autocomplete="list" aria-label="Search coverage by country, market, commodity or topic"
          value={value} placeholder={"Try " + EXAMPLES[ph]}
          onChange={(e) => { onChange(e.target.value); setOpen(true); }}
          onFocus={() => setOpen(true)} onKeyDown={onKey}
        />
        {value && <button type="button" className="cov-search-clear" aria-label="Clear search" onClick={() => { onChange(""); inputRef.current && inputRef.current.focus(); }}><CIcon name="x" size={18} /></button>}
      </div>
      {showList && (
        <div className="cov-listbox" id="cov-listbox" role="listbox" aria-label="Coverage results">
          {grouped.map(([g, items]) => (
            <div key={g} className="cov-lb-group">
              <div className="cov-lb-head">{g}</div>
              {items.map((h) => {
                optIndex++; const idx = optIndex; const svc = byId[h.serviceId];
                return (
                  <div key={h.term + h.serviceId} id={"cov-opt-" + idx} role="option" aria-selected={idx === hi}
                    className={"cov-opt" + (idx === hi ? " hi" : "")}
                    onMouseEnter={() => setHi(idx)} onMouseDown={(e) => e.preventDefault()} onClick={() => commit(h)}>
                    <span className="cov-opt-term">{h.term}</span>
                    <span className="cov-opt-svc">{svc.name}<CIcon name="chevron-right" size={15} /></span>
                  </div>
                );
              })}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

/* ================================================================
   Result states
================================================================ */
function StatStrip() {
  return (
    <div className="cov-stats">
      {STATS.map(([n, l]) => (
        <div key={l} className="cov-stat"><span className="cov-stat-n">{n}</span><span className="cov-stat-l">{l}</span></div>
      ))}
    </div>
  );
}

function IdleState({ chip }) {
  const cat = chip ? CHIP_CAT[chip] : null;
  const list = cat ? COVERAGE.filter((s) => s.category === cat) : COVERAGE;
  return (
    <div>
      <StatStrip />
      <div className="cov-grid">{list.map((s) => <ServiceCard key={s.id} s={s} />)}</div>
    </div>
  );
}

function WhatYouGet() {
  return (
    <div className="cov-wyg">
      {WHAT_YOU_GET.map((w) => <span key={w} className="cov-wyg-item"><span className="cov-wyg-tick"><CIcon name="check" size={13} stroke={2.6} /></span>{w}</span>)}
    </div>
  );
}

function MatchState({ term, service, onClear }) {
  const related = relatedTo(service.id);
  return (
    <div className="cov-answer">
      <div className="cov-answer-head">
        <div>
          <h3 className="cov-answer-line"><span className="cov-yes">Yes.</span> {term} is covered.</h3>
          <div className="cov-answer-in">In <strong>{service.name}</strong></div>
        </div>
        <button type="button" className="cov-clear" onClick={onClear}><CIcon name="x" size={15} />Clear search</button>
      </div>

      <div className="cov-answer-card">
        <div className="cov-card-cat">{CAT_LABEL[service.category]}</div>
        <div className="cov-answer-name">{service.name}</div>
        <p className="cov-answer-blurb">{service.blurb}</p>
        <div className="cov-answer-entities-label">Covers</div>
        <div className="cov-answer-entities">{service.entities.map((e) => <span key={e} className="cov-ent">{e}</span>)}</div>
        <WhatYouGet />
        <div className="cov-answer-cta">
          <Button variant="primary" size="lg" iconEnd={<CIcon name="arrow-right" size={18} />}>Start free trial</Button>
          <a href={"#service-" + service.id} className="cov-textlink">See the {service.name} service</a>
        </div>
      </div>

      <div className="cov-related">
        <div className="cov-related-head">Related coverage</div>
        <div className="cov-grid cov-grid-3">{related.map((s) => <ServiceCard key={s.id} s={s} />)}</div>
      </div>
    </div>
  );
}

function NoMatchState({ term, onClear }) {
  return (
    <div className="cov-answer">
      <div className="cov-answer-head">
        <div>
          <h3 className="cov-answer-line cov-answer-line-no">We don't have a dedicated service for {term ? "“" + term + "”" : "that"}.</h3>
          <div className="cov-answer-in">Here's the closest coverage we do have.</div>
        </div>
        <button type="button" className="cov-clear" onClick={onClear}><CIcon name="x" size={15} />Clear search</button>
      </div>
      <div className="cov-grid cov-grid-3">{CLOSEST.map((s) => <ServiceCard key={s.id} s={s} />)}</div>
      <div className="cov-bespoke">
        <div>
          <div className="cov-bespoke-h">Need something bespoke?</div>
          <p className="cov-bespoke-p">Our consultancy team builds custom research to answer questions the published services do not.</p>
        </div>
        <a href="/consultancy" className="cov-textlink cov-textlink-strong">Talk to our team<CIcon name="corner-up-right" size={16} /></a>
      </div>
    </div>
  );
}

function SectionFooter() {
  return (
    <div className="cov-footer">
      <div className="cov-footer-actions">
        <Button variant="primary" size="lg" iconEnd={<CIcon name="arrow-right" size={18} />}>Start free trial</Button>
        <span className="cov-footer-note">Get started in under a minute, no sales call required.</span>
      </div>
      <a href="/consultancy" className="cov-textlink">Talk to our team about full coverage</a>
    </div>
  );
}

/* ================================================================
   Full section
================================================================ */
function CoverageExplainer({ deepLink }) {
  const [query, setQuery] = React.useState("");
  const [chip, setChip] = React.useState(null);
  const [committed, setCommitted] = React.useState(null); // { term, serviceId }

  React.useEffect(() => {
    if (!deepLink || !deepLink.term) return;
    setQuery(deepLink.term);
    const hits = searchHits(deepLink.term, null);
    setCommitted({ term: deepLink.term, serviceId: hits[0] ? hits[0].serviceId : null });
  }, [deepLink && deepLink.nonce]);

  const onCommit = (c) => { setQuery(c.term); setCommitted(c); };
  const clear = () => { setCommitted(null); setQuery(""); };

  const state = committed ? (committed.serviceId ? "match" : "nomatch") : "idle";

  return (
    <section className="cov-section" id="cov-full" aria-labelledby="cov-h">
      <div className="cov-hero">
        <div className="cov-hero-in">
          <div className="cov-header">
            <h2 className="cov-h" id="cov-h">Do we cover it?</h2>
            <p className="cov-sub">31 research services. 100+ economies. Search for a country, market or topic.</p>
          </div>
          <SearchBox value={query} onChange={(v) => { setQuery(v); if (committed) setCommitted(null); }} onCommit={onCommit} chip={chip} autoFocus />
          <div className="cov-chips" role="group" aria-label="Filter by category">
            {CHIPS.map((c) => (
              <button key={c} type="button" className={"cov-chip" + (chip === c ? " on" : "")} aria-pressed={chip === c}
                onClick={() => setChip((x) => x === c ? null : c)}>{c}</button>
            ))}
          </div>
        </div>
      </div>
      <div className="cov-inner">
        <div className="cov-results">
          {state === "idle" && <IdleState chip={chip} />}
          {state === "match" && <MatchState term={committed.term} service={byId[committed.serviceId]} onClear={clear} />}
          {state === "nomatch" && <NoMatchState term={committed.term} onClear={clear} />}
        </div>
        <SectionFooter />
      </div>
    </section>
  );
}

/* ================================================================
   Compressed homepage variant — header, search, four chips, stat
   strip and a "See everything we cover" link. No results grid.
   Same search behaviour, but it deep-links to the full page.
================================================================ */
function CoverageExplainerCompact({ onDeepLink }) {
  const [query, setQuery] = React.useState("");
  return (
    <section className="cov-compact" aria-labelledby="covc-h">
      <div className="cov-hero cov-hero-compact">
        <div className="cov-hero-in">
          <div className="cov-header">
            <h2 className="cov-h cov-h-sm" id="covc-h">Do we cover it?</h2>
            <p className="cov-sub">31 research services. 100+ economies. Search for a country, market or topic.</p>
          </div>
          <SearchBox value={query} onChange={setQuery} onCommit={(c) => onDeepLink(c.term)} compact />
          <div className="cov-chips" role="group" aria-label="Browse by category">
            {CHIPS.map((c) => <button key={c} type="button" className="cov-chip" onClick={() => onDeepLink(c)}>{c}</button>)}
          </div>
          <StatStrip />
          <a href="#cov-full" className="cov-seeall" onClick={(e) => { e.preventDefault(); onDeepLink(""); }}>See everything we cover<CIcon name="arrow-right" size={16} /></a>
        </div>
      </div>
    </section>
  );
}

/* ================================================================ CSS */
(function injectCovCSS() {
  if (typeof document === "undefined" || document.getElementById("cov-css")) return;
  const css = `
  .cov-section, .cov-compact { background: var(--surface-page); overflow-x: hidden; }
  .cov-hero { background: linear-gradient(157deg, #1b2038 0%, #17285a 52%, #164194 120%); }
  .cov-hero-in { max-width: ${MAX}px; margin: 0 auto; padding: 78px 32px 46px; }
  .cov-hero-compact .cov-hero-in { padding: 58px 32px 50px; }
  .cov-inner { max-width: ${MAX}px; margin: 0 auto; padding: 46px 32px 68px; }
  .cov-header { text-align: center; margin-bottom: 30px; }
  .cov-h { font-family: ${SERIF}; font-weight: 600; font-size: 56px; line-height: 1.01; letter-spacing: -0.026em; color: #fff; margin: 0; }
  .cov-h-sm { font-size: 42px; }
  .cov-sub { font-family: ${NS}; font-size: 17px; line-height: 1.5; color: rgba(255,255,255,0.78); margin: 15px 0 0; }

  /* search */
  .cov-search { position: relative; max-width: 760px; margin: 0 auto; }
  .cov-search-field { display: flex; align-items: center; gap: 14px; background: #fff; border: 2px solid transparent; border-radius: var(--radius-lg); padding: 0 20px; height: 74px; color: var(--text-muted); box-shadow: 0 22px 54px rgba(9,15,40,0.38); transition: border-color 140ms cubic-bezier(0.2,0,0,1), box-shadow 140ms; }
  .cov-search:focus-within .cov-search-field { border-color: var(--brand); box-shadow: 0 0 0 4px rgba(165,181,222,0.5), 0 22px 54px rgba(9,15,40,0.38); color: var(--brand); }
  .cov-search.is-compact .cov-search-field { height: 60px; }
  .cov-search-field input { flex: 1; border: 0; outline: 0; background: transparent; font-family: ${NS}; font-size: 20px; font-weight: 500; color: var(--text-primary); }
  .cov-search.is-compact .cov-search-field input { font-size: 17px; }
  .cov-search-field input::placeholder { color: var(--text-muted); font-weight: 500; }
  .cov-search-clear { border: 0; background: transparent; color: var(--text-muted); cursor: pointer; display: inline-flex; padding: 4px; border-radius: 6px; }
  .cov-search-clear:hover { color: var(--text-secondary); }

  /* listbox */
  .cov-listbox { position: absolute; top: calc(100% + 8px); left: 0; right: 0; z-index: 40; background: var(--surface-card); border: 1px solid var(--border-default); border-radius: var(--radius-lg); box-shadow: 0 18px 50px rgba(20,30,60,0.18); padding: 8px; max-height: 380px; overflow-y: auto; }
  .cov-lb-group { padding: 4px 0; }
  .cov-lb-head { font-family: ${NS}; font-weight: 700; font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted); padding: 8px 12px 6px; }
  .cov-opt { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 10px 12px; border-radius: 8px; cursor: pointer; }
  .cov-opt.hi { background: var(--brand-subtle); }
  .cov-opt-term { font-family: ${NS}; font-size: 15.5px; font-weight: 600; color: var(--text-primary); }
  .cov-opt.hi .cov-opt-term { color: var(--brand); }
  .cov-opt-svc { display: inline-flex; align-items: center; gap: 4px; font-family: ${NS}; font-size: 13px; color: var(--text-muted); white-space: nowrap; }

  /* chips */
  .cov-chips { display: flex; flex-wrap: wrap; gap: 9px; justify-content: center; margin: 18px 0 0; }
  .cov-chip { font-family: ${NS}; font-size: 14px; font-weight: 700; padding: 9px 18px; border-radius: 999px; border: 1px solid var(--border-default); background: var(--surface-card); color: var(--text-secondary); cursor: pointer; transition: all 140ms cubic-bezier(0.2,0,0,1); }
  .cov-chip:hover { border-color: var(--brand); color: var(--brand); }
  .cov-chip.on { background: var(--brand); border-color: var(--brand); color: #fff; }
  .cov-hero .cov-chip { background: rgba(255,255,255,0.08); border-color: rgba(255,255,255,0.22); color: rgba(255,255,255,0.92); }
  .cov-hero .cov-chip:hover { background: rgba(255,255,255,0.16); border-color: rgba(255,255,255,0.55); color: #fff; }
  .cov-hero .cov-chip.on { background: #fff; border-color: #fff; color: var(--brand); }

  /* results */
  .cov-results { margin-top: 34px; }
  .cov-stats { display: flex; flex-wrap: wrap; gap: 14px; justify-content: center; padding: 20px 24px; background: var(--surface-card); border: 1px solid var(--border-subtle); border-radius: var(--radius-lg); margin-bottom: 28px; }
  .cov-compact .cov-stats { margin: 26px 0 0; }
  .cov-hero .cov-stats { background: rgba(255,255,255,0.06); border-color: rgba(255,255,255,0.14); }
  .cov-hero .cov-stat + .cov-stat { border-left-color: rgba(255,255,255,0.16); }
  .cov-hero .cov-stat-n { color: #fff; }
  .cov-hero .cov-stat-l { color: rgba(255,255,255,0.72); }
  .cov-stat { display: flex; flex-direction: column; align-items: center; padding: 0 18px; flex: 1 1 auto; }
  .cov-stat + .cov-stat { border-left: 1px solid var(--border-subtle); }
  .cov-stat-n { font-family: ${SERIF}; font-weight: 600; font-size: 30px; line-height: 1; letter-spacing: -0.01em; color: var(--brand); font-variant-numeric: tabular-nums; }
  .cov-stat-l { font-family: ${NS}; font-size: 13px; color: var(--text-secondary); margin-top: 6px; text-align: center; }

  /* grid + card */
  .cov-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
  .cov-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .cov-card { display: flex; flex-direction: column; background: var(--surface-card); border: 1px solid var(--border-subtle); border-radius: var(--radius-lg); padding: 18px 20px; text-decoration: none; color: inherit; transition: border-color 150ms cubic-bezier(0.2,0,0,1), box-shadow 150ms, transform 150ms; }
  .cov-card:hover { border-color: var(--border-default); box-shadow: var(--shadow-sm); transform: translateY(-2px); }
  .cov-card-cat { font-family: ${NS}; font-weight: 700; font-size: 10.5px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--brand); margin-bottom: 8px; }
  .cov-card-name { font-family: ${SERIF}; font-weight: 600; font-size: 18px; line-height: 1.2; letter-spacing: -0.01em; color: var(--text-primary); margin-bottom: 7px; }
  .cov-card-blurb { font-family: ${NS}; font-size: 13.5px; line-height: 1.45; color: var(--text-secondary); margin: 0 0 12px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .cov-card-entities { font-family: ${NS}; font-size: 12.5px; color: var(--text-muted); margin-top: auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

  /* answer (match) */
  .cov-answer-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 20px; }
  .cov-answer-line { font-family: ${SERIF}; font-weight: 600; font-size: 32px; line-height: 1.12; letter-spacing: -0.018em; color: var(--text-primary); margin: 0; }
  .cov-yes { color: var(--positive, #3c8f5a); }
  .cov-answer-line-no { font-size: 27px; }
  .cov-answer-in { font-family: ${NS}; font-size: 16px; color: var(--text-secondary); margin-top: 8px; }
  .cov-answer-in strong { color: var(--text-primary); font-weight: 700; }
  .cov-clear { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--border-default); background: var(--surface-card); color: var(--text-secondary); font-family: ${NS}; font-size: 13px; font-weight: 700; padding: 8px 13px; border-radius: 999px; cursor: pointer; white-space: nowrap; flex: 0 0 auto; }
  .cov-clear:hover { border-color: var(--border-strong); color: var(--text-primary); }
  .cov-answer-card { background: var(--surface-card); border: 1px solid var(--border-default); border-left: 4px solid var(--brand); border-radius: var(--radius-lg); padding: 26px 28px; box-shadow: 0 8px 30px rgba(36,33,58,0.07); }
  .cov-answer-name { font-family: ${SERIF}; font-weight: 600; font-size: 24px; line-height: 1.16; letter-spacing: -0.015em; color: var(--text-primary); margin: 4px 0 10px; }
  .cov-answer-blurb { font-family: ${NS}; font-size: 15.5px; line-height: 1.55; color: var(--text-secondary); margin: 0 0 20px; max-width: 760px; }
  .cov-answer-entities-label { font-family: ${NS}; font-weight: 700; font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 10px; }
  .cov-answer-entities { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 22px; }
  .cov-ent { font-family: ${NS}; font-size: 13.5px; font-weight: 600; color: var(--text-primary); background: var(--surface-sunken, #f2f4f8); border: 1px solid var(--border-subtle); border-radius: 999px; padding: 5px 12px; }
  .cov-wyg { display: flex; flex-wrap: wrap; gap: 18px; padding: 18px 0; border-top: 1px solid var(--border-subtle); margin-bottom: 22px; }
  .cov-wyg-item { display: inline-flex; align-items: center; gap: 9px; font-family: ${NS}; font-size: 14.5px; font-weight: 600; color: var(--text-primary); }
  .cov-wyg-tick { width: 20px; height: 20px; border-radius: 999px; background: var(--brand-subtle); color: var(--brand); display: inline-flex; align-items: center; justify-content: center; }
  .cov-answer-cta { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
  .cov-textlink { font-family: ${NS}; font-size: 14.5px; font-weight: 700; color: var(--text-link); text-decoration: none; display: inline-flex; align-items: center; gap: 6px; }
  .cov-textlink:hover { text-decoration: underline; }
  .cov-textlink-strong { color: var(--brand); }
  .cov-related { margin-top: 34px; }
  .cov-related-head { font-family: ${NS}; font-weight: 700; font-size: 12px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 14px; }

  /* no match */
  .cov-bespoke { display: flex; align-items: center; justify-content: space-between; gap: 20px; flex-wrap: wrap; margin-top: 28px; padding: 22px 26px; background: var(--surface-sunken, #f2f4f8); border: 1px solid var(--border-subtle); border-radius: var(--radius-lg); }
  .cov-bespoke-h { font-family: ${SERIF}; font-weight: 600; font-size: 19px; color: var(--text-primary); }
  .cov-bespoke-p { font-family: ${NS}; font-size: 14.5px; line-height: 1.5; color: var(--text-secondary); margin: 6px 0 0; max-width: 560px; }

  /* footer */
  .cov-footer { display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap; margin-top: 44px; padding-top: 32px; border-top: 1px solid var(--border-default); }
  .cov-footer-actions { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
  .cov-footer-note { font-family: ${NS}; font-size: 14.5px; color: var(--text-secondary); }

  /* compact */
  .cov-seeall { display: flex; align-items: center; justify-content: center; gap: 7px; font-family: ${NS}; font-size: 15px; font-weight: 700; color: var(--brand); text-decoration: none; margin-top: 24px; }
  .cov-seeall:hover { text-decoration: underline; }
  .cov-hero .cov-seeall { color: #fff; margin-top: 26px; }

  @media (max-width: 980px) { .cov-grid, .cov-grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
  @media (max-width: 680px) {
    .cov-inner { padding: 34px 18px 48px; }
    .cov-hero-in { padding: 46px 18px 32px; }
    .cov-hero-compact .cov-hero-in { padding: 40px 18px 36px; }
    .cov-h { font-size: 36px; } .cov-h-sm { font-size: 30px; }
    .cov-search-field { height: 58px; } .cov-search-field input { font-size: 17px; }
    .cov-chips { justify-content: flex-start; overflow-x: auto; flex-wrap: nowrap; margin-left: -18px; margin-right: -18px; padding: 4px 18px 0; }
    .cov-chip { flex: 0 0 auto; }
    .cov-stats { flex-direction: column; gap: 0; }
    .cov-stat { flex-direction: row; justify-content: space-between; width: 100%; padding: 11px 4px; }
    .cov-stat + .cov-stat { border-left: 0; border-top: 1px solid var(--border-subtle); }
    .cov-stat-n { font-size: 22px; } .cov-stat-l { margin-top: 0; }
    .cov-grid, .cov-grid-3 { grid-template-columns: 1fr; }
    .cov-answer-line { font-size: 26px; } .cov-answer-line-no { font-size: 22px; }
    .cov-answer-head { flex-direction: column; }
    .cov-footer { flex-direction: column; align-items: flex-start; }
  }
  `;
  const el = document.createElement("style"); el.id = "cov-css"; el.textContent = css;
  document.head.appendChild(el);
})();

/* ================================================================ App */
function App() {
  const [deepLink, setDeepLink] = React.useState(null);
  const nonce = React.useRef(0);
  const onDeepLink = (term) => {
    nonce.current += 1;
    setDeepLink({ term, nonce: nonce.current });
    const el = document.getElementById("cov-full");
    if (el) window.scrollTo({ top: window.scrollY + el.getBoundingClientRect().top - 12, behavior: "smooth" });
  };
  return (
    <div style={{ minHeight: "100vh", background: "var(--surface-page)", overflowX: "hidden" }}>
      <div className="cov-demo-label"><span>Homepage variant — compressed, deep-links to the full page</span></div>
      <CoverageExplainerCompact onDeepLink={onDeepLink} />
      <div className="cov-demo-divider" />
      <div className="cov-demo-label"><span>Full section — interactive: idle, match and no-match states</span></div>
      <CoverageExplainer deepLink={deepLink} />
    </div>
  );
}

(function injectDemoLabelCSS() {
  if (document.getElementById("cov-demo-css")) return;
  const el = document.createElement("style"); el.id = "cov-demo-css";
  el.textContent = `.cov-demo-label{max-width:${MAX}px;margin:0 auto;padding:20px 32px 0;}.cov-demo-label span{font-family:${NS};font-weight:700;font-size:11px;letter-spacing:0.1em;text-transform:uppercase;color:var(--text-muted);}.cov-demo-divider{height:1px;background:var(--border-default);max-width:${MAX}px;margin:8px auto;}`;
  document.head.appendChild(el);
})();

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
