/* ================================================================
   content-detail.jsx — Capital Economics shared content detail
   template. One page shell for all free long-form content: the
   Chief Economist's Note, case studies, event pages and on-demand
   recordings. Worked example is the Note; everything generalises
   through the `variant` config (eyebrow, rail panel, conversion
   block copy and primary action).

   Structure: breadcrumb · compressed navy hero · two-column body
   (narrow sticky rail + editorial main column) · article footer
   (tags) · author card · conversion block (the centre of gravity)
   · related content · site footer.

   Rail on desktop: On this page jump links (active section rule),
   download, share, a variant fact panel, and a compact trial card
   that fades in past ~25% of the article. On mobile the rail
   collapses: jump links become a top "On this page" control,
   download/share become a slim sticky bottom bar, the trial card
   is dropped (the end conversion block covers it), and charts
   scroll horizontally.

   UK English. No em or en dashes in copy. No teal, no green.
   Reuses SiteHeader/SiteFooter, ArticleCard + AccessBadge, MiniChart.
================================================================ */
const { Button } = window.CapitalEconomicsDesignSystem_f2a5b2;
const { NS, SERIF, SiteHeader, SiteFooter, Icon } = window;
const { ArticleCard, AccessBadge, MiniChart, IIcon } = window;

/* ---- extra icons not in the shared set ---- */
const CD_ICONS = {
  lock: <><rect width="18" height="11" x="3" y="11" rx="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" /></>,
  download: <><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /><path d="M7 10l5 5 5-5" /><path d="M12 15V3" /></>,
  share: <><circle cx="18" cy="5" r="3" /><circle cx="6" cy="12" r="3" /><circle cx="18" cy="19" r="3" /><path d="m8.6 13.5 6.8 4M15.4 6.5 8.6 10.5" /></>,
  "arrow-right": <><path d="M5 12h14" /><path d="m12 5 7 7-7 7" /></>,
  clock: <><circle cx="12" cy="12" r="10" /><path d="M12 6v6l4 2" /></>,
  calendar: <><rect width="18" height="18" x="3" y="4" rx="2" /><path d="M16 2v4M8 2v4M3 10h18" /></>,
  "map-pin": <><path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" /><circle cx="12" cy="10" r="3" /></>,
};
function CdIcon({ 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">{CD_ICONS[name]}</svg>
  );
}

