// Pathway pages
const { useState: useStateP, useMemo: useMemoP, useEffect: useEffectP } = React;

// ── Overview (two variants) ────────────────────────────────────────
function OverviewPage({ ctx, variant }) {
  const { range, channelsOn, scenario } = ctx;
  const totals = useMemoP(() => CoverStory.buildTotals(range, channelsOn), [range, channelsOn]);
  const series = useMemoP(() => CoverStory.buildSeries(range, channelsOn), [range, channelsOn]);
  const channelTotals = useMemoP(() => CoverStory.buildChannelTotals(range).filter(c => channelsOn[c.id]), [range, channelsOn]);
  const d = CoverStory.DELTAS[range];
  const factor = scenario === '+10% spend' ? 1.08 : scenario === 'Forecast' ? 1.04 : 1;
  const rev = totals.revenue * factor;
  const spend = totals.spend * (scenario === '+10% spend' ? 1.10 : 1);
  const roas = spend ? rev / spend : 0;

  if (variant === 'B') return <OverviewB ctx={ctx} totals={totals} series={series} channelTotals={channelTotals} d={d} rev={rev} spend={spend} roas={roas} />;
  return <OverviewA ctx={ctx} totals={totals} series={series} channelTotals={channelTotals} d={d} rev={rev} spend={spend} roas={roas} />;
}

function OverviewA({ ctx, totals, series, channelTotals, d, rev, spend, roas }) {
  const rm = CoverStory.RESERVATION_METRICS[ctx.range] || CoverStory.RESERVATION_METRICS['30d'] || { avgPartySize: 0, spendPerHead: 0, leadTime: 0, showRate: 0, returningPct: 0, utilisation: 0 };
  return (
    <div>
      {/* Revenue performance */}
      <div style={{ fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--pw-fg-subtle)', marginBottom: 10, display: 'flex', alignItems: 'center', gap: 8 }}>
        <span style={{ width: 18, height: 1, background: 'var(--pw-fg-subtle)' }} /> Revenue performance
      </div>
      <div className="pw-grid pw-grid-3" style={{ marginBottom: 20 }}>
        <Kpi label="Pipeline revenue" value={CoverStory.fmtMoneyExact(rev)} delta={d.revenue} sub={ctx.rangeLabel}
          sparkline={<Sparkline series={series} field="revenue" color="var(--pw-accent)" />} />
        <Kpi label="ASPH" value={CoverStory.fmtMoneyExact(totals.covers > 0 ? rev / totals.covers : 0)} delta={d.aov} sub="Average spend per head" />
        <Kpi label="Avg reservation value" value={CoverStory.fmtMoneyExact(totals.bookings > 0 ? rev / totals.bookings : 0)} delta={d.aov} sub="Per booking" />
      </div>

      {/* Reservation performance */}
      <div style={{ fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--pw-fg-subtle)', marginBottom: 10, display: 'flex', alignItems: 'center', gap: 8 }}>
        <span style={{ width: 18, height: 1, background: 'var(--pw-fg-subtle)' }} /> Reservation performance
      </div>
      <div className="pw-grid pw-grid-4" style={{ marginBottom: 20 }}>
        <Kpi label="Attributed bookings" value={CoverStory.fmtInt(totals.bookings)} delta={d.bookings} sub={ctx.rangeLabel}
          sparkline={<Sparkline series={series} field="covers" color="var(--pw-chart-3)" />} />
        <Kpi label="Covers" value={CoverStory.fmtInt(totals.covers)} delta={d.covers} sub="Across attributed bookings" />
        <Kpi label="Avg party size" value={rm.avgPartySize.toFixed(1)} delta={d.partySize} sub="Guests per booking" />
        <Kpi label="Returning guests" value={rm.returningPct + '%'} delta={d.returning} sub="Share of attributed bookings" />
      </div>

      <div className="pw-grid pw-grid-main" style={{ marginBottom: 16 }}>
        <Card title="Revenue & bookings by channel" sub="RAM attribution — daily stacked" right={<div style={{ display: 'flex', gap: 6 }}>
          {CoverStory.CHANNELS.filter(c => ctx.channelsOn[c.id]).map(c => (
            <span key={c.id} style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 11, color: 'var(--pw-fg-muted)' }}>
              <span style={{ width: 8, height: 8, background: c.color }} />{c.name}
            </span>
          ))}
        </div>}>
          <StackedArea series={series} channelsOn={ctx.channelsOn} height={460} />
        </Card>
        <Card title="Channel mix" sub="Share of pipeline revenue">
          <div style={{ display: 'flex', alignItems: 'center', gap: 16, marginBottom: 14 }}>
            <Donut items={channelTotals.map(c => ({ ...c, value: c.revenue }))} total={channelTotals.reduce((s,c) => s + c.revenue, 0)} />
            <div>
              <div style={{ fontSize: 32, fontWeight: 500, letterSpacing: '-0.02em', lineHeight: 1 }}>{CoverStory.fmtMoneyExact(rev)}</div>
              <div style={{ fontSize: 12, color: 'var(--pw-fg-muted)', marginTop: 4 }}>{ctx.rangeLabel}</div>
            </div>
          </div>
          <BarList items={channelTotals.map(c => ({ ...c, value: c.revenue }))} />
        </Card>
      </div>

      <div className="pw-grid" style={{ marginBottom: 16 }}>
        <Card title="Location performance" sub="By pipeline revenue" right={<button className="pw-btn pw-btn-ghost" onClick={() => ctx.go('locations')}>View all <Icon.arrowRight /></button>}>
          <table className="pw-table">
            <thead><tr><th>Location</th><th className="num">Bookings</th><th className="num">Revenue</th><th className="num">Trend</th></tr></thead>
            <tbody>
              {CoverStory.LOCATIONS.slice(0, 6).map(v => (
                <tr key={v.id} className="clickable" onClick={() => ctx.go('locations')}>
                  <td style={{ fontWeight: 500 }}>{v.name}</td>
                  <td className="num">{CoverStory.fmtInt(v.bookings)}</td>
                  <td className="num">{CoverStory.fmtMoney(v.revenue)}</td>
                  <td className="num"><Delta value={v.trend} /></td>
                </tr>
              ))}
            </tbody>
          </table>
        </Card>
      </div>

      <div className="pw-grid" style={{ marginBottom: 16 }}>
        <Card title="Bookings pattern" sub="Day-of-week distribution — Revenue vs Covers">
          <div style={{ display: 'flex', alignItems: 'flex-end', gap: 10, height: 200, padding: '8px 4px 0' }}>
            {CoverStory.BOOKINGS_BY_DOW.map((day, i) => {
              const maxDow = Math.max(...CoverStory.BOOKINGS_BY_DOW.map(x => x.bookings));
              const revH = (day.bookings / maxDow) * 100;
              const covH = revH * (0.82 + (i % 3) * 0.04);
              return (
                <div key={day.day} style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', height: '100%' }}>
                  <div style={{ flex: 1, width: '100%', display: 'flex', gap: 3, alignItems: 'flex-end' }}>
                    <div style={{ flex: 1, height: revH + '%', background: 'var(--pw-accent)' }} title={`Revenue index ${day.day}`} />
                    <div style={{ flex: 1, height: covH + '%', background: 'var(--pw-chart-3)', opacity: 0.7 }} title={`Covers index ${day.day}`} />
                  </div>
                  <div style={{ fontSize: 11, color: 'var(--pw-fg-muted)', marginTop: 8 }}>{day.day}</div>
                </div>
              );
            })}
          </div>
          <div style={{ display: 'flex', gap: 16, marginTop: 12, fontSize: 11, color: 'var(--pw-fg-muted)' }}>
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}><span style={{ width: 10, height: 10, background: 'var(--pw-accent)' }} /> Revenue</span>
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}><span style={{ width: 10, height: 10, background: 'var(--pw-chart-3)', opacity: 0.7 }} /> Covers</span>
          </div>
        </Card>
      </div>
    </div>
  );
}

