/* On The Limit — Admin Dashboard v2 */
(function(){
  const WORKER   = 'https://otl-analytics.liambell2103.workers.dev';
  const PASSWORD = 'R88robinson!?';

  // ── Palette ───────────────────────────────────────────────────────────────
  const C = {
    accent:    '#72DD9E',
    accentDim: 'rgba(114,221,158,0.18)',
    accentBg:  'rgba(114,221,158,0.07)',
    blue:      '#60A5FA',
    blueDim:   'rgba(96,165,250,0.18)',
    amber:     '#FBBF24',
    amberDim:  'rgba(251,191,36,0.18)',
    pink:      '#F472B6',
    purple:    '#A78BFA',
    cyan:      '#22D3EE',
    grid:      'rgba(255,255,255,0.05)',
    muted:     'rgba(255,255,255,0.35)',
  };
  const DONUT_COLORS = [C.accent, C.blue, C.amber, C.pink, C.purple, C.cyan, 'rgba(255,255,255,0.3)'];
  const DOW = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];

  const PAGE_LABELS = {
    'home':'Home','grit':'GRIT','hyrox':'HYROX','studio':'Studio Classes',
    'gym-floor':'Gym Floor','personal-training':'Personal Training',
    'students-juniors':'Students & Juniors','foundation':'6 Week Foundation',
    'timetable':'Timetable','pricing':'Pricing','team':'Fitness Team',
    'faqs':'FAQs','contact':'Contact','join':'Join','gallery':'Gallery',
    'gym-near-hemel-hempstead':'Hemel (SEO)','gym-near-berkhamsted':'Berkhamsted (SEO)',
    'gym-near-wendover':'Wendover (SEO)','gym-near-aylesbury':'Aylesbury (SEO)',
    'no-contract-gym-tring':'No-Contract (SEO)','gym-day-pass-tring':'Day Pass (SEO)',
  };

  // ── Chart.js global defaults ──────────────────────────────────────────────
  if (window.Chart) {
    Chart.defaults.color                            = C.muted;
    Chart.defaults.borderColor                      = C.grid;
    Chart.defaults.font.size                        = 11;
    Chart.defaults.plugins.legend.labels.boxWidth   = 10;
    Chart.defaults.plugins.legend.labels.padding    = 14;
    Chart.defaults.plugins.legend.labels.color      = C.muted;
    Chart.defaults.plugins.tooltip.backgroundColor  = 'rgba(18,18,18,0.96)';
    Chart.defaults.plugins.tooltip.borderColor      = 'rgba(255,255,255,0.1)';
    Chart.defaults.plugins.tooltip.borderWidth      = 1;
    Chart.defaults.plugins.tooltip.padding          = 10;
    Chart.defaults.plugins.tooltip.cornerRadius     = 8;
    Chart.defaults.plugins.tooltip.titleColor       = '#fff';
    Chart.defaults.plugins.tooltip.bodyColor        = C.muted;
  }

  // ── Data helpers ──────────────────────────────────────────────────────────
  function fmtDay(y, m, d) {
    return new Date(+y, +m - 1, +d).toLocaleDateString('en-GB', { day:'numeric', month:'short' });
  }

  function fillDays(data, days) {
    const n   = days || 30;
    const map = Object.fromEntries((data || []).map(r => [r.day, r.count]));
    const out = [];
    const now = new Date();
    for (let i = n - 1; i >= 0; i--) {
      const dt  = new Date(now.getFullYear(), now.getMonth(), now.getDate() - i);
      const y   = dt.getFullYear();
      const m   = String(dt.getMonth() + 1).padStart(2, '0');
      const d   = String(dt.getDate()).padStart(2, '0');
      const key = `${y}-${m}-${d}`;
      out.push({ day: key, label: fmtDay(y, m, d), count: map[key] || 0 });
    }
    return out;
  }

  function fillHours(data) {
    const map = Object.fromEntries((data || []).map(r => [r.hour, r.count]));
    return Array.from({ length: 24 }, (_, h) => ({ hour: h, count: map[h] || 0 }));
  }

  function fillDow(data) {
    const map = Object.fromEntries((data || []).map(r => [r.dow, r.count]));
    return Array.from({ length: 7 }, (_, i) => ({ dow: i, count: map[i] || 0 }));
  }

  // ── ChartCanvas ───────────────────────────────────────────────────────────
  function ChartCanvas({ cfg, height }) {
    const ref    = React.useRef();
    const cfgRef = React.useRef(cfg);
    React.useEffect(() => {
      if (!ref.current || !window.Chart) return;
      const chart = new Chart(ref.current, cfgRef.current);
      return () => chart.destroy();
    }, []);
    const h = height || 160;
    return (
      <div style={{ position:'relative', width:'100%', height:h, minHeight:h, maxHeight:h }}>
        <canvas ref={ref} style={{ position:'absolute', inset:0, width:'100%', height:'100%' }} />
      </div>
    );
  }

  // ── UI atoms ──────────────────────────────────────────────────────────────
  function Card({ title, children, style }) {
    return (
      <div style={{ background:'var(--surface-card)', border:'1px solid var(--border-subtle)', borderRadius:16, padding:28, ...style }}>
        {title && <h3 style={{ margin:'0 0 20px', fontFamily:'var(--font-display)', fontWeight:800, textTransform:'uppercase', fontSize:12, color:'#fff', letterSpacing:'0.06em' }}>{title}</h3>}
        {children}
      </div>
    );
  }

  function Stat({ label, value, accent, sub }) {
    return (
      <div style={{ background:'var(--surface-card)', border: accent ? `1.5px solid ${C.accent}` : '1px solid var(--border-subtle)', borderRadius:14, padding:'20px 22px' }}>
        <div style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:32, color: accent ? C.accent : '#fff', lineHeight:1 }}>{value}</div>
        <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10, letterSpacing:'0.1em', textTransform:'uppercase', color:'var(--text-muted)', marginTop:8 }}>{label}</div>
        {sub && <div style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--text-faint)', marginTop:3 }}>{sub}</div>}
      </div>
    );
  }

  function HBar({ label, value, max, color }) {
    const pct = max > 0 ? Math.round((value / max) * 100) : 0;
    const col = color || C.accent;
    return (
      <div style={{ display:'flex', alignItems:'center', gap:12 }}>
        <div style={{ fontFamily:'var(--font-body)', fontSize:12, color:'var(--fog-200)', width:156, flexShrink:0, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{label}</div>
        <div style={{ flex:1, background:'var(--surface-raised)', borderRadius:99, height:7, overflow:'hidden' }}>
          <div style={{ width:`${pct}%`, height:'100%', background:col, borderRadius:99, transition:'width .6s ease' }} />
        </div>
        <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:12, color:col, minWidth:34, textAlign:'right' }}>{value}</div>
      </div>
    );
  }

  function Empty({ text }) {
    return <div style={{ fontFamily:'var(--font-body)', fontSize:13, color:'var(--text-faint)', padding:'8px 0' }}>{text || 'No data yet'}</div>;
  }

  // ── Overview tab ──────────────────────────────────────────────────────────
  function OverviewTab({ stats, derived }) {
    const { joinRate, avg7, totalClassTaps, filledViews, filledJoins, filledDow, avgDailyViews, avgWeeklyViews, avgDailyJoins, avgWeeklyJoins, bestDay, peakDow, peakHour, avgEnquiriesPerWeek } = derived;

    const trendCfg = {
      type: 'line',
      data: {
        labels: filledViews.map(d => d.label),
        datasets: [
          {
            label: 'Page Views',
            data: filledViews.map(d => d.count),
            borderColor: C.accent, backgroundColor: C.accentDim,
            fill: true, tension: 0.35, pointRadius: 0, borderWidth: 2,
          },
          {
            label: 'Join Clicks',
            data: filledJoins.map(d => d.count),
            borderColor: C.blue, backgroundColor: 'transparent',
            fill: false, tension: 0.35, pointRadius: 0, borderWidth: 2,
          },
        ],
      },
      options: {
        responsive: true, maintainAspectRatio: false,
        interaction: { mode:'index', intersect:false },
        plugins: { legend: { display:true, position:'bottom' } },
        scales: {
          x: { grid:{ color:C.grid }, ticks:{ maxTicksLimit:8, color:C.muted } },
          y: { grid:{ color:C.grid }, beginAtZero:true, ticks:{ color:C.muted } },
        },
      },
    };

    const pageDonutCfg = {
      type: 'doughnut',
      data: {
        labels: stats.topPages.slice(0,6).map(d => PAGE_LABELS[d.page] || d.page || 'Home'),
        datasets: [{ data: stats.topPages.slice(0,6).map(d => d.count), backgroundColor: DONUT_COLORS, borderWidth: 0 }],
      },
      options: {
        responsive: true, maintainAspectRatio: false, cutout: '62%',
        plugins: { legend: { position:'right' } },
      },
    };

    const sourcesDonutCfg = {
      type: 'doughnut',
      data: {
        labels: stats.referrers.length
          ? stats.referrers.slice(0,6).map(d => d.source ? (d.source[0].toUpperCase() + d.source.slice(1)) : 'Direct')
          : ['No data'],
        datasets: [{
          data: stats.referrers.length ? stats.referrers.slice(0,6).map(d => d.count) : [1],
          backgroundColor: stats.referrers.length ? DONUT_COLORS : ['rgba(255,255,255,0.08)'],
          borderWidth: 0,
        }],
      },
      options: {
        responsive: true, maintainAspectRatio: false, cutout: '62%',
        plugins: { legend: { position:'right' } },
      },
    };

    const dowCfg = {
      type: 'bar',
      data: {
        labels: DOW,
        datasets: [{
          data: filledDow.map(d => d.count),
          backgroundColor: C.accentDim, borderColor: C.accent, borderWidth: 1.5, borderRadius: 5,
        }],
      },
      options: {
        responsive: true, maintainAspectRatio: false,
        plugins: { legend:{ display:false } },
        scales: {
          x: { grid:{ display:false }, ticks:{ color:C.muted } },
          y: { grid:{ color:C.grid }, beginAtZero:true, ticks:{ color:C.muted } },
        },
      },
    };

    return (
      <div>
        <div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fit,minmax(158px,1fr))', gap:14, marginBottom:14 }}>
          <Stat label="Total Page Views"  value={stats.pageViews.toLocaleString()}   accent />
          <Stat label="Join Now Clicks"   value={stats.joinClicks.toLocaleString()}  />
          <Stat label="Contact Enquiries" value={stats.contactSubmits.toLocaleString()} />
          <Stat label="Class Taps"        value={totalClassTaps.toLocaleString()}    />
          <Stat label="Conversion Rate"   value={joinRate + '%'} sub="clicks ÷ views" />
          <Stat label="7-Day Daily Avg"   value={avg7.toLocaleString()}              sub="page views" />
        </div>

        <div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fit,minmax(158px,1fr))', gap:14, marginBottom:24 }}>
          <Stat label="Avg Views / Day"    value={avgDailyViews.toLocaleString()}   sub="last 30 days" />
          <Stat label="Avg Views / Week"   value={avgWeeklyViews.toLocaleString()}  sub="last 30 days" />
          <Stat label="Avg Joins / Day"    value={avgDailyJoins}                    sub="last 30 days" />
          <Stat label="Avg Joins / Week"   value={avgWeeklyJoins.toLocaleString()}  sub="last 30 days" />
          <Stat label="Best Single Day"    value={bestDay.count.toLocaleString()}   sub={bestDay.label || '—'} />
          <Stat label="Peak Day"           value={peakDow}                          sub="most visits" />
          <Stat label="Peak Hour"          value={peakHour}                         sub="most traffic" />
          <Stat label="Enquiries / Week"   value={avgEnquiriesPerWeek}              sub="avg last 30 days" />
        </div>

        <Card title="30-Day Traffic — Page Views & Join Clicks" style={{ marginBottom:24 }}>
          {filledViews.some(d => d.count > 0)
            ? <ChartCanvas cfg={trendCfg} height={160} />
            : <Empty />}
        </Card>

        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:24, marginBottom:24 }}>
          <Card title="Page Traffic Share">
            {stats.topPages.length ? <ChartCanvas cfg={pageDonutCfg} height={180} /> : <Empty />}
          </Card>
          <Card title="Traffic Sources">
            <ChartCanvas cfg={sourcesDonutCfg} height={180} />
          </Card>
        </div>

        <Card title="When Do People Visit? (Day of Week)">
          <ChartCanvas cfg={dowCfg} height={140} />
        </Card>
      </div>
    );
  }

  // ── Pages & Content tab ───────────────────────────────────────────────────
  function ContentTab({ stats }) {
    const topPageMax = stats.topPages[0]?.count || 1;

    const classesCfg = {
      type: 'bar',
      data: {
        labels: stats.topClasses.map(d => d.data || 'Unknown'),
        datasets: [{
          data: stats.topClasses.map(d => d.count),
          backgroundColor: C.blueDim, borderColor: C.blue, borderWidth: 1.5, borderRadius: 5,
        }],
      },
      options: {
        indexAxis: 'y',
        responsive: true, maintainAspectRatio: false,
        plugins: { legend:{ display:false } },
        scales: {
          x: { grid:{ color:C.grid }, beginAtZero:true, ticks:{ color:C.muted } },
          y: { grid:{ display:false }, ticks:{ color:C.muted } },
        },
      },
    };

    const sourcesCfg = {
      type: 'bar',
      data: {
        labels: stats.referrers.map(d => d.source ? (d.source[0].toUpperCase() + d.source.slice(1)) : 'Direct'),
        datasets: [{
          data: stats.referrers.map(d => d.count),
          backgroundColor: C.amberDim, borderColor: C.amber, borderWidth: 1.5, borderRadius: 5,
        }],
      },
      options: {
        indexAxis: 'y',
        responsive: true, maintainAspectRatio: false,
        plugins: { legend:{ display:false } },
        scales: {
          x: { grid:{ color:C.grid }, beginAtZero:true, ticks:{ color:C.muted } },
          y: { grid:{ display:false }, ticks:{ color:C.muted } },
        },
      },
    };

    return (
      <div>
        <Card title="Most Visited Pages" style={{ marginBottom:24 }}>
          <div style={{ display:'flex', flexDirection:'column', gap:12 }}>
            {stats.topPages.map(({ page, count }) =>
              <HBar key={page} label={PAGE_LABELS[page] || page || 'Home'} value={count} max={topPageMax} />
            )}
            {stats.topPages.length === 0 && <Empty />}
          </div>
        </Card>

        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:24 }}>
          <Card title="Most Tapped Classes (Timetable)">
            {stats.topClasses.length
              ? <ChartCanvas cfg={classesCfg} height={Math.max(120, stats.topClasses.length * 28)} />
              : <Empty />}
          </Card>
          <Card title="Traffic Sources">
            {stats.referrers.length
              ? <ChartCanvas cfg={sourcesCfg} height={Math.max(120, stats.referrers.length * 28)} />
              : <Empty />}
          </Card>
        </div>
      </div>
    );
  }

  // ── Conversion tab ────────────────────────────────────────────────────────
  function ConversionTab({ stats, derived }) {
    const { joinRate, filledViews, filledJoins, filledHours, filledPVHours, filledJoinDow, pageConversions } = derived;
    const topJoinMax = stats.topJoinPages[0]?.count || 1;

    const dualLineCfg = {
      type: 'line',
      data: {
        labels: filledViews.map(d => d.label),
        datasets: [
          {
            label: 'Page Views',
            data: filledViews.map(d => d.count),
            borderColor: C.accent, backgroundColor: C.accentDim,
            fill: true, tension: 0.35, pointRadius: 0, borderWidth: 2,
          },
          {
            label: 'Join Clicks',
            data: filledJoins.map(d => d.count),
            borderColor: C.blue, backgroundColor: C.blueDim,
            fill: true, tension: 0.35, pointRadius: 0, borderWidth: 2,
          },
        ],
      },
      options: {
        responsive: true, maintainAspectRatio: false,
        interaction: { mode:'index', intersect:false },
        plugins: { legend: { display:true, position:'bottom' } },
        scales: {
          x: { grid:{ color:C.grid }, ticks:{ maxTicksLimit:8, color:C.muted } },
          y: { grid:{ color:C.grid }, beginAtZero:true, ticks:{ color:C.muted } },
        },
      },
    };

    return (
      <div>
        <div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fit,minmax(158px,1fr))', gap:14, marginBottom:24 }}>
          <Stat label="Join Page Views"    value={stats.joinPageViews.toLocaleString()} />
          <Stat label="Join Now Clicks"    value={stats.joinClicks.toLocaleString()} accent />
          <Stat label="Click-through Rate" value={joinRate + '%'} sub="clicks ÷ all pageviews" />
        </div>

        <Card title="Conversion Funnel" style={{ marginBottom:24 }}>
          <div style={{ display:'grid', gridTemplateColumns:'1fr auto 1fr auto 1fr', alignItems:'center', gap:8 }}>
            {[
              { label:'Site Visitors', value:stats.pageViews, sub:'Total page views' },
              null,
              { label:'Clicked Join Now', value:stats.joinClicks, sub:joinRate+'% of visitors', hl:true },
              null,
              { label:'Reached Join Page', value:stats.joinPageViews, sub:'direct visits included' },
            ].map((item, i) => item === null
              ? <div key={i} style={{ textAlign:'center', fontSize:18, color:'var(--border-subtle)' }}>→</div>
              : <div key={i} style={{ background:item.hl?'rgba(114,221,158,0.07)':'var(--surface-raised)', border:item.hl?`1.5px solid ${C.accent}`:'1px solid var(--border-subtle)', borderRadius:12, padding:'18px 14px', textAlign:'center' }}>
                  <div style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:28, color:item.hl?C.accent:'#fff', lineHeight:1 }}>{item.value.toLocaleString()}</div>
                  <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10, textTransform:'uppercase', letterSpacing:'0.06em', color:'var(--text-muted)', marginTop:8 }}>{item.label}</div>
                  <div style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--text-faint)', marginTop:4 }}>{item.sub}</div>
                </div>
            )}
          </div>
        </Card>

        <Card title="Views vs Join Clicks — Last 30 Days" style={{ marginBottom:24 }}>
          {filledViews.some(d => d.count > 0) || filledJoins.some(d => d.count > 0)
            ? <ChartCanvas cfg={dualLineCfg} height={160} />
            : <Empty />}
        </Card>

        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:24, marginBottom:24 }}>
          <Card title="Join Now — Clicked From">
            <div style={{ display:'flex', flexDirection:'column', gap:12 }}>
              {stats.topJoinPages.map(({ page, count }) =>
                <HBar key={page} label={PAGE_LABELS[page]||page||'Home'} value={count} max={topJoinMax} color={C.blue} />
              )}
              {stats.topJoinPages.length === 0 && <Empty />}
            </div>
          </Card>
          <Card title="Per-Page Conversion Rate">
            <div style={{ display:'flex', flexDirection:'column', gap:0 }}>
              <div style={{ display:'grid', gridTemplateColumns:'1fr 64px 64px 64px', gap:8, padding:'0 0 10px', borderBottom:'1px solid var(--border-subtle)', marginBottom:4 }}>
                {['Page','Views','Joins','Rate'].map(h => (
                  <div key={h} style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10, textTransform:'uppercase', letterSpacing:'0.08em', color:'var(--text-faint)', textAlign:h==='Page'?'left':'right' }}>{h}</div>
                ))}
              </div>
              {pageConversions.map(d => (
                <div key={d.page} style={{ display:'grid', gridTemplateColumns:'1fr 64px 64px 64px', gap:8, padding:'8px 0', borderBottom:'1px solid var(--border-subtle)' }}>
                  <div style={{ fontFamily:'var(--font-body)', fontSize:12, color:'var(--fog-200)', overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{PAGE_LABELS[d.page]||d.page||'Home'}</div>
                  <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:12, color:'var(--text-muted)', textAlign:'right' }}>{d.views.toLocaleString()}</div>
                  <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:12, color:C.blue, textAlign:'right' }}>{d.joins.toLocaleString()}</div>
                  <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:12, color:C.accent, textAlign:'right' }}>{d.rate}%</div>
                </div>
              ))}
              {pageConversions.length === 0 && <Empty />}
            </div>
          </Card>
        </div>
      </div>
    );
  }

  // ── Flow tab ──────────────────────────────────────────────────────────────
  function FlowTab({ stats, derived }) {
    const { filledHours, filledJoinDow } = derived;

    const hourCfg2 = {
      type: 'bar',
      data: {
        labels: filledHours.map(d => d.hour + ':00'),
        datasets: [{ label:'Join clicks', data:filledHours.map(d => d.count), backgroundColor:C.blue, borderRadius:4 }],
      },
      options: { responsive:true, maintainAspectRatio:false, plugins:{legend:{display:false}}, scales:{
        x:{grid:{display:false},ticks:{color:C.muted,maxTicksLimit:12}},
        y:{grid:{color:C.grid},beginAtZero:true,ticks:{color:C.muted}},
      }},
    };

    const joinDowCfg2 = {
      type: 'bar',
      data: {
        labels: filledJoinDow.map(d => d.label),
        datasets: [{ label:'Join clicks', data:filledJoinDow.map(d => d.count), backgroundColor:C.blue, borderRadius:4 }],
      },
      options: { responsive:true, maintainAspectRatio:false, plugins:{legend:{display:false}}, scales:{
        x:{grid:{display:false},ticks:{color:C.muted}},
        y:{grid:{color:C.grid},beginAtZero:true,ticks:{color:C.muted}},
      }},
    };

    return (
      <div>
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:24, marginBottom:24 }}>
          <Card title="Join Clicks by Hour of Day">
            <ChartCanvas cfg={hourCfg2} height={150} />
          </Card>
          <Card title="Join Clicks by Day of Week">
            <ChartCanvas cfg={joinDowCfg2} height={150} />
          </Card>
        </div>

        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:24 }}>
          <Card title="Most Navigated To">
            <div style={{ display:'flex', flexDirection:'column', gap:0 }}>
              {(stats.topDestinations || []).map(d => (
                <div key={d.page} style={{ display:'flex', justifyContent:'space-between', alignItems:'center', padding:'8px 0', borderBottom:'1px solid var(--border-subtle)' }}>
                  <span style={{ fontFamily:'var(--font-body)', fontSize:13, color:'var(--fog-200)' }}>{PAGE_LABELS[d.page] || d.page || 'Home'}</span>
                  <span style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:13, color:C.accent }}>{d.count.toLocaleString()}</span>
                </div>
              ))}
              {!(stats.topDestinations || []).length && <Empty />}
            </div>
          </Card>

          <Card title="Click Paths (from → to)">
            <div style={{ display:'flex', flexDirection:'column', gap:0 }}>
              {(stats.navFlows || []).slice(0,12).map((d, i) => {
                let to = 'home';
                try { to = JSON.parse(d.data).to || 'home'; } catch {}
                return (
                  <div key={i} style={{ display:'flex', justifyContent:'space-between', alignItems:'center', padding:'7px 0', borderBottom:'1px solid var(--border-subtle)', gap:8 }}>
                    <span style={{ fontFamily:'var(--font-body)', fontSize:12, color:'var(--text-muted)', flexShrink:0 }}>{PAGE_LABELS[d.from_page]||d.from_page||'Home'}</span>
                    <span style={{ color:'var(--text-faint)', fontSize:11 }}>→</span>
                    <span style={{ fontFamily:'var(--font-body)', fontSize:12, color:'var(--fog-200)', flex:1 }}>{PAGE_LABELS[to]||to||'Home'}</span>
                    <span style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:12, color:C.accent, flexShrink:0 }}>{d.count}</span>
                  </div>
                );
              })}
              {!(stats.navFlows || []).length && <Empty />}
            </div>
          </Card>
        </div>
      </div>
    );
  }

  // ── Contacts tab ──────────────────────────────────────────────────────────
  const SOURCE_LABEL = {
    timetable:    'Timetable',
    exit_intent:  'Exit intent',
    pricing_cta:  'Pricing page',
    unknown:      'Unknown',
  };

  function ContactsTab({ stats, derived }) {
    const { filledContactDays } = derived;

    const contactCfg = {
      type: 'bar',
      data: {
        labels: filledContactDays.map(d => d.label),
        datasets: [{
          data: filledContactDays.map(d => d.count),
          backgroundColor: C.accentDim, borderColor: C.accent, borderWidth: 1, borderRadius: 4,
        }],
      },
      options: {
        responsive: true, maintainAspectRatio: false,
        plugins: { legend:{ display:false } },
        scales: {
          x: { grid:{ display:false }, ticks:{ maxTicksLimit:8, color:C.muted } },
          y: { grid:{ color:C.grid }, beginAtZero:true, ticks:{ stepSize:1, color:C.muted } },
        },
      },
    };

    return (
      <div>
        <div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fit,minmax(158px,1fr))', gap:14, marginBottom:24 }}>
          <Stat label="Total Enquiries" value={stats.contactSubmits.toLocaleString()} accent />
          <Stat label="Tour / Class Leads" value={(stats.leadCaptures||[]).length.toLocaleString()} />
        </div>

        {(stats.leadCaptures||[]).length > 0 && (
          <Card title="Tour & Class Booking Leads" style={{ marginBottom:24 }}>
            <div style={{ display:'flex', flexDirection:'column', gap:0 }}>
              {(stats.leadCaptures||[]).map((ev, i) => {
                let d = {};
                try { const p = JSON.parse(ev.data); d = typeof p === 'string' ? JSON.parse(p) : p; } catch(e) {}
                const srcLabel = SOURCE_LABEL[ev.source] || ev.source || '—';
                const ctxLabel = d.context && d.context !== 'tour' ? d.context : null;
                return (
                  <div key={i} style={{ display:'flex', alignItems:'center', gap:14, padding:'10px 0', borderBottom:'1px solid var(--border-subtle)', flexWrap:'wrap' }}>
                    <span style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10, letterSpacing:'0.08em', textTransform:'uppercase', color:C.blue, background:'rgba(96,165,250,0.1)', border:'1px solid rgba(96,165,250,0.25)', borderRadius:99, padding:'3px 10px', whiteSpace:'nowrap' }}>{srcLabel}{ctxLabel ? ' · '+ctxLabel : ''}</span>
                    <span style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:13, color:'#fff' }}>{d.name||'—'}</span>
                    <span style={{ fontFamily:'var(--font-body)', fontSize:13, color:C.accent }}>{d.phone||'—'}</span>
                    <span style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--text-faint)', marginLeft:'auto', whiteSpace:'nowrap' }}>{ev.created_at?.replace('T',' ').slice(0,16)}</span>
                  </div>
                );
              })}
            </div>
          </Card>
        )}

        <Card title="Enquiries Over Time — Last 30 Days" style={{ marginBottom:24 }}>
          {filledContactDays.some(d => d.count > 0)
            ? <ChartCanvas cfg={contactCfg} height={140} />
            : <Empty text="No enquiries in the last 30 days" />}
        </Card>

        <Card title="Contact Enquiries">
          <div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fill,minmax(300px,1fr))', gap:12 }}>
            {stats.contactLog.map((ev, i) => {
              let d = {};
              try { const p = JSON.parse(ev.data); d = typeof p === 'string' ? JSON.parse(p) : p; } catch(e) {}
              const subject = encodeURIComponent(`Website enquiry from ${d.name||'a visitor'}`);
              const body    = encodeURIComponent(`Name: ${d.name||'—'}\nEmail: ${d.email||'—'}${d.phone?`\nPhone: ${d.phone}`:''}\nDate: ${ev.created_at?.slice(0,10)||'—'}\n\nMessage:\n${d.message||'—'}`);
              return (
                <div key={i} style={{ background:'var(--surface-raised)', border:'1px solid var(--border-subtle)', borderRadius:10, padding:'14px 16px', display:'flex', flexDirection:'column', gap:6 }}>
                  <div style={{ display:'flex', justifyContent:'space-between', alignItems:'flex-start', gap:8 }}>
                    <div style={{ display:'flex', flexDirection:'column', gap:4, flex:1 }}>
                      <span style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:13, color:'#fff' }}>{d.name||'—'}</span>
                      {d.email && <span style={{ fontFamily:'var(--font-body)', fontSize:12, color:C.accent }}>{d.email}</span>}
                      {d.phone && <span style={{ fontFamily:'var(--font-body)', fontSize:12, color:C.blue }}>{d.phone}</span>}
                    </div>
                    <div style={{ display:'flex', alignItems:'center', gap:8, flexShrink:0 }}>
                      <span style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--text-faint)' }}>{ev.created_at?.slice(0,10)}</span>
                      <a href={`mailto:?subject=${subject}&body=${body}`} style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10, letterSpacing:'0.06em', textTransform:'uppercase', color:C.accent, background:'rgba(114,221,158,0.1)', border:'1px solid rgba(114,221,158,0.3)', borderRadius:99, padding:'3px 10px', textDecoration:'none', whiteSpace:'nowrap' }}>Share ↗</a>
                    </div>
                  </div>
                  {d.message && <span style={{ fontFamily:'var(--font-body)', fontSize:13, color:'var(--text-muted)', lineHeight:1.6 }}>{d.message}</span>}
                </div>
              );
            })}
            {stats.contactLog.length === 0 && <Empty text="No enquiries yet" />}
          </div>
        </Card>
      </div>
    );
  }

  // ── Activity tab ──────────────────────────────────────────────────────────
  function ActivityTab({ stats }) {
    return (
      <Card title="Recent Activity (Last 20 Events)">
        <div style={{ display:'flex', flexDirection:'column' }}>
          {stats.recentEvents.map((ev, i) => (
            <div key={i} style={{ display:'flex', alignItems:'center', gap:14, padding:'10px 0', borderBottom:'1px solid var(--border-subtle)' }}>
              <span style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10, letterSpacing:'0.08em', textTransform:'uppercase', color:C.accent, background:'rgba(114,221,158,0.1)', border:'1px solid rgba(114,221,158,0.2)', borderRadius:99, padding:'3px 10px', whiteSpace:'nowrap' }}>{ev.event_type.replace(/_/g,' ')}</span>
              <span style={{ fontFamily:'var(--font-body)', fontSize:13, color:'var(--fog-200)', flex:1 }}>{PAGE_LABELS[ev.page]||ev.page||'Home'}{ev.data ? ` — ${ev.data}` : ''}</span>
              <span style={{ fontFamily:'var(--font-body)', fontSize:11, color:'var(--text-faint)', whiteSpace:'nowrap' }}>{ev.created_at?.replace('T',' ').slice(0,16)}</span>
            </div>
          ))}
          {stats.recentEvents.length === 0 && <Empty text="No activity yet" />}
        </div>
      </Card>
    );
  }

  // ── Main component ────────────────────────────────────────────────────────
  function AdminPage() {
    const [authed,     setAuthed]     = React.useState(() => localStorage.getItem('otl_admin') === '1');
    const [pw,         setPw]         = React.useState('');
    const [error,      setError]      = React.useState('');
    const [stats,      setStats]      = React.useState(null);
    const [loading,    setLoading]    = React.useState(false);
    const [fetchError, setFetchError] = React.useState('');
    const [tab,        setTab]        = React.useState('overview');
    const [lastSeen,   setLastSeen]   = React.useState(() => localStorage.getItem('otl_contacts_seen') || '');

    function login(e) {
      e.preventDefault();
      if (pw === PASSWORD) { localStorage.setItem('otl_admin', '1'); setAuthed(true); setError(''); }
      else setError('Incorrect password.');
    }

    function loadStats() {
      setLoading(true); setFetchError('');
      fetch(WORKER + '/admin/stats', { headers: { Authorization: 'Bearer ' + PASSWORD } })
        .then(r => { if (!r.ok) throw new Error('Status ' + r.status); return r.json(); })
        .then(d => { setStats(d); setLoading(false); })
        .catch(e => { setFetchError('Could not load stats: ' + e.message); setLoading(false); });
    }

    React.useEffect(() => { if (authed) loadStats(); }, [authed]);

    if (!authed) return (
      <div style={{ minHeight:'80vh', display:'flex', alignItems:'center', justifyContent:'center', padding:24 }}>
        <div style={{ background:'var(--surface-card)', border:'1px solid var(--border-subtle)', borderRadius:20, padding:'40px 36px', width:'100%', maxWidth:380, display:'flex', flexDirection:'column', gap:20 }}>
          <div>
            <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:11, letterSpacing:'0.16em', textTransform:'uppercase', color:C.accent, marginBottom:8 }}>On The Limit</div>
            <h2 style={{ margin:0, fontFamily:'var(--font-display)', fontWeight:800, textTransform:'uppercase', fontSize:26, color:'#fff' }}>Admin</h2>
          </div>
          <form onSubmit={login} style={{ display:'flex', flexDirection:'column', gap:12 }}>
            <input type="password" name="password" autoComplete="current-password" placeholder="Password" value={pw}
              onChange={e => setPw(e.target.value)}
              style={{ fontFamily:'var(--font-body)', fontSize:15, background:'var(--surface-raised)', border:'1px solid var(--border-subtle)', borderRadius:10, padding:'14px 16px', color:'#fff', outline:'none', width:'100%', boxSizing:'border-box' }}
            />
            {error && <div style={{ fontFamily:'var(--font-body)', fontSize:13, color:'#f87171' }}>{error}</div>}
            <button type="submit" style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:13, letterSpacing:'0.06em', textTransform:'uppercase', background:C.accent, color:'#0d0d0d', border:'none', borderRadius:99, padding:'14px 24px', cursor:'pointer' }}>Sign In</button>
          </form>
        </div>
      </div>
    );

    if (loading || !stats) return (
      <div style={{ minHeight:'80vh', display:'flex', alignItems:'center', justifyContent:'center' }}>
        <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:13, letterSpacing:'0.1em', textTransform:'uppercase', color:'var(--text-muted)' }}>Loading…</div>
      </div>
    );

    if (fetchError) return (
      <div style={{ minHeight:'80vh', display:'flex', alignItems:'center', justifyContent:'center', padding:24 }}>
        <div style={{ background:'var(--surface-card)', border:'1px solid var(--border-subtle)', borderRadius:16, padding:'36px 32px', maxWidth:400, textAlign:'center', display:'flex', flexDirection:'column', gap:16 }}>
          <div style={{ fontFamily:'var(--font-display)', fontWeight:800, fontSize:16, color:'#f87171' }}>Failed to load stats</div>
          <div style={{ fontFamily:'var(--font-body)', fontSize:13, color:'var(--text-muted)', lineHeight:1.6 }}>{fetchError}</div>
          <button onClick={loadStats} style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:12, letterSpacing:'0.06em', textTransform:'uppercase', background:C.accent, color:'#0d0d0d', border:'none', borderRadius:99, padding:'12px 24px', cursor:'pointer' }}>Try Again</button>
        </div>
      </div>
    );

    // ── Derived values ────────────────────────────────────────────────────
    const joinRate       = stats.pageViews > 0 ? ((stats.joinClicks / stats.pageViews) * 100).toFixed(1) : '0.0';
    const totalClassTaps = (stats.topClasses || []).reduce((a, c) => a + c.count, 0);
    const filledViews    = fillDays(stats.dailyViews);
    const filledJoins    = fillDays(stats.dailyJoinClicks);
    const filledHours    = fillHours(stats.joinByHour);
    const filledPVHours  = fillHours(stats.hourlyPageviews || []);
    const filledDow      = fillDow(stats.pageviewsByDayOfWeek || []);
    const filledJoinDow  = fillDow(stats.joinClicksByDayOfWeek || []);
    const filledContactDays = fillDays(stats.dailyContactSubmits || []);

    // Averages & peaks
    const totalViews30   = filledViews.reduce((a, d) => a + d.count, 0);
    const totalJoins30   = filledJoins.reduce((a, d) => a + d.count, 0);
    const avgDailyViews  = Math.round(totalViews30 / 30);
    const avgWeeklyViews = Math.round((totalViews30 / 30) * 7);
    const avgDailyJoins  = (totalJoins30 / 30).toFixed(1);
    const avgWeeklyJoins = Math.round((totalJoins30 / 30) * 7);
    const avg7           = Math.round(filledViews.slice(-7).reduce((a, d) => a + d.count, 0) / 7);
    const bestDay        = filledViews.reduce((best, d) => d.count > best.count ? d : best, { count: 0, label: '—' });
    const peakDowEntry   = filledDow.reduce((best, d) => d.count > best.count ? d : best, { count: 0, dow: -1 });
    const peakDow        = peakDowEntry.dow >= 0 ? DOW[peakDowEntry.dow] : '—';
    const peakPVHour     = filledPVHours.reduce((best, d) => d.count > best.count ? d : best, { count: 0, hour: -1 });
    const peakHour       = peakPVHour.hour >= 0 ? `${peakPVHour.hour}:00` : '—';
    const avgEnquiriesPerWeek = ((stats.contactSubmits / 30) * 7).toFixed(1);

    const joinMap        = Object.fromEntries((stats.topJoinPages || []).map(d => [d.page, d.count]));
    const pageConversions = (stats.topPages || [])
      .filter(d => d.count > 0)
      .map(d => ({ page: d.page, views: d.count, joins: joinMap[d.page] || 0, rate: joinMap[d.page] ? ((joinMap[d.page] / d.count) * 100).toFixed(1) : '0.0' }))
      .sort((a, b) => parseFloat(b.rate) - parseFloat(a.rate));

    const derived = { joinRate, totalClassTaps, filledViews, filledJoins, avg7, filledHours, filledPVHours, filledDow, filledJoinDow, filledContactDays, pageConversions, avgDailyViews, avgWeeklyViews, avgDailyJoins, avgWeeklyJoins, bestDay, peakDow, peakHour, avgEnquiriesPerWeek };

    const allContacts = [...(stats.leadCaptures || []), ...(stats.contactLog || [])];
    const newCount = lastSeen
      ? allContacts.filter(c => c.created_at > lastSeen).length
      : allContacts.length;

    function handleTabClick(id) {
      setTab(id);
      if (id === 'contacts') {
        const now = new Date().toISOString();
        localStorage.setItem('otl_contacts_seen', now);
        setLastSeen(now);
      }
    }

    const TABS = [
      { id:'overview',   label:'Overview' },
      { id:'content',    label:'Pages & Content' },
      { id:'conversion', label:'Conversion' },
      { id:'flow',       label:'Flow' },
      { id:'contacts',   label:'Contacts', badge: newCount },
      { id:'activity',   label:'Activity' },
    ];

    const tabStyle = (t) => ({
      fontFamily:'var(--font-display)', fontWeight:700, fontSize:11, letterSpacing:'0.06em', textTransform:'uppercase',
      background: tab === t ? C.accent : 'var(--surface-card)',
      color:      tab === t ? '#0d0d0d' : 'var(--text-muted)',
      border:     tab === t ? 'none'    : '1px solid var(--border-subtle)',
      borderRadius:99, padding:'9px 20px', cursor:'pointer', position:'relative',
    });

    return (
      <div style={{ maxWidth:1100, margin:'0 auto', padding:'48px 24px' }}>
        <div style={{ marginBottom:32, display:'flex', alignItems:'flex-end', justifyContent:'space-between', flexWrap:'wrap', gap:16 }}>
          <div>
            <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:11, letterSpacing:'0.16em', textTransform:'uppercase', color:C.accent, marginBottom:8 }}>On The Limit</div>
            <h1 style={{ margin:0, fontFamily:'var(--font-display)', fontWeight:800, textTransform:'uppercase', fontSize:'clamp(28px,4vw,42px)', color:'#fff', letterSpacing:'-0.02em' }}>Analytics</h1>
          </div>
          <button onClick={loadStats} style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:11, letterSpacing:'0.06em', textTransform:'uppercase', background:'var(--surface-card)', color:'var(--fog-200)', border:'1px solid var(--border-subtle)', borderRadius:99, padding:'9px 18px', cursor:'pointer' }}>↻ Refresh</button>
        </div>

        <div style={{ display:'flex', gap:8, marginBottom:36, flexWrap:'wrap' }}>
          {TABS.map(t => (
            <button key={t.id} style={tabStyle(t.id)} onClick={() => handleTabClick(t.id)}>
              {t.label}
              {t.badge > 0 && tab !== t.id && (
                <span style={{ marginLeft:7, background:'#ef4444', color:'#fff', fontFamily:'var(--font-display)', fontWeight:800, fontSize:10, borderRadius:99, padding:'1px 6px', verticalAlign:'middle' }}>
                  {t.badge}
                </span>
              )}
            </button>
          ))}
        </div>

        {tab === 'overview'   && <OverviewTab    stats={stats} derived={derived} />}
        {tab === 'content'    && <ContentTab     stats={stats} />}
        {tab === 'conversion' && <ConversionTab  stats={stats} derived={derived} />}
        {tab === 'flow'       && <FlowTab        stats={stats} derived={derived} />}
        {tab === 'contacts'   && <ContactsTab    stats={stats} derived={derived} />}
        {tab === 'activity'   && <ActivityTab    stats={stats} />}

        <div style={{ marginTop:56, borderTop:'1px solid var(--border-subtle)', paddingTop:40 }}>
          <div style={{ fontFamily:'var(--font-display)', fontWeight:700, fontSize:10, letterSpacing:'0.16em', textTransform:'uppercase', color:'var(--text-faint)', textAlign:'center', marginBottom:24 }}>Proud Partners</div>
          <div style={{ display:'flex', gap:20, justifyContent:'center', flexWrap:'wrap' }}>
            {[
              { src:'site/partner-elite.jpg', alt:'Elite Physical Medicine', href:'https://www.elitephysicalmedicine.co.uk/', h:56 },
              { src:'site/partner-mummy.jpg', alt:'The Mummy MOT',           href:'https://themummymot.com/',               h:56 },
              { src:'site/partner-west6.jpg', alt:'The West 6',              href:'https://www.thewest6.com/',              h:72 },
            ].map(({ src, alt, href, h }) => (
              <a key={alt} href={href} target="_blank" rel="noopener noreferrer"
                style={{ background:'#fff', borderRadius:12, padding:'10px 18px', display:'flex', alignItems:'center', justifyContent:'center', height:96, width:160, boxShadow:'0 1px 6px rgba(0,0,0,0.18)', textDecoration:'none', flexShrink:0 }}>
                <img src={src} alt={alt} loading="lazy" decoding="async" style={{ height:h, width:'auto', maxWidth:130, objectFit:'contain', display:'block' }} />
              </a>
            ))}
          </div>
        </div>

        <div style={{ marginTop:32, textAlign:'right' }}>
          <button onClick={() => { localStorage.removeItem('otl_admin'); setAuthed(false); setPw(''); setStats(null); }}
            style={{ fontFamily:'var(--font-body)', fontSize:12, color:'var(--text-faint)', background:'none', border:'none', cursor:'pointer' }}>Sign out</button>
        </div>
      </div>
    );
  }

  window.OTL_AdminPage = AdminPage;
})();