let cdCSS = false;
function injectCdCSS() {
  if (cdCSS || typeof document === "undefined") return;
  cdCSS = true;
  const css = `
  .cd-root { font-family: ${NS}; color: var(--text-primary); background: var(--surface-page); container-type: inline-size; }

  /* access badge (from the insights component; styles re-declared here) */
  .ins-access-wrap { position: relative; display: inline-flex; }
  .ins-access { font-family: ${NS}; font-weight: 700; font-size: 11px; letter-spacing: 0.02em; padding: 3px 9px; border-radius: 999px; cursor: help; white-space: nowrap; }
  .ins-access.is-free { background: var(--grey-100); color: var(--grey-600); }
  .ins-access.is-credit { background: transparent; color: var(--brand); border: 1px solid var(--brand); }
  .ins-access.is-sub { background: var(--brand); color: #fff; }
  .ins-tip { position: absolute; bottom: calc(100% + 8px); right: 0; width: 210px; background: #1d233f; color: #fff; font-family: ${NS}; font-size: 12px; line-height: 1.45; padding: 9px 11px; border-radius: 8px; box-shadow: 0 10px 30px rgba(20,30,60,0.28); opacity: 0; visibility: hidden; transform: translateY(4px); transition: opacity 140ms, transform 140ms, visibility 140ms; z-index: 20; }
  .ins-tip a, .ins-tip-link { color: var(--ce-blue-light); font-weight: 700; text-decoration: underline; cursor: pointer; }
  .ins-access-wrap:hover .ins-tip, .ins-access:focus + .ins-tip { opacity: 1; visibility: visible; transform: none; }
  .cd-wrap { max-width: 1180px; margin: 0 auto; padding: 0 32px; }

  /* --- Breadcrumb --- */
  .cd-crumb { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 13px; color: var(--text-muted); padding: 22px 0 0; }
  .cd-crumb a { color: var(--text-muted); text-decoration: none; }
  .cd-crumb a:hover { color: var(--text-secondary); }
  .cd-crumb .cd-cr-sep { color: var(--border-strong); }
  .cd-crumb .cd-cr-here { color: var(--text-secondary); font-weight: 600; }

  /* --- Hero (compressed, navy, centred on the content column) --- */
  .cd-hero { background: var(--ce-navy); color: #fff; margin-top: 16px; }
  .cd-hero-in { max-width: 1180px; margin: 0 auto; padding: 40px 32px 38px; }
  .cd-eyebrow { font-weight: 700; font-size: 12px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ce-blue-light); margin: 0 0 16px; }
  .cd-h1 { font-family: ${SERIF}; font-weight: 600; font-size: 48px; line-height: 1.1; letter-spacing: -0.022em; margin: 0 0 16px; max-width: 30ch; text-wrap: balance; color: #fff; }
  .cd-standfirst { font-size: 18px; line-height: 1.5; font-weight: 400; color: rgba(255,255,255,0.82); margin: 0 0 26px; max-width: 58ch; }
  .cd-metarow { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; font-size: 13.5px; color: rgba(255,255,255,0.72); }
  .cd-avatar { width: 38px; height: 38px; border-radius: 50%; overflow: hidden; background: var(--ce-blue); color: #fff; display: inline-flex; align-items: center; justify-content: center; font-weight: 700; font-size: 14px; letter-spacing: 0.02em; flex: 0 0 auto; }
  .cd-byline { color: #fff; font-weight: 600; }
  .cd-meta-sep { width: 3px; height: 3px; border-radius: 50%; background: rgba(255,255,255,0.4); }
  .cd-hero .ins-access { background: rgba(255,255,255,0.14); color: #fff; }

  /* --- Two-column body --- */
  .cd-body { display: grid; grid-template-columns: 196px minmax(0, 1fr); gap: 0 56px; padding: 46px 0 20px; align-items: start; }

  /* Rail */
  .cd-rail { position: sticky; top: 24px; display: flex; flex-direction: column; gap: 26px; }
  .cd-rail-mobtoggle { display: none; }
  .cd-onthis-h { font-weight: 700; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-muted); margin: 0 0 12px; }
  .cd-jump { list-style: none; margin: 0; padding: 0; border-left: 1px solid var(--border-default); }
  .cd-jump a { display: block; font-size: 13.5px; line-height: 1.35; color: var(--text-secondary); text-decoration: none; padding: 7px 0 7px 14px; margin-left: -1px; border-left: 2px solid transparent; }
  .cd-jump a:hover { color: var(--text-primary); }
  .cd-jump a.on { color: var(--brand); font-weight: 700; border-left-color: var(--brand); }

  .cd-railactions { display: flex; flex-direction: column; gap: 2px; }
  .cd-railact { display: inline-flex; align-items: center; gap: 9px; font-size: 13.5px; font-weight: 600; color: var(--text-secondary); background: 0; border: 0; padding: 7px 0; cursor: pointer; text-decoration: none; }
  .cd-railact:hover { color: var(--brand); }
  .cd-railact svg { color: var(--text-muted); }
  .cd-railact:hover svg { color: var(--brand); }

  /* Variant fact panel */
  .cd-factpanel { border-top: 1px solid var(--border-default); padding-top: 16px; }
  .cd-factpanel dl { margin: 0; display: flex; flex-direction: column; gap: 12px; }
  .cd-factrow dt { font-weight: 700; font-size: 10.5px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted); margin: 0 0 2px; }
  .cd-factrow dd { margin: 0; font-size: 14px; font-weight: 600; color: var(--text-primary); }

  /* Event speakers panel */
  .cd-speakers { border-top: 1px solid var(--border-default); padding-top: 16px; }
  .cd-panel-h { font-weight: 700; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-muted); margin: 0 0 14px; }
  .cd-speaker-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }
  .cd-speaker { display: flex; gap: 11px; align-items: center; }
  .cd-speaker-av { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; display: block; flex: none; }
  .cd-speaker-name { margin: 0; font-size: 13.5px; font-weight: 700; color: var(--text-primary); line-height: 1.25; }
  .cd-speaker-role { margin: 1px 0 0; font-size: 12px; color: var(--text-muted); line-height: 1.3; }

  /* Compact trial card (fades in past 25%) */
  .cd-trial { border-top: 2px solid var(--ce-navy); background: var(--surface-subtle); border-radius: 0 0 var(--radius-md,6px) var(--radius-md,6px); padding: 16px 16px 18px; opacity: 0; transform: translateY(6px); transition: opacity 200ms cubic-bezier(0.2,0,0,1), transform 200ms cubic-bezier(0.2,0,0,1); pointer-events: none; }
  .cd-trial.show { opacity: 1; transform: none; pointer-events: auto; }
  .cd-trial-eyebrow { display: inline-flex; align-items: center; gap: 6px; font-weight: 700; font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ce-navy); margin: 0 0 8px; }
  .cd-trial-txt { font-size: 13px; line-height: 1.45; color: var(--text-secondary); margin: 0 0 13px; }
  .cd-trial .ce-btn { width: 100%; height: 42px; font-size: 14px; }

  /* --- Main column (editorial type system) --- */
  .cd-main { min-width: 0; }
  .cd-article > * { max-width: 78ch; }
  .cd-article p { font-family: ${SERIF}; font-size: 18.5px; line-height: 1.72; color: var(--grey-700); margin: 0 0 24px; }
  .cd-article h2 { font-family: ${SERIF}; font-weight: 600; font-size: 26px; line-height: 1.2; letter-spacing: -0.015em; color: var(--text-primary); margin: 40px 0 16px; scroll-margin-top: 24px; }
  .cd-article a { color: var(--text-link); text-decoration: underline; text-underline-offset: 2px; }
  .cd-article a:hover { color: var(--brand-hover, var(--brand)); }
  .cd-article strong { font-weight: 700; color: var(--text-primary); }
  .cd-lead { font-size: 20px !important; color: var(--text-primary) !important; font-weight: 500; }
  .cd-pull { max-width: 78ch; margin: 34px 0; padding: 4px 0 4px 26px; border-left: 3px solid var(--ce-navy); }
  .cd-pull p { font-family: ${SERIF}; font-weight: 500; font-size: 24px; line-height: 1.36; letter-spacing: -0.015em; color: var(--text-primary); margin: 0; }

  /* Chart breakout: wider than the reading measure */
  .cd-figure { max-width: none; margin: 34px 0; }
  .cd-figure .cd-fig-cap { font-family: ${NS}; font-weight: 700; font-size: 13px; letter-spacing: 0.02em; color: var(--text-primary); margin: 0 0 10px; }
  .cd-fig-frame { border: 1px solid var(--border-default); border-radius: var(--radius-md,6px); background: var(--surface-card); padding: 20px 22px; }
  .cd-fig-chart { width: 100%; height: 260px; }
  .cd-fig-src { font-family: ${NS}; font-size: 12px; color: var(--text-muted); margin: 10px 0 0; }

  /* --- Article footer: topic tags --- */
  .cd-tags { display: flex; flex-wrap: wrap; gap: 8px; margin: 40px 0 0; max-width: none; }
  .cd-tag { font-size: 13px; font-weight: 600; color: var(--text-secondary); background: var(--surface-subtle); border: 1px solid var(--border-subtle); border-radius: 999px; padding: 5px 13px; text-decoration: none; }
  .cd-tag:hover { border-color: var(--brand); color: var(--brand); }
  .cd-rule { border: 0; border-top: 1px solid var(--border-subtle); margin: 30px 0; max-width: none; }

  /* --- Author card --- */
  .cd-author { display: flex; gap: 18px; align-items: flex-start; max-width: none; }
  .cd-author-av { width: 60px; height: 60px; border-radius: 50%; overflow: hidden; background: var(--ce-blue); color: #fff; display: inline-flex; align-items: center; justify-content: center; font-weight: 700; font-size: 20px; flex: 0 0 auto; }
  .cd-author-name { font-family: ${SERIF}; font-weight: 600; font-size: 19px; letter-spacing: -0.01em; color: var(--text-primary); margin: 0; }
  .cd-author-role { font-size: 13.5px; color: var(--text-muted); margin: 2px 0 8px; }
  .cd-author-bio { font-size: 14.5px; line-height: 1.55; color: var(--text-secondary); margin: 0 0 8px; max-width: 60ch; }
  .cd-author-link { font-size: 14px; font-weight: 700; color: var(--brand); text-decoration: none; display: inline-flex; align-items: center; gap: 5px; }
  .cd-author-link:hover { text-decoration: underline; }

  /* --- Conversion block (centre of gravity) --- */
  .cd-conv { max-width: none; margin: 44px 0 0; background: var(--brand-subtle); border: 1px solid #cfd9f0; border-radius: var(--radius-lg, 8px); padding: 40px 42px; }
  .cd-conv-h { font-family: ${SERIF}; font-weight: 600; font-size: 28px; line-height: 1.16; letter-spacing: -0.02em; color: var(--text-primary); margin: 0 0 14px; max-width: 26ch; }
  .cd-conv-p { font-size: 16px; line-height: 1.6; color: var(--text-secondary); margin: 0 0 24px; max-width: 62ch; }
  .cd-conv .ce-btn { height: 52px; }
  .cd-conv-sub { font-size: 13.5px; color: var(--text-muted); margin: 16px 0 0; }
  .cd-conv-sub a { color: var(--text-secondary); font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }
  .cd-conv-sub a:hover { color: var(--text-link); }

  /* --- Related content --- */
  .cd-related { max-width: none; margin: 50px 0 8px; }
  .cd-related-h { font-family: ${SERIF}; font-weight: 600; font-size: 24px; letter-spacing: -0.015em; color: var(--text-primary); margin: 0 0 20px; }
  .cd-related-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }

  /* content card (from the insights component; styles re-declared here) */
  .cd-related .ins-card { display: flex; flex-direction: column; background: var(--surface-card); border: 1px solid var(--border-subtle); border-radius: var(--radius-lg); overflow: hidden; text-decoration: none; color: inherit; transition: border-color 150ms cubic-bezier(0.2,0,0,1), box-shadow 150ms cubic-bezier(0.2,0,0,1), transform 150ms cubic-bezier(0.2,0,0,1); }
  .cd-related .ins-card:hover { border-color: var(--border-default); box-shadow: var(--shadow-sm); transform: translateY(-2px); }
  .cd-related .ins-thumb { position: relative; aspect-ratio: 16/9; background: #EDF1FB; overflow: hidden; }
  .cd-related .ins-thumb svg { width: 100%; height: 100%; }
  .cd-related .ins-badge-type { font-family: ${NS}; font-weight: 700; font-size: 10.5px; letter-spacing: 0.08em; text-transform: uppercase; color: #fff; background: #1d233f; padding: 4px 9px; border-radius: 4px; }
  .cd-related .ins-badge-over { position: absolute; top: 12px; left: 12px; }
  .cd-related .ins-card-body { padding: 16px 18px 18px; display: flex; flex-direction: column; flex: 1; }
  .cd-related .ins-eyebrow { font-family: ${NS}; font-weight: 700; font-size: 11px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--brand); margin-bottom: 9px; }
  .cd-related .ins-title { font-family: ${SERIF}; font-weight: 600; font-size: 19px; line-height: 1.24; letter-spacing: -0.01em; color: var(--text-primary); margin: 0; text-decoration: none; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .cd-related .ins-standfirst { font-family: ${NS}; font-size: 14px; line-height: 1.5; color: var(--text-secondary); text-decoration: none; margin: 9px 0 0; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
  .cd-related .ins-meta { display: flex; align-items: center; gap: 8px; margin-top: 14px; padding-top: 13px; border-top: 1px solid var(--border-subtle); font-family: ${NS}; font-size: 12.5px; color: var(--text-muted); }
  .cd-related .ins-dot { opacity: 0.6; }

  /* Slim sticky mobile action bar (hidden on desktop) */
  .cd-mobbar { display: none; }

  /* --- Mobile (container query) --- */
  @container (max-width: 820px) {
    .cd-h1 { font-size: 30px; }
    .cd-hero-in { padding: 30px 22px 28px; }
    .cd-wrap { padding: 0 22px; }
    .cd-body { grid-template-columns: 1fr; gap: 0; padding: 26px 0 20px; }
    .cd-rail { position: static; gap: 0; margin-bottom: 22px; }
    .cd-rail-desktoponly { display: none; }
    .cd-rail-mobtoggle { display: block; border: 1px solid var(--border-subtle); border-radius: var(--radius-md,6px); background: var(--surface-card); }
    .cd-rail-mobtoggle summary { list-style: none; cursor: pointer; font-weight: 700; font-size: 13.5px; color: var(--text-primary); padding: 13px 16px; display: flex; align-items: center; justify-content: space-between; }
    .cd-rail-mobtoggle summary::-webkit-details-marker { display: none; }
    .cd-rail-mobtoggle[open] summary { border-bottom: 1px solid var(--border-subtle); }
    .cd-rail-mobtoggle .cd-jump { border-left: 0; padding: 8px 16px 14px; }
    .cd-rail-mobtoggle .cd-jump a { border-left: 0; padding: 6px 0; }
    .cd-mobfacts { margin-top: 16px; }
    .cd-article > *, .cd-pull, .cd-conv-p { max-width: none; }
    .cd-conv { padding: 28px 22px; }
    .cd-conv-h { font-size: 23px; }
    .cd-related-grid { grid-template-columns: 1fr; }
    .cd-fig-frame { overflow-x: auto; }
    .cd-fig-chart { min-width: 520px; }
    .cd-mobbar { display: flex; position: sticky; bottom: 0; z-index: 5; gap: 0; background: var(--surface-card); border-top: 1px solid var(--border-subtle); box-shadow: 0 -4px 16px rgba(20,30,60,0.06); }
    .cd-mobbar button { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 8px; border: 0; background: 0; font-family: ${NS}; font-size: 14px; font-weight: 600; color: var(--text-secondary); padding: 14px; cursor: pointer; }
    .cd-mobbar button + button { border-left: 1px solid var(--border-subtle); }
  }
  `;
  const el = document.createElement("style");
  el.setAttribute("data-ce", "content-detail");
  el.textContent = css;
  document.head.appendChild(el);
}