// Variant B: hero KPI + ram strip
function OverviewB({ ctx, totals, series, channelTotals, d, rev, spend, roas }) {
  const rmB = CoverStory.RESERVATION_METRICS[ctx.range] || CoverStory.RESERVATION_METRICS['30d'] || { avgPartySize: 0, spendPerHead: 0, leadTime: 0, showRate: 0, returningPct: 0, utilisation: 0 };
  return _OverviewB({ ctx, totals, series, channelTotals, d, rev, spend, roas, rmB });
}
function _OverviewB({ ctx, totals, series, channelTotals, d, rev, spend, roas, rmB }) {
  return (
    <div>
      <div style={{ background: 'var(--pw-accent)', color: 'var(--pw-accent-fg)', padding: '32px 36px', marginBottom: 16 }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 48 }}>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', opacity: 0.7, marginBottom: 12 }}>
              <Sparkle size="10" /> Pipeline revenue — {ctx.rangeLabel}
            </div>
            <div style={{ fontFamily: "'Clash Display', 'Clash Grotesk', sans-serif", fontSize: 88, fontWeight: 500, lineHeight: 0.95, letterSpacing: '-0.03em' }}>
              {CoverStory.fmtMoneyExact(rev)}
            </div>
            <div style={{ display: 'flex', gap: 24, marginTop: 18, fontSize: 13, flexWrap: 'wrap' }}>
              <div><span style={{ opacity: 0.7 }}>Δ vs prior</span> <span style={{ fontWeight: 500, marginLeft: 8 }}>+{d.revenue.toFixed(1)}%</span></div>
              <div><span style={{ opacity: 0.7 }}>Bookings</span> <span style={{ fontWeight: 500, marginLeft: 8 }}>{CoverStory.fmtInt(totals.bookings)}</span></div>
              <div><span style={{ opacity: 0.7 }}>Covers</span> <span style={{ fontWeight: 500, marginLeft: 8 }}>{CoverStory.fmtInt(totals.covers)}</span></div>
              <div><span style={{ opacity: 0.7 }}>Party size</span> <span style={{ fontWeight: 500, marginLeft: 8 }}>{rmB.avgPartySize.toFixed(1)}</span></div>
              <div><span style={{ opacity: 0.7 }}>Spend/head</span> <span style={{ fontWeight: 500, marginLeft: 8 }}>£{rmB.spendPerHead}</span></div>
              <div><span style={{ opacity: 0.7 }}>ROAS</span> <span style={{ fontWeight: 500, marginLeft: 8 }}>{roas.toFixed(1)}×</span></div>
            </div>
          </div>
          <div style={{ width: 340 }}>
            <Sparkline series={series} field="revenue" color="var(--pw-accent-fg)" fill={false} />
            <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, opacity: 0.7, marginTop: 4, letterSpacing: '0.1em' }}>
              <span>DAY 1</span><span>DAY {Math.round(series[series.length-1].t)+1}</span>
            </div>
          </div>
        </div>
      </div>

      <div className="pw-grid pw-grid-4" style={{ marginBottom: 16 }}>
        <div className="pw-kpi">
          <div className="pw-kpi-label">Attributed bookings</div>
          <div className="pw-kpi-value">{CoverStory.fmtInt(totals.bookings)}</div>
          <div style={{ fontSize: 12, color: 'var(--pw-fg-muted)' }}>+{d.bookings.toFixed(1)}% · {ctx.rangeLabel}</div>
        </div>
        <div className="pw-kpi">
          <div className="pw-kpi-label">Avg party size</div>
          <div className="pw-kpi-value">{rmB.avgPartySize.toFixed(1)}</div>
          <div style={{ fontSize: 12, color: 'var(--pw-fg-muted)' }}>guests / booking · +{d.partySize.toFixed(1)}%</div>
        </div>
        <div className="pw-kpi">
          <div className="pw-kpi-label">Spend per head</div>
          <div className="pw-kpi-value">£{rmB.spendPerHead}</div>
          <div style={{ fontSize: 12, color: 'var(--pw-fg-muted)' }}>+{d.sph.toFixed(1)}% · covers-weighted</div>
        </div>
        <div className="pw-kpi">
          <div className="pw-kpi-label">Show rate · Returning</div>
          <div className="pw-kpi-value">{rmB.showRate}% · {rmB.returningPct}%</div>
          <div style={{ fontSize: 12, color: 'var(--pw-fg-muted)' }}>Utilisation {rmB.utilisation}%</div>
        </div>
      </div>

      <div className="pw-grid pw-grid-3" style={{ marginBottom: 16 }}>
        {channelTotals.slice(0, 6).map(c => (
          <div key={c.id} className="pw-kpi" style={{ cursor: 'pointer' }} onClick={() => ctx.go('channel', { id: c.id })}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ width: 10, height: 10, background: c.color }} />
              <div className="pw-kpi-label" style={{ color: 'var(--pw-fg)' }}>{c.name}</div>
            </div>
            <div className="pw-kpi-value" style={{ fontSize: 30 }}>{CoverStory.fmtMoney(c.revenue)}</div>
            <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12, color: 'var(--pw-fg-muted)' }}>
              <span>{c.roas ? c.roas.toFixed(1) + '× ROAS' : 'Organic'}</span>
              <span>{CoverStory.fmtInt(c.covers)} covers</span>
            </div>
          </div>
        ))}
      </div>

      <Card title="Attribution flow — ad spend to revenue" sub="RAM — revenue attribution modelling"
        right={<button className="pw-btn pw-btn-ghost" onClick={() => ctx.go('ram')}>Open RAM <Icon.arrowRight /></button>}>
        <RamSankey channelTotals={channelTotals} height={340} />
      </Card>
    </div>
  );
}

// ── RAM Attribution (two variants) ─────────────────────────────────
function RamPage({ ctx, variant }) {
  const channelTotals = useMemoP(() => CoverStory.buildChannelTotals(ctx.range).filter(c => ctx.channelsOn[c.id]), [ctx.range, ctx.channelsOn]);
  if (variant === 'B') return <RamB ctx={ctx} channelTotals={channelTotals} />;
  return <RamA ctx={ctx} channelTotals={channelTotals} />;
}

function RamA({ ctx, channelTotals }) {
  const totals = CoverStory.buildTotals(ctx.range, ctx.channelsOn);
  return (
    <div>
      <div className="pw-grid pw-grid-4" style={{ marginBottom: 16 }}>
        <Kpi label="Total spend" value={CoverStory.fmtMoney(totals.spend)} sub={ctx.rangeLabel} />
        <Kpi label="Attributed covers" value={CoverStory.fmtInt(totals.covers)} sub="Across all channels" />
        <Kpi label="Pipeline revenue" value={CoverStory.fmtMoneyExact(totals.revenue)} sub="RAM-closed loop" />
        <Kpi label="Revenue per cover" value={CoverStory.fmtMoneyFull(totals.aov)} sub="Average order value" />
      </div>

      <Card title="Average" sub="Sankey — RAM attribution flow" style={{ marginBottom: 16 }}
        right={<div style={{ fontSize: 11, color: 'var(--pw-fg-subtle)', letterSpacing: '0.1em', textTransform: 'uppercase' }}>
          <Sparkle size="10" /> Hover a flow for detail
        </div>}>
        <RamSankey channelTotals={channelTotals} height={440} />
      </Card>

      <div className="pw-grid pw-grid-2">
        <Card title="Channel attribution table" sub="Deep dive">
          <table className="pw-table">
            <thead><tr><th>Channel</th><th className="num">Spend</th><th className="num">Covers</th><th className="num">Revenue</th><th className="num">ROAS</th><th className="num">Share</th></tr></thead>
            <tbody>
              {channelTotals.map(c => (
                <tr key={c.id} className="clickable" onClick={() => ctx.go('channel', { id: c.id })}>
                  <td><span style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontWeight: 500 }}>
                    <span style={{ width: 10, height: 10, background: c.color }} />{c.name}
                  </span></td>
                  <td className="num">{c.spend > 0 ? CoverStory.fmtMoney(c.spend) : '—'}</td>
                  <td className="num">{CoverStory.fmtInt(c.covers)}</td>
                  <td className="num" style={{ fontWeight: 500 }}>{CoverStory.fmtMoney(c.revenue)}</td>
                  <td className="num">{c.roas ? c.roas.toFixed(1) + '×' : 'N/A'}</td>
                  <td className="num">{(c.share * 100).toFixed(0)}%</td>
                </tr>
              ))}
            </tbody>
          </table>
        </Card>
        <Card title="Attribution methodology" sub="How RAM differs">
          <div style={{ display: 'grid', gap: 14, fontSize: 14, lineHeight: 1.45 }}>
            <div>
              <div style={{ fontWeight: 500, marginBottom: 4 }}>1 · Signal ingestion</div>
              <div style={{ color: 'var(--pw-fg-muted)' }}>Ad platforms, booking system, EPOS, and loyalty feed into Pathway every 15 minutes.</div>
            </div>
            <div>
              <div style={{ fontWeight: 500, marginBottom: 4 }}>2 · Identity stitching</div>
              <div style={{ color: 'var(--pw-fg-muted)' }}>Deterministic + probabilistic joins link click → booking → cover → spend per visit.</div>
            </div>
            <div>
              <div style={{ fontWeight: 500, marginBottom: 4 }}>3 · Incrementality weighting</div>
              <div style={{ color: 'var(--pw-fg-muted)' }}>Geo and time-of-day tests calibrate each channel's true lift — credit is redistributed accordingly.</div>
            </div>
            <div>
              <div style={{ fontWeight: 500, marginBottom: 4 }}>4 · Hospitality outputs</div>
              <div style={{ color: 'var(--pw-fg-muted)' }}>Covers, revenue-per-cover, and £ per booking — not clicks.</div>
            </div>
          </div>
        </Card>
      </div>
    </div>
  );
}

