// ───────────────────────────────────────────────────────────── AUDIENCE INSIGHTS
// astro.audience_insights — age_distribution, gender_distribution, top_countries,
// top_cities, peak_listening_hours, peak_listening_days, avg_listen_duration_seconds,
// completion_rate, skip_rate, save_rate, discovery_sources, device_distribution.
//
// Page surfaces:
//   1. Overview KPIs (audience size, completion, skip, save)
//   2. Demographics — age × gender stacked bars
//   3. Geography — top countries + cities table
//   4. Engagement — completion / skip / save curve, listen duration
//   5. Listening rhythm — 24h × 7d heatmap
//   6. Discovery — pie chart of sources (algorithm / playlist / search / library / other)
//   7. Devices — mobile / desktop / smart speaker / web / TV breakdown

(function(){
const { useState, useMemo } = React;

// ─────────────────────────── seeded RNG
function seed(s){let h=2166136261;for(let i=0;i<s.length;i++){h^=s.charCodeAt(i);h=Math.imul(h,16777619);}return ()=>((h=Math.imul(h^(h>>>13),3432918353))>>>0)/4294967296;}
function fmtBig(n){ if(!n) return '—'; if(n>=1e9) return (n/1e9).toFixed(1)+'B'; if(n>=1e6) return (n/1e6).toFixed(1)+'M'; if(n>=1e3) return (n/1e3).toFixed(0)+'k'; return String(n); }
function fmtPct(n){ return (n*100).toFixed(1) + '%'; }

// ─────────────────────────── taxonomy
const AGE_BUCKETS = ['13–17','18–22','23–27','28–34','35–44','45–59','60+'];
const GENDERS = [
  { id:'female', label:'Female', color:'#7a4a8a' },
  { id:'male',   label:'Male',   color:'#3a4a8a' },
  { id:'nonbin', label:'Non-binary / undisclosed', color:'#7a6e2d' },
];
const PLATFORMS = [
  { id:'spotify',     name:'Spotify',         color:'#3a6a3a' },
  { id:'apple_music', name:'Apple Music',     color:'#a04432' },
  { id:'amazon',      name:'Amazon Music',    color:'#3a4a8a' },
  { id:'tidal',       name:'Tidal',           color:'#000000' },
  { id:'deezer',      name:'Deezer',          color:'#5a3a4a' },
  { id:'youtube',     name:'YouTube Music',   color:'#a04432' },
];
// Top streaming markets — curated to the ~15 territories that drive >85% of
// global streaming income. Names are sourced from REF.territoryByIso2 so the
// label and emoji_flag match the Directory rather than drifting.
const TOP_COUNTRY_ISOS = ['US','GB','DE','BR','MX','CA','JP','AU','FR','NL','SE','IT','ES','PL','IN'];
const TOP_COUNTRIES = TOP_COUNTRY_ISOS.map(iso => {
  const t = window.REF && window.REF.ready && window.REF.territoryByIso2 && window.REF.territoryByIso2.get(iso);
  return { iso, name: (t && t.common_name) || iso, flag: (t && t.emoji_flag) || '' };
});
const CITIES = [
  { name:'Los Angeles, US' },{ name:'New York, US' },{ name:'London, GB' },
  { name:'Mexico City, MX' },{ name:'São Paulo, BR' },{ name:'Berlin, DE' },
  { name:'Toronto, CA' },{ name:'Tokyo, JP' },{ name:'Paris, FR' },
  { name:'Sydney, AU' },{ name:'Madrid, ES' },{ name:'Stockholm, SE' },
  { name:'Amsterdam, NL' },{ name:'Chicago, US' },{ name:'Atlanta, US' },
];
const DISCOVERY = [
  { id:'algorithm', label:'Algorithm',     color:'#3a6a3a', desc:'Discover Weekly · Release Radar · For You' },
  { id:'playlist',  label:'Editorial',     color:'#c79538', desc:'Editorial playlists' },
  { id:'library',   label:'Listener',      color:'#3a4a8a', desc:'Saved · Library · Direct play' },
  { id:'search',    label:'Search',        color:'#7a4a8a', desc:'Direct artist or track search' },
  { id:'social',    label:'Social',        color:'#a04432', desc:'Shared link · TikTok · IG' },
  { id:'radio',     label:'Radio',         color:'#5a3a4a', desc:'Artist radio · station' },
  { id:'other',     label:'Other',         color:'var(--ink-3)', desc:'External · podcast · sync' },
];
const DEVICES = [
  { id:'mobile',  label:'Mobile',        color:'#3a6a3a' },
  { id:'desktop', label:'Desktop',       color:'#3a4a8a' },
  { id:'web',     label:'Web player',    color:'#7a4a8a' },
  { id:'speaker', label:'Smart speaker', color:'#c79538' },
  { id:'tv',      label:'Connected TV',  color:'#7a6e2d' },
  { id:'auto',    label:'Automotive',    color:'#a04432' },
];

// ─────────────────────────── synthesise insights for an entity
function buildInsights(entityKey, entityType) {
  const r = seed('aud_'+entityKey);

  // Audience size
  const monthlyListeners = entityType === 'release' ? Math.floor(50000 + r() * 8000000)
    : entityType === 'recording' ? Math.floor(20000 + r() * 3500000)
    : Math.floor(80000 + r() * 12000000);

  // Age distribution — pick a centroid, build skewed dist
  const centroidAge = 1 + Math.floor(r() * 4); // 18-22 .. 35-44
  const ageDist = AGE_BUCKETS.map((b, i) => {
    const dist = Math.abs(i - centroidAge);
    const w = Math.exp(-dist / 1.7) * (0.7 + r() * 0.3);
    return { bucket: b, weight: w };
  });
  const ageSum = ageDist.reduce((s,a) => s + a.weight, 0);
  ageDist.forEach(a => a.share = a.weight / ageSum);

  // Gender — biased toward one
  const gBias = r();
  const gShares = gBias < 0.4
    ? [0.62 + r()*0.1, 0.34 - r()*0.1, 0.04]
    : gBias < 0.75
      ? [0.45 + r()*0.1, 0.50 - r()*0.05, 0.05]
      : [0.30, 0.66, 0.04];
  const genderDist = GENDERS.map((g, i) => ({...g, share: gShares[i]}));
  const gNorm = genderDist.reduce((s,g) => s + g.share, 0);
  genderDist.forEach(g => g.share = g.share / gNorm);

  // Geography — pick 8 countries with weights (US-heavy or international)
  const intl = r() < 0.5;
  const countryShuffle = [...TOP_COUNTRIES].sort(() => r() - 0.5);
  const countries = countryShuffle.slice(0, 12).map((c, i) => {
    let weight;
    if (intl) {
      weight = Math.exp(-i / 5) * (0.7 + r() * 0.5);
    } else {
      weight = i === 0 ? 5 + r() : Math.exp(-i / 3) * (0.6 + r() * 0.4);
    }
    return { ...c, weight };
  });
  const cSum = countries.reduce((s,c) => s + c.weight, 0);
  countries.forEach(c => c.share = c.weight / cSum);
  countries.sort((a,b) => b.share - a.share);

  // Cities — top 10
  const cities = [...CITIES].sort(() => r() - 0.5).slice(0, 10).map((c, i) => {
    const w = Math.exp(-i / 3.5) * (0.6 + r() * 0.5);
    return { ...c, weight: w };
  });
  const ciSum = cities.reduce((s,c) => s + c.weight, 0);
  cities.forEach(c => c.share = c.weight / ciSum);
  cities.sort((a,b) => b.share - a.share);

  // Engagement
  const completion = 0.42 + r() * 0.4;          // 42-82%
  const skipRate = 0.08 + r() * 0.22;            // 8-30%
  const saveRate = 0.012 + r() * 0.06;           // 1.2-7.2%
  const avgDuration = Math.floor(80 + r() * 180); // 80-260s

  // Discovery sources
  const discoveryWeights = DISCOVERY.map((d, i) => ({
    ...d,
    share: 0,
    weight: i === 0 ? 0.4 + r()*0.25
          : i === 1 ? 0.15 + r()*0.15
          : i === 2 ? 0.12 + r()*0.10
          : i === 3 ? 0.06 + r()*0.06
          : i === 4 ? 0.04 + r()*0.10
          : 0.02 + r()*0.04
  }));
  const dSum = discoveryWeights.reduce((s,d) => s + d.weight, 0);
  discoveryWeights.forEach(d => d.share = d.weight / dSum);

  // Devices
  const deviceWeights = DEVICES.map((d, i) => ({
    ...d,
    weight: i === 0 ? 0.55 + r()*0.18
          : i === 1 ? 0.12 + r()*0.10
          : i === 2 ? 0.06 + r()*0.06
          : i === 3 ? 0.05 + r()*0.05
          : i === 4 ? 0.03 + r()*0.04
          : 0.02 + r()*0.04
  }));
  const devSum = deviceWeights.reduce((s,d) => s + d.weight, 0);
  deviceWeights.forEach(d => d.share = d.weight / devSum);

  // Peak listening 24×7 heatmap
  const heatmap = [];
  // Centroid: day=4 (Fri), hour=20 (8pm)
  const dayCentroid = 3 + Math.floor(r() * 3);
  const hourCentroid = 17 + Math.floor(r() * 6);
  for (let d = 0; d < 7; d++) {
    for (let h = 0; h < 24; h++) {
      const dDist = Math.min(Math.abs(d - dayCentroid), 7 - Math.abs(d - dayCentroid));
      const hDist = Math.min(Math.abs(h - hourCentroid), 24 - Math.abs(h - hourCentroid));
      const v = Math.exp(-dDist/2) * Math.exp(-hDist/4) * (0.7 + r() * 0.6);
      heatmap.push({ day: d, hour: h, value: v });
    }
  }
  const hMax = Math.max(...heatmap.map(c => c.value));
  heatmap.forEach(c => c.norm = c.value / hMax);

  // Platform breakdown — for header
  const platformShare = PLATFORMS.map(p => ({
    ...p,
    weight: p.id === 'spotify' ? 0.55 + r()*0.15
         : p.id === 'apple_music' ? 0.18 + r()*0.10
         : p.id === 'amazon' ? 0.08 + r()*0.05
         : 0.02 + r()*0.05
  }));
  const pSum = platformShare.reduce((s,p) => s + p.weight, 0);
  platformShare.forEach(p => p.share = p.weight / pSum);

  return {
    monthlyListeners,
    ageDist, genderDist,
    countries, cities,
    completion, skipRate, saveRate, avgDuration,
    discoveryWeights, deviceWeights,
    heatmap, platformShare,
    period_start: '2025-12-01', period_end: '2026-04-30',
  };
}

// ─────────────────────────── UI bits
function CountryFlag({ code }) {
  if (!code || code.length !== 2) return null;
  const A = 0x1F1E6;
  return <span style={{fontSize:14}}>
    {String.fromCodePoint(A + code.charCodeAt(0) - 65) + String.fromCodePoint(A + code.charCodeAt(1) - 65)}
  </span>;
}

function Stat({ label, value, sub, accent, last }) {
  return (
    <div style={{padding:'18px 22px',borderRight: last ? 'none' : '1px solid var(--rule)',flex:1,minWidth:0}}>
      <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.12em',color:'var(--ink-3)',marginBottom:8,minHeight:22,display:'flex',alignItems:'flex-end'}}>{label}</div>
      <div className="ff-display" style={{fontSize:28,fontWeight:600,letterSpacing:'-0.02em',lineHeight:1,color:accent||'var(--ink)'}}>{value}</div>
      <div style={{fontSize:11,color:'var(--ink-3)',marginTop:6,letterSpacing:'-0.005em'}}>{sub}</div>
    </div>
  );
}

function Section({ title, sub, children, right }) {
  return (
    <section style={{marginBottom:30,border:'1px solid var(--rule)',background:'var(--bg)'}}>
      <header style={{padding:'14px 20px',borderBottom:'1px solid var(--rule)',display:'flex',justifyContent:'space-between',alignItems:'flex-end',gap:12,flexWrap:'wrap'}}>
        <div>
          <h2 className="ff-display" style={{fontSize:18,fontWeight:600,letterSpacing:'-0.02em',margin:0,lineHeight:1.1}}>{title}</h2>
          {sub && <div style={{fontSize:11,color:'var(--ink-3)',marginTop:4,letterSpacing:'-0.005em'}}>{sub}</div>}
        </div>
        {right}
      </header>
      <div style={{padding:'18px 20px'}}>{children}</div>
    </section>
  );
}

// Stacked horizontal bar
function StackedBar({ segments, height=24 }) {
  const total = segments.reduce((s,x) => s + x.share, 0);
  return (
    <div style={{display:'flex',height,width:'100%',background:'var(--bg-2)',overflow:'hidden'}}>
      {segments.map((s, i) => (
        <div key={i} style={{flex: s.share / total, background: s.color || 'var(--ink-2)',
          display:'flex',alignItems:'center',justifyContent:'center'}}
          title={`${s.label}: ${(s.share*100).toFixed(1)}%`}>
          {s.share > 0.10 && (
            <span className="ff-mono" style={{fontSize:10,color:'#fff',fontWeight:600,letterSpacing:'.02em'}}>
              {(s.share*100).toFixed(0)}%
            </span>
          )}
        </div>
      ))}
    </div>
  );
}

// 24x7 heatmap
function Heatmap({ data }) {
  const cellW = 28, cellH = 16;
  const days = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'];
  return (
    <div style={{overflowX:'auto'}}>
      <div style={{display:'inline-block',minWidth:24*cellW + 60}}>
        {/* Hour labels */}
        <div style={{display:'flex',marginLeft:48,marginBottom:6}}>
          {[0,3,6,9,12,15,18,21].map(h => (
            <div key={h} style={{width: cellW*3, fontSize:10,color:'var(--ink-3)',letterSpacing:'.02em'}} className="ff-mono">
              {h.toString().padStart(2,'0')}:00
            </div>
          ))}
        </div>
        {/* Rows */}
        {days.map((day, di) => (
          <div key={di} style={{display:'flex',alignItems:'center',marginBottom:2}}>
            <div className="ff-mono" style={{width:48,fontSize:10,color:'var(--ink-3)',letterSpacing:'.04em'}}>{day}</div>
            <div style={{display:'flex',gap:1}}>
              {Array.from({length:24}, (_, h) => {
                const cell = data.find(c => c.day === di && c.hour === h);
                const v = cell ? cell.norm : 0;
                const bg = `rgba(58,106,58, ${0.06 + v * 0.85})`;
                return (
                  <div key={h} style={{width: cellW-1, height: cellH, background: bg,
                    display:'flex',alignItems:'center',justifyContent:'center'}}
                    title={`${day} ${h.toString().padStart(2,'0')}:00 — ${(v*100).toFixed(0)}%`}/>
                );
              })}
            </div>
          </div>
        ))}
        <div style={{display:'flex',gap:8,marginTop:14,alignItems:'center',marginLeft:48}}>
          <span className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.08em'}}>LESS</span>
          <div style={{display:'flex',gap:1}}>
            {[0.1, 0.3, 0.5, 0.7, 0.9].map((v,i) => (
              <div key={i} style={{width:18,height:10,background:`rgba(58,106,58, ${0.06 + v * 0.85})`}}/>
            ))}
          </div>
          <span className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.08em'}}>MORE</span>
        </div>
      </div>
    </div>
  );
}

// Donut for discovery + devices
function Donut({ segments, size=180, label, sublabel }) {
  const cx = size/2, cy = size/2;
  const r = size*0.42, rIn = size*0.28;
  const total = segments.reduce((s,x) => s + x.share, 0);
  let acc = 0;
  const arcs = segments.map(s => {
    const startAngle = (acc / total) * 2 * Math.PI - Math.PI/2;
    acc += s.share;
    const endAngle = (acc / total) * 2 * Math.PI - Math.PI/2;
    const large = (endAngle - startAngle) > Math.PI ? 1 : 0;
    const x1 = cx + r * Math.cos(startAngle);
    const y1 = cy + r * Math.sin(startAngle);
    const x2 = cx + r * Math.cos(endAngle);
    const y2 = cy + r * Math.sin(endAngle);
    const x3 = cx + rIn * Math.cos(endAngle);
    const y3 = cy + rIn * Math.sin(endAngle);
    const x4 = cx + rIn * Math.cos(startAngle);
    const y4 = cy + rIn * Math.sin(startAngle);
    const d = `M ${x1} ${y1} A ${r} ${r} 0 ${large} 1 ${x2} ${y2} L ${x3} ${y3} A ${rIn} ${rIn} 0 ${large} 0 ${x4} ${y4} Z`;
    return { d, color: s.color };
  });
  return (
    <svg width={size} height={size} style={{flexShrink:0}}>
      {arcs.map((a, i) => <path key={i} d={a.d} fill={a.color}/>)}
      <text x={cx} y={cy - 4} textAnchor="middle" className="ff-display"
        style={{fontSize:18,fontWeight:600,letterSpacing:'-0.02em',fill:'var(--ink)'}}>{label}</text>
      <text x={cx} y={cy + 14} textAnchor="middle" className="ff-mono upper"
        style={{fontSize:9,letterSpacing:'.1em',fill:'var(--ink-3)'}}>{sublabel}</text>
    </svg>
  );
}

// Legend
function Legend({ items }) {
  return (
    <div style={{display:'flex',flexDirection:'column',gap:8,minWidth:220}}>
      {items.map((it, i) => (
        <div key={i} style={{display:'flex',alignItems:'center',gap:10,fontSize:12}}>
          <span style={{width:12,height:12,background:it.color,flexShrink:0}}/>
          <span style={{flex:1,color:'var(--ink-2)',letterSpacing:'-0.005em'}}>{it.label}</span>
          {it.desc && <span style={{fontSize:10,color:'var(--ink-3)',display:'none'}}>{it.desc}</span>}
          <span className="ff-mono num" style={{fontSize:11,color:'var(--ink),fontWeight:600'}}>{(it.share*100).toFixed(1)}%</span>
        </div>
      ))}
    </div>
  );
}

// ─────────────────────────── filter bar
function ScopeBar({ scope, setScope, period, setPeriod }) {
  return (
    <div style={{border:'1px solid var(--rule)',marginBottom:24,padding:'12px 16px',display:'flex',gap:14,alignItems:'center',flexWrap:'wrap'}}>
      <span className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em'}}>SCOPE</span>
      <select value={scope} onChange={e=>setScope(e.target.value)} className="ff-mono"
        style={{fontSize:11,padding:'7px 12px',background:'var(--bg)',border:'1px solid var(--rule)',color:'var(--ink)',minWidth:280}}>
        <option value="catalog">Entire catalog</option>
        <option value="rec_0001">Recording — Slow Burn</option>
        <option value="rec_0002">Recording — Northern Light</option>
        <option value="rel_0001">Release — Half Step EP</option>
        <option value="rel_0002">Release — Daylight Chord</option>
        <option value="profile_001">Artist — Maren Vesper</option>
        <option value="profile_002">Artist — The Inland Sea</option>
      </select>

      <span className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.1em',marginLeft:14}}>PERIOD</span>
      <select value={period} onChange={e=>setPeriod(e.target.value)} className="ff-mono"
        style={{fontSize:11,padding:'7px 12px',background:'var(--bg)',border:'1px solid var(--rule)',color:'var(--ink)'}}>
        <option value="28d">Last 28 days</option>
        <option value="90d">Last 90 days</option>
        <option value="ytd">YTD 2026</option>
        <option value="12m">Last 12 months</option>
      </select>

      <span className="ff-mono" style={{marginLeft:'auto',fontSize:11,color:'var(--ink-3)',letterSpacing:'.04em'}}>
        Sources: Spotify · Apple · Amazon · Tidal · Deezer · YouTube
      </span>
    </div>
  );
}

// ─────────────────────────── main screen
function ScreenAudience({ go }) {
  const [scope, setScope] = useState('catalog');
  const [period, setPeriod] = useState('28d');

  const insights = useMemo(() => {
    const entityType = scope.startsWith('rec_') ? 'recording'
      : scope.startsWith('rel_') ? 'release'
      : scope.startsWith('profile_') ? 'profile'
      : 'catalog';
    return buildInsights(scope + '_' + period, entityType);
  }, [scope, period]);

  // Composite engagement score
  const engageScore = useMemo(() => {
    const c = insights.completion;
    const s = 1 - insights.skipRate;
    const sv = Math.min(insights.saveRate * 8, 1);
    return (c * 0.45 + s * 0.35 + sv * 0.20);
  }, [insights]);

  return (
    <>
      {/* Header — canonical <PageHeader> */}
      <div style={{borderBottom:'1px solid var(--rule)',paddingBottom:24,marginBottom:24}}>
        <PageHeader
          eyebrow="ANALYTICS · AUDIENCE"
          title="audience"
          highlight="audience"
          sub="Demographics, geography, and listening behavior across all DSPs. Drill into any recording, release, or artist for entity-specific insights."
          meta={
            <div className="ff-mono upper" style={{fontSize:10,color:'var(--ink-3)',letterSpacing:'.08em'}}>
              {insights.period_start} → {insights.period_end}
            </div>
          }
        />
      </div>

      {/* Scope + period */}
      <ScopeBar scope={scope} setScope={setScope} period={period} setPeriod={setPeriod}/>

      {/* KPI strip */}
      <div style={{display:'flex',border:'1px solid var(--rule)',marginBottom:30}}>
        <Stat label="MONTHLY LISTENERS" value={fmtBig(insights.monthlyListeners)} sub="distinct accounts (28d)"/>
        <Stat label="COMPLETION" value={fmtPct(insights.completion)} sub="finished playthrough" accent={insights.completion > 0.65 ? '#3a6a3a' : insights.completion > 0.5 ? '#7a6e2d' : '#a04432'}/>
        <Stat label="SKIP RATE" value={fmtPct(insights.skipRate)} sub="under 30 seconds" accent={insights.skipRate < 0.15 ? '#3a6a3a' : insights.skipRate < 0.22 ? '#7a6e2d' : '#a04432'}/>
        <Stat label="SAVE RATE" value={fmtPct(insights.saveRate)} sub="added to library or playlist" accent={'#c79538'}/>
        <Stat label="AVG LISTEN" value={`${insights.avgDuration}s`} sub={`${Math.floor(insights.avgDuration/60)}m ${insights.avgDuration%60}s per session`}/>
        <Stat label="ENGAGEMENT" value={fmtPct(engageScore)} sub="composite score" last accent={'#3a6a3a'}/>
      </div>

      {/* Demographics */}
      <Section title="Demographics" sub="Age × gender breakdown of monthly listeners">
        <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:30}}>
          {/* Age dist */}
          <div>
            <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)',marginBottom:14}}>AGE</div>
            <div style={{display:'flex',flexDirection:'column',gap:8}}>
              {insights.ageDist.map((a, i) => (
                <div key={a.bucket} style={{display:'flex',alignItems:'center',gap:10}}>
                  <span className="ff-mono num" style={{width:60,fontSize:11,color:'var(--ink-2)',letterSpacing:'.02em'}}>{a.bucket}</span>
                  <div style={{flex:1,height:14,background:'var(--bg-2)'}}>
                    <div style={{height:'100%',width:(a.share/Math.max(...insights.ageDist.map(x=>x.share))*100)+'%',background:'#3a4a8a'}}/>
                  </div>
                  <span className="ff-mono num" style={{width:50,textAlign:'right',fontSize:11,color:'var(--ink),fontWeight:600'}}>{(a.share*100).toFixed(1)}%</span>
                </div>
              ))}
            </div>
          </div>
          {/* Gender */}
          <div>
            <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)',marginBottom:14}}>GENDER</div>
            <StackedBar segments={insights.genderDist} height={36}/>
            <div style={{marginTop:18,display:'flex',flexDirection:'column',gap:10}}>
              {insights.genderDist.map(g => (
                <div key={g.id} style={{display:'flex',alignItems:'center',gap:10,fontSize:12}}>
                  <span style={{width:14,height:14,background:g.color,flexShrink:0}}/>
                  <span style={{flex:1,color:'var(--ink-2)',letterSpacing:'-0.005em'}}>{g.label}</span>
                  <span className="ff-mono num" style={{fontSize:12,fontWeight:600,color:'var(--ink)'}}>{(g.share*100).toFixed(1)}%</span>
                </div>
              ))}
            </div>
          </div>
        </div>
      </Section>

      {/* Geography */}
      <Section title="Geography" sub="Where listeners are from"
        right={<span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)'}}>BY MONTHLY LISTENERS</span>}>
        <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:30}}>
          {/* Countries */}
          <div>
            <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)',marginBottom:14}}>TOP COUNTRIES</div>
            <div style={{display:'flex',flexDirection:'column',gap:8}}>
              {insights.countries.slice(0, 10).map((c, i) => (
                <div key={c.iso} style={{display:'flex',alignItems:'center',gap:10}}>
                  <span style={{width:18,textAlign:'right',fontSize:10,color:'var(--ink-3)'}} className="ff-mono num">{i+1}</span>
                  <CountryFlag code={c.iso}/>
                  <span style={{flex:1,fontSize:12,color:'var(--ink)',letterSpacing:'-0.005em'}}>{c.name}</span>
                  <div style={{width:120,height:8,background:'var(--bg-2)'}}>
                    <div style={{height:'100%',width:(c.share/insights.countries[0].share*100)+'%',background:'#3a6a3a'}}/>
                  </div>
                  <span className="ff-mono num" style={{width:54,textAlign:'right',fontSize:11,color:'var(--ink-2),fontWeight:600'}}>
                    {fmtBig(Math.floor(c.share * insights.monthlyListeners))}
                  </span>
                </div>
              ))}
            </div>
          </div>
          {/* Cities */}
          <div>
            <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)',marginBottom:14}}>TOP CITIES</div>
            <div style={{display:'flex',flexDirection:'column',gap:8}}>
              {insights.cities.slice(0, 10).map((c, i) => (
                <div key={c.name} style={{display:'flex',alignItems:'center',gap:10}}>
                  <span style={{width:18,textAlign:'right',fontSize:10,color:'var(--ink-3)'}} className="ff-mono num">{i+1}</span>
                  <span style={{flex:1,fontSize:12,color:'var(--ink)',letterSpacing:'-0.005em'}}>{c.name}</span>
                  <div style={{width:120,height:8,background:'var(--bg-2)'}}>
                    <div style={{height:'100%',width:(c.share/insights.cities[0].share*100)+'%',background:'#7a4a8a'}}/>
                  </div>
                  <span className="ff-mono num" style={{width:54,textAlign:'right',fontSize:11,color:'var(--ink-2),fontWeight:600'}}>
                    {fmtBig(Math.floor(c.share * insights.monthlyListeners))}
                  </span>
                </div>
              ))}
            </div>
          </div>
        </div>
      </Section>

      {/* Listening rhythm */}
      <Section title="Listening rhythm" sub="When this audience listens — local time, weekday × hour"
        right={<span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)'}}>NORMALISED · DARKER = HIGHER</span>}>
        <Heatmap data={insights.heatmap}/>
      </Section>

      {/* Discovery + Devices */}
      <Section title="Discovery & devices" sub="How and where listeners reach the catalog">
        <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:30}}>
          <div>
            <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)',marginBottom:14}}>DISCOVERY SOURCE</div>
            <div style={{display:'flex',gap:24,alignItems:'center'}}>
              <Donut segments={insights.discoveryWeights} size={180}
                label={fmtPct(insights.discoveryWeights[0].share)}
                sublabel={insights.discoveryWeights[0].label.toUpperCase()}/>
              <Legend items={insights.discoveryWeights.sort((a,b)=>b.share-a.share)}/>
            </div>
          </div>
          <div>
            <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)',marginBottom:14}}>DEVICE</div>
            <div style={{display:'flex',gap:24,alignItems:'center'}}>
              <Donut segments={insights.deviceWeights} size={180}
                label={fmtPct(insights.deviceWeights[0].share)}
                sublabel={insights.deviceWeights[0].label.toUpperCase()}/>
              <Legend items={insights.deviceWeights.sort((a,b)=>b.share-a.share)}/>
            </div>
          </div>
        </div>
      </Section>

      {/* Platform breakdown */}
      <Section title="Platform mix" sub="Share of monthly listeners by DSP">
        <StackedBar segments={insights.platformShare} height={32}/>
        <div style={{display:'flex',flexWrap:'wrap',gap:18,marginTop:16}}>
          {insights.platformShare.sort((a,b)=>b.share-a.share).map(p => (
            <div key={p.id} style={{display:'flex',alignItems:'center',gap:8,fontSize:12}}>
              <span style={{width:14,height:14,background:p.color,flexShrink:0}}/>
              <span style={{color:'var(--ink-2)'}}>{p.name}</span>
              <span className="ff-mono num" style={{color:'var(--ink),fontWeight:600'}}>{(p.share*100).toFixed(1)}%</span>
            </div>
          ))}
        </div>
      </Section>

      <div style={{padding:'16px 0',marginTop:24,borderTop:'1px solid var(--rule)',fontSize:11,color:'var(--ink-3)',letterSpacing:'-0.005em'}}>
        Audience figures aggregate the prior 28 days of unique listeners across reporting DSPs.
        Engagement metrics (completion, skip, save) are weighted by play count.
        Heatmap times are local to each listener.
      </div>
    </>
  );
}

window.ScreenAudience = ScreenAudience;
})();