/* ---- Variant configuration ---- */
const AUTHOR = { initials: "NS", name: "Neil Shearing", role: "Group Chief Economist",
  bio: "Neil leads the global economics team and sets the firm's house view across the economies we cover. He writes the Chief Economist's Note on the questions moving markets." };

const VARIANTS = {
  note: {
    eyebrow: "The Chief Economist's Note",
    h1: "Warsh shows why quality trumps quantity in central bank communications",
    standfirst: "Clearer guidance from fewer voices would do more for markets than the current volume of speeches and forecasts.",
    access: "Free", metaBits: ["12 June 2026", "12 min read", "3 charts"],
    factPanel: null,
    conv: {
      h: "The analysis behind this note",
      p: "This note is free to read. The forecasts, country coverage and data it draws on sit inside the platform. A seven-day trial gives you ten publications of your choosing, no card required.",
      primary: "Start free trial", subLead: "Not ready?", subLink: "Register for 3 free credits",
    },
  },
  case: {
    eyebrow: "Case study",
    h1: "How a global asset manager retired three external feeds",
    standfirst: "Anchoring the house macro view on Capital Economics forecasts across 40 markets cut cost and cleared up the desk's read on rates.",
    access: "Free", metaBits: ["April 2026", "8 min read"],
    factPanel: [["Sector", "Asset management"], ["Region", "Global"], ["Service used", "CE Advance"]],
    conv: {
      h: "See what this could look like for your team",
      p: "Every engagement starts with the questions your desk needs answered. Talk to our team about coverage, data access and how other firms in your sector work with us.",
      primary: "Talk to our team", subLead: "Prefer to explore first?", subLink: "Start free trial",
    },
  },
  event: {
    eyebrow: "Event",
    h1: "Mid-year outlook: where rates, growth and the dollar go next",
    standfirst: "Our senior economists take stock at the half-year and answer your questions live on the calls that matter most.",
    access: "Free", metaBits: ["Upcoming", "60 min", "Live online"],
    factPanel: [["Date", "3 July 2026"], ["Time", "15:00"], ["Timezone", "BST (London)"], ["Format", "Live online"]],
    speakers: [
      { photo: "assets/people/Neil-Shearing.jpeg", name: "Neil Shearing", role: "Group Chief Economist" },
      { photo: "assets/people/Jennifer-McKeown.jpg", name: "Jennifer McKeown", role: "Chief Global Economist" },
      { photo: "assets/people/Paul-Ashworth.png", name: "Paul Ashworth", role: "Chief North America Economist" },
    ],
    conv: {
      h: "Save your place on the call",
      p: "Places are limited and the session includes live Q&A with the economists. Register to attend, and the recording will be sent to you afterwards.",
      primary: "Register to attend", subLead: "Not a client yet?", subLink: "Start free trial",
    },
  },
};