// Variant B: matrix comparison view
function RamB({ ctx, channelTotals }) {
  return (
    <div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 16, marginBottom: 16 }}>
        <div className="pw-card" style={{ background: 'var(--pw-accent)', color: 'var(--pw-accent-fg)', borderColor: 'var(--pw-accent)' }}>
          <div style={{ fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', opacity: 0.7, marginBottom: 12 }}>Last-click attribution</div>
          <div style={{ fontSize: 44, fontWeight: 500, letterSpacing: '-0.02em', lineHeight: 1 }}>{CoverStory.fmtMoney(channelTotals.reduce((s, c) => s + c.revenue, 0) * 0.78)}</div>
          <div style={{ fontSize: 13, opacity: 0.7, marginTop: 8 }}>Under-reports by 22% vs RAM</div>
        </div>
        <div className="pw-card">
          <div className="pw-card-sub">Platform-reported</div>
          <div style={{ fontSize: 44, fontWeight: 500, letterSpacing: '-0.02em', lineHeight: 1, marginTop: 8 }}>{CoverStory.fmtMoney(channelTotals.reduce((s, c) => s + c.revenue, 0) * 1.34)}</div>
          <div style={{ fontSize: 13, color: 'var(--pw-fg-muted)', marginTop: 8 }}>Over-reports by 34% (double-counted)</div>
        </div>
        <div className="pw-card" style={{ borderWidth: 2, borderColor: 'var(--pw-fg)' }}>
          <div style={{ fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--pw-fg-subtle)', marginBottom: 12 }}>
            <Sparkle size="10" /> RAM — what actually happened
          </div>
          <div style={{ fontSize: 44, fontWeight: 500, letterSpacing: '-0.02em', lineHeight: 1 }}>{CoverStory.fmtMoney(channelTotals.reduce((s, c) => s + c.revenue, 0))}</div>
          <div style={{ fontSize: 13, color: 'var(--pw-fg-muted)', marginTop: 8 }}>Incrementality-adjusted, hospitality-native</div>
        </div>
      </div>

      <Card title="Cross-channel assist matrix" sub="Where credit shifts under RAM" style={{ marginBottom: 16 }}>
        <table className="pw-table">
          <thead><tr>
            <th>Channel</th>
            <th className="num">Platform-reported</th>
            <th className="num">RAM-adjusted</th>
            <th className="num">Assisted by</th>
            <th className="num">Δ</th>
          </tr></thead>
          <tbody>
            {channelTotals.map(c => {
              const overClaim = c.id === 'paid_social' ? 0.42 : c.id === 'paid_search' ? 0.28 : c.id === 'influencer' ? 0.38 : c.id === 'affiliate' ? 0.32 : 0.12;
              const platform = c.revenue * (1 + overClaim);
              const ram = c.revenue;
              const delta = ((ram - platform) / platform) * 100;
              const assistors = c.id === 'paid_social' ? 'Paid Search, AEO' :
                                c.id === 'paid_search' ? 'Organic Search, DOOH' :
                                c.id === 'dooh' ? 'Paid Search, Direct' :
                                c.id === 'aeo' ? 'Organic Search, Direct' :
                                c.id === 'organic_social' ? 'Influencer, PR' :
                                c.id === 'email' ? 'Direct, Paid Social' :
                                c.id === 'influencer' ? 'Paid Social, Organic Social' :
                                c.id === 'pr' ? 'Organic Search, Direct' :
                                c.id === 'referral' ? 'Direct, Email' :
                                c.id === 'affiliate' ? 'Paid Search, Direct' :
                                c.id === 'organic_search' ? 'AEO, Direct' :
                                'Paid Search, Direct';
              return (
                <tr key={c.id}>
                  <td><span style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontWeight: 500 }}>
                    <span style={{ width: 10, height: 10, background: c.color }} />{c.name}
                  </span></td>
                  <td className="num">{CoverStory.fmtMoney(platform)}</td>
                  <td className="num" style={{ fontWeight: 500 }}>{CoverStory.fmtMoney(ram)}</td>
                  <td>{assistors}</td>
                  <td className="num"><Delta value={delta} /></td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </Card>

      <Card title="Attribution flow" sub="Sankey">
        <RamSankey channelTotals={channelTotals} height={380} />
      </Card>
    </div>
  );
}

// ── Channels ───────────────────────────────────────────────────────
function ChannelsPage({ ctx }) {
  const channelTotals = useMemoP(() => CoverStory.buildChannelTotals(ctx.range), [ctx.range]);
  const [tab, setTab] = useStateP('all');
  const shown = tab === 'all' ? channelTotals : channelTotals.filter(c => c.id === tab);

  return (
    <div>
      <div className="pw-tabs">
        <button className={'pw-tab' + (tab === 'all' ? ' active' : '')} onClick={() => setTab('all')}>All channels</button>
        {CoverStory.CHANNELS.map(c => (
          <button key={c.id} className={'pw-tab' + (tab === c.id ? ' active' : '')} onClick={() => setTab(c.id)}>{c.name}</button>
        ))}
      </div>

      <div className="pw-grid pw-grid-3" style={{ marginBottom: 16 }}>
        {shown.map(c => (
          <div key={c.id} className="pw-card" style={{ cursor: 'pointer' }} onClick={() => ctx.go('channel', { id: c.id })}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 14 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <span style={{ width: 36, height: 36, background: c.color, display: 'grid', placeItems: 'center', color: 'var(--pw-bg)', fontWeight: 500, fontSize: 16 }}>{c.glyph}</span>
                <div>
                  <div style={{ fontWeight: 500, fontSize: 15 }}>{c.name}</div>
                  <div style={{ fontSize: 11, color: 'var(--pw-fg-subtle)', letterSpacing: '0.1em', textTransform: 'uppercase' }}>{(c.share * 100).toFixed(0)}% of revenue</div>
                </div>
              </div>
              <Icon.arrowRight width="16" height="16" />
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, fontSize: 13 }}>
              <div>
                <div style={{ color: 'var(--pw-fg-subtle)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase' }}>Revenue</div>
                <div style={{ fontWeight: 500, fontSize: 22, letterSpacing: '-0.01em' }}>{CoverStory.fmtMoney(c.revenue)}</div>
              </div>
              <div>
                <div style={{ color: 'var(--pw-fg-subtle)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase' }}>ROAS</div>
                <div style={{ fontWeight: 500, fontSize: 22, letterSpacing: '-0.01em' }}>{c.roas ? c.roas.toFixed(1) + '×' : 'N/A'}</div>
              </div>
              <div>
                <div style={{ color: 'var(--pw-fg-subtle)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase' }}>Spend</div>
                <div style={{ fontWeight: 500, fontSize: 16 }}>{CoverStory.fmtMoney(c.spend)}</div>
              </div>
              <div>
                <div style={{ color: 'var(--pw-fg-subtle)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase' }}>Covers</div>
                <div style={{ fontWeight: 500, fontSize: 16 }}>{CoverStory.fmtInt(c.covers)}</div>
              </div>
            </div>
          </div>
        ))}
      </div>

      <Card title="Channel comparison" sub="Spend vs revenue">
        <BarList items={channelTotals.map(c => ({ ...c, value: c.revenue }))} />
      </Card>
    </div>
  );
}

// ── Channel detail ────────────────────────────────────────────────
function ChannelDetailPage({ ctx }) {
  const ch = CoverStory.CHANNELS.find(c => c.id === ctx.param);
  const totals = useMemoP(() => CoverStory.buildChannelTotals(ctx.range).find(c => c.id === ctx.param), [ctx.range, ctx.param]);
  const series = useMemoP(() => CoverStory.buildSeries(ctx.range, { [ctx.param]: true }), [ctx.range, ctx.param]);
  const channelCampaigns = CoverStory.CAMPAIGNS.filter(c => c.channel === ctx.param);

  return (
    <div>
      <div className="pw-subnav">
        <a onClick={() => ctx.go('channels')}>Channels</a>
        <span className="sep">/</span>
        <span className="cur">{ch.name}</span>
      </div>

      <div className="pw-grid pw-grid-4" style={{ marginBottom: 16 }}>
        <Kpi label="Pipeline revenue" value={CoverStory.fmtMoneyExact(totals.revenue)} sub={ch.name} />
        <Kpi label="Attributed bookings" value={CoverStory.fmtInt(Math.round(totals.covers / 3.2))} sub="RAM-closed loop" />
        <Kpi label="Covers" value={CoverStory.fmtInt(totals.covers)} sub="attributed" />
        <Kpi label="Revenue per cover" value={totals.covers ? CoverStory.fmtMoneyFull(totals.revenue / totals.covers) : '—'} sub="Avg order value" />
      </div>

      <div className="pw-grid pw-grid-4" style={{ marginBottom: 16 }}>
        <Kpi label="Spend" value={CoverStory.fmtMoney(totals.spend)} sub={ctx.rangeLabel} />
        <Kpi label="ROAS" value={totals.roas ? totals.roas.toFixed(1) + '×' : 'N/A'} sub="Channel blended" />
        <Kpi label="Cost per booking" value={totals.spend && totals.covers ? '£' + Math.round(totals.spend / (totals.covers / 3.2)) : '—'} sub="Acquisition cost" />
        <Kpi label="Avg party size" value={(3.2 + (ch.id.charCodeAt(0) % 4) * 0.1).toFixed(1)} sub="Guests per booking" />
      </div>

      <Card title={`${ch.name} · revenue trend`} sub="RAM-attributed" style={{ marginBottom: 16 }}>
        <LineChart series={series} field="revenue" height={240} color={ch.color} />
      </Card>

      <Card title="Campaigns" sub={`In ${ch.name}`} style={{ marginBottom: 16 }}>
        <table className="pw-table">
          <thead><tr><th>Campaign</th><th>Status</th><th className="num">Spend</th><th className="num">Covers</th><th className="num">Revenue</th><th className="num">ROAS</th></tr></thead>
          <tbody>
            {channelCampaigns.map(c => (
              <tr key={c.id} className="clickable" onClick={() => ctx.go('campaign', { id: c.id })}>
                <td style={{ fontWeight: 500 }}>{c.name}</td>
                <td><span className={'pw-badge' + (c.status === 'live' ? ' live' : '')}>{c.status}</span></td>
                <td className="num">{CoverStory.fmtMoney(c.spend30)}</td>
                <td className="num">{CoverStory.fmtInt(c.covers30)}</td>
                <td className="num" style={{ fontWeight: 500 }}>{CoverStory.fmtMoney(c.revenue30)}</td>
                <td className="num">{(c.revenue30 / c.spend30).toFixed(1)}×</td>
              </tr>
            ))}
            {!channelCampaigns.length && (
              <tr><td colSpan="6" style={{ padding: 0 }}>
                <EmptyState
                  title="No campaign breakdown yet"
                  hint="Campaign-level data populates when ad-platform spend is connected."
                />
              </td></tr>
            )}
          </tbody>
        </table>
      </Card>

      <ChannelBookingsTable channelId={ctx.param} channelName={ch.name} onOpenJourney={(b) => ctx.go('bookings', { focusRef: b.id })} />
    </div>
  );
}

// Live bookings table scoped to one channel. Reuses LIVE_BOOKINGS so the
// row shape matches Bookings Activity exactly — same campaign, landing
// page, referrer values, no second source of truth.
function ChannelBookingsTable({ channelId, channelName, onOpenJourney }) {
  const live = (window.CoverStory && window.CoverStory.LIVE_BOOKINGS) || [];
  const rows = live.filter(b => b.channel && b.channel.id === channelId).slice(0, 40);
  return (
    <Card title="Bookings" sub={`Attributed to ${channelName}`}>
      <table className="pw-table">
        <thead>
          <tr>
            <th>Booking ref</th>
            <th>Site</th>
            <th>Booking date</th>
            <th className="num">Covers</th>
            <th>Campaign</th>
            <th>Landing page</th>
            <th>Outcome</th>
          </tr>
        </thead>
        <tbody>
          {rows.map(b => (
            <tr key={b.id} className="clickable" onClick={() => onOpenJourney && onOpenJourney(b)}>
              <td><span className="bk-ref">{b.id}</span></td>
              <td style={{ color: 'var(--pw-fg-muted)' }}>{b.site.name}</td>
              <td className="bk-mono" style={{ color: 'var(--pw-fg-muted)' }}>{fmtDt(b.bookingDate)}</td>
              <td className="num bk-mono">{b.covers}</td>
              <td style={{ color: 'var(--pw-fg-muted)', maxWidth: 180, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} title={b.campaign}>
                {b.campaign && b.campaign !== '—' ? b.campaign : <span style={{ color: 'var(--pw-fg-subtle)' }}>—</span>}
              </td>
              <td style={{ color: 'var(--pw-fg-muted)', maxWidth: 220, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} title={b.landingPage}>
                {b.landingPage ? <span style={{ fontFamily: 'var(--pw-mono, ui-monospace, monospace)', fontSize: 11 }}>{b.landingPage}</span> : <span style={{ color: 'var(--pw-fg-subtle)' }}>—</span>}
              </td>
              <td style={{ color: 'var(--pw-fg-muted)' }}>{b.conversionStatus}</td>
            </tr>
          ))}
          {!rows.length && (
            <tr><td colSpan="7" style={{ padding: 0 }}>
              <EmptyState
                title={`No ${channelName} bookings in this timeframe`}
                hint="Change the topbar timeframe to a wider window to see attributed bookings."
              />
            </td></tr>
          )}
        </tbody>
      </table>
    </Card>
  );
}

// ── Campaigns list + detail ────────────────────────────────────────
function CampaignsPage({ ctx }) {
  const [q, setQ] = useStateP('');
  const [filter, setFilter] = useStateP('all');
  const list = CoverStory.CAMPAIGNS.filter(c => {
    if (filter !== 'all' && c.channel !== filter) return false;
    if (q && !c.name.toLowerCase().includes(q.toLowerCase())) return false;
    return ctx.channelsOn[c.channel];
  });

  return (
    <div>
      <div style={{ display: 'flex', gap: 12, marginBottom: 16, alignItems: 'center' }}>
        <div style={{ position: 'relative', flex: 1 }}>
          <Icon.search width="14" height="14" style={{ position: 'absolute', left: 12, top: '50%', transform: 'translateY(-50%)', color: 'var(--pw-fg-subtle)' }} />
          <input value={q} onChange={e => setQ(e.target.value)} placeholder="Search campaigns"
            style={{ width: '100%', padding: '9px 12px 9px 34px', background: 'var(--pw-surface)', border: '1px solid var(--pw-hair-strong)', color: 'var(--pw-fg)', fontFamily: 'inherit', fontSize: 13 }} />
        </div>
        <div className="pw-toggle">
          <button className={filter === 'all' ? 'on' : ''} onClick={() => setFilter('all')}>All</button>
          {CoverStory.CHANNELS.map(c => <button key={c.id} className={filter === c.id ? 'on' : ''} onClick={() => setFilter(c.id)}>{c.name}</button>)}
        </div>
      </div>

      <Card>
        <table className="pw-table">
          <thead><tr><th>Campaign</th><th>Channel</th><th>Status</th><th className="num">Spend</th><th className="num">Covers</th><th className="num">Revenue</th><th className="num">ROAS</th><th></th></tr></thead>
          <tbody>
            {list.map(c => {
              const ch = CoverStory.CHANNELS.find(x => x.id === c.channel);
              return (
                <tr key={c.id} className="clickable" onClick={() => ctx.go('campaign', { id: c.id })}>
                  <td style={{ fontWeight: 500 }}>{c.name}</td>
                  <td><span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 12 }}>
                    <span style={{ width: 8, height: 8, background: ch.color }} />{ch.name}
                  </span></td>
                  <td><span className={'pw-badge' + (c.status === 'live' ? ' live' : '')}>{c.status}</span></td>
                  <td className="num">{CoverStory.fmtMoney(c.spend30)}</td>
                  <td className="num">{CoverStory.fmtInt(c.covers30)}</td>
                  <td className="num" style={{ fontWeight: 500 }}>{CoverStory.fmtMoney(c.revenue30)}</td>
                  <td className="num">{(c.revenue30 / c.spend30).toFixed(1)}×</td>
                  <td style={{ color: 'var(--pw-fg-subtle)' }}><Icon.arrowRight width="14" height="14" /></td>
                </tr>
              );
            })}
            {!list.length && <tr><td colSpan="8" style={{ textAlign: 'center', padding: 40, color: 'var(--pw-fg-muted)' }}>No campaigns match — adjust filters.</td></tr>}
          </tbody>
        </table>
      </Card>
    </div>
  );
}

function CampaignDetailPage({ ctx }) {
  const c = CoverStory.CAMPAIGNS.find(x => x.id === ctx.param);
  const ch = CoverStory.CHANNELS.find(x => x.id === c.channel);
  const creatives = useMemoP(() => CoverStory.buildCreatives(c.id), [c.id]);
  const series = useMemoP(() => CoverStory.buildSeries(ctx.range, { [c.channel]: true }), [ctx.range, c.channel]);

  return (
    <div>
      <div className="pw-subnav">
        <a onClick={() => ctx.go('campaigns')}>Campaigns</a>
        <span className="sep">/</span>
        <a onClick={() => ctx.go('channel', { id: c.channel })}>{ch.name}</a>
        <span className="sep">/</span>
        <span className="cur">{c.name}</span>
      </div>

      <div className="pw-grid pw-grid-4" style={{ marginBottom: 16 }}>
        <Kpi label="Pipeline revenue" value={CoverStory.fmtMoney(c.revenue30)} sub={c.name} />
        <Kpi label="Attributed bookings" value={CoverStory.fmtInt(Math.round(c.covers30 / 3.2))} sub="Last 30d" />
        <Kpi label="Covers" value={CoverStory.fmtInt(c.covers30)} sub="attributed" />
        <Kpi label="Revenue per cover" value={CoverStory.fmtMoneyFull(c.revenue30 / c.covers30)} sub="Avg order value" />
      </div>

      <div className="pw-grid pw-grid-4" style={{ marginBottom: 16 }}>
        <Kpi label="Spend" value={CoverStory.fmtMoney(c.spend30)} sub="Last 30d" />
        <Kpi label="ROAS" value={(c.revenue30 / c.spend30).toFixed(1) + '×'} sub={c.status} />
        <Kpi label="Cost per booking" value={'£' + Math.round(c.spend30 / (c.covers30 / 3.2))} sub="Acquisition cost" />
        <Kpi label="Avg party size" value={(3.0 + (c.id.charCodeAt(1) % 5) * 0.1).toFixed(1)} sub="Guests per booking" />
      </div>

      <Card title="Revenue trend" sub="RAM-attributed" style={{ marginBottom: 16 }}>
        <LineChart series={series} field="revenue" color={ch.color} />
      </Card>

      <Card title="Creative performance" sub="Ranked by ROAS">
        <table className="pw-table">
          <thead><tr><th>Creative</th><th className="num">Impressions</th><th className="num">CTR</th><th className="num">Covers</th><th className="num">CVR</th><th className="num">Revenue</th><th className="num">ROAS</th></tr></thead>
          <tbody>
            {creatives.sort((a, b) => b.roas - a.roas).map(cr => (
              <tr key={cr.id}>
                <td style={{ fontWeight: 500 }}>{cr.name}</td>
                <td className="num">{CoverStory.fmtInt(cr.impressions)}</td>
                <td className="num">{(cr.ctr * 100).toFixed(2)}%</td>
                <td className="num">{CoverStory.fmtInt(cr.covers)}</td>
                <td className="num">{(cr.cvr * 100).toFixed(1)}%</td>
                <td className="num" style={{ fontWeight: 500 }}>{CoverStory.fmtMoney(cr.revenue)}</td>
                <td className="num">{cr.roas.toFixed(1)}×</td>
              </tr>
            ))}
          </tbody>
        </table>
      </Card>
    </div>
  );
}

// ── Audiences ──────────────────────────────────────────────────────
function AudiencesPage({ ctx }) {
  return (
    <div>
      <div className="pw-grid pw-grid-3" style={{ marginBottom: 16 }}>
        {CoverStory.AUDIENCES.slice(0, 3).map(a => (
          <Card key={a.id} sub={`${CoverStory.fmtInt(a.size)} people`} title={a.name}>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, marginTop: 10 }}>
              <div>
                <div style={{ fontSize: 11, color: 'var(--pw-fg-subtle)', letterSpacing: '0.08em', textTransform: 'uppercase' }}>Revenue</div>
                <div style={{ fontWeight: 500, fontSize: 22, letterSpacing: '-0.01em' }}>{CoverStory.fmtMoney(a.revenue)}</div>
              </div>
              <div>
                <div style={{ fontSize: 11, color: 'var(--pw-fg-subtle)', letterSpacing: '0.08em', textTransform: 'uppercase' }}>ROAS</div>
                <div style={{ fontWeight: 500, fontSize: 22, letterSpacing: '-0.01em' }}>{(a.revenue / a.spend).toFixed(1)}×</div>
              </div>
            </div>
          </Card>
        ))}
      </div>

      <Card title="All segments" sub="Feeding Meta and Google audiences">
        <table className="pw-table">
          <thead><tr><th>Segment</th><th className="num">Size</th><th className="num">Spend</th><th className="num">Covers</th><th className="num">Revenue</th><th className="num">ROAS</th></tr></thead>
          <tbody>
            {CoverStory.AUDIENCES.map(a => (
              <tr key={a.id}>
                <td style={{ fontWeight: 500 }}>{a.name}</td>
                <td className="num">{CoverStory.fmtInt(a.size)}</td>
                <td className="num">{CoverStory.fmtMoney(a.spend)}</td>
                <td className="num">{CoverStory.fmtInt(a.covers)}</td>
                <td className="num" style={{ fontWeight: 500 }}>{CoverStory.fmtMoney(a.revenue)}</td>
                <td className="num">{(a.revenue / a.spend).toFixed(1)}×</td>
              </tr>
            ))}
          </tbody>
        </table>
      </Card>
    </div>
  );
}