const SECTIONS = [
  { id: "overview", label: "Overview" },
  { id: "quality", label: "Why quality beats quantity" },
  { id: "markets", label: "What it means for markets" },
];

const RELATED = [
  { id: "r1", type: "Insight", topic: "Monetary policy", region: "US", title: "The Fed's next move: one more cut, then a long pause", standfirst: "Why the market's easing path still looks too aggressive.", date: "2026-06-09", read: 6, access: "Free", chart: "line" },
  { id: "r2", type: "Publication", topic: "Rates", region: "Global", title: "Global rates outlook: the descent from the peak", standfirst: "Our full forecast set across the economies we cover.", date: "2026-06-04", read: 18, access: "1 credit", chart: "bars" },
  { id: "r3", type: "Insight", topic: "FX", region: "Global", title: "What slower cuts mean for the dollar", standfirst: "Rate differentials keep the dollar firmer for longer.", date: "2026-05-28", read: 9, access: "Subscribers", chart: "scatter" },
];

/* ---- Article body (worked example; shared across variants for the demo) ---- */
function ArticleBody() {
  return (
    <div className="cd-article">
      <section id="overview">
        <p className="cd-lead">
          Kevin Warsh's recent intervention on central bank communication lands on a real problem. Policymakers
          now say a great deal, across speeches, minutes, forecasts and press conferences, and the sheer volume
          has started to work against the clarity it was meant to create.
        </p>
        <p>
          The case for transparency was never in doubt. Markets price the path of policy, and a central bank
          that explains its reasoning helps that pricing settle closer to where the data point. The question
          Warsh raises is different. It is whether more communication, from more officials, on more occasions,
          actually improves the signal, or whether it simply adds noise that traders then have to filter out.
        </p>
        <div className="cd-figure">
          <p className="cd-fig-cap">Figure 1: Public communications per meeting cycle have roughly doubled since 2010</p>
          <div className="cd-fig-frame">
            <MiniChart kind="bars" seed={4} style={{ display: "block", width: "100%", height: "100%" }} />
          </div>
          <p className="cd-fig-src">Source: Capital Economics, central bank calendars. Speeches, testimony and published minutes, indexed.</p>
        </div>
      </section>

      <section id="quality">
        <h2>Why quality beats quantity</h2>
        <p>
          The evidence from the past two cycles is that markets respond to a small number of high-signal events
          and largely discount the rest. A well-drafted statement, a clear set of projections and one considered
          press conference move pricing. The tenth speech of the month rarely does, and when officials disagree
          in public the effect can be to widen the range of outcomes the market has to hold.
        </p>
        <div className="cd-pull">
          <p>Fewer voices, saying more considered things less often, would raise the signal without losing the transparency.</p>
        </div>
        <p>
          That is the trade Warsh is pointing to. It is not a call for secrecy. It is a call to treat
          communication as a scarce resource, spent where it does the most work, rather than a volume target to
          be met. For the economies we cover, the banks that already operate this way tend to see calmer
          reactions to their decisions, because the market has fewer conflicting inputs to reconcile.
        </p>
      </section>

      <section id="markets">
        <h2>What it means for markets</h2>
        <p>
          For traders and portfolio managers the practical point is about where to spend attention. The events
          worth clearing the desk for are the statement, the projections and the chair's press conference. The
          rest is context, useful for colour but rarely decisive for pricing.
        </p>
        <div className="cd-figure">
          <p className="cd-fig-cap">Figure 2: Market reaction concentrates on decision days, not the speeches around them</p>
          <div className="cd-fig-frame">
            <MiniChart kind="line" seed={7} style={{ display: "block", width: "100%", height: "100%" }} />
          </div>
          <p className="cd-fig-src">Source: Capital Economics. Absolute two-year yield move on the day, by event type.</p>
        </div>
        <p>
          Our read is that the direction of travel favours fewer, clearer communications, and that the banks
          which get there first will find their guidance carries further. We set out how this shapes our
          rate calls across the major economies in the accompanying forecast set.
        </p>
      </section>
    </div>
  );
}