// ── Reports ────────────────────────────────────────────────────────
function ReportsPage({ ctx }) {
  const reports = [
    { name: 'Weekly RAM summary', cadence: 'Every Monday 09:00', channels: 'All', last: 'Yesterday' },
    { name: 'Covers attribution — venue level', cadence: 'Monthly', channels: 'All', last: '12 days ago' },
    { name: 'Meta creative performance', cadence: 'Weekly', channels: 'Meta', last: '2 days ago' },
    { name: 'Board deck — attributed revenue', cadence: 'Monthly', channels: 'All', last: '8 days ago' },
    { name: 'AEO coverage report', cadence: 'Weekly', channels: 'AEO, SEO', last: '5 days ago' },
  ];
  return (
    <div>
      <Card title="Scheduled reports" sub="Exports sent to email, Slack, Google Drive"
        right={<button className="pw-btn pw-btn-primary"><Icon.plus /> New report</button>}>
        <table className="pw-table">
          <thead><tr><th>Report</th><th>Channels</th><th>Cadence</th><th>Last sent</th><th></th></tr></thead>
          <tbody>
            {reports.map(r => (
              <tr key={r.name} className="clickable">
                <td style={{ fontWeight: 500 }}>{r.name}</td>
                <td>{r.channels}</td>
                <td>{r.cadence}</td>
                <td style={{ color: 'var(--pw-fg-muted)' }}>{r.last}</td>
                <td><button className="pw-btn pw-btn-ghost"><Icon.download /> Export</button></td>
              </tr>
            ))}
          </tbody>
        </table>
      </Card>
    </div>
  );
}

// ── Settings ───────────────────────────────────────────────────────
function SettingsPage({ ctx }) {
  const integrations = [
    { name: 'Google Ads', status: 'connected', note: '3 accounts' },
    { name: 'Meta Ads', status: 'connected', note: '2 ad accounts' },
    { name: 'DOOH — Clear Channel', status: 'connected', note: 'API key OK' },
    { name: 'Google Search Console', status: 'connected', note: 'All properties' },
    { name: 'SevenRooms', status: 'connected', note: 'Bookings & covers' },
    { name: 'Toast POS', status: 'connected', note: 'Live sync' },
    { name: 'Perplexity · AEO', status: 'pending', note: 'Awaiting credentials' },
    { name: 'ChatGPT · AEO', status: 'connected', note: 'Tracking 42 prompts' },
  ];
  return (
    <div>
      <Card title="Data integrations" sub="Pathway connects 8 sources" style={{ marginBottom: 16 }}>
        <div className="pw-grid pw-grid-2">
          {integrations.map(i => (
            <div key={i.name} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '12px 0', borderBottom: '1px solid var(--pw-hair)' }}>
              <div>
                <div style={{ fontWeight: 500, fontSize: 14 }}>{i.name}</div>
                <div style={{ fontSize: 12, color: 'var(--pw-fg-muted)' }}>{i.note}</div>
              </div>
              <span className={'pw-badge' + (i.status === 'connected' ? ' live' : '')}>{i.status}</span>
            </div>
          ))}
        </div>
      </Card>
      <Card title="RAM configuration" sub="Attribution window & weighting">
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 16 }}>
          <div>
            <div style={{ fontSize: 11, color: 'var(--pw-fg-subtle)', letterSpacing: '0.08em', textTransform: 'uppercase', marginBottom: 6 }}>Click window</div>
            <div style={{ fontWeight: 500, fontSize: 22 }}>30 days</div>
          </div>
          <div>
            <div style={{ fontSize: 11, color: 'var(--pw-fg-subtle)', letterSpacing: '0.08em', textTransform: 'uppercase', marginBottom: 6 }}>View window</div>
            <div style={{ fontWeight: 500, fontSize: 22 }}>7 days</div>
          </div>
          <div>
            <div style={{ fontSize: 11, color: 'var(--pw-fg-subtle)', letterSpacing: '0.08em', textTransform: 'uppercase', marginBottom: 6 }}>Incrementality model</div>
            <div style={{ fontWeight: 500, fontSize: 22 }}>Geo-calibrated</div>
          </div>
        </div>
      </Card>
    </div>
  );
}