/* ---- Rail ---- */
function Rail({ variant, active, staticShow }) {
  const cfg = VARIANTS[variant];
  const jump = (
    <>
      <p className="cd-onthis-h">On this page</p>
      <ul className="cd-jump">
        {SECTIONS.map((s) => (
          <li key={s.id}><a href={"#" + s.id} className={active === s.id ? "on" : ""}>{s.label}</a></li>
        ))}
      </ul>
    </>
  );
  const facts = cfg.factPanel && (
    <div className="cd-factpanel">
      <dl>
        {cfg.factPanel.map(([k, v]) => (
          <div className="cd-factrow" key={k}><dt>{k}</dt><dd>{v}</dd></div>
        ))}
      </dl>
    </div>
  );
  const speakers = cfg.speakers && (
    <div className="cd-speakers">
      <p className="cd-panel-h">Speakers</p>
      <ul className="cd-speaker-list">
        {cfg.speakers.map((s) => (
          <li className="cd-speaker" key={s.name}>
            <img className="cd-speaker-av" src={s.photo} alt={s.name} />
            <div><p className="cd-speaker-name">{s.name}</p><p className="cd-speaker-role">{s.role}</p></div>
          </li>
        ))}
      </ul>
    </div>
  );
  return (
    <aside className="cd-rail">
      {/* Desktop: jump links */}
      <div className="cd-rail-desktoponly">{jump}</div>
      {/* Mobile: collapsible On this page */}
      <details className="cd-rail-mobtoggle">
        <summary>On this page <CdIcon name="arrow-right" size={16} style={{ transform: "rotate(90deg)" }} /></summary>
        <ul className="cd-jump">
          {SECTIONS.map((s) => <li key={s.id}><a href={"#" + s.id}>{s.label}</a></li>)}
        </ul>
      </details>

      <div className="cd-railactions cd-rail-desktoponly">
        <a href="#" className="cd-railact"><CdIcon name="download" size={17} />Download PDF</a>
        <button className="cd-railact"><CdIcon name="share" size={17} />Share</button>
      </div>

      {facts && <div className="cd-rail-desktoponly">{facts}</div>}
      {facts && <div className="cd-mobfacts" style={{ display: "none" }} />}
      {speakers && <div className="cd-rail-desktoponly">{speakers}</div>}

      <div className={"cd-trial cd-rail-desktoponly" + (staticShow ? " show" : "")} data-cd-trial>
        <span className="cd-trial-eyebrow"><CdIcon name="lock" size={11} stroke={2.2} />Free trial</span>
        <p className="cd-trial-txt">Read this and nine more, free for seven days.</p>
        <Button variant="primary" size="sm">Start free trial</Button>
      </div>
    </aside>
  );
}

/* ---- Conversion block ---- */
function ConversionBlock({ variant }) {
  const c = VARIANTS[variant].conv;
  return (
    <section className="cd-conv" id="conversion">
      <h2 className="cd-conv-h">{c.h}</h2>
      <p className="cd-conv-p">{c.p}</p>
      <Button variant="primary" size="lg" iconEnd={<CdIcon name="arrow-right" size={18} />}>{c.primary}</Button>
      <p className="cd-conv-sub">{c.subLead} <a href="#">{c.subLink}</a></p>
    </section>
  );
}

/* ---- Author card ---- */
function AuthorCard() {
  return (
    <div className="cd-author">
      <span className="cd-author-av"><img src="assets/people/Neil-Shearing.jpeg" alt="Neil Shearing" style={{ width: "60px", height: "60px", borderRadius: "50%", objectFit: "cover", display: "block" }} /></span>
      <div>
        <p className="cd-author-name">{AUTHOR.name}</p>
        <p className="cd-author-role">{AUTHOR.role}</p>
        <p className="cd-author-bio">{AUTHOR.bio}</p>
        <a href="#" className="cd-author-link">More from {AUTHOR.name}<CdIcon name="arrow-right" size={15} /></a>
      </div>
    </div>
  );
}

/* ================================================================
   ContentDetail — the full template. `chrome` wraps it in the site
   header/footer (live page); omit for canvas artboards.
================================================================ */
function ContentDetail({ variant = "note", staticTrial = false }) {
  const cfg = VARIANTS[variant];
  const [active, setActive] = React.useState(SECTIONS[0].id);
  const mainRef = React.useRef(null);

  React.useEffect(() => {
    const root = mainRef.current; if (!root) return;
    if (staticTrial) { const t = root.querySelector("[data-cd-trial]"); if (t) t.classList.add("show"); return; }
    // Active jump link
    const obs = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) setActive(e.target.id); });
    }, { rootMargin: "-20% 0px -70% 0px", threshold: 0 });
    root.querySelectorAll("section[id]").forEach((s) => obs.observe(s));
    // Trial card fade-in past ~25%
    const trial = root.querySelector("[data-cd-trial]");
    const article = root.querySelector(".cd-article");
    const onScroll = () => {
      if (!trial || !article) return;
      const r = article.getBoundingClientRect();
      const passed = (window.innerHeight * 0.5 - r.top) / r.height;
      trial.classList.toggle("show", passed > 0.25);
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => { obs.disconnect(); window.removeEventListener("scroll", onScroll); };
  }, [variant]);

  return (
    <div className="cd-root" ref={mainRef}>
      <div className="cd-wrap">
        <nav className="cd-crumb" aria-label="Breadcrumb">
          <a href="#">Insights</a>
          <span className="cd-cr-sep" aria-hidden="true">/</span>
          <span className="cd-cr-here">{cfg.eyebrow}</span>
        </nav>
      </div>

      <header className="cd-hero">
        <div className="cd-hero-in">
          <p className="cd-eyebrow">{cfg.eyebrow}</p>
          <h1 className="cd-h1">{cfg.h1}</h1>
          <p className="cd-standfirst">{cfg.standfirst}</p>
          <div className="cd-metarow">
            <span className="cd-avatar"><img src="assets/people/Neil-Shearing.jpeg" alt="Neil Shearing" style={{ width: "38px", height: "38px", borderRadius: "50%", objectFit: "cover", display: "block" }} /></span>
            <span className="cd-byline">{AUTHOR.name}, {AUTHOR.role}</span>
            {cfg.metaBits.map((b, i) => (
              <React.Fragment key={b}><span className="cd-meta-sep" aria-hidden="true" />{" "}<span>{b}</span></React.Fragment>
            ))}
            <span className="cd-meta-sep" aria-hidden="true" />
            <AccessBadge level={cfg.access} onNavy />
          </div>
        </div>
      </header>

      <div className="cd-wrap">
        <div className="cd-body">
          <Rail variant={variant} active={active} staticShow={staticTrial} />
          <main className="cd-main">
            <ArticleBody />
            <div className="cd-tags">
              {["Monetary policy", "Central banks", "US", "Rates", "Fed"].map((t) => (
                <a key={t} href="#" className="cd-tag">{t}</a>
              ))}
            </div>
            <hr className="cd-rule" />
            <AuthorCard />
            <ConversionBlock variant={variant} />
            <section className="cd-related">
              <h2 className="cd-related-h">Related content</h2>
              <div className="cd-related-grid">
                {RELATED.map((it) => <ArticleCard key={it.id} it={it} />)}
              </div>
            </section>
          </main>
        </div>
      </div>

      {/* Slim sticky mobile action bar */}
      <div className="cd-mobbar">
        <button><CdIcon name="download" size={17} />Download</button>
        <button><CdIcon name="share" size={17} />Share</button>
      </div>
    </div>
  );
}