// ── Locations ──────────────────────────────────────────────────────
function LocationsPage({ ctx }) {
  const totalBookings = CoverStory.LOCATIONS.reduce((s, l) => s + l.bookings, 0);
  const totalRevenue  = CoverStory.LOCATIONS.reduce((s, l) => s + l.revenue, 0);
  const avgAov = totalBookings ? totalRevenue / totalBookings : 0;

  return (
    <div>
      <div className="pw-grid pw-grid-4" style={{ marginBottom: 16 }}>
        <Kpi label="Pipeline revenue" value={CoverStory.fmtMoney(totalRevenue)} sub={ctx.rangeLabel} />
        <Kpi label="Revenue per booking" value={'£' + Math.round(avgAov)} sub="Average order value" />
        <Kpi label="Attributed bookings" value={CoverStory.fmtInt(totalBookings)} sub={`Across ${CoverStory.LOCATIONS.length} venues`} />
        <Kpi label="Avg party size" value="3.2" sub="Guests per booking" />
      </div>

      <div className="pw-grid pw-grid-3">
        {CoverStory.LOCATIONS.map(l => {
          const pts = Array.from({ length: 24 }, (_, i) => {
            const t = i / 23;
            const base = 0.35 + 0.45 * t + 0.1 * Math.sin(i * 0.9) + ((l.id.charCodeAt(1) % 4) * 0.03);
            return base;
          });
          const max = Math.max(...pts);
          const d = pts.map((p, i) => {
            const x = (i / (pts.length - 1)) * 100;
            const y = 100 - (p / max) * 100;
            return `${i === 0 ? 'M' : 'L'} ${x.toFixed(1)} ${y.toFixed(1)}`;
          }).join(' ');
          return (
            <div key={l.id} className="pw-card clickable" style={{ cursor: 'pointer' }} onClick={() => ctx.go('location', { id: l.id })}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 12 }}>
                <div>
                  <div style={{ fontWeight: 500, fontSize: 15 }}>{l.name}</div>
                  <div style={{ fontSize: 11, color: 'var(--pw-fg-subtle)', letterSpacing: '0.1em', textTransform: 'uppercase', marginTop: 2 }}>{l.area}</div>
                </div>
                <Delta value={l.trend} />
              </div>
              <svg viewBox="0 0 100 100" preserveAspectRatio="none" style={{ width: '100%', height: 48, marginBottom: 12 }}>
                <path d={d} fill="none" stroke="var(--pw-accent)" strokeWidth="1.5" vectorEffect="non-scaling-stroke" />
                <path d={d + ' L 100 100 L 0 100 Z'} fill="var(--pw-accent)" fillOpacity="0.08" />
              </svg>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 10, fontSize: 13 }}>
                <div>
                  <div style={{ color: 'var(--pw-fg-subtle)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase' }}>Bookings</div>
                  <div style={{ fontWeight: 500, fontSize: 18 }}>{CoverStory.fmtInt(l.bookings)}</div>
                </div>
                <div>
                  <div style={{ color: 'var(--pw-fg-subtle)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase' }}>Revenue</div>
                  <div style={{ fontWeight: 500, fontSize: 18 }}>{CoverStory.fmtMoneyExact(l.revenue)}</div>
                </div>
                <div>
                  <div style={{ color: 'var(--pw-fg-subtle)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase' }}>Avg reservation value</div>
                  <div style={{ fontWeight: 500, fontSize: 18 }}>{CoverStory.fmtMoneyExact(l.aov)}</div>
                </div>
              </div>
              <div style={{ marginTop: 12, paddingTop: 10, borderTop: '1px solid var(--pw-hair)', fontSize: 12, color: 'var(--pw-fg-muted)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                <span><Sparkle size="10" /> Top channel</span>
                <span style={{ color: 'var(--pw-fg)', fontWeight: 500 }}>{l.top || '—'}</span>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ── Guest Insights ────────────────────────────────────────────────
function GuestInsightsPage({ ctx }) {
  const g = CoverStory.GUEST_METRICS;
  const maxDow = Math.max(...CoverStory.BOOKINGS_BY_DOW.map(d => d.bookings));
  const totalSegRev = CoverStory.SEGMENTS.reduce((s, x) => s + x.revenue, 0);

  // Donut segments
  let acc = 0;
  const donut = CoverStory.SEGMENTS.map(s => {
    const start = acc / totalSegRev;
    acc += s.revenue;
    const end = acc / totalSegRev;
    return { ...s, start, end };
  });

  function arc(cx, cy, rOuter, rInner, start, end) {
    const a0 = (start * 2 - 0.5) * Math.PI;
    const a1 = (end * 2 - 0.5) * Math.PI;
    const large = end - start > 0.5 ? 1 : 0;
    const x0 = cx + rOuter * Math.cos(a0), y0 = cy + rOuter * Math.sin(a0);
    const x1 = cx + rOuter * Math.cos(a1), y1 = cy + rOuter * Math.sin(a1);
    const x2 = cx + rInner * Math.cos(a1), y2 = cy + rInner * Math.sin(a1);
    const x3 = cx + rInner * Math.cos(a0), y3 = cy + rInner * Math.sin(a0);
    return `M ${x0} ${y0} A ${rOuter} ${rOuter} 0 ${large} 1 ${x1} ${y1} L ${x2} ${y2} A ${rInner} ${rInner} 0 ${large} 0 ${x3} ${y3} Z`;
  }

  return (
    <div>
      <div className="pw-grid pw-grid-4" style={{ marginBottom: 16 }}>
        <Kpi label="Avg party size" value={g.avgPartySize.toFixed(1)} sub="guests per booking" />
        <Kpi label="Days between visits" value={g.daysBetweenVisits} sub="For returning guests" />
        <Kpi label="Booking lead time" value={g.bookingLeadTime + ' days'} sub="Average advance booking" />
        <Kpi label="Peak booking window" value={g.peakWindow} sub="Revenue concentration" />
      </div>

      <div className="pw-grid pw-grid-2" style={{ marginBottom: 16 }}>
        <Card title="New vs returning" sub="Guest composition — this period">
          <div style={{ display: 'flex', alignItems: 'center', gap: 28, padding: '12px 4px' }}>
            <svg width="150" height="150" viewBox="0 0 150 150">
              <circle cx="75" cy="75" r="62" fill="none" stroke="var(--pw-hair)" strokeWidth="18" />
              <circle cx="75" cy="75" r="62" fill="none" stroke="var(--pw-accent)" strokeWidth="18"
                      strokeDasharray={`${(g.newPct / 100) * Math.PI * 124} ${Math.PI * 124}`}
                      transform="rotate(-90 75 75)" strokeLinecap="butt" />
              <text x="75" y="72" textAnchor="middle" fontFamily="Clash Display, Clash Grotesk" fontSize="34" fontWeight="500" fill="var(--pw-fg)" letterSpacing="-0.02em">{CoverStory.fmtInt(g.totalGuests)}</text>
              <text x="75" y="92" textAnchor="middle" fontSize="10" letterSpacing="0.12em" fill="var(--pw-fg-subtle)">TOTAL GUESTS</text>
            </svg>
            <div style={{ display: 'grid', gap: 14 }}>
              <div>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <span style={{ width: 10, height: 10, background: 'var(--pw-accent)' }} />
                  <span style={{ fontFamily: "'Clash Display','Clash Grotesk',sans-serif", fontSize: 32, fontWeight: 500, letterSpacing: '-0.02em' }}>{g.newPct}%</span>
                </div>
                <div style={{ fontSize: 12, color: 'var(--pw-fg-muted)', marginLeft: 18 }}>New guests</div>
              </div>
              <div>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <span style={{ width: 10, height: 10, background: 'var(--pw-hair-strong)' }} />
                  <span style={{ fontFamily: "'Clash Display','Clash Grotesk',sans-serif", fontSize: 32, fontWeight: 500, letterSpacing: '-0.02em' }}>{g.returningPct}%</span>
                </div>
                <div style={{ fontSize: 12, color: 'var(--pw-fg-muted)', marginLeft: 18 }}>Returning guests</div>
              </div>
            </div>
          </div>
        </Card>

        <Card title="Booking patterns" sub="Bookings by day of week">
          <div style={{ display: 'flex', alignItems: 'flex-end', gap: 10, height: 200, padding: '8px 4px 0' }}>
            {CoverStory.BOOKINGS_BY_DOW.map(d => {
              const h = (d.bookings / maxDow) * 100;
              const isPeak = d.day === 'Fri' || d.day === 'Sat';
              return (
                <div key={d.day} style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8, height: '100%' }}>
                  <div style={{ flex: 1, width: '100%', display: 'flex', alignItems: 'flex-end' }}>
                    <div style={{ width: '100%', height: h + '%', background: isPeak ? 'var(--pw-accent)' : 'var(--pw-accent)', opacity: isPeak ? 1 : 0.55, transition: 'height .3s var(--pw-ease)' }} title={`${d.day}: ${d.bookings}`} />
                  </div>
                  <div style={{ fontSize: 11, color: 'var(--pw-fg-muted)', letterSpacing: '0.08em' }}>{d.day}</div>
                </div>
              );
            })}
          </div>
        </Card>
      </div>

      <Card title="Top revenue segments" sub="Guest types driving the most revenue" style={{ marginBottom: 16 }}>
        <div style={{ display: 'grid', gridTemplateColumns: '180px 1fr', gap: 32, alignItems: 'center' }}>
          <svg width="180" height="180" viewBox="0 0 180 180">
            {donut.map(s => (
              <path key={s.id} d={arc(90, 90, 80, 54, s.start, s.end)} fill={s.color} />
            ))}
          </svg>
          <table className="pw-table">
            <tbody>
              {donut.map(s => (
                <tr key={s.id}>
                  <td style={{ width: 20 }}><span style={{ width: 10, height: 10, background: s.color, display: 'inline-block' }} /></td>
                  <td style={{ fontWeight: 500 }}>{s.name}</td>
                  <td className="num">{CoverStory.fmtMoneyFull(s.revenue)}</td>
                  <td className="num" style={{ color: 'var(--pw-fg-muted)' }}>{s.share}%</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </Card>

      <Card title="Guest journey" sub="Touchpoints to first booking — average sequence">
        <div style={{ display: 'flex', gap: 0, alignItems: 'stretch' }}>
          {[
            { step: 'Discovery', ch: 'Paid Social / AEO', days: '14 days before', pct: 100 },
            { step: 'Research',  ch: 'Organic Search',    days: '8 days before',  pct: 74 },
            { step: 'Consideration', ch: 'Direct / Reviews', days: '3 days before', pct: 52 },
            { step: 'Intent',    ch: 'Paid Search',       days: '1 day before',   pct: 38 },
            { step: 'Booking',   ch: 'Direct / OpenTable', days: 'Same day',      pct: 22 },
          ].map((s, i, arr) => (
            <div key={s.step} style={{ flex: 1, padding: '16px 20px', borderRight: i < arr.length - 1 ? '1px solid var(--pw-hair)' : 'none', position: 'relative' }}>
              <div style={{ fontSize: 10, letterSpacing: '0.14em', color: 'var(--pw-fg-subtle)', textTransform: 'uppercase', marginBottom: 8 }}>Step {i + 1}</div>
              <div style={{ fontWeight: 500, fontSize: 15, marginBottom: 4 }}>{s.step}</div>
              <div style={{ fontSize: 12, color: 'var(--pw-fg-muted)', marginBottom: 10 }}>{s.ch}</div>
              <div style={{ fontFamily: "'Clash Display','Clash Grotesk',sans-serif", fontSize: 28, fontWeight: 500, letterSpacing: '-0.02em', lineHeight: 1 }}>{s.pct}%</div>
              <div style={{ fontSize: 11, color: 'var(--pw-fg-subtle)', marginTop: 4 }}>{s.days}</div>
            </div>
          ))}
        </div>
      </Card>
    </div>
  );
}

// ── Channel Comparison ─────────────────────────────────────────────
function ChannelComparisonPage({ ctx }) {
  const totals = useMemoP(() => CoverStory.buildChannelTotals(ctx.range).filter(c => ctx.channelsOn[c.id]), [ctx.range, ctx.channelsOn]);
  const maxRev = Math.max(...totals.map(c => c.revenue));
  const maxRoas = Math.max(...totals.map(c => c.roas || 0));

  return (
    <div>
      <Card title="Side-by-side channel metrics" sub="Sorted by RAM-attributed revenue" style={{ marginBottom: 16 }}>
        <table className="pw-table">
          <thead><tr>
            <th>Channel</th>
            <th className="num">Spend</th>
            <th>Revenue</th>
            <th className="num">ROAS</th>
            <th className="num">Bookings</th>
            <th className="num">Covers</th>
            <th className="num">Share</th>
          </tr></thead>
          <tbody>
            {totals.slice().sort((a, b) => b.revenue - a.revenue).map(c => (
              <tr key={c.id} className="clickable" onClick={() => ctx.go('channel', { id: c.id })}>
                <td><span style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontWeight: 500 }}>
                  <span style={{ width: 10, height: 10, background: c.color }} />{c.name}
                </span></td>
                <td className="num">{c.spend > 0 ? CoverStory.fmtMoney(c.spend) : '—'}</td>
                <td>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                    <div style={{ flex: 1, height: 8, background: 'var(--pw-hair)', minWidth: 80 }}>
                      <div style={{ width: (c.revenue / maxRev * 100) + '%', height: '100%', background: c.color }} />
                    </div>
                    <span className="num" style={{ minWidth: 70, fontWeight: 500 }}>{CoverStory.fmtMoney(c.revenue)}</span>
                  </div>
                </td>
                <td className="num" style={{ fontWeight: 500 }}>{c.roas ? c.roas.toFixed(2) + '×' : 'N/A'}</td>
                <td className="num">{CoverStory.fmtInt(Math.round(c.covers * 0.82))}</td>
                <td className="num">{CoverStory.fmtInt(c.covers)}</td>
                <td className="num">{(c.share * 100).toFixed(1)}%</td>
              </tr>
            ))}
          </tbody>
        </table>
      </Card>

      <div className="pw-grid pw-grid-2">
        <Card title="Efficiency frontier" sub="Spend vs return — bigger bubble = more covers">
          <div style={{ position: 'relative', height: 280, padding: '20px 0 28px 40px' }}>
            <div style={{ position: 'absolute', left: 0, top: 8, fontSize: 10, letterSpacing: '0.1em', color: 'var(--pw-fg-subtle)', textTransform: 'uppercase', transform: 'rotate(-90deg)', transformOrigin: 'left top' }}>ROAS →</div>
            <div style={{ position: 'absolute', bottom: 8, right: 8, fontSize: 10, letterSpacing: '0.1em', color: 'var(--pw-fg-subtle)', textTransform: 'uppercase' }}>SPEND →</div>
            {/* axes */}
            <div style={{ position: 'absolute', left: 40, right: 0, bottom: 28, height: 1, background: 'var(--pw-hair-strong)' }} />
            <div style={{ position: 'absolute', left: 40, top: 20, bottom: 28, width: 1, background: 'var(--pw-hair-strong)' }} />
            {totals.filter(c => c.spend > 0 && c.roas).map(c => {
              const maxSpend = Math.max(...totals.map(x => x.spend));
              const x = 4 + (c.spend / maxSpend) * 88;
              const y = 94 - (c.roas / maxRoas) * 84;
              const size = 12 + (c.covers / Math.max(...totals.map(x => x.covers))) * 28;
              return (
                <div key={c.id} title={`${c.name}: ${c.roas.toFixed(1)}× ROAS`}
                     style={{ position: 'absolute', left: x + '%', top: y + '%', width: size, height: size, background: c.color, borderRadius: 0, transform: 'translate(-50%, -50%)', opacity: 0.85, cursor: 'pointer' }} />
              );
            })}
          </div>
        </Card>
        <Card title="Cost efficiency" sub="Cost per acquisition by channel">
          {totals.filter(c => c.spend > 0).sort((a, b) => (a.spend / a.covers) - (b.spend / b.covers)).map(c => {
            const cpa = c.covers ? c.spend / c.covers : 0;
            const maxCpa = Math.max(...totals.filter(x => x.spend > 0 && x.covers > 0).map(x => x.spend / x.covers));
            return (
              <div key={c.id} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '10px 0', borderBottom: '1px solid var(--pw-hair)' }}>
                <span style={{ width: 10, height: 10, background: c.color }} />
                <div style={{ width: 130, fontSize: 13, fontWeight: 500 }}>{c.name}</div>
                <div style={{ flex: 1, height: 6, background: 'var(--pw-hair)' }}>
                  <div style={{ width: (cpa / maxCpa * 100) + '%', height: '100%', background: c.color }} />
                </div>
                <div className="num" style={{ width: 70, fontWeight: 500, fontSize: 13 }}>£{Math.round(cpa)}</div>
              </div>
            );
          })}
        </Card>
      </div>
    </div>
  );
}

// ── UTM Builder ───────────────────────────────────────────────────
function UtmBuilderPage({ ctx }) {
  const [src, setSrc]   = useStateP('instagram');
  const [med, setMed]   = useStateP('paid_social');
  const [cmp, setCmp]   = useStateP('spring-menu-2026');
  const [trm, setTrm]   = useStateP('');
  const [cnt, setCnt]   = useStateP('hero-video');
  const [base, setBase] = useStateP('https://demorestaurantgroup.co.uk/book');
  const [copied, setCopied] = useStateP(false);

  const url = `${base}?utm_source=${encodeURIComponent(src)}&utm_medium=${encodeURIComponent(med)}&utm_campaign=${encodeURIComponent(cmp)}${trm ? '&utm_term=' + encodeURIComponent(trm) : ''}${cnt ? '&utm_content=' + encodeURIComponent(cnt) : ''}`;

  function copy() {
    navigator.clipboard?.writeText(url);
    setCopied(true);
    setTimeout(() => setCopied(false), 1600);
  }

  const Input = ({ label, value, onChange, placeholder, required, hint }) => (
    <label style={{ display: 'block', marginBottom: 14 }}>
      <div style={{ fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--pw-fg-subtle)', marginBottom: 6 }}>
        {label}{required && <span style={{ color: 'var(--pw-accent)' }}> *</span>}
      </div>
      <input value={value} onChange={e => onChange(e.target.value)} placeholder={placeholder}
             style={{ width: '100%', padding: '10px 12px', background: 'var(--pw-surface)', border: '1px solid var(--pw-hair-strong)', color: 'var(--pw-fg)', fontFamily: 'inherit', fontSize: 13 }} />
      {hint && <div style={{ fontSize: 11, color: 'var(--pw-fg-muted)', marginTop: 4 }}>{hint}</div>}
    </label>
  );

  const recent = [
    { cmp: 'spring-menu-2026', src: 'instagram', med: 'paid_social',  clicks: 2840, bookings: 142 },
    { cmp: 'valentines-2026',  src: 'google',    med: 'paid_search',  clicks: 4120, bookings: 218 },
    { cmp: 'newsletter-apr',   src: 'mailchimp', med: 'email',        clicks: 1820, bookings: 94 },
    { cmp: 'tube-oxford-st',   src: 'clear-channel', med: 'dooh',     clicks: 1240, bookings: 68 },
    { cmp: 'chef-interview',   src: 'timeout',   med: 'pr',           clicks: 820,  bookings: 38 },
  ];

  return (
    <div>
      <div className="pw-grid pw-grid-main" style={{ marginBottom: 16 }}>
        <Card title="Build a tagged URL" sub="UTM parameters feed directly into Pathway attribution">
          <Input label="Website URL" value={base} onChange={setBase} required />
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
            <Input label="Campaign source" value={src} onChange={setSrc} required placeholder="instagram" hint="utm_source — where the traffic comes from" />
            <Input label="Campaign medium" value={med} onChange={setMed} required placeholder="paid_social" hint="utm_medium — the channel type" />
          </div>
          <Input label="Campaign name" value={cmp} onChange={setCmp} required placeholder="spring-menu-2026" hint="utm_campaign — unique campaign identifier" />
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
            <Input label="Campaign term" value={trm} onChange={setTrm} placeholder="(optional)" hint="utm_term — paid keywords" />
            <Input label="Campaign content" value={cnt} onChange={setCnt} placeholder="hero-video" hint="utm_content — ad variant / creative" />
          </div>
        </Card>

        <Card title="Generated URL" sub="Ready to use">
          <div style={{ background: 'var(--pw-fg)', color: 'var(--pw-bg)', padding: 16, fontFamily: 'ui-monospace, SF Mono, Menlo, monospace', fontSize: 12, wordBreak: 'break-all', lineHeight: 1.5, marginBottom: 12 }}>
            {url}
          </div>
          <button className="pw-btn pw-btn-primary" style={{ width: '100%', justifyContent: 'center' }} onClick={copy}>
            {copied ? <><Sparkle size="12" /> Copied</> : <><Icon.download /> Copy URL</>}
          </button>

          <div style={{ marginTop: 20, paddingTop: 16, borderTop: '1px solid var(--pw-hair)' }}>
            <div style={{ fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--pw-fg-subtle)', marginBottom: 10 }}>Parameter summary</div>
            <div style={{ display: 'grid', gap: 8, fontSize: 13 }}>
              {[['Source', src], ['Medium', med], ['Campaign', cmp], ['Term', trm || '—'], ['Content', cnt || '—']].map(([k, v]) => (
                <div key={k} style={{ display: 'flex', justifyContent: 'space-between', paddingBottom: 6, borderBottom: '1px solid var(--pw-hair)' }}>
                  <span style={{ color: 'var(--pw-fg-muted)' }}>{k}</span>
                  <span style={{ fontWeight: 500, fontFamily: 'ui-monospace, monospace' }}>{v}</span>
                </div>
              ))}
            </div>
          </div>
        </Card>
      </div>

      <Card title="Recent tagged URLs" sub="Last 30 days — performance">
        <table className="pw-table">
          <thead><tr><th>Campaign</th><th>Source</th><th>Medium</th><th className="num">Clicks</th><th className="num">Bookings</th><th className="num">CVR</th></tr></thead>
          <tbody>
            {recent.map(r => (
              <tr key={r.cmp}>
                <td style={{ fontWeight: 500, fontFamily: 'ui-monospace, monospace', fontSize: 12 }}>{r.cmp}</td>
                <td style={{ fontFamily: 'ui-monospace, monospace', fontSize: 12 }}>{r.src}</td>
                <td style={{ fontFamily: 'ui-monospace, monospace', fontSize: 12 }}>{r.med}</td>
                <td className="num">{CoverStory.fmtInt(r.clicks)}</td>
                <td className="num" style={{ fontWeight: 500 }}>{CoverStory.fmtInt(r.bookings)}</td>
                <td className="num">{(r.bookings / r.clicks * 100).toFixed(1)}%</td>
              </tr>
            ))}
          </tbody>
        </table>
      </Card>
    </div>
  );
}

// ── Location Detail ───────────────────────────────────────────────
function LocationDetailPage({ ctx }) {
  const venue = ctx.param;
  const loc = CoverStory.LOCATIONS.find(l => l.id === venue) || { name: venue, bookings: 0, covers: 0, revenue: 0, aov: 0, top: '' };
  // Filter the live bookings list to this venue, then derive everything we can
  // from it client-side: channel breakdown, recent bookings table, ASPH.
  const allBookings = (window.CoverStory && window.CoverStory.LIVE_BOOKINGS) || [];
  const venueBookings = useMemoP(() => allBookings.filter(b => b.site && b.site.id === venue), [allBookings, venue]);

  // Channel breakdown for this venue
  const channelBreakdown = useMemoP(() => {
    const map = new Map();
    venueBookings.forEach(b => {
      const cid = b.channel.id;
      if (!map.has(cid)) {
        const meta = CoverStory.CHANNELS.find(c => c.id === cid) || { id: cid, name: b.channel.name, color: b.channel.color };
        map.set(cid, { id: cid, name: meta.name, color: meta.color, bookings: 0, covers: 0, revenue: 0 });
      }
      const row = map.get(cid);
      row.bookings += 1;
      row.covers += b.covers || 0;
      row.revenue += b.potentialRevenue || 0;
    });
    return Array.from(map.values()).sort((a, b) => b.revenue - a.revenue);
  }, [venueBookings]);

  const totalChannelRev = channelBreakdown.reduce((s, c) => s + c.revenue, 0) || 1;

  // Recent bookings table for this venue (10 most recent)
  const recentBookings = useMemoP(() => venueBookings.slice().sort((a, b) => b.bookingDate - a.bookingDate).slice(0, 10), [venueBookings]);

  return (
    <div>
      <div style={{ marginBottom: 16, display: 'flex', alignItems: 'baseline', gap: 12 }}>
        <button className="pw-btn pw-btn-ghost" onClick={() => ctx.go('locations')}>← All locations</button>
      </div>

      <div className="pw-grid pw-grid-4" style={{ marginBottom: 20 }}>
        <Kpi label="Pipeline revenue" value={CoverStory.fmtMoneyExact(loc.revenue)} sub={ctx.rangeLabel} />
        <Kpi label="Attributed bookings" value={CoverStory.fmtInt(loc.bookings)} sub={`${CoverStory.fmtInt(loc.covers || 0)} covers`} />
        <Kpi label="ASPH" value={CoverStory.fmtMoneyExact(loc.covers > 0 ? loc.revenue / loc.covers : 0)} sub="Avg spend per head" />
        <Kpi label="Avg reservation value" value={CoverStory.fmtMoneyExact(loc.aov)} sub="Per booking" />
      </div>

      <div className="pw-grid pw-grid-main" style={{ marginBottom: 16 }}>
        <Card title={`${loc.name} — channel mix`} sub="Share of pipeline revenue for this venue">
          {channelBreakdown.length === 0 ? (
            <div style={{ padding: 24, color: 'var(--pw-fg-muted)', fontSize: 13 }}>No bookings in this period.</div>
          ) : (
            <table className="pw-table">
              <thead>
                <tr><th>Channel</th><th className="num">Bookings</th><th className="num">Covers</th><th className="num">Revenue</th><th className="num">Share</th></tr>
              </thead>
              <tbody>
                {channelBreakdown.map(c => (
                  <tr key={c.id}>
                    <td>
                      <span className="pw-chip" style={{ cursor: 'default' }}>
                        <span className="pw-chip-dot" style={{ background: c.color }} />
                        {c.name}
                      </span>
                    </td>
                    <td className="num">{CoverStory.fmtInt(c.bookings)}</td>
                    <td className="num">{CoverStory.fmtInt(c.covers)}</td>
                    <td className="num" style={{ fontWeight: 500 }}>{CoverStory.fmtMoneyExact(c.revenue)}</td>
                    <td className="num" style={{ color: 'var(--pw-fg-muted)' }}>{(100 * c.revenue / totalChannelRev).toFixed(1)}%</td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </Card>

        <Card title="Top channel" sub={loc.top || '—'}>
          <div style={{ padding: '20px 4px' }}>
            <div style={{ fontSize: 11, color: 'var(--pw-fg-subtle)', letterSpacing: '0.08em', textTransform: 'uppercase', marginBottom: 8 }}>Pipeline revenue</div>
            <div style={{ fontSize: 36, fontWeight: 500, letterSpacing: '-0.02em' }}>{CoverStory.fmtMoneyExact(loc.revenue)}</div>
            <div style={{ fontSize: 12, color: 'var(--pw-fg-muted)', marginTop: 4 }}>{ctx.rangeLabel}</div>

            <div className="bk-divider" style={{ margin: '20px 0' }} />

            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, fontSize: 13 }}>
              <div>
                <div style={{ color: 'var(--pw-fg-subtle)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase' }}>Covers</div>
                <div style={{ fontWeight: 500, fontSize: 18 }}>{CoverStory.fmtInt(loc.covers || 0)}</div>
              </div>
              <div>
                <div style={{ color: 'var(--pw-fg-subtle)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase' }}>Bookings</div>
                <div style={{ fontWeight: 500, fontSize: 18 }}>{CoverStory.fmtInt(loc.bookings)}</div>
              </div>
              <div>
                <div style={{ color: 'var(--pw-fg-subtle)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase' }}>ASPH</div>
                <div style={{ fontWeight: 500, fontSize: 18 }}>{CoverStory.fmtMoneyExact(loc.covers > 0 ? loc.revenue / loc.covers : 0)}</div>
              </div>
              <div>
                <div style={{ color: 'var(--pw-fg-subtle)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase' }}>Avg party</div>
                <div style={{ fontWeight: 500, fontSize: 18 }}>{loc.covers > 0 && loc.bookings > 0 ? (loc.covers / loc.bookings).toFixed(1) : '—'}</div>
              </div>
            </div>
          </div>
        </Card>
      </div>

      <Card title="Recent bookings" sub={`${recentBookings.length} of ${venueBookings.length} for ${loc.name}`} right={<button className="pw-btn pw-btn-ghost" onClick={() => ctx.go('bookings')}>All bookings <Icon.arrowRight /></button>}>
        {recentBookings.length === 0 ? (
          <div style={{ padding: 24, color: 'var(--pw-fg-muted)', fontSize: 13 }}>No recent bookings for this venue.</div>
        ) : (
          <table className="pw-table">
            <thead>
              <tr><th>Booking ref</th><th>Reservation</th><th className="num">Covers</th><th>Channel</th><th className="num">Lead time</th><th className="num">Pipeline value</th></tr>
            </thead>
            <tbody>
              {recentBookings.map(b => (
                <tr key={b.id}>
                  <td><span className="bk-ref">{b.id}</span></td>
                  <td style={{ color: 'var(--pw-fg-muted)', fontSize: 13 }}>
                    {b.bookingDate.toLocaleDateString('en-GB', { day: '2-digit', month: 'short' })}
                    {' · '}
                    {b.bookingDate.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' })}
                  </td>
                  <td className="num">{b.covers}</td>
                  <td>
                    <span className="pw-chip" style={{ cursor: 'default' }}>
                      <span className="pw-chip-dot" style={{ background: b.channel.color }} />
                      {b.channel.name}
                    </span>
                  </td>
                  <td className="num" style={{ color: 'var(--pw-fg-muted)' }}>{b.daysToBook > 0 ? b.daysToBook + 'd' : '—'}</td>
                  <td className="num" style={{ fontWeight: 500 }}>{CoverStory.fmtMoneyExact(b.potentialRevenue)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </Card>
    </div>
  );
}

Object.assign(window, { OverviewPage, RamPage, ChannelsPage, ChannelDetailPage, CampaignsPage, CampaignDetailPage, AudiencesPage, ReportsPage, SettingsPage, LocationsPage, LocationDetailPage, GuestInsightsPage, ChannelComparisonPage, UtmBuilderPage });