Object.assign(window, { ContentDetail, injectCdCSS, VARIANTS: window.VARIANTS_CD = VARIANTS });

/* ---- Standalone canvas: three variants (rail + conversion focus) ---- */
function VariantCard({ variant, label }) {
  return (
    <div style={{ background: "var(--surface-page)" }}>
      <ContentDetail variant={variant} staticTrial />
    </div>
  );
}

function CanvasApp() {
  injectCdCSS();
  const { DesignCanvas, DCSection, DCArtboard } = window;
  return (
    <DesignCanvas>
      <DCSection id="variants" title="Content detail template — three variants" subtitle="One shell, reused. The eyebrow, rail fact panel and conversion block change by content type; everything else holds.">
        <DCArtboard id="note" label="Chief Economist's Note" width={1040} height={2760}>
          <VariantCard variant="note" />
        </DCArtboard>
        <DCArtboard id="case" label="Case study (rail fact panel · Talk to our team)" width={1040} height={2760}>
          <VariantCard variant="case" />
        </DCArtboard>
        <DCArtboard id="event" label="Event, upcoming (rail date panel · Register to attend)" width={1040} height={2760}>
          <VariantCard variant="event" />
        </DCArtboard>
      </DCSection>
      <DCSection id="mobile" title="375px mobile" subtitle="Rail collapses: jump links become a top control, download and share a sticky bottom bar, trial card dropped, charts scroll.">
        <DCArtboard id="m-note" label="Chief Economist's Note — mobile" width={375} height={2680}>
          <VariantCard variant="note" />
        </DCArtboard>
      </DCSection>
    </DesignCanvas>
  );
}

if (window.__CD_MODE === "canvas") {
  ReactDOM.createRoot(document.getElementById("root")).render(<CanvasApp />);
}
